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.

677 lines
20 KiB

  1. #if !defined(_FUSION_INC_FUSIONCOM_H_INCLUDED_)
  2. #define _FUSION_INC_FUSIONCOM_H_INCLUDED_
  3. #pragma once
  4. #include <stddef.h>
  5. #include <guiddef.h>
  6. #include <basetsd.h>
  7. #include "smartref.h"
  8. //
  9. // The basic design for this COM support is lifted from ATL.
  10. //
  11. // ATL's implementation is much more complicated because it tries to
  12. // support all the sorts of COM objects there may be. Perhaps over
  13. // time this COM base stuff will extend as much and we may wish we
  14. // just used ATL, but for now people feel that ATL is overkill, so
  15. // rather than implement IUnknown::AddRef() and IUnknown::Release()
  16. // a thousand times, we'll at least have enough to have a single
  17. // common implementation.
  18. //
  19. // Turn off the warning about using a typedef name as if it were a class name.
  20. // We tend to do that a lot with CFusionCOMObjectBase (which is really just
  21. // a typedef for a much hairier name...)
  22. #pragma warning(disable: 4097) // use of typedef as class name
  23. #pragma warning(disable: 4505) // dead code warning
  24. // UNUSED macro with local unique name:
  25. #define FUSION_FUSIONCOM_UNUSED(x) (x)
  26. #define FUSION_COM_PACKING 8
  27. #pragma pack(push, FUSION_COM_PACKING)
  28. #define offsetofclass(base, derived) (reinterpret_cast<ULONG_PTR>(static_cast<base*>(reinterpret_cast<derived*>(FUSION_COM_PACKING)))-FUSION_COM_PACKING)
  29. struct CFusionCOMInterfaceMapEntry
  30. {
  31. const IID *piid;
  32. DWORD_PTR dwOffset;
  33. enum
  34. {
  35. eSimpleMapEntry,
  36. eDelegate,
  37. eEndOfMap,
  38. } eType;
  39. };
  40. class CFusionCOMCriticalSectionSynchronization
  41. {
  42. public:
  43. CFusionCOMCriticalSectionSynchronization() : m_fInitialized(false) { }
  44. ~CFusionCOMCriticalSectionSynchronization() { m_fInitialized = false; }
  45. static ULONG Increment(ULONG &rul) { return ::InterlockedIncrement((LONG *) &rul); }
  46. static ULONG Decrement(ULONG &rul) { return ::InterlockedDecrement((LONG *) &rul); }
  47. HRESULT Initialize(DWORD dwSpinCount = (0x80000000 | 4000))
  48. {
  49. HRESULT hr = NOERROR;
  50. ASSERT(!m_fInitialized);
  51. if (m_fInitialized)
  52. {
  53. hr = E_UNEXPECTED;
  54. goto Exit;
  55. }
  56. if (!::InitializeCriticalSectionAndSpinCount(&m_cs, dwSpinCount))
  57. {
  58. hr = HRESULT_FROM_WIN32(::GetLastError());
  59. goto Exit;
  60. }
  61. m_fInitialized = true;
  62. hr = NOERROR;
  63. Exit:
  64. return hr;
  65. }
  66. HRESULT Lock()
  67. {
  68. HRESULT hr = NOERROR;
  69. ASSERT(m_fInitialized);
  70. if (!m_fInitialized)
  71. {
  72. hr = E_UNEXPECTED;
  73. goto Exit;
  74. }
  75. ::EnterCriticalSection(&m_cs);
  76. hr = NOERROR;
  77. Exit:
  78. return hr;
  79. }
  80. HRESULT Unlock()
  81. {
  82. HRESULT hr = NOERROR;
  83. ASSERT(m_fInitialized);
  84. if (!m_fInitialized)
  85. {
  86. hr = E_UNEXPECTED;
  87. goto Exit;
  88. }
  89. ::LeaveCriticalSection(&m_cs);
  90. hr = NOERROR;
  91. Exit:
  92. return hr;
  93. }
  94. HRESULT TryLock(bool &rfLocked)
  95. {
  96. HRESULT hr = NOERROR;
  97. ASSERT(m_fInitialized);
  98. if (!m_fInitialized)
  99. {
  100. hr = E_UNEXPECTED;
  101. goto Exit;
  102. }
  103. rfLocked = (::TryEnterCriticalSection(&m_cs) != 0);
  104. hr = NOERROR;
  105. Exit:
  106. return hr;
  107. }
  108. private:
  109. CRITICAL_SECTION m_cs;
  110. bool m_fInitialized;
  111. };
  112. class CFusionCOMNullSynchronization
  113. {
  114. public:
  115. CFusionCOMNullSynchronization() : m_fInitialized(false) { }
  116. ~CFusionCOMNullSynchronization() { m_fInitialized = false; }
  117. static ULONG Increment(ULONG &rul) { return ++rul; }
  118. static ULONG Decrement(ULONG &rul) { return --rul; }
  119. HRESULT Initialize()
  120. {
  121. HRESULT hr = NOERROR;
  122. ASSERT(!m_fInitialized);
  123. if (m_fInitialized)
  124. {
  125. hr = E_UNEXPECTED;
  126. goto Exit;
  127. }
  128. m_fInitialized = true;
  129. hr = NOERROR;
  130. Exit:
  131. return hr;
  132. }
  133. HRESULT Lock()
  134. {
  135. HRESULT hr = NOERROR;
  136. ASSERT(m_fInitialized);
  137. if (!m_fInitialized)
  138. {
  139. hr = E_UNEXPECTED;
  140. goto Exit;
  141. }
  142. hr = NOERROR;
  143. Exit:
  144. return hr;
  145. }
  146. HRESULT Unlock()
  147. {
  148. HRESULT hr = NOERROR;
  149. ASSERT(m_fInitialized);
  150. if (!m_fInitialized)
  151. {
  152. hr = E_UNEXPECTED;
  153. goto Exit;
  154. }
  155. hr = NOERROR;
  156. Exit:
  157. return hr;
  158. }
  159. HRESULT TryLock(bool &rfLocked)
  160. {
  161. HRESULT hr = NOERROR;
  162. ASSERT(m_fInitialized);
  163. if (!m_fInitialized)
  164. {
  165. hr = E_UNEXPECTED;
  166. goto Exit;
  167. }
  168. rfLocked = true;
  169. hr = NOERROR;
  170. Exit:
  171. return hr;
  172. }
  173. private:
  174. bool m_fInitialized;
  175. };
  176. template <typename TSynch = CFusionCOMCriticalSectionSynchronization> class __declspec(novtable) CFusionCOMObjectBaseEx : public IUnknown
  177. {
  178. protected:
  179. CFusionCOMObjectBaseEx() : m_cRef(0), m_fInFinalRelease(false), m_fFusionCOMObjectBaseExInitialized(false) { }
  180. virtual ~CFusionCOMObjectBaseEx() { ASSERT(m_cRef == 0); }
  181. ULONG _InternalAddRef()
  182. {
  183. // You really shouldn't be causing new references on this object after its ref
  184. // count has dropped to zero...
  185. ASSERT(!m_fInFinalRelease);
  186. // You shouldn't be adding refs to this object prior to calling the base class's
  187. // Initialize() function.
  188. ASSERT(m_fFusionCOMObjectBaseExInitialized);
  189. return TSynch::Increment(m_cRef);
  190. }
  191. ULONG _InternalRelease()
  192. {
  193. // You really shouldn't be causing new references on this object after its ref
  194. // count has dropped to zero...
  195. ASSERT(!m_fInFinalRelease);
  196. // You shouldn't be adding (or removing) refs to this object prior to calling the base class's
  197. // Initialize() function.
  198. ASSERT(m_fFusionCOMObjectBaseExInitialized);
  199. return TSynch::Decrement(m_cRef);
  200. }
  201. VOID OnFinalRelease() { m_srpIUnknown_FTM.Release(); }
  202. // Derived classes must call this in order for the critical section/mutex/whatever
  203. // to be initialized.
  204. HRESULT Initialize(bool fCreateFTM = true)
  205. {
  206. HRESULT hr = NOERROR;
  207. ASSERT(!m_fFusionCOMObjectBaseExInitialized);
  208. if (m_fFusionCOMObjectBaseExInitialized)
  209. {
  210. hr = E_UNEXPECTED;
  211. goto Exit;
  212. }
  213. hr = m_SynchronizationObject.Initialize();
  214. if (FAILED(hr))
  215. goto Exit;
  216. if (fCreateFTM)
  217. {
  218. hr = ::CoCreateFreeThreadedMarshaler(this, &m_srpIUnknown_FTM);
  219. if (FAILED(hr))
  220. goto Exit;
  221. }
  222. m_fFusionCOMObjectBaseExInitialized = true;
  223. hr = NOERROR;
  224. Exit:
  225. return hr;
  226. }
  227. static HRESULT WINAPI InternalQueryInterface(
  228. void *pThis,
  229. const CFusionCOMInterfaceMapEntry* pEntries,
  230. REFIID riid,
  231. void **ppvObject)
  232. {
  233. HRESULT hr = NOERROR;
  234. IUnknown *pIUnknown = NULL;
  235. ASSERT(pThis != NULL);
  236. if (ppvObject != NULL)
  237. *ppvObject = NULL;
  238. if (ppvObject == NULL)
  239. {
  240. hr = E_POINTER;
  241. goto Exit;
  242. }
  243. while (pEntries->eType != CFusionCOMInterfaceMapEntry::eEndOfMap)
  244. {
  245. if ((pEntries->piid == NULL) || ((*(pEntries->piid)) == riid))
  246. {
  247. switch (pEntries->eType)
  248. {
  249. default:
  250. ASSERT(FALSE);
  251. hr = E_UNEXPECTED;
  252. goto Exit;
  253. case CFusionCOMInterfaceMapEntry::eDelegate:
  254. pIUnknown = *((IUnknown **) (((DWORD_PTR) pThis) + pEntries->dwOffset));
  255. if (pIUnknown != NULL)
  256. {
  257. hr = pIUnknown->QueryInterface(riid, ppvObject);
  258. if (FAILED(hr))
  259. goto Exit;
  260. }
  261. break;
  262. case CFusionCOMInterfaceMapEntry::eSimpleMapEntry:
  263. ASSERT(pEntries->eType == CFusionCOMInterfaceMapEntry::eSimpleMapEntry);
  264. pIUnknown = (IUnknown *) (((DWORD_PTR) pThis) + pEntries->dwOffset);
  265. pIUnknown->AddRef();
  266. *ppvObject = pIUnknown;
  267. break;
  268. }
  269. // If we did find a match, get out of here. (This may have been
  270. // a delegation entry that matched, but there was no delegatee in
  271. // the storage at pEntries->dwOffset, so we skipped it. This allows
  272. // a derived class to not create, for example, a free threaded marshaler
  273. // and have normal marshaling semantics.
  274. if (pIUnknown != NULL)
  275. break;
  276. }
  277. pEntries++;
  278. }
  279. if (pEntries->eType == CFusionCOMInterfaceMapEntry::eEndOfMap)
  280. {
  281. hr = E_NOINTERFACE;
  282. goto Exit;
  283. }
  284. hr = NOERROR;
  285. Exit:
  286. return hr;
  287. }
  288. ULONG m_cRef;
  289. TSynch m_SynchronizationObject;
  290. CSmartRef<IUnknown> m_srpIUnknown_FTM;
  291. bool m_fInFinalRelease;
  292. bool m_fFusionCOMObjectBaseExInitialized;
  293. };
  294. typedef CFusionCOMObjectBaseEx<CFusionCOMCriticalSectionSynchronization> CFusionCOMObjectBase;
  295. // Putting the entry macros before the begin/end map macros so that
  296. // we can use the entry macros in the begin/end map macros to
  297. // automatically add entries for IUnknown and IMarshal.
  298. #define FUSION_COM_INTERFACE_ENTRY(x) { &__uuidof(x), offsetofclass(x, _ComMapClass), CFusionCOMInterfaceMapEntry::eSimpleMapEntry },
  299. #define FUSION_COM_INTERFACE_ENTRY2(x, x2) { &__uuidof(x), (DWORD_PTR)((x*)(x2*)((_ComMapClass*)8))-8, CFusionCOMInterfaceMapEntry::eSimpleMapEntry },
  300. #define FUSION_COM_INTERFACE_ENTRY_IID(iid, x) { &(iid), offsetofclass(x, _ComMapClass), CFusionCOMInterfaceMapEntry::eSimpleMapEntry },
  301. #define FUSION_COM_INTERFACE_ENTRY_AGGREGATE(x, punk) \
  302. {&__uuidof(x),\
  303. offsetof(_ComMapClass, punk),\
  304. CFusionCOMInterfaceMapEntry::eDelegate },
  305. #define FUSION_BEGIN_COM_MAP_EX(x, basetype) \
  306. public: \
  307. virtual ULONG STDMETHODCALLTYPE AddRef(void) = 0; \
  308. virtual ULONG STDMETHODCALLTYPE Release(void) = 0; \
  309. virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, LPVOID *) = 0; \
  310. typedef x _ComMapClass; \
  311. HRESULT _InternalQueryInterface(REFIID riid, void** ppvObject) \
  312. { \
  313. return InternalQueryInterface(this, _GetEntries(), riid, ppvObject); \
  314. } \
  315. const static CFusionCOMInterfaceMapEntry * WINAPI _GetEntries() \
  316. { \
  317. static const CFusionCOMInterfaceMapEntry _entries[] = { \
  318. FUSION_COM_INTERFACE_ENTRY2(IUnknown, basetype)
  319. #define FUSION_BEGIN_COM_MAP(x) FUSION_BEGIN_COM_MAP_EX(x, CFusionCOMObjectBase)
  320. #define FUSION_END_COM_MAP() \
  321. FUSION_COM_INTERFACE_ENTRY_AGGREGATE(IMarshal, m_srpIUnknown_FTM.m_pt) \
  322. { NULL, 0, CFusionCOMInterfaceMapEntry::eEndOfMap} \
  323. }; \
  324. return _entries; \
  325. }
  326. template <typename TBase> class CFusionCOMObject : public TBase
  327. {
  328. public:
  329. CFusionCOMObject() { }
  330. virtual ~CFusionCOMObject() { }
  331. STDMETHODIMP_(ULONG) AddRef() { return this->_InternalAddRef(); }
  332. STDMETHODIMP_(ULONG) Release()
  333. {
  334. ULONG cRef = this->_InternalRelease();
  335. // If the ref count hits zero, but we were already in final release,
  336. // we know that the outer Release() will actually do the delete, so
  337. // we don't have to.
  338. if ((cRef == 0) && !m_fInFinalRelease)
  339. {
  340. m_fInFinalRelease = true;
  341. this->OnFinalRelease();
  342. // Make sure that the OnFinalRelease() didn't do something wacky
  343. // like increment the ref count...
  344. ASSERT(m_fInFinalRelease);
  345. ASSERT(m_cRef == 0);
  346. m_fInFinalRelease = false;
  347. delete this;
  348. }
  349. return cRef;
  350. }
  351. STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppv) { return this->_InternalQueryInterface(riid, ppv); }
  352. };
  353. //
  354. // Use CFusionAutoCOMObject<> to instantiate a CFusionCOMObject-derived instance
  355. // in automatic (e.g. stack) storage.
  356. //
  357. template <typename TBase> class CFusionAutoCOMObject : public TBase
  358. {
  359. public:
  360. CFusionAutoCOMObject() { }
  361. STDMETHODIMP_(ULONG) AddRef() { return this->_InternalAddRef(); }
  362. STDMETHODIMP_(ULONG) Release() { return this->_InternalRelease(); }
  363. STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppv) { return this->_InternalQueryInterface(riid, ppv); }
  364. typedef BOOL (CALLBACK * PUMPMESSAGESPROC)(LPVOID pvContext);
  365. BOOL WaitForZeroRefCount(DWORD dwMilliseconds, DWORD dwWakeMask, DWORD dwFlags, PUMPMESSAGESPROC lpMsgPump, LPVOID pvContext)
  366. {
  367. FUSION_FUSIONCOM_UNUSED(dwMilliseconds);
  368. // Anything other than dwMilliseconds == INFINITE is not implemented today...
  369. ASSERT(dwMilliseconds == INFINITE);
  370. ASSERT(dwFlags & MWMO_ALERTABLE);
  371. dwFlags |= MWMO_ALERTABLE;
  372. while (m_cRef != 0)
  373. {
  374. DWORD dwTemp = ::MsgWaitForMultipleObjectsEx(0, NULL, INFINITE, dwWakeMask, dwFlags);
  375. if (dwTemp == -1)
  376. return FALSE;
  377. if (m_cRef == 0)
  378. break;
  379. if (dwTemp == WAIT_OBJECT_0)
  380. {
  381. BOOL fSucceeded = (*lpMsgPump)(pvContext);
  382. if (!fSucceeded)
  383. return FALSE;
  384. }
  385. }
  386. return TRUE;
  387. }
  388. // Use WaitForZeroRefCount() prior to this
  389. virtual ~CFusionAutoCOMObject()
  390. {
  391. ASSERT(!m_fInFinalRelease);
  392. if (!m_fInFinalRelease)
  393. {
  394. m_fInFinalRelease = true;
  395. this->OnFinalRelease();
  396. m_fInFinalRelease = false;
  397. }
  398. ASSERT(m_cRef == 0);
  399. }
  400. };
  401. template <typename TEnumInterface, typename TItemInterface> class CFusionCOMIter
  402. {
  403. public:
  404. CFusionCOMIter() { }
  405. ~CFusionCOMIter() { }
  406. CFusionCOMIter(TEnumInterface *pTEnumInterface) { m_srpTEnumInterface = pTEnumInterface; }
  407. void operator =(TEnumInterface *pTEnumInterface) { m_srpTEnumInterface = pTEnumInterface; m_srpTItemInterface.Release(); }
  408. TEnumInterface **operator &() { return &m_srpTEnumInterface; }
  409. TItemInterface *operator ->() const { return m_srpTItemInterface; }
  410. operator TItemInterface *() const { return m_srpTItemInterface; }
  411. void Release() { m_srpTEnumInterface.Release(); m_srpTItemInterface.Release(); }
  412. bool EnumIsNull() const { return m_srpTEnumInterface == NULL; }
  413. HRESULT Reset()
  414. {
  415. HRESULT hr = NOERROR;
  416. if (m_srpTEnumInterface == NULL)
  417. {
  418. hr = E_UNEXPECTED;
  419. goto Exit;
  420. }
  421. hr = m_srpTEnumInterface->Reset();
  422. if (FAILED(hr))
  423. goto Exit;
  424. hr = m_srpTEnumInterface->Next(1, &m_srpTItemInterface, NULL);
  425. if (FAILED(hr))
  426. goto Exit;
  427. hr = NOERROR;
  428. Exit:
  429. return hr;
  430. }
  431. bool More() const { return (m_srpTItemInterface != NULL); }
  432. HRESULT Next()
  433. {
  434. HRESULT hr = NOERROR;
  435. if (m_srpTEnumInterface == NULL)
  436. {
  437. hr = E_UNEXPECTED;
  438. goto Exit;
  439. }
  440. hr = m_srpTEnumInterface->Next(1, &m_srpTItemInterface, NULL);
  441. if (FAILED(hr))
  442. goto Exit;
  443. hr = NOERROR;
  444. Exit:
  445. return hr;
  446. }
  447. protected:
  448. CSmartRef<TEnumInterface> m_srpTEnumInterface;
  449. CSmartRef<TItemInterface> m_srpTItemInterface;
  450. };
  451. template <class TInstance, class TInterface> class CFusionCOMObjectCreator : public CSmartRef<TInterface>
  452. {
  453. public:
  454. CFusionCOMObjectCreator() : m_ptinstance(NULL), m_fDeleteInstance(false) { }
  455. ~CFusionCOMObjectCreator() { if (m_fDeleteInstance) { CSxsPreserveLastError ple; delete m_ptinstance; ple.Restore(); } }
  456. HRESULT CreateInstance()
  457. {
  458. if (m_ptinstance != NULL) return E_UNEXPECTED;
  459. m_ptinstance = NEW(CFusionCOMObject<TInstance>);
  460. if (m_ptinstance == NULL) return E_OUTOFMEMORY;
  461. m_fDeleteInstance = true;
  462. HRESULT hr = m_ptinstance->Initialize();
  463. if (FAILED(hr)) return hr;
  464. hr = m_ptinstance->QueryInterface(__uuidof(TInterface), (LPVOID *) &m_pt);
  465. if (FAILED(hr)) return hr;
  466. m_fDeleteInstance = false;
  467. return NOERROR;
  468. }
  469. template <typename TArg1> HRESULT CreateInstanceWithArg(TArg1 arg1)
  470. {
  471. if (m_ptinstance != NULL) return E_UNEXPECTED;
  472. m_ptinstance = NEW(CFusionCOMObject<TInstance>);
  473. if (m_ptinstance == NULL) return E_OUTOFMEMORY;
  474. m_fDeleteInstance = true;
  475. HRESULT hr = m_ptinstance->Initialize(arg1);
  476. if (FAILED(hr)) return hr;
  477. hr = m_ptinstance->QueryInterface(__uuidof(TInterface), (LPVOID *) &m_pt);
  478. if (FAILED(hr)) return hr;
  479. m_fDeleteInstance = false;
  480. return NOERROR;
  481. }
  482. template <typename TArg1, typename TArg2> HRESULT CreateInstanceWith2Args(TArg1 arg1, TArg2 arg2)
  483. {
  484. if (m_ptinstance != NULL) return E_UNEXPECTED;
  485. m_ptinstance = NEW(CFusionCOMObject<TInstance>);
  486. if (m_ptinstance == NULL) return E_OUTOFMEMORY;
  487. m_fDeleteInstance = true;
  488. HRESULT hr = m_ptinstance->Initialize(arg1, arg2);
  489. if (FAILED(hr)) return hr;
  490. hr = m_ptinstance->QueryInterface(__uuidof(TInterface), (LPVOID *) &m_pt);
  491. if (FAILED(hr)) return hr;
  492. m_fDeleteInstance = false;
  493. return NOERROR;
  494. }
  495. template <typename TArg1, typename TArg2, typename TArg3> HRESULT CreateInstanceWith3Args(TArg1 arg1, TArg2 arg2, TArg3 arg3)
  496. {
  497. if (m_ptinstance != NULL) return E_UNEXPECTED;
  498. m_ptinstance = NEW(CFusionCOMObject<TInstance>);
  499. if (m_ptinstance == NULL) return E_OUTOFMEMORY;
  500. m_fDeleteInstance = true;
  501. HRESULT hr = m_ptinstance->Initialize(arg1, arg2, arg3);
  502. if (FAILED(hr)) return hr;
  503. hr = m_ptinstance->QueryInterface(__uuidof(TInterface), (LPVOID *) &m_pt);
  504. if (FAILED(hr)) return hr;
  505. m_fDeleteInstance = false;
  506. return NOERROR;
  507. }
  508. template <typename TArg1, typename TArg2, typename TArg3, typename TArg4> HRESULT CreateInstanceWith4Args(TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4)
  509. {
  510. if (m_ptinstance != NULL) return E_UNEXPECTED;
  511. m_ptinstance = NEW(CFusionCOMObject<TInstance>);
  512. if (m_ptinstance == NULL) return E_OUTOFMEMORY;
  513. m_fDeleteInstance = true;
  514. HRESULT hr = m_ptinstance->Initialize(arg1, arg2, arg3, arg4);
  515. if (FAILED(hr)) return hr;
  516. hr = m_ptinstance->QueryInterface(__uuidof(TInterface), (LPVOID *) &m_pt);
  517. if (FAILED(hr)) return hr;
  518. m_fDeleteInstance = false;
  519. return NOERROR;
  520. }
  521. template <typename TArg1, typename TArg2, typename TArg3, typename TArg4, typename TArg5> HRESULT CreateInstanceWith5Args(TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5)
  522. {
  523. if (m_ptinstance != NULL) return E_UNEXPECTED;
  524. m_ptinstance = NEW(CFusionCOMObject<TInstance>);
  525. if (m_ptinstance == NULL) return E_OUTOFMEMORY;
  526. m_fDeleteInstance = true;
  527. HRESULT hr = m_ptinstance->Initialize(arg1, arg2, arg3, arg4, arg5);
  528. if (FAILED(hr)) return hr;
  529. hr = m_ptinstance->QueryInterface(__uuidof(TInterface), (LPVOID *) &m_pt);
  530. if (FAILED(hr)) return hr;
  531. m_fDeleteInstance = false;
  532. return NOERROR;
  533. }
  534. // Call this if you need to clear out objects explicitly e.g. before uninitializing COM.
  535. inline void Release()
  536. {
  537. CSxsPreserveLastError ple;
  538. if (m_fDeleteInstance)
  539. delete m_ptinstance;
  540. CSmartRef<TInterface>::Release();
  541. m_fDeleteInstance = false;
  542. m_ptinstance = NULL;
  543. ple.Restore();
  544. }
  545. inline TInstance *ObjectPtr() const { return m_ptinstance; }
  546. private:
  547. CFusionCOMObject<TInstance> *m_ptinstance;
  548. bool m_fDeleteInstance;
  549. };
  550. #pragma pack(pop)
  551. #endif