1 /* 2 * ITfCompartmentMgr 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 <stdarg.h> 22 23 #define COBJMACROS 24 25 #include "wine/debug.h" 26 #include "windef.h" 27 #include "winbase.h" 28 #include "winreg.h" 29 #include "winuser.h" 30 #include "shlwapi.h" 31 #include "winerror.h" 32 #include "objbase.h" 33 #include "oleauto.h" 34 #include "olectl.h" 35 36 #include "msctf.h" 37 #include "msctf_internal.h" 38 39 WINE_DEFAULT_DEBUG_CHANNEL(msctf); 40 41 typedef struct tagCompartmentValue { 42 struct list entry; 43 GUID guid; 44 TfClientId owner; 45 ITfCompartment *compartment; 46 } CompartmentValue; 47 48 typedef struct tagCompartmentMgr { 49 ITfCompartmentMgr ITfCompartmentMgr_iface; 50 LONG refCount; 51 52 IUnknown *pUnkOuter; 53 54 struct list values; 55 } CompartmentMgr; 56 57 typedef struct tagCompartmentEnumGuid { 58 IEnumGUID IEnumGUID_iface; 59 LONG refCount; 60 61 struct list *values; 62 struct list *cursor; 63 } CompartmentEnumGuid; 64 65 typedef struct tagCompartment { 66 ITfCompartment ITfCompartment_iface; 67 ITfSource ITfSource_iface; 68 LONG refCount; 69 70 /* Only VT_I4, VT_UNKNOWN and VT_BSTR data types are allowed */ 71 VARIANT variant; 72 CompartmentValue *valueData; 73 struct list CompartmentEventSink; 74 } Compartment; 75 76 static HRESULT CompartmentEnumGuid_Constructor(struct list* values, IEnumGUID **ppOut); 77 static HRESULT Compartment_Constructor(CompartmentValue *value, ITfCompartment **ppOut); 78 79 static inline CompartmentMgr *impl_from_ITfCompartmentMgr(ITfCompartmentMgr *iface) 80 { 81 return CONTAINING_RECORD(iface, CompartmentMgr, ITfCompartmentMgr_iface); 82 } 83 84 static inline Compartment *impl_from_ITfCompartment(ITfCompartment *iface) 85 { 86 return CONTAINING_RECORD(iface, Compartment, ITfCompartment_iface); 87 } 88 89 static inline Compartment *impl_from_ITfSource(ITfSource *iface) 90 { 91 return CONTAINING_RECORD(iface, Compartment, ITfSource_iface); 92 } 93 94 static inline CompartmentEnumGuid *impl_from_IEnumGUID(IEnumGUID *iface) 95 { 96 return CONTAINING_RECORD(iface, CompartmentEnumGuid, IEnumGUID_iface); 97 } 98 99 HRESULT CompartmentMgr_Destructor(ITfCompartmentMgr *iface) 100 { 101 CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface); 102 struct list *cursor, *cursor2; 103 104 LIST_FOR_EACH_SAFE(cursor, cursor2, &This->values) 105 { 106 CompartmentValue* value = LIST_ENTRY(cursor,CompartmentValue,entry); 107 list_remove(cursor); 108 ITfCompartment_Release(value->compartment); 109 HeapFree(GetProcessHeap(),0,value); 110 } 111 112 HeapFree(GetProcessHeap(),0,This); 113 return S_OK; 114 } 115 116 /***************************************************** 117 * ITfCompartmentMgr functions 118 *****************************************************/ 119 static HRESULT WINAPI CompartmentMgr_QueryInterface(ITfCompartmentMgr *iface, REFIID iid, LPVOID *ppvOut) 120 { 121 CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface); 122 if (This->pUnkOuter) 123 return IUnknown_QueryInterface(This->pUnkOuter, iid, ppvOut); 124 else 125 { 126 *ppvOut = NULL; 127 128 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfCompartmentMgr)) 129 { 130 *ppvOut = &This->ITfCompartmentMgr_iface; 131 } 132 133 if (*ppvOut) 134 { 135 ITfCompartmentMgr_AddRef(iface); 136 return S_OK; 137 } 138 139 WARN("unsupported interface: %s\n", debugstr_guid(iid)); 140 return E_NOINTERFACE; 141 } 142 } 143 144 static ULONG WINAPI CompartmentMgr_AddRef(ITfCompartmentMgr *iface) 145 { 146 CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface); 147 if (This->pUnkOuter) 148 return IUnknown_AddRef(This->pUnkOuter); 149 else 150 return InterlockedIncrement(&This->refCount); 151 } 152 153 static ULONG WINAPI CompartmentMgr_Release(ITfCompartmentMgr *iface) 154 { 155 CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface); 156 if (This->pUnkOuter) 157 return IUnknown_Release(This->pUnkOuter); 158 else 159 { 160 ULONG ret; 161 162 ret = InterlockedDecrement(&This->refCount); 163 if (ret == 0) 164 CompartmentMgr_Destructor(iface); 165 return ret; 166 } 167 } 168 169 static HRESULT WINAPI CompartmentMgr_GetCompartment(ITfCompartmentMgr *iface, 170 REFGUID rguid, ITfCompartment **ppcomp) 171 { 172 CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface); 173 CompartmentValue* value; 174 struct list *cursor; 175 HRESULT hr; 176 177 TRACE("(%p) %s %p\n",This,debugstr_guid(rguid),ppcomp); 178 179 LIST_FOR_EACH(cursor, &This->values) 180 { 181 value = LIST_ENTRY(cursor,CompartmentValue,entry); 182 if (IsEqualGUID(rguid,&value->guid)) 183 { 184 ITfCompartment_AddRef(value->compartment); 185 *ppcomp = value->compartment; 186 return S_OK; 187 } 188 } 189 190 value = HeapAlloc(GetProcessHeap(),0,sizeof(CompartmentValue)); 191 value->guid = *rguid; 192 value->owner = 0; 193 hr = Compartment_Constructor(value,&value->compartment); 194 if (SUCCEEDED(hr)) 195 { 196 list_add_head(&This->values,&value->entry); 197 ITfCompartment_AddRef(value->compartment); 198 *ppcomp = value->compartment; 199 } 200 else 201 { 202 HeapFree(GetProcessHeap(),0,value); 203 *ppcomp = NULL; 204 } 205 return hr; 206 } 207 208 static HRESULT WINAPI CompartmentMgr_ClearCompartment(ITfCompartmentMgr *iface, 209 TfClientId tid, REFGUID rguid) 210 { 211 CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface); 212 struct list *cursor; 213 214 TRACE("(%p) %i %s\n",This,tid,debugstr_guid(rguid)); 215 216 LIST_FOR_EACH(cursor, &This->values) 217 { 218 CompartmentValue* value = LIST_ENTRY(cursor,CompartmentValue,entry); 219 if (IsEqualGUID(rguid,&value->guid)) 220 { 221 if (value->owner && tid != value->owner) 222 return E_UNEXPECTED; 223 list_remove(cursor); 224 ITfCompartment_Release(value->compartment); 225 HeapFree(GetProcessHeap(),0,value); 226 return S_OK; 227 } 228 } 229 230 return CONNECT_E_NOCONNECTION; 231 } 232 233 static HRESULT WINAPI CompartmentMgr_EnumCompartments(ITfCompartmentMgr *iface, 234 IEnumGUID **ppEnum) 235 { 236 CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface); 237 238 TRACE("(%p) %p\n",This,ppEnum); 239 if (!ppEnum) 240 return E_INVALIDARG; 241 return CompartmentEnumGuid_Constructor(&This->values, ppEnum); 242 } 243 244 static const ITfCompartmentMgrVtbl CompartmentMgrVtbl = 245 { 246 CompartmentMgr_QueryInterface, 247 CompartmentMgr_AddRef, 248 CompartmentMgr_Release, 249 CompartmentMgr_GetCompartment, 250 CompartmentMgr_ClearCompartment, 251 CompartmentMgr_EnumCompartments 252 }; 253 254 HRESULT CompartmentMgr_Constructor(IUnknown *pUnkOuter, REFIID riid, IUnknown **ppOut) 255 { 256 CompartmentMgr *This; 257 258 if (!ppOut) 259 return E_POINTER; 260 261 if (pUnkOuter && !IsEqualIID (riid, &IID_IUnknown)) 262 return CLASS_E_NOAGGREGATION; 263 264 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CompartmentMgr)); 265 if (This == NULL) 266 return E_OUTOFMEMORY; 267 268 This->ITfCompartmentMgr_iface.lpVtbl = &CompartmentMgrVtbl; 269 This->pUnkOuter = pUnkOuter; 270 list_init(&This->values); 271 272 if (pUnkOuter) 273 { 274 *ppOut = (IUnknown*)&This->ITfCompartmentMgr_iface; 275 TRACE("returning %p\n", *ppOut); 276 return S_OK; 277 } 278 else 279 { 280 HRESULT hr; 281 hr = ITfCompartmentMgr_QueryInterface(&This->ITfCompartmentMgr_iface, riid, (void**)ppOut); 282 if (FAILED(hr)) 283 HeapFree(GetProcessHeap(),0,This); 284 return hr; 285 } 286 } 287 288 /************************************************** 289 * IEnumGUID implementation for ITfCompartmentMgr::EnumCompartments 290 **************************************************/ 291 static void CompartmentEnumGuid_Destructor(CompartmentEnumGuid *This) 292 { 293 TRACE("destroying %p\n", This); 294 HeapFree(GetProcessHeap(),0,This); 295 } 296 297 static HRESULT WINAPI CompartmentEnumGuid_QueryInterface(IEnumGUID *iface, REFIID iid, LPVOID *ppvOut) 298 { 299 CompartmentEnumGuid *This = impl_from_IEnumGUID(iface); 300 *ppvOut = NULL; 301 302 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IEnumGUID)) 303 { 304 *ppvOut = &This->IEnumGUID_iface; 305 } 306 307 if (*ppvOut) 308 { 309 IEnumGUID_AddRef(iface); 310 return S_OK; 311 } 312 313 WARN("unsupported interface: %s\n", debugstr_guid(iid)); 314 return E_NOINTERFACE; 315 } 316 317 static ULONG WINAPI CompartmentEnumGuid_AddRef(IEnumGUID *iface) 318 { 319 CompartmentEnumGuid *This = impl_from_IEnumGUID(iface); 320 return InterlockedIncrement(&This->refCount); 321 } 322 323 static ULONG WINAPI CompartmentEnumGuid_Release(IEnumGUID *iface) 324 { 325 CompartmentEnumGuid *This = impl_from_IEnumGUID(iface); 326 ULONG ret; 327 328 ret = InterlockedDecrement(&This->refCount); 329 if (ret == 0) 330 CompartmentEnumGuid_Destructor(This); 331 return ret; 332 } 333 334 /***************************************************** 335 * IEnumGuid functions 336 *****************************************************/ 337 static HRESULT WINAPI CompartmentEnumGuid_Next(IEnumGUID *iface, 338 ULONG celt, GUID *rgelt, ULONG *pceltFetched) 339 { 340 CompartmentEnumGuid *This = impl_from_IEnumGUID(iface); 341 ULONG fetched = 0; 342 343 TRACE("(%p)\n",This); 344 345 if (rgelt == NULL) return E_POINTER; 346 347 while (fetched < celt && This->cursor) 348 { 349 CompartmentValue* value = LIST_ENTRY(This->cursor,CompartmentValue,entry); 350 if (!value) 351 break; 352 353 This->cursor = list_next(This->values,This->cursor); 354 *rgelt = value->guid; 355 356 ++fetched; 357 ++rgelt; 358 } 359 360 if (pceltFetched) *pceltFetched = fetched; 361 return fetched == celt ? S_OK : S_FALSE; 362 } 363 364 static HRESULT WINAPI CompartmentEnumGuid_Skip(IEnumGUID *iface, ULONG celt) 365 { 366 CompartmentEnumGuid *This = impl_from_IEnumGUID(iface); 367 TRACE("(%p)\n",This); 368 369 This->cursor = list_next(This->values,This->cursor); 370 return S_OK; 371 } 372 373 static HRESULT WINAPI CompartmentEnumGuid_Reset(IEnumGUID *iface) 374 { 375 CompartmentEnumGuid *This = impl_from_IEnumGUID(iface); 376 TRACE("(%p)\n",This); 377 This->cursor = list_head(This->values); 378 return S_OK; 379 } 380 381 static HRESULT WINAPI CompartmentEnumGuid_Clone(IEnumGUID *iface, 382 IEnumGUID **ppenum) 383 { 384 CompartmentEnumGuid *This = impl_from_IEnumGUID(iface); 385 HRESULT res; 386 387 TRACE("(%p)\n",This); 388 389 if (ppenum == NULL) return E_POINTER; 390 391 res = CompartmentEnumGuid_Constructor(This->values, ppenum); 392 if (SUCCEEDED(res)) 393 { 394 CompartmentEnumGuid *new_This = impl_from_IEnumGUID(*ppenum); 395 new_This->cursor = This->cursor; 396 } 397 return res; 398 } 399 400 static const IEnumGUIDVtbl EnumGUIDVtbl = 401 { 402 CompartmentEnumGuid_QueryInterface, 403 CompartmentEnumGuid_AddRef, 404 CompartmentEnumGuid_Release, 405 CompartmentEnumGuid_Next, 406 CompartmentEnumGuid_Skip, 407 CompartmentEnumGuid_Reset, 408 CompartmentEnumGuid_Clone 409 }; 410 411 static HRESULT CompartmentEnumGuid_Constructor(struct list *values, IEnumGUID **ppOut) 412 { 413 CompartmentEnumGuid *This; 414 415 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CompartmentEnumGuid)); 416 if (This == NULL) 417 return E_OUTOFMEMORY; 418 419 This->IEnumGUID_iface.lpVtbl= &EnumGUIDVtbl; 420 This->refCount = 1; 421 422 This->values = values; 423 This->cursor = list_head(values); 424 425 *ppOut = &This->IEnumGUID_iface; 426 TRACE("returning %p\n", *ppOut); 427 return S_OK; 428 } 429 430 /************************************************** 431 * ITfCompartment 432 **************************************************/ 433 static void Compartment_Destructor(Compartment *This) 434 { 435 TRACE("destroying %p\n", This); 436 VariantClear(&This->variant); 437 free_sinks(&This->CompartmentEventSink); 438 HeapFree(GetProcessHeap(),0,This); 439 } 440 441 static HRESULT WINAPI Compartment_QueryInterface(ITfCompartment *iface, REFIID iid, LPVOID *ppvOut) 442 { 443 Compartment *This = impl_from_ITfCompartment(iface); 444 445 *ppvOut = NULL; 446 447 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfCompartment)) 448 { 449 *ppvOut = &This->ITfCompartment_iface; 450 } 451 else if (IsEqualIID(iid, &IID_ITfSource)) 452 { 453 *ppvOut = &This->ITfSource_iface; 454 } 455 456 if (*ppvOut) 457 { 458 ITfCompartment_AddRef(iface); 459 return S_OK; 460 } 461 462 WARN("unsupported interface: %s\n", debugstr_guid(iid)); 463 return E_NOINTERFACE; 464 } 465 466 static ULONG WINAPI Compartment_AddRef(ITfCompartment *iface) 467 { 468 Compartment *This = impl_from_ITfCompartment(iface); 469 return InterlockedIncrement(&This->refCount); 470 } 471 472 static ULONG WINAPI Compartment_Release(ITfCompartment *iface) 473 { 474 Compartment *This = impl_from_ITfCompartment(iface); 475 ULONG ret; 476 477 ret = InterlockedDecrement(&This->refCount); 478 if (ret == 0) 479 Compartment_Destructor(This); 480 return ret; 481 } 482 483 static HRESULT WINAPI Compartment_SetValue(ITfCompartment *iface, 484 TfClientId tid, const VARIANT *pvarValue) 485 { 486 Compartment *This = impl_from_ITfCompartment(iface); 487 ITfCompartmentEventSink *sink; 488 struct list *cursor; 489 490 TRACE("(%p) %i %p\n",This,tid,pvarValue); 491 492 if (!pvarValue) 493 return E_INVALIDARG; 494 495 if (!(V_VT(pvarValue) == VT_BSTR || V_VT(pvarValue) == VT_I4 || 496 V_VT(pvarValue) == VT_UNKNOWN)) 497 return E_INVALIDARG; 498 499 if (!This->valueData->owner) 500 This->valueData->owner = tid; 501 502 VariantClear(&This->variant); 503 504 /* Shallow copy of value and type */ 505 This->variant = *pvarValue; 506 507 if (V_VT(pvarValue) == VT_BSTR) 508 V_BSTR(&This->variant) = SysAllocStringByteLen((char*)V_BSTR(pvarValue), 509 SysStringByteLen(V_BSTR(pvarValue))); 510 else if (V_VT(pvarValue) == VT_UNKNOWN) 511 IUnknown_AddRef(V_UNKNOWN(&This->variant)); 512 513 SINK_FOR_EACH(cursor, &This->CompartmentEventSink, ITfCompartmentEventSink, sink) 514 { 515 ITfCompartmentEventSink_OnChange(sink, &This->valueData->guid); 516 } 517 518 return S_OK; 519 } 520 521 static HRESULT WINAPI Compartment_GetValue(ITfCompartment *iface, 522 VARIANT *pvarValue) 523 { 524 Compartment *This = impl_from_ITfCompartment(iface); 525 TRACE("(%p) %p\n",This, pvarValue); 526 527 if (!pvarValue) 528 return E_INVALIDARG; 529 530 VariantInit(pvarValue); 531 if (V_VT(&This->variant) == VT_EMPTY) return S_FALSE; 532 return VariantCopy(pvarValue,&This->variant); 533 } 534 535 static const ITfCompartmentVtbl CompartmentVtbl = 536 { 537 Compartment_QueryInterface, 538 Compartment_AddRef, 539 Compartment_Release, 540 Compartment_SetValue, 541 Compartment_GetValue 542 }; 543 544 /***************************************************** 545 * ITfSource functions 546 *****************************************************/ 547 548 static HRESULT WINAPI CompartmentSource_QueryInterface(ITfSource *iface, REFIID iid, LPVOID *ppvOut) 549 { 550 Compartment *This = impl_from_ITfSource(iface); 551 return ITfCompartment_QueryInterface(&This->ITfCompartment_iface, iid, ppvOut); 552 } 553 554 static ULONG WINAPI CompartmentSource_AddRef(ITfSource *iface) 555 { 556 Compartment *This = impl_from_ITfSource(iface); 557 return ITfCompartment_AddRef(&This->ITfCompartment_iface); 558 } 559 560 static ULONG WINAPI CompartmentSource_Release(ITfSource *iface) 561 { 562 Compartment *This = impl_from_ITfSource(iface); 563 return ITfCompartment_Release(&This->ITfCompartment_iface); 564 } 565 566 static HRESULT WINAPI CompartmentSource_AdviseSink(ITfSource *iface, 567 REFIID riid, IUnknown *punk, DWORD *pdwCookie) 568 { 569 Compartment *This = impl_from_ITfSource(iface); 570 571 TRACE("(%p) %s %p %p\n",This,debugstr_guid(riid),punk,pdwCookie); 572 573 if (!riid || !punk || !pdwCookie) 574 return E_INVALIDARG; 575 576 if (IsEqualIID(riid, &IID_ITfCompartmentEventSink)) 577 return advise_sink(&This->CompartmentEventSink, &IID_ITfCompartmentEventSink, 578 COOKIE_MAGIC_COMPARTMENTSINK, punk, pdwCookie); 579 580 FIXME("(%p) Unhandled Sink: %s\n",This,debugstr_guid(riid)); 581 return E_NOTIMPL; 582 } 583 584 static HRESULT WINAPI CompartmentSource_UnadviseSink(ITfSource *iface, DWORD pdwCookie) 585 { 586 Compartment *This = impl_from_ITfSource(iface); 587 588 TRACE("(%p) %x\n",This,pdwCookie); 589 590 if (get_Cookie_magic(pdwCookie)!=COOKIE_MAGIC_COMPARTMENTSINK) 591 return E_INVALIDARG; 592 593 return unadvise_sink(pdwCookie); 594 } 595 596 static const ITfSourceVtbl CompartmentSourceVtbl = 597 { 598 CompartmentSource_QueryInterface, 599 CompartmentSource_AddRef, 600 CompartmentSource_Release, 601 CompartmentSource_AdviseSink, 602 CompartmentSource_UnadviseSink, 603 }; 604 605 static HRESULT Compartment_Constructor(CompartmentValue *valueData, ITfCompartment **ppOut) 606 { 607 Compartment *This; 608 609 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(Compartment)); 610 if (This == NULL) 611 return E_OUTOFMEMORY; 612 613 This->ITfCompartment_iface.lpVtbl= &CompartmentVtbl; 614 This->ITfSource_iface.lpVtbl = &CompartmentSourceVtbl; 615 This->refCount = 1; 616 617 This->valueData = valueData; 618 VariantInit(&This->variant); 619 620 list_init(&This->CompartmentEventSink); 621 622 *ppOut = &This->ITfCompartment_iface; 623 TRACE("returning %p\n", *ppOut); 624 return S_OK; 625 } 626