1 /* 2 * MSCTF Server DLL 3 * 4 * Copyright 2008 Aric Stewart, CodeWeavers 5 * 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. 10 * 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. 15 * 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 19 */ 20 21 #include "config.h" 22 23 #include <stdarg.h> 24 #include <stdio.h> 25 26 #define COBJMACROS 27 28 #include "wine/debug.h" 29 #include "windef.h" 30 #include "winbase.h" 31 #include "winreg.h" 32 #include "shlwapi.h" 33 #include "shlguid.h" 34 #include "comcat.h" 35 #include "olectl.h" 36 #include "rpcproxy.h" 37 #include "msctf.h" 38 #include "inputscope.h" 39 40 #include "msctf_internal.h" 41 42 WINE_DEFAULT_DEBUG_CHANNEL(msctf); 43 44 static HINSTANCE MSCTF_hinstance; 45 46 typedef struct 47 { 48 DWORD id; 49 DWORD magic; 50 LPVOID data; 51 } CookieInternal; 52 53 typedef struct { 54 TF_LANGUAGEPROFILE LanguageProfile; 55 ITfTextInputProcessor *pITfTextInputProcessor; 56 ITfThreadMgrEx *pITfThreadMgrEx; 57 ITfKeyEventSink *pITfKeyEventSink; 58 TfClientId tid; 59 } ActivatedTextService; 60 61 typedef struct 62 { 63 struct list entry; 64 ActivatedTextService *ats; 65 } AtsEntry; 66 67 static CookieInternal *cookies; 68 static UINT id_last; 69 static UINT array_size; 70 71 static struct list AtsList = LIST_INIT(AtsList); 72 static UINT activated = 0; 73 74 DWORD tlsIndex = 0; 75 TfClientId processId = 0; 76 ITfCompartmentMgr *globalCompartmentMgr = NULL; 77 78 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}; 79 const WCHAR szwSystemCTFKey[] = {'S','O','F','T','W','A','R','E','\\','M','i','c','r','o','s','o','f','t','\\','C','T','F',0}; 80 81 typedef HRESULT (*LPFNCONSTRUCTOR)(IUnknown *pUnkOuter, IUnknown **ppvOut); 82 83 static const struct { 84 REFCLSID clsid; 85 LPFNCONSTRUCTOR ctor; 86 } ClassesTable[] = { 87 {&CLSID_TF_ThreadMgr, ThreadMgr_Constructor}, 88 {&CLSID_TF_InputProcessorProfiles, InputProcessorProfiles_Constructor}, 89 {&CLSID_TF_CategoryMgr, CategoryMgr_Constructor}, 90 {&CLSID_TF_LangBarMgr, LangBarMgr_Constructor}, 91 {&CLSID_TF_DisplayAttributeMgr, DisplayAttributeMgr_Constructor}, 92 {NULL, NULL} 93 }; 94 95 typedef struct tagClassFactory 96 { 97 IClassFactory IClassFactory_iface; 98 LONG ref; 99 LPFNCONSTRUCTOR ctor; 100 } ClassFactory; 101 102 static inline ClassFactory *impl_from_IClassFactory(IClassFactory *iface) 103 { 104 return CONTAINING_RECORD(iface, ClassFactory, IClassFactory_iface); 105 } 106 107 static void ClassFactory_Destructor(ClassFactory *This) 108 { 109 TRACE("Destroying class factory %p\n", This); 110 HeapFree(GetProcessHeap(),0,This); 111 } 112 113 static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, LPVOID *ppvOut) 114 { 115 *ppvOut = NULL; 116 if (IsEqualIID(riid, &IID_IClassFactory) || IsEqualIID(riid, &IID_IUnknown)) { 117 IClassFactory_AddRef(iface); 118 *ppvOut = iface; 119 return S_OK; 120 } 121 122 WARN("Unknown interface %s\n", debugstr_guid(riid)); 123 return E_NOINTERFACE; 124 } 125 126 static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface) 127 { 128 ClassFactory *This = impl_from_IClassFactory(iface); 129 return InterlockedIncrement(&This->ref); 130 } 131 132 static ULONG WINAPI ClassFactory_Release(IClassFactory *iface) 133 { 134 ClassFactory *This = impl_from_IClassFactory(iface); 135 ULONG ret = InterlockedDecrement(&This->ref); 136 137 if (ret == 0) 138 ClassFactory_Destructor(This); 139 return ret; 140 } 141 142 static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, IUnknown *punkOuter, REFIID iid, LPVOID *ppvOut) 143 { 144 ClassFactory *This = impl_from_IClassFactory(iface); 145 HRESULT ret; 146 IUnknown *obj; 147 148 TRACE("(%p, %p, %s, %p)\n", iface, punkOuter, debugstr_guid(iid), ppvOut); 149 ret = This->ctor(punkOuter, &obj); 150 if (FAILED(ret)) 151 return ret; 152 ret = IUnknown_QueryInterface(obj, iid, ppvOut); 153 IUnknown_Release(obj); 154 return ret; 155 } 156 157 static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL fLock) 158 { 159 ClassFactory *This = impl_from_IClassFactory(iface); 160 161 TRACE("(%p)->(%x)\n", This, fLock); 162 163 return S_OK; 164 } 165 166 static const IClassFactoryVtbl ClassFactoryVtbl = { 167 /* IUnknown */ 168 ClassFactory_QueryInterface, 169 ClassFactory_AddRef, 170 ClassFactory_Release, 171 172 /* IClassFactory*/ 173 ClassFactory_CreateInstance, 174 ClassFactory_LockServer 175 }; 176 177 static HRESULT ClassFactory_Constructor(LPFNCONSTRUCTOR ctor, LPVOID *ppvOut) 178 { 179 ClassFactory *This = HeapAlloc(GetProcessHeap(),0,sizeof(ClassFactory)); 180 This->IClassFactory_iface.lpVtbl = &ClassFactoryVtbl; 181 This->ref = 1; 182 This->ctor = ctor; 183 *ppvOut = &This->IClassFactory_iface; 184 TRACE("Created class factory %p\n", This); 185 return S_OK; 186 } 187 188 /************************************************************************* 189 * DWORD Cookie Management 190 */ 191 DWORD generate_Cookie(DWORD magic, LPVOID data) 192 { 193 UINT i; 194 195 /* try to reuse IDs if possible */ 196 for (i = 0; i < id_last; i++) 197 if (cookies[i].id == 0) break; 198 199 if (i == array_size) 200 { 201 if (!array_size) 202 { 203 cookies = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CookieInternal) * 10); 204 if (!cookies) 205 { 206 ERR("Out of memory, Unable to alloc cookies array\n"); 207 return 0; 208 } 209 array_size = 10; 210 } 211 else 212 { 213 CookieInternal *new_cookies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cookies, 214 sizeof(CookieInternal) * (array_size * 2)); 215 if (!new_cookies) 216 { 217 ERR("Out of memory, Unable to realloc cookies array\n"); 218 return 0; 219 } 220 cookies = new_cookies; 221 array_size *= 2; 222 } 223 } 224 225 cookies[i].id = i + 1; /* a return of 0 is used for failure */ 226 cookies[i].magic = magic; 227 cookies[i].data = data; 228 229 if (i == id_last) 230 id_last++; 231 232 return cookies[i].id; 233 } 234 235 DWORD get_Cookie_magic(DWORD id) 236 { 237 UINT index = id - 1; 238 239 if (index >= id_last) 240 return 0; 241 242 if (cookies[index].id == 0) 243 return 0; 244 245 return cookies[index].magic; 246 } 247 248 LPVOID get_Cookie_data(DWORD id) 249 { 250 UINT index = id - 1; 251 252 if (index >= id_last) 253 return NULL; 254 255 if (cookies[index].id == 0) 256 return NULL; 257 258 return cookies[index].data; 259 } 260 261 LPVOID remove_Cookie(DWORD id) 262 { 263 UINT index = id - 1; 264 265 if (index >= id_last) 266 return NULL; 267 268 if (cookies[index].id == 0) 269 return NULL; 270 271 cookies[index].id = 0; 272 return cookies[index].data; 273 } 274 275 DWORD enumerate_Cookie(DWORD magic, DWORD *index) 276 { 277 unsigned int i; 278 for (i = *index; i < id_last; i++) 279 if (cookies[i].id != 0 && cookies[i].magic == magic) 280 { 281 *index = (i+1); 282 return cookies[i].id; 283 } 284 return 0x0; 285 } 286 287 HRESULT advise_sink(struct list *sink_list, REFIID riid, DWORD cookie_magic, IUnknown *unk, DWORD *cookie) 288 { 289 Sink *sink; 290 291 sink = HeapAlloc(GetProcessHeap(), 0, sizeof(*sink)); 292 if (!sink) 293 return E_OUTOFMEMORY; 294 295 if (FAILED(IUnknown_QueryInterface(unk, riid, (void**)&sink->interfaces.pIUnknown))) 296 { 297 HeapFree(GetProcessHeap(), 0, sink); 298 return CONNECT_E_CANNOTCONNECT; 299 } 300 301 list_add_head(sink_list, &sink->entry); 302 *cookie = generate_Cookie(cookie_magic, sink); 303 TRACE("cookie %x\n", *cookie); 304 return S_OK; 305 } 306 307 static void free_sink(Sink *sink) 308 { 309 list_remove(&sink->entry); 310 IUnknown_Release(sink->interfaces.pIUnknown); 311 HeapFree(GetProcessHeap(), 0, sink); 312 } 313 314 HRESULT unadvise_sink(DWORD cookie) 315 { 316 Sink *sink; 317 318 sink = remove_Cookie(cookie); 319 if (!sink) 320 return CONNECT_E_NOCONNECTION; 321 322 free_sink(sink); 323 return S_OK; 324 } 325 326 void free_sinks(struct list *sink_list) 327 { 328 while(!list_empty(sink_list)) 329 { 330 Sink* sink = LIST_ENTRY(sink_list->next, Sink, entry); 331 free_sink(sink); 332 } 333 } 334 335 /***************************************************************************** 336 * Active Text Service Management 337 *****************************************************************************/ 338 static HRESULT activate_given_ts(ActivatedTextService *actsvr, ITfThreadMgrEx *tm) 339 { 340 HRESULT hr; 341 342 /* Already Active? */ 343 if (actsvr->pITfTextInputProcessor) 344 return S_OK; 345 346 hr = CoCreateInstance (&actsvr->LanguageProfile.clsid, NULL, CLSCTX_INPROC_SERVER, 347 &IID_ITfTextInputProcessor, (void**)&actsvr->pITfTextInputProcessor); 348 if (FAILED(hr)) return hr; 349 350 hr = ITfTextInputProcessor_Activate(actsvr->pITfTextInputProcessor, (ITfThreadMgr *)tm, actsvr->tid); 351 if (FAILED(hr)) 352 { 353 ITfTextInputProcessor_Release(actsvr->pITfTextInputProcessor); 354 actsvr->pITfTextInputProcessor = NULL; 355 return hr; 356 } 357 358 actsvr->pITfThreadMgrEx = tm; 359 ITfThreadMgrEx_AddRef(tm); 360 return hr; 361 } 362 363 static HRESULT deactivate_given_ts(ActivatedTextService *actsvr) 364 { 365 HRESULT hr = S_OK; 366 367 if (actsvr->pITfTextInputProcessor) 368 { 369 hr = ITfTextInputProcessor_Deactivate(actsvr->pITfTextInputProcessor); 370 ITfTextInputProcessor_Release(actsvr->pITfTextInputProcessor); 371 ITfThreadMgrEx_Release(actsvr->pITfThreadMgrEx); 372 actsvr->pITfTextInputProcessor = NULL; 373 actsvr->pITfThreadMgrEx = NULL; 374 } 375 376 return hr; 377 } 378 379 static void deactivate_remove_conflicting_ts(REFCLSID catid) 380 { 381 AtsEntry *ats, *cursor2; 382 383 LIST_FOR_EACH_ENTRY_SAFE(ats, cursor2, &AtsList, AtsEntry, entry) 384 { 385 if (IsEqualCLSID(catid,&ats->ats->LanguageProfile.catid)) 386 { 387 deactivate_given_ts(ats->ats); 388 list_remove(&ats->entry); 389 HeapFree(GetProcessHeap(),0,ats->ats); 390 HeapFree(GetProcessHeap(),0,ats); 391 /* we are guaranteeing there is only 1 */ 392 break; 393 } 394 } 395 } 396 397 HRESULT add_active_textservice(TF_LANGUAGEPROFILE *lp) 398 { 399 ActivatedTextService *actsvr; 400 ITfCategoryMgr *catmgr; 401 AtsEntry *entry; 402 ITfThreadMgrEx *tm = TlsGetValue(tlsIndex); 403 ITfClientId *clientid; 404 405 if (!tm) return E_UNEXPECTED; 406 407 actsvr = HeapAlloc(GetProcessHeap(),0,sizeof(ActivatedTextService)); 408 if (!actsvr) return E_OUTOFMEMORY; 409 410 ITfThreadMgrEx_QueryInterface(tm, &IID_ITfClientId, (void **)&clientid); 411 ITfClientId_GetClientId(clientid, &lp->clsid, &actsvr->tid); 412 ITfClientId_Release(clientid); 413 414 if (!actsvr->tid) 415 { 416 HeapFree(GetProcessHeap(),0,actsvr); 417 return E_OUTOFMEMORY; 418 } 419 420 actsvr->pITfTextInputProcessor = NULL; 421 actsvr->LanguageProfile = *lp; 422 actsvr->pITfKeyEventSink = NULL; 423 424 /* get TIP category */ 425 if (SUCCEEDED(CategoryMgr_Constructor(NULL,(IUnknown**)&catmgr))) 426 { 427 static const GUID *list[3] = {&GUID_TFCAT_TIP_SPEECH, &GUID_TFCAT_TIP_KEYBOARD, &GUID_TFCAT_TIP_HANDWRITING}; 428 429 ITfCategoryMgr_FindClosestCategory(catmgr, 430 &actsvr->LanguageProfile.clsid, &actsvr->LanguageProfile.catid, 431 list, 3); 432 433 ITfCategoryMgr_Release(catmgr); 434 } 435 else 436 { 437 ERR("CategoryMgr construction failed\n"); 438 actsvr->LanguageProfile.catid = GUID_NULL; 439 } 440 441 if (!IsEqualGUID(&actsvr->LanguageProfile.catid,&GUID_NULL)) 442 deactivate_remove_conflicting_ts(&actsvr->LanguageProfile.catid); 443 444 if (activated > 0) 445 activate_given_ts(actsvr, tm); 446 447 entry = HeapAlloc(GetProcessHeap(),0,sizeof(AtsEntry)); 448 449 if (!entry) 450 { 451 HeapFree(GetProcessHeap(),0,actsvr); 452 return E_OUTOFMEMORY; 453 } 454 455 entry->ats = actsvr; 456 list_add_head(&AtsList, &entry->entry); 457 458 return S_OK; 459 } 460 461 BOOL get_active_textservice(REFCLSID rclsid, TF_LANGUAGEPROFILE *profile) 462 { 463 AtsEntry *ats; 464 465 LIST_FOR_EACH_ENTRY(ats, &AtsList, AtsEntry, entry) 466 { 467 if (IsEqualCLSID(rclsid,&ats->ats->LanguageProfile.clsid)) 468 { 469 if (profile) 470 *profile = ats->ats->LanguageProfile; 471 return TRUE; 472 } 473 } 474 return FALSE; 475 } 476 477 HRESULT activate_textservices(ITfThreadMgrEx *tm) 478 { 479 HRESULT hr = S_OK; 480 AtsEntry *ats; 481 482 activated ++; 483 if (activated > 1) 484 return S_OK; 485 486 LIST_FOR_EACH_ENTRY(ats, &AtsList, AtsEntry, entry) 487 { 488 hr = activate_given_ts(ats->ats, tm); 489 if (FAILED(hr)) 490 FIXME("Failed to activate text service\n"); 491 } 492 return hr; 493 } 494 495 HRESULT deactivate_textservices(void) 496 { 497 AtsEntry *ats; 498 499 if (activated > 0) 500 activated --; 501 502 if (activated == 0) 503 LIST_FOR_EACH_ENTRY(ats, &AtsList, AtsEntry, entry) 504 deactivate_given_ts(ats->ats); 505 506 return S_OK; 507 } 508 509 CLSID get_textservice_clsid(TfClientId tid) 510 { 511 AtsEntry *ats; 512 513 LIST_FOR_EACH_ENTRY(ats, &AtsList, AtsEntry, entry) 514 if (ats->ats->tid == tid) 515 return ats->ats->LanguageProfile.clsid; 516 return GUID_NULL; 517 } 518 519 HRESULT get_textservice_sink(TfClientId tid, REFCLSID iid, IUnknown **sink) 520 { 521 AtsEntry *ats; 522 523 if (!IsEqualCLSID(iid,&IID_ITfKeyEventSink)) 524 return E_NOINTERFACE; 525 526 LIST_FOR_EACH_ENTRY(ats, &AtsList, AtsEntry, entry) 527 if (ats->ats->tid == tid) 528 { 529 *sink = (IUnknown*)ats->ats->pITfKeyEventSink; 530 return S_OK; 531 } 532 533 return E_FAIL; 534 } 535 536 HRESULT set_textservice_sink(TfClientId tid, REFCLSID iid, IUnknown* sink) 537 { 538 AtsEntry *ats; 539 540 if (!IsEqualCLSID(iid,&IID_ITfKeyEventSink)) 541 return E_NOINTERFACE; 542 543 LIST_FOR_EACH_ENTRY(ats, &AtsList, AtsEntry, entry) 544 if (ats->ats->tid == tid) 545 { 546 ats->ats->pITfKeyEventSink = (ITfKeyEventSink*)sink; 547 return S_OK; 548 } 549 550 return E_FAIL; 551 } 552 553 /************************************************************************* 554 * MSCTF DllMain 555 */ 556 BOOL WINAPI DllMain(HINSTANCE hinst, DWORD fdwReason, LPVOID fImpLoad) 557 { 558 TRACE("%p 0x%x %p\n", hinst, fdwReason, fImpLoad); 559 switch (fdwReason) 560 { 561 case DLL_WINE_PREATTACH: 562 return FALSE; /* prefer native version */ 563 case DLL_PROCESS_ATTACH: 564 MSCTF_hinstance = hinst; 565 tlsIndex = TlsAlloc(); 566 break; 567 case DLL_PROCESS_DETACH: 568 if (fImpLoad) break; 569 TlsFree(tlsIndex); 570 break; 571 } 572 return TRUE; 573 } 574 575 /************************************************************************* 576 * DllCanUnloadNow (MSCTF.@) 577 */ 578 HRESULT WINAPI DllCanUnloadNow(void) 579 { 580 return S_FALSE; 581 } 582 583 /*********************************************************************** 584 * DllGetClassObject (MSCTF.@) 585 */ 586 HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID iid, LPVOID *ppvOut) 587 { 588 int i; 589 590 *ppvOut = NULL; 591 if (!IsEqualIID(iid, &IID_IUnknown) && !IsEqualIID(iid, &IID_IClassFactory)) 592 return E_NOINTERFACE; 593 594 for (i = 0; ClassesTable[i].clsid != NULL; i++) 595 if (IsEqualCLSID(ClassesTable[i].clsid, clsid)) { 596 return ClassFactory_Constructor(ClassesTable[i].ctor, ppvOut); 597 } 598 FIXME("CLSID %s not supported\n", debugstr_guid(clsid)); 599 return CLASS_E_CLASSNOTAVAILABLE; 600 } 601 602 /*********************************************************************** 603 * DllRegisterServer (MSCTF.@) 604 */ 605 HRESULT WINAPI DllRegisterServer(void) 606 { 607 return __wine_register_resources( MSCTF_hinstance ); 608 } 609 610 /*********************************************************************** 611 * DllUnregisterServer (MSCTF.@) 612 */ 613 HRESULT WINAPI DllUnregisterServer(void) 614 { 615 return __wine_unregister_resources( MSCTF_hinstance ); 616 } 617 618 /*********************************************************************** 619 * TF_CreateThreadMgr (MSCTF.@) 620 */ 621 HRESULT WINAPI TF_CreateThreadMgr(ITfThreadMgr **pptim) 622 { 623 TRACE("\n"); 624 return ThreadMgr_Constructor(NULL,(IUnknown**)pptim); 625 } 626 627 /*********************************************************************** 628 * TF_GetThreadMgr (MSCTF.@) 629 */ 630 HRESULT WINAPI TF_GetThreadMgr(ITfThreadMgr **pptim) 631 { 632 TRACE("\n"); 633 *pptim = TlsGetValue(tlsIndex); 634 635 if (*pptim) 636 ITfThreadMgr_AddRef(*pptim); 637 638 return S_OK; 639 } 640 641 /*********************************************************************** 642 * SetInputScope(MSCTF.@) 643 */ 644 HRESULT WINAPI SetInputScope(HWND hwnd, InputScope inputscope) 645 { 646 FIXME("STUB: %p %i\n",hwnd,inputscope); 647 return S_OK; 648 } 649 650 /*********************************************************************** 651 * SetInputScopes(MSCTF.@) 652 */ 653 HRESULT WINAPI SetInputScopes(HWND hwnd, const InputScope *pInputScopes, 654 UINT cInputScopes, WCHAR **ppszPhraseList, 655 UINT cPhrases, WCHAR *pszRegExp, WCHAR *pszSRGS) 656 { 657 UINT i; 658 FIXME("STUB: %p ... %s %s\n",hwnd, debugstr_w(pszRegExp), debugstr_w(pszSRGS)); 659 for (i = 0; i < cInputScopes; i++) 660 TRACE("\tScope[%u] = %i\n",i,pInputScopes[i]); 661 for (i = 0; i < cPhrases; i++) 662 TRACE("\tPhrase[%u] = %s\n",i,debugstr_w(ppszPhraseList[i])); 663 664 return S_OK; 665 } 666 667 /*********************************************************************** 668 * TF_CreateInputProcessorProfiles(MSCTF.@) 669 */ 670 HRESULT WINAPI TF_CreateInputProcessorProfiles( 671 ITfInputProcessorProfiles **ppipr) 672 { 673 return InputProcessorProfiles_Constructor(NULL,(IUnknown**)ppipr); 674 } 675 676 /*********************************************************************** 677 * TF_InvalidAssemblyListCacheIfExist(MSCTF.@) 678 */ 679 HRESULT WINAPI TF_InvalidAssemblyListCacheIfExist(void) 680 { 681 FIXME("Stub\n"); 682 return S_OK; 683 } 684 685 /*********************************************************************** 686 * TF_CreateLangBarMgr (MSCTF.@) 687 */ 688 HRESULT WINAPI TF_CreateLangBarMgr(ITfLangBarMgr **pppbm) 689 { 690 TRACE("\n"); 691 return LangBarMgr_Constructor(NULL,(IUnknown**)pppbm); 692 } 693 694 HRESULT WINAPI TF_CreateLangBarItemMgr(ITfLangBarItemMgr **pplbim) 695 { 696 FIXME("stub %p\n", pplbim); 697 *pplbim = NULL; 698 699 return E_NOTIMPL; 700 } 701 702 /*********************************************************************** 703 * TF_InitMlngInfo (MSCTF.@) 704 */ 705 HRESULT WINAPI TF_InitMlngInfo(void) 706 { 707 FIXME("stub\n"); 708 return S_OK; 709 } 710