compartmentmgr.c 18.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
/*
 *  ITfCompartmentMgr implementation
 *
 *  Copyright 2009 Aric Stewart, CodeWeavers
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include "config.h"

#include <stdarg.h>

#define COBJMACROS

#include "wine/debug.h"
#include "windef.h"
#include "winbase.h"
#include "winreg.h"
#include "winuser.h"
#include "shlwapi.h"
#include "winerror.h"
#include "objbase.h"
#include "oleauto.h"
36
#include "olectl.h"
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53

#include "wine/unicode.h"
#include "wine/list.h"

#include "msctf.h"
#include "msctf_internal.h"

WINE_DEFAULT_DEBUG_CHANNEL(msctf);

typedef struct tagCompartmentValue {
    struct list entry;
    GUID guid;
    TfClientId owner;
    ITfCompartment *compartment;
} CompartmentValue;

typedef struct tagCompartmentMgr {
54
    ITfCompartmentMgr ITfCompartmentMgr_iface;
55 56 57 58 59 60 61
    LONG refCount;

    IUnknown *pUnkOuter;

    struct list values;
} CompartmentMgr;

62
typedef struct tagCompartmentEnumGuid {
63
    IEnumGUID IEnumGUID_iface;
64 65 66 67 68 69
    LONG refCount;

    struct list *values;
    struct list *cursor;
} CompartmentEnumGuid;

70 71 72 73 74

typedef struct tagCompartmentSink {
    struct list         entry;
    union {
        IUnknown            *pIUnknown;
75
        ITfCompartmentEventSink *pITfCompartmentEventSink;
76 77 78
    } interfaces;
} CompartmentSink;

79
typedef struct tagCompartment {
80 81
    ITfCompartment ITfCompartment_iface;
    ITfSource ITfSource_iface;
82 83 84 85 86
    LONG refCount;

    /* Only VT_I4, VT_UNKNOWN and VT_BSTR data types are allowed */
    VARIANT variant;
    CompartmentValue *valueData;
87
    struct list CompartmentEventSink;
88 89
} Compartment;

90
static HRESULT CompartmentEnumGuid_Constructor(struct list* values, IEnumGUID **ppOut);
91
static HRESULT Compartment_Constructor(CompartmentValue *value, ITfCompartment **ppOut);
92

93
static inline CompartmentMgr *impl_from_ITfCompartmentMgr(ITfCompartmentMgr *iface)
94
{
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
    return CONTAINING_RECORD(iface, CompartmentMgr, ITfCompartmentMgr_iface);
}

static inline Compartment *impl_from_ITfCompartment(ITfCompartment *iface)
{
    return CONTAINING_RECORD(iface, Compartment, ITfCompartment_iface);
}

static inline Compartment *impl_from_ITfSource(ITfSource *iface)
{
    return CONTAINING_RECORD(iface, Compartment, ITfSource_iface);
}

static inline CompartmentEnumGuid *impl_from_IEnumGUID(IEnumGUID *iface)
{
    return CONTAINING_RECORD(iface, CompartmentEnumGuid, IEnumGUID_iface);
111 112
}

113 114
HRESULT CompartmentMgr_Destructor(ITfCompartmentMgr *iface)
{
115
    CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface);
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
    struct list *cursor, *cursor2;

    LIST_FOR_EACH_SAFE(cursor, cursor2, &This->values)
    {
        CompartmentValue* value = LIST_ENTRY(cursor,CompartmentValue,entry);
        list_remove(cursor);
        ITfCompartment_Release(value->compartment);
        HeapFree(GetProcessHeap(),0,value);
    }

    HeapFree(GetProcessHeap(),0,This);
    return S_OK;
}

/*****************************************************
 * ITfCompartmentMgr functions
 *****************************************************/
static HRESULT WINAPI CompartmentMgr_QueryInterface(ITfCompartmentMgr *iface, REFIID iid, LPVOID *ppvOut)
{
135
    CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface);
