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.

123 lines
3.2 KiB

  1. #include "stock.h"
  2. #pragma hdrstop
  3. #include "caggunk.h"
  4. ULONG CAggregatedUnknown::AddRef()
  5. {
  6. return _punkAgg->AddRef();
  7. }
  8. ULONG CAggregatedUnknown::Release()
  9. {
  10. return _punkAgg->Release();
  11. }
  12. HRESULT CAggregatedUnknown::QueryInterface(REFIID riid, void **ppvObj)
  13. {
  14. return _punkAgg->QueryInterface(riid, ppvObj);
  15. }
  16. HRESULT CAggregatedUnknown::CUnkInner::QueryInterface(REFIID riid, void **ppvObj)
  17. {
  18. if (IsEqualIID(riid, IID_IUnknown))
  19. {
  20. *ppvObj = SAFECAST(this, IUnknown*);
  21. InterlockedIncrement(&_cRef);
  22. return S_OK;
  23. }
  24. CAggregatedUnknown* pparent = IToClass(CAggregatedUnknown, _unkInner, this);
  25. return pparent->v_InternalQueryInterface(riid, ppvObj);
  26. }
  27. ULONG CAggregatedUnknown::CUnkInner::AddRef(void)
  28. {
  29. return InterlockedIncrement(&_cRef);
  30. }
  31. ULONG CAggregatedUnknown::CUnkInner::Release(void)
  32. {
  33. if (InterlockedDecrement(&_cRef))
  34. return _cRef;
  35. CAggregatedUnknown* pparent = IToClass(CAggregatedUnknown, _unkInner, this);
  36. if (!pparent->v_HandleDelete(&_cRef))
  37. {
  38. _cRef = 1000; // protect against cached pointers bumping us up then down
  39. delete pparent;
  40. }
  41. return 0;
  42. }
  43. CAggregatedUnknown::CAggregatedUnknown(IUnknown* punkAgg)
  44. {
  45. _punkAgg = punkAgg ? punkAgg : &_unkInner;
  46. }
  47. CAggregatedUnknown::~CAggregatedUnknown()
  48. {
  49. }
  50. //
  51. // Convert our controlling unknown to its canonical IUnknown *without*
  52. // altering the reference count on the outer object.
  53. //
  54. // This is critical in order for QueryOuterInterface to work properly.
  55. //
  56. // Returns NULL if something horrible went wrong.
  57. //
  58. // OLE Magic: Since objects are required also to return the canonical
  59. // IUnknown in response to any QI(IUnknown), it follows that the canonical
  60. // IUnknown remains valid so long as there are any outstanding references
  61. // to the object. In other words, you can Release() the canonical IUnknown
  62. // and the pointer remains valid so long as you keep the object alive by
  63. // other means.
  64. //
  65. // Believe it or not, this is a feature. It's in the book!
  66. //
  67. IUnknown *CAggregatedUnknown::_GetCanonicalOuter(void)
  68. {
  69. IUnknown *punkAggCanon;
  70. HRESULT hres = _punkAgg->QueryInterface(IID_IUnknown, (void **)&punkAggCanon);
  71. if (SUCCEEDED(hres))
  72. {
  73. punkAggCanon->Release(); // see "OLE Magic" comment above
  74. return punkAggCanon;
  75. }
  76. else
  77. {
  78. // The outer object is most likely some other shell component,
  79. // so let's ASSERT so whoever owns the outer component will fix it.
  80. ASSERT(!"The outer object's implementation of QI(IUnknown) is broken.");
  81. return NULL;
  82. }
  83. }
  84. void CAggregatedUnknown::_ReleaseOuterInterface(IUnknown** ppunk)
  85. {
  86. ASSERT(IS_VALID_CODE_PTR(_punkAgg, IUnknown));
  87. IUnknown *punkAggCanon = _GetCanonicalOuter(); // non-refcounted pointer
  88. //
  89. // SHReleaseOuterInterface can handle punkAggCanon == NULL
  90. //
  91. SHReleaseOuterInterface(punkAggCanon, ppunk);
  92. }
  93. HRESULT CAggregatedUnknown::_QueryOuterInterface(REFIID riid, void ** ppvOut)
  94. {
  95. IUnknown *punkAggCanon = _GetCanonicalOuter(); // non-refcounted pointer
  96. //
  97. // SHQueryOuterInterface can handle punkAggCanon == NULL.
  98. //
  99. return SHQueryOuterInterface(punkAggCanon, riid, ppvOut);
  100. }