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/. */
7 #ifndef mozilla_mscom_AgileReference_h
8 #define mozilla_mscom_AgileReference_h
10 #include "mozilla/Attributes.h"
11 #include "mozilla/RefPtr.h"
12 #include "nsISupportsImpl.h"
20 class MOZ_HEAP_CLASS GlobalInterfaceTableCookie final
{
22 GlobalInterfaceTableCookie(IUnknown
* aObject
, REFIID aIid
,
23 HRESULT
& aOutHResult
);
25 bool IsValid() const { return !!mCookie
; }
26 HRESULT
GetInterface(REFIID aIid
, void** aOutInterface
) const;
28 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GlobalInterfaceTableCookie
)
30 GlobalInterfaceTableCookie(const GlobalInterfaceTableCookie
&) = delete;
31 GlobalInterfaceTableCookie(GlobalInterfaceTableCookie
&&) = delete;
33 GlobalInterfaceTableCookie
& operator=(const GlobalInterfaceTableCookie
&) =
35 GlobalInterfaceTableCookie
& operator=(GlobalInterfaceTableCookie
&&) = delete;
38 ~GlobalInterfaceTableCookie();
44 static IGlobalInterfaceTable
* ObtainGit();
50 * This class encapsulates an "agile reference." These are references that
51 * allow you to pass COM interfaces between apartments. When you have an
52 * interface that you would like to pass between apartments, you wrap that
53 * interface in an AgileReference and pass the agile reference instead. Then
54 * you unwrap the interface by calling AgileReference::Resolve.
58 * // In the multithreaded apartment, foo is an IFoo*
59 * auto myAgileRef = MakeUnique<AgileReference>(IID_IFoo, foo);
61 * // myAgileRef is passed to our main thread, which runs in a single-threaded
65 * HRESULT hr = myAgileRef->Resolve(IID_IFoo, getter_AddRefs(foo));
66 * // Now foo may be called from the main thread
68 class AgileReference final
{
72 template <typename InterfaceT
>
73 explicit AgileReference(RefPtr
<InterfaceT
>& aObject
)
74 : AgileReference(__uuidof(InterfaceT
), aObject
) {}
76 AgileReference(REFIID aIid
, IUnknown
* aObject
);
78 AgileReference(const AgileReference
& aOther
) = default;
79 AgileReference(AgileReference
&& aOther
);
83 explicit operator bool() const {
84 return mAgileRef
|| (mGitCookie
&& mGitCookie
->IsValid());
87 HRESULT
GetHResult() const { return mHResult
; }
90 void Assign(const RefPtr
<T
>& aOther
) {
91 Assign(__uuidof(T
), aOther
);
95 AgileReference
& operator=(const RefPtr
<T
>& aOther
) {
100 HRESULT
Resolve(REFIID aIid
, void** aOutInterface
) const;
102 AgileReference
& operator=(const AgileReference
& aOther
);
103 AgileReference
& operator=(AgileReference
&& aOther
);
105 AgileReference
& operator=(decltype(nullptr)) {
113 void Assign(REFIID aIid
, IUnknown
* aObject
);
114 void AssignInternal(IUnknown
* aObject
);
118 RefPtr
<IAgileReference
> mAgileRef
;
119 RefPtr
<detail::GlobalInterfaceTableCookie
> mGitCookie
;
124 } // namespace mozilla
126 template <typename T
>
127 RefPtr
<T
>::RefPtr(const mozilla::mscom::AgileReference
& aAgileRef
)
132 template <typename T
>
133 RefPtr
<T
>& RefPtr
<T
>::operator=(
134 const mozilla::mscom::AgileReference
& aAgileRef
) {
136 if (FAILED(aAgileRef
.Resolve(__uuidof(T
), &newRawPtr
))) {
139 assign_assuming_AddRef(static_cast<T
*>(newRawPtr
));
143 #endif // mozilla_mscom_AgileReference_h