Backed out 2 changesets (bug 1156659) for causing multiple dt failures on browser_jst...
[gecko.git] / ipc / mscom / AgileReference.cpp
blob8af1a65dc4db0598ad1384a862bd4b081c7e7b62
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 #include "mozilla/mscom/AgileReference.h"
9 #include <utility>
11 #include "mozilla/Assertions.h"
12 #include "mozilla/DebugOnly.h"
13 #include "mozilla/DynamicallyLinkedFunctionPtr.h"
14 #include "mozilla/mscom/Utils.h"
16 #if defined(MOZILLA_INTERNAL_API)
17 # include "nsDebug.h"
18 # include "nsPrintfCString.h"
19 #endif // defined(MOZILLA_INTERNAL_API)
21 #if defined(__MINGW32__)
23 // Declarations from Windows SDK specific to Windows 8.1
25 enum AgileReferenceOptions {
26 AGILEREFERENCE_DEFAULT = 0,
27 AGILEREFERENCE_DELAYEDMARSHAL = 1,
30 HRESULT WINAPI RoGetAgileReference(AgileReferenceOptions options, REFIID riid,
31 IUnknown* pUnk,
32 IAgileReference** ppAgileReference);
34 #endif // defined(__MINGW32__)
36 namespace mozilla {
37 namespace mscom {
38 namespace detail {
40 GlobalInterfaceTableCookie::GlobalInterfaceTableCookie(IUnknown* aObject,
41 REFIID aIid,
42 HRESULT& aOutHResult)
43 : mCookie(0) {
44 IGlobalInterfaceTable* git = ObtainGit();
45 MOZ_ASSERT(git);
46 if (!git) {
47 aOutHResult = E_POINTER;
48 return;
51 aOutHResult = git->RegisterInterfaceInGlobal(aObject, aIid, &mCookie);
52 MOZ_ASSERT(SUCCEEDED(aOutHResult));
55 GlobalInterfaceTableCookie::~GlobalInterfaceTableCookie() {
56 IGlobalInterfaceTable* git = ObtainGit();
57 MOZ_ASSERT(git);
58 if (!git) {
59 return;
62 DebugOnly<HRESULT> hr = git->RevokeInterfaceFromGlobal(mCookie);
63 #if defined(MOZILLA_INTERNAL_API)
64 NS_WARNING_ASSERTION(
65 SUCCEEDED(hr),
66 nsPrintfCString("IGlobalInterfaceTable::RevokeInterfaceFromGlobal failed "
67 "with HRESULT 0x%08lX",
68 ((HRESULT)hr))
69 .get());
70 #else
71 MOZ_ASSERT(SUCCEEDED(hr));
72 #endif // defined(MOZILLA_INTERNAL_API)
73 mCookie = 0;
76 HRESULT GlobalInterfaceTableCookie::GetInterface(REFIID aIid,
77 void** aOutInterface) const {
78 IGlobalInterfaceTable* git = ObtainGit();
79 MOZ_ASSERT(git);
80 if (!git) {
81 return E_UNEXPECTED;
84 MOZ_ASSERT(IsValid());
85 return git->GetInterfaceFromGlobal(mCookie, aIid, aOutInterface);
88 /* static */
89 IGlobalInterfaceTable* GlobalInterfaceTableCookie::ObtainGit() {
90 // Internally to COM, the Global Interface Table is a singleton, therefore we
91 // don't worry about holding onto this reference indefinitely.
92 static IGlobalInterfaceTable* sGit = []() -> IGlobalInterfaceTable* {
93 IGlobalInterfaceTable* result = nullptr;
94 DebugOnly<HRESULT> hr = ::CoCreateInstance(
95 CLSID_StdGlobalInterfaceTable, nullptr, CLSCTX_INPROC_SERVER,
96 IID_IGlobalInterfaceTable, reinterpret_cast<void**>(&result));
97 MOZ_ASSERT(SUCCEEDED(hr));
98 return result;
99 }();
101 return sGit;
104 } // namespace detail
106 AgileReference::AgileReference() : mIid(), mHResult(E_NOINTERFACE) {}
108 AgileReference::AgileReference(REFIID aIid, IUnknown* aObject)
109 : mIid(aIid), mHResult(E_UNEXPECTED) {
110 AssignInternal(aObject);
113 AgileReference::AgileReference(AgileReference&& aOther)
114 : mIid(aOther.mIid),
115 mAgileRef(std::move(aOther.mAgileRef)),
116 mGitCookie(std::move(aOther.mGitCookie)),
117 mHResult(aOther.mHResult) {
118 aOther.mHResult = CO_E_RELEASED;
121 void AgileReference::Assign(REFIID aIid, IUnknown* aObject) {
122 Clear();
123 mIid = aIid;
124 AssignInternal(aObject);
127 void AgileReference::AssignInternal(IUnknown* aObject) {
128 // We expect mIid to already be set
129 DebugOnly<IID> zeroIid = {};
130 MOZ_ASSERT(mIid != zeroIid);
133 * There are two possible techniques for creating agile references. Starting
134 * with Windows 8.1, we may use the RoGetAgileReference API, which is faster.
135 * If that API is not available, we fall back to using the Global Interface
136 * Table.
138 static const StaticDynamicallyLinkedFunctionPtr<
139 decltype(&::RoGetAgileReference)>
140 pRoGetAgileReference(L"ole32.dll", "RoGetAgileReference");
142 MOZ_ASSERT(aObject);
144 if (pRoGetAgileReference &&
145 SUCCEEDED(mHResult =
146 pRoGetAgileReference(AGILEREFERENCE_DEFAULT, mIid, aObject,
147 getter_AddRefs(mAgileRef)))) {
148 return;
151 mGitCookie = new detail::GlobalInterfaceTableCookie(aObject, mIid, mHResult);
152 MOZ_ASSERT(mGitCookie->IsValid());
155 AgileReference::~AgileReference() { Clear(); }
157 void AgileReference::Clear() {
158 mIid = {};
159 mAgileRef = nullptr;
160 mGitCookie = nullptr;
161 mHResult = E_NOINTERFACE;
164 AgileReference& AgileReference::operator=(const AgileReference& aOther) {
165 Clear();
166 mIid = aOther.mIid;
167 mAgileRef = aOther.mAgileRef;
168 mGitCookie = aOther.mGitCookie;
169 mHResult = aOther.mHResult;
170 return *this;
173 AgileReference& AgileReference::operator=(AgileReference&& aOther) {
174 Clear();
175 mIid = aOther.mIid;
176 mAgileRef = std::move(aOther.mAgileRef);
177 mGitCookie = std::move(aOther.mGitCookie);
178 mHResult = aOther.mHResult;
179 aOther.mHResult = CO_E_RELEASED;
180 return *this;
183 HRESULT
184 AgileReference::Resolve(REFIID aIid, void** aOutInterface) const {
185 MOZ_ASSERT(aOutInterface);
186 // This check is exclusive-OR; we should have one or the other, but not both
187 MOZ_ASSERT((mAgileRef || mGitCookie) && !(mAgileRef && mGitCookie));
188 MOZ_ASSERT(IsCOMInitializedOnCurrentThread());
190 if (!aOutInterface) {
191 return E_INVALIDARG;
194 *aOutInterface = nullptr;
196 if (mAgileRef) {
197 // IAgileReference lets you directly resolve the interface you want...
198 return mAgileRef->Resolve(aIid, aOutInterface);
201 if (!mGitCookie) {
202 return E_UNEXPECTED;
205 RefPtr<IUnknown> originalInterface;
206 HRESULT hr =
207 mGitCookie->GetInterface(mIid, getter_AddRefs(originalInterface));
208 if (FAILED(hr)) {
209 return hr;
212 if (aIid == mIid) {
213 originalInterface.forget(aOutInterface);
214 return S_OK;
217 // ...Whereas the GIT requires us to obtain the same interface that we
218 // requested and then QI for the desired interface afterward.
219 return originalInterface->QueryInterface(aIid, aOutInterface);
222 } // namespace mscom
223 } // namespace mozilla