[PATCH v2 0/2] MR10996: msctf: Add a stub implementation of ITfFnReconversion.
-- v2: msctf: Add a stub implementation of ITfFnReconversion. msctf: Return stub interface from ThreadMgr_GetFunctionProvider(). https://gitlab.winehq.org/wine/wine/-/merge_requests/10996
From: Paul Gofman <pgofman@codeweavers.com> --- dlls/msctf/threadmgr.c | 70 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 2 deletions(-) diff --git a/dlls/msctf/threadmgr.c b/dlls/msctf/threadmgr.c index 11c79c030ff..5dec9d25806 100644 --- a/dlls/msctf/threadmgr.c +++ b/dlls/msctf/threadmgr.c @@ -34,6 +34,9 @@ #include "msctf.h" #include "msctf_internal.h" +#include "initguid.h" + +DEFINE_GUID(GUID_SYSTEM_FUNCTIONPROVIDER, 0x9a698bb0,0x0f21,0x11d3,0x8d,0xf1,0x00,0x10,0x5a,0x27,0x99,0xb5); WINE_DEFAULT_DEBUG_CHANNEL(msctf); @@ -70,6 +73,7 @@ typedef struct tagACLMulti { /* const ITfLangBarItemMgrVtbl *LangBarItemMgrVtbl; */ ITfUIElementMgr ITfUIElementMgr_iface; ITfSourceSingle ITfSourceSingle_iface; + ITfFunctionProvider ITfFunctionProvider_iface; LONG refCount; /* Aggregation */ @@ -150,11 +154,62 @@ static inline ThreadMgr *impl_from_ITfSourceSingle(ITfSourceSingle *iface) return CONTAINING_RECORD(iface, ThreadMgr, ITfSourceSingle_iface); } +static ThreadMgr *impl_from_ITfFunctionProvider(ITfFunctionProvider *iface) +{ + return CONTAINING_RECORD(iface, ThreadMgr, ITfFunctionProvider_iface); +} + static inline EnumTfDocumentMgr *impl_from_IEnumTfDocumentMgrs(IEnumTfDocumentMgrs *iface) { return CONTAINING_RECORD(iface, EnumTfDocumentMgr, IEnumTfDocumentMgrs_iface); } +static HRESULT WINAPI func_provider_QueryInterface(ITfFunctionProvider *iface, REFIID iid, LPVOID *ppvOut) +{ + ThreadMgr *This = impl_from_ITfFunctionProvider(iface); + return ITfThreadMgrEx_QueryInterface(&This->ITfThreadMgrEx_iface, iid, ppvOut); +} + +static ULONG WINAPI func_provider_AddRef(ITfFunctionProvider *iface) +{ + ThreadMgr *This = impl_from_ITfFunctionProvider(iface); + return ITfThreadMgrEx_AddRef(&This->ITfThreadMgrEx_iface); +} + +static ULONG WINAPI func_provider_Release(ITfFunctionProvider *iface) +{ + ThreadMgr *This = impl_from_ITfFunctionProvider(iface); + return ITfThreadMgrEx_Release(&This->ITfThreadMgrEx_iface); +} + +static HRESULT WINAPI func_provider_GetType(ITfFunctionProvider *iface, GUID *guid) +{ + FIXME("(%p) %p stub.\n", iface, guid); + return E_NOTIMPL; +} + +static HRESULT WINAPI func_provider_GetDescription(ITfFunctionProvider *iface, BSTR *desc) +{ + FIXME("(%p) %p stub.\n", iface, desc); + return E_NOTIMPL; +} + +static HRESULT WINAPI func_provider_GetFunction(ITfFunctionProvider *iface, REFGUID guid, REFIID riid, IUnknown **func) +{ + FIXME("(%p) %s %s %p stub.\n", iface, debugstr_guid(guid), debugstr_guid(riid), func); + return E_NOTIMPL; +} + +static const ITfFunctionProviderVtbl TfFunctionProviderVtbl = +{ + func_provider_QueryInterface, + func_provider_AddRef, + func_provider_Release, + func_provider_GetType, + func_provider_GetDescription, + func_provider_GetFunction, +}; + static void ThreadMgr_Destructor(ThreadMgr *This) { struct list *cursor, *cursor2; @@ -493,8 +548,18 @@ static HRESULT WINAPI ThreadMgr_GetFunctionProvider(ITfThreadMgrEx *iface, REFCL ITfFunctionProvider **ppFuncProv) { ThreadMgr *This = impl_from_ITfThreadMgrEx(iface); - FIXME("STUB:(%p)\n",This); - return E_NOTIMPL; + + TRACE("(%p) %s\n", This, debugstr_guid(clsid)); + + if (!IsEqualGUID(clsid, &GUID_SYSTEM_FUNCTIONPROVIDER)) + { + FIXME("clsid %s not supported\n", debugstr_guid(clsid)); + return E_NOTIMPL; + } + + *ppFuncProv = &This->ITfFunctionProvider_iface; + ITfFunctionProvider_AddRef(*ppFuncProv); + return S_OK; } static HRESULT WINAPI ThreadMgr_EnumFunctionProviders(ITfThreadMgrEx *iface, @@ -1366,6 +1431,7 @@ HRESULT ThreadMgr_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut) This->ITfThreadMgrEventSink_iface.lpVtbl = &ThreadMgrEventSinkVtbl; This->ITfUIElementMgr_iface.lpVtbl = &ThreadMgrUIElementMgrVtbl; This->ITfSourceSingle_iface.lpVtbl = &SourceSingleVtbl; + This->ITfFunctionProvider_iface.lpVtbl = &TfFunctionProviderVtbl; This->refCount = 1; TlsSetValue(tlsIndex,This); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10996
From: Hans Leidekker <hans@codeweavers.com> Based on a patch by Paul Gofman. --- dlls/msctf/tests/Makefile.in | 2 +- dlls/msctf/tests/inputprocessor.c | 25 ++++++ dlls/msctf/threadmgr.c | 121 ++++++++++++++++++++++++++++++ include/Makefile.in | 1 + include/ctffunc.idl | 80 ++++++++++++++++++++ include/msctf.idl | 10 +++ 6 files changed, 238 insertions(+), 1 deletion(-) create mode 100644 include/ctffunc.idl diff --git a/dlls/msctf/tests/Makefile.in b/dlls/msctf/tests/Makefile.in index dc572d4d9c1..029e30de451 100644 --- a/dlls/msctf/tests/Makefile.in +++ b/dlls/msctf/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = msctf.dll -IMPORTS = ole32 user32 advapi32 +IMPORTS = oleaut32 ole32 user32 advapi32 SOURCES = \ inputprocessor.c \ diff --git a/dlls/msctf/tests/inputprocessor.c b/dlls/msctf/tests/inputprocessor.c index 5038b733b55..b912ecda697 100644 --- a/dlls/msctf/tests/inputprocessor.c +++ b/dlls/msctf/tests/inputprocessor.c @@ -29,6 +29,7 @@ #include "shlguid.h" #include "comcat.h" #include "msctf.h" +#include "ctffunc.h" #include "olectl.h" static ITfInputProcessorProfiles* g_ipp; @@ -1082,6 +1083,7 @@ DEFINE_GUID(GUID_COMPARTMENT_SPEECH_GLOBALSTATE, 0x2a54fe8e,0x0d08,0x460c,0xa DEFINE_GUID(GUID_COMPARTMENT_PERSISTMENUENABLED, 0x575f3783,0x70c8,0x47c8,0xae,0x5d,0x91,0xa0,0x1a,0x1f,0x75,0x92); DEFINE_GUID(GUID_COMPARTMENT_EMPTYCONTEXT, 0xd7487dbf,0x804e,0x41c5,0x89,0x4d,0xad,0x96,0xfd,0x4e,0xea,0x13); DEFINE_GUID(GUID_COMPARTMENT_TIPUISTATUS, 0x148ca3ec,0x0366,0x401c,0x8d,0x75,0xed,0x97,0x8d,0x85,0xfb,0xc9); +DEFINE_GUID(GUID_SYSTEM_FUNCTIONPROVIDER, 0x9a698bb0,0x0f21,0x11d3,0x8d,0xf1,0x00,0x10,0x5a,0x27,0x99,0xb5); static HRESULT initialize(void) { @@ -2627,6 +2629,28 @@ static void test_MultiThreadApartment(void) CloseHandle(thread); } +static void test_function_provider(void) +{ + ITfFunctionProvider *provider; + ITfFnReconversion *reconv; + BSTR name; + HRESULT hr; + + hr = ITfThreadMgr_GetFunctionProvider(g_tm, &GUID_SYSTEM_FUNCTIONPROVIDER, &provider); + ok(hr == S_OK, "got %lx\n", hr); + + hr = ITfFunctionProvider_GetFunction(provider, &GUID_NULL, &IID_ITfFnReconversion, (IUnknown **)&reconv); + ok(hr == S_OK, "got %lx\n", hr); + + hr = ITfFnReconversion_GetDisplayName(reconv, &name); + ok(hr == S_OK, "got %lx\n", hr); + ok(!wcscmp(name, L"Reconversion"), "got %s\n", debugstr_w(name)); + SysFreeString(name); + + ITfFnReconversion_Release(reconv); + ITfFunctionProvider_Release(provider); +} + START_TEST(inputprocessor) { if (SUCCEEDED(initialize())) @@ -2657,6 +2681,7 @@ START_TEST(inputprocessor) test_Unregister(); test_profile_mgr(); test_MultiThreadApartment(); + test_function_provider(); ITextStoreACPSink_Release(ACPSink); ITfDocumentMgr_Release(g_dm); diff --git a/dlls/msctf/threadmgr.c b/dlls/msctf/threadmgr.c index 5dec9d25806..312b527eb74 100644 --- a/dlls/msctf/threadmgr.c +++ b/dlls/msctf/threadmgr.c @@ -35,6 +35,7 @@ #include "msctf.h" #include "msctf_internal.h" #include "initguid.h" +#include "ctffunc.h" DEFINE_GUID(GUID_SYSTEM_FUNCTIONPROVIDER, 0x9a698bb0,0x0f21,0x11d3,0x8d,0xf1,0x00,0x10,0x5a,0x27,0x99,0xb5); @@ -164,6 +165,109 @@ static inline EnumTfDocumentMgr *impl_from_IEnumTfDocumentMgrs(IEnumTfDocumentMg return CONTAINING_RECORD(iface, EnumTfDocumentMgr, IEnumTfDocumentMgrs_iface); } +struct reconv +{ + ITfFnReconversion ITfFnReconversion_iface; + LONG ref; +}; + +static inline struct reconv *impl_from_ITfFnReconversion(ITfFnReconversion *iface) +{ + return CONTAINING_RECORD(iface, struct reconv, ITfFnReconversion_iface); +} + +static HRESULT WINAPI reconv_QueryInterface(ITfFnReconversion *iface, REFIID iid, void **out) +{ + TRACE("(%p) %s, %p.\n", iface, debugstr_guid(iid), out); + + *out = NULL; + if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfFunction) + || IsEqualIID(iid, &IID_ITfFnReconversion)) + { + *out = iface; + ITfFnReconversion_AddRef(iface); + return S_OK; + } + + WARN("unsupported interface: %s\n", debugstr_guid(iid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI reconv_AddRef(ITfFnReconversion *iface) +{ + struct reconv *reconv = impl_from_ITfFnReconversion(iface); + return InterlockedIncrement(&reconv->ref); +} + +static ULONG WINAPI reconv_Release(ITfFnReconversion *iface) +{ + struct reconv *reconv = impl_from_ITfFnReconversion(iface); + ULONG ret; + + if (!(ret = InterlockedDecrement(&reconv->ref))) free(reconv); + return ret; +} + +static HRESULT WINAPI reconv_GetDisplayName(ITfFnReconversion *iface, BSTR *name) +{ + BSTR str; + + TRACE("(%p) %p\n", iface, name); + + if (!(str = SysAllocString(L"Reconversion"))) return E_OUTOFMEMORY; + *name = str; + return S_OK; +} + +static HRESULT WINAPI reconv_QueryRange(ITfFnReconversion *iface, ITfRange *range, ITfRange **new_range, + BOOL *convertable) +{ + FIXME("(%p) %p %p %p stub.\n", iface, range, new_range, convertable); + + *convertable = FALSE; + *new_range = NULL; + return E_NOTIMPL; +} + +static HRESULT WINAPI reconv_GetReconversion(ITfFnReconversion *iface, ITfRange *range, ITfCandidateList **cand_list) +{ + FIXME("(%p) %p %p stub.\n", iface, range, cand_list); + + *cand_list = NULL; + return E_NOTIMPL; +} + +static HRESULT WINAPI reconv_Reconvert(ITfFnReconversion *iface, ITfRange *range) +{ + FIXME("(%p) %p stub.\n", iface, range); + return E_NOTIMPL; +} + +static ITfFnReconversionVtbl reconv_vtbl = +{ + reconv_QueryInterface, + reconv_AddRef, + reconv_Release, + reconv_GetDisplayName, + reconv_QueryRange, + reconv_GetReconversion, + reconv_Reconvert, +}; + +static HRESULT ITfFnReconversion_Constructor(IUnknown **out) +{ + struct reconv *reconv; + + if (!(reconv = calloc(1, sizeof(*reconv)))) return E_OUTOFMEMORY; + + reconv->ITfFnReconversion_iface.lpVtbl= &reconv_vtbl; + reconv->ref = 1; + + TRACE("returning %p\n", &reconv->ITfFnReconversion_iface); + *out = (IUnknown *)&reconv->ITfFnReconversion_iface; + return S_OK; +} + static HRESULT WINAPI func_provider_QueryInterface(ITfFunctionProvider *iface, REFIID iid, LPVOID *ppvOut) { ThreadMgr *This = impl_from_ITfFunctionProvider(iface); @@ -194,8 +298,25 @@ static HRESULT WINAPI func_provider_GetDescription(ITfFunctionProvider *iface, B return E_NOTIMPL; } +static const struct +{ + const GUID *iid; + HRESULT (*constructor)(IUnknown **); +} +function_table[] = +{ + { &IID_ITfFnReconversion, ITfFnReconversion_Constructor }, +}; + static HRESULT WINAPI func_provider_GetFunction(ITfFunctionProvider *iface, REFGUID guid, REFIID riid, IUnknown **func) { + ULONG i; + + TRACE("(%p) %s %s %p\n", iface, debugstr_guid(guid), debugstr_guid(riid), func); + + for (i = 0; i < ARRAY_SIZE(function_table); i++) + if (IsEqualIID(riid, function_table[i].iid)) return function_table[i].constructor(func); + FIXME("(%p) %s %s %p stub.\n", iface, debugstr_guid(guid), debugstr_guid(riid), func); return E_NOTIMPL; } diff --git a/include/Makefile.in b/include/Makefile.in index 9e4ef779ae5..eda503972d7 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -108,6 +108,7 @@ SOURCES = \ cryptdlg.h \ cryptuiapi.h \ cryptxml.h \ + ctffunc.idl \ ctfutb.idl \ ctxtcall.idl \ custcntl.h \ diff --git a/include/ctffunc.idl b/include/ctffunc.idl new file mode 100644 index 00000000000..c308c5377c7 --- /dev/null +++ b/include/ctffunc.idl @@ -0,0 +1,80 @@ +/* + * Copyright 2026 Paul Gofman for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef DO_NO_IMPORTS +import "oaidl.idl"; +import "msctf.idl"; +#endif + +interface IEnumTfCandidates; + +[ + object, + uuid(581f317e-fd9d-443f-b972-ed00467c5d40), + pointer_default(unique) +] +interface ITfCandidateString : IUnknown +{ + HRESULT GetString([out] BSTR *bstr); + HRESULT GetIndex([out] ULONG *index); +} + +[ + object, + uuid(defb1926-6c80-4ce8-87d4-d6b72b812bde), + pointer_default(unique) +] +interface IEnumTfCandidates : IUnknown +{ + HRESULT Clone([out] IEnumTfCandidates **ret_enum); + HRESULT Next([in] ULONG count, [out] ITfCandidateString **cand, [out] ULONG *fetched); + HRESULT Reset(); + HRESULT Skip([in] ULONG count); +} + +typedef [uuid(baa898f2-0207-4643-92ca-f3f7b0cf6f80)] enum +{ + CAND_FINALIZED = 0x0, + CAND_SELECTED = 0x1, + CAND_CANCELED = 0x2, +} TfCandidateResult; + +[ + object, + uuid(a3ad50fb-9bdb-49e3-a843-6c76520fbf5d), + pointer_default(unique) +] +interface ITfCandidateList : IUnknown +{ + HRESULT EnumCandidates([out] IEnumTfCandidates **ret_enum); + HRESULT GetCandidate([in] ULONG index, [out] ITfCandidateString **cand); + HRESULT GetCandidateNum([out] ULONG *count); + HRESULT SetResult([in] ULONG nIndex, [in] TfCandidateResult imcr); +} + +[ + object, + uuid(4cea93c0-0a58-11d3-8df0-00105a2799b5), + pointer_default(unique) +] +interface ITfFnReconversion : ITfFunction +{ + HRESULT QueryRange([in] ITfRange *range, ITfRange **new_range, BOOL *convertable); + HRESULT GetReconversion(ITfRange *range, ITfCandidateList **cand_list); + HRESULT Reconvert([in] ITfRange *range); +} diff --git a/include/msctf.idl b/include/msctf.idl index 6b0c84bdd53..a1c40e944e4 100644 --- a/include/msctf.idl +++ b/include/msctf.idl @@ -172,6 +172,16 @@ typedef [uuid(d678c645-eb6a-45c9-b4ee-0f3e3a991348)] struct TF_PROPERTYVAL VARIANT varValue; } TF_PROPERTYVAL; +[ + object, + uuid(db593490-098f-11d3-8df0-00105a2799b5), + pointer_default(unique) +] +interface ITfFunction : IUnknown +{ + HRESULT GetDisplayName([out] BSTR *name); +} + [ object, uuid(101d6610-0990-11d3-8df0-00105a2799b5), -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10996
v2: Check provider GUID and introduce a table for builtin functions. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10996#note_141410
This merge request was approved by Paul Gofman. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10996
participants (4)
-
Hans Leidekker -
Hans Leidekker (@hans) -
Paul Gofman -
Paul Gofman (@gofman)