Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

335 lines
8.1 KiB

  1. #include "priv.h"
  2. class CMyHlinkSrc : public IHlinkSource
  3. {
  4. friend HRESULT CMyHlinkSrc_CreateInstance(REFCLSID rclsid, DWORD grfContext, REFIID riid, LPVOID* ppvOut);
  5. public:
  6. // *** IUnknown methods ***
  7. virtual STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj);
  8. virtual STDMETHODIMP_(ULONG) AddRef(void) ;
  9. virtual STDMETHODIMP_(ULONG) Release(void);
  10. // *** IHlinkSource methods ***
  11. virtual STDMETHODIMP SetBrowseContext(
  12. IHlinkBrowseContext *pihlbc);
  13. virtual STDMETHODIMP GetBrowseContext(
  14. IHlinkBrowseContext **ppihlbc);
  15. virtual STDMETHODIMP Navigate(
  16. DWORD grfHLNF,
  17. LPCWSTR pwzJumpLocation);
  18. virtual STDMETHODIMP GetMoniker(
  19. LPCWSTR pwzLocation,
  20. DWORD dwAssign,
  21. IMoniker **ppimkLocation);
  22. virtual STDMETHODIMP GetFriendlyName(
  23. LPCWSTR pwzLocation,
  24. LPWSTR *ppwzFriendlyName);
  25. protected:
  26. CMyHlinkSrc();
  27. ~CMyHlinkSrc();
  28. UINT _cRef;
  29. IUnknown* _punkInner; // aggregated inner object
  30. IHlinkSource* _phlsrc; // cached IHlinkSource
  31. IHlinkBrowseContext* _phlbc;
  32. };
  33. CMyHlinkSrc::CMyHlinkSrc() : _cRef(1), _punkInner(NULL), _phlsrc(NULL), _phlbc(NULL)
  34. {
  35. DllAddRef();
  36. }
  37. CMyHlinkSrc::~CMyHlinkSrc()
  38. {
  39. DllRelease();
  40. }
  41. //
  42. // This function returns an aggregated object
  43. //
  44. HRESULT CMyHlinkSrc_CreateInstance(REFCLSID rclsid, DWORD grfContext, REFIID riid, LPVOID* ppvOut)
  45. {
  46. HRESULT hres = E_OUTOFMEMORY;
  47. *ppvOut = NULL;
  48. CMyHlinkSrc* phlsrcOuter = new CMyHlinkSrc();
  49. if (phlsrcOuter)
  50. {
  51. hres = CoCreateInstance(rclsid, phlsrcOuter, grfContext, IID_IUnknown,
  52. (LPVOID*)&phlsrcOuter->_punkInner);
  53. if (SUCCEEDED(hres))
  54. {
  55. // TraceMsg(DM_TRACE, "sdv TR CMyHlinkSrc_CreateInstenace CoCreateSucceeded");
  56. // Cache IHlinkSource of the inner object (if any).
  57. HRESULT hresT = phlsrcOuter->_punkInner->QueryInterface(
  58. IID_IHlinkSource, (LPVOID*)&phlsrcOuter->_phlsrc);
  59. // TraceMsg(DM_TRACE, "sdv TR CMyHlinkSrc_CreateInstenace QI(IID_IHlinkSource) returned (%x)", hres);
  60. if (SUCCEEDED(hresT)) {
  61. //
  62. // Decrement the reference count to avoid cycled reference.
  63. // See "The COM Programmer's Cookbook for detail.
  64. //
  65. phlsrcOuter->Release();
  66. }
  67. hres = phlsrcOuter->QueryInterface(riid, ppvOut);
  68. }
  69. else
  70. {
  71. TraceMsg(DM_TRACE, "sdv TR CMyHlinkSrc_CreateInstenace CoCI failed (%x)", hres);
  72. }
  73. phlsrcOuter->Release();
  74. }
  75. // TraceMsg(DM_TRACE, "sdv TR CMyHlinkSrc_CreateInstenace leaving");
  76. return hres;
  77. }
  78. HRESULT CMyHlinkSrc::QueryInterface(REFIID riid, LPVOID * ppvObj)
  79. {
  80. if (IsEqualIID(riid, IID_IUnknown))
  81. {
  82. *ppvObj = (IUnknown*)this;
  83. _cRef++;
  84. return S_OK;
  85. }
  86. else if (IsEqualIID(riid, IID_IHlinkSource))
  87. {
  88. //
  89. // If the inner object supports IHlinkSource, return it;
  90. // otherwise, return our own.
  91. //
  92. TraceMsg(DM_TRACE, "sdv TR CMyHlinkSrc::QueryInterface IID_IHlinkSource called");
  93. *ppvObj = _phlsrc ? _phlsrc : (IHlinkSource*)this;
  94. _cRef++;
  95. return S_OK;
  96. }
  97. else if (_punkInner)
  98. {
  99. //
  100. // Delegate QI down to the inner object. This technique is
  101. // called "Blind QueryInterfcae" in the COM Programmer's Cookbook.
  102. // This book says, we shouldn't use this technique unless we modify
  103. // any behavior of other interfaces. In this case, we don't modify
  104. // any behavior and it's safe to use this technique.
  105. //
  106. // TraceMsg(DM_TRACE, "sdv TR CMyHlinkSrc::QueryInterface delegating QI to inner object");
  107. return _punkInner->QueryInterface(riid, ppvObj);
  108. }
  109. *ppvObj = NULL;
  110. return E_NOINTERFACE;
  111. }
  112. ULONG CMyHlinkSrc::AddRef(void)
  113. {
  114. // TraceMsg(DM_TRACE, "sdv TR CMyHlinkSrc::AddRef new _cRef is %d", _cRef+1);
  115. return ++_cRef;
  116. }
  117. ULONG CMyHlinkSrc::Release(void)
  118. {
  119. if (--_cRef > 0) {
  120. // TraceMsg(DM_TRACE, "sdv TR CMyHlinkSrc::Release new _cRef is %d", _cRef);
  121. return _cRef;
  122. }
  123. TraceMsg(DM_TRACE, "sdv TR CMyHlinkSrc::Release deleting this object ----- (YES!)");
  124. if (_phlbc) {
  125. _phlbc->Release();
  126. }
  127. _cRef = 1; // guard (to be recursively hit this code)
  128. if (_phlsrc) {
  129. AddRef(); // balance the ref. count
  130. _phlsrc->Release(); // release the cached interface
  131. }
  132. if (_punkInner) {
  133. _punkInner->Release();
  134. }
  135. ASSERT(_cRef == 1);
  136. delete this;
  137. return 0;
  138. }
  139. // *** IHlinkSource methods ***
  140. HRESULT CMyHlinkSrc::SetBrowseContext(
  141. IHlinkBrowseContext *pihlbc)
  142. {
  143. if (_phlbc) {
  144. _phlbc->Release();
  145. }
  146. _phlbc = pihlbc;
  147. if (_phlbc) {
  148. _phlbc->AddRef();
  149. }
  150. return S_OK;
  151. }
  152. HRESULT CMyHlinkSrc::GetBrowseContext(
  153. IHlinkBrowseContext **ppihlbc)
  154. {
  155. *ppihlbc = _phlbc;
  156. if (_phlbc) {
  157. _phlbc->AddRef();
  158. }
  159. return S_OK;
  160. }
  161. HRESULT CMyHlinkSrc::Navigate(
  162. DWORD grfHLNF,
  163. LPCWSTR pwzJumpLocation)
  164. {
  165. IOleDocumentView* pmsov = NULL;
  166. HRESULT hres = _punkInner->QueryInterface(IID_IOleDocumentView, (LPVOID*)&pmsov);
  167. if (SUCCEEDED(hres)) {
  168. hres = pmsov->UIActivate(TRUE);
  169. TraceMsg(DM_TRACE, "sdv TR CHS::Navigate pmsov->UIActivate() returned %x", hres);
  170. if (SUCCEEDED(hres)) {
  171. // HlinkOnNavigate
  172. }
  173. pmsov->Release();
  174. } else {
  175. TraceMsg(DM_TRACE, "sdv TR CHS::Navigate _punkInner->QI(IID_Mso) failed");
  176. }
  177. return S_OK;
  178. }
  179. HRESULT CMyHlinkSrc::GetMoniker(
  180. LPCWSTR pwzLocation,
  181. DWORD dwAssign,
  182. IMoniker **ppimkLocation)
  183. {
  184. return E_NOTIMPL;
  185. }
  186. HRESULT CMyHlinkSrc::GetFriendlyName(
  187. LPCWSTR pwzLocation,
  188. LPWSTR *ppwzFriendlyName)
  189. {
  190. return E_NOTIMPL;
  191. }
  192. //
  193. // Almost identical copy of OleCreate, which allows us to pass
  194. // the punkOuter.
  195. //
  196. HRESULT CMyHlinkSrc_OleCreate(CLSID rclsid, REFIID riid, DWORD renderOpt,
  197. FORMATETC* pFormatEtc, IOleClientSite* pclient,
  198. IStorage* pstg, LPVOID* ppvOut)
  199. {
  200. HRESULT hres;
  201. *ppvOut = NULL; // assume error
  202. IUnknown* punk;
  203. hres = CMyHlinkSrc_CreateInstance(rclsid, CLSCTX_INPROC, IID_IUnknown, (LPVOID*)&punk);
  204. if (SUCCEEDED(hres))
  205. {
  206. // Artificial one-time loop, which allows us to easily
  207. // handle error cases by saying "if (FAILED(hres)) break;"
  208. do {
  209. // Call IPersistStorage::InitNew
  210. IPersistStorage* ppstg;
  211. hres = punk->QueryInterface(IID_IPersistStorage, (LPVOID*)&ppstg);
  212. if (FAILED(hres))
  213. break;
  214. hres = ppstg->InitNew(pstg);
  215. ppstg->Release();
  216. if (FAILED(hres))
  217. break;
  218. // Call IOleObject::SetClientSite
  219. IOleObject* pole;
  220. hres = punk->QueryInterface(IID_IOleObject, (LPVOID*)&pole);
  221. if (FAILED(hres))
  222. break;
  223. hres = pole->SetClientSite(pclient);
  224. pole->Release();
  225. if (FAILED(hres))
  226. break;
  227. hres = punk->QueryInterface(riid, ppvOut);
  228. } while (0);
  229. punk->Release();
  230. }
  231. return hres;
  232. }
  233. //
  234. // Almost identical copy of OleLoad, which allows us to pass
  235. // the punkOuter.
  236. //
  237. HRESULT CMyHlinkSrc_OleLoad(IStorage* pstg, REFIID riid,
  238. IOleClientSite* pclient, LPVOID* ppvOut)
  239. {
  240. // TraceMsg(DM_TRACE, "sdv TR CMyHlinkSrc_OleLoad called");
  241. HRESULT hres;
  242. *ppvOut = NULL; // assume error
  243. STATSTG statstg;
  244. hres = pstg->Stat(&statstg, STATFLAG_NONAME);
  245. if (SUCCEEDED(hres))
  246. {
  247. IUnknown* punk;
  248. hres = CMyHlinkSrc_CreateInstance(statstg.clsid, CLSCTX_INPROC, IID_IUnknown, (LPVOID*)&punk);
  249. if (SUCCEEDED(hres))
  250. {
  251. // Artificial one-time loop, which allows us to easily
  252. // handle error cases by saying "if (FAILED(hres)) break;"
  253. do {
  254. // TraceMsg(DM_TRACE, "sdv TR CMyHlinkSrc_OladLoad calling IPS::Load");
  255. // Call IPersistStorage::Load
  256. IPersistStorage* ppstg;
  257. hres = punk->QueryInterface(IID_IPersistStorage, (LPVOID*)&ppstg);
  258. if (FAILED(hres))
  259. break;
  260. hres = ppstg->Load(pstg);
  261. ppstg->Release();
  262. if (FAILED(hres))
  263. break;
  264. // TraceMsg(DM_TRACE, "sdv TR CMyHlinkSrc_OladLoad calling IOO::SetClientSite");
  265. // Call IOleObject::SetClientSite
  266. IOleObject* pole;
  267. hres = punk->QueryInterface(IID_IOleObject, (LPVOID*)&pole);
  268. if (FAILED(hres))
  269. break;
  270. hres = pole->SetClientSite(pclient);
  271. pole->Release();
  272. if (FAILED(hres))
  273. break;
  274. // TraceMsg(DM_TRACE, "sdv TR CMyHlinkSrc_OladLoad calling IUnk::QI");
  275. hres = punk->QueryInterface(riid, ppvOut);
  276. } while (0);
  277. punk->Release();
  278. }
  279. }
  280. // TraceMsg(DM_TRACE, "sdv TR CMyHlinkSrc_OleLoad is leaving");
  281. return hres;
  282. }