windows-nt/Source/XPSP1/NT/shell/shdocvw/occtrl.cpp
2020-09-26 16:20:57 +08:00

1629 lines
46 KiB
C++

//---------------------------------------------------------------------------
//
// 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 ;
}