4 * Copyright 2008 Aric Stewart, CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "wine/debug.h"
29 #include "wine/list.h"
39 #include "msctf_internal.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(msctf);
43 static LONG MSCTF_refCount;
45 static HINSTANCE MSCTF_hinstance;
55 TF_LANGUAGEPROFILE LanguageProfile;
56 ITfTextInputProcessor *pITfTextInputProcessor;
57 ITfThreadMgr *pITfThreadMgr;
59 } ActivatedTextService;
64 ActivatedTextService *ats;
67 static CookieInternal *cookies;
69 static UINT array_size;
71 static struct list AtsList = LIST_INIT(AtsList);
75 const WCHAR szwSystemTIPKey[] = {'S','O','F','T','W','A','R','E','\\','M','i','c','r','o','s','o','f','t','\\','C','T','F','\\','T','I','P',0};
77 typedef HRESULT (*LPFNCONSTRUCTOR)(IUnknown *pUnkOuter, IUnknown **ppvOut);
83 {&CLSID_TF_ThreadMgr, ThreadMgr_Constructor},
84 {&CLSID_TF_InputProcessorProfiles, InputProcessorProfiles_Constructor},
85 {&CLSID_TF_CategoryMgr, CategoryMgr_Constructor},
89 typedef struct tagClassFactory
91 const IClassFactoryVtbl *vtbl;
96 static void ClassFactory_Destructor(ClassFactory *This)
98 TRACE("Destroying class factory %p\n", This);
99 HeapFree(GetProcessHeap(),0,This);
103 static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, LPVOID *ppvOut)
106 if (IsEqualIID(riid, &IID_IClassFactory) || IsEqualIID(riid, &IID_IUnknown)) {
107 IClassFactory_AddRef(iface);
112 WARN("Unknown interface %s\n", debugstr_guid(riid));
113 return E_NOINTERFACE;
116 static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface)
118 ClassFactory *This = (ClassFactory *)iface;
119 return InterlockedIncrement(&This->ref);
122 static ULONG WINAPI ClassFactory_Release(IClassFactory *iface)
124 ClassFactory *This = (ClassFactory *)iface;
125 ULONG ret = InterlockedDecrement(&This->ref);
128 ClassFactory_Destructor(This);
132 static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, IUnknown *punkOuter, REFIID iid, LPVOID *ppvOut)
134 ClassFactory *This = (ClassFactory *)iface;
138 TRACE("(%p, %p, %s, %p)\n", iface, punkOuter, debugstr_guid(iid), ppvOut);
139 ret = This->ctor(punkOuter, &obj);
142 ret = IUnknown_QueryInterface(obj, iid, ppvOut);
143 IUnknown_Release(obj);
147 static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL fLock)
149 ClassFactory *This = (ClassFactory *)iface;
151 TRACE("(%p)->(%x)\n", This, fLock);
154 InterlockedIncrement(&MSCTF_refCount);
156 InterlockedDecrement(&MSCTF_refCount);
161 static const IClassFactoryVtbl ClassFactoryVtbl = {
163 ClassFactory_QueryInterface,
165 ClassFactory_Release,
168 ClassFactory_CreateInstance,
169 ClassFactory_LockServer
172 static HRESULT ClassFactory_Constructor(LPFNCONSTRUCTOR ctor, LPVOID *ppvOut)
174 ClassFactory *This = HeapAlloc(GetProcessHeap(),0,sizeof(ClassFactory));
175 This->vtbl = &ClassFactoryVtbl;
179 TRACE("Created class factory %p\n", This);
184 /*************************************************************************
185 * DWORD Cookie Management
187 DWORD generate_Cookie(DWORD magic, LPVOID data)
191 /* try to reuse IDs if possible */
192 for (i = 0; i < id_last; i++)
193 if (cookies[i].id == 0) break;
199 cookies = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CookieInternal) * 10);
202 ERR("Out of memory, Unable to alloc cookies array\n");
209 CookieInternal *new_cookies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cookies,
210 sizeof(CookieInternal) * (array_size * 2));
213 ERR("Out of memory, Unable to realloc cookies array\n");
216 cookies = new_cookies;
221 cookies[i].id = i + 1; /* a return of 0 is used for failure */
222 cookies[i].magic = magic;
223 cookies[i].data = data;
228 return cookies[i].id;
231 DWORD get_Cookie_magic(DWORD id)
235 if (index >= id_last)
238 if (cookies[index].id == 0)
241 return cookies[index].magic;
244 LPVOID get_Cookie_data(DWORD id)
248 if (index >= id_last)
251 if (cookies[index].id == 0)
254 return cookies[index].data;
257 LPVOID remove_Cookie(DWORD id)
261 if (index >= id_last)
264 if (cookies[index].id == 0)
267 cookies[index].id = 0;
268 return cookies[index].data;
271 DWORD enumerate_Cookie(DWORD magic, DWORD *index)
274 for (i = *index; i < id_last; i++)
275 if (cookies[i].id != 0 && cookies[i].magic == magic)
278 return cookies[i].id;
283 /*****************************************************************************
284 * Active Text Service Management
285 *****************************************************************************/
286 static HRESULT activate_given_ts(ActivatedTextService *actsvr, ITfThreadMgr* tm)
290 /* Already Active? */
291 if (actsvr->pITfTextInputProcessor)
294 hr = CoCreateInstance (&actsvr->LanguageProfile.clsid, NULL, CLSCTX_INPROC_SERVER,
295 &IID_ITfTextInputProcessor, (void**)&actsvr->pITfTextInputProcessor);
296 if (FAILED(hr)) return hr;
298 hr = ITfTextInputProcessor_Activate(actsvr->pITfTextInputProcessor, tm, actsvr->tid);
301 ITfTextInputProcessor_Release(actsvr->pITfTextInputProcessor);
302 actsvr->pITfTextInputProcessor = NULL;
306 actsvr->pITfThreadMgr = tm;
307 ITfThreadMgr_AddRef(tm);
311 static HRESULT deactivate_given_ts(ActivatedTextService *actsvr)
315 if (actsvr->pITfTextInputProcessor)
317 hr = ITfTextInputProcessor_Deactivate(actsvr->pITfTextInputProcessor);
318 ITfTextInputProcessor_Release(actsvr->pITfTextInputProcessor);
319 ITfThreadMgr_Release(actsvr->pITfThreadMgr);
320 actsvr->pITfTextInputProcessor = NULL;
321 actsvr->pITfThreadMgr = NULL;
327 static void deactivate_remove_conflicting_ts(REFCLSID catid)
329 AtsEntry *ats, *cursor2;
331 LIST_FOR_EACH_ENTRY_SAFE(ats, cursor2, &AtsList, AtsEntry, entry)
333 if (IsEqualCLSID(catid,&ats->ats->LanguageProfile.catid))
335 deactivate_given_ts(ats->ats);
336 list_remove(&ats->entry);
337 HeapFree(GetProcessHeap(),0,ats->ats);
338 HeapFree(GetProcessHeap(),0,ats);
339 /* we are guarenteeing there is only 1 */
345 HRESULT add_active_textservice(TF_LANGUAGEPROFILE *lp)
347 ActivatedTextService *actsvr;
348 ITfCategoryMgr *catmgr;
350 ITfThreadMgr *tm = (ITfThreadMgr*)TlsGetValue(tlsIndex);
351 ITfClientId *clientid;
353 if (!tm) return E_UNEXPECTED;
355 actsvr = HeapAlloc(GetProcessHeap(),0,sizeof(ActivatedTextService));
356 if (!actsvr) return E_OUTOFMEMORY;
358 entry = HeapAlloc(GetProcessHeap(),0,sizeof(AtsEntry));
362 HeapFree(GetProcessHeap(),0,actsvr);
363 return E_OUTOFMEMORY;
366 ITfThreadMgr_QueryInterface(tm,&IID_ITfClientId,(LPVOID)&clientid);
367 ITfClientId_GetClientId(clientid, &lp->clsid, &actsvr->tid);
368 ITfClientId_Release(clientid);
372 HeapFree(GetProcessHeap(),0,actsvr);
373 return E_OUTOFMEMORY;
376 actsvr->pITfTextInputProcessor = NULL;
377 actsvr->LanguageProfile = *lp;
378 actsvr->LanguageProfile.fActive = TRUE;
380 /* get TIP category */
381 if (SUCCEEDED(CategoryMgr_Constructor(NULL,(IUnknown**)&catmgr)))
383 static const GUID *list[3] = {&GUID_TFCAT_TIP_SPEECH, &GUID_TFCAT_TIP_KEYBOARD, &GUID_TFCAT_TIP_HANDWRITING};
385 ITfCategoryMgr_FindClosestCategory(catmgr,
386 &actsvr->LanguageProfile.clsid, &actsvr->LanguageProfile.catid,
389 ITfCategoryMgr_Release(catmgr);
393 ERR("CategoryMgr construction failed\n");
394 actsvr->LanguageProfile.catid = GUID_NULL;
397 if (!IsEqualGUID(&actsvr->LanguageProfile.catid,&GUID_NULL))
398 deactivate_remove_conflicting_ts(&actsvr->LanguageProfile.catid);
401 list_add_head(&AtsList, &entry->entry);
406 BOOL get_active_textservice(REFCLSID rclsid, TF_LANGUAGEPROFILE *profile)
410 LIST_FOR_EACH_ENTRY(ats, &AtsList, AtsEntry, entry)
412 if (IsEqualCLSID(rclsid,&ats->ats->LanguageProfile.clsid))
415 *profile = ats->ats->LanguageProfile;
422 HRESULT activate_textservices(ITfThreadMgr *tm)
427 LIST_FOR_EACH_ENTRY(ats, &AtsList, AtsEntry, entry)
429 hr = activate_given_ts(ats->ats, tm);
431 FIXME("Failed to activate text service\n");
436 HRESULT deactivate_textservices(void)
440 LIST_FOR_EACH_ENTRY(ats, &AtsList, AtsEntry, entry)
441 deactivate_given_ts(ats->ats);
446 /*************************************************************************
449 BOOL WINAPI DllMain(HINSTANCE hinst, DWORD fdwReason, LPVOID fImpLoad)
451 TRACE("%p 0x%x %p\n", hinst, fdwReason, fImpLoad);
454 case DLL_WINE_PREATTACH:
455 return FALSE; /* prefer native version */
456 case DLL_PROCESS_ATTACH:
457 MSCTF_hinstance = hinst;
458 tlsIndex = TlsAlloc();
460 case DLL_PROCESS_DETACH:
467 /*************************************************************************
468 * DllCanUnloadNow (MSCTF.@)
470 HRESULT WINAPI DllCanUnloadNow(void)
472 return MSCTF_refCount ? S_FALSE : S_OK;
475 /***********************************************************************
476 * DllGetClassObject (MSCTF.@)
478 HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID iid, LPVOID *ppvOut)
483 if (!IsEqualIID(iid, &IID_IUnknown) && !IsEqualIID(iid, &IID_IClassFactory))
484 return E_NOINTERFACE;
486 for (i = 0; ClassesTable[i].clsid != NULL; i++)
487 if (IsEqualCLSID(ClassesTable[i].clsid, clsid)) {
488 return ClassFactory_Constructor(ClassesTable[i].ctor, ppvOut);
490 FIXME("CLSID %s not supported\n", debugstr_guid(clsid));
491 return CLASS_E_CLASSNOTAVAILABLE;
494 /***********************************************************************
495 * TF_CreateThreadMgr (MSCTF.@)
497 HRESULT WINAPI TF_CreateThreadMgr(ITfThreadMgr **pptim)
500 return ThreadMgr_Constructor(NULL,(IUnknown**)pptim);
503 /***********************************************************************
504 * TF_GetThreadMgr (MSCTF.@)
506 HRESULT WINAPI TF_GetThreadMgr(ITfThreadMgr **pptim)
509 *pptim = TlsGetValue(tlsIndex);
512 ITfThreadMgr_AddRef(*pptim);
517 /***********************************************************************
518 * SetInputScope(MSCTF.@)
520 HRESULT WINAPI SetInputScope(HWND hwnd, INT inputscope)
522 FIXME("STUB: %p %i\n",hwnd,inputscope);
526 /***********************************************************************
527 * SetInputScopes(MSCTF.@)
529 HRESULT WINAPI SetInputScopes(HWND hwnd, const INT *pInputScopes,
530 UINT cInputScopes, WCHAR **ppszPhraseList,
531 UINT cPhrases, WCHAR *pszRegExp, WCHAR *pszSRGS)
534 FIXME("STUB: %p ... %s %s\n",hwnd, debugstr_w(pszRegExp), debugstr_w(pszSRGS));
535 for (i = 0; i < cInputScopes; i++)
536 TRACE("\tScope[%i] = %i\n",i,pInputScopes[i]);
537 for (i = 0; i < cPhrases; i++)
538 TRACE("\tPhrase[%i] = %s\n",i,debugstr_w(ppszPhraseList[i]));