|
|
//
// compart.cpp
//
#include "private.h"
#include "globals.h"
#include "regsvr.h"
#include "compart.h"
#include "helpers.h"
#include "thdutil.h"
#include "tim.h"
#include "cicmutex.h"
#include "timlist.h"
#include "cregkey.h"
/* e575186e-71a8-4ef4-90da-14ed705e7df2 */ extern const IID IID_PRIV_CCOMPARTMENTMGR = { 0xe575186e, 0x71a8, 0x4ef4, {0x90, 0xda, 0x14, 0xed, 0x70, 0x5e, 0x7d, 0xf2} };
/* 8b05c1ad-adf0-4a78-a3e2-d38cae3e28be */ extern const IID IID_PRIV_CGLOBALCOMPARTMENT = { 0x8b05c1ad, 0xadf0, 0x4a78, {0xa3, 0xe2, 0xd3, 0x8c, 0xae, 0x3e, 0x28, 0xbe} };
DBG_ID_INSTANCE(CCompartment); DBG_ID_INSTANCE(CCompartmentMgr); DBG_ID_INSTANCE(CEnumCompartment); DBG_ID_INSTANCE(CGlobalCompartment);
extern CCicMutex g_mutexCompart;
//+---------------------------------------------------------------------------
//
// EnsureGlobalCompartment
//
//----------------------------------------------------------------------------
BOOL EnsureGlobalCompartment(SYSTHREAD *psfn) { if (psfn->_pGlobalCompMgr) return TRUE;
psfn->_pGlobalCompMgr = new CGlobalCompartmentMgr(g_gaApp);
if (psfn->_pGlobalCompMgr) { if (g_gcomplist.Init(psfn)) return TRUE;
delete psfn->_pGlobalCompMgr; psfn->_pGlobalCompMgr = NULL; } return FALSE; }
//+---------------------------------------------------------------------------
//
// GetCompartmentDWORD
//
//----------------------------------------------------------------------------
HRESULT MyGetCompartmentDWORD(CCompartmentMgr *pCompMgr, REFGUID rguid, DWORD *pdw) { HRESULT hr; ITfCompartment *pComp; VARIANT var;
if (!pCompMgr) return E_FAIL;
*pdw = 0; if (SUCCEEDED(hr = pCompMgr->GetCompartment(rguid, &pComp))) { hr = pComp->GetValue(&var); if (hr == S_OK) { Assert(var.vt == VT_I4); *pdw = var.lVal; // no need to VariantClear because VT_I4
} pComp->Release(); }
return hr; }
//+---------------------------------------------------------------------------
//
// SetCompartmentDWORD
//
//----------------------------------------------------------------------------
HRESULT MySetCompartmentDWORD(TfClientId tid, CCompartmentMgr *pCompMgr, REFGUID rguid, DWORD dw) { HRESULT hr; ITfCompartment *pComp; VARIANT var;
if (!pCompMgr) return E_FAIL;
if (SUCCEEDED(hr = pCompMgr->GetCompartment(rguid, &pComp))) { var.vt = VT_I4; var.lVal = dw; hr = pComp->SetValue(tid, &var); pComp->Release(); }
return hr; }
//+---------------------------------------------------------------------------
//
// ToggleCompartmentDWORD
//
// Toggle DWORD value between 0 and 1.
//
//----------------------------------------------------------------------------
HRESULT MyToggleCompartmentDWORD(TfClientId tid, CCompartmentMgr *pCompMgr, REFGUID rguid, DWORD *pdwOld) { ITfCompartment *pComp; VARIANT var; DWORD dw = 0; HRESULT hr = E_FAIL;
if (!pCompMgr) return E_FAIL;
if (pCompMgr->GetCompartment(rguid, &pComp) == S_OK) { if (SUCCEEDED(pComp->GetValue(&var))) { if (var.vt == VT_EMPTY) { // compartment is uninitialized
var.vt = VT_I4; var.lVal = 0; } else { Assert(var.vt == VT_I4); }
var.lVal = (var.lVal == 0) ? 1 : 0; // no need to VariantClear because VT_I4
if ((hr = pComp->SetValue(tid, &var)) == S_OK) { dw = var.lVal; } }
pComp->Release(); }
if (pdwOld) *pdwOld = dw;
return hr; }
//////////////////////////////////////////////////////////////////////////////
//
// CCompartmentMgr
//
//////////////////////////////////////////////////////////////////////////////
//+---------------------------------------------------------------------------
//
// ctor
//
//----------------------------------------------------------------------------
CCompartmentMgr::CCompartmentMgr(TfClientId tidOwner, COMPTYPE cType) { Dbg_MemSetThisNameIDCounter(TEXT("CCompartmentMgr"), PERF_COMPARTMGR_COUNTER);
_tidOwner = tidOwner; _cType = cType; }
//+---------------------------------------------------------------------------
//
// dtor
//
//----------------------------------------------------------------------------
CCompartmentMgr::~CCompartmentMgr() { CleanUp(); }
//+---------------------------------------------------------------------------
//
// CleanUp
//
//----------------------------------------------------------------------------
void CCompartmentMgr::CleanUp() { int nCnt = _rgCompartment.Count(); int i;
for (i = 0; i < nCnt; i++) { CCompartmentBase *pComp = _rgCompartment.Get(i); pComp->Invalid(); pComp->Release(); } _rgCompartment.Clear(); }
//+---------------------------------------------------------------------------
//
// GetCompartment
//
//----------------------------------------------------------------------------
STDAPI CCompartmentMgr::GetCompartment(REFGUID rguid, ITfCompartment **ppcomp) { CCompartmentBase *pComp;
if (!ppcomp) return E_INVALIDARG;
*ppcomp = NULL;
pComp = _Get(rguid); if (!pComp) return E_OUTOFMEMORY;
*ppcomp = pComp; pComp->AddRef();
return S_OK; }
//+---------------------------------------------------------------------------
//
// ClearCompartment
//
//----------------------------------------------------------------------------
STDAPI CCompartmentMgr::ClearCompartment(TfClientId tid, REFGUID rguid) { TfGuidAtom guidatom; CCompartmentBase *pComp; int iInsert; HRESULT hr;
if (FAILED(hr = MyRegisterGUID(rguid, &guidatom))) return hr;
pComp = _Find(guidatom, &iInsert);
if (!pComp) return CONNECT_E_NOCONNECTION;
if (pComp->_GetAccess() & CA_ONLYOWNERSET) { if (_tidOwner != tid) return E_UNEXPECTED; }
_rgCompartment.Remove(iInsert, 1); pComp->Invalid(); pComp->Release();
return S_OK; }
//+---------------------------------------------------------------------------
//
// EnumCompartment
//
//----------------------------------------------------------------------------
STDAPI CCompartmentMgr::EnumCompartments(IEnumGUID **ppEnum) { CEnumCompartment *pEnum;
if (!ppEnum) return E_INVALIDARG;
pEnum = new CEnumCompartment();
if (!pEnum) return E_OUTOFMEMORY;
if (pEnum->_Init(&_rgCompartment)) *ppEnum = pEnum; else SafeReleaseClear(pEnum);
return pEnum ? S_OK : E_FAIL; }
//+---------------------------------------------------------------------------
//
// _Find
//
//----------------------------------------------------------------------------
CCompartmentBase *CCompartmentMgr::_Find(TfGuidAtom guidatom, int *piOut) { CCompartmentBase *pComp; CCompartmentBase *pCompMatch; int iMin; int iMax; int iMid;
pCompMatch = NULL; iMid = -1; iMin = 0; iMax = _rgCompartment.Count();
while (iMin < iMax) { iMid = (iMin + iMax) / 2; pComp = _rgCompartment.Get(iMid); Assert(pComp != NULL);
if (guidatom < pComp->GetGuidAtom()) { iMax = iMid; } else if (guidatom > pComp->GetGuidAtom()) { iMin = iMid + 1; } else // guidatom == pComp->GetGuidAtom().
{ pCompMatch = pComp; break; } }
if (!pCompMatch) { if (iMid >= 0) { CCompartmentBase *pCompTmp = _rgCompartment.Get(iMid); if (pCompTmp->GetGuidAtom() < guidatom) { iMid++; } } }
if (piOut) *piOut = iMid;
return pCompMatch; }
//+---------------------------------------------------------------------------
//
// _Get
//
//----------------------------------------------------------------------------
CCompartmentBase *CCompartmentMgr::_Get(REFGUID rguid) { CCompartmentBase *pComp; int iInsert; TfGuidAtom guidatom;
if (FAILED(MyRegisterGUID(rguid, &guidatom))) return NULL;
pComp = _Find(guidatom, &iInsert);
if (!pComp) { TfPropertyType proptype = TF_PT_NONE;
//
// system predefined compartments does not allow any other type.
//
if ((IsEqualGUID(rguid, GUID_COMPARTMENT_KEYBOARD_DISABLED)) || (IsEqualGUID(rguid, GUID_COMPARTMENT_HANDWRITING_OPENCLOSE)) || (IsEqualGUID(rguid, GUID_COMPARTMENT_SPEECH_OPENCLOSE))) { proptype = TF_PT_DWORD; }
if (_cType == COMPTYPE_GLOBAL) pComp = new CGlobalCompartment(this, rguid, guidatom, proptype); else pComp = new CCompartment(this, guidatom, proptype); if (pComp) { if (iInsert < 0) iInsert = 0;
if (_rgCompartment.Insert(iInsert, 1)) { _rgCompartment.Set(iInsert, pComp); } else { delete pComp; pComp = NULL; } } }
return pComp; }
//+---------------------------------------------------------------------------
//
// NotifyGlobalCompartmentChange
//
//----------------------------------------------------------------------------
void CCompartmentMgr::NotifyGlobalCompartmentChange(DWORD dwId) { Assert(_cType == COMPTYPE_GLOBAL);
int nCnt = _rgCompartment.Count();
for (int i = 0; i < nCnt; i++) { CCompartmentBase *pComp = _rgCompartment.Get(i); if (dwId == pComp->GetId()) { pComp->MakeNotify(); break; } } }
//////////////////////////////////////////////////////////////////////////////
//
// CGlobalCompartmenMgr
//
//////////////////////////////////////////////////////////////////////////////
STDAPI CGlobalCompartmentMgr::QueryInterface(REFIID riid, void **ppvObj) { *ppvObj = NULL;
if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_ITfCompartmentMgr)) { *ppvObj = SAFECAST(this, ITfCompartmentMgr *); }
if (*ppvObj) { return S_OK; }
return E_NOINTERFACE; }
ULONG CGlobalCompartmentMgr::AddRef(void) { _cRef++; return _cRef; }
ULONG CGlobalCompartmentMgr::Release(void) { _cRef--; if (_cRef <= 0) { //
// Calller may call Release() more than AddRef()..
// We should not call TIM::Release() at this time.
//
Assert(0)
return 0; }
return _cRef; }
//////////////////////////////////////////////////////////////////////////////
//
// CEnumCompartment
//
//////////////////////////////////////////////////////////////////////////////
//+---------------------------------------------------------------------------
//
// ctor
//
//----------------------------------------------------------------------------
CEnumCompartment::CEnumCompartment() { Dbg_MemSetThisNameIDCounter(TEXT("CEnumCompartment"), PERF_ENUMCOMPART_COUNTER); }
//+---------------------------------------------------------------------------
//
// Init
//
//----------------------------------------------------------------------------
BOOL CEnumCompartment::_Init(CPtrArray<CCompartmentBase> *prgComp) { int nCnt = prgComp->Count(); int i; BOOL fRet = FALSE;
CicEnterCriticalSection(g_cs);
_pga = SGA_Init(nCnt, NULL);
if (_pga == NULL) goto Exit;
for (i = 0; i < nCnt; i++) { CCompartmentBase *pComp = prgComp->Get(i);
if (FAILED((MyGetGUID(pComp->GetGuidAtom(), &_pga->rgGuid[i])))) goto Exit; }
fRet = TRUE;
Exit: CicLeaveCriticalSection(g_cs); return fRet; }
//////////////////////////////////////////////////////////////////////////////
//
// CCompartmentBase
//
//////////////////////////////////////////////////////////////////////////////
const COMPARTMENTACCESS CCompartmentBase::_c_ca[] = { {&GUID_COMPARTMENT_KEYBOARD_DISABLED, CA_ONLYOWNERSET}, {NULL, 0} }; CCompartmentBase::CCompartmentBase(CCompartmentMgr *pCompMgr, TfGuidAtom guidatom, TfPropertyType proptype) { Assert(!_fInvalid);
_guidatom = guidatom; _proptype = proptype; _pCompMgr = pCompMgr;
int n = 0; while (_c_ca[n].pguid) { if (MyIsEqualTfGuidAtom(guidatom, *_c_ca[n].pguid)) { _dwAccess = _c_ca[n].dwAccess; } n++; } }
//////////////////////////////////////////////////////////////////////////////
//
// CCompartment
//
//////////////////////////////////////////////////////////////////////////////
//+---------------------------------------------------------------------------
//
// ctor
//
//----------------------------------------------------------------------------
CCompartment::CCompartment(CCompartmentMgr *pCompMgr, TfGuidAtom guidatom, TfPropertyType proptype) :CCompartmentBase(pCompMgr, guidatom, proptype) { Dbg_MemSetThisNameIDCounter(TEXT("CCompartment"), PERF_COMPART_COUNTER); }
//+---------------------------------------------------------------------------
//
// dtor
//
//----------------------------------------------------------------------------
CCompartment::~CCompartment() { if (_prop.type == TF_PT_UNKNOWN) { //
// #489905
//
// we can not call sink anymore after DLL_PROCESS_DETACH.
//
if (!DllShutdownInProgress()) _prop.punk->Release(); } else if (_prop.type == TF_PT_BSTR) SysFreeString(_prop.bstr); }
//+---------------------------------------------------------------------------
//
// Advise
//
//----------------------------------------------------------------------------
HRESULT CCompartment::AdviseSink(REFIID riid, IUnknown *punk, DWORD *pdwCookie) { const IID *rgiid;
rgiid = &IID_ITfCompartmentEventSink;
return GenericAdviseSink(riid, punk, &rgiid, &_rgCompartmentSink, 1, pdwCookie); }
//+---------------------------------------------------------------------------
//
// Unadvise
//
//----------------------------------------------------------------------------
HRESULT CCompartment::UnadviseSink(DWORD dwCookie) { return GenericUnadviseSink(&_rgCompartmentSink, 1, dwCookie); }
//+---------------------------------------------------------------------------
//
// GetValue
//
//----------------------------------------------------------------------------
HRESULT CCompartment::GetValue(VARIANT *pvarValue) { HRESULT hr;
if (_fInvalid) { Assert(0); return E_UNEXPECTED; }
if (pvarValue == NULL) return E_INVALIDARG;
QuickVariantInit(pvarValue);
hr = TfPropToVariant(pvarValue, &_prop, ADDREF);
if (hr != S_OK) return hr;
return (pvarValue->vt == VT_EMPTY) ? S_FALSE : S_OK; }
//+---------------------------------------------------------------------------
//
// SetValue
//
//----------------------------------------------------------------------------
HRESULT CCompartment::SetValue(TfClientId tid, const VARIANT *pvarValue) { HRESULT hr;
if (_fInvalid) { Assert(0); return E_UNEXPECTED; }
if (_fInSet) return E_UNEXPECTED;
if (pvarValue == NULL) return E_INVALIDARG;
if (!IsValidCiceroVarType(pvarValue->vt)) return E_INVALIDARG;
if (pvarValue->vt == VT_EMPTY) return E_INVALIDARG;
if (_GetAccess() & CA_ONLYOWNERSET) { if (_GetMgr()->_GetTIPOwner() != tid) return E_UNEXPECTED; }
hr = VariantToTfProp(&_prop, pvarValue, ADDREF, FALSE);
if (hr != S_OK) return hr;
int i; int nCnt = _rgCompartmentSink.Count(); if (nCnt) { GUID guid; if (FAILED(MyGetGUID(_guidatom, &guid))) { return E_FAIL; Assert(0); }
_fInSet = TRUE; for (i = 0; i < nCnt; i++) { ((ITfCompartmentEventSink *)_rgCompartmentSink.GetPtr(i)->pSink)->OnChange(guid); } _fInSet = FALSE; }
return S_OK; }
//////////////////////////////////////////////////////////////////////////////
//
// CGlobalCompartment
//
//////////////////////////////////////////////////////////////////////////////
//+---------------------------------------------------------------------------
//
// ctor
//
//----------------------------------------------------------------------------
CGlobalCompartment::CGlobalCompartment(CCompartmentMgr *pCompMgr, REFGUID rguid, TfGuidAtom guidatom, TfPropertyType proptype) :CCompartmentBase(pCompMgr, guidatom, proptype) { Dbg_MemSetThisNameIDCounter(TEXT("CGlobalCompartment"), PERF_GLOBCOMPART_COUNTER); _dwId = (DWORD)(-1); _guidCompart = rguid; }
//+---------------------------------------------------------------------------
//
// dtor
//
//----------------------------------------------------------------------------
CGlobalCompartment::~CGlobalCompartment() { }
//+---------------------------------------------------------------------------
//
// Advise
//
//----------------------------------------------------------------------------
HRESULT CGlobalCompartment::AdviseSink(REFIID riid, IUnknown *punk, DWORD *pdwCookie) { const IID *rgiid;
if (_dwId == (DWORD)(-1)) { _dwId = g_gcomplist.GetId(_guidCompart); if (_dwId == (DWORD)(-1)) { TFPROPERTY prop; memset(&prop, 0, sizeof(prop)); _dwId = g_gcomplist.SetProperty(_guidCompart, &prop); if (_dwId == (DWORD)(-1)) return E_FAIL; } }
rgiid = &IID_ITfCompartmentEventSink;
return GenericAdviseSink(riid, punk, &rgiid, &_rgCompartmentSink, 1, pdwCookie); }
//+---------------------------------------------------------------------------
//
// Unadvise
//
//----------------------------------------------------------------------------
HRESULT CGlobalCompartment::UnadviseSink(DWORD dwCookie) { return GenericUnadviseSink(&_rgCompartmentSink, 1, dwCookie); }
//+---------------------------------------------------------------------------
//
// GetValue
//
//----------------------------------------------------------------------------
HRESULT CGlobalCompartment::GetValue(VARIANT *pvarValue) { HRESULT hr; TFPROPERTY prop;
if (_fInvalid) { Assert(0); return E_UNEXPECTED; }
if (pvarValue == NULL) return E_INVALIDARG;
QuickVariantInit(pvarValue);
if (_dwId == (DWORD)(-1)) { _dwId = g_gcomplist.GetId(_guidCompart); }
memset(&prop, 0, sizeof(TFPROPERTY)); if (_dwId != (DWORD)(-1)) g_gcomplist.GetProperty(_guidCompart, &prop);
Assert(prop.type != TF_PT_UNKNOWN);
hr = TfPropToVariant(pvarValue, &prop, ADDREF);
if (hr != S_OK) return hr;
return (pvarValue->vt == VT_EMPTY) ? S_FALSE : S_OK; }
//+---------------------------------------------------------------------------
//
// SetValue
//
//----------------------------------------------------------------------------
HRESULT CGlobalCompartment::SetValue(TfClientId tid, const VARIANT *pvarValue) { HRESULT hr; TFPROPERTY prop;
if (_fInvalid) { Assert(0); return E_UNEXPECTED; }
if (_fInSet) return E_UNEXPECTED;
if (pvarValue == NULL) return E_INVALIDARG;
if (!IsValidCiceroVarType(pvarValue->vt)) return E_INVALIDARG;
if (_GetAccess() & CA_ONLYOWNERSET) { if (_GetMgr()->_GetTIPOwner() != tid) return E_UNEXPECTED; }
if (pvarValue->vt == VT_UNKNOWN) { Assert(0); return E_INVALIDARG; }
hr = VariantToTfProp(&prop, pvarValue, NO_ADDREF, FALSE);
if (hr != S_OK) return hr;
_dwId = g_gcomplist.SetProperty(_guidCompart, &prop); if (_dwId == (DWORD)(-1)) return E_FAIL;
hr = (prop.type != TF_PT_NONE) ? S_OK : E_FAIL;
if (SUCCEEDED(hr)) { //
// make a notify to the sinks of the current thread.
//
if (!MakeNotify()) return E_FAIL; PostTimListMessage(TLF_GCOMPACTIVE, 0, g_msgPrivate, TFPRIV_GLOBALCOMPARTMENTSYNC, _dwId);
}
return hr; }
//+---------------------------------------------------------------------------
//
// EnumThreadProc
//
//----------------------------------------------------------------------------
BOOL CGlobalCompartment::EnumThreadProc(DWORD dwThreadId, DWORD dwProcessId, void *pv) { if (dwThreadId != GetCurrentThreadId()) { CGlobalCompartment *_this = (CGlobalCompartment *)pv;
PostThreadMessage(dwThreadId, g_msgPrivate, TFPRIV_GLOBALCOMPARTMENTSYNC, _this->_dwId); } return FALSE; }
//+---------------------------------------------------------------------------
//
// MakeNotify
//
//----------------------------------------------------------------------------
BOOL CGlobalCompartment::MakeNotify() { int i; int nCnt = _rgCompartmentSink.Count(); if (nCnt) { GUID guid; if (FAILED(MyGetGUID(_guidatom, &guid))) { Assert(0); return FALSE; }
_fInSet = TRUE; for (i = 0; i < nCnt; i++) { ((ITfCompartmentEventSink *)_rgCompartmentSink.GetPtr(i)->pSink)->OnChange(guid); } _fInSet = FALSE; }
return TRUE; }
|