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 #include "mozilla/mscom/ActivationContext.h"
8 
9 #include "mozilla/Assertions.h"
10 #include "mozilla/DebugOnly.h"
11 #include "mozilla/mscom/Utils.h"
12 
13 namespace mozilla {
14 namespace mscom {
15 
ActivationContext(WORD aResourceId)16 ActivationContext::ActivationContext(WORD aResourceId)
17     : ActivationContext(reinterpret_cast<HMODULE>(GetContainingModuleHandle()),
18                         aResourceId) {}
19 
ActivationContext(HMODULE aLoadFromModule,WORD aResourceId)20 ActivationContext::ActivationContext(HMODULE aLoadFromModule, WORD aResourceId)
21     : mActCtx(INVALID_HANDLE_VALUE) {
22   ACTCTX actCtx = {sizeof(actCtx)};
23   actCtx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_HMODULE_VALID;
24   actCtx.lpResourceName = MAKEINTRESOURCE(aResourceId);
25   actCtx.hModule = aLoadFromModule;
26 
27   Init(actCtx);
28 }
29 
Init(ACTCTX & aActCtx)30 void ActivationContext::Init(ACTCTX& aActCtx) {
31   MOZ_ASSERT(mActCtx == INVALID_HANDLE_VALUE);
32   mActCtx = ::CreateActCtx(&aActCtx);
33   MOZ_ASSERT(mActCtx != INVALID_HANDLE_VALUE);
34 }
35 
AddRef()36 void ActivationContext::AddRef() {
37   if (mActCtx == INVALID_HANDLE_VALUE) {
38     return;
39   }
40   ::AddRefActCtx(mActCtx);
41 }
42 
ActivationContext(ActivationContext && aOther)43 ActivationContext::ActivationContext(ActivationContext&& aOther)
44     : mActCtx(aOther.mActCtx) {
45   aOther.mActCtx = INVALID_HANDLE_VALUE;
46 }
47 
operator =(ActivationContext && aOther)48 ActivationContext& ActivationContext::operator=(ActivationContext&& aOther) {
49   Release();
50 
51   mActCtx = aOther.mActCtx;
52   aOther.mActCtx = INVALID_HANDLE_VALUE;
53   return *this;
54 }
55 
ActivationContext(const ActivationContext & aOther)56 ActivationContext::ActivationContext(const ActivationContext& aOther)
57     : mActCtx(aOther.mActCtx) {
58   AddRef();
59 }
60 
operator =(const ActivationContext & aOther)61 ActivationContext& ActivationContext::operator=(
62     const ActivationContext& aOther) {
63   Release();
64   mActCtx = aOther.mActCtx;
65   AddRef();
66   return *this;
67 }
68 
Release()69 void ActivationContext::Release() {
70   if (mActCtx == INVALID_HANDLE_VALUE) {
71     return;
72   }
73   ::ReleaseActCtx(mActCtx);
74   mActCtx = INVALID_HANDLE_VALUE;
75 }
76 
~ActivationContext()77 ActivationContext::~ActivationContext() { Release(); }
78 
79 #if defined(MOZILLA_INTERNAL_API)
80 
GetCurrent()81 /* static */ Result<uintptr_t, HRESULT> ActivationContext::GetCurrent() {
82   HANDLE actCtx;
83   if (!::GetCurrentActCtx(&actCtx)) {
84     return Result<uintptr_t, HRESULT>(HRESULT_FROM_WIN32(::GetLastError()));
85   }
86 
87   return reinterpret_cast<uintptr_t>(actCtx);
88 }
89 
90 /* static */
GetCurrentManifestPath(nsAString & aOutManifestPath)91 HRESULT ActivationContext::GetCurrentManifestPath(nsAString& aOutManifestPath) {
92   aOutManifestPath.Truncate();
93 
94   SIZE_T bytesNeeded;
95   BOOL ok = ::QueryActCtxW(QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX, nullptr,
96                            nullptr, ActivationContextDetailedInformation,
97                            nullptr, 0, &bytesNeeded);
98   if (!ok) {
99     DWORD err = ::GetLastError();
100     if (err != ERROR_INSUFFICIENT_BUFFER) {
101       return HRESULT_FROM_WIN32(err);
102     }
103   }
104 
105   auto ctxBuf = MakeUnique<BYTE[]>(bytesNeeded);
106 
107   ok = ::QueryActCtxW(QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX, nullptr, nullptr,
108                       ActivationContextDetailedInformation, ctxBuf.get(),
109                       bytesNeeded, nullptr);
110   if (!ok) {
111     return HRESULT_FROM_WIN32(::GetLastError());
112   }
113 
114   auto ctxInfo =
115       reinterpret_cast<ACTIVATION_CONTEXT_DETAILED_INFORMATION*>(ctxBuf.get());
116 
117   // assemblyIndex is 1-based, and we want the last index, so we can just copy
118   // ctxInfo->ulAssemblyCount directly.
119   DWORD assemblyIndex = ctxInfo->ulAssemblyCount;
120   ok = ::QueryActCtxW(
121       QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX, nullptr, &assemblyIndex,
122       AssemblyDetailedInformationInActivationContext, nullptr, 0, &bytesNeeded);
123   if (!ok) {
124     DWORD err = ::GetLastError();
125     if (err != ERROR_INSUFFICIENT_BUFFER) {
126       return HRESULT_FROM_WIN32(err);
127     }
128   }
129 
130   auto assemblyBuf = MakeUnique<BYTE[]>(bytesNeeded);
131 
132   ok = ::QueryActCtxW(QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX, nullptr,
133                       &assemblyIndex,
134                       AssemblyDetailedInformationInActivationContext,
135                       assemblyBuf.get(), bytesNeeded, &bytesNeeded);
136   if (!ok) {
137     return HRESULT_FROM_WIN32(::GetLastError());
138   }
139 
140   auto assemblyInfo =
141       reinterpret_cast<ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION*>(
142           assemblyBuf.get());
143   aOutManifestPath = nsDependentString(
144       assemblyInfo->lpAssemblyManifestPath,
145       (assemblyInfo->ulManifestPathLength + 1) / sizeof(wchar_t));
146 
147   return S_OK;
148 }
149 
150 #endif  // defined(MOZILLA_INTERNAL_API)
151 
ActivationContextRegion()152 ActivationContextRegion::ActivationContextRegion() : mActCookie(0) {}
153 
ActivationContextRegion(const ActivationContext & aActCtx)154 ActivationContextRegion::ActivationContextRegion(
155     const ActivationContext& aActCtx)
156     : mActCtx(aActCtx), mActCookie(0) {
157   Activate();
158 }
159 
operator =(const ActivationContext & aActCtx)160 ActivationContextRegion& ActivationContextRegion::operator=(
161     const ActivationContext& aActCtx) {
162   Deactivate();
163   mActCtx = aActCtx;
164   Activate();
165   return *this;
166 }
167 
ActivationContextRegion(ActivationContext && aActCtx)168 ActivationContextRegion::ActivationContextRegion(ActivationContext&& aActCtx)
169     : mActCtx(std::move(aActCtx)), mActCookie(0) {
170   Activate();
171 }
172 
operator =(ActivationContext && aActCtx)173 ActivationContextRegion& ActivationContextRegion::operator=(
174     ActivationContext&& aActCtx) {
175   Deactivate();
176   mActCtx = std::move(aActCtx);
177   Activate();
178   return *this;
179 }
180 
ActivationContextRegion(ActivationContextRegion && aRgn)181 ActivationContextRegion::ActivationContextRegion(ActivationContextRegion&& aRgn)
182     : mActCtx(std::move(aRgn.mActCtx)), mActCookie(aRgn.mActCookie) {
183   aRgn.mActCookie = 0;
184 }
185 
operator =(ActivationContextRegion && aRgn)186 ActivationContextRegion& ActivationContextRegion::operator=(
187     ActivationContextRegion&& aRgn) {
188   Deactivate();
189   mActCtx = std::move(aRgn.mActCtx);
190   mActCookie = aRgn.mActCookie;
191   aRgn.mActCookie = 0;
192   return *this;
193 }
194 
Activate()195 void ActivationContextRegion::Activate() {
196   if (mActCtx.mActCtx == INVALID_HANDLE_VALUE) {
197     return;
198   }
199 
200 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
201   BOOL activated =
202 #endif
203       ::ActivateActCtx(mActCtx.mActCtx, &mActCookie);
204   MOZ_DIAGNOSTIC_ASSERT(activated);
205 }
206 
Deactivate()207 bool ActivationContextRegion::Deactivate() {
208   if (!mActCookie) {
209     return true;
210   }
211 
212   BOOL deactivated = ::DeactivateActCtx(0, mActCookie);
213   MOZ_DIAGNOSTIC_ASSERT(deactivated);
214   if (deactivated) {
215     mActCookie = 0;
216   }
217 
218   return !!deactivated;
219 }
220 
~ActivationContextRegion()221 ActivationContextRegion::~ActivationContextRegion() { Deactivate(); }
222 
223 }  // namespace mscom
224 }  // namespace mozilla
225