//--------------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation // // File: olecontrol.cpp // // History: // 7-31-96 by dli //------------------------------------------------------------------------ #include "priv.h" class COleControlHost; //--------------------------------------------------------------------------- // Event sink class CEventSink : public IDispatch //--------------------------------------------------------------------------- { public: CEventSink( BOOL bAutoDelete = FALSE ) ; // Connect/disconnect BOOL Connect( HWND hwndOwner, HWND hwndSite, LPUNKNOWN punkOC ) ; BOOL Disconnect() ; // IUnknown methods STDMETHOD (QueryInterface)( REFIID riid, void** ppvObj ) ; STDMETHOD_(ULONG, AddRef)() ; STDMETHOD_(ULONG, Release)() ; // IDispatch methods STDMETHOD (GetTypeInfoCount)( UINT *pctinfo ) { return E_NOTIMPL ; } STDMETHOD (GetTypeInfo)( UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo ) { return E_NOTIMPL ; } STDMETHOD (GetIDsOfNames)( REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId ) { return E_NOTIMPL ; } STDMETHOD (Invoke)( IN DISPID dispIdMember, IN REFIID riid, IN LCID lcid, IN WORD wFlags, IN OUT DISPPARAMS *pDispParams, OUT VARIANT *pVarResult, OUT EXCEPINFO *pExcepInfo, OUT UINT *puArgErr) ; private: static HRESULT _GetDefaultEventIID( LPUNKNOWN punkOC, IID* piid ) ; BOOL _Connect( HWND hwndOwner, HWND hwndSite, LPUNKNOWN punkOC, REFIID iid ) ; BOOL _IsConnected( REFIID iid ) ; ULONG _dwCookie ; // connection cookie IID _iid ; // connection interface IID _iidDefault ; // OC's default event dispatch interface LPUNKNOWN _punkOC ; // OC's unknown LONG _cRef ; // ref count HWND _hwndSite, // _hwndOwner ; BOOL _bAutoDelete ; } ; class CProxyUIHandler : public IDocHostUIHandler2 { public: // *** IUnknown methods *** STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj); STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void); // *** IDocHostUIHandler methods *** virtual STDMETHODIMP ShowContextMenu(DWORD dwID, POINT *ppt, IUnknown *pcmdtReserved, IDispatch *pdispReserved); virtual STDMETHODIMP GetHostInfo(DOCHOSTUIINFO *pInfo); virtual STDMETHODIMP ShowUI(DWORD dwID, IOleInPlaceActiveObject *pActiveObject, IOleCommandTarget *pCommandTarget, IOleInPlaceFrame *pFrame, IOleInPlaceUIWindow *pDoc); virtual STDMETHODIMP HideUI(); virtual STDMETHODIMP UpdateUI(); virtual STDMETHODIMP EnableModeless(BOOL fActivate); virtual STDMETHODIMP OnDocWindowActivate(BOOL fActivate); virtual STDMETHODIMP OnFrameWindowActivate(BOOL fActivate); virtual STDMETHODIMP ResizeBorder(LPCRECT prcBorder, IOleInPlaceUIWindow *pUIWindow, BOOL fRameWindow); virtual STDMETHODIMP TranslateAccelerator(LPMSG lpMsg, const GUID *pguidCmdGroup, DWORD nCmdID); virtual STDMETHODIMP GetOptionKeyPath(LPOLESTR *pchKey, DWORD dw); virtual STDMETHODIMP GetDropTarget(IDropTarget *pDropTarget, IDropTarget **ppDropTarget); virtual STDMETHODIMP GetExternal(IDispatch **ppDispatch); virtual STDMETHODIMP TranslateUrl(DWORD dwTranslate, OLECHAR *pchURLIn, OLECHAR **ppchURLOut); virtual STDMETHODIMP FilterDataObject( IDataObject *pDO, IDataObject **ppDORet); // *** IDocHostUIHandler2 methods *** virtual STDMETHODIMP GetOverrideKeyPath( LPOLESTR *pchKey, DWORD dw); }; //--------------------------------------------------------------------------- // Ole control container object class COleControlHost : public IOleClientSite, public IAdviseSink, public IOleInPlaceSite, public IOleInPlaceFrame, public IServiceProvider, public IOleCommandTarget, public IDispatch // For ambient properties { friend CProxyUIHandler; protected: static LRESULT CALLBACK OCHostWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); HRESULT _Draw(HDC hdc); HRESULT _PersistInit(); HRESULT _Init(); HRESULT _Activate(); HRESULT _Deactivate(); HRESULT _DoVerb(long iVerb, LPMSG lpMsg); HRESULT _Exit(); HRESULT _InitOCStruct(LPOCHINITSTRUCT lpocs); LRESULT _OnPaint(); LRESULT _OnSize(HWND hwnd, LPARAM lParam); LRESULT _OnCreate(HWND hwnd, LPCREATESTRUCT); LRESULT _OnDestroy(); LRESULT _OnQueryInterface(WPARAM wParam, LPARAM lParam); LRESULT _SetOwner(IUnknown * punkOwner); LRESULT _ConnectEvents( LPUNKNOWN punkOC, BOOL bConnect ) ; LRESULT _SetServiceProvider(IServiceProvider* pSP); LRESULT _SendNotify(UINT code, LPNMHDR pnmhdr); // IUnknown UINT _cRef; DWORD _dwAspect; DWORD _dwMiscStatus; // OLE misc status DWORD _dwConnection; // Token for Advisory connections BOOL _bInPlaceActive; // Flag indicating if the OC is in place active HWND _hwnd; HWND _hwndParent; CLSID _clsidOC; IUnknown *_punkOC; IViewObject *_pIViewObject; IOleObject *_pIOleObject; IOleInPlaceObject *_pIOleIPObject; IUnknown *_punkOwner; CEventSink _eventSink ; CProxyUIHandler _xuih; IDocHostUIHandler *_pIDocHostUIParent; IDocHostUIHandler2 *_pIDocHostUIParent2; IDispatch *_pdispSiteDelegate; public: COleControlHost(HWND hwnd); static void _RegisterClass(); // *** IUnknown methods *** STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj); STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void); // IServiceProvider STDMETHODIMP QueryService(REFGUID guidService, REFIID riid, LPVOID* ppvObj); // *** IOleClientSite methods *** STDMETHOD (SaveObject)(); STDMETHOD (GetMoniker)(DWORD, DWORD, LPMONIKER *); STDMETHOD (GetContainer)(LPOLECONTAINER *); STDMETHOD (ShowObject)(); STDMETHOD (OnShowWindow)(BOOL); STDMETHOD (RequestNewObjectLayout)(); // *** IAdviseSink methods *** STDMETHOD_(void,OnDataChange)(FORMATETC *, STGMEDIUM *); STDMETHOD_(void,OnViewChange)(DWORD, LONG); STDMETHOD_(void,OnRename)(LPMONIKER); STDMETHOD_(void,OnSave)(); STDMETHOD_(void,OnClose)(); // *** IOleWindow Methods *** STDMETHOD (GetWindow) (HWND * phwnd); STDMETHOD (ContextSensitiveHelp) (BOOL fEnterMode); // *** IOleInPlaceSite Methods *** STDMETHOD (CanInPlaceActivate) (void); STDMETHOD (OnInPlaceActivate) (void); STDMETHOD (OnUIActivate) (void); STDMETHOD (GetWindowContext) (IOleInPlaceFrame ** ppFrame, IOleInPlaceUIWindow ** ppDoc, LPRECT lprcPosRect, LPRECT lprcClipRect, LPOLEINPLACEFRAMEINFO lpFrameInfo); STDMETHOD (Scroll) (SIZE scrollExtent); STDMETHOD (OnUIDeactivate) (BOOL fUndoable); STDMETHOD (OnInPlaceDeactivate) (void); STDMETHOD (DiscardUndoState) (void); STDMETHOD (DeactivateAndUndo) (void); STDMETHOD (OnPosRectChange) (LPCRECT lprcPosRect); // IOleInPlaceUIWindow methods. STDMETHOD (GetBorder)(LPRECT lprectBorder); STDMETHOD (RequestBorderSpace)(LPCBORDERWIDTHS lpborderwidths); STDMETHOD (SetBorderSpace)(LPCBORDERWIDTHS lpborderwidths); STDMETHOD (SetActiveObject)(IOleInPlaceActiveObject * pActiveObject, LPCOLESTR lpszObjName); // IOleInPlaceFrame methods STDMETHOD (InsertMenus)(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths); STDMETHOD (SetMenu)(HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject); STDMETHOD (RemoveMenus)(HMENU hmenuShared); STDMETHOD (SetStatusText)(LPCOLESTR pszStatusText); STDMETHOD (EnableModeless)(BOOL fEnable); STDMETHOD (TranslateAccelerator)(LPMSG lpmsg, WORD wID); // IOleCommandTarget virtual STDMETHODIMP QueryStatus(const GUID *pguid, ULONG cCmds, MSOCMD rgCmds[], MSOCMDTEXT *pcmdtext); virtual STDMETHODIMP Exec(const GUID *pguid, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut); // IDispatch (for ambient properties) STDMETHODIMP GetTypeInfoCount(UINT* pctinfo); STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo); STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId); STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pvarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr); }; HRESULT COleControlHost::GetTypeInfoCount(UINT* pctinfo) { if (_pdispSiteDelegate) { return _pdispSiteDelegate->GetTypeInfoCount(pctinfo); } return E_NOTIMPL; } HRESULT COleControlHost::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) { if (_pdispSiteDelegate) { return _pdispSiteDelegate->GetTypeInfo(iTInfo, lcid, ppTInfo); } return E_NOTIMPL; } HRESULT COleControlHost::GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) { if (_pdispSiteDelegate) { return _pdispSiteDelegate->GetIDsOfNames(riid, rgszNames, cNames, lcid, rgDispId); } return E_NOTIMPL; } HRESULT COleControlHost::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pvarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) { if (_pdispSiteDelegate) { return _pdispSiteDelegate->Invoke(dispIdMember, riid, lcid, wFlags, pDispParams, pvarResult, pExcepInfo, puArgErr); } return DISP_E_MEMBERNOTFOUND; } HRESULT COleControlHost::_Draw(HDC hdc) { HRESULT hr = E_FAIL; if (_hwnd && _punkOC && !_bInPlaceActive) { RECT rc; GetClientRect(_hwnd, &rc); hr = OleDraw(_punkOC, _dwAspect, hdc, &rc); } return(hr); } HRESULT COleControlHost::_PersistInit() { IPersistStreamInit * pIPersistStreamInit; if (_SendNotify(OCN_PERSISTINIT, NULL) == OCNPERSISTINIT_HANDLED) return S_FALSE; HRESULT hr = _punkOC->QueryInterface(IID_IPersistStreamInit, (void **)&pIPersistStreamInit); if (SUCCEEDED(hr)) { hr = pIPersistStreamInit->InitNew(); pIPersistStreamInit->Release(); } else { IPersistStorage * pIPersistStorage; hr = _punkOC->QueryInterface(IID_IPersistStorage, (void **)&pIPersistStorage); if (SUCCEEDED(hr)) { // Create a zero sized ILockBytes. ILockBytes *pILockBytes; hr = CreateILockBytesOnHGlobal(NULL, TRUE, &pILockBytes); if (SUCCEEDED(hr)) { // Use the ILockBytes to create a storage. IStorage *pIStorage; hr = StgCreateDocfileOnILockBytes(pILockBytes, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pIStorage); if (SUCCEEDED(hr)) { // Call InitNew to initialize the object. hr = pIPersistStorage->InitNew(pIStorage); // Clean up pIStorage->Release(); } // IStorage pILockBytes->Release(); } // ILockBytes pIPersistStorage->Release(); } } return hr; } HRESULT COleControlHost::_Init() { HRESULT hr = E_FAIL; OCNCOCREATEMSG ocm = {0}; ocm.clsidOC = _clsidOC; ocm.ppunk = &_punkOC; if(_SendNotify(OCN_COCREATEINSTANCE, &ocm.nmhdr) != OCNCOCREATE_HANDLED) { hr = CoCreateInstance(_clsidOC, NULL, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, IID_IUnknown, (LPVOID *)&_punkOC); if (FAILED(hr)) { TraceMsg(TF_OCCONTROL, "_Init: Unable to CoCreateInstance this Class ID -- hr = %lX -- hr = %lX", _clsidOC, hr); return hr; } } ASSERT(_punkOC != NULL); if (_punkOC == NULL) return E_FAIL; hr = _punkOC->QueryInterface(IID_IOleObject, (void **)&_pIOleObject); if (FAILED(hr)) { TraceMsg(TF_OCCONTROL, "_Init: Unable to QueryInterface IOleObject -- hr = %s", hr); return hr; } hr = _pIOleObject->GetMiscStatus(_dwAspect, &_dwMiscStatus); // Set the inplace active flag here // If this fails, we will assume that we can setclientsite later if (_dwMiscStatus & OLEMISC_SETCLIENTSITEFIRST) { hr = _pIOleObject->SetClientSite(this); _PersistInit(); } else { _PersistInit(); hr = _pIOleObject->SetClientSite(this); } if (FAILED(hr)) { TraceMsg(TF_OCCONTROL, "_Init: Unable to set client site -- hr = %lX", hr); return hr; } if (SUCCEEDED(_punkOC->QueryInterface(IID_IViewObject, (void **)&_pIViewObject))) { _pIViewObject->SetAdvise(_dwAspect, 0, this); } //FEATURE: this is not really useful because we do not handle the cases, yet _pIOleObject->Advise(this, &_dwConnection); _pIOleObject->SetHostNames(TEXTW("OC Host Window"), TEXTW("OC Host Window")); return S_OK; } // HRESULT COleControlHost::_Activate() { HRESULT hr = E_FAIL; RECT rcClient; ASSERT(_hwnd); _SendNotify(OCN_ACTIVATE, NULL); if (!GetClientRect(_hwnd, &rcClient)) SetRectEmpty(&rcClient); hr = _pIOleObject->DoVerb(OLEIVERB_INPLACEACTIVATE, NULL, this, 0, _hwnd, &rcClient); if (SUCCEEDED(hr)) _bInPlaceActive = TRUE; // Calling second DoVerb with OLEIVERB_SHOW because: // 1. If the above DoVerb fails, this is a back up activation call // 2. If the above DoVerb succeeds, this is also necessary because // Some embeddings needs to be explicitly told to show themselves. if (!(_dwMiscStatus & OLEMISC_INVISIBLEATRUNTIME)) hr = _pIOleObject->DoVerb(OLEIVERB_SHOW, NULL, this, 0, _hwnd, &rcClient); if (FAILED(hr)) TraceMsg(TF_OCCONTROL, "_Activate: %d Unable to DoVerb! Error = %lX", _bInPlaceActive, hr); return hr; } HRESULT COleControlHost::_Deactivate() { _SendNotify(OCN_DEACTIVATE, NULL); if (_pIOleIPObject) { _pIOleIPObject->InPlaceDeactivate(); // Should be set to NULL by the above function call ASSERT(_pIOleIPObject == NULL); return S_OK; } return S_FALSE; } HRESULT COleControlHost::_DoVerb(long iVerb, LPMSG lpMsg) { HRESULT hr = E_FAIL; RECT rcClient; ASSERT(_hwnd && IsWindow(_hwnd)); if (!GetClientRect(_hwnd, &rcClient)) SetRectEmpty(&rcClient); hr = _pIOleObject->DoVerb(iVerb, lpMsg, this, 0, _hwnd, &rcClient); if (SUCCEEDED(hr)) _bInPlaceActive = TRUE; #if 0 // we'll count on DocHost::DoVerb to do this if needed (or our caller?) // note that DocHost does this always (no OLEMISC_* check) if (iVerb == OLEIVERB_INPLACEACTIVATE) { // Calling second DoVerb with OLEIVERB_SHOW because: // 1. If the above DoVerb fails, this is a back up activation call // 2. If the above DoVerb succeeds, this is also necessary because // Some embeddings needs to be explicitly told to show themselves. if (!(_dwMiscStatus & OLEMISC_INVISIBLEATRUNTIME)) hr = _pIOleObject->DoVerb(OLEIVERB_SHOW, lpMsg, this, 0, _hwnd, &rcClient); } #endif if (FAILED(hr)) TraceMsg(TF_OCCONTROL, "_Activate: %d Unable to DoVerb! Error = %lX", _bInPlaceActive, hr); return hr; } // Clean up and Release all of interface pointers used in this object HRESULT COleControlHost::_Exit() { _SendNotify(OCN_EXIT, NULL); if (_pIViewObject) { _pIViewObject->SetAdvise(_dwAspect, 0, NULL); _pIViewObject->Release(); _pIViewObject = NULL; } if (_pIOleObject) { if (_dwConnection) { _pIOleObject->Unadvise(_dwConnection); _dwConnection = 0; } _pIOleObject->Close(OLECLOSE_NOSAVE); _pIOleObject->SetClientSite(NULL); _pIOleObject->Release(); _pIOleObject = NULL; } if (_punkOC) { ULONG ulRef; ulRef = _punkOC->Release(); _punkOC = NULL; if (ulRef != 0) TraceMsg(TF_OCCONTROL, "OCHOST _Exit: After last release ref = %d > 0", ulRef); } ATOMICRELEASE(_pIDocHostUIParent); ATOMICRELEASE(_pIDocHostUIParent2); if (_punkOwner) { _punkOwner->Release(); _punkOwner = NULL; } if (_pdispSiteDelegate) { _pdispSiteDelegate->Release(); _pdispSiteDelegate = NULL; } return S_OK; } COleControlHost::COleControlHost(HWND hwnd) : _cRef(1), _dwAspect(DVASPECT_CONTENT), _hwnd(hwnd) { // These variables should be initialized to zeros automatically ASSERT(_dwMiscStatus == 0); ASSERT(_dwConnection == 0); ASSERT(_bInPlaceActive == FALSE); ASSERT(_pIDocHostUIParent == NULL); ASSERT(_pIDocHostUIParent2 == NULL); ASSERT(_clsidOC == CLSID_NULL); ASSERT(_punkOC == NULL); ASSERT(_pIViewObject == NULL); ASSERT(_pIOleIPObject == NULL); ASSERT(_pdispSiteDelegate == NULL); ASSERT(_hwnd); } #ifdef DEBUG #define _AddRef(psz) { ++_cRef; TraceMsg(TF_OCCONTROL, "CDocObjectHost(%x)::QI(%s) is AddRefing _cRef=%lX", this, psz, _cRef); } #else #define _AddRef(psz) ++_cRef #endif // *** IUnknown Methods *** HRESULT COleControlHost::QueryInterface(REFIID riid, LPVOID * ppvObj) { // ppvObj must not be NULL ASSERT(ppvObj != NULL); if (ppvObj == NULL) return E_INVALIDARG; *ppvObj = NULL; if ((IsEqualIID(riid, IID_IUnknown)) || (IsEqualIID(riid, IID_IOleWindow)) || (IsEqualIID(riid, IID_IOleInPlaceUIWindow)) || (IsEqualIID(riid, IID_IOleInPlaceFrame))) { *ppvObj = SAFECAST(this, IOleInPlaceFrame *); TraceMsg(TF_OCCONTROL, "QI IOleInPlaceFrame succeeded"); } else if (IsEqualIID(riid, IID_IServiceProvider)) { *ppvObj = SAFECAST(this, IServiceProvider *); TraceMsg(TF_OCCONTROL, "QI IServiceProvider succeeded"); } else if (IsEqualIID(riid, IID_IOleClientSite)) { *ppvObj = SAFECAST(this, IOleClientSite *); TraceMsg(TF_OCCONTROL, "QI IOleClientSite succeeded"); } else if (IsEqualIID(riid, IID_IAdviseSink)) { *ppvObj = SAFECAST(this, IAdviseSink *); TraceMsg(TF_OCCONTROL, "QI IAdviseSink succeeded"); } else if (IsEqualIID(riid, IID_IOleInPlaceSite)) { *ppvObj = SAFECAST(this, IOleInPlaceSite *); TraceMsg(TF_OCCONTROL, "QI IOleInPlaceSite succeeded"); } else if (IsEqualIID(riid, IID_IOleCommandTarget)) { *ppvObj = SAFECAST(this, IOleCommandTarget *); TraceMsg(TF_OCCONTROL, "QI IOleCommandTarget succeeded"); } else if (NULL != _pIDocHostUIParent && IsEqualIID(riid, IID_IDocHostUIHandler)) { // only implement this if the host implements it *ppvObj = SAFECAST(&_xuih, IDocHostUIHandler *); TraceMsg(TF_OCCONTROL, "QI IDocHostUIHandler succeeded"); } else if (NULL != _pIDocHostUIParent2 && IsEqualIID(riid, IID_IDocHostUIHandler2)) { // only implement this if the host implements it *ppvObj = SAFECAST(&_xuih, IDocHostUIHandler2 *); TraceMsg(TF_OCCONTROL, "QI IDocHostUIHandler2 succeeded"); } else if (IsEqualIID(riid, IID_IDispatch)) { *ppvObj = SAFECAST(this, IDispatch *); TraceMsg(TF_OCCONTROL, "QI IDispatch succeeded"); } else return E_NOINTERFACE; // Otherwise, don't delegate to HTMLObj!! _AddRef(TEXT("IOleInPlaceSite")); return S_OK; } ULONG COleControlHost::AddRef() { _cRef++; TraceMsg(TF_OCCONTROL, "COleControlHost(%x)::AddRef called, new _cRef=%lX", this, _cRef); return _cRef; } ULONG COleControlHost::Release() { _cRef--; TraceMsg(TF_OCCONTROL, "COleControlHost(%x)::Release called, new _cRef=%lX", this, _cRef); if (_cRef > 0) return _cRef; delete this; return 0; } // ServiceProvider interfaces HRESULT COleControlHost::QueryService(REFGUID guidService, REFIID riid, void **ppvObj) { HRESULT hres = E_FAIL; *ppvObj = NULL; if (_punkOwner) { IServiceProvider *psp; _punkOwner->QueryInterface(IID_IServiceProvider, (LPVOID*)&psp); if (psp) { hres = psp->QueryService(guidService, riid, ppvObj); psp->Release(); } } return hres; } // ************************ IOleClientSite methods ****************** HRESULT COleControlHost::SaveObject() { //FEATURE: default set to E_NOTIMPL may not be correct HRESULT hr = E_NOTIMPL; IStorage * pIs; if (SUCCEEDED(_punkOC->QueryInterface(IID_IStorage, (void **)&pIs))) { IPersistStorage *pIps; if (SUCCEEDED(_punkOC->QueryInterface(IID_IPersistStorage, (void **)&pIps))) { OleSave(pIps, pIs, TRUE); pIps->SaveCompleted(NULL); pIps->Release(); hr = S_OK; } pIs->Release(); } return hr; } HRESULT COleControlHost::GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, LPMONIKER * ppMk) { return E_NOTIMPL; } HRESULT COleControlHost::GetContainer(LPOLECONTAINER * ppContainer) { *ppContainer = NULL; return E_NOINTERFACE; } HRESULT COleControlHost::ShowObject() { // RECTL rcl; // POINT pt1, pt2; return S_OK; } HRESULT COleControlHost::OnShowWindow(BOOL fShow) { return S_OK; } HRESULT COleControlHost::RequestNewObjectLayout() { return E_NOTIMPL; } // ************************ IAdviseSink methods ********************* void COleControlHost::OnDataChange(FORMATETC * pFmt, STGMEDIUM * pStgMed) { // NOTES: This is optional return; } void COleControlHost::OnViewChange(DWORD dwAspect, LONG lIndex) { // FEATURE: need to let the container know the colors might have changed // but don't want to deal with the paletts now // Draw only if not inplace active and this is the right aspect. Inplace // active objects have their own window and are responsible for painting // themselves. // WARNING: _bInPlaceActive is not determined, yet. // This funtion is called as a result of calling doverb, however, // _bInPlaceActive will only be determined as DoVerb returns // works fine for now, but could be trouble later. if ((_hwnd) && (!_bInPlaceActive) && (dwAspect == _dwAspect)) { HDC hdc = GetDC(_hwnd); if (hdc) { _Draw(hdc); ReleaseDC(_hwnd, hdc); } } } void COleControlHost::OnRename(LPMONIKER pMoniker) { return; } void COleControlHost::OnSave() { // NOTES: This is optional return; } void COleControlHost::OnClose() { // FEATURE: need to let the container know the colors might have changed return; } // ************************ IOleWindow Methods ********************** HRESULT COleControlHost::GetWindow(HWND * lphwnd) { *lphwnd = _hwnd; return S_OK; } HRESULT COleControlHost::ContextSensitiveHelp(BOOL fEnterMode) { // NOTES: This is optional return E_NOTIMPL; } // *********************** IOleInPlaceSite Methods ***************** HRESULT COleControlHost::CanInPlaceActivate(void) { return S_OK; } HRESULT COleControlHost::OnInPlaceActivate(void) { if (!_pIOleIPObject) return (_punkOC->QueryInterface(IID_IOleInPlaceObject, (void **)&_pIOleIPObject)); else return S_OK; } HRESULT COleControlHost::OnUIActivate(void) { LRESULT lres; OCNONUIACTIVATEMSG oam = {0}; oam.punk = _punkOC; lres = _SendNotify(OCN_ONUIACTIVATE, &oam.nmhdr); return S_OK; } HRESULT COleControlHost::GetWindowContext (IOleInPlaceFrame ** ppFrame, IOleInPlaceUIWindow ** ppIIPUIWin, LPRECT lprcPosRect, LPRECT lprcClipRect, LPOLEINPLACEFRAMEINFO lpFrameInfo) { *ppFrame = this; _AddRef("GetWindowContext"); // This is set to NULL because the document window is the same as the frame // window *ppIIPUIWin = NULL; ASSERT(_hwnd); if (!GetClientRect(_hwnd, lprcPosRect)) SetRectEmpty(lprcPosRect); // Set the clip rectangle to be the same as the position rectangle CopyRect(lprcClipRect, lprcPosRect); lpFrameInfo->cb = sizeof(OLEINPLACEFRAMEINFO); #ifdef MDI lpFrameInfo->fMDIApp = TRUE; #else lpFrameInfo->fMDIApp = FALSE; #endif lpFrameInfo->hwndFrame = _hwnd; lpFrameInfo->haccel = 0; lpFrameInfo->cAccelEntries = 0; return S_OK; } HRESULT COleControlHost::Scroll(SIZE scrollExtent) { // Should implement later return E_NOTIMPL; } HRESULT COleControlHost::OnUIDeactivate(BOOL fUndoable) { return E_NOTIMPL; } HRESULT COleControlHost::OnInPlaceDeactivate(void) { if (_pIOleIPObject) { _pIOleIPObject->Release(); _pIOleIPObject = NULL; } return S_OK; } HRESULT COleControlHost::DiscardUndoState(void) { // Should implement later return E_NOTIMPL; } HRESULT COleControlHost::DeactivateAndUndo(void) { // Should implement later return E_NOTIMPL; } HRESULT COleControlHost::OnPosRectChange(LPCRECT lprcPosRect) { // We do not allow the children to change the size themselves OCNONPOSRECTCHANGEMSG opcm = {0}; opcm.prcPosRect = lprcPosRect; _SendNotify(OCN_ONPOSRECTCHANGE, &opcm.nmhdr); return S_OK; } // ************************ IOleInPlaceUIWindow methods ************* HRESULT COleControlHost::GetBorder(LPRECT lprectBorder) { return E_NOTIMPL; } HRESULT COleControlHost::RequestBorderSpace(LPCBORDERWIDTHS lpborderwidths) { return E_NOTIMPL; } HRESULT COleControlHost::SetBorderSpace(LPCBORDERWIDTHS lpborderwidths) { return E_NOTIMPL; } HRESULT COleControlHost::SetActiveObject(IOleInPlaceActiveObject * pActiveObject, LPCOLESTR lpszObjName) { return E_NOTIMPL; } // *********************** IOleInPlaceFrame Methods ***************** HRESULT COleControlHost::InsertMenus(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths) { // Should implement later return E_NOTIMPL; } HRESULT COleControlHost::SetMenu(HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject) { // Should implement later return E_NOTIMPL; } HRESULT COleControlHost::RemoveMenus(HMENU hmenuShared) { // Should implement later return E_NOTIMPL; } HRESULT COleControlHost::SetStatusText(LPCOLESTR pszStatusText) { OCNONSETSTATUSTEXTMSG osst = {0}; osst.pwszStatusText = pszStatusText; _SendNotify(OCN_ONSETSTATUSTEXT, &osst.nmhdr); return S_OK; } HRESULT COleControlHost::EnableModeless(BOOL fEnable) { // Should implement later return E_NOTIMPL; } HRESULT COleControlHost::TranslateAccelerator(LPMSG lpmsg, WORD wID) { // Should implement later return E_NOTIMPL; } // ************************ IOleCommandTarget Methods ************* HRESULT COleControlHost::QueryStatus(const GUID *pguid, ULONG cCmds, MSOCMD rgCmds[], MSOCMDTEXT *pcmdtext) { return IUnknown_QueryStatus(_punkOwner, pguid, cCmds, rgCmds, pcmdtext); } HRESULT COleControlHost::Exec(const GUID *pguid, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut) { return IUnknown_Exec(_punkOwner, pguid, nCmdID, nCmdexecopt, pvarargIn, pvarargOut); } HRESULT COleControlHost::_InitOCStruct(LPOCHINITSTRUCT lpocs) { HRESULT hres = E_FAIL; if (_punkOC) return S_FALSE; if (lpocs) { if (lpocs->cbSize != SIZEOF(OCHINITSTRUCT)) return hres; if (lpocs->clsidOC == CLSID_NULL) return hres; _clsidOC = lpocs->clsidOC; _SetOwner(lpocs->punkOwner); } else return hres; hres = _Init(); if (SUCCEEDED(hres)) hres = _Activate(); return hres; } LRESULT COleControlHost::_OnPaint() { ASSERT(_hwnd); PAINTSTRUCT ps; HDC hdc = BeginPaint(_hwnd, &ps); _Draw(hdc); EndPaint(_hwnd, &ps); return 0; } LRESULT COleControlHost::_OnSize(HWND hwnd, LPARAM lParam) { if (_pIOleIPObject) { RECT rcPos, rcClip ; SetRect( &rcPos, 0, 0, LOWORD(lParam), HIWORD(lParam) ) ; rcClip = rcPos ; _pIOleIPObject->SetObjectRects(&rcPos, &rcClip); } return 0; } LRESULT COleControlHost::_OnCreate(HWND hwnd, LPCREATESTRUCT lpcs) { TCHAR szClsid[50]; _hwndParent = GetParent(hwnd); SetWindowLongPtr(hwnd, 0, (LONG_PTR)this); LPOCHINITSTRUCT lpois = (LPOCHINITSTRUCT)lpcs->lpCreateParams; HRESULT hres = S_OK; if (lpois) hres = _InitOCStruct(lpois); else if (GetWindowText(hwnd, szClsid, ARRAYSIZE(szClsid))) { OCHINITSTRUCT ois; ois.cbSize = SIZEOF(OCHINITSTRUCT); if (FAILED(SHCLSIDFromString(szClsid, &ois.clsidOC))) ois.clsidOC = CLSID_NULL; ois.punkOwner = NULL; hres = _InitOCStruct(&ois); } if (FAILED(hres)) return -1; return 0; } LRESULT COleControlHost::_OnDestroy() { ASSERT(_hwnd); SetWindowLongPtr(_hwnd, 0, 0); _ConnectEvents( _punkOC, FALSE ) ; _Deactivate(); _Exit(); Release(); return 0; } LRESULT COleControlHost::_OnQueryInterface(WPARAM wParam, LPARAM lParam) { if (lParam) { QIMSG * qiMsg = (QIMSG *)lParam; return _punkOC->QueryInterface(*qiMsg->qiid, qiMsg->ppvObject); } return -1; } LRESULT COleControlHost::_SetOwner(IUnknown * punkNewOwner) { if (_punkOwner) _punkOwner->Release(); _punkOwner = punkNewOwner; if (_punkOwner) _punkOwner->AddRef(); ATOMICRELEASE(_pIDocHostUIParent); ATOMICRELEASE(_pIDocHostUIParent2); // Query if owner supports IDocHostUIHandler, if so then // we turn on our delegating wrapper if (punkNewOwner) { punkNewOwner->QueryInterface(IID_IDocHostUIHandler, (LPVOID *)&_pIDocHostUIParent); punkNewOwner->QueryInterface(IID_IDocHostUIHandler2, (LPVOID *)&_pIDocHostUIParent2); } return 0; } LRESULT COleControlHost::_ConnectEvents( LPUNKNOWN punkOC, BOOL bConnect ) { if( bConnect ) { ASSERT( punkOC ) ; return _eventSink.Connect( _hwndParent, _hwnd, punkOC ) ; } return _eventSink.Disconnect() ; } LRESULT COleControlHost::_SetServiceProvider(IServiceProvider* pSP) { // Free any existing delegates if (_pdispSiteDelegate) { _pdispSiteDelegate->Release(); } // For now, we just delegate IDispatch (Ambient properties) calls HRESULT hr = pSP->QueryService(SID_OleControlSite, IID_PPV_ARG(IDispatch, &_pdispSiteDelegate)); if (FAILED(hr)) { _pdispSiteDelegate = NULL; } return 0; } LRESULT COleControlHost::_SendNotify(UINT code, LPNMHDR pnmhdr) { NMHDR nmhdr; ASSERT(_hwnd); if (!_hwndParent) return 0; if (!pnmhdr) pnmhdr = &nmhdr; pnmhdr->hwndFrom = _hwnd; pnmhdr->idFrom = GetDlgCtrlID( _hwnd ) ; pnmhdr->code = code; return SendMessage(_hwndParent, WM_NOTIFY, 0, (LPARAM)pnmhdr); } LRESULT CALLBACK COleControlHost::OCHostWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { COleControlHost *pcoch = (COleControlHost *)GetWindowPtr(hwnd, 0); if (!pcoch && (uMsg != WM_CREATE)) return DefWindowProcWrap(hwnd, uMsg, wParam, lParam); switch(uMsg) { case WM_CREATE: pcoch = new COleControlHost(hwnd); if (pcoch) return pcoch->_OnCreate(hwnd, (LPCREATESTRUCT)lParam); return -1; case WM_ERASEBKGND: if (pcoch->_punkOC && pcoch->_bInPlaceActive) { // Now tell windows we don't need no stinkin' // erased background because our view object // is in-place active and he/she will be // taking over from here. return TRUE; } break; case WM_PAINT: return pcoch->_OnPaint(); case WM_SIZE: return pcoch->_OnSize(hwnd, lParam); case WM_DESTROY: return pcoch->_OnDestroy(); case OCM_QUERYINTERFACE: return pcoch->_OnQueryInterface(wParam, lParam); case OCM_INITIALIZE: return pcoch->_InitOCStruct((LPOCHINITSTRUCT)lParam); case OCM_SETOWNER: return pcoch->_SetOwner((IUnknown*)lParam); case OCM_DOVERB: return pcoch->_DoVerb((long)wParam, (LPMSG)lParam); case OCM_ENABLEEVENTS: return pcoch->_ConnectEvents( pcoch->_punkOC, (BOOL)wParam ) ; case OCM_SETSERVICEPROVIDER: return pcoch->_SetServiceProvider((IServiceProvider*) lParam); case WM_PALETTECHANGED: if (pcoch->_pIOleIPObject) { HWND hwnd; if (SUCCEEDED(pcoch->_pIOleIPObject->GetWindow(&hwnd))) { SendMessage(hwnd, WM_PALETTECHANGED, wParam, lParam); } } break; case WM_SETFOCUS: // OC doesn't respond to OLEIVERB_UIACTIVATE ? if( pcoch->_dwMiscStatus & OLEMISC_NOUIACTIVATE ) { // so explicitly assign focus HWND hwndObj ; if( pcoch->_pIOleIPObject && SUCCEEDED( pcoch->_pIOleIPObject->GetWindow( &hwndObj ) ) ) SetFocus( hwndObj ) ; } else pcoch->_DoVerb( OLEIVERB_UIACTIVATE, NULL ) ; break ; default: return DefWindowProcWrap(hwnd, uMsg, wParam, lParam); } return 0; } void COleControlHost::_RegisterClass() { WNDCLASS wc = {0}; wc.style = CS_GLOBALCLASS; wc.lpfnWndProc = OCHostWndProc; //wc.cbClsExtra = 0; wc.cbWndExtra = SIZEOF(LPVOID); wc.hInstance = HINST_THISDLL; //wc.hIcon = NULL; wc.hCursor = LoadCursor (NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH) (COLOR_BACKGROUND + 1); //wc.lpszMenuName = NULL; wc.lpszClassName = OCHOST_CLASS; SHRegisterClass(&wc); } HRESULT CProxyUIHandler::QueryInterface(REFIID riid, LPVOID * ppvObj) { COleControlHost *poch = IToClass(COleControlHost, _xuih, this); return poch->QueryInterface(riid, ppvObj); }; ULONG CProxyUIHandler::AddRef(void) { COleControlHost *poch = IToClass(COleControlHost, _xuih, this); return poch->AddRef(); }; ULONG CProxyUIHandler::Release(void) { COleControlHost *poch = IToClass(COleControlHost, _xuih, this); return poch->Release(); }; HRESULT CProxyUIHandler::ShowContextMenu(DWORD dwID, POINT *ppt, IUnknown *pcmdtReserved, IDispatch *pdispReserved) { COleControlHost *poch = IToClass(COleControlHost, _xuih, this); return poch->_pIDocHostUIParent ? poch->_pIDocHostUIParent->ShowContextMenu(dwID, ppt, pcmdtReserved, pdispReserved) : E_NOTIMPL; } HRESULT CProxyUIHandler::GetHostInfo(DOCHOSTUIINFO *pInfo) { COleControlHost *poch = IToClass(COleControlHost, _xuih, this); return poch->_pIDocHostUIParent ? poch->_pIDocHostUIParent->GetHostInfo(pInfo) : E_NOTIMPL; } HRESULT CProxyUIHandler::ShowUI(DWORD dwID, IOleInPlaceActiveObject *pActiveObject, IOleCommandTarget *pCommandTarget, IOleInPlaceFrame *pFrame, IOleInPlaceUIWindow *pDoc) { COleControlHost *poch = IToClass(COleControlHost, _xuih, this); return poch->_pIDocHostUIParent ? poch->_pIDocHostUIParent->ShowUI(dwID, pActiveObject, pCommandTarget, pFrame, pDoc): E_NOTIMPL; } HRESULT CProxyUIHandler::HideUI() { COleControlHost *poch = IToClass(COleControlHost, _xuih, this); return poch->_pIDocHostUIParent ? poch->_pIDocHostUIParent->HideUI(): E_NOTIMPL; } HRESULT CProxyUIHandler::UpdateUI() { COleControlHost *poch = IToClass(COleControlHost, _xuih, this); return poch->_pIDocHostUIParent ? poch->_pIDocHostUIParent->UpdateUI(): E_NOTIMPL; } HRESULT CProxyUIHandler::EnableModeless(BOOL fActivate) { COleControlHost *poch = IToClass(COleControlHost, _xuih, this); return poch->_pIDocHostUIParent ? poch->_pIDocHostUIParent->EnableModeless(fActivate): E_NOTIMPL; } HRESULT CProxyUIHandler::OnDocWindowActivate(BOOL fActivate) { COleControlHost *poch = IToClass(COleControlHost, _xuih, this); return poch->_pIDocHostUIParent ? poch->_pIDocHostUIParent->OnDocWindowActivate(fActivate): E_NOTIMPL; } HRESULT CProxyUIHandler::OnFrameWindowActivate(BOOL fActivate) { COleControlHost *poch = IToClass(COleControlHost, _xuih, this); return poch->_pIDocHostUIParent ? poch->_pIDocHostUIParent->OnFrameWindowActivate(fActivate): E_NOTIMPL; } HRESULT CProxyUIHandler::ResizeBorder(LPCRECT prcBorder, IOleInPlaceUIWindow *pUIWindow, BOOL fRameWindow) { COleControlHost *poch = IToClass(COleControlHost, _xuih, this); return poch->_pIDocHostUIParent ? poch->_pIDocHostUIParent->ResizeBorder(prcBorder, pUIWindow, fRameWindow): E_NOTIMPL; } HRESULT CProxyUIHandler::TranslateAccelerator(LPMSG lpMsg, const GUID *pguidCmdGroup, DWORD nCmdID) { COleControlHost *poch = IToClass(COleControlHost, _xuih, this); return poch->_pIDocHostUIParent ? poch->_pIDocHostUIParent->TranslateAccelerator(lpMsg, pguidCmdGroup, nCmdID): E_NOTIMPL; } HRESULT CProxyUIHandler::GetOptionKeyPath(LPOLESTR *pchKey, DWORD dw) { COleControlHost *poch = IToClass(COleControlHost, _xuih, this); return poch->_pIDocHostUIParent ? poch->_pIDocHostUIParent->GetOptionKeyPath(pchKey, dw): E_NOTIMPL; } HRESULT CProxyUIHandler::GetDropTarget(IDropTarget *pDropTarget, IDropTarget **ppDropTarget) { COleControlHost *poch = IToClass(COleControlHost, _xuih, this); return poch->_pIDocHostUIParent ? poch->_pIDocHostUIParent->GetDropTarget(pDropTarget, ppDropTarget) : E_NOTIMPL; } HRESULT CProxyUIHandler::GetExternal(IDispatch **ppDispatch) { COleControlHost *poch = IToClass(COleControlHost, _xuih, this); return poch->_pIDocHostUIParent ? poch->_pIDocHostUIParent->GetExternal(ppDispatch) : E_NOTIMPL; } HRESULT CProxyUIHandler::TranslateUrl(DWORD dwTranslate, OLECHAR *pchURLIn, OLECHAR **ppchURLOut) { COleControlHost *poch = IToClass(COleControlHost, _xuih, this); return poch->_pIDocHostUIParent ? poch->_pIDocHostUIParent->TranslateUrl(dwTranslate, pchURLIn, ppchURLOut) : E_NOTIMPL; } HRESULT CProxyUIHandler::FilterDataObject( IDataObject *pDO, IDataObject **ppDORet) { COleControlHost *poch = IToClass(COleControlHost, _xuih, this); return poch->_pIDocHostUIParent ? poch->_pIDocHostUIParent->FilterDataObject(pDO, ppDORet) : E_NOTIMPL; } HRESULT CProxyUIHandler::GetOverrideKeyPath( LPOLESTR *pchKey, DWORD dw) { COleControlHost *poch = IToClass(COleControlHost, _xuih, this); return poch->_pIDocHostUIParent2 ? poch->_pIDocHostUIParent2->GetOverrideKeyPath(pchKey, dw) : E_NOTIMPL; } STDAPI_(BOOL) DllRegisterWindowClasses(const SHDRC * pshdrc) { if (pshdrc && pshdrc->cbSize == SIZEOF(SHDRC) && !(pshdrc->dwFlags & ~SHDRCF_ALL)) { if (pshdrc->dwFlags & SHDRCF_OCHOST) { COleControlHost::_RegisterClass(); return TRUE; } } return FALSE; } //--------------------------------------------------------------------------- // CEventSink constructor CEventSink::CEventSink( BOOL bAutoDelete ) : _hwndSite(NULL), _hwndOwner(NULL), _punkOC(NULL), _dwCookie(0), _cRef(1), _bAutoDelete( bAutoDelete ) { _iid = _iidDefault = IID_NULL ; } // CEventSink IUnknown impl STDMETHODIMP CEventSink::QueryInterface( REFIID riid, void** ppvObj ) { *ppvObj = NULL ; if( IsEqualGUID( riid, IID_IUnknown ) || IsEqualGUID( riid, IID_IDispatch )|| IsEqualGUID( riid, _iidDefault ) ) { *ppvObj = this ; return S_OK ; } return E_NOINTERFACE ; } STDMETHODIMP_(ULONG) CEventSink::AddRef() { return InterlockedIncrement( &_cRef ) ; } STDMETHODIMP_(ULONG) CEventSink::Release() { if( InterlockedDecrement( &_cRef ) <= 0 ) { if( _bAutoDelete ) delete this ; return 0 ; } return _cRef ; } // Connects the sink to the OC's default event dispatch interface. BOOL CEventSink::Connect( HWND hwndOwner, HWND hwndSite, LPUNKNOWN punkOC ) { ASSERT( punkOC ) ; IID iidDefault = IID_NULL ; if( SUCCEEDED( _GetDefaultEventIID( punkOC, &iidDefault ) ) ) { _iidDefault = iidDefault ; return _Connect( hwndOwner, hwndSite, punkOC, iidDefault ) ; } return FALSE ; } // Establishes advise connection on the specified interface BOOL CEventSink::_Connect( HWND hwndOwner, HWND hwndSite, LPUNKNOWN punkOC, REFIID iid ) { LPCONNECTIONPOINTCONTAINER pcpc; ASSERT(punkOC != NULL) ; HRESULT hr = CONNECT_E_CANNOTCONNECT ; if( _IsConnected( iid ) ) return TRUE ; if( _dwCookie ) Disconnect() ; if( punkOC && SUCCEEDED( punkOC->QueryInterface(IID_IConnectionPointContainer, (LPVOID*)&pcpc ))) { LPCONNECTIONPOINT pcp = NULL; DWORD dwCookie = 0; ASSERT(pcpc != NULL); if( SUCCEEDED(pcpc->FindConnectionPoint( iid, &pcp ))) { ASSERT(pcp != NULL); hr = pcp->Advise( this, &dwCookie ) ; if( SUCCEEDED( hr ) ) { _iid = iid ; _dwCookie = dwCookie ; _hwndOwner = hwndOwner ; _hwndSite = hwndSite ; _punkOC = punkOC ; _punkOC->AddRef() ; } pcp->Release(); } pcpc->Release(); } return SUCCEEDED( hr ) ; } // Retrieves default event dispatch interface from the OC. HRESULT CEventSink::_GetDefaultEventIID( LPUNKNOWN punkOC, IID* piid ) { HRESULT hr ; ASSERT( punkOC ) ; ASSERT( piid ) ; IProvideClassInfo *pci ; IProvideClassInfo2 *pci2 ; *piid = IID_NULL ; #define IMPLTYPE_MASK \ (IMPLTYPEFLAG_FDEFAULT|IMPLTYPEFLAG_FSOURCE|IMPLTYPEFLAG_FRESTRICTED) #define IMPLTYPE_DEFAULTSOURCE \ (IMPLTYPEFLAG_FDEFAULT|IMPLTYPEFLAG_FSOURCE) // Retrieve default outbound dispatch IID using OC's IProvideClassInfo2 if( SUCCEEDED( (hr = punkOC->QueryInterface( IID_IProvideClassInfo2, (void**)&pci2 )) ) ) { hr = pci2->GetGUID( GUIDKIND_DEFAULT_SOURCE_DISP_IID, piid ) ; pci2->Release() ; } else // no IProvideClassInfo2; try IProvideClassInfo: if( SUCCEEDED( (hr = punkOC->QueryInterface( IID_IProvideClassInfo, (void**)&pci )) ) ) { ITypeInfo* pClassInfo = NULL; if( SUCCEEDED( (hr = pci->GetClassInfo( &pClassInfo )) ) ) { LPTYPEATTR pClassAttr; ASSERT( pClassInfo ); if( SUCCEEDED( (hr = pClassInfo->GetTypeAttr( &pClassAttr )) ) ) { ASSERT( pClassAttr ) ; ASSERT( pClassAttr->typekind == TKIND_COCLASS ) ; // Enumerate implemented interfaces looking for default source IID. HREFTYPE hRefType; int nFlags; for( UINT i = 0; i < pClassAttr->cImplTypes; i++ ) { if( SUCCEEDED( (hr = pClassInfo->GetImplTypeFlags( i, &nFlags )) ) && ((nFlags & IMPLTYPE_MASK) == IMPLTYPE_DEFAULTSOURCE) ) { // Got the interface, now retrieve its IID: ITypeInfo* pEventInfo = NULL ; if( SUCCEEDED( (hr = pClassInfo->GetRefTypeOfImplType( i, &hRefType )) ) && SUCCEEDED( (hr = pClassInfo->GetRefTypeInfo( hRefType, &pEventInfo )) ) ) { LPTYPEATTR pEventAttr; ASSERT( pEventInfo ) ; if( SUCCEEDED( (hr = pEventInfo->GetTypeAttr( &pEventAttr )) ) ) { *piid = pEventAttr->guid ; pEventInfo->ReleaseTypeAttr(pEventAttr); } pEventInfo->Release(); } break; } } pClassInfo->ReleaseTypeAttr(pClassAttr); } pClassInfo->Release(); } pci->Release() ; } if( SUCCEEDED( hr ) && IsEqualIID( *piid, IID_NULL ) ) hr = E_FAIL ; return hr ; } // reports whether the sink is connected to the indicated sink BOOL CEventSink::_IsConnected( REFIID iid ) { return _dwCookie != 0L && IsEqualIID( iid, _iid ) ; } // disconnects the sink BOOL CEventSink::Disconnect() { LPCONNECTIONPOINTCONTAINER pcpc; if( _dwCookie != 0 && _punkOC && SUCCEEDED( _punkOC->QueryInterface(IID_IConnectionPointContainer, (LPVOID*)&pcpc))) { LPCONNECTIONPOINT pcp = NULL; ASSERT(pcpc != NULL); if (SUCCEEDED(pcpc->FindConnectionPoint(_iid, &pcp))) { ASSERT(pcp != NULL); pcp->Unadvise(_dwCookie); pcp->Release(); _iid = IID_NULL ; _dwCookie = 0L ; _hwndOwner = NULL ; _hwndSite = NULL ; _punkOC->Release() ; _punkOC = NULL ; } pcpc->Release(); return TRUE ; } return FALSE ; } // CEventSink IDispatch interface STDMETHODIMP CEventSink::Invoke( IN DISPID dispIdMember, IN REFIID riid, IN LCID lcid, IN WORD wFlags, IN OUT DISPPARAMS *pDispParams, OUT VARIANT *pVarResult, OUT EXCEPINFO *pExcepInfo, OUT UINT *puArgErr) { // Copy method args to notification block NMOCEVENT event ; ZeroMemory( &event, sizeof(event) ) ; event.hdr.hwndFrom = _hwndSite; event.hdr.idFrom = GetDlgCtrlID( _hwndSite ) ; event.hdr.code = OCN_OCEVENT ; event.dispID = dispIdMember ; event.iid = riid ; event.lcid = lcid ; event.wFlags = wFlags ; event.pDispParams = pDispParams ; event.pVarResult = pVarResult ; event.pExepInfo = pExcepInfo ; event.puArgErr = puArgErr ; // Notify parent of event ::SendMessage( _hwndOwner, WM_NOTIFY, event.hdr.idFrom, (LPARAM)&event ) ; // Cleanup args if (pVarResult != NULL) VariantClear( pVarResult ) ; return S_OK ; }