136
    if (This->pUnkOuter)
137
        return IUnknown_QueryInterface(This->pUnkOuter, iid, ppvOut);
138 139 140 141 142 143
    else
    {
        *ppvOut = NULL;

        if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfCompartmentMgr))
        {
144
            *ppvOut = &This->ITfCompartmentMgr_iface;
145 146 147 148
        }

        if (*ppvOut)
        {
149
            ITfCompartmentMgr_AddRef(iface);
150 151 152 153 154 155 156 157 158 159
            return S_OK;
        }

        WARN("unsupported interface: %s\n", debugstr_guid(iid));
        return E_NOINTERFACE;
    }
}

static ULONG WINAPI CompartmentMgr_AddRef(ITfCompartmentMgr *iface)
{
160
    CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface);
161 162 163 164 165 166 167 168
    if (This->pUnkOuter)
        return IUnknown_AddRef(This->pUnkOuter);
    else
        return InterlockedIncrement(&This->refCount);
}

static ULONG WINAPI CompartmentMgr_Release(ITfCompartmentMgr *iface)
{
169
    CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface);
170 171 172 173 174 175 176 177 178 179 180 181 182
    if (This->pUnkOuter)
        return IUnknown_Release(This->pUnkOuter);
    else
    {
        ULONG ret;

        ret = InterlockedDecrement(&This->refCount);
        if (ret == 0)
            CompartmentMgr_Destructor(iface);
        return ret;
    }
}

183
static HRESULT WINAPI CompartmentMgr_GetCompartment(ITfCompartmentMgr *iface,
184 185
        REFGUID rguid, ITfCompartment **ppcomp)
{
186
    CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface);
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
    CompartmentValue* value;
    struct list *cursor;
    HRESULT hr;

    TRACE("(%p) %s  %p\n",This,debugstr_guid(rguid),ppcomp);

    LIST_FOR_EACH(cursor, &This->values)
    {
        value = LIST_ENTRY(cursor,CompartmentValue,entry);
        if (IsEqualGUID(rguid,&value->guid))
        {
            ITfCompartment_AddRef(value->compartment);
            *ppcomp = value->compartment;
            return S_OK;
        }
    }

    value = HeapAlloc(GetProcessHeap(),0,sizeof(CompartmentValue));
    value->guid = *rguid;
    value->owner = 0;
    hr = Compartment_Constructor(value,&value->compartment);
    if (SUCCEEDED(hr))
    {
        list_add_head(&This->values,&value->entry);
        ITfCompartment_AddRef(value->compartment);
        *ppcomp = value->compartment;
    }
    else
    {
        HeapFree(GetProcessHeap(),0,value);
        *ppcomp = NULL;
    }
    return hr;
220 221
}

222
static HRESULT WINAPI CompartmentMgr_ClearCompartment(ITfCompartmentMgr *iface,
223 224
    TfClientId tid, REFGUID rguid)
{
225
    CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface);
226
    struct list *cursor;
227

228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
    TRACE("(%p) %i %s\n",This,tid,debugstr_guid(rguid));

    LIST_FOR_EACH(cursor, &This->values)
    {
        CompartmentValue* value = LIST_ENTRY(cursor,CompartmentValue,entry);
        if (IsEqualGUID(rguid,&value->guid))
        {
            if (value->owner && tid != value->owner)
                return E_UNEXPECTED;
            list_remove(cursor);
            ITfCompartment_Release(value->compartment);
            HeapFree(GetProcessHeap(),0,value);
            return S_OK;
        }
    }

    return CONNECT_E_NOCONNECTION;
245 246
}

247
static HRESULT WINAPI CompartmentMgr_EnumCompartments(ITfCompartmentMgr *iface,
248 249
 IEnumGUID **ppEnum)
{
250 251
    CompartmentMgr *This = impl_from_ITfCompartmentMgr(iface);

252 253 254 255
    TRACE("(%p) %p\n",This,ppEnum);
    if (!ppEnum)
        return E_INVALIDARG;
    return CompartmentEnumGuid_Constructor(&This->values, ppEnum);
256 257
}

