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