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