258
static const ITfCompartmentMgrVtbl CompartmentMgrVtbl =
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281
{
    CompartmentMgr_QueryInterface,
    CompartmentMgr_AddRef,
    CompartmentMgr_Release,
    CompartmentMgr_GetCompartment,
    CompartmentMgr_ClearCompartment,
    CompartmentMgr_EnumCompartments
};

HRESULT CompartmentMgr_Constructor(IUnknown *pUnkOuter, REFIID riid, IUnknown **ppOut)
{
    CompartmentMgr *This;

    if (!ppOut)
        return E_POINTER;

    if (pUnkOuter && !IsEqualIID (riid, &IID_IUnknown))
        return CLASS_E_NOAGGREGATION;

    This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CompartmentMgr));
    if (This == NULL)
        return E_OUTOFMEMORY;

282
    This->ITfCompartmentMgr_iface.lpVtbl = &CompartmentMgrVtbl;
283 284 285 286 287
    This->pUnkOuter = pUnkOuter;
    list_init(&This->values);

    if (pUnkOuter)
    {
288 289
        *ppOut = (IUnknown*)&This->ITfCompartmentMgr_iface;
        TRACE("returning %p\n", *ppOut);
290 291 292 293 294
        return S_OK;
    }
    else
    {
        HRESULT hr;
295
        hr = ITfCompartmentMgr_QueryInterface(&This->ITfCompartmentMgr_iface, riid, (void**)ppOut);
296 297 298 299 300
        if (FAILED(hr))
            HeapFree(GetProcessHeap(),0,This);
        return hr;
    }
}
301 302

/**************************************************
303
 * IEnumGUID implementation for ITfCompartmentMgr::EnumCompartments
304 305 306 307 308 309 310 311 312
 **************************************************/
static void CompartmentEnumGuid_Destructor(CompartmentEnumGuid *This)
{
    TRACE("destroying %p\n", This);
    HeapFree(GetProcessHeap(),0,This);
}

static HRESULT WINAPI CompartmentEnumGuid_QueryInterface(IEnumGUID *iface, REFIID iid, LPVOID *ppvOut)
{
313
    CompartmentEnumGuid *This = impl_from_IEnumGUID(iface);
314 315 316 317
    *ppvOut = NULL;

    if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IEnumGUID))
    {
318
        *ppvOut = &This->IEnumGUID_iface;
319 320 321 322
    }

    if (*ppvOut)
    {
323
        IEnumGUID_AddRef(iface);
324 325 326 327 328 329 330 331 332
        return S_OK;
    }

    WARN("unsupported interface: %s\n", debugstr_guid(iid));
    return E_NOINTERFACE;
}

static ULONG WINAPI CompartmentEnumGuid_AddRef(IEnumGUID *iface)
{
333
    CompartmentEnumGuid *This = impl_from_IEnumGUID(iface);
334 335 336 337 338
    return InterlockedIncrement(&This->refCount);
}

static ULONG WINAPI CompartmentEnumGuid_Release(IEnumGUID *iface)
{
339
    CompartmentEnumGuid *This = impl_from_IEnumGUID(iface);
340 341 342 343 344 345 346 347 348 349 350
    ULONG ret;

    ret = InterlockedDecrement(&This->refCount);
    if (ret == 0)
        CompartmentEnumGuid_Destructor(This);
    return ret;
}

/*****************************************************
 * IEnumGuid functions
 *****************************************************/
