// // ic.h // #ifndef IC_H #define IC_H #include "private.h" #include "globals.h" #include "rprop.h" #include "editrec.h" #include "strary.h" #include "compart.h" #define TF_ES_INEDITSESSION 0x80000000 #define TF_ES_INNOTIFY 0x40000000 #define TF_ES_WRITE (TF_ES_READWRITE & ~TF_ES_READ) #define TF_ES_PROPERTY_WRITE (TF_ES_READ_PROPERTY_WRITE & ~TF_ES_READ) #define TF_ES_ALL_ACCESS_BITS (TF_ES_READWRITE | TF_ES_READ_PROPERTY_WRITE) #define IC_NUM_CONNECTIONPTS 5 // these are indices into _rgSinks, must match CInputContext::_c_rgConnectionIIDs #define IC_SINK_ITfTextEditSink 0 #define IC_SINK_ITfTextLayoutSink 1 #define IC_SINK_ITfStatusSink 2 #define IC_SINK_ITfStartReconversionNotifySink 3 #define IC_SINK_ITfEditTransactionSink 4 class CRange; class CProperty; class CThreadInputMgr; class CFunctionProvider; class CFunction; class CContextView; class CComposition; class CDocumentInputManager; class CInputContext; extern const IID IID_PRIV_CINPUTCONTEXT; #define LEFT_FILTERTIP 0 #define RIGHT_FILTERTIP 1 typedef struct _CLEANUPSINK { TfClientId tid; ITfCleanupContextSink *pSink; } CLEANUPSINK; ////////////////////////////////////////////////////////////////////////////// // // QUEUE_ITEM structures // ////////////////////////////////////////////////////////////////////////////// typedef enum { QI_ADDREF, QI_DISPATCH, QI_FREE } QiCallbackCode; struct _TS_QUEUE_ITEM; typedef HRESULT (*QI_CALLBACK)(CInputContext *pic, struct _TS_QUEUE_ITEM *pItem, QiCallbackCode qiCode); typedef struct _EDITSESSION { TfClientId tid; ITfEditSession *pes; } EDITSESSION; typedef struct _PSEUDO_EDITSESSION { ULONG uCode; void *pvState; } PSEUDO_EDITSESSION; class CAsyncQueueItem; typedef struct _ASYNCQUEUE_EDITSESSION { CAsyncQueueItem *paqi; } ASYNCQUEUE_EDITSESSION; typedef struct _TS_QUEUE_ITEM { QI_CALLBACK pfnCallback; DWORD dwFlags; // TF_ES_READWRITE | TF_ES_READ | TF_ES_WRITE | TF_ES_SYNC union { // state for edit sessions EDITSESSION es; PSEUDO_EDITSESSION pes; ASYNCQUEUE_EDITSESSION aqe; // other state... } state; } TS_QUEUE_ITEM; // // PSEUDO_EDITSESSION callback codes // #define PSEUDO_ESCB_TERMCOMPOSITION 0 #define PSEUDO_ESCB_UPDATEKEYEVENTFILTER 1 #define PSEUDO_ESCB_GROWRANGE 2 #define PSEUDO_ESCB_BUILDOWNERRANGELIST 3 #define PSEUDO_ESCB_SHIFTENDTORANGE 4 #define PSEUDO_ESCB_GETSELECTION 5 #define PSEUDO_ESCB_SERIALIZE_ACP 6 #define PSEUDO_ESCB_SERIALIZE_ANCHOR 7 #define PSEUDO_ESCB_UNSERIALIZE_ACP 8 #define PSEUDO_ESCB_UNSERIALIZE_ANCHOR 9 #define PSEUDO_ESCB_GETWHOLEDOCRANGE 10 typedef struct _SERIALIZE_ANCHOR_PARAMS { CProperty *pProp; CRange *pRange; TF_PERSISTENT_PROPERTY_HEADER_ANCHOR *pHdr; IStream *pStream; } SERIALIZE_ANCHOR_PARAMS; typedef struct _UNSERIALIZE_ANCHOR_PARAMS { CProperty *pProp; const TF_PERSISTENT_PROPERTY_HEADER_ANCHOR *pHdr; IStream *pStream; ITfPersistentPropertyLoaderAnchor *pLoader; } UNSERIALIZE_ANCHOR_PARAMS; ////////////////////////////////////////////////////////////////////////////// // // CAsyncQueueItem // ////////////////////////////////////////////////////////////////////////////// class CAsyncQueueItem { public: CAsyncQueueItem(BOOL fSync = FALSE) { _item.pfnCallback = _EditSessionQiCallback; _item.dwFlags = TF_ES_READWRITE | (fSync ? TF_ES_SYNC : 0); _item.state.aqe.paqi = this; _cRef = 1; } virtual ~CAsyncQueueItem() {}; static HRESULT _EditSessionQiCallback(CInputContext *pic, struct _TS_QUEUE_ITEM *pItem, QiCallbackCode qiCode); virtual HRESULT DoDispatch(CInputContext *pic) = 0; void _CheckReadOnly(CInputContext *pic); TS_QUEUE_ITEM *GetItem() { return &_item; } LONG _AddRef() { _cRef++; return _cRef; } LONG _Release() { LONG ret = --_cRef; if (!_cRef) delete this; return ret; } private: LONG _cRef; TS_QUEUE_ITEM _item; }; ////////////////////////////////////////////////////////////////////////////// // // CInputContext // ////////////////////////////////////////////////////////////////////////////// class CInputContext : public ITfContext_P, public ITfQueryEmbedded, public ITfInsertAtSelection, public ITfContextOwnerServices, public ITfContextOwnerCompositionServices, public ITfSource, public ITfSourceSingle, public ITextStoreAnchorSink, public ITextStoreAnchorServices, public ITfMouseTracker, public IServiceProvider, public ITfContextRenderingMarkup, public CCompartmentMgr, public CComObjectRootImmx { public: CInputContext(TfClientId tid); ~CInputContext(); BEGIN_COM_MAP_IMMX(CInputContext) COM_INTERFACE_ENTRY_IID(IID_PRIV_CINPUTCONTEXT, CInputContext) COM_INTERFACE_ENTRY(ITfContext) COM_INTERFACE_ENTRY(ITfContext_P) COM_INTERFACE_ENTRY(ITfQueryEmbedded) COM_INTERFACE_ENTRY(ITfInsertAtSelection) COM_INTERFACE_ENTRY(ITfContextComposition) COM_INTERFACE_ENTRY(ITfContextOwnerCompositionServices) COM_INTERFACE_ENTRY(ITfSource) COM_INTERFACE_ENTRY(ITfSourceSingle) COM_INTERFACE_ENTRY(ITextStoreAnchorSink) COM_INTERFACE_ENTRY(ITextStoreAnchorServices) COM_INTERFACE_ENTRY(ITfCompartmentMgr) COM_INTERFACE_ENTRY(ITfContextOwnerServices) // Issue: it would be nice if this was only avail w/ cicero def text store // COM_INTERFACE_ENTRY_FUNC COM_INTERFACE_ENTRY(ITfMouseTracker) COM_INTERFACE_ENTRY(IServiceProvider) COM_INTERFACE_ENTRY(ITfContextRenderingMarkup) END_COM_MAP_IMMX() IMMX_OBJECT_IUNKNOWN_FOR_ATL() // // ITfContext // STDMETHODIMP RequestEditSession(TfClientId tid, ITfEditSession *pes, DWORD dwFlags, HRESULT *phrSession); STDMETHODIMP InWriteSession(TfClientId tid, BOOL *pfWriteSession); STDMETHODIMP GetSelection(TfEditCookie ec, ULONG ulIndex, ULONG ulCount, TF_SELECTION *pSelection, ULONG *pcFetched); STDMETHODIMP SetSelection(TfEditCookie ec, ULONG ulCount, const TF_SELECTION *pSelection); STDMETHODIMP GetStart(TfEditCookie ec, ITfRange **ppStart); STDMETHODIMP GetEnd(TfEditCookie ec, ITfRange **ppEnd); STDMETHODIMP GetStatus(TS_STATUS *pdcs); STDMETHODIMP GetActiveView(ITfContextView **ppView); STDMETHODIMP EnumViews(IEnumTfContextViews **ppEnum); STDMETHODIMP GetProperty(REFGUID guidProp, ITfProperty **ppv); STDMETHODIMP GetAppProperty(REFGUID guidProp, ITfReadOnlyProperty **ppProp); STDMETHODIMP TrackProperties(const GUID **pguidProp, ULONG cProp, const GUID **pguidAppProp, ULONG cAppProp, ITfReadOnlyProperty **ppPropX); STDMETHODIMP EnumProperties(IEnumTfProperties **ppEnum); STDMETHODIMP GetDocumentMgr(ITfDocumentMgr **ppDoc); STDMETHODIMP CreateRangeBackup(TfEditCookie ec, ITfRange *pRange, ITfRangeBackup **ppBackup); // ITfQueryEmbedded STDMETHODIMP QueryInsertEmbedded(const GUID *pguidService, const FORMATETC *pFormatEtc, BOOL *pfInsertable); // ITfInsertAtSelection STDMETHODIMP InsertTextAtSelection(TfEditCookie ec, DWORD dwFlags, const WCHAR *pchText, LONG cch, ITfRange **ppRange); STDMETHODIMP InsertEmbeddedAtSelection(TfEditCookie ec, DWORD dwFlags, IDataObject *pDataObject, ITfRange **ppRange); // ITfContextOwnerServices STDMETHODIMP OnLayoutChange(); //STDMETHODIMP OnStatusChange(); // use ITextStoreAnchorSink::OnStatusChange STDMETHODIMP OnAttributeChange(REFGUID rguidAttribute); STDMETHODIMP Serialize(ITfProperty *pProp, ITfRange *pRange, TF_PERSISTENT_PROPERTY_HEADER_ACP *pHdr, IStream *pStream); STDMETHODIMP Unserialize(ITfProperty *pProp, const TF_PERSISTENT_PROPERTY_HEADER_ACP *pHdr, IStream *pStream, ITfPersistentPropertyLoaderACP *pLoader); STDMETHODIMP ForceLoadProperty(ITfProperty *pProp); STDMETHODIMP CreateRange(LONG acpStart, LONG acpEnd, ITfRangeACP **ppRange); // ITfContextComposition STDMETHODIMP StartComposition(TfEditCookie ecWrite, ITfRange *pCompositionRange, ITfCompositionSink *pSink, ITfComposition **ppComposition); STDMETHODIMP EnumCompositions(IEnumITfCompositionView **ppEnum); STDMETHODIMP FindComposition(TfEditCookie ecRead, ITfRange *pTestRange, IEnumITfCompositionView **ppEnum); STDMETHODIMP TakeOwnership(TfEditCookie ecWrite, ITfCompositionView *pComposition, ITfCompositionSink *pSink, ITfComposition **ppComposition); // ITfContextOwnerCompositionServices STDMETHODIMP TerminateComposition(ITfCompositionView *pComposition); // ITfSource STDMETHODIMP AdviseSink(REFIID riid, IUnknown *punk, DWORD *pdwCookie); STDMETHODIMP UnadviseSink(DWORD dwCookie); // ITfSourceSingle STDMETHODIMP AdviseSingleSink(TfClientId tid, REFIID riid, IUnknown *punk); STDMETHODIMP UnadviseSingleSink(TfClientId tid, REFIID riid); // ITextStoreAnchorSink STDMETHODIMP OnTextChange(DWORD dwFlags, IAnchor *paStart, IAnchor *paEnd); STDMETHODIMP OnSelectionChange(); STDMETHODIMP OnLayoutChange(TsLayoutCode lcode, TsViewCookie vcView); STDMETHODIMP OnStatusChange(DWORD dwFlags); STDMETHODIMP OnAttrsChange(IAnchor *paStart, IAnchor *paEnd, ULONG cAttrs, const TS_ATTRID *paAttrs); STDMETHODIMP OnLockGranted(DWORD dwLockFlags); STDMETHODIMP OnStartEditTransaction(); STDMETHODIMP OnEndEditTransaction(); // ITextStoreAnchorServices STDMETHODIMP Serialize(ITfProperty *pProp, ITfRange *pRange, TF_PERSISTENT_PROPERTY_HEADER_ANCHOR *pHdr, IStream *pStream); STDMETHODIMP Unserialize(ITfProperty *pProp, const TF_PERSISTENT_PROPERTY_HEADER_ANCHOR *pHdr, IStream *pStream, ITfPersistentPropertyLoaderAnchor *pLoader); STDMETHODIMP CreateRange(IAnchor *paStart, IAnchor *paEnd, ITfRangeAnchor **ppRange); // ITfMouseTracker STDMETHODIMP AdviseMouseSink(ITfRange *range, ITfMouseSink *pSink, DWORD *pdwCookie); STDMETHODIMP UnadviseMouseSink(DWORD dwCookie); // IServiceProvider STDMETHODIMP QueryService(REFGUID guidService, REFIID riid, void **ppv); // ITfContextRenderingMarkup STDMETHODIMP GetRenderingMarkup(TfEditCookie ec, DWORD dwFlags, ITfRange *pRangeCover, IEnumTfRenderingMarkup **ppEnum); STDMETHODIMP FindNextRenderingMarkup(TfEditCookie ec, DWORD dwFlags, ITfRange *pRangeQuery, TfAnchor tfAnchorQuery, ITfRange **ppRangeFound, TF_RENDERINGMARKUP *ptfRenderingMarkup); // ITfContext_P STDMETHODIMP MapAppProperty(REFGUID guidAppProp, REFGUID guidProp); STDMETHODIMP EnableLockRequestPosting(BOOL fEnable); HRESULT _Init(CThreadInputMgr *tim, CDocumentInputManager *dm, ITextStoreAnchor *ptsi, ITfContextOwnerCompositionSink *pOwnerComposeSink); void _Pushed(); void _Popped(); void _AdviseSinks(); void _UnadviseSinks(CThreadInputMgr *tim); void _UpdateKeyEventFilter(); HRESULT _UpdateKeyEventFilterCallback(TfEditCookie ec); HRESULT _GetProperty(REFGUID rguidProp, CProperty **ppv); BOOL _NotifyEndEdit(void); CProperty *_FindProperty(REFGUID rguidProp) { TfGuidAtom ga; if (MyRegisterGUID(rguidProp, &ga) != S_OK) return NULL; return _FindProperty(ga); } CProperty *_FindProperty(TfGuidAtom gaProp); void _PropertyTextUpdate(DWORD dwFlags, IAnchor *paStart, IAnchor *paEnd); CProperty *_GetFirstProperty() { return _pPropList; } CProperty *_pPropList; BOOL _IsCiceroTSI() { return _fCiceroTSI; } ITextStoreAnchor *_GetTSI() { return _ptsi; } ITextStoreAnchor *_GetAATSI() { return _pMSAAState ? _pMSAAState->pAADoc : NULL; } BOOL _IsInEditSession() { return (_dwEditSessionFlags & TF_ES_INEDITSESSION); } BOOL _IsConnected() { return _dm ? TRUE : FALSE; } BOOL _IsValidEditCookie(TfEditCookie ec, DWORD dwFlags) { Assert(dwFlags & TF_ES_READ); // minimum access... if (ec == BACKDOOR_EDIT_COOKIE) { Assert(!(dwFlags & (TF_ES_WRITE | TF_ES_PROPERTY_WRITE))); // app is trying to use def ec with write operation return !(dwFlags & (TF_ES_WRITE | TF_ES_PROPERTY_WRITE)); // app can read anything it wants } Assert(_ec != TF_INVALID_EDIT_COOKIE); // must always return FALSE for TF_INVALID_EDIT_COOKIE... Assert(!(_dwEditSessionFlags & TF_ES_WRITE) || (_dwEditSessionFlags & TF_ES_PROPERTY_WRITE)); // write implies property write return (ec == _ec && (_dwEditSessionFlags & TF_ES_INEDITSESSION) && (!(dwFlags & TF_ES_WRITE) || (_dwEditSessionFlags & TF_ES_WRITE))) && (!(dwFlags & TF_ES_PROPERTY_WRITE) || (_dwEditSessionFlags & TF_ES_PROPERTY_WRITE)); } void _IncLastLockReleaseID() { _dwLastLockReleaseID++; /* Issue: handle wrap-around */ } DWORD _GetLastLockReleaseID() { return _dwLastLockReleaseID; } CDocumentInputManager *_GetDm() { return _dm; } CEditRecord *_GetEditRecord() { return _pEditRecord; } HRESULT _OnTextChangeInternal(DWORD dwFlags, IAnchor *paStart, IAnchor *paEnd, AnchorOwnership ao); CProperty *GetTextOwnerProperty(); TfClientId _GetClientInEditSession(TfEditCookie ec) { return ec == BACKDOOR_EDIT_COOKIE ? g_gaApp : _tidInEditSession; } TfClientId _SetRawClientInEditSession(TfClientId tid) { TfClientId tidTmp = _tidInEditSession; _tidInEditSession = tid; return tidTmp; } CStructArray *_GetTextEditSinks() { return &_rgSinks[IC_SINK_ITfTextEditSink]; } CStructArray *_GetTextLayoutSinks() { return &_rgSinks[IC_SINK_ITfTextLayoutSink]; } CStructArray *_GetStatusSinks() { return &_rgSinks[IC_SINK_ITfStatusSink]; } CStructArray *_GetStartReconversionNotifySinks() { return &_rgSinks[IC_SINK_ITfStartReconversionNotifySink]; } CStructArray *_GetEditTransactionSink() { return &_rgSinks[IC_SINK_ITfEditTransactionSink]; } CStructArray *_GetCleanupSinks() { return &_rgCleanupSinks; } BOOL _AppSupportsCompositions() { return _pCompositionList != NULL; } CComposition *_GetCompositionList() { return _pCompositionList; } CComposition **_GetCompositionListPtr() { return &_pCompositionList; } ITfContextOwnerCompositionSink *_GetOwnerCompositionSink() { return _pOwnerComposeSink; } BOOL _DoesAppSupportCompositions() { return _pOwnerComposeSink != NULL; } BOOL _EnterCompositionOp() { return (_fInCompositionOp ? FALSE : (_fInCompositionOp = TRUE)); } void _LeaveCompositionOp() { Assert(_fInCompositionOp); _fInCompositionOp = FALSE; } HRESULT _StartComposition(TfEditCookie ecWrite, IAnchor *paStart, IAnchor *paEnd, ITfCompositionSink *pSink, CComposition **ppComposition); HRESULT _TerminateCompositionWithLock(ITfCompositionView *pComposition, TfEditCookie ec); void _AbortCompositions(); static void _PostponeLockRequestCallback(SYSTHREAD *psfn, CInputContext *pic); HRESULT _DoPseudoSyncEditSession(DWORD dwFlags, ULONG uCode, void *pvState, HRESULT *phrSession) { TS_QUEUE_ITEM item; item.pfnCallback = _PseudoSyncEditSessionQiCallback; item.dwFlags = dwFlags | TF_ES_SYNC; item.state.pes.uCode = uCode; item.state.pes.pvState = pvState; return _QueueItem(&item, FALSE, phrSession); } HRESULT _QueueItem(TS_QUEUE_ITEM *pItem, BOOL fForceAsync, HRESULT *phrSession); BOOL _ContextNeedsCleanup(const GUID *pCatId, LANGID langid, CStructArray **pprgClientIds); void _CleanupContext(CStructArray *prgClientIds); HRESULT GetMappedAppProperty(REFGUID guidProp, CProperty **ppProp); private: friend CThreadInputMgr; friend CRange; friend CProperty; friend CFunction; typedef struct _IAS_OBJ { enum { IAS_TEXT, IAS_DATAOBJ } type; union { struct { const WCHAR *pchText; LONG cch; } text; struct { IDataObject *pDataObject; } obj; } state; } IAS_OBJ; HRESULT _InsertXAtSelection(TfEditCookie ec, DWORD dwFlags, IAS_OBJ *pObj, ITfRange **ppRange); void _DoPostTextEditNotifications(CComposition *pComposition, TfEditCookie ec, DWORD dwFlags, ULONG cchInserted, IAnchor *paStart, IAnchor *paEnd, CRange *range); BOOL _InsertXAtSelectionAggressive(TfEditCookie ec, DWORD dwFlags, IAS_OBJ *pObj, IAnchor **ppaStart, IAnchor **ppaEnd); int _GetCleanupListIndex(TfClientId tid); HRESULT _UnadviseOwnerSink(); HRESULT _GetStartOrEnd(TfEditCookie ec, BOOL fStart, ITfRange **ppStart); BOOL _SynchAppChanges(DWORD dwLockFlags); HRESULT _EmptyLockQueue(DWORD dwLockFlags, BOOL fAppChangesSent); void _AbortQueueItems(); void _PostponeLockRequest(DWORD dwFlags); HRESULT _DispatchQueueItem(TS_QUEUE_ITEM *pItem) { return pItem->pfnCallback(this, pItem, QI_DISPATCH); } void _ReleaseQueueItem(TS_QUEUE_ITEM *pItem) { pItem->pfnCallback(this, pItem, QI_FREE); } void _AddRefQueueItem(TS_QUEUE_ITEM *pItem) { pItem->pfnCallback(this, pItem, QI_ADDREF); } HRESULT _DoEditSession(TfClientId tid, ITfEditSession *pes, DWORD dwFlags); static HRESULT _EditSessionQiCallback(CInputContext *pic, TS_QUEUE_ITEM *pItem, QiCallbackCode qiCode); static HRESULT _PseudoSyncEditSessionQiCallback(CInputContext *pic, TS_QUEUE_ITEM *pItem, QiCallbackCode qiCode); HRESULT _OnSelectionChangeInternal(BOOL fAppChange); HRESULT _OnLayoutChangeInternal(TsLayoutCode lcode, TsViewCookie vcView); HRESULT _OnStatusChangeInternal(); void _MarkDirtyRanges(IAnchor *paStart, IAnchor *paEnd); TFPROPERTYSTYLE _GetPropStyle(REFGUID rguidProp); void _IncEditCookie() { _ec++; // avoid reserved values! if (_ec == 0) { _ec = EC_MIN; } } void _Dbg_AssertNoSyncQueueItems() { #ifdef DEBUG for (int i=0; i<_rgLockQueue.Count(); i++) { Assert((_rgLockQueue.GetPtr(i)->dwFlags & TF_ES_SYNC) == 0); } #endif // DEBUG } CDocumentInputManager *_dm; ITextStoreAnchor *_ptsi; BOOL _fCiceroTSI; DWORD _dwLastLockReleaseID; TfEditCookie _ec; int _cEditRef; DWORD _dwEditSessionFlags; BOOL _fLockHeld; // perf: redundant with _dwlt? DWORD _dwlt; // perf: only need 2 bits TfClientId _tidInEditSession; DWORD _dwPendingLockRequest; // perf: only need 2 bits CEditRecord *_pEditRecord; BOOL EnsureEditRecord() { if (!_pEditRecord) _pEditRecord = new CEditRecord(this); return _pEditRecord ? TRUE : FALSE; } BOOL _fLayoutChanged; BOOL _fStatusChanged; // perf: redundant w/ _dwStatusChangedFlags? DWORD _dwStatusChangedFlags; // array of TIP guidatom for both left and right side of the caret. TfGuidAtom _gaKeyEventFilterTIP[2]; BOOL _fInvalidKeyEventFilterTIP; ITfContextKeyEventSink *_pICKbdSink; DWORD _dwSysFuncPrvCookie; // system function provider cookie // // TextOwner Property cache // CProperty *_pPropTextOwner; static const GUID *_c_rgPropStyle[]; CStructArray _rgLockQueue; static const IID *_c_rgConnectionIIDs[IC_NUM_CONNECTIONPTS]; CStructArray _rgSinks[IC_NUM_CONNECTIONPTS]; CStructArray _rgCleanupSinks; CStructArray _rgAppTextChanges; CComposition *_pCompositionList; CRange *_pOnChangeRanges; // ranges with ITfRangeChange sinks CContextView *_pActiveView; ITfContextOwnerCompositionSink *_pOwnerComposeSink; // may be NULL, be careful LONG _cRefEditTransaction; BOOL _fInCompositionOp : 1; // TRUE if we're inside a write modification to a composition (ceate, terminate, etc.) BOOL _fInUnserialize : 1; // TRUE if we're inside a property _Unserialize // // App Property Map // typedef struct _APPPROPMAP { GUID guidAppProp; GUID guidProp; } APPPROPMAP; CStructArray _rgAppPropMap; APPPROPMAP *FindMapAppProperty(REFGUID guidAppProp); // // disable PostThreadMessage for LoackRequest. // ULONG _nLockReqPostDisableRef; // aa stuff // void _InitMSAAHook(IAccServerDocMgr *pAAAdaptor); void _UninitMSAAHook(IAccServerDocMgr *pAAAdaptor); typedef struct { ITextStoreAnchor *ptsiOrg; // the original, unwrapped ptsi ITextStoreAnchor *pAADoc; // the wrapped ITextStoreAnchor passed to _pAAAdaptor } MSAA_STATE; MSAA_STATE *_pMSAAState; // use a struct since we rarely use msaa // // end aa stuff #ifdef DEBUG BOOL _dbg_fInOnLockGranted; #endif DBG_ID_DECLARE; }; inline CInputContext *GetCInputContext(IUnknown *punk) { CInputContext *pic; punk->QueryInterface(IID_PRIV_CINPUTCONTEXT, (void **)&pic); return pic; } //+--------------------------------------------------------------------------- // // SafeRequestLock // // ITextStoreAnchor::RequestLock wrapper. // // Normally each CInputContext holds a ref to a text store in its _ptsi member. // But, it's possible that some crazy tip will Pop the context inside a // RequestLock call, which releases and clears _ptsi. This will likely crash // the ptsi code, since after OnLockGranted, the object will be freed. // So we protect the app by AddRef'ing the ptsi before the RequestLock call. //---------------------------------------------------------------------------- inline HRESULT SafeRequestLock(ITextStoreAnchor *ptsi, DWORD dwLockFlags, HRESULT *phrSession) { HRESULT hr; ptsi->AddRef(); // protect pointer in case someone Pops this context inside the RequestLock hr = ptsi->RequestLock(dwLockFlags, phrSession); ptsi->Release(); return hr; } #endif // IC_H