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

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