351
static HRESULT WINAPI CompartmentEnumGuid_Next(IEnumGUID *iface,
352 353
    ULONG celt, GUID *rgelt, ULONG *pceltFetched)
{
354
    CompartmentEnumGuid *This = impl_from_IEnumGUID(iface);
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
    ULONG fetched = 0;

    TRACE("(%p)\n",This);

    if (rgelt == NULL) return E_POINTER;

    while (fetched < celt && This->cursor)
    {
        CompartmentValue* value = LIST_ENTRY(This->cursor,CompartmentValue,entry);
        if (!value)
            break;

        This->cursor = list_next(This->values,This->cursor);
        *rgelt = value->guid;

        ++fetched;
        ++rgelt;
    }

    if (pceltFetched) *pceltFetched = fetched;
    return fetched == celt ? S_OK : S_FALSE;
}

378
static HRESULT WINAPI CompartmentEnumGuid_Skip(IEnumGUID *iface, ULONG celt)
379
{
380
    CompartmentEnumGuid *This = impl_from_IEnumGUID(iface);
381 382 383 384 385 386
    TRACE("(%p)\n",This);

    This->cursor = list_next(This->values,This->cursor);
    return S_OK;
}

387
static HRESULT WINAPI CompartmentEnumGuid_Reset(IEnumGUID *iface)
388
{
389
    CompartmentEnumGuid *This = impl_from_IEnumGUID(iface);
390 391 392 393 394
    TRACE("(%p)\n",This);
    This->cursor = list_head(This->values);
    return S_OK;
}

395
static HRESULT WINAPI CompartmentEnumGuid_Clone(IEnumGUID *iface,
396 397
    IEnumGUID **ppenum)
{
398
    CompartmentEnumGuid *This = impl_from_IEnumGUID(iface);
399 400 401 402 403 404 405 406 407
    HRESULT res;

    TRACE("(%p)\n",This);

    if (ppenum == NULL) return E_POINTER;

    res = CompartmentEnumGuid_Constructor(This->values, ppenum);
    if (SUCCEEDED(res))
    {
408
        CompartmentEnumGuid *new_This = impl_from_IEnumGUID(*ppenum);
409 410 411 412 413
        new_This->cursor = This->cursor;
    }
    return res;
}

414 415
static const IEnumGUIDVtbl EnumGUIDVtbl =
{
416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432
    CompartmentEnumGuid_QueryInterface,
    CompartmentEnumGuid_AddRef,
    CompartmentEnumGuid_Release,
    CompartmentEnumGuid_Next,
    CompartmentEnumGuid_Skip,
    CompartmentEnumGuid_Reset,
    CompartmentEnumGuid_Clone
};

static HRESULT CompartmentEnumGuid_Constructor(struct list *values, IEnumGUID **ppOut)
{
    CompartmentEnumGuid *This;

    This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CompartmentEnumGuid));
    if (This == NULL)
        return E_OUTOFMEMORY;

433
    This->IEnumGUID_iface.lpVtbl= &EnumGUIDVtbl;
434 435 436 437 438
    This->refCount = 1;

    This->values = values;
    This->cursor = list_head(values);

439 440
    *ppOut = &This->IEnumGUID_iface;
    TRACE("returning %p\n", *ppOut);
441 442
    return S_OK;
}
443 444 445 446

/**************************************************
 * ITfCompartment
 **************************************************/
447 448 449 450 451 452
static void free_sink(CompartmentSink *sink)
{
        IUnknown_Release(sink->interfaces.pIUnknown);
        HeapFree(GetProcessHeap(),0,sink);
}

453 454
static void Compartment_Destructor(Compartment *This)
{
455
    struct list *cursor, *cursor2;
456 457
    TRACE("destroying %p\n", This);
    VariantClear(&This->variant);
458 459 460 461 462 463
    LIST_FOR_EACH_SAFE(cursor, cursor2, &This->CompartmentEventSink)
    {
        CompartmentSink* sink = LIST_ENTRY(cursor,CompartmentSink,entry);
        list_remove(cursor);
        free_sink(sink);
    }
464 465 466 467 468
    HeapFree(GetProcessHeap(),0,This);
}

