1629 lines
46 KiB
C++
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 ;
|
|
}
|