Reactos
1/*
2 * PROJECT: ReactOS CTF
3 * LICENSE: LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later)
4 * PURPOSE: ITfThreadMgr implementation
5 * COPYRIGHT: Copyright 2008 Aric Stewart, CodeWeavers
6 * Copyright 2025 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
7 */
8
9#include "precomp.h"
10
11#include <wine/debug.h>
12WINE_DEFAULT_DEBUG_CHANNEL(msctf);
13
14////////////////////////////////////////////////////////////////////////////
15
16typedef struct tagPreservedKey
17{
18 struct list entry;
19 GUID guid;
20 TF_PRESERVEDKEY prekey;
21 LPWSTR description;
22 TfClientId tid;
23} PreservedKey;
24
25typedef struct tagDocumentMgrs
26{
27 struct list entry;
28 ITfDocumentMgr *docmgr;
29} DocumentMgrEntry;
30
31typedef struct tagAssociatedWindow
32{
33 struct list entry;
34 HWND hwnd;
35 ITfDocumentMgr *docmgr;
36} AssociatedWindow;
37
38////////////////////////////////////////////////////////////////////////////
39
40class CThreadMgr
41 : public ITfThreadMgrEx
42 , public ITfSource
43 , public ITfKeystrokeMgr
44 , public ITfMessagePump
45 , public ITfClientId
46 // , public ITfConfigureSystemKeystrokeFeed
47 // , public ITfLangBarItemMgr
48 , public ITfUIElementMgr
49 , public ITfSourceSingle
50 , public ITfThreadMgrEventSink
51{
52public:
53 CThreadMgr();
54 virtual ~CThreadMgr();
55
56 static HRESULT CreateInstance(IUnknown *pUnkOuter, CThreadMgr **ppOut);
57 void OnDocumentMgrDestruction(ITfDocumentMgr *mgr);
58
59 // ** IUnknown methods **
60 STDMETHODIMP QueryInterface(REFIID iid, LPVOID *ppvObject) override;
61 STDMETHODIMP_(ULONG) AddRef() override;
62 STDMETHODIMP_(ULONG) Release() override;
63
64 // ** ITfThreadMgr methods **
65 STDMETHODIMP Activate(_Out_ TfClientId *ptid) override;
66 STDMETHODIMP Deactivate() override;
67 STDMETHODIMP CreateDocumentMgr(_Out_ ITfDocumentMgr **ppdim) override;
68 STDMETHODIMP EnumDocumentMgrs(_Out_ IEnumTfDocumentMgrs **ppEnum) override;
69 STDMETHODIMP GetFocus(_Out_ ITfDocumentMgr **ppdimFocus) override;
70 STDMETHODIMP SetFocus(_In_ ITfDocumentMgr *pdimFocus) override;
71 STDMETHODIMP AssociateFocus(
72 _In_ HWND hwnd,
73 _In_ ITfDocumentMgr *pdimNew,
74 _Out_ ITfDocumentMgr **ppdimPrev) override;
75 STDMETHODIMP IsThreadFocus(_Out_ BOOL *pfThreadFocus) override;
76 STDMETHODIMP GetFunctionProvider(
77 _In_ REFCLSID clsid,
78 _Out_ ITfFunctionProvider **ppFuncProv) override;
79 STDMETHODIMP EnumFunctionProviders(_Out_ IEnumTfFunctionProviders **ppEnum) override;
80 STDMETHODIMP GetGlobalCompartment(_Out_ ITfCompartmentMgr **ppCompMgr) override;
81
82 // ** ITfThreadMgrEx methods **
83 STDMETHODIMP ActivateEx(
84 _Out_ TfClientId *id,
85 _In_ DWORD flags) override;
86 STDMETHODIMP GetActiveFlags(_Out_ DWORD *flags) override;
87
88 // ** ITfSource methods **
89 STDMETHODIMP AdviseSink(
90 _In_ REFIID riid,
91 _In_ IUnknown *punk,
92 _Out_ DWORD *pdwCookie) override;
93 STDMETHODIMP UnadviseSink(_In_ DWORD dwCookie) override;
94
95 // ** ITfKeystrokeMgr methods **
96 STDMETHODIMP AdviseKeyEventSink(
97 _In_ TfClientId tid,
98 _In_ ITfKeyEventSink *pSink,
99 _In_ BOOL fForeground) override;
100 STDMETHODIMP UnadviseKeyEventSink(_In_ TfClientId tid) override;
101 STDMETHODIMP GetForeground(_Out_ CLSID *pclsid) override;
102 STDMETHODIMP TestKeyDown(
103 _In_ WPARAM wParam,
104 _In_ LPARAM lParam,
105 _Out_ BOOL *pfEaten) override;
106 STDMETHODIMP TestKeyUp(
107 _In_ WPARAM wParam,
108 _In_ LPARAM lParam,
109 _Out_ BOOL *pfEaten) override;
110 STDMETHODIMP KeyDown(
111 _In_ WPARAM wParam,
112 _In_ LPARAM lParam,
113 _Out_ BOOL *pfEaten) override;
114 STDMETHODIMP KeyUp(
115 _In_ WPARAM wParam,
116 _In_ LPARAM lParam,
117 _Out_ BOOL *pfEaten) override;
118 STDMETHODIMP GetPreservedKey(
119 _In_ ITfContext *pic,
120 _In_ const TF_PRESERVEDKEY *pprekey,
121 _Out_ GUID *pguid) override;
122 STDMETHODIMP IsPreservedKey(
123 _In_ REFGUID rguid,
124 _In_ const TF_PRESERVEDKEY *pprekey,
125 _Out_ BOOL *pfRegistered) override;
126 STDMETHODIMP PreserveKey(
127 _In_ TfClientId tid,
128 _In_ REFGUID rguid,
129 _In_ const TF_PRESERVEDKEY *prekey,
130 _In_ const WCHAR *pchDesc,
131 _In_ ULONG cchDesc) override;
132 STDMETHODIMP UnpreserveKey(
133 _In_ REFGUID rguid,
134 _In_ const TF_PRESERVEDKEY *pprekey) override;
135 STDMETHODIMP SetPreservedKeyDescription(
136 _In_ REFGUID rguid,
137 _In_ const WCHAR *pchDesc,
138 _In_ ULONG cchDesc) override;
139 STDMETHODIMP GetPreservedKeyDescription(
140 _In_ REFGUID rguid,
141 _Out_ BSTR *pbstrDesc) override;
142 STDMETHODIMP SimulatePreservedKey(
143 _In_ ITfContext *pic,
144 _In_ REFGUID rguid,
145 _Out_ BOOL *pfEaten) override;
146
147 // ** ITfMessagePump methods **
148 STDMETHODIMP PeekMessageA(
149 _Out_ LPMSG pMsg,
150 _In_ HWND hwnd,
151 _In_ UINT wMsgFilterMin,
152 _In_ UINT wMsgFilterMax,
153 _In_ UINT wRemoveMsg,
154 _Out_ BOOL *pfResult) override;
155 STDMETHODIMP GetMessageA(
156 _Out_ LPMSG pMsg,
157 _In_ HWND hwnd,
158 _In_ UINT wMsgFilterMin,
159 _In_ UINT wMsgFilterMax,
160 _Out_ BOOL *pfResult) override;
161 STDMETHODIMP PeekMessageW(
162 _Out_ LPMSG pMsg,
163 _In_ HWND hwnd,
164 _In_ UINT wMsgFilterMin,
165 _In_ UINT wMsgFilterMax,
166 _In_ UINT wRemoveMsg,
167 _Out_ BOOL *pfResult) override;
168 STDMETHODIMP GetMessageW(
169 _Out_ LPMSG pMsg,
170 _In_ HWND hwnd,
171 _In_ UINT wMsgFilterMin,
172 _In_ UINT wMsgFilterMax,
173 _Out_ BOOL *pfResult) override;
174
175 // ** ITfClientId methods **
176 STDMETHODIMP GetClientId(
177 _In_ REFCLSID rclsid,
178 _Out_ TfClientId *ptid) override;
179
180 // ** ITfUIElementMgr methods **
181 STDMETHODIMP BeginUIElement(
182 _In_ ITfUIElement *element,
183 _Inout_ BOOL *show,
184 _Out_ DWORD *id) override;
185 STDMETHODIMP UpdateUIElement(_In_ DWORD id) override;
186 STDMETHODIMP EndUIElement(_In_ DWORD id) override;
187 STDMETHODIMP GetUIElement(
188 _In_ DWORD id,
189 _Out_ ITfUIElement **element) override;
190 STDMETHODIMP EnumUIElements(_Out_ IEnumTfUIElements **enum_elements) override;
191
192 // ** ITfSourceSingle methods **
193 STDMETHODIMP AdviseSingleSink(
194 _In_ TfClientId tid,
195 _In_ REFIID riid,
196 _In_ IUnknown *punk) override;
197 STDMETHODIMP UnadviseSingleSink(
198 _In_ TfClientId tid,
199 _In_ REFIID riid) override;
200
201 // ** ITfThreadMgrEventSink methods **
202 STDMETHODIMP OnInitDocumentMgr(_In_ ITfDocumentMgr *pdim) override;
203 STDMETHODIMP OnUninitDocumentMgr(_In_ ITfDocumentMgr *pdim) override;
204 STDMETHODIMP OnSetFocus(
205 _In_ ITfDocumentMgr *pdimFocus,
206 _In_ ITfDocumentMgr *pdimPrevFocus) override;
207 STDMETHODIMP OnPushContext(_In_ ITfContext *pic) override;
208 STDMETHODIMP OnPopContext(_In_ ITfContext *pic) override;
209
210protected:
211 LONG m_cRefs;
212
213 /* Aggregation */
214 ITfCompartmentMgr *m_CompartmentMgr;
215
216 ITfDocumentMgr *m_focus;
217 LONG m_activationCount;
218
219 ITfKeyEventSink *m_foregroundKeyEventSink;
220 CLSID m_foregroundTextService;
221
222 struct list m_CurrentPreservedKeys;
223 struct list m_CreatedDocumentMgrs;
224
225 struct list m_AssociatedFocusWindows;
226 HHOOK m_focusHook;
227
228 /* kept as separate lists to reduce unnecessary iterations */
229 struct list m_ActiveLanguageProfileNotifySink;
230 struct list m_DisplayAttributeNotifySink;
231 struct list m_KeyTraceEventSink;
232 struct list m_PreservedKeyNotifySink;
233 struct list m_ThreadFocusSink;
234 struct list m_ThreadMgrEventSink;
235 struct list m_UIElementSink;
236 struct list m_InputProcessorProfileActivationSink;
237
238 static LRESULT CALLBACK ThreadFocusHookProc(INT nCode, WPARAM wParam, LPARAM lParam);
239 LRESULT _ThreadFocusHookProc(INT nCode, WPARAM wParam, LPARAM lParam);
240
241 HRESULT SetupWindowsHook();
242};
243
244////////////////////////////////////////////////////////////////////////////
245
246class CEnumTfDocumentMgr
247 : public IEnumTfDocumentMgrs
248{
249public:
250 CEnumTfDocumentMgr();
251 virtual ~CEnumTfDocumentMgr();
252
253 static HRESULT CreateInstance(struct list* head, CEnumTfDocumentMgr **ppOut);
254
255 // ** IUnknown methods **
256 STDMETHODIMP QueryInterface(REFIID iid, LPVOID *ppvObject) override;
257 STDMETHODIMP_(ULONG) AddRef() override;
258 STDMETHODIMP_(ULONG) Release() override;
259
260 // ** IEnumTfDocumentMgrs methods **
261 STDMETHODIMP Clone(_Out_ IEnumTfDocumentMgrs **ppEnum) override;
262 STDMETHODIMP Next(
263 _In_ ULONG ulCount,
264 _Out_ ITfDocumentMgr **rgDocumentMgr,
265 _Out_ ULONG *pcFetched) override;
266 STDMETHODIMP Reset() override;
267 STDMETHODIMP Skip(_In_ ULONG ulCount) override;
268
269protected:
270 LONG m_cRefs;
271 struct list *m_index;
272 struct list *m_head;
273};
274
275////////////////////////////////////////////////////////////////////////////
276
277CThreadMgr::CThreadMgr()
278 : m_cRefs(1)
279 , m_CompartmentMgr(NULL)
280 , m_focus(NULL)
281 , m_activationCount(0)
282 , m_foregroundKeyEventSink(NULL)
283{
284 m_foregroundTextService = GUID_NULL;
285
286 list_init(&m_CurrentPreservedKeys);
287 list_init(&m_CreatedDocumentMgrs);
288
289 list_init(&m_AssociatedFocusWindows);
290 m_focusHook = NULL;
291
292 /* kept as separate lists to reduce unnecessary iterations */
293 list_init(&m_ActiveLanguageProfileNotifySink);
294 list_init(&m_DisplayAttributeNotifySink);
295 list_init(&m_KeyTraceEventSink);
296 list_init(&m_PreservedKeyNotifySink);
297 list_init(&m_ThreadFocusSink);
298 list_init(&m_ThreadMgrEventSink);
299 list_init(&m_UIElementSink);
300 list_init(&m_InputProcessorProfileActivationSink);
301}
302
303CThreadMgr::~CThreadMgr()
304{
305 struct list *cursor, *cursor2;
306
307 /* unhook right away */
308 if (m_focusHook)
309 UnhookWindowsHookEx(m_focusHook);
310
311 TlsSetValue(g_dwTLSIndex, NULL);
312 TRACE("destroying %p\n", this);
313
314 if (m_focus)
315 m_focus->Release();
316
317 free_sinks(&m_ActiveLanguageProfileNotifySink);
318 free_sinks(&m_DisplayAttributeNotifySink);
319 free_sinks(&m_KeyTraceEventSink);
320 free_sinks(&m_PreservedKeyNotifySink);
321 free_sinks(&m_ThreadFocusSink);
322 free_sinks(&m_ThreadMgrEventSink);
323 free_sinks(&m_UIElementSink);
324 free_sinks(&m_InputProcessorProfileActivationSink);
325
326 LIST_FOR_EACH_SAFE(cursor, cursor2, &m_CurrentPreservedKeys)
327 {
328 PreservedKey* key = LIST_ENTRY(cursor, PreservedKey, entry);
329 list_remove(cursor);
330 cicMemFree(key->description);
331 cicMemFree(key);
332 }
333
334 LIST_FOR_EACH_SAFE(cursor, cursor2, &m_CreatedDocumentMgrs)
335 {
336 DocumentMgrEntry *mgr = LIST_ENTRY(cursor, DocumentMgrEntry, entry);
337 list_remove(cursor);
338 FIXME("Left Over ITfDocumentMgr. Should we do something with it?\n");
339 cicMemFree(mgr);
340 }
341
342 LIST_FOR_EACH_SAFE(cursor, cursor2, &m_AssociatedFocusWindows)
343 {
344 AssociatedWindow *wnd = LIST_ENTRY(cursor, AssociatedWindow, entry);
345 list_remove(cursor);
346 cicMemFree(wnd);
347 }
348
349 m_CompartmentMgr->Release();
350}
351
352STDMETHODIMP CThreadMgr::QueryInterface(REFIID iid, LPVOID *ppvObject)
353{
354 *ppvObject = NULL;
355
356 IUnknown *pUnk = NULL;
357 if (iid == IID_IUnknown || iid == IID_ITfThreadMgr || iid == IID_ITfThreadMgrEx)
358 pUnk = static_cast<ITfThreadMgrEx *>(this);
359 else if (iid == IID_ITfSource)
360 pUnk = static_cast<ITfSource *>(this);
361 else if (iid == IID_ITfKeystrokeMgr)
362 pUnk = static_cast<ITfKeystrokeMgr *>(this);
363 else if (iid == IID_ITfMessagePump)
364 pUnk = static_cast<ITfMessagePump *>(this);
365 else if (iid == IID_ITfClientId)
366 pUnk = static_cast<ITfClientId *>(this);
367 else if (iid == IID_ITfCompartmentMgr)
368 pUnk = m_CompartmentMgr;
369 else if (iid == IID_ITfUIElementMgr)
370 pUnk = static_cast<ITfUIElementMgr *>(this);
371 else if (iid == IID_ITfSourceSingle)
372 pUnk = static_cast<ITfSourceSingle *>(this);
373
374 if (pUnk)
375 {
376 *ppvObject = pUnk;
377 pUnk->AddRef();
378 return S_OK;
379 }
380
381 WARN("unsupported interface: %s\n", debugstr_guid(&iid));
382 return E_NOINTERFACE;
383}
384
385STDMETHODIMP_(ULONG) CThreadMgr::AddRef()
386{
387 return ::InterlockedIncrement(&m_cRefs);
388}
389
390STDMETHODIMP_(ULONG) CThreadMgr::Release()
391{
392 ULONG ret = ::InterlockedDecrement(&m_cRefs);
393 if (!ret)
394 delete this;
395 return ret;
396}
397
398STDMETHODIMP CThreadMgr::Activate(_Out_ TfClientId *ptid)
399{
400 TRACE("(%p) %p\n", this, ptid);
401 return ActivateEx(ptid, 0);
402}
403
404STDMETHODIMP CThreadMgr::Deactivate()
405{
406 TRACE("(%p)\n", this);
407
408 if (m_activationCount == 0)
409 return E_UNEXPECTED;
410
411 --m_activationCount;
412
413 if (m_activationCount == 0)
414 {
415 if (m_focus)
416 {
417 OnSetFocus(NULL, m_focus);
418 m_focus->Release();
419 m_focus = NULL;
420 }
421 }
422
423 deactivate_textservices();
424 return S_OK;
425}
426
427STDMETHODIMP CThreadMgr::CreateDocumentMgr(_Out_ ITfDocumentMgr **ppdim)
428{
429 TRACE("(%p)\n", this);
430
431 if (!ppdim)
432 return E_INVALIDARG;
433
434 DocumentMgrEntry *mgrentry = (DocumentMgrEntry *)cicMemAlloc(sizeof(DocumentMgrEntry));
435 if (!mgrentry)
436 return E_OUTOFMEMORY;
437
438 HRESULT hr = DocumentMgr_Constructor(this, ppdim);
439 if (SUCCEEDED(hr))
440 {
441 mgrentry->docmgr = *ppdim;
442 list_add_head(&m_CreatedDocumentMgrs, &mgrentry->entry);
443 }
444 else
445 {
446 cicMemFree(mgrentry);
447 }
448
449 return hr;
450}
451
452STDMETHODIMP CThreadMgr::EnumDocumentMgrs(_Out_ IEnumTfDocumentMgrs **ppEnum)
453{
454 TRACE("(%p) %p\n", this, ppEnum);
455
456 if (!ppEnum)
457 return E_INVALIDARG;
458
459 return CEnumTfDocumentMgr::CreateInstance(&m_CreatedDocumentMgrs, (CEnumTfDocumentMgr **)ppEnum);
460}
461
462STDMETHODIMP CThreadMgr::GetFocus(_Out_ ITfDocumentMgr **ppdimFocus)
463{
464 TRACE("(%p)\n", this);
465
466 if (!ppdimFocus)
467 return E_INVALIDARG;
468
469 *ppdimFocus = m_focus;
470
471 TRACE("->%p\n", m_focus);
472
473 if (!m_focus)
474 return S_FALSE;
475
476 m_focus->AddRef();
477 return S_OK;
478}
479
480STDMETHODIMP CThreadMgr::SetFocus(_In_ ITfDocumentMgr *pdimFocus)
481{
482 ITfDocumentMgr *check;
483
484 TRACE("(%p) %p\n", this, pdimFocus);
485
486 if (!pdimFocus)
487 check = NULL;
488 else if (FAILED(pdimFocus->QueryInterface(IID_ITfDocumentMgr, (LPVOID*)&check)))
489 return E_INVALIDARG;
490
491 OnSetFocus(check, m_focus);
492
493 if (m_focus)
494 m_focus->Release();
495
496 m_focus = check;
497 return S_OK;
498}
499
500LRESULT CThreadMgr::_ThreadFocusHookProc(INT nCode, WPARAM wParam, LPARAM lParam)
501{
502 if (!m_focusHook)
503 {
504 ERR("Hook proc but no ThreadMgr focus Hook. Serious Error\n");
505 return 0;
506 }
507
508 if (nCode == HCBT_SETFOCUS) /* focus change within our thread */
509 {
510 struct list *cursor;
511
512 LIST_FOR_EACH(cursor, &m_AssociatedFocusWindows)
513 {
514 AssociatedWindow *wnd = LIST_ENTRY(cursor, AssociatedWindow, entry);
515 if (wnd->hwnd == (HWND)wParam)
516 {
517 TRACE("Triggering Associated window focus\n");
518 if (m_focus != wnd->docmgr)
519 SetFocus(wnd->docmgr);
520 break;
521 }
522 }
523 }
524
525 return CallNextHookEx(m_focusHook, nCode, wParam, lParam);
526}
527
528LRESULT CALLBACK CThreadMgr::ThreadFocusHookProc(INT nCode, WPARAM wParam, LPARAM lParam)
529{
530 CThreadMgr *This = (CThreadMgr *)TlsGetValue(g_dwTLSIndex);
531 if (!This)
532 {
533 ERR("Hook proc but no ThreadMgr for this thread. Serious Error\n");
534 return 0;
535 }
536 return This->_ThreadFocusHookProc(nCode, wParam, lParam);
537}
538
539HRESULT CThreadMgr::SetupWindowsHook()
540{
541 if (!m_focusHook)
542 {
543 m_focusHook = SetWindowsHookExW(WH_CBT, ThreadFocusHookProc, 0, GetCurrentThreadId());
544 if (!m_focusHook)
545 {
546 ERR("Unable to set focus hook\n");
547 return E_FAIL;
548 }
549 return S_OK;
550 }
551 return S_FALSE;
552}
553
554STDMETHODIMP CThreadMgr::AssociateFocus(
555 _In_ HWND hwnd,
556 _In_ ITfDocumentMgr *pdimNew,
557 _Out_ ITfDocumentMgr **ppdimPrev)
558{
559 struct list *cursor, *cursor2;
560 AssociatedWindow *wnd;
561
562 TRACE("(%p) %p %p %p\n", this, hwnd, pdimNew, ppdimPrev);
563
564 if (!ppdimPrev)
565 return E_INVALIDARG;
566
567 *ppdimPrev = NULL;
568
569 LIST_FOR_EACH_SAFE(cursor, cursor2, &m_AssociatedFocusWindows)
570 {
571 wnd = LIST_ENTRY(cursor, AssociatedWindow, entry);
572 if (wnd->hwnd == hwnd)
573 {
574 if (wnd->docmgr)
575 wnd->docmgr->AddRef();
576 *ppdimPrev = wnd->docmgr;
577 wnd->docmgr = pdimNew;
578 if (::GetFocus() == hwnd)
579 SetFocus(pdimNew);
580 return S_OK;
581 }
582 }
583
584 wnd = (AssociatedWindow *)cicMemAlloc(sizeof(AssociatedWindow));
585 wnd->hwnd = hwnd;
586 wnd->docmgr = pdimNew;
587 list_add_head(&m_AssociatedFocusWindows, &wnd->entry);
588
589 if (::GetFocus() == hwnd)
590 SetFocus(pdimNew);
591
592 this->SetupWindowsHook();
593 return S_OK;
594}
595
596STDMETHODIMP CThreadMgr::IsThreadFocus(_Out_ BOOL *pfThreadFocus)
597{
598 TRACE("(%p) %p\n", this, pfThreadFocus);
599
600 if (!pfThreadFocus)
601 return E_INVALIDARG;
602
603 HWND focus = ::GetFocus();
604 *pfThreadFocus = !focus;
605 return S_OK;
606}
607
608STDMETHODIMP CThreadMgr::GetFunctionProvider(
609 _In_ REFCLSID clsid,
610 _Out_ ITfFunctionProvider **ppFuncProv)
611{
612 FIXME("STUB:(%p)\n", this);
613 return E_NOTIMPL;
614}
615
616STDMETHODIMP CThreadMgr::EnumFunctionProviders(_Out_ IEnumTfFunctionProviders **ppEnum)
617{
618 FIXME("STUB:(%p)\n", this);
619 return E_NOTIMPL;
620}
621
622STDMETHODIMP CThreadMgr::GetGlobalCompartment(_Out_ ITfCompartmentMgr **ppCompMgr)
623{
624 HRESULT hr;
625 TRACE("(%p) %p\n", this, ppCompMgr);
626
627 if (!ppCompMgr)
628 return E_INVALIDARG;
629
630 if (!g_globalCompartmentMgr)
631 {
632 hr = CompartmentMgr_Constructor(NULL, IID_ITfCompartmentMgr, (IUnknown **)&g_globalCompartmentMgr);
633 if (FAILED(hr))
634 return hr;
635 }
636
637 g_globalCompartmentMgr->AddRef();
638 *ppCompMgr = g_globalCompartmentMgr;
639 return S_OK;
640}
641
642STDMETHODIMP CThreadMgr::ActivateEx(
643 _Out_ TfClientId *id,
644 _In_ DWORD flags)
645{
646 TRACE("(%p) %p, %#x\n", this, id, flags);
647
648 if (!id)
649 return E_INVALIDARG;
650
651 if (flags)
652 FIXME("Unimplemented flags %#x\n", flags);
653
654 if (!g_processId)
655 {
656 GUID guid;
657 CoCreateGuid(&guid);
658 GetClientId(guid, &g_processId);
659 }
660
661 activate_textservices(this);
662 ++m_activationCount;
663 *id = g_processId;
664 return S_OK;
665}
666
667STDMETHODIMP CThreadMgr::GetActiveFlags(_Out_ DWORD *flags)
668{
669 FIXME("STUB:(%p)\n", this);
670 return E_NOTIMPL;
671}
672
673STDMETHODIMP CThreadMgr::AdviseSink(
674 _In_ REFIID riid,
675 _In_ IUnknown *punk,
676 _Out_ DWORD *pdwCookie)
677{
678 TRACE("(%p) %s %p %p\n", this, debugstr_guid(&riid), punk, pdwCookie);
679
680 if (cicIsNullPtr(&riid) || !punk || !pdwCookie)
681 return E_INVALIDARG;
682
683 if (riid == IID_ITfThreadMgrEventSink)
684 return advise_sink(&m_ThreadMgrEventSink, IID_ITfThreadMgrEventSink, COOKIE_MAGIC_TMSINK, punk, pdwCookie);
685
686 if (riid == IID_ITfThreadFocusSink)
687 {
688 WARN("semi-stub for ITfThreadFocusSink: sink won't be used.\n");
689 return advise_sink(&m_ThreadFocusSink, IID_ITfThreadFocusSink, COOKIE_MAGIC_THREADFOCUSSINK, punk, pdwCookie);
690 }
691
692 if (riid == IID_ITfActiveLanguageProfileNotifySink)
693 {
694 WARN("semi-stub for ITfActiveLanguageProfileNotifySink: sink won't be used.\n");
695 return advise_sink(&m_ActiveLanguageProfileNotifySink, IID_ITfActiveLanguageProfileNotifySink,
696 COOKIE_MAGIC_ACTIVELANGSINK, punk, pdwCookie);
697 }
698
699 if (riid == IID_ITfKeyTraceEventSink)
700 {
701 WARN("semi-stub for ITfKeyTraceEventSink: sink won't be used.\n");
702 return advise_sink(&m_KeyTraceEventSink, IID_ITfKeyTraceEventSink,
703 COOKIE_MAGIC_KEYTRACESINK, punk, pdwCookie);
704 }
705
706 if (riid == IID_ITfUIElementSink)
707 {
708 WARN("semi-stub for ITfUIElementSink: sink won't be used.\n");
709 return advise_sink(&m_UIElementSink, IID_ITfUIElementSink,
710 COOKIE_MAGIC_UIELEMENTSINK, punk, pdwCookie);
711 }
712
713 if (riid == IID_ITfInputProcessorProfileActivationSink)
714 {
715 WARN("semi-stub for ITfInputProcessorProfileActivationSink: sink won't be used.\n");
716 return advise_sink(&m_InputProcessorProfileActivationSink, IID_ITfInputProcessorProfileActivationSink,
717 COOKIE_MAGIC_INPUTPROCESSORPROFILEACTIVATIONSINK, punk, pdwCookie);
718 }
719
720 FIXME("(%p) Unhandled Sink: %s\n", this, debugstr_guid(&riid));
721 return E_NOTIMPL;
722}
723
724STDMETHODIMP CThreadMgr::UnadviseSink(_In_ DWORD dwCookie)
725{
726 DWORD magic;
727
728 TRACE("(%p) %x\n", this, dwCookie);
729
730 magic = get_Cookie_magic(dwCookie);
731 if (magic != COOKIE_MAGIC_TMSINK &&
732 magic != COOKIE_MAGIC_THREADFOCUSSINK &&
733 magic != COOKIE_MAGIC_KEYTRACESINK &&
734 magic != COOKIE_MAGIC_UIELEMENTSINK &&
735 magic != COOKIE_MAGIC_INPUTPROCESSORPROFILEACTIVATIONSINK)
736 {
737 return E_INVALIDARG;
738 }
739
740 return unadvise_sink(dwCookie);
741}
742
743STDMETHODIMP CThreadMgr::AdviseKeyEventSink(
744 _In_ TfClientId tid,
745 _In_ ITfKeyEventSink *pSink,
746 _In_ BOOL fForeground)
747{
748 CLSID textservice;
749 ITfKeyEventSink *check = NULL;
750
751 TRACE("(%p) %x %p %i\n", this, tid, pSink, fForeground);
752
753 if (!tid || !pSink)
754 return E_INVALIDARG;
755
756 textservice = get_textservice_clsid(tid);
757 if (GUID_NULL == textservice)
758 return E_INVALIDARG;
759
760 get_textservice_sink(tid, IID_ITfKeyEventSink, (IUnknown **)&check);
761 if (check)
762 return CONNECT_E_ADVISELIMIT;
763
764 if (FAILED(pSink->QueryInterface(IID_ITfKeyEventSink, (LPVOID*)&check)))
765 return E_INVALIDARG;
766
767 set_textservice_sink(tid, IID_ITfKeyEventSink, check);
768
769 if (fForeground)
770 {
771 if (m_foregroundKeyEventSink)
772 {
773 m_foregroundKeyEventSink->OnSetFocus(FALSE);
774 m_foregroundKeyEventSink->Release();
775 }
776 check->AddRef();
777 check->OnSetFocus(TRUE);
778 m_foregroundKeyEventSink = check;
779 m_foregroundTextService = textservice;
780 }
781 return S_OK;
782}
783
784STDMETHODIMP CThreadMgr::UnadviseKeyEventSink(_In_ TfClientId tid)
785{
786 CLSID textservice;
787 ITfKeyEventSink *check = NULL;
788 TRACE("(%p) %x\n", this, tid);
789
790 if (!tid)
791 return E_INVALIDARG;
792
793 textservice = get_textservice_clsid(tid);
794 if (GUID_NULL == textservice)
795 return E_INVALIDARG;
796
797 get_textservice_sink(tid, IID_ITfKeyEventSink, (IUnknown **)&check);
798
799 if (!check)
800 return CONNECT_E_NOCONNECTION;
801
802 set_textservice_sink(tid, IID_ITfKeyEventSink, NULL);
803 check->Release();
804
805 if (m_foregroundKeyEventSink == check)
806 {
807 m_foregroundKeyEventSink->Release();
808 m_foregroundKeyEventSink = NULL;
809 m_foregroundTextService = GUID_NULL;
810 }
811 return S_OK;
812}
813
814STDMETHODIMP CThreadMgr::GetForeground(_Out_ CLSID *pclsid)
815{
816 TRACE("(%p) %p\n", this, pclsid);
817 if (!pclsid)
818 return E_INVALIDARG;
819
820 if (m_foregroundTextService == GUID_NULL)
821 return S_FALSE;
822
823 *pclsid = m_foregroundTextService;
824 return S_OK;
825}
826
827STDMETHODIMP CThreadMgr::TestKeyDown(
828 _In_ WPARAM wParam,
829 _In_ LPARAM lParam,
830 _Out_ BOOL *pfEaten)
831{
832 FIXME("STUB:(%p)\n", this);
833 if (!pfEaten)
834 return E_INVALIDARG;
835 *pfEaten = FALSE;
836 return S_OK;
837}
838
839STDMETHODIMP CThreadMgr::TestKeyUp(
840 _In_ WPARAM wParam,
841 _In_ LPARAM lParam,
842 _Out_ BOOL *pfEaten)
843{
844 FIXME("STUB:(%p)\n", this);
845 if (!pfEaten)
846 return E_INVALIDARG;
847 *pfEaten = FALSE;
848 return S_OK;
849}
850
851STDMETHODIMP CThreadMgr::KeyDown(
852 _In_ WPARAM wParam,
853 _In_ LPARAM lParam,
854 _Out_ BOOL *pfEaten)
855{
856 FIXME("STUB:(%p)\n", this);
857 if (!pfEaten)
858 return E_INVALIDARG;
859 *pfEaten = FALSE;
860 return E_NOTIMPL;
861}
862
863STDMETHODIMP CThreadMgr::KeyUp(
864 _In_ WPARAM wParam,
865 _In_ LPARAM lParam,
866 _Out_ BOOL *pfEaten)
867{
868 FIXME("STUB:(%p)\n", this);
869 if (!pfEaten)
870 return E_INVALIDARG;
871 *pfEaten = FALSE;
872 return E_NOTIMPL;
873}
874
875STDMETHODIMP CThreadMgr::GetPreservedKey(
876 _In_ ITfContext *pic,
877 _In_ const TF_PRESERVEDKEY *pprekey,
878 _Out_ GUID *pguid)
879{
880 FIXME("STUB:(%p)\n", this);
881 return E_NOTIMPL;
882}
883
884STDMETHODIMP CThreadMgr::IsPreservedKey(
885 _In_ REFGUID rguid,
886 _In_ const TF_PRESERVEDKEY *pprekey,
887 _Out_ BOOL *pfRegistered)
888{
889 struct list *cursor;
890
891 TRACE("(%p) %s (%x %x) %p\n", this, debugstr_guid(&rguid), (pprekey ? pprekey->uVKey : 0), (pprekey ? pprekey->uModifiers : 0), pfRegistered);
892
893 if (cicIsNullPtr(&rguid) || !pprekey || !pfRegistered)
894 return E_INVALIDARG;
895
896 LIST_FOR_EACH(cursor, &m_CurrentPreservedKeys)
897 {
898 PreservedKey* key = LIST_ENTRY(cursor, PreservedKey, entry);
899 if (rguid == key->guid && pprekey->uVKey == key->prekey.uVKey && pprekey->uModifiers == key->prekey.uModifiers)
900 {
901 *pfRegistered = TRUE;
902 return S_OK;
903 }
904 }
905
906 *pfRegistered = FALSE;
907 return S_FALSE;
908}
909
910STDMETHODIMP CThreadMgr::PreserveKey(
911 _In_ TfClientId tid,
912 _In_ REFGUID rguid,
913 _In_ const TF_PRESERVEDKEY *prekey,
914 _In_ const WCHAR *pchDesc,
915 _In_ ULONG cchDesc)
916{
917 struct list *cursor;
918
919 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));
920
921 if (!tid || cicIsNullPtr(&rguid) || !prekey || (cchDesc && !pchDesc))
922 return E_INVALIDARG;
923
924 LIST_FOR_EACH(cursor, &m_CurrentPreservedKeys)
925 {
926 PreservedKey* key = LIST_ENTRY(cursor, PreservedKey, entry);
927 if (rguid == key->guid && prekey->uVKey == key->prekey.uVKey && prekey->uModifiers == key->prekey.uModifiers)
928 return TF_E_ALREADY_EXISTS;
929 }
930
931 PreservedKey *newkey = (PreservedKey *)cicMemAlloc(sizeof(PreservedKey));
932 if (!newkey)
933 return E_OUTOFMEMORY;
934
935 newkey->guid = rguid;
936 newkey->prekey = *prekey;
937 newkey->tid = tid;
938 newkey->description = NULL;
939 if (cchDesc)
940 {
941 newkey->description = (LPWSTR)cicMemAlloc((cchDesc + 1) * sizeof(WCHAR));
942 if (!newkey->description)
943 {
944 cicMemFree(newkey);
945 return E_OUTOFMEMORY;
946 }
947 CopyMemory(newkey->description, pchDesc, cchDesc * sizeof(WCHAR));
948 newkey->description[cchDesc] = UNICODE_NULL;
949 }
950
951 list_add_head(&m_CurrentPreservedKeys, &newkey->entry);
952 return S_OK;
953}
954
955STDMETHODIMP CThreadMgr::UnpreserveKey(
956 _In_ REFGUID rguid,
957 _In_ const TF_PRESERVEDKEY *pprekey)
958{
959 PreservedKey* key = NULL;
960 struct list *cursor;
961 TRACE("(%p) %s (%x %x)\n", this, debugstr_guid(&rguid), (pprekey ? pprekey->uVKey : 0), (pprekey ? pprekey->uModifiers : 0));
962
963 if (!pprekey || cicIsNullPtr(&rguid))
964 return E_INVALIDARG;
965
966 LIST_FOR_EACH(cursor, &m_CurrentPreservedKeys)
967 {
968 key = LIST_ENTRY(cursor, PreservedKey, entry);
969 if (rguid == key->guid && pprekey->uVKey == key->prekey.uVKey && pprekey->uModifiers == key->prekey.uModifiers)
970 break;
971 key = NULL;
972 }
973
974 if (!key)
975 return CONNECT_E_NOCONNECTION;
976
977 list_remove(&key->entry);
978 cicMemFree(key->description);
979 cicMemFree(key);
980
981 return S_OK;
982}
983
984STDMETHODIMP CThreadMgr::SetPreservedKeyDescription(
985 _In_ REFGUID rguid,
986 _In_ const WCHAR *pchDesc,
987 _In_ ULONG cchDesc)
988{
989 FIXME("STUB:(%p)\n", this);
990 return E_NOTIMPL;
991}
992
993STDMETHODIMP CThreadMgr::GetPreservedKeyDescription(
994 _In_ REFGUID rguid,
995 _Out_ BSTR *pbstrDesc)
996{
997 FIXME("STUB:(%p)\n", this);
998 return E_NOTIMPL;
999}
1000
1001STDMETHODIMP CThreadMgr::SimulatePreservedKey(
1002 _In_ ITfContext *pic,
1003 _In_ REFGUID rguid,
1004 _Out_ BOOL *pfEaten)
1005{
1006 FIXME("STUB:(%p)\n", this);
1007 if (!pfEaten)
1008 return E_INVALIDARG;
1009 *pfEaten = FALSE;
1010 return E_NOTIMPL;
1011}
1012
1013STDMETHODIMP CThreadMgr::PeekMessageA(
1014 _Out_ LPMSG pMsg,
1015 _In_ HWND hwnd,
1016 _In_ UINT wMsgFilterMin,
1017 _In_ UINT wMsgFilterMax,
1018 _In_ UINT wRemoveMsg,
1019 _Out_ BOOL *pfResult)
1020{
1021 if (!pfResult)
1022 return E_INVALIDARG;
1023 *pfResult = ::PeekMessageA(pMsg, hwnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
1024 return S_OK;
1025}
1026
1027STDMETHODIMP CThreadMgr::GetMessageA(
1028 _Out_ LPMSG pMsg,
1029 _In_ HWND hwnd,
1030 _In_ UINT wMsgFilterMin,
1031 _In_ UINT wMsgFilterMax,
1032 _Out_ BOOL *pfResult)
1033{
1034 if (!pfResult)
1035 return E_INVALIDARG;
1036 *pfResult = ::GetMessageA(pMsg, hwnd, wMsgFilterMin, wMsgFilterMax);
1037 return S_OK;
1038}
1039
1040STDMETHODIMP CThreadMgr::PeekMessageW(
1041 _Out_ LPMSG pMsg,
1042 _In_ HWND hwnd,
1043 _In_ UINT wMsgFilterMin,
1044 _In_ UINT wMsgFilterMax,
1045 _In_ UINT wRemoveMsg,
1046 _Out_ BOOL *pfResult)
1047{
1048 if (!pfResult)
1049 return E_INVALIDARG;
1050 *pfResult = ::PeekMessageW(pMsg, hwnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
1051 return S_OK;
1052}
1053
1054STDMETHODIMP CThreadMgr::GetMessageW(
1055 _Out_ LPMSG pMsg,
1056 _In_ HWND hwnd,
1057 _In_ UINT wMsgFilterMin,
1058 _In_ UINT wMsgFilterMax,
1059 _Out_ BOOL *pfResult)
1060{
1061 if (!pfResult)
1062 return E_INVALIDARG;
1063 *pfResult = ::GetMessageW(pMsg, hwnd, wMsgFilterMin, wMsgFilterMax);
1064 return S_OK;
1065}
1066
1067STDMETHODIMP CThreadMgr::GetClientId(
1068 _In_ REFCLSID rclsid,
1069 _Out_ TfClientId *ptid)
1070{
1071 HRESULT hr;
1072 ITfCategoryMgr *catmgr;
1073
1074 TRACE("(%p) %s\n", this, debugstr_guid(&rclsid));
1075
1076 CategoryMgr_Constructor(NULL, (IUnknown **)&catmgr);
1077 hr = catmgr->RegisterGUID(rclsid, ptid);
1078 catmgr->Release();
1079
1080 return hr;
1081}
1082
1083STDMETHODIMP CThreadMgr::OnInitDocumentMgr(_In_ ITfDocumentMgr *pdim)
1084{
1085 ITfThreadMgrEventSink *sink;
1086 struct list *cursor;
1087
1088 TRACE("(%p) %p\n", this, pdim);
1089
1090 SINK_FOR_EACH(cursor, &m_ThreadMgrEventSink, ITfThreadMgrEventSink, sink)
1091 {
1092 sink->OnInitDocumentMgr(pdim);
1093 }
1094
1095 return S_OK;
1096}
1097
1098STDMETHODIMP CThreadMgr::OnUninitDocumentMgr(_In_ ITfDocumentMgr *pdim)
1099{
1100 ITfThreadMgrEventSink *sink;
1101 struct list *cursor;
1102
1103 TRACE("(%p) %p\n", this, pdim);
1104
1105 SINK_FOR_EACH(cursor, &m_ThreadMgrEventSink, ITfThreadMgrEventSink, sink)
1106 {
1107 sink->OnUninitDocumentMgr(pdim);
1108 }
1109
1110 return S_OK;
1111}
1112
1113STDMETHODIMP CThreadMgr::OnSetFocus(
1114 _In_ ITfDocumentMgr *pdimFocus,
1115 _In_ ITfDocumentMgr *pdimPrevFocus)
1116{
1117 ITfThreadMgrEventSink *sink;
1118 struct list *cursor;
1119
1120 TRACE("(%p) %p %p\n", this, pdimFocus, pdimPrevFocus);
1121
1122 SINK_FOR_EACH(cursor, &m_ThreadMgrEventSink, ITfThreadMgrEventSink, sink)
1123 {
1124 sink->OnSetFocus(pdimFocus, pdimPrevFocus);
1125 }
1126
1127 return S_OK;
1128}
1129
1130STDMETHODIMP CThreadMgr::OnPushContext(_In_ ITfContext *pic)
1131{
1132 ITfThreadMgrEventSink *sink;
1133 struct list *cursor;
1134
1135 TRACE("(%p) %p\n", this, pic);
1136
1137 SINK_FOR_EACH(cursor, &m_ThreadMgrEventSink, ITfThreadMgrEventSink, sink)
1138 {
1139 sink->OnPushContext(pic);
1140 }
1141
1142 return S_OK;
1143}
1144
1145STDMETHODIMP CThreadMgr::OnPopContext(_In_ ITfContext *pic)
1146{
1147 ITfThreadMgrEventSink *sink;
1148 struct list *cursor;
1149
1150 TRACE("(%p) %p\n", this, pic);
1151
1152 SINK_FOR_EACH(cursor, &m_ThreadMgrEventSink, ITfThreadMgrEventSink, sink)
1153 {
1154 sink->OnPopContext(pic);
1155 }
1156
1157 return S_OK;
1158}
1159
1160STDMETHODIMP CThreadMgr::BeginUIElement(
1161 _In_ ITfUIElement *element,
1162 _Inout_ BOOL *show,
1163 _Out_ DWORD *id)
1164{
1165 FIXME("STUB:(%p)\n", this);
1166 return E_NOTIMPL;
1167}
1168
1169STDMETHODIMP CThreadMgr::UpdateUIElement(_In_ DWORD id)
1170{
1171 FIXME("STUB:(%p)\n", this);
1172 return E_NOTIMPL;
1173}
1174
1175STDMETHODIMP CThreadMgr::EndUIElement(_In_ DWORD id)
1176{
1177 FIXME("STUB:(%p)\n", this);
1178 return E_NOTIMPL;
1179}
1180
1181STDMETHODIMP CThreadMgr::GetUIElement(
1182 _In_ DWORD id,
1183 _Out_ ITfUIElement **element)
1184{
1185 FIXME("STUB:(%p)\n", this);
1186 return E_NOTIMPL;
1187}
1188
1189STDMETHODIMP CThreadMgr::EnumUIElements(_Out_ IEnumTfUIElements **enum_elements)
1190{
1191 FIXME("STUB:(%p)\n", this);
1192 return E_NOTIMPL;
1193}
1194
1195STDMETHODIMP CThreadMgr::AdviseSingleSink(
1196 _In_ TfClientId tid,
1197 _In_ REFIID riid,
1198 _In_ IUnknown *punk)
1199{
1200 FIXME("STUB:(%p) %i %s %p\n", this, tid, debugstr_guid(&riid), punk);
1201 return E_NOTIMPL;
1202}
1203
1204STDMETHODIMP CThreadMgr::UnadviseSingleSink(
1205 _In_ TfClientId tid,
1206 _In_ REFIID riid)
1207{
1208 FIXME("STUB:(%p) %i %s\n", this, tid, debugstr_guid(&riid));
1209 return E_NOTIMPL;
1210}
1211
1212HRESULT CThreadMgr::CreateInstance(IUnknown *pUnkOuter, CThreadMgr **ppOut)
1213{
1214 if (pUnkOuter)
1215 return CLASS_E_NOAGGREGATION;
1216
1217 /* Only 1 ThreadMgr is created per thread */
1218 CThreadMgr *This = (CThreadMgr *)TlsGetValue(g_dwTLSIndex);
1219 if (This)
1220 {
1221 This->AddRef();
1222 *ppOut = This;
1223 return S_OK;
1224 }
1225
1226 This = new(cicNoThrow) CThreadMgr();
1227 if (!This)
1228 return E_OUTOFMEMORY;
1229
1230 TlsSetValue(g_dwTLSIndex, This);
1231
1232 ITfCompartmentMgr *pCompMgr = NULL;
1233 CompartmentMgr_Constructor(static_cast<ITfThreadMgrEx *>(This), IID_IUnknown, (IUnknown **)&pCompMgr);
1234 This->m_CompartmentMgr = pCompMgr;
1235
1236 TRACE("returning %p\n", This);
1237 *ppOut = This;
1238 return S_OK;
1239}
1240
1241void CThreadMgr::OnDocumentMgrDestruction(ITfDocumentMgr *mgr)
1242{
1243 struct list *cursor;
1244 LIST_FOR_EACH(cursor, &m_CreatedDocumentMgrs)
1245 {
1246 DocumentMgrEntry *mgrentry = LIST_ENTRY(cursor, DocumentMgrEntry, entry);
1247 if (mgrentry->docmgr == mgr)
1248 {
1249 list_remove(cursor);
1250 cicMemFree(mgrentry);
1251 return;
1252 }
1253 }
1254 FIXME("ITfDocumentMgr %p not found in this thread\n", mgr);
1255}
1256
1257////////////////////////////////////////////////////////////////////////////
1258
1259CEnumTfDocumentMgr::CEnumTfDocumentMgr()
1260 : m_cRefs(1)
1261 , m_index(NULL)
1262 , m_head(NULL)
1263{
1264}
1265
1266CEnumTfDocumentMgr::~CEnumTfDocumentMgr()
1267{
1268 TRACE("destroying %p\n", this);
1269}
1270
1271STDMETHODIMP CEnumTfDocumentMgr::QueryInterface(REFIID iid, LPVOID *ppvObject)
1272{
1273 *ppvObject = NULL;
1274
1275 if (iid == IID_IUnknown || iid == IID_IEnumTfDocumentMgrs)
1276 *ppvObject = static_cast<IEnumTfDocumentMgrs *>(this);
1277
1278 if (*ppvObject)
1279 {
1280 AddRef();
1281 return S_OK;
1282 }
1283
1284 WARN("unsupported interface: %s\n", debugstr_guid(&iid));
1285 return E_NOINTERFACE;
1286}
1287
1288STDMETHODIMP_(ULONG) CEnumTfDocumentMgr::AddRef()
1289{
1290 return InterlockedIncrement(&m_cRefs);
1291}
1292
1293STDMETHODIMP_(ULONG) CEnumTfDocumentMgr::Release()
1294{
1295 ULONG ret = InterlockedDecrement(&m_cRefs);
1296 if (!ret)
1297 delete this;
1298 return ret;
1299}
1300
1301STDMETHODIMP CEnumTfDocumentMgr::Clone(_Out_ IEnumTfDocumentMgrs **ppEnum)
1302{
1303 TRACE("(%p)\n", this);
1304
1305 if (!ppEnum)
1306 return E_POINTER;
1307
1308 *ppEnum = NULL;
1309
1310 CEnumTfDocumentMgr *cloned;
1311 HRESULT hr = CEnumTfDocumentMgr::CreateInstance(m_head, &cloned);
1312 if (SUCCEEDED(hr))
1313 {
1314 *ppEnum = static_cast<IEnumTfDocumentMgrs *>(cloned);
1315 cloned->m_index = m_index;
1316 }
1317
1318 return hr;
1319}
1320
1321STDMETHODIMP CEnumTfDocumentMgr::Next(
1322 _In_ ULONG ulCount,
1323 _Out_ ITfDocumentMgr **rgDocumentMgr,
1324 _Out_ ULONG *pcFetched)
1325{
1326 ULONG fetched = 0;
1327
1328 TRACE("(%p)\n", this);
1329
1330 if (!rgDocumentMgr)
1331 return E_POINTER;
1332
1333 while (fetched < ulCount)
1334 {
1335 DocumentMgrEntry *mgrentry;
1336 if (!m_index)
1337 break;
1338
1339 mgrentry = LIST_ENTRY(m_index, DocumentMgrEntry, entry);
1340 if (!mgrentry)
1341 break;
1342
1343 *rgDocumentMgr = mgrentry->docmgr;
1344 (*rgDocumentMgr)->AddRef();
1345
1346 m_index = list_next(m_head, m_index);
1347 ++fetched;
1348 ++rgDocumentMgr;
1349 }
1350
1351 if (pcFetched)
1352 *pcFetched = fetched;
1353 return fetched == ulCount ? S_OK : S_FALSE;
1354}
1355
1356STDMETHODIMP CEnumTfDocumentMgr::Reset()
1357{
1358 TRACE("(%p)\n", this);
1359 m_index = list_head(m_head);
1360 return S_OK;
1361}
1362
1363STDMETHODIMP CEnumTfDocumentMgr::Skip(_In_ ULONG ulCount)
1364{
1365 TRACE("(%p)\n", this);
1366 for (ULONG i = 0; i < ulCount && m_index; ++i)
1367 m_index = list_next(m_head, m_index);
1368 return S_OK;
1369}
1370
1371HRESULT CEnumTfDocumentMgr::CreateInstance(struct list* head, CEnumTfDocumentMgr **ppOut)
1372{
1373 CEnumTfDocumentMgr *This = new(cicNoThrow) CEnumTfDocumentMgr();
1374 if (!This)
1375 return E_OUTOFMEMORY;
1376
1377 This->m_head = head;
1378 This->m_index = list_head(This->m_head);
1379
1380 *ppOut = This;
1381 TRACE("returning %p\n", *ppOut);
1382 return S_OK;
1383}
1384
1385////////////////////////////////////////////////////////////////////////////
1386
1387EXTERN_C
1388HRESULT ThreadMgr_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut)
1389{
1390 return CThreadMgr::CreateInstance(pUnkOuter, (CThreadMgr **)ppOut);
1391}
1392
1393EXTERN_C
1394void ThreadMgr_OnDocumentMgrDestruction(ITfThreadMgr *iface, ITfDocumentMgr *mgr)
1395{
1396 CThreadMgr *This = static_cast<CThreadMgr *>(iface);
1397 This->OnDocumentMgrDestruction(mgr);
1398}