static HRESULT WINAPI Compartment_QueryInterface(ITfCompartment *iface, REFIID iid, LPVOID *ppvOut)
{
469 470
    Compartment *This = impl_from_ITfCompartment(iface);

471 472 473 474
    *ppvOut = NULL;

    if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfCompartment))
    {
475
        *ppvOut = &This->ITfCompartment_iface;
476
    }
477 478
    else if (IsEqualIID(iid, &IID_ITfSource))
    {
479
        *ppvOut = &This->ITfSource_iface;
480
    }
481 482 483

    if (*ppvOut)
    {
484
        ITfCompartment_AddRef(iface);
485 486 487 488 489 490 491 492 493
        return S_OK;
    }

    WARN("unsupported interface: %s\n", debugstr_guid(iid));
    return E_NOINTERFACE;
}

static ULONG WINAPI Compartment_AddRef(ITfCompartment *iface)
{
494
    Compartment *This = impl_from_ITfCompartment(iface);
495 496 497 498 499
    return InterlockedIncrement(&This->refCount);
}

static ULONG WINAPI Compartment_Release(ITfCompartment *iface)
{
500
    Compartment *This = impl_from_ITfCompartment(iface);
501 502 503 504 505 506 507 508 509 510 511
    ULONG ret;

    ret = InterlockedDecrement(&This->refCount);
    if (ret == 0)
        Compartment_Destructor(This);
    return ret;
}

static HRESULT WINAPI Compartment_SetValue(ITfCompartment *iface,
    TfClientId tid, const VARIANT *pvarValue)
{
512
    Compartment *This = impl_from_ITfCompartment(iface);
513
    struct list *cursor;
514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537

    TRACE("(%p) %i %p\n",This,tid,pvarValue);

    if (!pvarValue)
        return E_INVALIDARG;

    if (!(V_VT(pvarValue) == VT_BSTR || V_VT(pvarValue) == VT_I4 ||
          V_VT(pvarValue) == VT_UNKNOWN))
        return E_INVALIDARG;

    if (!This->valueData->owner)
        This->valueData->owner = tid;

    VariantClear(&This->variant);

    /* Shallow copy of value and type */
    This->variant = *pvarValue;

    if (V_VT(pvarValue) == VT_BSTR)
        V_BSTR(&This->variant) = SysAllocStringByteLen((char*)V_BSTR(pvarValue),
                SysStringByteLen(V_BSTR(pvarValue)));
    else if (V_VT(pvarValue) == VT_UNKNOWN)
        IUnknown_AddRef(V_UNKNOWN(&This->variant));

538 539 540 541 542 543
    LIST_FOR_EACH(cursor, &This->CompartmentEventSink)
    {
        CompartmentSink* sink = LIST_ENTRY(cursor,CompartmentSink,entry);
        ITfCompartmentEventSink_OnChange(sink->interfaces.pITfCompartmentEventSink,&This->valueData->guid);
    }

544
    return S_OK;
545 546 547 548 549
}

static HRESULT WINAPI Compartment_GetValue(ITfCompartment *iface,
    VARIANT *pvarValue)
{
550
    Compartment *This = impl_from_ITfCompartment(iface);
551 552 553 554 555
    TRACE("(%p) %p\n",This, pvarValue);

    if (!pvarValue)
        return E_INVALIDARG;

556 557 558
    VariantInit(pvarValue);
    if (V_VT(&This->variant) == VT_EMPTY) return S_FALSE;
    return VariantCopy(pvarValue,&This->variant);
559 560
}

561 562
static const ITfCompartmentVtbl CompartmentVtbl =
{
563 564 565 566 567 568 569
    Compartment_QueryInterface,
    Compartment_AddRef,
    Compartment_Release,
    Compartment_SetValue,
    Compartment_GetValue
};

570 571 572 573
/*****************************************************
 * ITfSource functions
 *****************************************************/

574
static HRESULT WINAPI CompartmentSource_QueryInterface(ITfSource *iface, REFIID iid, LPVOID *ppvOut)
575
{
576
    Compartment *This = impl_from_ITfSource(iface);
577
    return ITfCompartment_QueryInterface(&This->ITfCompartment_iface, iid, ppvOut);
578 579
}

