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