336 lines
8.1 KiB
C++
336 lines
8.1 KiB
C++
|
#include "priv.h"
|
||
|
|
||
|
|
||
|
class CMyHlinkSrc : public IHlinkSource
|
||
|
{
|
||
|
friend HRESULT CMyHlinkSrc_CreateInstance(REFCLSID rclsid, DWORD grfContext, REFIID riid, LPVOID* ppvOut);
|
||
|
public:
|
||
|
// *** IUnknown methods ***
|
||
|
virtual STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj);
|
||
|
virtual STDMETHODIMP_(ULONG) AddRef(void) ;
|
||
|
virtual STDMETHODIMP_(ULONG) Release(void);
|
||
|
|
||
|
// *** IHlinkSource methods ***
|
||
|
virtual STDMETHODIMP SetBrowseContext(
|
||
|
IHlinkBrowseContext *pihlbc);
|
||
|
|
||
|
virtual STDMETHODIMP GetBrowseContext(
|
||
|
IHlinkBrowseContext **ppihlbc);
|
||
|
|
||
|
virtual STDMETHODIMP Navigate(
|
||
|
DWORD grfHLNF,
|
||
|
LPCWSTR pwzJumpLocation);
|
||
|
|
||
|
virtual STDMETHODIMP GetMoniker(
|
||
|
LPCWSTR pwzLocation,
|
||
|
DWORD dwAssign,
|
||
|
IMoniker **ppimkLocation);
|
||
|
|
||
|
virtual STDMETHODIMP GetFriendlyName(
|
||
|
LPCWSTR pwzLocation,
|
||
|
LPWSTR *ppwzFriendlyName);
|
||
|
|
||
|
protected:
|
||
|
CMyHlinkSrc();
|
||
|
~CMyHlinkSrc();
|
||
|
|
||
|
UINT _cRef;
|
||
|
IUnknown* _punkInner; // aggregated inner object
|
||
|
IHlinkSource* _phlsrc; // cached IHlinkSource
|
||
|
IHlinkBrowseContext* _phlbc;
|
||
|
};
|
||
|
|
||
|
CMyHlinkSrc::CMyHlinkSrc() : _cRef(1), _punkInner(NULL), _phlsrc(NULL), _phlbc(NULL)
|
||
|
{
|
||
|
DllAddRef();
|
||
|
}
|
||
|
|
||
|
CMyHlinkSrc::~CMyHlinkSrc()
|
||
|
{
|
||
|
DllRelease();
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// This function returns an aggregated object
|
||
|
//
|
||
|
HRESULT CMyHlinkSrc_CreateInstance(REFCLSID rclsid, DWORD grfContext, REFIID riid, LPVOID* ppvOut)
|
||
|
{
|
||
|
HRESULT hres = E_OUTOFMEMORY;
|
||
|
*ppvOut = NULL;
|
||
|
|
||
|
CMyHlinkSrc* phlsrcOuter = new CMyHlinkSrc();
|
||
|
if (phlsrcOuter)
|
||
|
{
|
||
|
|
||
|
hres = CoCreateInstance(rclsid, phlsrcOuter, grfContext, IID_IUnknown,
|
||
|
(LPVOID*)&phlsrcOuter->_punkInner);
|
||
|
if (SUCCEEDED(hres))
|
||
|
{
|
||
|
// TraceMsg(DM_TRACE, "sdv TR CMyHlinkSrc_CreateInstenace CoCreateSucceeded");
|
||
|
// Cache IHlinkSource of the inner object (if any).
|
||
|
HRESULT hresT = phlsrcOuter->_punkInner->QueryInterface(
|
||
|
IID_IHlinkSource, (LPVOID*)&phlsrcOuter->_phlsrc);
|
||
|
// TraceMsg(DM_TRACE, "sdv TR CMyHlinkSrc_CreateInstenace QI(IID_IHlinkSource) returned (%x)", hres);
|
||
|
if (SUCCEEDED(hresT)) {
|
||
|
//
|
||
|
// Decrement the reference count to avoid cycled reference.
|
||
|
// See "The COM Programmer's Cookbook for detail.
|
||
|
//
|
||
|
phlsrcOuter->Release();
|
||
|
}
|
||
|
|
||
|
hres = phlsrcOuter->QueryInterface(riid, ppvOut);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceMsg(DM_TRACE, "sdv TR CMyHlinkSrc_CreateInstenace CoCI failed (%x)", hres);
|
||
|
}
|
||
|
|
||
|
phlsrcOuter->Release();
|
||
|
}
|
||
|
|
||
|
// TraceMsg(DM_TRACE, "sdv TR CMyHlinkSrc_CreateInstenace leaving");
|
||
|
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
HRESULT CMyHlinkSrc::QueryInterface(REFIID riid, LPVOID * ppvObj)
|
||
|
{
|
||
|
if (IsEqualIID(riid, IID_IUnknown))
|
||
|
{
|
||
|
*ppvObj = (IUnknown*)this;
|
||
|
_cRef++;
|
||
|
return S_OK;
|
||
|
}
|
||
|
else if (IsEqualIID(riid, IID_IHlinkSource))
|
||
|
{
|
||
|
//
|
||
|
// If the inner object supports IHlinkSource, return it;
|
||
|
// otherwise, return our own.
|
||
|
//
|
||
|
TraceMsg(DM_TRACE, "sdv TR CMyHlinkSrc::QueryInterface IID_IHlinkSource called");
|
||
|
*ppvObj = _phlsrc ? _phlsrc : (IHlinkSource*)this;
|
||
|
_cRef++;
|
||
|
return S_OK;
|
||
|
}
|
||
|
else if (_punkInner)
|
||
|
{
|
||
|
//
|
||
|
// Delegate QI down to the inner object. This technique is
|
||
|
// called "Blind QueryInterfcae" in the COM Programmer's Cookbook.
|
||
|
// This book says, we shouldn't use this technique unless we modify
|
||
|
// any behavior of other interfaces. In this case, we don't modify
|
||
|
// any behavior and it's safe to use this technique.
|
||
|
//
|
||
|
// TraceMsg(DM_TRACE, "sdv TR CMyHlinkSrc::QueryInterface delegating QI to inner object");
|
||
|
return _punkInner->QueryInterface(riid, ppvObj);
|
||
|
}
|
||
|
|
||
|
*ppvObj = NULL;
|
||
|
return E_NOINTERFACE;
|
||
|
}
|
||
|
|
||
|
ULONG CMyHlinkSrc::AddRef(void)
|
||
|
{
|
||
|
// TraceMsg(DM_TRACE, "sdv TR CMyHlinkSrc::AddRef new _cRef is %d", _cRef+1);
|
||
|
return ++_cRef;
|
||
|
}
|
||
|
|
||
|
ULONG CMyHlinkSrc::Release(void)
|
||
|
{
|
||
|
if (--_cRef > 0) {
|
||
|
// TraceMsg(DM_TRACE, "sdv TR CMyHlinkSrc::Release new _cRef is %d", _cRef);
|
||
|
return _cRef;
|
||
|
}
|
||
|
|
||
|
TraceMsg(DM_TRACE, "sdv TR CMyHlinkSrc::Release deleting this object ----- (YES!)");
|
||
|
|
||
|
if (_phlbc) {
|
||
|
_phlbc->Release();
|
||
|
}
|
||
|
|
||
|
_cRef = 1; // guard (to be recursively hit this code)
|
||
|
if (_phlsrc) {
|
||
|
AddRef(); // balance the ref. count
|
||
|
_phlsrc->Release(); // release the cached interface
|
||
|
}
|
||
|
|
||
|
if (_punkInner) {
|
||
|
_punkInner->Release();
|
||
|
}
|
||
|
|
||
|
ASSERT(_cRef == 1);
|
||
|
delete this;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// *** IHlinkSource methods ***
|
||
|
HRESULT CMyHlinkSrc::SetBrowseContext(
|
||
|
IHlinkBrowseContext *pihlbc)
|
||
|
{
|
||
|
if (_phlbc) {
|
||
|
_phlbc->Release();
|
||
|
}
|
||
|
|
||
|
_phlbc = pihlbc;
|
||
|
if (_phlbc) {
|
||
|
_phlbc->AddRef();
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT CMyHlinkSrc::GetBrowseContext(
|
||
|
IHlinkBrowseContext **ppihlbc)
|
||
|
{
|
||
|
*ppihlbc = _phlbc;
|
||
|
|
||
|
if (_phlbc) {
|
||
|
_phlbc->AddRef();
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT CMyHlinkSrc::Navigate(
|
||
|
DWORD grfHLNF,
|
||
|
LPCWSTR pwzJumpLocation)
|
||
|
{
|
||
|
IOleDocumentView* pmsov = NULL;
|
||
|
HRESULT hres = _punkInner->QueryInterface(IID_IOleDocumentView, (LPVOID*)&pmsov);
|
||
|
if (SUCCEEDED(hres)) {
|
||
|
hres = pmsov->UIActivate(TRUE);
|
||
|
TraceMsg(DM_TRACE, "sdv TR CHS::Navigate pmsov->UIActivate() returned %x", hres);
|
||
|
if (SUCCEEDED(hres)) {
|
||
|
// HlinkOnNavigate
|
||
|
}
|
||
|
pmsov->Release();
|
||
|
} else {
|
||
|
TraceMsg(DM_TRACE, "sdv TR CHS::Navigate _punkInner->QI(IID_Mso) failed");
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT CMyHlinkSrc::GetMoniker(
|
||
|
LPCWSTR pwzLocation,
|
||
|
DWORD dwAssign,
|
||
|
IMoniker **ppimkLocation)
|
||
|
{
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
HRESULT CMyHlinkSrc::GetFriendlyName(
|
||
|
LPCWSTR pwzLocation,
|
||
|
LPWSTR *ppwzFriendlyName)
|
||
|
{
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Almost identical copy of OleCreate, which allows us to pass
|
||
|
// the punkOuter.
|
||
|
//
|
||
|
HRESULT CMyHlinkSrc_OleCreate(CLSID rclsid, REFIID riid, DWORD renderOpt,
|
||
|
FORMATETC* pFormatEtc, IOleClientSite* pclient,
|
||
|
IStorage* pstg, LPVOID* ppvOut)
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
*ppvOut = NULL; // assume error
|
||
|
|
||
|
IUnknown* punk;
|
||
|
hres = CMyHlinkSrc_CreateInstance(rclsid, CLSCTX_INPROC, IID_IUnknown, (LPVOID*)&punk);
|
||
|
if (SUCCEEDED(hres))
|
||
|
{
|
||
|
// Artificial one-time loop, which allows us to easily
|
||
|
// handle error cases by saying "if (FAILED(hres)) break;"
|
||
|
do {
|
||
|
// Call IPersistStorage::InitNew
|
||
|
IPersistStorage* ppstg;
|
||
|
hres = punk->QueryInterface(IID_IPersistStorage, (LPVOID*)&ppstg);
|
||
|
if (FAILED(hres))
|
||
|
break;
|
||
|
hres = ppstg->InitNew(pstg);
|
||
|
ppstg->Release();
|
||
|
if (FAILED(hres))
|
||
|
break;
|
||
|
|
||
|
// Call IOleObject::SetClientSite
|
||
|
IOleObject* pole;
|
||
|
hres = punk->QueryInterface(IID_IOleObject, (LPVOID*)&pole);
|
||
|
if (FAILED(hres))
|
||
|
break;
|
||
|
hres = pole->SetClientSite(pclient);
|
||
|
pole->Release();
|
||
|
if (FAILED(hres))
|
||
|
break;
|
||
|
|
||
|
hres = punk->QueryInterface(riid, ppvOut);
|
||
|
} while (0);
|
||
|
|
||
|
punk->Release();
|
||
|
}
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Almost identical copy of OleLoad, which allows us to pass
|
||
|
// the punkOuter.
|
||
|
//
|
||
|
HRESULT CMyHlinkSrc_OleLoad(IStorage* pstg, REFIID riid,
|
||
|
IOleClientSite* pclient, LPVOID* ppvOut)
|
||
|
{
|
||
|
// TraceMsg(DM_TRACE, "sdv TR CMyHlinkSrc_OleLoad called");
|
||
|
|
||
|
HRESULT hres;
|
||
|
*ppvOut = NULL; // assume error
|
||
|
|
||
|
STATSTG statstg;
|
||
|
hres = pstg->Stat(&statstg, STATFLAG_NONAME);
|
||
|
if (SUCCEEDED(hres))
|
||
|
{
|
||
|
IUnknown* punk;
|
||
|
hres = CMyHlinkSrc_CreateInstance(statstg.clsid, CLSCTX_INPROC, IID_IUnknown, (LPVOID*)&punk);
|
||
|
if (SUCCEEDED(hres))
|
||
|
{
|
||
|
// Artificial one-time loop, which allows us to easily
|
||
|
// handle error cases by saying "if (FAILED(hres)) break;"
|
||
|
do {
|
||
|
// TraceMsg(DM_TRACE, "sdv TR CMyHlinkSrc_OladLoad calling IPS::Load");
|
||
|
// Call IPersistStorage::Load
|
||
|
IPersistStorage* ppstg;
|
||
|
hres = punk->QueryInterface(IID_IPersistStorage, (LPVOID*)&ppstg);
|
||
|
if (FAILED(hres))
|
||
|
break;
|
||
|
hres = ppstg->Load(pstg);
|
||
|
ppstg->Release();
|
||
|
if (FAILED(hres))
|
||
|
break;
|
||
|
|
||
|
// TraceMsg(DM_TRACE, "sdv TR CMyHlinkSrc_OladLoad calling IOO::SetClientSite");
|
||
|
// Call IOleObject::SetClientSite
|
||
|
IOleObject* pole;
|
||
|
hres = punk->QueryInterface(IID_IOleObject, (LPVOID*)&pole);
|
||
|
if (FAILED(hres))
|
||
|
break;
|
||
|
hres = pole->SetClientSite(pclient);
|
||
|
pole->Release();
|
||
|
if (FAILED(hres))
|
||
|
break;
|
||
|
|
||
|
// TraceMsg(DM_TRACE, "sdv TR CMyHlinkSrc_OladLoad calling IUnk::QI");
|
||
|
hres = punk->QueryInterface(riid, ppvOut);
|
||
|
} while (0);
|
||
|
|
||
|
punk->Release();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// TraceMsg(DM_TRACE, "sdv TR CMyHlinkSrc_OleLoad is leaving");
|
||
|
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
|
||
|
|