xref: /reactos/dll/win32/msctf/threadmgr.c (revision aad80191)
1 /*
2  *  ITfThreadMgr implementation
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 
25 #define COBJMACROS
26 
27 #include "wine/debug.h"
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winreg.h"
31 #include "winuser.h"
32 #include "shlwapi.h"
33 #include "winerror.h"
34 #include "objbase.h"
35 #include "olectl.h"
36 
37 #include "wine/unicode.h"
38 
39 #include "msctf.h"
40 #include "msctf_internal.h"
41 
42 WINE_DEFAULT_DEBUG_CHANNEL(msctf);
43 
44 typedef struct tagPreservedKey
45 {
46     struct list     entry;
47     GUID            guid;
48     TF_PRESERVEDKEY prekey;
49     LPWSTR          description;
50     TfClientId      tid;
51 } PreservedKey;
52 
53 typedef struct tagDocumentMgrs
54 {
55     struct list     entry;
56     ITfDocumentMgr  *docmgr;
57 } DocumentMgrEntry;
58 
59 typedef struct tagAssociatedWindow
60 {
61     struct list     entry;
62     HWND            hwnd;
63     ITfDocumentMgr  *docmgr;
64 } AssociatedWindow;
65 
66 typedef struct tagACLMulti {
67     ITfThreadMgrEx ITfThreadMgrEx_iface;
68     ITfSource ITfSource_iface;
69     ITfKeystrokeMgr ITfKeystrokeMgr_iface;
70     ITfMessagePump ITfMessagePump_iface;
71     ITfClientId ITfClientId_iface;
72     /* const ITfThreadMgrExVtbl *ThreadMgrExVtbl; */
73     /* const ITfConfigureSystemKeystrokeFeedVtbl *ConfigureSystemKeystrokeFeedVtbl; */
74     /* const ITfLangBarItemMgrVtbl *LangBarItemMgrVtbl; */
75     ITfUIElementMgr ITfUIElementMgr_iface;
76     ITfSourceSingle ITfSourceSingle_iface;
77     LONG refCount;
78 
79     /* Aggregation */
80     ITfCompartmentMgr  *CompartmentMgr;
81 
82     ITfThreadMgrEventSink ITfThreadMgrEventSink_iface; /* internal */
83 
84     ITfDocumentMgr *focus;
85     LONG activationCount;
86 
87     ITfKeyEventSink *foregroundKeyEventSink;
88     CLSID foregroundTextService;
89 
90     struct list CurrentPreservedKeys;
91     struct list CreatedDocumentMgrs;
92 
93     struct list AssociatedFocusWindows;
94     HHOOK  focusHook;
95 
96     /* kept as separate lists to reduce unnecessary iterations */
97     struct list     ActiveLanguageProfileNotifySink;
98     struct list     DisplayAttributeNotifySink;
99     struct list     KeyTraceEventSink;
100     struct list     PreservedKeyNotifySink;
101     struct list     ThreadFocusSink;
102     struct list     ThreadMgrEventSink;
103 } ThreadMgr;
104 
105 typedef struct tagEnumTfDocumentMgr {
106     IEnumTfDocumentMgrs IEnumTfDocumentMgrs_iface;
107     LONG refCount;
108 
109     struct list *index;
110     struct list *head;
111 } EnumTfDocumentMgr;
112 
113 static HRESULT EnumTfDocumentMgr_Constructor(struct list* head, IEnumTfDocumentMgrs **ppOut);
114 
115 static inline ThreadMgr *impl_from_ITfThreadMgrEx(ITfThreadMgrEx *iface)
116 {
117     return CONTAINING_RECORD(iface, ThreadMgr, ITfThreadMgrEx_iface);
118 }
119 
120 static inline ThreadMgr *impl_from_ITfSource(ITfSource *iface)
121 {
122     return CONTAINING_RECORD(iface, ThreadMgr, ITfSource_iface);
123 }
124 
125 static inline ThreadMgr *impl_from_ITfKeystrokeMgr(ITfKeystrokeMgr *iface)
126 {
127     return CONTAINING_RECORD(iface, ThreadMgr, ITfKeystrokeMgr_iface);
128 }
129 
130 static inline ThreadMgr *impl_from_ITfMessagePump(ITfMessagePump *iface)
131 {
132     return CONTAINING_RECORD(iface, ThreadMgr, ITfMessagePump_iface);
133 }
134 
135 static inline ThreadMgr *impl_from_ITfClientId(ITfClientId *iface)
136 {
137     return CONTAINING_RECORD(iface, ThreadMgr, ITfClientId_iface);
138 }
139 
140 static inline ThreadMgr *impl_from_ITfThreadMgrEventSink(ITfThreadMgrEventSink *iface)
141 {
142     return CONTAINING_RECORD(iface, ThreadMgr, ITfThreadMgrEventSink_iface);
143 }
144 
145 static inline ThreadMgr *impl_from_ITfUIElementMgr(ITfUIElementMgr *iface)
146 {
147     return CONTAINING_RECORD(iface, ThreadMgr, ITfUIElementMgr_iface);
148 }
149 
150 static inline ThreadMgr *impl_from_ITfSourceSingle(ITfSourceSingle *iface)
151 {
152     return CONTAINING_RECORD(iface, ThreadMgr, ITfSourceSingle_iface);
153 }
154 
155 static inline EnumTfDocumentMgr *impl_from_IEnumTfDocumentMgrs(IEnumTfDocumentMgrs *iface)
156 {
157     return CONTAINING_RECORD(iface, EnumTfDocumentMgr, IEnumTfDocumentMgrs_iface);
158 }
159 
160 static void ThreadMgr_Destructor(ThreadMgr *This)
161 {
162     struct list *cursor, *cursor2;
163 
164     /* unhook right away */
165     if (This->focusHook)
166         UnhookWindowsHookEx(This->focusHook);
167 
168     TlsSetValue(tlsIndex,NULL);
169     TRACE("destroying %p\n", This);
170     if (This->focus)
171         ITfDocumentMgr_Release(This->focus);
172 
173     free_sinks(&This->ActiveLanguageProfileNotifySink);
174     free_sinks(&This->DisplayAttributeNotifySink);
175     free_sinks(&This->KeyTraceEventSink);
176     free_sinks(&This->PreservedKeyNotifySink);
177     free_sinks(&This->ThreadFocusSink);
178     free_sinks(&This->ThreadMgrEventSink);
179 
180     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->CurrentPreservedKeys)
181     {
182         PreservedKey* key = LIST_ENTRY(cursor,PreservedKey,entry);
183         list_remove(cursor);
184         HeapFree(GetProcessHeap(),0,key->description);
185         HeapFree(GetProcessHeap(),0,key);
186     }
187 
188     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->CreatedDocumentMgrs)
189     {
190         DocumentMgrEntry *mgr = LIST_ENTRY(cursor,DocumentMgrEntry,entry);
191         list_remove(cursor);
192         FIXME("Left Over ITfDocumentMgr.  Should we do something with it?\n");
193         HeapFree(GetProcessHeap(),0,mgr);
194     }
195 
196     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->AssociatedFocusWindows)
197     {
198         AssociatedWindow *wnd = LIST_ENTRY(cursor,AssociatedWindow,entry);
199         list_remove(cursor);
200         HeapFree(GetProcessHeap(),0,wnd);
201     }
202 
203     CompartmentMgr_Destructor(This->CompartmentMgr);
204 
205     HeapFree(GetProcessHeap(),0,This);
206 }
207 
208 static HRESULT WINAPI ThreadMgr_QueryInterface(ITfThreadMgrEx *iface, REFIID iid, LPVOID *ppvOut)
209 {
210     ThreadMgr *This = impl_from_ITfThreadMgrEx(iface);
211     *ppvOut = NULL;
212 
213     if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfThreadMgr)
214         || IsEqualIID(iid, &IID_ITfThreadMgrEx))
215     {
216         *ppvOut = &This->ITfThreadMgrEx_iface;
217     }
218     else if (IsEqualIID(iid, &IID_ITfSource))
219     {
220         *ppvOut = &This->ITfSource_iface;
221     }
222     else if (IsEqualIID(iid, &IID_ITfKeystrokeMgr))
223     {
224         *ppvOut = &This->ITfKeystrokeMgr_iface;
225     }
226     else if (IsEqualIID(iid, &IID_ITfMessagePump))
227     {
228         *ppvOut = &This->ITfMessagePump_iface;
229     }
230     else if (IsEqualIID(iid, &IID_ITfClientId))
231     {
232         *ppvOut = &This->ITfClientId_iface;
233     }
234     else if (IsEqualIID(iid, &IID_ITfCompartmentMgr))
235     {
236         *ppvOut = This->CompartmentMgr;
237     }
238     else if (IsEqualIID(iid, &IID_ITfUIElementMgr))
239     {
240         *ppvOut = &This->ITfUIElementMgr_iface;
241     }
242     else if (IsEqualIID(iid, &IID_ITfSourceSingle))
243     {
244         *ppvOut = &This->ITfSourceSingle_iface;
245     }
246 
247     if (*ppvOut)
248     {
249         ITfThreadMgrEx_AddRef(iface);
250         return S_OK;
251     }
252 
253     WARN("unsupported interface: %s\n", debugstr_guid(iid));
254     return E_NOINTERFACE;
255 }
256 
257 static ULONG WINAPI ThreadMgr_AddRef(ITfThreadMgrEx *iface)
258 {
259     ThreadMgr *This = impl_from_ITfThreadMgrEx(iface);
260     return InterlockedIncrement(&This->refCount);
261 }
262 
263 static ULONG WINAPI ThreadMgr_Release(ITfThreadMgrEx *iface)
264 {
265     ThreadMgr *This = impl_from_ITfThreadMgrEx(iface);
266     ULONG ret;
267 
268     ret = InterlockedDecrement(&This->refCount);
269     if (ret == 0)
270         ThreadMgr_Destructor(This);
271     return ret;
272 }
273 
274 /*****************************************************
275  * ITfThreadMgr functions
276  *****************************************************/
277 
278 static HRESULT WINAPI ThreadMgr_Activate(ITfThreadMgrEx *iface, TfClientId *id)
279 {
280     ThreadMgr *This = impl_from_ITfThreadMgrEx(iface);
281 
282     TRACE("(%p) %p\n", This, id);
283     return ITfThreadMgrEx_ActivateEx(iface, id, 0);
284 }
285 
286 static HRESULT WINAPI ThreadMgr_Deactivate(ITfThreadMgrEx *iface)
287 {
288     ThreadMgr *This = impl_from_ITfThreadMgrEx(iface);
289     TRACE("(%p)\n",This);
290 
291     if (This->activationCount == 0)
292         return E_UNEXPECTED;
293 
294     This->activationCount --;
295 
296     if (This->activationCount == 0)
297     {
298         if (This->focus)
299         {
300             ITfThreadMgrEventSink_OnSetFocus(&This->ITfThreadMgrEventSink_iface, 0, This->focus);
301             ITfDocumentMgr_Release(This->focus);
302             This->focus = 0;
303         }
304     }
305 
306     deactivate_textservices();
307 
308     return S_OK;
309 }
310 
311 static HRESULT WINAPI ThreadMgr_CreateDocumentMgr(ITfThreadMgrEx *iface, ITfDocumentMgr **ppdim)
312 {
313     ThreadMgr *This = impl_from_ITfThreadMgrEx(iface);
314     DocumentMgrEntry *mgrentry;
315     HRESULT hr;
316 
317     TRACE("(%p)\n",iface);
318     mgrentry = HeapAlloc(GetProcessHeap(),0,sizeof(DocumentMgrEntry));
319     if (mgrentry == NULL)
320         return E_OUTOFMEMORY;
321 
322     hr = DocumentMgr_Constructor(&This->ITfThreadMgrEventSink_iface, ppdim);
323 
324     if (SUCCEEDED(hr))
325     {
326         mgrentry->docmgr = *ppdim;
327         list_add_head(&This->CreatedDocumentMgrs,&mgrentry->entry);
328     }
329     else
330         HeapFree(GetProcessHeap(),0,mgrentry);
331 
332     return hr;
333 }
334 
335 static HRESULT WINAPI ThreadMgr_EnumDocumentMgrs(ITfThreadMgrEx *iface, IEnumTfDocumentMgrs **ppEnum)
336 {
337     ThreadMgr *This = impl_from_ITfThreadMgrEx(iface);
338     TRACE("(%p) %p\n",This,ppEnum);
339 
340     if (!ppEnum)
341         return E_INVALIDARG;
342 
343     return EnumTfDocumentMgr_Constructor(&This->CreatedDocumentMgrs, ppEnum);
344 }
345 
346 static HRESULT WINAPI ThreadMgr_GetFocus(ITfThreadMgrEx *iface, ITfDocumentMgr **ppdimFocus)
347 {
348     ThreadMgr *This = impl_from_ITfThreadMgrEx(iface);
349     TRACE("(%p)\n",This);
350 
351     if (!ppdimFocus)
352         return E_INVALIDARG;
353 
354     *ppdimFocus = This->focus;
355 
356     TRACE("->%p\n",This->focus);
357 
358     if (This->focus == NULL)
359         return S_FALSE;
360 
361     ITfDocumentMgr_AddRef(This->focus);
362 
363     return S_OK;
364 }
365 
366 static HRESULT WINAPI ThreadMgr_SetFocus(ITfThreadMgrEx *iface, ITfDocumentMgr *pdimFocus)
367 {
368     ThreadMgr *This = impl_from_ITfThreadMgrEx(iface);
369     ITfDocumentMgr *check;
370 
371     TRACE("(%p) %p\n",This,pdimFocus);
372 
373     if (!pdimFocus)
374         check = NULL;
375     else if (FAILED(ITfDocumentMgr_QueryInterface(pdimFocus,&IID_ITfDocumentMgr,(LPVOID*) &check)))
376         return E_INVALIDARG;
377 
378     ITfThreadMgrEventSink_OnSetFocus(&This->ITfThreadMgrEventSink_iface, check, This->focus);
379 
380     if (This->focus)
381         ITfDocumentMgr_Release(This->focus);
382 
383     This->focus = check;
384     return S_OK;
385 }
386 
387 static LRESULT CALLBACK ThreadFocusHookProc(int nCode, WPARAM wParam, LPARAM lParam)
388 {
389     ThreadMgr *This;
390 
391     This = TlsGetValue(tlsIndex);
392     if (!This)
393     {
394         ERR("Hook proc but no ThreadMgr for this thread. Serious Error\n");
395         return 0;
396     }
397     if (!This->focusHook)
398     {
399         ERR("Hook proc but no ThreadMgr focus Hook. Serious Error\n");
400         return 0;
401     }
402 
403     if (nCode == HCBT_SETFOCUS) /* focus change within our thread */
404     {
405         struct list *cursor;
406 
407         LIST_FOR_EACH(cursor, &This->AssociatedFocusWindows)
408         {
409             AssociatedWindow *wnd = LIST_ENTRY(cursor,AssociatedWindow,entry);
410             if (wnd->hwnd == (HWND)wParam)
411             {
412                 TRACE("Triggering Associated window focus\n");
413                 if (This->focus != wnd->docmgr)
414                     ThreadMgr_SetFocus(&This->ITfThreadMgrEx_iface, wnd->docmgr);
415                 break;
416             }
417         }
418     }
419 
420     return CallNextHookEx(This->focusHook, nCode, wParam, lParam);
421 }
422 
423 static HRESULT SetupWindowsHook(ThreadMgr *This)
424 {
425     if (!This->focusHook)
426     {
427         This->focusHook = SetWindowsHookExW(WH_CBT, ThreadFocusHookProc, 0,
428                              GetCurrentThreadId());
429         if (!This->focusHook)
430         {
431             ERR("Unable to set focus hook\n");
432             return E_FAIL;
433         }
434         return S_OK;
435     }
436     return S_FALSE;
437 }
438 
439 static HRESULT WINAPI ThreadMgr_AssociateFocus(ITfThreadMgrEx *iface, HWND hwnd,
440 ITfDocumentMgr *pdimNew, ITfDocumentMgr **ppdimPrev)
441 {
442     ThreadMgr *This = impl_from_ITfThreadMgrEx(iface);
443     struct list *cursor, *cursor2;
444     AssociatedWindow *wnd;
445 
446     TRACE("(%p) %p %p %p\n",This,hwnd,pdimNew,ppdimPrev);
447 
448     if (!ppdimPrev)
449         return E_INVALIDARG;
450 
451     *ppdimPrev = NULL;
452 
453     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->AssociatedFocusWindows)
454     {
455         wnd = LIST_ENTRY(cursor,AssociatedWindow,entry);
456         if (wnd->hwnd == hwnd)
457         {
458             if (wnd->docmgr)
459                 ITfDocumentMgr_AddRef(wnd->docmgr);
460             *ppdimPrev = wnd->docmgr;
461             wnd->docmgr = pdimNew;
462             if (GetFocus() == hwnd)
463                 ThreadMgr_SetFocus(iface,pdimNew);
464             return S_OK;
465         }
466     }
467 
468     wnd = HeapAlloc(GetProcessHeap(),0,sizeof(AssociatedWindow));
469     wnd->hwnd = hwnd;
470     wnd->docmgr = pdimNew;
471     list_add_head(&This->AssociatedFocusWindows,&wnd->entry);
472 
473     if (GetFocus() == hwnd)
474         ThreadMgr_SetFocus(iface,pdimNew);
475 
476     SetupWindowsHook(This);
477 
478     return S_OK;
479 }
480 
481 static HRESULT WINAPI ThreadMgr_IsThreadFocus(ITfThreadMgrEx *iface, BOOL *pfThreadFocus)
482 {
483     ThreadMgr *This = impl_from_ITfThreadMgrEx(iface);
484     HWND focus;
485 
486     TRACE("(%p) %p\n",This,pfThreadFocus);
487     focus = GetFocus();
488     *pfThreadFocus = (focus == NULL);
489     return S_OK;
490 }
491 
492 static HRESULT WINAPI ThreadMgr_GetFunctionProvider(ITfThreadMgrEx *iface, REFCLSID clsid,
493 ITfFunctionProvider **ppFuncProv)
494 {
495     ThreadMgr *This = impl_from_ITfThreadMgrEx(iface);
496     FIXME("STUB:(%p)\n",This);
497     return E_NOTIMPL;
498 }
499 
500 static HRESULT WINAPI ThreadMgr_EnumFunctionProviders(ITfThreadMgrEx *iface,
501 IEnumTfFunctionProviders **ppEnum)
502 {
503     ThreadMgr *This = impl_from_ITfThreadMgrEx(iface);
504     FIXME("STUB:(%p)\n",This);
505     return E_NOTIMPL;
506 }
507 
508 static HRESULT WINAPI ThreadMgr_GetGlobalCompartment(ITfThreadMgrEx *iface,
509 ITfCompartmentMgr **ppCompMgr)
510 {
511     ThreadMgr *This = impl_from_ITfThreadMgrEx(iface);
512     HRESULT hr;
513     TRACE("(%p) %p\n",This, ppCompMgr);
514 
515     if (!ppCompMgr)
516         return E_INVALIDARG;
517 
518     if (!globalCompartmentMgr)
519     {
520         hr = CompartmentMgr_Constructor(NULL,&IID_ITfCompartmentMgr,(IUnknown**)&globalCompartmentMgr);
521         if (FAILED(hr))
522             return hr;
523     }
524 
525     ITfCompartmentMgr_AddRef(globalCompartmentMgr);
526     *ppCompMgr = globalCompartmentMgr;
527     return S_OK;
528 }
529 
530 static HRESULT WINAPI ThreadMgr_ActivateEx(ITfThreadMgrEx *iface, TfClientId *id, DWORD flags)
531 {
532     ThreadMgr *This = impl_from_ITfThreadMgrEx(iface);
533 
534     TRACE("(%p) %p, %#x\n", This, id, flags);
535 
536     if (!id)
537         return E_INVALIDARG;
538 
539     if (flags)
540         FIXME("Unimplemented flags %#x\n", flags);
541 
542     if (!processId)
543     {
544         GUID guid;
545         CoCreateGuid(&guid);
546         ITfClientId_GetClientId(&This->ITfClientId_iface, &guid, &processId);
547     }
548 
549     activate_textservices(iface);
550     This->activationCount++;
551     *id = processId;
552     return S_OK;
553 }
554 
555 static HRESULT WINAPI ThreadMgr_GetActiveFlags(ITfThreadMgrEx *iface, DWORD *flags)
556 {
557     ThreadMgr *This = impl_from_ITfThreadMgrEx(iface);
558 
559     FIXME("STUB:(%p)\n", This);
560     return E_NOTIMPL;
561 }
562 
563 static const ITfThreadMgrExVtbl ThreadMgrExVtbl =
564 {
565     ThreadMgr_QueryInterface,
566     ThreadMgr_AddRef,
567     ThreadMgr_Release,
568     ThreadMgr_Activate,
569     ThreadMgr_Deactivate,
570     ThreadMgr_CreateDocumentMgr,
571     ThreadMgr_EnumDocumentMgrs,
572     ThreadMgr_GetFocus,
573     ThreadMgr_SetFocus,
574     ThreadMgr_AssociateFocus,
575     ThreadMgr_IsThreadFocus,
576     ThreadMgr_GetFunctionProvider,
577     ThreadMgr_EnumFunctionProviders,
578     ThreadMgr_GetGlobalCompartment,
579 
580     ThreadMgr_ActivateEx,
581     ThreadMgr_GetActiveFlags
582 };
583 
584 static HRESULT WINAPI Source_QueryInterface(ITfSource *iface, REFIID iid, LPVOID *ppvOut)
585 {
586     ThreadMgr *This = impl_from_ITfSource(iface);
587     return ITfThreadMgrEx_QueryInterface(&This->ITfThreadMgrEx_iface, iid, ppvOut);
588 }
589 
590 static ULONG WINAPI Source_AddRef(ITfSource *iface)
591 {
592     ThreadMgr *This = impl_from_ITfSource(iface);
593     return ITfThreadMgrEx_AddRef(&This->ITfThreadMgrEx_iface);
594 }
595 
596 static ULONG WINAPI Source_Release(ITfSource *iface)
597 {
598     ThreadMgr *This = impl_from_ITfSource(iface);
599     return ITfThreadMgrEx_Release(&This->ITfThreadMgrEx_iface);
600 }
601 
602 /*****************************************************
603  * ITfSource functions
604  *****************************************************/
605 static HRESULT WINAPI ThreadMgrSource_AdviseSink(ITfSource *iface,
606         REFIID riid, IUnknown *punk, DWORD *pdwCookie)
607 {
608     ThreadMgr *This = impl_from_ITfSource(iface);
609 
610     TRACE("(%p) %s %p %p\n",This,debugstr_guid(riid),punk,pdwCookie);
611 
612     if (!riid || !punk || !pdwCookie)
613         return E_INVALIDARG;
614 
615     if (IsEqualIID(riid, &IID_ITfThreadMgrEventSink))
616         return advise_sink(&This->ThreadMgrEventSink, &IID_ITfThreadMgrEventSink, COOKIE_MAGIC_TMSINK, punk, pdwCookie);
617 
618     if (IsEqualIID(riid, &IID_ITfThreadFocusSink))
619     {
620         WARN("semi-stub for ITfThreadFocusSink: sink won't be used.\n");
621         return advise_sink(&This->ThreadFocusSink, &IID_ITfThreadFocusSink, COOKIE_MAGIC_THREADFOCUSSINK, punk, pdwCookie);
622     }
623 
624     if (IsEqualIID(riid, &IID_ITfKeyTraceEventSink))
625     {
626         WARN("semi-stub for ITfKeyTraceEventSink: sink won't be used.\n");
627         return advise_sink(&This->KeyTraceEventSink, &IID_ITfKeyTraceEventSink,
628                            COOKIE_MAGIC_KEYTRACESINK, punk, pdwCookie);
629     }
630 
631     FIXME("(%p) Unhandled Sink: %s\n",This,debugstr_guid(riid));
632     return E_NOTIMPL;
633 }
634 
635 static HRESULT WINAPI ThreadMgrSource_UnadviseSink(ITfSource *iface, DWORD pdwCookie)
636 {
637     ThreadMgr *This = impl_from_ITfSource(iface);
638     DWORD magic;
639 
640     TRACE("(%p) %x\n",This,pdwCookie);
641 
642     magic = get_Cookie_magic(pdwCookie);
643     if (magic != COOKIE_MAGIC_TMSINK && magic != COOKIE_MAGIC_THREADFOCUSSINK
644         && magic != COOKIE_MAGIC_KEYTRACESINK)
645         return E_INVALIDARG;
646 
647     return unadvise_sink(pdwCookie);
648 }
649 
650 static const ITfSourceVtbl ThreadMgrSourceVtbl =
651 {
652     Source_QueryInterface,
653     Source_AddRef,
654     Source_Release,
655     ThreadMgrSource_AdviseSink,
656     ThreadMgrSource_UnadviseSink,
657 };
658 
659 /*****************************************************
660  * ITfKeystrokeMgr functions
661  *****************************************************/
662 
663 static HRESULT WINAPI KeystrokeMgr_QueryInterface(ITfKeystrokeMgr *iface, REFIID iid, LPVOID *ppvOut)
664 {
665     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
666     return ITfThreadMgrEx_QueryInterface(&This->ITfThreadMgrEx_iface, iid, ppvOut);
667 }
668 
669 static ULONG WINAPI KeystrokeMgr_AddRef(ITfKeystrokeMgr *iface)
670 {
671     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
672     return ITfThreadMgrEx_AddRef(&This->ITfThreadMgrEx_iface);
673 }
674 
675 static ULONG WINAPI KeystrokeMgr_Release(ITfKeystrokeMgr *iface)
676 {
677     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
678     return ITfThreadMgrEx_Release(&This->ITfThreadMgrEx_iface);
679 }
680 
681 static HRESULT WINAPI KeystrokeMgr_AdviseKeyEventSink(ITfKeystrokeMgr *iface,
682         TfClientId tid, ITfKeyEventSink *pSink, BOOL fForeground)
683 {
684     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
685     CLSID textservice;
686     ITfKeyEventSink *check = NULL;
687 
688     TRACE("(%p) %x %p %i\n",This,tid,pSink,fForeground);
689 
690     if (!tid || !pSink)
691         return E_INVALIDARG;
692 
693     textservice = get_textservice_clsid(tid);
694     if (IsEqualCLSID(&GUID_NULL,&textservice))
695         return E_INVALIDARG;
696 
697     get_textservice_sink(tid, &IID_ITfKeyEventSink, (IUnknown**)&check);
698     if (check != NULL)
699         return CONNECT_E_ADVISELIMIT;
700 
701     if (FAILED(ITfKeyEventSink_QueryInterface(pSink,&IID_ITfKeyEventSink,(LPVOID*) &check)))
702         return E_INVALIDARG;
703 
704     set_textservice_sink(tid, &IID_ITfKeyEventSink, (IUnknown*)check);
705 
706     if (fForeground)
707     {
708         if (This->foregroundKeyEventSink)
709         {
710             ITfKeyEventSink_OnSetFocus(This->foregroundKeyEventSink, FALSE);
711             ITfKeyEventSink_Release(This->foregroundKeyEventSink);
712         }
713         ITfKeyEventSink_AddRef(check);
714         ITfKeyEventSink_OnSetFocus(check, TRUE);
715         This->foregroundKeyEventSink = check;
716         This->foregroundTextService = textservice;
717     }
718     return S_OK;
719 }
720 
721 static HRESULT WINAPI KeystrokeMgr_UnadviseKeyEventSink(ITfKeystrokeMgr *iface,
722         TfClientId tid)
723 {
724     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
725     CLSID textservice;
726     ITfKeyEventSink *check = NULL;
727     TRACE("(%p) %x\n",This,tid);
728 
729     if (!tid)
730         return E_INVALIDARG;
731 
732     textservice = get_textservice_clsid(tid);
733     if (IsEqualCLSID(&GUID_NULL,&textservice))
734         return E_INVALIDARG;
735 
736     get_textservice_sink(tid, &IID_ITfKeyEventSink, (IUnknown**)&check);
737 
738     if (!check)
739         return CONNECT_E_NOCONNECTION;
740 
741     set_textservice_sink(tid, &IID_ITfKeyEventSink, NULL);
742     ITfKeyEventSink_Release(check);
743 
744     if (This->foregroundKeyEventSink == check)
745     {
746         ITfKeyEventSink_Release(This->foregroundKeyEventSink);
747         This->foregroundKeyEventSink = NULL;
748         This->foregroundTextService = GUID_NULL;
749     }
750     return S_OK;
751 }
752 
753 static HRESULT WINAPI KeystrokeMgr_GetForeground(ITfKeystrokeMgr *iface,
754         CLSID *pclsid)
755 {
756     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
757     TRACE("(%p) %p\n",This,pclsid);
758     if (!pclsid)
759         return E_INVALIDARG;
760 
761     if (IsEqualCLSID(&This->foregroundTextService,&GUID_NULL))
762         return S_FALSE;
763 
764     *pclsid = This->foregroundTextService;
765     return S_OK;
766 }
767 
768 static HRESULT WINAPI KeystrokeMgr_TestKeyDown(ITfKeystrokeMgr *iface,
769         WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
770 {
771     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
772     FIXME("STUB:(%p)\n",This);
773     *pfEaten = FALSE;
774     return S_OK;
775 }
776 
777 static HRESULT WINAPI KeystrokeMgr_TestKeyUp(ITfKeystrokeMgr *iface,
778         WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
779 {
780     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
781     FIXME("STUB:(%p)\n",This);
782     *pfEaten = FALSE;
783     return S_OK;
784 }
785 
786 static HRESULT WINAPI KeystrokeMgr_KeyDown(ITfKeystrokeMgr *iface,
787         WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
788 {
789     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
790     FIXME("STUB:(%p)\n",This);
791     return E_NOTIMPL;
792 }
793 
794 static HRESULT WINAPI KeystrokeMgr_KeyUp(ITfKeystrokeMgr *iface,
795         WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
796 {
797     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
798     FIXME("STUB:(%p)\n",This);
799     return E_NOTIMPL;
800 }
801 
802 static HRESULT WINAPI KeystrokeMgr_GetPreservedKey(ITfKeystrokeMgr *iface,
803         ITfContext *pic, const TF_PRESERVEDKEY *pprekey, GUID *pguid)
804 {
805     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
806     FIXME("STUB:(%p)\n",This);
807     return E_NOTIMPL;
808 }
809 
810 static HRESULT WINAPI KeystrokeMgr_IsPreservedKey(ITfKeystrokeMgr *iface,
811         REFGUID rguid, const TF_PRESERVEDKEY *pprekey, BOOL *pfRegistered)
812 {
813     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
814     struct list *cursor;
815 
816     TRACE("(%p) %s (%x %x) %p\n",This,debugstr_guid(rguid), (pprekey)?pprekey->uVKey:0, (pprekey)?pprekey->uModifiers:0, pfRegistered);
817 
818     if (!rguid || !pprekey || !pfRegistered)
819         return E_INVALIDARG;
820 
821     LIST_FOR_EACH(cursor, &This->CurrentPreservedKeys)
822     {
823         PreservedKey* key = LIST_ENTRY(cursor,PreservedKey,entry);
824         if (IsEqualGUID(rguid,&key->guid) && pprekey->uVKey == key->prekey.uVKey && pprekey->uModifiers == key->prekey.uModifiers)
825         {
826             *pfRegistered = TRUE;
827             return S_OK;
828         }
829     }
830 
831     *pfRegistered = FALSE;
832     return S_FALSE;
833 }
834 
835 static HRESULT WINAPI KeystrokeMgr_PreserveKey(ITfKeystrokeMgr *iface,
836         TfClientId tid, REFGUID rguid, const TF_PRESERVEDKEY *prekey,
837         const WCHAR *pchDesc, ULONG cchDesc)
838 {
839     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
840     struct list *cursor;
841     PreservedKey *newkey;
842 
843     TRACE("(%p) %x %s (%x,%x) %s\n",This,tid, debugstr_guid(rguid),(prekey)?prekey->uVKey:0,(prekey)?prekey->uModifiers:0,debugstr_wn(pchDesc,cchDesc));
844 
845     if (!tid || ! rguid || !prekey || (cchDesc && !pchDesc))
846         return E_INVALIDARG;
847 
848     LIST_FOR_EACH(cursor, &This->CurrentPreservedKeys)
849     {
850         PreservedKey* key = LIST_ENTRY(cursor,PreservedKey,entry);
851         if (IsEqualGUID(rguid,&key->guid) && prekey->uVKey == key->prekey.uVKey && prekey->uModifiers == key->prekey.uModifiers)
852             return TF_E_ALREADY_EXISTS;
853     }
854 
855     newkey = HeapAlloc(GetProcessHeap(),0,sizeof(PreservedKey));
856     if (!newkey)
857         return E_OUTOFMEMORY;
858 
859     newkey->guid  = *rguid;
860     newkey->prekey = *prekey;
861     newkey->tid = tid;
862     newkey->description = NULL;
863     if (cchDesc)
864     {
865         newkey->description = HeapAlloc(GetProcessHeap(),0,cchDesc * sizeof(WCHAR));
866         if (!newkey->description)
867         {
868             HeapFree(GetProcessHeap(),0,newkey);
869             return E_OUTOFMEMORY;
870         }
871         memcpy(newkey->description, pchDesc, cchDesc*sizeof(WCHAR));
872     }
873 
874     list_add_head(&This->CurrentPreservedKeys,&newkey->entry);
875 
876     return S_OK;
877 }
878 
879 static HRESULT WINAPI KeystrokeMgr_UnpreserveKey(ITfKeystrokeMgr *iface,
880         REFGUID rguid, const TF_PRESERVEDKEY *pprekey)
881 {
882     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
883     PreservedKey* key = NULL;
884     struct list *cursor;
885     TRACE("(%p) %s (%x %x)\n",This,debugstr_guid(rguid),(pprekey)?pprekey->uVKey:0, (pprekey)?pprekey->uModifiers:0);
886 
887     if (!pprekey || !rguid)
888         return E_INVALIDARG;
889 
890     LIST_FOR_EACH(cursor, &This->CurrentPreservedKeys)
891     {
892         key = LIST_ENTRY(cursor,PreservedKey,entry);
893         if (IsEqualGUID(rguid,&key->guid) && pprekey->uVKey == key->prekey.uVKey && pprekey->uModifiers == key->prekey.uModifiers)
894             break;
895         key = NULL;
896     }
897 
898     if (!key)
899         return CONNECT_E_NOCONNECTION;
900 
901     list_remove(&key->entry);
902     HeapFree(GetProcessHeap(),0,key->description);
903     HeapFree(GetProcessHeap(),0,key);
904 
905     return S_OK;
906 }
907 
908 static HRESULT WINAPI KeystrokeMgr_SetPreservedKeyDescription(ITfKeystrokeMgr *iface,
909         REFGUID rguid, const WCHAR *pchDesc, ULONG cchDesc)
910 {
911     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
912     FIXME("STUB:(%p)\n",This);
913     return E_NOTIMPL;
914 }
915 
916 static HRESULT WINAPI KeystrokeMgr_GetPreservedKeyDescription(ITfKeystrokeMgr *iface,
917         REFGUID rguid, BSTR *pbstrDesc)
918 {
919     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
920     FIXME("STUB:(%p)\n",This);
921     return E_NOTIMPL;
922 }
923 
924 static HRESULT WINAPI KeystrokeMgr_SimulatePreservedKey(ITfKeystrokeMgr *iface,
925         ITfContext *pic, REFGUID rguid, BOOL *pfEaten)
926 {
927     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
928     FIXME("STUB:(%p)\n",This);
929     return E_NOTIMPL;
930 }
931 
932 static const ITfKeystrokeMgrVtbl KeystrokeMgrVtbl =
933 {
934     KeystrokeMgr_QueryInterface,
935     KeystrokeMgr_AddRef,
936     KeystrokeMgr_Release,
937     KeystrokeMgr_AdviseKeyEventSink,
938     KeystrokeMgr_UnadviseKeyEventSink,
939     KeystrokeMgr_GetForeground,
940     KeystrokeMgr_TestKeyDown,
941     KeystrokeMgr_TestKeyUp,
942     KeystrokeMgr_KeyDown,
943     KeystrokeMgr_KeyUp,
944     KeystrokeMgr_GetPreservedKey,
945     KeystrokeMgr_IsPreservedKey,
946     KeystrokeMgr_PreserveKey,
947     KeystrokeMgr_UnpreserveKey,
948     KeystrokeMgr_SetPreservedKeyDescription,
949     KeystrokeMgr_GetPreservedKeyDescription,
950     KeystrokeMgr_SimulatePreservedKey
951 };
952 
953 /*****************************************************
954  * ITfMessagePump functions
955  *****************************************************/
956 
957 static HRESULT WINAPI MessagePump_QueryInterface(ITfMessagePump *iface, REFIID iid, LPVOID *ppvOut)
958 {
959     ThreadMgr *This = impl_from_ITfMessagePump(iface);
960     return ITfThreadMgrEx_QueryInterface(&This->ITfThreadMgrEx_iface, iid, ppvOut);
961 }
962 
963 static ULONG WINAPI MessagePump_AddRef(ITfMessagePump *iface)
964 {
965     ThreadMgr *This = impl_from_ITfMessagePump(iface);
966     return ITfThreadMgrEx_AddRef(&This->ITfThreadMgrEx_iface);
967 }
968 
969 static ULONG WINAPI MessagePump_Release(ITfMessagePump *iface)
970 {
971     ThreadMgr *This = impl_from_ITfMessagePump(iface);
972     return ITfThreadMgrEx_Release(&This->ITfThreadMgrEx_iface);
973 }
974 
975 static HRESULT WINAPI MessagePump_PeekMessageA(ITfMessagePump *iface,
976         LPMSG pMsg, HWND hwnd, UINT wMsgFilterMin, UINT wMsgFilterMax,
977         UINT wRemoveMsg, BOOL *pfResult)
978 {
979     if (!pfResult)
980         return E_INVALIDARG;
981     *pfResult = PeekMessageA(pMsg, hwnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
982     return S_OK;
983 }
984 
985 static HRESULT WINAPI MessagePump_GetMessageA(ITfMessagePump *iface,
986         LPMSG pMsg, HWND hwnd, UINT wMsgFilterMin, UINT wMsgFilterMax,
987         BOOL *pfResult)
988 {
989     if (!pfResult)
990         return E_INVALIDARG;
991     *pfResult = GetMessageA(pMsg, hwnd, wMsgFilterMin, wMsgFilterMax);
992     return S_OK;
993 }
994 
995 static HRESULT WINAPI MessagePump_PeekMessageW(ITfMessagePump *iface,
996         LPMSG pMsg, HWND hwnd, UINT wMsgFilterMin, UINT wMsgFilterMax,
997         UINT wRemoveMsg, BOOL *pfResult)
998 {
999     if (!pfResult)
1000         return E_INVALIDARG;
1001     *pfResult = PeekMessageW(pMsg, hwnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
1002     return S_OK;
1003 }
1004 
1005 static HRESULT WINAPI MessagePump_GetMessageW(ITfMessagePump *iface,
1006         LPMSG pMsg, HWND hwnd, UINT wMsgFilterMin, UINT wMsgFilterMax,
1007         BOOL *pfResult)
1008 {
1009     if (!pfResult)
1010         return E_INVALIDARG;
1011     *pfResult = GetMessageW(pMsg, hwnd, wMsgFilterMin, wMsgFilterMax);
1012     return S_OK;
1013 }
1014 
1015 static const ITfMessagePumpVtbl MessagePumpVtbl =
1016 {
1017     MessagePump_QueryInterface,
1018     MessagePump_AddRef,
1019     MessagePump_Release,
1020     MessagePump_PeekMessageA,
1021     MessagePump_GetMessageA,
1022     MessagePump_PeekMessageW,
1023     MessagePump_GetMessageW
1024 };
1025 
1026 /*****************************************************
1027  * ITfClientId functions
1028  *****************************************************/
1029 
1030 static HRESULT WINAPI ClientId_QueryInterface(ITfClientId *iface, REFIID iid, LPVOID *ppvOut)
1031 {
1032     ThreadMgr *This = impl_from_ITfClientId(iface);
1033     return ITfThreadMgrEx_QueryInterface(&This->ITfThreadMgrEx_iface, iid, ppvOut);
1034 }
1035 
1036 static ULONG WINAPI ClientId_AddRef(ITfClientId *iface)
1037 {
1038     ThreadMgr *This = impl_from_ITfClientId(iface);
1039     return ITfThreadMgrEx_AddRef(&This->ITfThreadMgrEx_iface);
1040 }
1041 
1042 static ULONG WINAPI ClientId_Release(ITfClientId *iface)
1043 {
1044     ThreadMgr *This = impl_from_ITfClientId(iface);
1045     return ITfThreadMgrEx_Release(&This->ITfThreadMgrEx_iface);
1046 }
1047 
1048 static HRESULT WINAPI ClientId_GetClientId(ITfClientId *iface,
1049     REFCLSID rclsid, TfClientId *ptid)
1050 
1051 {
1052     ThreadMgr *This = impl_from_ITfClientId(iface);
1053     HRESULT hr;
1054     ITfCategoryMgr *catmgr;
1055 
1056     TRACE("(%p) %s\n",This,debugstr_guid(rclsid));
1057 
1058     CategoryMgr_Constructor(NULL,(IUnknown**)&catmgr);
1059     hr = ITfCategoryMgr_RegisterGUID(catmgr,rclsid,ptid);
1060     ITfCategoryMgr_Release(catmgr);
1061 
1062     return hr;
1063 }
1064 
1065 static const ITfClientIdVtbl ClientIdVtbl =
1066 {
1067     ClientId_QueryInterface,
1068     ClientId_AddRef,
1069     ClientId_Release,
1070     ClientId_GetClientId
1071 };
1072 
1073 /*****************************************************
1074  * ITfThreadMgrEventSink functions  (internal)
1075  *****************************************************/
1076 static HRESULT WINAPI ThreadMgrEventSink_QueryInterface(ITfThreadMgrEventSink *iface, REFIID iid, LPVOID *ppvOut)
1077 {
1078     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
1079     return ITfThreadMgrEx_QueryInterface(&This->ITfThreadMgrEx_iface, iid, ppvOut);
1080 }
1081 
1082 static ULONG WINAPI ThreadMgrEventSink_AddRef(ITfThreadMgrEventSink *iface)
1083 {
1084     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
1085     return ITfThreadMgrEx_AddRef(&This->ITfThreadMgrEx_iface);
1086 }
1087 
1088 static ULONG WINAPI ThreadMgrEventSink_Release(ITfThreadMgrEventSink *iface)
1089 {
1090     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
1091     return ITfThreadMgrEx_Release(&This->ITfThreadMgrEx_iface);
1092 }
1093 
1094 
1095 static HRESULT WINAPI ThreadMgrEventSink_OnInitDocumentMgr(
1096         ITfThreadMgrEventSink *iface,ITfDocumentMgr *pdim)
1097 {
1098     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
1099     ITfThreadMgrEventSink *sink;
1100     struct list *cursor;
1101 
1102     TRACE("(%p) %p\n",This,pdim);
1103 
1104     SINK_FOR_EACH(cursor, &This->ThreadMgrEventSink, ITfThreadMgrEventSink, sink)
1105     {
1106         ITfThreadMgrEventSink_OnInitDocumentMgr(sink, pdim);
1107     }
1108 
1109     return S_OK;
1110 }
1111 
1112 static HRESULT WINAPI ThreadMgrEventSink_OnUninitDocumentMgr(
1113         ITfThreadMgrEventSink *iface, ITfDocumentMgr *pdim)
1114 {
1115     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
1116     ITfThreadMgrEventSink *sink;
1117     struct list *cursor;
1118 
1119     TRACE("(%p) %p\n",This,pdim);
1120 
1121     SINK_FOR_EACH(cursor, &This->ThreadMgrEventSink, ITfThreadMgrEventSink, sink)
1122     {
1123         ITfThreadMgrEventSink_OnUninitDocumentMgr(sink, pdim);
1124     }
1125 
1126     return S_OK;
1127 }
1128 
1129 static HRESULT WINAPI ThreadMgrEventSink_OnSetFocus(
1130         ITfThreadMgrEventSink *iface, ITfDocumentMgr *pdimFocus,
1131         ITfDocumentMgr *pdimPrevFocus)
1132 {
1133     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
1134     ITfThreadMgrEventSink *sink;
1135     struct list *cursor;
1136 
1137     TRACE("(%p) %p %p\n",This,pdimFocus, pdimPrevFocus);
1138 
1139     SINK_FOR_EACH(cursor, &This->ThreadMgrEventSink, ITfThreadMgrEventSink, sink)
1140     {
1141         ITfThreadMgrEventSink_OnSetFocus(sink, pdimFocus, pdimPrevFocus);
1142     }
1143 
1144     return S_OK;
1145 }
1146 
1147 static HRESULT WINAPI ThreadMgrEventSink_OnPushContext(
1148         ITfThreadMgrEventSink *iface, ITfContext *pic)
1149 {
1150     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
1151     ITfThreadMgrEventSink *sink;
1152     struct list *cursor;
1153 
1154     TRACE("(%p) %p\n",This,pic);
1155 
1156     SINK_FOR_EACH(cursor, &This->ThreadMgrEventSink, ITfThreadMgrEventSink, sink)
1157     {
1158         ITfThreadMgrEventSink_OnPushContext(sink, pic);
1159     }
1160 
1161     return S_OK;
1162 }
1163 
1164 static HRESULT WINAPI ThreadMgrEventSink_OnPopContext(
1165         ITfThreadMgrEventSink *iface, ITfContext *pic)
1166 {
1167     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
1168     ITfThreadMgrEventSink *sink;
1169     struct list *cursor;
1170 
1171     TRACE("(%p) %p\n",This,pic);
1172 
1173     SINK_FOR_EACH(cursor, &This->ThreadMgrEventSink, ITfThreadMgrEventSink, sink)
1174     {
1175         ITfThreadMgrEventSink_OnPopContext(sink, pic);
1176     }
1177 
1178     return S_OK;
1179 }
1180 
1181 static const ITfThreadMgrEventSinkVtbl ThreadMgrEventSinkVtbl =
1182 {
1183     ThreadMgrEventSink_QueryInterface,
1184     ThreadMgrEventSink_AddRef,
1185     ThreadMgrEventSink_Release,
1186     ThreadMgrEventSink_OnInitDocumentMgr,
1187     ThreadMgrEventSink_OnUninitDocumentMgr,
1188     ThreadMgrEventSink_OnSetFocus,
1189     ThreadMgrEventSink_OnPushContext,
1190     ThreadMgrEventSink_OnPopContext
1191 };
1192 
1193 /*****************************************************
1194  * ITfUIElementMgr functions
1195  *****************************************************/
1196 static HRESULT WINAPI UIElementMgr_QueryInterface(ITfUIElementMgr *iface, REFIID iid, void **ppvOut)
1197 {
1198     ThreadMgr *This = impl_from_ITfUIElementMgr(iface);
1199 
1200     return ITfThreadMgrEx_QueryInterface(&This->ITfThreadMgrEx_iface, iid, ppvOut);
1201 }
1202 
1203 static ULONG WINAPI UIElementMgr_AddRef(ITfUIElementMgr *iface)
1204 {
1205     ThreadMgr *This = impl_from_ITfUIElementMgr(iface);
1206 
1207     return ITfThreadMgrEx_AddRef(&This->ITfThreadMgrEx_iface);
1208 }
1209 
1210 static ULONG WINAPI UIElementMgr_Release(ITfUIElementMgr *iface)
1211 {
1212     ThreadMgr *This = impl_from_ITfUIElementMgr(iface);
1213 
1214     return ITfThreadMgrEx_Release(&This->ITfThreadMgrEx_iface);
1215 }
1216 
1217 static HRESULT WINAPI UIElementMgr_BeginUIElement(ITfUIElementMgr *iface, ITfUIElement *element,
1218                                                   BOOL *show, DWORD *id)
1219 {
1220     ThreadMgr *This = impl_from_ITfUIElementMgr(iface);
1221 
1222     FIXME("STUB:(%p)\n", This);
1223     return E_NOTIMPL;
1224 }
1225 
1226 static HRESULT WINAPI UIElementMgr_UpdateUIElement(ITfUIElementMgr *iface, DWORD id)
1227 {
1228     ThreadMgr *This = impl_from_ITfUIElementMgr(iface);
1229 
1230     FIXME("STUB:(%p)\n", This);
1231     return E_NOTIMPL;
1232 }
1233 
1234 static HRESULT WINAPI UIElementMgr_EndUIElement(ITfUIElementMgr *iface, DWORD id)
1235 {
1236     ThreadMgr *This = impl_from_ITfUIElementMgr(iface);
1237 
1238     FIXME("STUB:(%p)\n", This);
1239     return E_NOTIMPL;
1240 }
1241 
1242 static HRESULT WINAPI UIElementMgr_GetUIElement(ITfUIElementMgr *iface, DWORD id,
1243                                                 ITfUIElement **element)
1244 {
1245     ThreadMgr *This = impl_from_ITfUIElementMgr(iface);
1246 
1247     FIXME("STUB:(%p)\n", This);
1248     return E_NOTIMPL;
1249 }
1250 
1251 static HRESULT WINAPI UIElementMgr_EnumUIElements(ITfUIElementMgr *iface,
1252                                                   IEnumTfUIElements **enum_elements)
1253 {
1254     ThreadMgr *This = impl_from_ITfUIElementMgr(iface);
1255 
1256     FIXME("STUB:(%p)\n", This);
1257     return E_NOTIMPL;
1258 }
1259 
1260 static const ITfUIElementMgrVtbl ThreadMgrUIElementMgrVtbl =
1261 {
1262     UIElementMgr_QueryInterface,
1263     UIElementMgr_AddRef,
1264     UIElementMgr_Release,
1265 
1266     UIElementMgr_BeginUIElement,
1267     UIElementMgr_UpdateUIElement,
1268     UIElementMgr_EndUIElement,
1269     UIElementMgr_GetUIElement,
1270     UIElementMgr_EnumUIElements
1271 };
1272 
1273 /*****************************************************
1274  * ITfSourceSingle functions
1275  *****************************************************/
1276 static HRESULT WINAPI ThreadMgrSourceSingle_QueryInterface(ITfSourceSingle *iface, REFIID iid, LPVOID *ppvOut)
1277 {
1278     ThreadMgr *This = impl_from_ITfSourceSingle(iface);
1279     return ITfThreadMgrEx_QueryInterface(&This->ITfThreadMgrEx_iface, iid, ppvOut);
1280 }
1281 
1282 static ULONG WINAPI ThreadMgrSourceSingle_AddRef(ITfSourceSingle *iface)
1283 {
1284     ThreadMgr *This = impl_from_ITfSourceSingle(iface);
1285     return ITfThreadMgrEx_AddRef(&This->ITfThreadMgrEx_iface);
1286 }
1287 
1288 static ULONG WINAPI ThreadMgrSourceSingle_Release(ITfSourceSingle *iface)
1289 {
1290     ThreadMgr *This = impl_from_ITfSourceSingle(iface);
1291     return ITfThreadMgrEx_Release(&This->ITfThreadMgrEx_iface);
1292 }
1293 
1294 static HRESULT WINAPI ThreadMgrSourceSingle_AdviseSingleSink( ITfSourceSingle *iface,
1295     TfClientId tid, REFIID riid, IUnknown *punk)
1296 {
1297     ThreadMgr *This = impl_from_ITfSourceSingle(iface);
1298     FIXME("STUB:(%p) %i %s %p\n",This, tid, debugstr_guid(riid),punk);
1299     return E_NOTIMPL;
1300 }
1301 
1302 static HRESULT WINAPI ThreadMgrSourceSingle_UnadviseSingleSink( ITfSourceSingle *iface,
1303     TfClientId tid, REFIID riid)
1304 {
1305     ThreadMgr *This = impl_from_ITfSourceSingle(iface);
1306     FIXME("STUB:(%p) %i %s\n",This, tid, debugstr_guid(riid));
1307     return E_NOTIMPL;
1308 }
1309 
1310 static const ITfSourceSingleVtbl SourceSingleVtbl =
1311 {
1312     ThreadMgrSourceSingle_QueryInterface,
1313     ThreadMgrSourceSingle_AddRef,
1314     ThreadMgrSourceSingle_Release,
1315     ThreadMgrSourceSingle_AdviseSingleSink,
1316     ThreadMgrSourceSingle_UnadviseSingleSink
1317 };
1318 
1319 HRESULT ThreadMgr_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut)
1320 {
1321     ThreadMgr *This;
1322     if (pUnkOuter)
1323         return CLASS_E_NOAGGREGATION;
1324 
1325     /* Only 1 ThreadMgr is created per thread */
1326     This = TlsGetValue(tlsIndex);
1327     if (This)
1328     {
1329         ThreadMgr_AddRef(&This->ITfThreadMgrEx_iface);
1330         *ppOut = (IUnknown*)&This->ITfThreadMgrEx_iface;
1331         return S_OK;
1332     }
1333 
1334     This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ThreadMgr));
1335     if (This == NULL)
1336         return E_OUTOFMEMORY;
1337 
1338     This->ITfThreadMgrEx_iface.lpVtbl = &ThreadMgrExVtbl;
1339     This->ITfSource_iface.lpVtbl = &ThreadMgrSourceVtbl;
1340     This->ITfKeystrokeMgr_iface.lpVtbl = &KeystrokeMgrVtbl;
1341     This->ITfMessagePump_iface.lpVtbl = &MessagePumpVtbl;
1342     This->ITfClientId_iface.lpVtbl = &ClientIdVtbl;
1343     This->ITfThreadMgrEventSink_iface.lpVtbl = &ThreadMgrEventSinkVtbl;
1344     This->ITfUIElementMgr_iface.lpVtbl = &ThreadMgrUIElementMgrVtbl;
1345     This->ITfSourceSingle_iface.lpVtbl = &SourceSingleVtbl;
1346     This->refCount = 1;
1347     TlsSetValue(tlsIndex,This);
1348 
1349     CompartmentMgr_Constructor((IUnknown*)&This->ITfThreadMgrEx_iface, &IID_IUnknown, (IUnknown**)&This->CompartmentMgr);
1350 
1351     list_init(&This->CurrentPreservedKeys);
1352     list_init(&This->CreatedDocumentMgrs);
1353     list_init(&This->AssociatedFocusWindows);
1354 
1355     list_init(&This->ActiveLanguageProfileNotifySink);
1356     list_init(&This->DisplayAttributeNotifySink);
1357     list_init(&This->KeyTraceEventSink);
1358     list_init(&This->PreservedKeyNotifySink);
1359     list_init(&This->ThreadFocusSink);
1360     list_init(&This->ThreadMgrEventSink);
1361 
1362     TRACE("returning %p\n", This);
1363     *ppOut = (IUnknown *)&This->ITfThreadMgrEx_iface;
1364     return S_OK;
1365 }
1366 
1367 /**************************************************
1368  * IEnumTfDocumentMgrs implementation
1369  **************************************************/
1370 static void EnumTfDocumentMgr_Destructor(EnumTfDocumentMgr *This)
1371 {
1372     TRACE("destroying %p\n", This);
1373     HeapFree(GetProcessHeap(),0,This);
1374 }
1375 
1376 static HRESULT WINAPI EnumTfDocumentMgr_QueryInterface(IEnumTfDocumentMgrs *iface, REFIID iid, LPVOID *ppvOut)
1377 {
1378     EnumTfDocumentMgr *This = impl_from_IEnumTfDocumentMgrs(iface);
1379     *ppvOut = NULL;
1380 
1381     if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IEnumTfDocumentMgrs))
1382     {
1383         *ppvOut = &This->IEnumTfDocumentMgrs_iface;
1384     }
1385 
1386     if (*ppvOut)
1387     {
1388         IEnumTfDocumentMgrs_AddRef(iface);
1389         return S_OK;
1390     }
1391 
1392     WARN("unsupported interface: %s\n", debugstr_guid(iid));
1393     return E_NOINTERFACE;
1394 }
1395 
1396 static ULONG WINAPI EnumTfDocumentMgr_AddRef(IEnumTfDocumentMgrs *iface)
1397 {
1398     EnumTfDocumentMgr *This = impl_from_IEnumTfDocumentMgrs(iface);
1399     return InterlockedIncrement(&This->refCount);
1400 }
1401 
1402 static ULONG WINAPI EnumTfDocumentMgr_Release(IEnumTfDocumentMgrs *iface)
1403 {
1404     EnumTfDocumentMgr *This = impl_from_IEnumTfDocumentMgrs(iface);
1405     ULONG ret;
1406 
1407     ret = InterlockedDecrement(&This->refCount);
1408     if (ret == 0)
1409         EnumTfDocumentMgr_Destructor(This);
1410     return ret;
1411 }
1412 
1413 static HRESULT WINAPI EnumTfDocumentMgr_Next(IEnumTfDocumentMgrs *iface,
1414     ULONG ulCount, ITfDocumentMgr **rgDocumentMgr, ULONG *pcFetched)
1415 {
1416     EnumTfDocumentMgr *This = impl_from_IEnumTfDocumentMgrs(iface);
1417     ULONG fetched = 0;
1418 
1419     TRACE("(%p)\n",This);
1420 
1421     if (rgDocumentMgr == NULL) return E_POINTER;
1422 
1423     while (fetched < ulCount)
1424     {
1425         DocumentMgrEntry *mgrentry;
1426         if (This->index == NULL)
1427             break;
1428 
1429         mgrentry = LIST_ENTRY(This->index,DocumentMgrEntry,entry);
1430         if (mgrentry == NULL)
1431             break;
1432 
1433         *rgDocumentMgr = mgrentry->docmgr;
1434         ITfDocumentMgr_AddRef(*rgDocumentMgr);
1435 
1436         This->index = list_next(This->head, This->index);
1437         ++fetched;
1438         ++rgDocumentMgr;
1439     }
1440 
1441     if (pcFetched) *pcFetched = fetched;
1442     return fetched == ulCount ? S_OK : S_FALSE;
1443 }
1444 
1445 static HRESULT WINAPI EnumTfDocumentMgr_Skip( IEnumTfDocumentMgrs* iface, ULONG celt)
1446 {
1447     EnumTfDocumentMgr *This = impl_from_IEnumTfDocumentMgrs(iface);
1448     ULONG i;
1449 
1450     TRACE("(%p)\n",This);
1451     for(i = 0; i < celt && This->index != NULL; i++)
1452         This->index = list_next(This->head, This->index);
1453     return S_OK;
1454 }
1455 
1456 static HRESULT WINAPI EnumTfDocumentMgr_Reset( IEnumTfDocumentMgrs* iface)
1457 {
1458     EnumTfDocumentMgr *This = impl_from_IEnumTfDocumentMgrs(iface);
1459     TRACE("(%p)\n",This);
1460     This->index = list_head(This->head);
1461     return S_OK;
1462 }
1463 
1464 static HRESULT WINAPI EnumTfDocumentMgr_Clone( IEnumTfDocumentMgrs *iface,
1465     IEnumTfDocumentMgrs **ppenum)
1466 {
1467     EnumTfDocumentMgr *This = impl_from_IEnumTfDocumentMgrs(iface);
1468     HRESULT res;
1469 
1470     TRACE("(%p)\n",This);
1471 
1472     if (ppenum == NULL) return E_POINTER;
1473 
1474     res = EnumTfDocumentMgr_Constructor(This->head, ppenum);
1475     if (SUCCEEDED(res))
1476     {
1477         EnumTfDocumentMgr *new_This = impl_from_IEnumTfDocumentMgrs(*ppenum);
1478         new_This->index = This->index;
1479     }
1480     return res;
1481 }
1482 
1483 static const IEnumTfDocumentMgrsVtbl EnumTfDocumentMgrsVtbl =
1484 {
1485     EnumTfDocumentMgr_QueryInterface,
1486     EnumTfDocumentMgr_AddRef,
1487     EnumTfDocumentMgr_Release,
1488     EnumTfDocumentMgr_Clone,
1489     EnumTfDocumentMgr_Next,
1490     EnumTfDocumentMgr_Reset,
1491     EnumTfDocumentMgr_Skip
1492 };
1493 
1494 static HRESULT EnumTfDocumentMgr_Constructor(struct list* head, IEnumTfDocumentMgrs **ppOut)
1495 {
1496     EnumTfDocumentMgr *This;
1497 
1498     This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(EnumTfDocumentMgr));
1499     if (This == NULL)
1500         return E_OUTOFMEMORY;
1501 
1502     This->IEnumTfDocumentMgrs_iface.lpVtbl= &EnumTfDocumentMgrsVtbl;
1503     This->refCount = 1;
1504     This->head = head;
1505     This->index = list_head(This->head);
1506 
1507     TRACE("returning %p\n", &This->IEnumTfDocumentMgrs_iface);
1508     *ppOut = &This->IEnumTfDocumentMgrs_iface;
1509     return S_OK;
1510 }
1511 
1512 void ThreadMgr_OnDocumentMgrDestruction(ITfThreadMgr *iface, ITfDocumentMgr *mgr)
1513 {
1514     ThreadMgr *This = impl_from_ITfThreadMgrEx((ITfThreadMgrEx *)iface);
1515     struct list *cursor;
1516     LIST_FOR_EACH(cursor, &This->CreatedDocumentMgrs)
1517     {
1518         DocumentMgrEntry *mgrentry = LIST_ENTRY(cursor,DocumentMgrEntry,entry);
1519         if (mgrentry->docmgr == mgr)
1520         {
1521             list_remove(cursor);
1522             HeapFree(GetProcessHeap(),0,mgrentry);
1523             return;
1524         }
1525     }
1526     FIXME("ITfDocumentMgr %p not found in this thread\n",mgr);
1527 }
1528