Reactos
at master 460 lines 11 kB view raw
1/* 2 * PROJECT: ReactOS CTF 3 * LICENSE: LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later) 4 * PURPOSE: Implementation of ITfDocumentMgr and IEnumTfContexts 5 * COPYRIGHT: Copyright 2009 Aric Stewart, CodeWeavers 6 * Copyright 2025 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com> 7 */ 8 9#include "precomp.h" 10#include "documentmgr.h" 11 12#include <wine/debug.h> 13WINE_DEFAULT_DEBUG_CHANNEL(msctf); 14 15//////////////////////////////////////////////////////////////////////////// 16 17CDocumentMgr::CDocumentMgr(ITfThreadMgrEventSink *threadMgrSink) 18 : m_cRefs(1) 19 , m_pCompartmentMgr(NULL) 20 , m_initialContext(NULL) 21 , m_pThreadMgrSink(threadMgrSink) 22{ 23 m_contextStack[1] = m_contextStack[0] = NULL; 24 25 list_init(&m_transitoryExtensionSink); 26 27 ITfDocumentMgr *pDocMgr = static_cast<ITfDocumentMgr *>(this); 28 ITfCompartmentMgr **ppCompMgr = static_cast<ITfCompartmentMgr **>(&m_pCompartmentMgr); 29 CompartmentMgr_Constructor(pDocMgr, IID_IUnknown, reinterpret_cast<IUnknown **>(ppCompMgr)); 30 31 DWORD cookie; 32 Context_Constructor(g_processId, NULL, pDocMgr, &m_initialContext, &cookie); 33} 34 35CDocumentMgr::~CDocumentMgr() 36{ 37 TRACE("destroying %p\n", this); 38 39 ITfThreadMgr *tm = NULL; 40 TF_GetThreadMgr(&tm); 41 if (tm) 42 { 43 ThreadMgr_OnDocumentMgrDestruction(tm, static_cast<ITfDocumentMgr*>(this)); 44 tm->Release(); 45 } 46 47 if (m_initialContext) 48 m_initialContext->Release(); 49 if (m_contextStack[0]) 50 m_contextStack[0]->Release(); 51 if (m_contextStack[1]) 52 m_contextStack[1]->Release(); 53 54 free_sinks(&m_transitoryExtensionSink); 55 56 if (m_pCompartmentMgr) 57 { 58 m_pCompartmentMgr->Release(); 59 m_pCompartmentMgr = NULL; 60 } 61} 62 63HRESULT 64CDocumentMgr::CreateInstance( 65 _In_ ITfThreadMgrEventSink *pThreadMgrSink, 66 _Out_ ITfDocumentMgr **ppOut) 67{ 68 if (!ppOut) 69 { 70 ERR("!ppOut\n"); 71 return E_POINTER; 72 } 73 74 if (!pThreadMgrSink) 75 { 76 ERR("!pThreadMgrSink\n"); 77 return E_INVALIDARG; 78 } 79 80 CDocumentMgr *This = new(cicNoThrow) CDocumentMgr(pThreadMgrSink); 81 if (!This) 82 { 83 ERR("E_OUTOFMEMORY\n"); 84 return E_OUTOFMEMORY; 85 } 86 87 *ppOut = static_cast<ITfDocumentMgr *>(This); 88 TRACE("returning %p\n", *ppOut); 89 return S_OK; 90} 91 92STDMETHODIMP CDocumentMgr::QueryInterface(REFIID iid, LPVOID *ppvObject) 93{ 94 TRACE("%p -> (%s, %p)\n", this, wine_dbgstr_guid(&iid), ppvObject); 95 *ppvObject = NULL; 96 97 IUnknown *pUnk = NULL; 98 if (iid == IID_IUnknown || iid == IID_ITfDocumentMgr) 99 pUnk = static_cast<ITfDocumentMgr *>(this); 100 else if (iid == IID_ITfSource) 101 pUnk = static_cast<ITfSource *>(this); 102 else if (iid == IID_ITfCompartmentMgr) 103 pUnk = m_pCompartmentMgr; 104 105 if (pUnk) 106 { 107 pUnk->AddRef(); 108 *ppvObject = pUnk; 109 return S_OK; 110 } 111 112 WARN("unsupported interface: %s\n", debugstr_guid(&iid)); 113 return E_NOINTERFACE; 114} 115 116STDMETHODIMP_(ULONG) CDocumentMgr::AddRef() 117{ 118 TRACE("%p -> ()\n", this); 119 return ::InterlockedIncrement(&m_cRefs); 120} 121 122STDMETHODIMP_(ULONG) CDocumentMgr::Release() 123{ 124 TRACE("%p -> ()\n", this); 125 ULONG ret = ::InterlockedDecrement(&m_cRefs); 126 if (!ret) 127 delete this; 128 return ret; 129} 130 131STDMETHODIMP 132CDocumentMgr::CreateContext( 133 TfClientId tidOwner, 134 DWORD dwFlags, 135 IUnknown *punk, 136 ITfContext **ppic, 137 TfEditCookie *pecTextStore) 138{ 139 TRACE("%p -> (%d, 0x%lX, %p, %p, %p)\n", this, tidOwner, dwFlags, punk, ppic, pecTextStore); 140 return Context_Constructor(tidOwner, punk, this, ppic, pecTextStore); 141} 142 143STDMETHODIMP CDocumentMgr::Push(ITfContext *pic) 144{ 145 TRACE("%p -> (%p)\n", this, pic); 146 147 if (m_contextStack[1]) /* Full */ 148 { 149 ERR("TF_E_STACKFULL\n"); 150 return TF_E_STACKFULL; 151 } 152 153 if (!pic) 154 { 155 ERR("!pic\n"); 156 return E_INVALIDARG; 157 } 158 159 ITfContext *check; 160 HRESULT hr = pic->QueryInterface(IID_ITfContext, reinterpret_cast<LPVOID *>(&check)); 161 if (FAILED(hr)) 162 { 163 ERR("hr: 0x%lX\n", hr); 164 return E_INVALIDARG; 165 } 166 167 if (!m_contextStack[0]) 168 m_pThreadMgrSink->OnInitDocumentMgr(this); 169 170 m_contextStack[1] = m_contextStack[0]; 171 m_contextStack[0] = check; 172 173 Context_Initialize(check, this); 174 m_pThreadMgrSink->OnPushContext(check); 175 176 return S_OK; 177} 178 179STDMETHODIMP CDocumentMgr::Pop(DWORD dwFlags) 180{ 181 TRACE("%p -> (0x%lX)\n", this, dwFlags); 182 183 if (dwFlags == TF_POPF_ALL) 184 { 185 for (SIZE_T i = 0; i < _countof(m_contextStack); i++) 186 { 187 if (!m_contextStack[i]) 188 continue; 189 190 m_pThreadMgrSink->OnPopContext(m_contextStack[i]); 191 Context_Uninitialize(m_contextStack[i]); 192 m_contextStack[i]->Release(); 193 m_contextStack[i] = NULL; 194 } 195 196 m_pThreadMgrSink->OnUninitDocumentMgr(this); 197 return S_OK; 198 } 199 200 if (dwFlags) 201 { 202 ERR("E_INVALIDARG: 0x%lX\n", dwFlags); 203 return E_INVALIDARG; 204 } 205 206 if (!m_contextStack[1]) // Cannot pop last context 207 { 208 ERR("!m_contextStack[1]\n"); 209 return E_FAIL; 210 } 211 212 m_pThreadMgrSink->OnPopContext(m_contextStack[0]); 213 Context_Uninitialize(m_contextStack[0]); 214 215 if (m_contextStack[0]) 216 m_contextStack[0]->Release(); 217 218 m_contextStack[0] = m_contextStack[1]; 219 m_contextStack[1] = NULL; 220 221 if (!m_contextStack[0]) 222 m_pThreadMgrSink->OnUninitDocumentMgr(this); 223 224 return S_OK; 225} 226 227STDMETHODIMP CDocumentMgr::GetTop(ITfContext **ppic) 228{ 229 TRACE("%p -> (%p)\n", this, ppic); 230 231 if (!ppic) 232 { 233 ERR("!ppic\n"); 234 return E_INVALIDARG; 235 } 236 237 ITfContext *target; 238 if (m_contextStack[0]) 239 target = m_contextStack[0]; 240 else 241 target = m_initialContext; 242 243 if (target) 244 target->AddRef(); 245 246 *ppic = target; 247 return S_OK; 248} 249 250STDMETHODIMP CDocumentMgr::GetBase(ITfContext **ppic) 251{ 252 TRACE("%p -> (%p)\n", this, ppic); 253 254 if (!ppic) 255 { 256 ERR("!ppic\n"); 257 return E_INVALIDARG; 258 } 259 260 ITfContext *target; 261 if (m_contextStack[1]) 262 target = m_contextStack[1]; 263 else if (m_contextStack[0]) 264 target = m_contextStack[0]; 265 else 266 target = m_initialContext; 267 268 if (target) 269 target->AddRef(); 270 271 *ppic = target; 272 return S_OK; 273} 274 275STDMETHODIMP CDocumentMgr::EnumContexts(IEnumTfContexts **ppEnum) 276{ 277 TRACE("%p -> (%p)\n", this, ppEnum); 278 return EnumTfContext_Constructor(this, ppEnum); 279} 280 281STDMETHODIMP CDocumentMgr::AdviseSink(REFIID riid, IUnknown *punk, DWORD *pdwCookie) 282{ 283 TRACE("%p -> (%s, %p, %p)\n", this, wine_dbgstr_guid(&riid), punk, pdwCookie); 284 285 if (cicIsNullPtr(&riid) || !punk || !pdwCookie) 286 return E_INVALIDARG; 287 288 if (riid == IID_ITfTransitoryExtensionSink) 289 { 290 WARN("semi-stub for ITfTransitoryExtensionSink: callback won't be used.\n"); 291 return advise_sink(&m_transitoryExtensionSink, IID_ITfTransitoryExtensionSink, 292 COOKIE_MAGIC_DMSINK, punk, pdwCookie); 293 } 294 295 FIXME("(%p) Unhandled Sink: %s\n", this, debugstr_guid(&riid)); 296 return E_NOTIMPL; 297} 298 299STDMETHODIMP CDocumentMgr::UnadviseSink(DWORD pdwCookie) 300{ 301 TRACE("%p -> (%p)\n", this, pdwCookie); 302 303 if (get_Cookie_magic(pdwCookie) != COOKIE_MAGIC_DMSINK) 304 return E_INVALIDARG; 305 306 return unadvise_sink(pdwCookie); 307} 308 309//////////////////////////////////////////////////////////////////////////// 310 311CEnumTfContext::CEnumTfContext(_In_opt_ CDocumentMgr *mgr) 312 : m_cRefs(1) 313 , m_index(0) 314 , m_pDocMgr(mgr) 315{ 316 if (mgr) 317 mgr->AddRef(); 318} 319 320CEnumTfContext::~CEnumTfContext() 321{ 322 if (m_pDocMgr) 323 { 324 m_pDocMgr->Release(); 325 m_pDocMgr = NULL; 326 } 327} 328 329HRESULT CEnumTfContext::CreateInstance(_In_opt_ CDocumentMgr *mgr, _Out_ IEnumTfContexts **ppOut) 330{ 331 if (!ppOut) 332 { 333 ERR("!ppOut\n"); 334 return E_POINTER; 335 } 336 337 CEnumTfContext *This = new(cicNoThrow) CEnumTfContext(mgr); 338 if (!This) 339 { 340 ERR("E_OUTOFMEMORY\n"); 341 return E_OUTOFMEMORY; 342 } 343 344 *ppOut = static_cast<IEnumTfContexts *>(This); 345 TRACE("returning %p\n", *ppOut); 346 return S_OK; 347} 348 349STDMETHODIMP CEnumTfContext::QueryInterface(REFIID iid, LPVOID *ppvObject) 350{ 351 TRACE("%p -> (%s, %p)\n", this, wine_dbgstr_guid(&iid), ppvObject); 352 353 *ppvObject = NULL; 354 355 if (iid == IID_IUnknown || iid == IID_IEnumTfContexts) 356 *ppvObject = static_cast<IEnumTfContexts *>(this); 357 358 if (*ppvObject) 359 { 360 AddRef(); 361 return S_OK; 362 } 363 364 WARN("E_NOINTERFACE: %s\n", wine_dbgstr_guid(&iid)); 365 return E_NOINTERFACE; 366} 367 368STDMETHODIMP_(ULONG) CEnumTfContext::AddRef() 369{ 370 TRACE("%p -> ()\n", this); 371 return ::InterlockedIncrement(&m_cRefs); 372} 373 374STDMETHODIMP_(ULONG) CEnumTfContext::Release() 375{ 376 TRACE("%p -> ()\n", this); 377 ULONG ret = ::InterlockedDecrement(&m_cRefs); 378 if (!ret) 379 delete this; 380 return ret; 381} 382 383STDMETHODIMP CEnumTfContext::Next(ULONG ulCount, ITfContext **rgContext, ULONG *pcFetched) 384{ 385 TRACE("%p -> (%lu, %p, %p)\n",this, ulCount, rgContext, pcFetched); 386 387 if (!rgContext) 388 { 389 ERR("!rgContext\n"); 390 return E_POINTER; 391 } 392 393 ULONG fetched; 394 for (fetched = 0; fetched < ulCount; ++fetched, ++m_index, ++rgContext) 395 { 396 if (m_index >= _countof(m_pDocMgr->m_contextStack)) 397 break; 398 399 if (!m_pDocMgr->m_contextStack[m_index]) 400 break; 401 402 *rgContext = m_pDocMgr->m_contextStack[m_index]; 403 (*rgContext)->AddRef(); 404 } 405 406 if (pcFetched) 407 *pcFetched = fetched; 408 409 return (fetched == ulCount) ? S_OK : S_FALSE; 410} 411 412STDMETHODIMP CEnumTfContext::Skip(ULONG celt) 413{ 414 TRACE("%p -> (%lu)\n", this, celt); 415 m_index += celt; 416 return S_OK; 417} 418 419STDMETHODIMP CEnumTfContext::Reset() 420{ 421 TRACE("%p -> ()\n", this); 422 m_index = 0; 423 return S_OK; 424} 425 426STDMETHODIMP CEnumTfContext::Clone(IEnumTfContexts **ppenum) 427{ 428 TRACE("%p -> (%p)\n", this, ppenum); 429 430 if (!ppenum) 431 { 432 ERR("!ppenum\n"); 433 return E_POINTER; 434 } 435 436 CEnumTfContext *This = new(cicNoThrow) CEnumTfContext(m_pDocMgr); 437 if (!This) 438 { 439 ERR("E_OUTOFMEMORY\n"); 440 return E_OUTOFMEMORY; 441 } 442 443 This->m_index = m_index; 444 *ppenum = This; 445 return S_OK; 446} 447 448//////////////////////////////////////////////////////////////////////////// 449 450EXTERN_C 451HRESULT DocumentMgr_Constructor(ITfThreadMgrEventSink *pThreadMgrSink, ITfDocumentMgr **ppOut) 452{ 453 return CDocumentMgr::CreateInstance(pThreadMgrSink, ppOut); 454} 455 456EXTERN_C 457HRESULT EnumTfContext_Constructor(CDocumentMgr *mgr, IEnumTfContexts **ppOut) 458{ 459 return CEnumTfContext::CreateInstance(mgr, ppOut); 460}