1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_mscom_Aggregation_h 8 #define mozilla_mscom_Aggregation_h 9 10 #include "mozilla/Attributes.h" 11 12 #include <stddef.h> 13 #include <unknwn.h> 14 15 namespace mozilla { 16 namespace mscom { 17 18 /** 19 * This is used for stabilizing a COM object's reference count during 20 * construction when that object aggregates other objects. Since the aggregated 21 * object(s) may AddRef() or Release(), we need to artifically boost the 22 * refcount to prevent premature destruction. Note that we increment/decrement 23 * instead of AddRef()/Release() in this class because we want to adjust the 24 * refcount without causing any other side effects (like object destruction). 25 */ 26 template <typename RefCntT> 27 class MOZ_RAII StabilizedRefCount { 28 public: StabilizedRefCount(RefCntT & aRefCnt)29 explicit StabilizedRefCount(RefCntT& aRefCnt) : mRefCnt(aRefCnt) { 30 ++aRefCnt; 31 } 32 ~StabilizedRefCount()33 ~StabilizedRefCount() { --mRefCnt; } 34 35 StabilizedRefCount(const StabilizedRefCount&) = delete; 36 StabilizedRefCount(StabilizedRefCount&&) = delete; 37 StabilizedRefCount& operator=(const StabilizedRefCount&) = delete; 38 StabilizedRefCount& operator=(StabilizedRefCount&&) = delete; 39 40 private: 41 RefCntT& mRefCnt; 42 }; 43 44 namespace detail { 45 46 template <typename T> 47 class InternalUnknown : public IUnknown { 48 public: QueryInterface(REFIID aIid,void ** aOutInterface)49 STDMETHODIMP QueryInterface(REFIID aIid, void** aOutInterface) override { 50 return This()->InternalQueryInterface(aIid, aOutInterface); 51 } 52 AddRef()53 STDMETHODIMP_(ULONG) AddRef() override { return This()->InternalAddRef(); } 54 Release()55 STDMETHODIMP_(ULONG) Release() override { return This()->InternalRelease(); } 56 57 private: This()58 T* This() { 59 return reinterpret_cast<T*>(reinterpret_cast<char*>(this) - 60 offsetof(T, mInternalUnknown)); 61 } 62 }; 63 64 } // namespace detail 65 } // namespace mscom 66 } // namespace mozilla 67 68 #define DECLARE_AGGREGATABLE(Type) \ 69 public: \ 70 STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override { \ 71 return mOuter->QueryInterface(riid, ppv); \ 72 } \ 73 STDMETHODIMP_(ULONG) AddRef() override { return mOuter->AddRef(); } \ 74 STDMETHODIMP_(ULONG) Release() override { return mOuter->Release(); } \ 75 \ 76 protected: \ 77 STDMETHODIMP InternalQueryInterface(REFIID riid, void** ppv); \ 78 STDMETHODIMP_(ULONG) InternalAddRef(); \ 79 STDMETHODIMP_(ULONG) InternalRelease(); \ 80 friend class mozilla::mscom::detail::InternalUnknown<Type>; \ 81 mozilla::mscom::detail::InternalUnknown<Type> mInternalUnknown 82 83 #endif // mozilla_mscom_Aggregation_h 84