1 /* 2 * ITfDocumentMgr implementation 3 * 4 * Copyright 2009 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 36 #include "wine/unicode.h" 37 38 #include "msctf.h" 39 #include "msctf_internal.h" 40 41 WINE_DEFAULT_DEBUG_CHANNEL(msctf); 42 43 typedef struct tagDocumentMgr { 44 ITfDocumentMgr ITfDocumentMgr_iface; 45 ITfSource ITfSource_iface; 46 LONG refCount; 47 48 /* Aggregation */ 49 ITfCompartmentMgr *CompartmentMgr; 50 51 ITfContext* contextStack[2]; /* limit of 2 contexts */ 52 ITfThreadMgrEventSink* ThreadMgrSink; 53 54 struct list TransitoryExtensionSink; 55 } DocumentMgr; 56 57 typedef struct tagEnumTfContext { 58 IEnumTfContexts IEnumTfContexts_iface; 59 LONG refCount; 60 61 DWORD index; 62 DocumentMgr *docmgr; 63 } EnumTfContext; 64 65 static HRESULT EnumTfContext_Constructor(DocumentMgr* mgr, IEnumTfContexts **ppOut); 66 67 static inline DocumentMgr *impl_from_ITfDocumentMgr(ITfDocumentMgr *iface) 68 { 69 return CONTAINING_RECORD(iface, DocumentMgr, ITfDocumentMgr_iface); 70 } 71 72 static inline DocumentMgr *impl_from_ITfSource(ITfSource *iface) 73 { 74 return CONTAINING_RECORD(iface, DocumentMgr, ITfSource_iface); 75 } 76 77 static inline EnumTfContext *impl_from_IEnumTfContexts(IEnumTfContexts *iface) 78 { 79 return CONTAINING_RECORD(iface, EnumTfContext, IEnumTfContexts_iface); 80 } 81 82 static void DocumentMgr_Destructor(DocumentMgr *This) 83 { 84 ITfThreadMgr *tm; 85 TRACE("destroying %p\n", This); 86 87 TF_GetThreadMgr(&tm); 88 ThreadMgr_OnDocumentMgrDestruction(tm, &This->ITfDocumentMgr_iface); 89 90 if (This->contextStack[0]) 91 ITfContext_Release(This->contextStack[0]); 92 if (This->contextStack[1]) 93 ITfContext_Release(This->contextStack[1]); 94 free_sinks(&This->TransitoryExtensionSink); 95 CompartmentMgr_Destructor(This->CompartmentMgr); 96 HeapFree(GetProcessHeap(),0,This); 97 } 98 99 static HRESULT WINAPI DocumentMgr_QueryInterface(ITfDocumentMgr *iface, REFIID iid, LPVOID *ppvOut) 100 { 101 DocumentMgr *This = impl_from_ITfDocumentMgr(iface); 102 *ppvOut = NULL; 103 104 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfDocumentMgr)) 105 { 106 *ppvOut = &This->ITfDocumentMgr_iface; 107 } 108 else if (IsEqualIID(iid, &IID_ITfSource)) 109 { 110 *ppvOut = &This->ITfSource_iface; 111 } 112 else if (IsEqualIID(iid, &IID_ITfCompartmentMgr)) 113 { 114 *ppvOut = This->CompartmentMgr; 115 } 116 117 if (*ppvOut) 118 { 119 ITfDocumentMgr_AddRef(iface); 120 return S_OK; 121 } 122 123 WARN("unsupported interface: %s\n", debugstr_guid(iid)); 124 return E_NOINTERFACE; 125 } 126 127 static ULONG WINAPI DocumentMgr_AddRef(ITfDocumentMgr *iface) 128 { 129 DocumentMgr *This = impl_from_ITfDocumentMgr(iface); 130 return InterlockedIncrement(&This->refCount); 131 } 132 133 static ULONG WINAPI DocumentMgr_Release(ITfDocumentMgr *iface) 134 { 135 DocumentMgr *This = impl_from_ITfDocumentMgr(iface); 136 ULONG ret; 137 138 ret = InterlockedDecrement(&This->refCount); 139 if (ret == 0) 140 DocumentMgr_Destructor(This); 141 return ret; 142 } 143 144 /***************************************************** 145 * ITfDocumentMgr functions 146 *****************************************************/ 147 static HRESULT WINAPI DocumentMgr_CreateContext(ITfDocumentMgr *iface, 148 TfClientId tidOwner, 149 DWORD dwFlags, IUnknown *punk, ITfContext **ppic, 150 TfEditCookie *pecTextStore) 151 { 152 DocumentMgr *This = impl_from_ITfDocumentMgr(iface); 153 TRACE("(%p) 0x%x 0x%x %p %p %p\n",This,tidOwner,dwFlags,punk,ppic,pecTextStore); 154 return Context_Constructor(tidOwner, punk, iface, ppic, pecTextStore); 155 } 156 157 static HRESULT WINAPI DocumentMgr_Push(ITfDocumentMgr *iface, ITfContext *pic) 158 { 159 DocumentMgr *This = impl_from_ITfDocumentMgr(iface); 160 ITfContext *check; 161 162 TRACE("(%p) %p\n",This,pic); 163 164 if (This->contextStack[1]) /* FUll */ 165 return TF_E_STACKFULL; 166 167 if (!pic || FAILED(ITfContext_QueryInterface(pic,&IID_ITfContext,(LPVOID*) &check))) 168 return E_INVALIDARG; 169 170 if (This->contextStack[0] == NULL) 171 ITfThreadMgrEventSink_OnInitDocumentMgr(This->ThreadMgrSink,iface); 172 173 This->contextStack[1] = This->contextStack[0]; 174 This->contextStack[0] = check; 175 176 Context_Initialize(check, iface); 177 ITfThreadMgrEventSink_OnPushContext(This->ThreadMgrSink,check); 178 179 return S_OK; 180 } 181 182 static HRESULT WINAPI DocumentMgr_Pop(ITfDocumentMgr *iface, DWORD dwFlags) 183 { 184 DocumentMgr *This = impl_from_ITfDocumentMgr(iface); 185 TRACE("(%p) 0x%x\n",This,dwFlags); 186 187 if (dwFlags == TF_POPF_ALL) 188 { 189 int i; 190 191 for (i = 0; i < sizeof(This->contextStack)/sizeof(This->contextStack[0]); i++) 192 if (This->contextStack[i]) 193 { 194 ITfThreadMgrEventSink_OnPopContext(This->ThreadMgrSink, This->contextStack[i]); 195 Context_Uninitialize(This->contextStack[i]); 196 ITfContext_Release(This->contextStack[i]); 197 This->contextStack[i] = NULL; 198 } 199 200 ITfThreadMgrEventSink_OnUninitDocumentMgr(This->ThreadMgrSink, iface); 201 return S_OK; 202 } 203 204 if (dwFlags) 205 return E_INVALIDARG; 206 207 if (This->contextStack[1] == NULL) /* Cannot pop last context */ 208 return E_FAIL; 209 210 ITfThreadMgrEventSink_OnPopContext(This->ThreadMgrSink,This->contextStack[0]); 211 Context_Uninitialize(This->contextStack[0]); 212 ITfContext_Release(This->contextStack[0]); 213 This->contextStack[0] = This->contextStack[1]; 214 This->contextStack[1] = NULL; 215 216 if (This->contextStack[0] == NULL) 217 ITfThreadMgrEventSink_OnUninitDocumentMgr(This->ThreadMgrSink, iface); 218 219 return S_OK; 220 } 221 222 static HRESULT WINAPI DocumentMgr_GetTop(ITfDocumentMgr *iface, ITfContext **ppic) 223 { 224 DocumentMgr *This = impl_from_ITfDocumentMgr(iface); 225 TRACE("(%p)\n",This); 226 if (!ppic) 227 return E_INVALIDARG; 228 229 if (This->contextStack[0]) 230 ITfContext_AddRef(This->contextStack[0]); 231 232 *ppic = This->contextStack[0]; 233 234 return S_OK; 235 } 236 237 static HRESULT WINAPI DocumentMgr_GetBase(ITfDocumentMgr *iface, ITfContext **ppic) 238 { 239 DocumentMgr *This = impl_from_ITfDocumentMgr(iface); 240 ITfContext *tgt; 241 242 TRACE("(%p)\n",This); 243 if (!ppic) 244 return E_INVALIDARG; 245 246 if (This->contextStack[1]) 247 tgt = This->contextStack[1]; 248 else 249 tgt = This->contextStack[0]; 250 251 if (tgt) 252 ITfContext_AddRef(tgt); 253 254 *ppic = tgt; 255 256 return S_OK; 257 } 258 259 static HRESULT WINAPI DocumentMgr_EnumContexts(ITfDocumentMgr *iface, IEnumTfContexts **ppEnum) 260 { 261 DocumentMgr *This = impl_from_ITfDocumentMgr(iface); 262 TRACE("(%p) %p\n",This,ppEnum); 263 return EnumTfContext_Constructor(This, ppEnum); 264 } 265 266 static const ITfDocumentMgrVtbl DocumentMgrVtbl = 267 { 268 DocumentMgr_QueryInterface, 269 DocumentMgr_AddRef, 270 DocumentMgr_Release, 271 DocumentMgr_CreateContext, 272 DocumentMgr_Push, 273 DocumentMgr_Pop, 274 DocumentMgr_GetTop, 275 DocumentMgr_GetBase, 276 DocumentMgr_EnumContexts 277 }; 278 279 static HRESULT WINAPI DocumentMgrSource_QueryInterface(ITfSource *iface, REFIID iid, LPVOID *ppvOut) 280 { 281 DocumentMgr *This = impl_from_ITfSource(iface); 282 return ITfDocumentMgr_QueryInterface(&This->ITfDocumentMgr_iface, iid, ppvOut); 283 } 284 285 static ULONG WINAPI DocumentMgrSource_AddRef(ITfSource *iface) 286 { 287 DocumentMgr *This = impl_from_ITfSource(iface); 288 return ITfDocumentMgr_AddRef(&This->ITfDocumentMgr_iface); 289 } 290 291 static ULONG WINAPI DocumentMgrSource_Release(ITfSource *iface) 292 { 293 DocumentMgr *This = impl_from_ITfSource(iface); 294 return ITfDocumentMgr_Release(&This->ITfDocumentMgr_iface); 295 } 296 297 /***************************************************** 298 * ITfSource functions 299 *****************************************************/ 300 static HRESULT WINAPI DocumentMgrSource_AdviseSink(ITfSource *iface, 301 REFIID riid, IUnknown *punk, DWORD *pdwCookie) 302 { 303 DocumentMgr *This = impl_from_ITfSource(iface); 304 305 TRACE("(%p) %s %p %p\n", This, debugstr_guid(riid), punk, pdwCookie); 306 307 if (!riid || !punk || !pdwCookie) 308 return E_INVALIDARG; 309 310 if (IsEqualIID(riid, &IID_ITfTransitoryExtensionSink)) 311 { 312 WARN("semi-stub for ITfTransitoryExtensionSink: callback won't be used.\n"); 313 return advise_sink(&This->TransitoryExtensionSink, &IID_ITfTransitoryExtensionSink, 314 COOKIE_MAGIC_DMSINK, punk, pdwCookie); 315 } 316 317 FIXME("(%p) Unhandled Sink: %s\n",This,debugstr_guid(riid)); 318 return E_NOTIMPL; 319 } 320 321 static HRESULT WINAPI DocumentMgrSource_UnadviseSink(ITfSource *iface, DWORD pdwCookie) 322 { 323 DocumentMgr *This = impl_from_ITfSource(iface); 324 325 TRACE("(%p) %x\n",This,pdwCookie); 326 327 if (get_Cookie_magic(pdwCookie)!=COOKIE_MAGIC_DMSINK) 328 return E_INVALIDARG; 329 330 return unadvise_sink(pdwCookie); 331 } 332 333 static const ITfSourceVtbl DocumentMgrSourceVtbl = 334 { 335 DocumentMgrSource_QueryInterface, 336 DocumentMgrSource_AddRef, 337 DocumentMgrSource_Release, 338 DocumentMgrSource_AdviseSink, 339 DocumentMgrSource_UnadviseSink, 340 }; 341 342 HRESULT DocumentMgr_Constructor(ITfThreadMgrEventSink *ThreadMgrSink, ITfDocumentMgr **ppOut) 343 { 344 DocumentMgr *This; 345 346 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DocumentMgr)); 347 if (This == NULL) 348 return E_OUTOFMEMORY; 349 350 This->ITfDocumentMgr_iface.lpVtbl = &DocumentMgrVtbl; 351 This->ITfSource_iface.lpVtbl = &DocumentMgrSourceVtbl; 352 This->refCount = 1; 353 This->ThreadMgrSink = ThreadMgrSink; 354 list_init(&This->TransitoryExtensionSink); 355 356 CompartmentMgr_Constructor((IUnknown*)&This->ITfDocumentMgr_iface, &IID_IUnknown, (IUnknown**)&This->CompartmentMgr); 357 358 *ppOut = &This->ITfDocumentMgr_iface; 359 TRACE("returning %p\n", *ppOut); 360 return S_OK; 361 } 362 363 /************************************************** 364 * IEnumTfContexts implementation 365 **************************************************/ 366 static void EnumTfContext_Destructor(EnumTfContext *This) 367 { 368 TRACE("destroying %p\n", This); 369 HeapFree(GetProcessHeap(),0,This); 370 } 371 372 static HRESULT WINAPI EnumTfContext_QueryInterface(IEnumTfContexts *iface, REFIID iid, LPVOID *ppvOut) 373 { 374 EnumTfContext *This = impl_from_IEnumTfContexts(iface); 375 *ppvOut = NULL; 376 377 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IEnumTfContexts)) 378 { 379 *ppvOut = &This->IEnumTfContexts_iface; 380 } 381 382 if (*ppvOut) 383 { 384 IEnumTfContexts_AddRef(iface); 385 return S_OK; 386 } 387 388 WARN("unsupported interface: %s\n", debugstr_guid(iid)); 389 return E_NOINTERFACE; 390 } 391 392 static ULONG WINAPI EnumTfContext_AddRef(IEnumTfContexts *iface) 393 { 394 EnumTfContext *This = impl_from_IEnumTfContexts(iface); 395 return InterlockedIncrement(&This->refCount); 396 } 397 398 static ULONG WINAPI EnumTfContext_Release(IEnumTfContexts *iface) 399 { 400 EnumTfContext *This = impl_from_IEnumTfContexts(iface); 401 ULONG ret; 402 403 ret = InterlockedDecrement(&This->refCount); 404 if (ret == 0) 405 EnumTfContext_Destructor(This); 406 return ret; 407 } 408 409 static HRESULT WINAPI EnumTfContext_Next(IEnumTfContexts *iface, 410 ULONG ulCount, ITfContext **rgContext, ULONG *pcFetched) 411 { 412 EnumTfContext *This = impl_from_IEnumTfContexts(iface); 413 ULONG fetched = 0; 414 415 TRACE("(%p)\n",This); 416 417 if (rgContext == NULL) return E_POINTER; 418 419 while (fetched < ulCount) 420 { 421 if (This->index > 1) 422 break; 423 424 if (!This->docmgr->contextStack[This->index]) 425 break; 426 427 *rgContext = This->docmgr->contextStack[This->index]; 428 ITfContext_AddRef(*rgContext); 429 430 ++This->index; 431 ++fetched; 432 ++rgContext; 433 } 434 435 if (pcFetched) *pcFetched = fetched; 436 return fetched == ulCount ? S_OK : S_FALSE; 437 } 438 439 static HRESULT WINAPI EnumTfContext_Skip( IEnumTfContexts* iface, ULONG celt) 440 { 441 EnumTfContext *This = impl_from_IEnumTfContexts(iface); 442 TRACE("(%p)\n",This); 443 This->index += celt; 444 return S_OK; 445 } 446 447 static HRESULT WINAPI EnumTfContext_Reset( IEnumTfContexts* iface) 448 { 449 EnumTfContext *This = impl_from_IEnumTfContexts(iface); 450 TRACE("(%p)\n",This); 451 This->index = 0; 452 return S_OK; 453 } 454 455 static HRESULT WINAPI EnumTfContext_Clone( IEnumTfContexts *iface, 456 IEnumTfContexts **ppenum) 457 { 458 EnumTfContext *This = impl_from_IEnumTfContexts(iface); 459 HRESULT res; 460 461 TRACE("(%p)\n",This); 462 463 if (ppenum == NULL) return E_POINTER; 464 465 res = EnumTfContext_Constructor(This->docmgr, ppenum); 466 if (SUCCEEDED(res)) 467 { 468 EnumTfContext *new_This = impl_from_IEnumTfContexts(*ppenum); 469 new_This->index = This->index; 470 } 471 return res; 472 } 473 474 static const IEnumTfContextsVtbl IEnumTfContexts_Vtbl ={ 475 EnumTfContext_QueryInterface, 476 EnumTfContext_AddRef, 477 EnumTfContext_Release, 478 479 EnumTfContext_Clone, 480 EnumTfContext_Next, 481 EnumTfContext_Reset, 482 EnumTfContext_Skip 483 }; 484 485 static HRESULT EnumTfContext_Constructor(DocumentMgr *mgr, IEnumTfContexts **ppOut) 486 { 487 EnumTfContext *This; 488 489 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(EnumTfContext)); 490 if (This == NULL) 491 return E_OUTOFMEMORY; 492 493 This->IEnumTfContexts_iface.lpVtbl = &IEnumTfContexts_Vtbl; 494 This->refCount = 1; 495 This->docmgr = mgr; 496 497 *ppOut = &This->IEnumTfContexts_iface; 498 TRACE("returning %p\n", *ppOut); 499 return S_OK; 500 } 501