Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564/* * PROJECT: ReactOS CTF * LICENSE: LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later) * PURPOSE: ITfCompartmentMgr implementation * COPYRIGHT: Copyright 2009 Aric Stewart, CodeWeavers * Copyright 2025 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com> */
#include "precomp.h"
#include <wine/debug.h>WINE_DEFAULT_DEBUG_CHANNEL(msctf);
////////////////////////////////////////////////////////////////////////////
typedef struct tagCompartmentValue{ struct list entry; GUID guid; TfClientId owner; ITfCompartment *compartment;} CompartmentValue;
////////////////////////////////////////////////////////////////////////////
class CCompartmentMgr : public ITfCompartmentMgr{public: CCompartmentMgr(IUnknown *pUnkOuter = NULL); virtual ~CCompartmentMgr();
static HRESULT CreateInstance(IUnknown *pUnkOuter, REFIID riid, IUnknown **ppOut);
// ** IUnknown methods ** STDMETHODIMP QueryInterface(REFIID iid, LPVOID *ppvObj) override; STDMETHODIMP_(ULONG) AddRef() override; STDMETHODIMP_(ULONG) Release() override;
// ** ITfCompartmentMgr methods ** STDMETHODIMP GetCompartment(_In_ REFGUID rguid, _Out_ ITfCompartment **ppcomp) override; STDMETHODIMP ClearCompartment(_In_ TfClientId tid, _In_ REFGUID rguid) override; STDMETHODIMP EnumCompartments(_Out_ IEnumGUID **ppEnum) override;
protected: LONG m_cRefs; IUnknown *m_pUnkOuter; struct list m_values;};
////////////////////////////////////////////////////////////////////////////
class CCompartmentEnumGuid : public IEnumGUID{public: CCompartmentEnumGuid(); virtual ~CCompartmentEnumGuid();
static HRESULT CreateInstance(struct list *values, IEnumGUID **ppOut); static HRESULT CreateInstance(struct list *values, IEnumGUID **ppOut, struct list *cursor);
// ** IUnknown methods ** STDMETHODIMP QueryInterface(REFIID iid, LPVOID *ppvObj) override; STDMETHODIMP_(ULONG) AddRef() override; STDMETHODIMP_(ULONG) Release() override;
// ** IEnumGUID methods ** STDMETHODIMP Next( _In_ ULONG celt, _Out_ GUID *rgelt, _Out_ ULONG *pceltFetched) override; STDMETHODIMP Skip(_In_ ULONG celt) override; STDMETHODIMP Reset() override; STDMETHODIMP Clone(_Out_ IEnumGUID **ppenum) override;
protected: LONG m_cRefs; struct list *m_values; struct list *m_cursor;};
////////////////////////////////////////////////////////////////////////////
class CCompartment : public ITfCompartment , public ITfSource{public: CCompartment(CompartmentValue *valueData); virtual ~CCompartment();
static HRESULT CreateInstance(CompartmentValue *valueData, ITfCompartment **ppOut);
// ** IUnknown methods ** STDMETHODIMP QueryInterface(REFIID iid, LPVOID *ppvObj) override; STDMETHODIMP_(ULONG) AddRef() override; STDMETHODIMP_(ULONG) Release() override;
// ** ITfCompartment methods ** STDMETHODIMP SetValue(_In_ TfClientId tid, _In_ const VARIANT *pvarValue) override; STDMETHODIMP GetValue(_Out_ VARIANT *pvarValue) override;
// ** ITfSource methods ** STDMETHODIMP AdviseSink( _In_ REFIID riid, _In_ IUnknown *punk, _Out_ DWORD *pdwCookie) override; STDMETHODIMP UnadviseSink(_In_ DWORD dwCookie) override;
protected: LONG m_cRefs; VARIANT m_variant; // Only VT_I4, VT_UNKNOWN and VT_BSTR data types are allowed CompartmentValue *m_valueData; struct list m_CompartmentEventSink;};
////////////////////////////////////////////////////////////////////////////
CCompartmentMgr::CCompartmentMgr(IUnknown *pUnkOuter) : m_cRefs(1) , m_pUnkOuter(pUnkOuter){ list_init(&m_values);}
CCompartmentMgr::~CCompartmentMgr(){ struct list *cursor, *cursor2;
LIST_FOR_EACH_SAFE(cursor, cursor2, &m_values) { CompartmentValue *value = LIST_ENTRY(cursor, CompartmentValue, entry); list_remove(cursor); value->compartment->Release(); cicMemFree(value); }}
HRESULT CCompartmentMgr::CreateInstance(IUnknown *pUnkOuter, REFIID riid, IUnknown **ppOut){ if (!ppOut) return E_POINTER;
if (pUnkOuter && riid != IID_IUnknown) return CLASS_E_NOAGGREGATION;
CCompartmentMgr *This = new(cicNoThrow) CCompartmentMgr(pUnkOuter); if (!This) return E_OUTOFMEMORY;
if (pUnkOuter) { *ppOut = static_cast<ITfCompartmentMgr *>(This); TRACE("returning %p\n", *ppOut); return S_OK; } else { HRESULT hr; hr = This->QueryInterface(riid, (void **)ppOut); if (FAILED(hr)) delete This; return hr; }}
STDMETHODIMP CCompartmentMgr::QueryInterface(REFIID iid, LPVOID *ppvOut){ if (m_pUnkOuter) return m_pUnkOuter->QueryInterface(iid, ppvOut);
*ppvOut = NULL;
if (iid == IID_IUnknown || iid == IID_ITfCompartmentMgr) *ppvOut = static_cast<ITfCompartmentMgr *>(this);
if (*ppvOut) { AddRef(); return S_OK; }
WARN("unsupported interface: %s\n", debugstr_guid(&iid)); return E_NOINTERFACE;}
STDMETHODIMP_(ULONG) CCompartmentMgr::AddRef(){ if (m_pUnkOuter) return m_pUnkOuter->AddRef(); return ::InterlockedIncrement(&m_cRefs);}
STDMETHODIMP_(ULONG) CCompartmentMgr::Release(){ if (m_pUnkOuter) return m_pUnkOuter->Release(); ULONG ret = ::InterlockedDecrement(&m_cRefs); if (!ret) delete this; return ret;}
HRESULT CCompartmentMgr::GetCompartment(_In_ REFGUID rguid, _Out_ ITfCompartment **ppcomp){ if (!ppcomp) return E_POINTER; CompartmentValue* value; struct list *cursor; HRESULT hr;
TRACE("(%p) %s %p\n", this, debugstr_guid(&rguid), ppcomp);
LIST_FOR_EACH(cursor, &m_values) { value = LIST_ENTRY(cursor, CompartmentValue, entry); if (rguid == value->guid) { value->compartment->AddRef(); *ppcomp = value->compartment; return S_OK; } }
value = (CompartmentValue *)cicMemAlloc(sizeof(CompartmentValue)); if (!value) return E_OUTOFMEMORY;
value->guid = rguid; value->owner = 0; hr = CCompartment::CreateInstance(value, &value->compartment); if (SUCCEEDED(hr)) { list_add_head(&m_values, &value->entry); value->compartment->AddRef(); *ppcomp = value->compartment; } else { cicMemFree(value); *ppcomp = NULL; }
return hr;}
HRESULT CCompartmentMgr::ClearCompartment(_In_ TfClientId tid, _In_ REFGUID rguid){ struct list *cursor;
TRACE("(%p) %i %s\n", this, tid, debugstr_guid(&rguid));
LIST_FOR_EACH(cursor, &m_values) { CompartmentValue *value = LIST_ENTRY(cursor,CompartmentValue, entry); if (rguid == value->guid) { if (value->owner && tid != value->owner) return E_UNEXPECTED; list_remove(cursor); value->compartment->Release(); cicMemFree(value); return S_OK; } }
return CONNECT_E_NOCONNECTION;}
HRESULT CCompartmentMgr::EnumCompartments(_Out_ IEnumGUID **ppEnum){ TRACE("(%p) %p\n", this, ppEnum); if (!ppEnum) return E_INVALIDARG;
return CCompartmentEnumGuid::CreateInstance(&m_values, ppEnum);}
////////////////////////////////////////////////////////////////////////////
CCompartmentEnumGuid::CCompartmentEnumGuid() : m_cRefs(1) , m_values(NULL) , m_cursor(NULL){}
CCompartmentEnumGuid::~CCompartmentEnumGuid(){ TRACE("destroying %p\n", this);}
HRESULTCCompartmentEnumGuid::CreateInstance(struct list *values, IEnumGUID **ppOut){ CCompartmentEnumGuid *This = new(cicNoThrow) CCompartmentEnumGuid(); if (!This) return E_OUTOFMEMORY;
This->m_values = values; This->m_cursor = list_head(values);
*ppOut = static_cast<IEnumGUID *>(This); TRACE("returning %p\n", *ppOut); return S_OK;}
HRESULTCCompartmentEnumGuid::CreateInstance(struct list *values, IEnumGUID **ppOut, struct list *cursor){ CCompartmentEnumGuid *This = new(cicNoThrow) CCompartmentEnumGuid(); if (!This) return E_OUTOFMEMORY;
This->m_values = values; This->m_cursor = cursor;
*ppOut = static_cast<IEnumGUID *>(This); TRACE("returning %p\n", *ppOut); return S_OK;}
STDMETHODIMP CCompartmentEnumGuid::QueryInterface(REFIID iid, LPVOID *ppvObj){ *ppvObj = NULL;
if (iid == IID_IUnknown || iid == IID_IEnumGUID) *ppvObj = static_cast<IEnumGUID *>(this);
if (*ppvObj) { AddRef(); return S_OK; }
WARN("unsupported interface: %s\n", debugstr_guid(&iid)); return E_NOINTERFACE;}
STDMETHODIMP_(ULONG) CCompartmentEnumGuid::AddRef(){ return ::InterlockedIncrement(&m_cRefs);}
STDMETHODIMP_(ULONG) CCompartmentEnumGuid::Release(){ ULONG ret = ::InterlockedDecrement(&m_cRefs); if (!ret) delete this; return ret;}
STDMETHODIMP CCompartmentEnumGuid::Next( _In_ ULONG celt, _Out_ GUID *rgelt, _Out_ ULONG *pceltFetched){ ULONG fetched = 0;
TRACE("(%p)\n", this);
if (!rgelt) return E_POINTER;
while (fetched < celt && m_cursor) { CompartmentValue* value = LIST_ENTRY(m_cursor, CompartmentValue, entry); if (!value) break;
m_cursor = list_next(m_values, m_cursor); *rgelt = value->guid;
++fetched; ++rgelt; }
if (pceltFetched) *pceltFetched = fetched; return fetched == celt ? S_OK : S_FALSE;}
STDMETHODIMP CCompartmentEnumGuid::Skip(_In_ ULONG celt){ TRACE("(%p)\n", this); m_cursor = list_next(m_values, m_cursor); return S_OK;}
STDMETHODIMP CCompartmentEnumGuid::Reset(){ TRACE("(%p)\n", this); m_cursor = list_head(m_values); return S_OK;}
STDMETHODIMP CCompartmentEnumGuid::Clone(_Out_ IEnumGUID **ppenum){ TRACE("(%p)\n", this);
if (!ppenum) return E_POINTER;
return CCompartmentEnumGuid::CreateInstance(m_values, ppenum, m_cursor);}
////////////////////////////////////////////////////////////////////////////
CCompartment::CCompartment(CompartmentValue *valueData) : m_cRefs(1) , m_valueData(valueData){ VariantInit(&m_variant); list_init(&m_CompartmentEventSink);}
CCompartment::~CCompartment(){ TRACE("destroying %p\n", this); VariantClear(&m_variant); free_sinks(&m_CompartmentEventSink);}
HRESULT CCompartment::CreateInstance(CompartmentValue *valueData, ITfCompartment **ppOut){ CCompartment *This = new(cicNoThrow) CCompartment(valueData); if (!This) return E_OUTOFMEMORY;
*ppOut = static_cast<ITfCompartment *>(This); TRACE("returning %p\n", *ppOut); return S_OK;}
STDMETHODIMP CCompartment::QueryInterface(REFIID iid, LPVOID *ppvObj){ *ppvObj = NULL;
if (iid == IID_IUnknown || iid == IID_ITfCompartment) *ppvObj = static_cast<ITfCompartment *>(this); else if (iid == IID_ITfSource) *ppvObj = static_cast<ITfSource *>(this);
if (*ppvObj) { AddRef(); return S_OK; }
WARN("unsupported interface: %s\n", debugstr_guid(&iid)); return E_NOINTERFACE;}
STDMETHODIMP_(ULONG) CCompartment::AddRef(){ return ::InterlockedIncrement(&m_cRefs);}
STDMETHODIMP_(ULONG) CCompartment::Release(){ ULONG ret = ::InterlockedDecrement(&m_cRefs); if (!ret) delete this; return ret;}
STDMETHODIMP CCompartment::SetValue(_In_ TfClientId tid, _In_ const VARIANT *pvarValue){ ITfCompartmentEventSink *sink; struct list *cursor;
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 (!m_valueData->owner) m_valueData->owner = tid;
::VariantClear(&m_variant);
/* Shallow copy of value and type */ m_variant = *pvarValue;
if (V_VT(pvarValue) == VT_BSTR) { V_BSTR(&m_variant) = ::SysAllocStringByteLen((char*)V_BSTR(pvarValue), ::SysStringByteLen(V_BSTR(pvarValue))); } else if (V_VT(pvarValue) == VT_UNKNOWN) { V_UNKNOWN(&m_variant)->AddRef(); }
SINK_FOR_EACH(cursor, &m_CompartmentEventSink, ITfCompartmentEventSink, sink) { sink->OnChange(m_valueData->guid); }
return S_OK;}
STDMETHODIMP CCompartment::GetValue(_Out_ VARIANT *pvarValue){ TRACE("(%p) %p\n", this, pvarValue);
if (!pvarValue) return E_INVALIDARG;
::VariantInit(pvarValue); if (V_VT(&m_variant) == VT_EMPTY) return S_FALSE; return ::VariantCopy(pvarValue, &m_variant);}
STDMETHODIMP CCompartment::AdviseSink( _In_ REFIID riid, _In_ IUnknown *punk, _Out_ DWORD *pdwCookie){ TRACE("(%p) %s %p %p\n", this, debugstr_guid(&riid), punk, pdwCookie);
if (cicIsNullPtr(&riid) || !punk || !pdwCookie) return E_INVALIDARG;
if (riid == IID_ITfCompartmentEventSink) { return advise_sink(&m_CompartmentEventSink, IID_ITfCompartmentEventSink, COOKIE_MAGIC_COMPARTMENTSINK, punk, pdwCookie); }
FIXME("(%p) Unhandled Sink: %s\n", this, debugstr_guid(&riid)); return E_NOTIMPL;}
STDMETHODIMP CCompartment::UnadviseSink(_In_ DWORD dwCookie){ TRACE("(%p) %x\n", this, dwCookie);
if (get_Cookie_magic(dwCookie) != COOKIE_MAGIC_COMPARTMENTSINK) return E_INVALIDARG;
return unadvise_sink(dwCookie);}
////////////////////////////////////////////////////////////////////////////
EXTERN_CHRESULT CompartmentMgr_Constructor(IUnknown *pUnkOuter, REFIID riid, IUnknown **ppOut){ return CCompartmentMgr::CreateInstance(pUnkOuter, riid, ppOut);}
EXTERN_CHRESULT CompartmentMgr_Destructor(ITfCompartmentMgr *iface){ iface->Release(); return S_OK;}