diff --git a/dlls/msctf/inputprocessor.c b/dlls/msctf/inputprocessor.c index 3950a9452a4..b0981690eab 100644 --- a/dlls/msctf/inputprocessor.c +++ b/dlls/msctf/inputprocessor.c @@ -52,6 +52,16 @@ typedef struct tagInputProcessorProfiles { LANGID currentLanguage; } InputProcessorProfiles; +typedef struct tagProfilesEnumGuid { + const IEnumGUIDVtbl *Vtbl; + LONG refCount; + + HKEY key; + DWORD next_index; +} ProfilesEnumGuid; + +static HRESULT ProfilesEnumGuid_Constructor(IEnumGUID **ppOut); + static void InputProcessorProfiles_Destructor(InputProcessorProfiles *This) { TRACE("destroying %p\n", This); @@ -236,8 +246,8 @@ static HRESULT WINAPI InputProcessorProfiles_EnumInputProcessorInfo( ITfInputProcessorProfiles *iface, IEnumGUID **ppEnum) { InputProcessorProfiles *This = (InputProcessorProfiles*)iface; - FIXME("STUB:(%p)\n",This); - return E_NOTIMPL; + TRACE("(%p) %p\n",This,ppEnum); + return ProfilesEnumGuid_Constructor(ppEnum); } static HRESULT WINAPI InputProcessorProfiles_GetDefaultLanguageProfile( @@ -485,3 +495,153 @@ HRESULT InputProcessorProfiles_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut *ppOut = (IUnknown *)This; return S_OK; } + +/************************************************** + * IEnumGUID implementaion for ITfInputProcessorProfiles::EnumInputProcessorInfo + **************************************************/ +static void ProfilesEnumGuid_Destructor(ProfilesEnumGuid *This) +{ + TRACE("destroying %p\n", This); + RegCloseKey(This->key); + HeapFree(GetProcessHeap(),0,This); +} + +static HRESULT WINAPI ProfilesEnumGuid_QueryInterface(IEnumGUID *iface, REFIID iid, LPVOID *ppvOut) +{ + ProfilesEnumGuid *This = (ProfilesEnumGuid *)iface; + *ppvOut = NULL; + + if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IEnumGUID)) + { + *ppvOut = This; + } + + if (*ppvOut) + { + IUnknown_AddRef(iface); + return S_OK; + } + + WARN("unsupported interface: %s\n", debugstr_guid(iid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI ProfilesEnumGuid_AddRef(IEnumGUID *iface) +{ + ProfilesEnumGuid *This = (ProfilesEnumGuid*)iface; + return InterlockedIncrement(&This->refCount); +} + +static ULONG WINAPI ProfilesEnumGuid_Release(IEnumGUID *iface) +{ + ProfilesEnumGuid *This = (ProfilesEnumGuid *)iface; + ULONG ret; + + ret = InterlockedDecrement(&This->refCount); + if (ret == 0) + ProfilesEnumGuid_Destructor(This); + return ret; +} + +/***************************************************** + * IEnumGuid functions + *****************************************************/ +static HRESULT WINAPI ProfilesEnumGuid_Next( LPENUMGUID iface, + ULONG celt, GUID *rgelt, ULONG *pceltFetched) +{ + ProfilesEnumGuid *This = (ProfilesEnumGuid *)iface; + ULONG fetched = 0; + + TRACE("(%p)\n",This); + + if (rgelt == NULL) return E_POINTER; + + if (This->key) while (fetched < celt) + { + LSTATUS res; + HRESULT hr; + WCHAR catid[39]; + DWORD cName = 39; + + res = RegEnumKeyExW(This->key, This->next_index, catid, &cName, + NULL, NULL, NULL, NULL); + if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) break; + ++(This->next_index); + + hr = CLSIDFromString(catid, rgelt); + if (FAILED(hr)) continue; + + ++fetched; + ++rgelt; + } + + if (pceltFetched) *pceltFetched = fetched; + return fetched == celt ? S_OK : S_FALSE; +} + +static HRESULT WINAPI ProfilesEnumGuid_Skip( LPENUMGUID iface, ULONG celt) +{ + ProfilesEnumGuid *This = (ProfilesEnumGuid *)iface; + TRACE("(%p)\n",This); + + This->next_index += celt; + return S_OK; +} + +static HRESULT WINAPI ProfilesEnumGuid_Reset( LPENUMGUID iface) +{ + ProfilesEnumGuid *This = (ProfilesEnumGuid *)iface; + TRACE("(%p)\n",This); + This->next_index = 0; + return S_OK; +} + +static HRESULT WINAPI ProfilesEnumGuid_Clone( LPENUMGUID iface, + IEnumGUID **ppenum) +{ + ProfilesEnumGuid *This = (ProfilesEnumGuid *)iface; + HRESULT res; + + TRACE("(%p)\n",This); + + if (ppenum == NULL) return E_POINTER; + + res = ProfilesEnumGuid_Constructor(ppenum); + if (SUCCEEDED(res)) + { + ProfilesEnumGuid *new_This = (ProfilesEnumGuid *)*ppenum; + new_This->next_index = This->next_index; + } + return res; +} + +static const IEnumGUIDVtbl IEnumGUID_Vtbl ={ + ProfilesEnumGuid_QueryInterface, + ProfilesEnumGuid_AddRef, + ProfilesEnumGuid_Release, + + ProfilesEnumGuid_Next, + ProfilesEnumGuid_Skip, + ProfilesEnumGuid_Reset, + ProfilesEnumGuid_Clone +}; + +static HRESULT ProfilesEnumGuid_Constructor(IEnumGUID **ppOut) +{ + ProfilesEnumGuid *This; + + This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ProfilesEnumGuid)); + if (This == NULL) + return E_OUTOFMEMORY; + + This->Vtbl= &IEnumGUID_Vtbl; + This->refCount = 1; + + if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, szwSystemTIPKey, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &This->key, NULL) != ERROR_SUCCESS) + return E_FAIL; + + TRACE("returning %p\n", This); + *ppOut = (IEnumGUID*)This; + return S_OK; +} diff --git a/dlls/msctf/tests/inputprocessor.c b/dlls/msctf/tests/inputprocessor.c index 34e47e5a30b..0520e495d9c 100644 --- a/dlls/msctf/tests/inputprocessor.c +++ b/dlls/msctf/tests/inputprocessor.c @@ -84,6 +84,24 @@ static void test_Unregister(void) ok(SUCCEEDED(hr),"Unable to unregister text service(%x)\n",hr); } +static void test_EnumInputProcessorInfo(void) +{ + IEnumGUID *ppEnum; + BOOL found = FALSE; + + if (SUCCEEDED(ITfInputProcessorProfiles_EnumInputProcessorInfo(g_ipp, &ppEnum))) + { + ULONG fetched; + GUID g; + while (IEnumGUID_Next(ppEnum, 1, &g, &fetched) == S_OK) + { + if(IsEqualGUID(&g,&CLSID_FakeService)) + found = TRUE; + } + } + ok(found,"Did not find registered text service\n"); +} + static void test_RegisterCategory(void) { HRESULT hr; @@ -105,6 +123,7 @@ START_TEST(inputprocessor) gLangid = GetUserDefaultLCID(); test_Register(); test_RegisterCategory(); + test_EnumInputProcessorInfo(); test_UnregisterCategory(); test_Unregister(); }