From 7d1952b68908515fde391894f30b6d78a1660302 Mon Sep 17 00:00:00 2001 From: Aric Stewart Date: Fri, 20 Feb 2009 13:53:06 -0600 Subject: [PATCH] msctf: Implement ITfInputProcessorProfiles::EnumLanguageProfiles. --- dlls/msctf/inputprocessor.c | 242 +++++++++++++++++++++++++++++- dlls/msctf/tests/inputprocessor.c | 22 +++ include/msctf.idl | 21 +++ 3 files changed, 283 insertions(+), 2 deletions(-) diff --git a/dlls/msctf/inputprocessor.c b/dlls/msctf/inputprocessor.c index b0981690eab..de39af977a5 100644 --- a/dlls/msctf/inputprocessor.c +++ b/dlls/msctf/inputprocessor.c @@ -60,7 +60,22 @@ typedef struct tagProfilesEnumGuid { DWORD next_index; } ProfilesEnumGuid; +typedef struct tagEnumTfLanguageProfiles { + const IEnumTfLanguageProfilesVtbl *Vtbl; + LONG refCount; + + HKEY tipkey; + DWORD tip_index; + WCHAR szwCurrentClsid[39]; + + HKEY langkey; + DWORD lang_index; + + LANGID langid; +} EnumTfLanguageProfiles; + static HRESULT ProfilesEnumGuid_Constructor(IEnumGUID **ppOut); +static HRESULT EnumTfLanguageProfiles_Constructor(LANGID langid, IEnumTfLanguageProfiles **ppOut); static void InputProcessorProfiles_Destructor(InputProcessorProfiles *This) { @@ -330,8 +345,8 @@ static HRESULT WINAPI InputProcessorProfiles_EnumLanguageProfiles( IEnumTfLanguageProfiles **ppEnum) { InputProcessorProfiles *This = (InputProcessorProfiles*)iface; - FIXME("STUB:(%p)\n",This); - return E_NOTIMPL; + TRACE("(%p) %x %p\n",This,langid,ppEnum); + return EnumTfLanguageProfiles_Constructor(langid, ppEnum); } static HRESULT WINAPI InputProcessorProfiles_EnableLanguageProfile( @@ -645,3 +660,226 @@ static HRESULT ProfilesEnumGuid_Constructor(IEnumGUID **ppOut) *ppOut = (IEnumGUID*)This; return S_OK; } + +/************************************************** + * IEnumTfLanguageProfiles implementaion + **************************************************/ +static void EnumTfLanguageProfiles_Destructor(EnumTfLanguageProfiles *This) +{ + TRACE("destroying %p\n", This); + RegCloseKey(This->tipkey); + if (This->langkey) + RegCloseKey(This->langkey); + HeapFree(GetProcessHeap(),0,This); +} + +static HRESULT WINAPI EnumTfLanguageProfiles_QueryInterface(IEnumTfLanguageProfiles *iface, REFIID iid, LPVOID *ppvOut) +{ + EnumTfLanguageProfiles *This = (EnumTfLanguageProfiles *)iface; + *ppvOut = NULL; + + if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IEnumTfLanguageProfiles)) + { + *ppvOut = This; + } + + if (*ppvOut) + { + IUnknown_AddRef(iface); + return S_OK; + } + + WARN("unsupported interface: %s\n", debugstr_guid(iid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI EnumTfLanguageProfiles_AddRef(IEnumTfLanguageProfiles *iface) +{ + EnumTfLanguageProfiles *This = (EnumTfLanguageProfiles*)iface; + return InterlockedIncrement(&This->refCount); +} + +static ULONG WINAPI EnumTfLanguageProfiles_Release(IEnumTfLanguageProfiles *iface) +{ + EnumTfLanguageProfiles *This = (EnumTfLanguageProfiles *)iface; + ULONG ret; + + ret = InterlockedDecrement(&This->refCount); + if (ret == 0) + EnumTfLanguageProfiles_Destructor(This); + return ret; +} + +/***************************************************** + * IEnumGuid functions + *****************************************************/ +static INT next_LanguageProfile(EnumTfLanguageProfiles *This, CLSID clsid, TF_LANGUAGEPROFILE *tflp) +{ + WCHAR fullkey[168]; + ULONG res; + WCHAR profileid[39]; + DWORD cName = 39; + GUID profile; + + static const WCHAR fmt[] = {'%','s','\\','%','s','\\','0','x','%','0','8','x',0}; + + if (This->langkey == NULL) + { + sprintfW(fullkey,fmt,This->szwCurrentClsid,szwLngp,This->langid); + res = RegOpenKeyExW(This->tipkey, fullkey, 0, KEY_READ | KEY_WRITE, &This->langkey); + if (res) + { + This->langkey = NULL; + return -1; + } + This->lang_index = 0; + } + res = RegEnumKeyExW(This->langkey, This->lang_index, profileid, &cName, + NULL, NULL, NULL, NULL); + if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) + { + RegCloseKey(This->langkey); + This->langkey = NULL; + return -1; + } + ++(This->lang_index); + + if (tflp) + { + res = CLSIDFromString(profileid, &profile); + if (FAILED(res)) return 0; + + tflp->clsid = clsid; + tflp->langid = This->langid; + /* FIXME */ + tflp->fActive = FALSE; + tflp->guidProfile = profile; + /* FIXME set catid */ + } + + return 1; +} + +static HRESULT WINAPI EnumTfLanguageProfiles_Next(IEnumTfLanguageProfiles *iface, + ULONG ulCount, TF_LANGUAGEPROFILE *pProfile, ULONG *pcFetch) +{ + EnumTfLanguageProfiles *This = (EnumTfLanguageProfiles *)iface; + ULONG fetched = 0; + + TRACE("(%p)\n",This); + + if (pProfile == NULL) return E_POINTER; + + if (This->tipkey) while (fetched < ulCount) + { + LSTATUS res; + HRESULT hr; + DWORD cName = 39; + GUID clsid; + + res = RegEnumKeyExW(This->tipkey, This->tip_index, + This->szwCurrentClsid, &cName, NULL, NULL, NULL, NULL); + if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) break; + ++(This->tip_index); + hr = CLSIDFromString(This->szwCurrentClsid, &clsid); + if (FAILED(hr)) continue; + + while ( fetched < ulCount) + { + INT res = next_LanguageProfile(This, clsid, pProfile); + if (res == 1) + { + ++fetched; + ++pProfile; + } + else if (res == -1) + break; + else + continue; + } + } + + if (pcFetch) *pcFetch = fetched; + return fetched == ulCount ? S_OK : S_FALSE; +} + +static HRESULT WINAPI EnumTfLanguageProfiles_Skip( IEnumTfLanguageProfiles* iface, ULONG celt) +{ + EnumTfLanguageProfiles *This = (EnumTfLanguageProfiles *)iface; + FIXME("STUB (%p)\n",This); + return E_NOTIMPL; +} + +static HRESULT WINAPI EnumTfLanguageProfiles_Reset( IEnumTfLanguageProfiles* iface) +{ + EnumTfLanguageProfiles *This = (EnumTfLanguageProfiles *)iface; + TRACE("(%p)\n",This); + This->tip_index = 0; + if (This->langkey) + RegCloseKey(This->langkey); + This->langkey = NULL; + This->lang_index = 0; + return S_OK; +} + +static HRESULT WINAPI EnumTfLanguageProfiles_Clone( IEnumTfLanguageProfiles *iface, + IEnumTfLanguageProfiles **ppenum) +{ + EnumTfLanguageProfiles *This = (EnumTfLanguageProfiles *)iface; + HRESULT res; + + TRACE("(%p)\n",This); + + if (ppenum == NULL) return E_POINTER; + + res = EnumTfLanguageProfiles_Constructor(This->langid, ppenum); + if (SUCCEEDED(res)) + { + EnumTfLanguageProfiles *new_This = (EnumTfLanguageProfiles *)*ppenum; + new_This->tip_index = This->tip_index; + lstrcpynW(new_This->szwCurrentClsid,This->szwCurrentClsid,39); + + if (This->langkey) + { + WCHAR fullkey[168]; + static const WCHAR fmt[] = {'%','s','\\','%','s','\\','0','x','%','0','8','x',0}; + + sprintfW(fullkey,fmt,This->szwCurrentClsid,szwLngp,This->langid); + res = RegOpenKeyExW(new_This->tipkey, fullkey, 0, KEY_READ | KEY_WRITE, &This->langkey); + new_This->lang_index = This->lang_index; + } + } + return res; +} + +static const IEnumTfLanguageProfilesVtbl IEnumTfLanguageProfiles_Vtbl ={ + EnumTfLanguageProfiles_QueryInterface, + EnumTfLanguageProfiles_AddRef, + EnumTfLanguageProfiles_Release, + + EnumTfLanguageProfiles_Clone, + EnumTfLanguageProfiles_Next, + EnumTfLanguageProfiles_Reset, + EnumTfLanguageProfiles_Skip +}; + +static HRESULT EnumTfLanguageProfiles_Constructor(LANGID langid, IEnumTfLanguageProfiles **ppOut) +{ + EnumTfLanguageProfiles *This; + + This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(EnumTfLanguageProfiles)); + if (This == NULL) + return E_OUTOFMEMORY; + + This->Vtbl= &IEnumTfLanguageProfiles_Vtbl; + This->refCount = 1; + This->langid = langid; + + if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, szwSystemTIPKey, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &This->tipkey, NULL) != ERROR_SUCCESS) + return E_FAIL; + + TRACE("returning %p\n", This); + *ppOut = (IEnumTfLanguageProfiles*)This; + return S_OK; +} diff --git a/dlls/msctf/tests/inputprocessor.c b/dlls/msctf/tests/inputprocessor.c index 0520e495d9c..b7e2695b38d 100644 --- a/dlls/msctf/tests/inputprocessor.c +++ b/dlls/msctf/tests/inputprocessor.c @@ -102,6 +102,27 @@ static void test_EnumInputProcessorInfo(void) ok(found,"Did not find registered text service\n"); } +static void test_EnumLanguageProfiles(void) +{ + BOOL found = FALSE; + IEnumTfLanguageProfiles *ppEnum; + if (SUCCEEDED(ITfInputProcessorProfiles_EnumLanguageProfiles(g_ipp,gLangid,&ppEnum))) + { + TF_LANGUAGEPROFILE profile; + while (IEnumTfLanguageProfiles_Next(ppEnum,1,&profile,NULL)==S_OK) + { + if (IsEqualGUID(&profile.clsid,&CLSID_FakeService)) + { + found = TRUE; + ok(profile.langid == gLangid, "LangId Incorrect\n"); + todo_wine ok(IsEqualGUID(&profile.catid,&GUID_TFCAT_TIP_KEYBOARD), "CatId Incorrect\n"); + ok(IsEqualGUID(&profile.guidProfile,&CLSID_FakeService), "guidProfile Incorrect\n"); + } + } + } + ok(found,"Registered text service not found\n"); +} + static void test_RegisterCategory(void) { HRESULT hr; @@ -124,6 +145,7 @@ START_TEST(inputprocessor) test_Register(); test_RegisterCategory(); test_EnumInputProcessorInfo(); + test_EnumLanguageProfiles(); test_UnregisterCategory(); test_Unregister(); } diff --git a/include/msctf.idl b/include/msctf.idl index 7ffb46c6c6a..8411e5bbbee 100644 --- a/include/msctf.idl +++ b/include/msctf.idl @@ -450,3 +450,24 @@ interface ITfContextOwnerCompositionSink : IUnknown HRESULT OnEndComposition( [in] ITfCompositionView *pComposition); }; + +[ + object, + uuid(3d61bf11-ac5f-42c8-a4cb-931bcc28c744), + pointer_default(unique) +] +interface IEnumTfLanguageProfiles : IUnknown +{ + HRESULT Clone( + [out] IEnumTfLanguageProfiles **ppEnum); + + HRESULT Next( + [in] ULONG ulCount, + [out, size_is(ulCount), length_is(*pcFetch)] TF_LANGUAGEPROFILE *pProfile, + [out] ULONG *pcFetch); + + HRESULT Reset(); + + HRESULT Skip( + [in] ULONG ulCount); +};