xref: /reactos/dll/win32/msctf/threadmgr.c (revision d5b576b2)
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     FIXME("(%p) Unhandled Sink: %s\n",This,debugstr_guid(riid));
625     return E_NOTIMPL;
626 }
627 
628 static HRESULT WINAPI ThreadMgrSource_UnadviseSink(ITfSource *iface, DWORD pdwCookie)
629 {
630     ThreadMgr *This = impl_from_ITfSource(iface);
631 
632     TRACE("(%p) %x\n",This,pdwCookie);
633 
634     if (get_Cookie_magic(pdwCookie) != COOKIE_MAGIC_TMSINK && get_Cookie_magic(pdwCookie) != COOKIE_MAGIC_THREADFOCUSSINK)
635         return E_INVALIDARG;
636 
637     return unadvise_sink(pdwCookie);
638 }
639 
640 static const ITfSourceVtbl ThreadMgrSourceVtbl =
641 {
642     Source_QueryInterface,
643     Source_AddRef,
644     Source_Release,
645     ThreadMgrSource_AdviseSink,
646     ThreadMgrSource_UnadviseSink,
647 };
648 
649 /*****************************************************
650  * ITfKeystrokeMgr functions
651  *****************************************************/
652 
653 static HRESULT WINAPI KeystrokeMgr_QueryInterface(ITfKeystrokeMgr *iface, REFIID iid, LPVOID *ppvOut)
654 {
655     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
656     return ITfThreadMgrEx_QueryInterface(&This->ITfThreadMgrEx_iface, iid, ppvOut);
657 }
658 
659 static ULONG WINAPI KeystrokeMgr_AddRef(ITfKeystrokeMgr *iface)
660 {
661     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
662     return ITfThreadMgrEx_AddRef(&This->ITfThreadMgrEx_iface);
663 }
664 
665 static ULONG WINAPI KeystrokeMgr_Release(ITfKeystrokeMgr *iface)
666 {
667     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
668     return ITfThreadMgrEx_Release(&This->ITfThreadMgrEx_iface);
669 }
670 
671 static HRESULT WINAPI KeystrokeMgr_AdviseKeyEventSink(ITfKeystrokeMgr *iface,
672         TfClientId tid, ITfKeyEventSink *pSink, BOOL fForeground)
673 {
674     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
675     CLSID textservice;
676     ITfKeyEventSink *check = NULL;
677 
678     TRACE("(%p) %x %p %i\n",This,tid,pSink,fForeground);
679 
680     if (!tid || !pSink)
681         return E_INVALIDARG;
682 
683     textservice = get_textservice_clsid(tid);
684     if (IsEqualCLSID(&GUID_NULL,&textservice))
685         return E_INVALIDARG;
686 
687     get_textservice_sink(tid, &IID_ITfKeyEventSink, (IUnknown**)&check);
688     if (check != NULL)
689         return CONNECT_E_ADVISELIMIT;
690 
691     if (FAILED(ITfKeyEventSink_QueryInterface(pSink,&IID_ITfKeyEventSink,(LPVOID*) &check)))
692         return E_INVALIDARG;
693 
694     set_textservice_sink(tid, &IID_ITfKeyEventSink, (IUnknown*)check);
695 
696     if (fForeground)
697     {
698         if (This->foregroundKeyEventSink)
699         {
700             ITfKeyEventSink_OnSetFocus(This->foregroundKeyEventSink, FALSE);
701             ITfKeyEventSink_Release(This->foregroundKeyEventSink);
702         }
703         ITfKeyEventSink_AddRef(check);
704         ITfKeyEventSink_OnSetFocus(check, TRUE);
705         This->foregroundKeyEventSink = check;
706         This->foregroundTextService = textservice;
707     }
708     return S_OK;
709 }
710 
711 static HRESULT WINAPI KeystrokeMgr_UnadviseKeyEventSink(ITfKeystrokeMgr *iface,
712         TfClientId tid)
713 {
714     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
715     CLSID textservice;
716     ITfKeyEventSink *check = NULL;
717     TRACE("(%p) %x\n",This,tid);
718 
719     if (!tid)
720         return E_INVALIDARG;
721 
722     textservice = get_textservice_clsid(tid);
723     if (IsEqualCLSID(&GUID_NULL,&textservice))
724         return E_INVALIDARG;
725 
726     get_textservice_sink(tid, &IID_ITfKeyEventSink, (IUnknown**)&check);
727 
728     if (!check)
729         return CONNECT_E_NOCONNECTION;
730 
731     set_textservice_sink(tid, &IID_ITfKeyEventSink, NULL);
732     ITfKeyEventSink_Release(check);
733 
734     if (This->foregroundKeyEventSink == check)
735     {
736         ITfKeyEventSink_Release(This->foregroundKeyEventSink);
737         This->foregroundKeyEventSink = NULL;
738         This->foregroundTextService = GUID_NULL;
739     }
740     return S_OK;
741 }
742 
743 static HRESULT WINAPI KeystrokeMgr_GetForeground(ITfKeystrokeMgr *iface,
744         CLSID *pclsid)
745 {
746     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
747     TRACE("(%p) %p\n",This,pclsid);
748     if (!pclsid)
749         return E_INVALIDARG;
750 
751     if (IsEqualCLSID(&This->foregroundTextService,&GUID_NULL))
752         return S_FALSE;
753 
754     *pclsid = This->foregroundTextService;
755     return S_OK;
756 }
757 
758 static HRESULT WINAPI KeystrokeMgr_TestKeyDown(ITfKeystrokeMgr *iface,
759         WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
760 {
761     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
762     FIXME("STUB:(%p)\n",This);
763     *pfEaten = FALSE;
764     return S_OK;
765 }
766 
767 static HRESULT WINAPI KeystrokeMgr_TestKeyUp(ITfKeystrokeMgr *iface,
768         WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
769 {
770     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
771     FIXME("STUB:(%p)\n",This);
772     *pfEaten = FALSE;
773     return S_OK;
774 }
775 
776 static HRESULT WINAPI KeystrokeMgr_KeyDown(ITfKeystrokeMgr *iface,
777         WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
778 {
779     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
780     FIXME("STUB:(%p)\n",This);
781     return E_NOTIMPL;
782 }
783 
784 static HRESULT WINAPI KeystrokeMgr_KeyUp(ITfKeystrokeMgr *iface,
785         WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
786 {
787     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
788     FIXME("STUB:(%p)\n",This);
789     return E_NOTIMPL;
790 }
791 
792 static HRESULT WINAPI KeystrokeMgr_GetPreservedKey(ITfKeystrokeMgr *iface,
793         ITfContext *pic, const TF_PRESERVEDKEY *pprekey, GUID *pguid)
794 {
795     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
796     FIXME("STUB:(%p)\n",This);
797     return E_NOTIMPL;
798 }
799 
800 static HRESULT WINAPI KeystrokeMgr_IsPreservedKey(ITfKeystrokeMgr *iface,
801         REFGUID rguid, const TF_PRESERVEDKEY *pprekey, BOOL *pfRegistered)
802 {
803     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
804     struct list *cursor;
805 
806     TRACE("(%p) %s (%x %x) %p\n",This,debugstr_guid(rguid), (pprekey)?pprekey->uVKey:0, (pprekey)?pprekey->uModifiers:0, pfRegistered);
807 
808     if (!rguid || !pprekey || !pfRegistered)
809         return E_INVALIDARG;
810 
811     LIST_FOR_EACH(cursor, &This->CurrentPreservedKeys)
812     {
813         PreservedKey* key = LIST_ENTRY(cursor,PreservedKey,entry);
814         if (IsEqualGUID(rguid,&key->guid) && pprekey->uVKey == key->prekey.uVKey && pprekey->uModifiers == key->prekey.uModifiers)
815         {
816             *pfRegistered = TRUE;
817             return S_OK;
818         }
819     }
820 
821     *pfRegistered = FALSE;
822     return S_FALSE;
823 }
824 
825 static HRESULT WINAPI KeystrokeMgr_PreserveKey(ITfKeystrokeMgr *iface,
826         TfClientId tid, REFGUID rguid, const TF_PRESERVEDKEY *prekey,
827         const WCHAR *pchDesc, ULONG cchDesc)
828 {
829     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
830     struct list *cursor;
831     PreservedKey *newkey;
832 
833     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));
834 
835     if (!tid || ! rguid || !prekey || (cchDesc && !pchDesc))
836         return E_INVALIDARG;
837 
838     LIST_FOR_EACH(cursor, &This->CurrentPreservedKeys)
839     {
840         PreservedKey* key = LIST_ENTRY(cursor,PreservedKey,entry);
841         if (IsEqualGUID(rguid,&key->guid) && prekey->uVKey == key->prekey.uVKey && prekey->uModifiers == key->prekey.uModifiers)
842             return TF_E_ALREADY_EXISTS;
843     }
844 
845     newkey = HeapAlloc(GetProcessHeap(),0,sizeof(PreservedKey));
846     if (!newkey)
847         return E_OUTOFMEMORY;
848 
849     newkey->guid  = *rguid;
850     newkey->prekey = *prekey;
851     newkey->tid = tid;
852     newkey->description = NULL;
853     if (cchDesc)
854     {
855         newkey->description = HeapAlloc(GetProcessHeap(),0,cchDesc * sizeof(WCHAR));
856         if (!newkey->description)
857         {
858             HeapFree(GetProcessHeap(),0,newkey);
859             return E_OUTOFMEMORY;
860         }
861         memcpy(newkey->description, pchDesc, cchDesc*sizeof(WCHAR));
862     }
863 
864     list_add_head(&This->CurrentPreservedKeys,&newkey->entry);
865 
866     return S_OK;
867 }
868 
869 static HRESULT WINAPI KeystrokeMgr_UnpreserveKey(ITfKeystrokeMgr *iface,
870         REFGUID rguid, const TF_PRESERVEDKEY *pprekey)
871 {
872     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
873     PreservedKey* key = NULL;
874     struct list *cursor;
875     TRACE("(%p) %s (%x %x)\n",This,debugstr_guid(rguid),(pprekey)?pprekey->uVKey:0, (pprekey)?pprekey->uModifiers:0);
876 
877     if (!pprekey || !rguid)
878         return E_INVALIDARG;
879 
880     LIST_FOR_EACH(cursor, &This->CurrentPreservedKeys)
881     {
882         key = LIST_ENTRY(cursor,PreservedKey,entry);
883         if (IsEqualGUID(rguid,&key->guid) && pprekey->uVKey == key->prekey.uVKey && pprekey->uModifiers == key->prekey.uModifiers)
884             break;
885         key = NULL;
886     }
887 
888     if (!key)
889         return CONNECT_E_NOCONNECTION;
890 
891     list_remove(&key->entry);
892     HeapFree(GetProcessHeap(),0,key->description);
893     HeapFree(GetProcessHeap(),0,key);
894 
895     return S_OK;
896 }
897 
898 static HRESULT WINAPI KeystrokeMgr_SetPreservedKeyDescription(ITfKeystrokeMgr *iface,
899         REFGUID rguid, const WCHAR *pchDesc, ULONG cchDesc)
900 {
901     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
902     FIXME("STUB:(%p)\n",This);
903     return E_NOTIMPL;
904 }
905 
906 static HRESULT WINAPI KeystrokeMgr_GetPreservedKeyDescription(ITfKeystrokeMgr *iface,
907         REFGUID rguid, BSTR *pbstrDesc)
908 {
909     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
910     FIXME("STUB:(%p)\n",This);
911     return E_NOTIMPL;
912 }
913 
914 static HRESULT WINAPI KeystrokeMgr_SimulatePreservedKey(ITfKeystrokeMgr *iface,
915         ITfContext *pic, REFGUID rguid, BOOL *pfEaten)
916 {
917     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
918     FIXME("STUB:(%p)\n",This);
919     return E_NOTIMPL;
920 }
921 
922 static const ITfKeystrokeMgrVtbl KeystrokeMgrVtbl =
923 {
924     KeystrokeMgr_QueryInterface,
925     KeystrokeMgr_AddRef,
926     KeystrokeMgr_Release,
927     KeystrokeMgr_AdviseKeyEventSink,
928     KeystrokeMgr_UnadviseKeyEventSink,
929     KeystrokeMgr_GetForeground,
930     KeystrokeMgr_TestKeyDown,
931     KeystrokeMgr_TestKeyUp,
932     KeystrokeMgr_KeyDown,
933     KeystrokeMgr_KeyUp,
934     KeystrokeMgr_GetPreservedKey,
935     KeystrokeMgr_IsPreservedKey,
936     KeystrokeMgr_PreserveKey,
937     KeystrokeMgr_UnpreserveKey,
938     KeystrokeMgr_SetPreservedKeyDescription,
939     KeystrokeMgr_GetPreservedKeyDescription,
940     KeystrokeMgr_SimulatePreservedKey
941 };
942 
943 /*****************************************************
944  * ITfMessagePump functions
945  *****************************************************/
946 
947 static HRESULT WINAPI MessagePump_QueryInterface(ITfMessagePump *iface, REFIID iid, LPVOID *ppvOut)
948 {
949     ThreadMgr *This = impl_from_ITfMessagePump(iface);
950     return ITfThreadMgrEx_QueryInterface(&This->ITfThreadMgrEx_iface, iid, ppvOut);
951 }
952 
953 static ULONG WINAPI MessagePump_AddRef(ITfMessagePump *iface)
954 {
955     ThreadMgr *This = impl_from_ITfMessagePump(iface);
956     return ITfThreadMgrEx_AddRef(&This->ITfThreadMgrEx_iface);
957 }
958 
959 static ULONG WINAPI MessagePump_Release(ITfMessagePump *iface)
960 {
961     ThreadMgr *This = impl_from_ITfMessagePump(iface);
962     return ITfThreadMgrEx_Release(&This->ITfThreadMgrEx_iface);
963 }
964 
965 static HRESULT WINAPI MessagePump_PeekMessageA(ITfMessagePump *iface,
966         LPMSG pMsg, HWND hwnd, UINT wMsgFilterMin, UINT wMsgFilterMax,
967         UINT wRemoveMsg, BOOL *pfResult)
968 {
969     if (!pfResult)
970         return E_INVALIDARG;
971     *pfResult = PeekMessageA(pMsg, hwnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
972     return S_OK;
973 }
974 
975 static HRESULT WINAPI MessagePump_GetMessageA(ITfMessagePump *iface,
976         LPMSG pMsg, HWND hwnd, UINT wMsgFilterMin, UINT wMsgFilterMax,
977         BOOL *pfResult)
978 {
979     if (!pfResult)
980         return E_INVALIDARG;
981     *pfResult = GetMessageA(pMsg, hwnd, wMsgFilterMin, wMsgFilterMax);
982     return S_OK;
983 }
984 
985 static HRESULT WINAPI MessagePump_PeekMessageW(ITfMessagePump *iface,
986         LPMSG pMsg, HWND hwnd, UINT wMsgFilterMin, UINT wMsgFilterMax,
987         UINT wRemoveMsg, BOOL *pfResult)
988 {
989     if (!pfResult)
990         return E_INVALIDARG;
991     *pfResult = PeekMessageW(pMsg, hwnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
992     return S_OK;
993 }
994 
995 static HRESULT WINAPI MessagePump_GetMessageW(ITfMessagePump *iface,
996         LPMSG pMsg, HWND hwnd, UINT wMsgFilterMin, UINT wMsgFilterMax,
997         BOOL *pfResult)
998 {
999     if (!pfResult)
1000         return E_INVALIDARG;
1001     *pfResult = GetMessageW(pMsg, hwnd, wMsgFilterMin, wMsgFilterMax);
1002     return S_OK;
1003 }
1004 
1005 static const ITfMessagePumpVtbl MessagePumpVtbl =
1006 {
1007     MessagePump_QueryInterface,
1008     MessagePump_AddRef,
1009     MessagePump_Release,
1010     MessagePump_PeekMessageA,
1011     MessagePump_GetMessageA,
1012     MessagePump_PeekMessageW,
1013     MessagePump_GetMessageW
1014 };
1015 
1016 /*****************************************************
1017  * ITfClientId functions
1018  *****************************************************/
1019 
1020 static HRESULT WINAPI ClientId_QueryInterface(ITfClientId *iface, REFIID iid, LPVOID *ppvOut)
1021 {
1022     ThreadMgr *This = impl_from_ITfClientId(iface);
1023     return ITfThreadMgrEx_QueryInterface(&This->ITfThreadMgrEx_iface, iid, ppvOut);
1024 }
1025 
1026 static ULONG WINAPI ClientId_AddRef(ITfClientId *iface)
1027 {
1028     ThreadMgr *This = impl_from_ITfClientId(iface);
1029     return ITfThreadMgrEx_AddRef(&This->ITfThreadMgrEx_iface);
1030 }
1031 
1032 static ULONG WINAPI ClientId_Release(ITfClientId *iface)
1033 {
1034     ThreadMgr *This = impl_from_ITfClientId(iface);
1035     return ITfThreadMgrEx_Release(&This->ITfThreadMgrEx_iface);
1036 }
1037 
1038 static HRESULT WINAPI ClientId_GetClientId(ITfClientId *iface,
1039     REFCLSID rclsid, TfClientId *ptid)
1040 
1041 {
1042     ThreadMgr *This = impl_from_ITfClientId(iface);
1043     HRESULT hr;
1044     ITfCategoryMgr *catmgr;
1045 
1046     TRACE("(%p) %s\n",This,debugstr_guid(rclsid));
1047 
1048     CategoryMgr_Constructor(NULL,(IUnknown**)&catmgr);
1049     hr = ITfCategoryMgr_RegisterGUID(catmgr,rclsid,ptid);
1050     ITfCategoryMgr_Release(catmgr);
1051 
1052     return hr;
1053 }
1054 
1055 static const ITfClientIdVtbl ClientIdVtbl =
1056 {
1057     ClientId_QueryInterface,
1058     ClientId_AddRef,
1059     ClientId_Release,
1060     ClientId_GetClientId
1061 };
1062 
1063 /*****************************************************
1064  * ITfThreadMgrEventSink functions  (internal)
1065  *****************************************************/
1066 static HRESULT WINAPI ThreadMgrEventSink_QueryInterface(ITfThreadMgrEventSink *iface, REFIID iid, LPVOID *ppvOut)
1067 {
1068     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
1069     return ITfThreadMgrEx_QueryInterface(&This->ITfThreadMgrEx_iface, iid, ppvOut);
1070 }
1071 
1072 static ULONG WINAPI ThreadMgrEventSink_AddRef(ITfThreadMgrEventSink *iface)
1073 {
1074     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
1075     return ITfThreadMgrEx_AddRef(&This->ITfThreadMgrEx_iface);
1076 }
1077 
1078 static ULONG WINAPI ThreadMgrEventSink_Release(ITfThreadMgrEventSink *iface)
1079 {
1080     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
1081     return ITfThreadMgrEx_Release(&This->ITfThreadMgrEx_iface);
1082 }
1083 
1084 
1085 static HRESULT WINAPI ThreadMgrEventSink_OnInitDocumentMgr(
1086         ITfThreadMgrEventSink *iface,ITfDocumentMgr *pdim)
1087 {
1088     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
1089     ITfThreadMgrEventSink *sink;
1090     struct list *cursor;
1091 
1092     TRACE("(%p) %p\n",This,pdim);
1093 
1094     SINK_FOR_EACH(cursor, &This->ThreadMgrEventSink, ITfThreadMgrEventSink, sink)
1095     {
1096         ITfThreadMgrEventSink_OnInitDocumentMgr(sink, pdim);
1097     }
1098 
1099     return S_OK;
1100 }
1101 
1102 static HRESULT WINAPI ThreadMgrEventSink_OnUninitDocumentMgr(
1103         ITfThreadMgrEventSink *iface, ITfDocumentMgr *pdim)
1104 {
1105     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
1106     ITfThreadMgrEventSink *sink;
1107     struct list *cursor;
1108 
1109     TRACE("(%p) %p\n",This,pdim);
1110 
1111     SINK_FOR_EACH(cursor, &This->ThreadMgrEventSink, ITfThreadMgrEventSink, sink)
1112     {
1113         ITfThreadMgrEventSink_OnUninitDocumentMgr(sink, pdim);
1114     }
1115 
1116     return S_OK;
1117 }
1118 
1119 static HRESULT WINAPI ThreadMgrEventSink_OnSetFocus(
1120         ITfThreadMgrEventSink *iface, ITfDocumentMgr *pdimFocus,
1121         ITfDocumentMgr *pdimPrevFocus)
1122 {
1123     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
1124     ITfThreadMgrEventSink *sink;
1125     struct list *cursor;
1126 
1127     TRACE("(%p) %p %p\n",This,pdimFocus, pdimPrevFocus);
1128 
1129     SINK_FOR_EACH(cursor, &This->ThreadMgrEventSink, ITfThreadMgrEventSink, sink)
1130     {
1131         ITfThreadMgrEventSink_OnSetFocus(sink, pdimFocus, pdimPrevFocus);
1132     }
1133 
1134     return S_OK;
1135 }
1136 
1137 static HRESULT WINAPI ThreadMgrEventSink_OnPushContext(
1138         ITfThreadMgrEventSink *iface, ITfContext *pic)
1139 {
1140     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
1141     ITfThreadMgrEventSink *sink;
1142     struct list *cursor;
1143 
1144     TRACE("(%p) %p\n",This,pic);
1145 
1146     SINK_FOR_EACH(cursor, &This->ThreadMgrEventSink, ITfThreadMgrEventSink, sink)
1147     {
1148         ITfThreadMgrEventSink_OnPushContext(sink, pic);
1149     }
1150 
1151     return S_OK;
1152 }
1153 
1154 static HRESULT WINAPI ThreadMgrEventSink_OnPopContext(
1155         ITfThreadMgrEventSink *iface, ITfContext *pic)
1156 {
1157     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
1158     ITfThreadMgrEventSink *sink;
1159     struct list *cursor;
1160 
1161     TRACE("(%p) %p\n",This,pic);
1162 
1163     SINK_FOR_EACH(cursor, &This->ThreadMgrEventSink, ITfThreadMgrEventSink, sink)
1164     {
1165         ITfThreadMgrEventSink_OnPopContext(sink, pic);
1166     }
1167 
1168     return S_OK;
1169 }
1170 
1171 static const ITfThreadMgrEventSinkVtbl ThreadMgrEventSinkVtbl =
1172 {
1173     ThreadMgrEventSink_QueryInterface,
1174     ThreadMgrEventSink_AddRef,
1175     ThreadMgrEventSink_Release,
1176     ThreadMgrEventSink_OnInitDocumentMgr,
1177     ThreadMgrEventSink_OnUninitDocumentMgr,
1178     ThreadMgrEventSink_OnSetFocus,
1179     ThreadMgrEventSink_OnPushContext,
1180     ThreadMgrEventSink_OnPopContext
1181 };
1182 
1183 /*****************************************************
1184  * ITfUIElementMgr functions
1185  *****************************************************/
1186 static HRESULT WINAPI UIElementMgr_QueryInterface(ITfUIElementMgr *iface, REFIID iid, void **ppvOut)
1187 {
1188     ThreadMgr *This = impl_from_ITfUIElementMgr(iface);
1189 
1190     return ITfThreadMgrEx_QueryInterface(&This->ITfThreadMgrEx_iface, iid, ppvOut);
1191 }
1192 
1193 static ULONG WINAPI UIElementMgr_AddRef(ITfUIElementMgr *iface)
1194 {
1195     ThreadMgr *This = impl_from_ITfUIElementMgr(iface);
1196 
1197     return ITfThreadMgrEx_AddRef(&This->ITfThreadMgrEx_iface);
1198 }
1199 
1200 static ULONG WINAPI UIElementMgr_Release(ITfUIElementMgr *iface)
1201 {
1202     ThreadMgr *This = impl_from_ITfUIElementMgr(iface);
1203 
1204     return ITfThreadMgrEx_Release(&This->ITfThreadMgrEx_iface);
1205 }
1206 
1207 static HRESULT WINAPI UIElementMgr_BeginUIElement(ITfUIElementMgr *iface, ITfUIElement *element,
1208                                                   BOOL *show, DWORD *id)
1209 {
1210     ThreadMgr *This = impl_from_ITfUIElementMgr(iface);
1211 
1212     FIXME("STUB:(%p)\n", This);
1213     return E_NOTIMPL;
1214 }
1215 
1216 static HRESULT WINAPI UIElementMgr_UpdateUIElement(ITfUIElementMgr *iface, DWORD id)
1217 {
1218     ThreadMgr *This = impl_from_ITfUIElementMgr(iface);
1219 
1220     FIXME("STUB:(%p)\n", This);
1221     return E_NOTIMPL;
1222 }
1223 
1224 static HRESULT WINAPI UIElementMgr_EndUIElement(ITfUIElementMgr *iface, DWORD id)
1225 {
1226     ThreadMgr *This = impl_from_ITfUIElementMgr(iface);
1227 
1228     FIXME("STUB:(%p)\n", This);
1229     return E_NOTIMPL;
1230 }
1231 
1232 static HRESULT WINAPI UIElementMgr_GetUIElement(ITfUIElementMgr *iface, DWORD id,
1233                                                 ITfUIElement **element)
1234 {
1235     ThreadMgr *This = impl_from_ITfUIElementMgr(iface);
1236 
1237     FIXME("STUB:(%p)\n", This);
1238     return E_NOTIMPL;
1239 }
1240 
1241 static HRESULT WINAPI UIElementMgr_EnumUIElements(ITfUIElementMgr *iface,
1242                                                   IEnumTfUIElements **enum_elements)
1243 {
1244     ThreadMgr *This = impl_from_ITfUIElementMgr(iface);
1245 
1246     FIXME("STUB:(%p)\n", This);
1247     return E_NOTIMPL;
1248 }
1249 
1250 static const ITfUIElementMgrVtbl ThreadMgrUIElementMgrVtbl =
1251 {
1252     UIElementMgr_QueryInterface,
1253     UIElementMgr_AddRef,
1254     UIElementMgr_Release,
1255 
1256     UIElementMgr_BeginUIElement,
1257     UIElementMgr_UpdateUIElement,
1258     UIElementMgr_EndUIElement,
1259     UIElementMgr_GetUIElement,
1260     UIElementMgr_EnumUIElements
1261 };
1262 
1263 /*****************************************************
1264  * ITfSourceSingle functions
1265  *****************************************************/
1266 static HRESULT WINAPI ThreadMgrSourceSingle_QueryInterface(ITfSourceSingle *iface, REFIID iid, LPVOID *ppvOut)
1267 {
1268     ThreadMgr *This = impl_from_ITfSourceSingle(iface);
1269     return ITfThreadMgrEx_QueryInterface(&This->ITfThreadMgrEx_iface, iid, ppvOut);
1270 }
1271 
1272 static ULONG WINAPI ThreadMgrSourceSingle_AddRef(ITfSourceSingle *iface)
1273 {
1274     ThreadMgr *This = impl_from_ITfSourceSingle(iface);
1275     return ITfThreadMgrEx_AddRef(&This->ITfThreadMgrEx_iface);
1276 }
1277 
1278 static ULONG WINAPI ThreadMgrSourceSingle_Release(ITfSourceSingle *iface)
1279 {
1280     ThreadMgr *This = impl_from_ITfSourceSingle(iface);
1281     return ITfThreadMgrEx_Release(&This->ITfThreadMgrEx_iface);
1282 }
1283 
1284 static HRESULT WINAPI ThreadMgrSourceSingle_AdviseSingleSink( ITfSourceSingle *iface,
1285     TfClientId tid, REFIID riid, IUnknown *punk)
1286 {
1287     ThreadMgr *This = impl_from_ITfSourceSingle(iface);
1288     FIXME("STUB:(%p) %i %s %p\n",This, tid, debugstr_guid(riid),punk);
1289     return E_NOTIMPL;
1290 }
1291 
1292 static HRESULT WINAPI ThreadMgrSourceSingle_UnadviseSingleSink( ITfSourceSingle *iface,
1293     TfClientId tid, REFIID riid)
1294 {
1295     ThreadMgr *This = impl_from_ITfSourceSingle(iface);
1296     FIXME("STUB:(%p) %i %s\n",This, tid, debugstr_guid(riid));
1297     return E_NOTIMPL;
1298 }
1299 
1300 static const ITfSourceSingleVtbl SourceSingleVtbl =
1301 {
1302     ThreadMgrSourceSingle_QueryInterface,
1303     ThreadMgrSourceSingle_AddRef,
1304     ThreadMgrSourceSingle_Release,
1305     ThreadMgrSourceSingle_AdviseSingleSink,
1306     ThreadMgrSourceSingle_UnadviseSingleSink
1307 };
1308 
1309 HRESULT ThreadMgr_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut)
1310 {
1311     ThreadMgr *This;
1312     if (pUnkOuter)
1313         return CLASS_E_NOAGGREGATION;
1314 
1315     /* Only 1 ThreadMgr is created per thread */
1316     This = TlsGetValue(tlsIndex);
1317     if (This)
1318     {
1319         ThreadMgr_AddRef(&This->ITfThreadMgrEx_iface);
1320         *ppOut = (IUnknown*)&This->ITfThreadMgrEx_iface;
1321         return S_OK;
1322     }
1323 
1324     This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ThreadMgr));
1325     if (This == NULL)
1326         return E_OUTOFMEMORY;
1327 
1328     This->ITfThreadMgrEx_iface.lpVtbl = &ThreadMgrExVtbl;
1329     This->ITfSource_iface.lpVtbl = &ThreadMgrSourceVtbl;
1330     This->ITfKeystrokeMgr_iface.lpVtbl = &KeystrokeMgrVtbl;
1331     This->ITfMessagePump_iface.lpVtbl = &MessagePumpVtbl;
1332     This->ITfClientId_iface.lpVtbl = &ClientIdVtbl;
1333     This->ITfThreadMgrEventSink_iface.lpVtbl = &ThreadMgrEventSinkVtbl;
1334     This->ITfUIElementMgr_iface.lpVtbl = &ThreadMgrUIElementMgrVtbl;
1335     This->ITfSourceSingle_iface.lpVtbl = &SourceSingleVtbl;
1336     This->refCount = 1;
1337     TlsSetValue(tlsIndex,This);
1338 
1339     CompartmentMgr_Constructor((IUnknown*)&This->ITfThreadMgrEx_iface, &IID_IUnknown, (IUnknown**)&This->CompartmentMgr);
1340 
1341     list_init(&This->CurrentPreservedKeys);
1342     list_init(&This->CreatedDocumentMgrs);
1343     list_init(&This->AssociatedFocusWindows);
1344 
1345     list_init(&This->ActiveLanguageProfileNotifySink);
1346     list_init(&This->DisplayAttributeNotifySink);
1347     list_init(&This->KeyTraceEventSink);
1348     list_init(&This->PreservedKeyNotifySink);
1349     list_init(&This->ThreadFocusSink);
1350     list_init(&This->ThreadMgrEventSink);
1351 
1352     TRACE("returning %p\n", This);
1353     *ppOut = (IUnknown *)&This->ITfThreadMgrEx_iface;
1354     return S_OK;
1355 }
1356 
1357 /**************************************************
1358  * IEnumTfDocumentMgrs implementation
1359  **************************************************/
1360 static void EnumTfDocumentMgr_Destructor(EnumTfDocumentMgr *This)
1361 {
1362     TRACE("destroying %p\n", This);
1363     HeapFree(GetProcessHeap(),0,This);
1364 }
1365 
1366 static HRESULT WINAPI EnumTfDocumentMgr_QueryInterface(IEnumTfDocumentMgrs *iface, REFIID iid, LPVOID *ppvOut)
1367 {
1368     EnumTfDocumentMgr *This = impl_from_IEnumTfDocumentMgrs(iface);
1369     *ppvOut = NULL;
1370 
1371     if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IEnumTfDocumentMgrs))
1372     {
1373         *ppvOut = &This->IEnumTfDocumentMgrs_iface;
1374     }
1375 
1376     if (*ppvOut)
1377     {
1378         IEnumTfDocumentMgrs_AddRef(iface);
1379         return S_OK;
1380     }
1381 
1382     WARN("unsupported interface: %s\n", debugstr_guid(iid));
1383     return E_NOINTERFACE;
1384 }
1385 
1386 static ULONG WINAPI EnumTfDocumentMgr_AddRef(IEnumTfDocumentMgrs *iface)
1387 {
1388     EnumTfDocumentMgr *This = impl_from_IEnumTfDocumentMgrs(iface);
1389     return InterlockedIncrement(&This->refCount);
1390 }
1391 
1392 static ULONG WINAPI EnumTfDocumentMgr_Release(IEnumTfDocumentMgrs *iface)
1393 {
1394     EnumTfDocumentMgr *This = impl_from_IEnumTfDocumentMgrs(iface);
1395     ULONG ret;
1396 
1397     ret = InterlockedDecrement(&This->refCount);
1398     if (ret == 0)
1399         EnumTfDocumentMgr_Destructor(This);
1400     return ret;
1401 }
1402 
1403 static HRESULT WINAPI EnumTfDocumentMgr_Next(IEnumTfDocumentMgrs *iface,
1404     ULONG ulCount, ITfDocumentMgr **rgDocumentMgr, ULONG *pcFetched)
1405 {
1406     EnumTfDocumentMgr *This = impl_from_IEnumTfDocumentMgrs(iface);
1407     ULONG fetched = 0;
1408 
1409     TRACE("(%p)\n",This);
1410 
1411     if (rgDocumentMgr == NULL) return E_POINTER;
1412 
1413     while (fetched < ulCount)
1414     {
1415         DocumentMgrEntry *mgrentry;
1416         if (This->index == NULL)
1417             break;
1418 
1419         mgrentry = LIST_ENTRY(This->index,DocumentMgrEntry,entry);
1420         if (mgrentry == NULL)
1421             break;
1422 
1423         *rgDocumentMgr = mgrentry->docmgr;
1424         ITfDocumentMgr_AddRef(*rgDocumentMgr);
1425 
1426         This->index = list_next(This->head, This->index);
1427         ++fetched;
1428         ++rgDocumentMgr;
1429     }
1430 
1431     if (pcFetched) *pcFetched = fetched;
1432     return fetched == ulCount ? S_OK : S_FALSE;
1433 }
1434 
1435 static HRESULT WINAPI EnumTfDocumentMgr_Skip( IEnumTfDocumentMgrs* iface, ULONG celt)
1436 {
1437     EnumTfDocumentMgr *This = impl_from_IEnumTfDocumentMgrs(iface);
1438     ULONG i;
1439 
1440     TRACE("(%p)\n",This);
1441     for(i = 0; i < celt && This->index != NULL; i++)
1442         This->index = list_next(This->head, This->index);
1443     return S_OK;
1444 }
1445 
1446 static HRESULT WINAPI EnumTfDocumentMgr_Reset( IEnumTfDocumentMgrs* iface)
1447 {
1448     EnumTfDocumentMgr *This = impl_from_IEnumTfDocumentMgrs(iface);
1449     TRACE("(%p)\n",This);
1450     This->index = list_head(This->head);
1451     return S_OK;
1452 }
1453 
1454 static HRESULT WINAPI EnumTfDocumentMgr_Clone( IEnumTfDocumentMgrs *iface,
1455     IEnumTfDocumentMgrs **ppenum)
1456 {
1457     EnumTfDocumentMgr *This = impl_from_IEnumTfDocumentMgrs(iface);
1458     HRESULT res;
1459 
1460     TRACE("(%p)\n",This);
1461 
1462     if (ppenum == NULL) return E_POINTER;
1463 
1464     res = EnumTfDocumentMgr_Constructor(This->head, ppenum);
1465     if (SUCCEEDED(res))
1466     {
1467         EnumTfDocumentMgr *new_This = impl_from_IEnumTfDocumentMgrs(*ppenum);
1468         new_This->index = This->index;
1469     }
1470     return res;
1471 }
1472 
1473 static const IEnumTfDocumentMgrsVtbl EnumTfDocumentMgrsVtbl =
1474 {
1475     EnumTfDocumentMgr_QueryInterface,
1476     EnumTfDocumentMgr_AddRef,
1477     EnumTfDocumentMgr_Release,
1478     EnumTfDocumentMgr_Clone,
1479     EnumTfDocumentMgr_Next,
1480     EnumTfDocumentMgr_Reset,
1481     EnumTfDocumentMgr_Skip
1482 };
1483 
1484 static HRESULT EnumTfDocumentMgr_Constructor(struct list* head, IEnumTfDocumentMgrs **ppOut)
1485 {
1486     EnumTfDocumentMgr *This;
1487 
1488     This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(EnumTfDocumentMgr));
1489     if (This == NULL)
1490         return E_OUTOFMEMORY;
1491 
1492     This->IEnumTfDocumentMgrs_iface.lpVtbl= &EnumTfDocumentMgrsVtbl;
1493     This->refCount = 1;
1494     This->head = head;
1495     This->index = list_head(This->head);
1496 
1497     TRACE("returning %p\n", &This->IEnumTfDocumentMgrs_iface);
1498     *ppOut = &This->IEnumTfDocumentMgrs_iface;
1499     return S_OK;
1500 }
1501 
1502 void ThreadMgr_OnDocumentMgrDestruction(ITfThreadMgr *iface, ITfDocumentMgr *mgr)
1503 {
1504     ThreadMgr *This = impl_from_ITfThreadMgrEx((ITfThreadMgrEx *)iface);
1505     struct list *cursor;
1506     LIST_FOR_EACH(cursor, &This->CreatedDocumentMgrs)
1507     {
1508         DocumentMgrEntry *mgrentry = LIST_ENTRY(cursor,DocumentMgrEntry,entry);
1509         if (mgrentry->docmgr == mgr)
1510         {
1511             list_remove(cursor);
1512             HeapFree(GetProcessHeap(),0,mgrentry);
1513             return;
1514         }
1515     }
1516     FIXME("ITfDocumentMgr %p not found in this thread\n",mgr);
1517 }
1518