580
static ULONG WINAPI CompartmentSource_AddRef(ITfSource *iface)
581
{
582 583
    Compartment *This = impl_from_ITfSource(iface);
    return ITfCompartment_AddRef(&This->ITfCompartment_iface);
584 585
}

586
static ULONG WINAPI CompartmentSource_Release(ITfSource *iface)
587
{
588 589
    Compartment *This = impl_from_ITfSource(iface);
    return ITfCompartment_Release(&This->ITfCompartment_iface);
590 591
}

592
static HRESULT WINAPI CompartmentSource_AdviseSink(ITfSource *iface,
593 594
        REFIID riid, IUnknown *punk, DWORD *pdwCookie)
{
595
    Compartment *This = impl_from_ITfSource(iface);
596
    CompartmentSink *cs;
597 598 599 600 601 602

    TRACE("(%p) %s %p %p\n",This,debugstr_guid(riid),punk,pdwCookie);

    if (!riid || !punk || !pdwCookie)
        return E_INVALIDARG;

603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624
    if (IsEqualIID(riid, &IID_ITfCompartmentEventSink))
    {
        cs = HeapAlloc(GetProcessHeap(),0,sizeof(CompartmentSink));
        if (!cs)
            return E_OUTOFMEMORY;
        if (FAILED(IUnknown_QueryInterface(punk, riid, (LPVOID *)&cs->interfaces.pITfCompartmentEventSink)))
        {
            HeapFree(GetProcessHeap(),0,cs);
            return CONNECT_E_CANNOTCONNECT;
        }
        list_add_head(&This->CompartmentEventSink,&cs->entry);
        *pdwCookie = generate_Cookie(COOKIE_MAGIC_COMPARTMENTSINK , cs);
    }
    else
    {
        FIXME("(%p) Unhandled Sink: %s\n",This,debugstr_guid(riid));
        return E_NOTIMPL;
    }

    TRACE("cookie %x\n",*pdwCookie);

    return S_OK;
625 626
}

627
static HRESULT WINAPI CompartmentSource_UnadviseSink(ITfSource *iface, DWORD pdwCookie)
628
{
629
    Compartment *This = impl_from_ITfSource(iface);
630 631 632 633 634 635 636
    CompartmentSink *sink;

    TRACE("(%p) %x\n",This,pdwCookie);

    if (get_Cookie_magic(pdwCookie)!=COOKIE_MAGIC_COMPARTMENTSINK)
        return E_INVALIDARG;

637
    sink = remove_Cookie(pdwCookie);
638 639 640 641 642 643 644 645 646
    if (!sink)
        return CONNECT_E_NOCONNECTION;

    list_remove(&sink->entry);
    free_sink(sink);

    return S_OK;
}

647
static const ITfSourceVtbl CompartmentSourceVtbl =
648
{
649 650 651
    CompartmentSource_QueryInterface,
    CompartmentSource_AddRef,
    CompartmentSource_Release,
652 653 654 655
    CompartmentSource_AdviseSink,
    CompartmentSource_UnadviseSink,
};

656 657 658 659 660 661 662 663
static HRESULT Compartment_Constructor(CompartmentValue *valueData, ITfCompartment **ppOut)
{
    Compartment *This;

    This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(Compartment));
    if (This == NULL)
        return E_OUTOFMEMORY;

664 665
    This->ITfCompartment_iface.lpVtbl= &CompartmentVtbl;
    This->ITfSource_iface.lpVtbl = &CompartmentSourceVtbl;
666 667 668 669 670
    This->refCount = 1;

    This->valueData = valueData;
    VariantInit(&This->variant);

671 672
    list_init(&This->CompartmentEventSink);

673 674
    *ppOut = &This->ITfCompartment_iface;
    TRACE("returning %p\n", *ppOut);
675 676
    return S_OK;
}