Bug 1310841: Make mscom registration use CoGetClassObject so that COM will retain a reference to the proxy dll; r?jimm
MozReview-Commit-ID: GZxbLCC6gVi
new file mode 100644
--- /dev/null
+++ b/accessible/interfaces/ia2/IA2Marshal.dll.manifest
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+ <assemblyIdentity type="win32" name="IA2Marshal" version="1.0.0.0" />
+ <file name = "IA2Marshal.dll">
+ <comInterfaceProxyStub
+ iid="{E89F726E-C4F4-4c19-BB19-B647D7FA8478}"
+ proxyStubClsid32="{E89F726E-C4F4-4c19-BB19-B647D7FA8478}"
+ name="IAccessible2"
+ tlbid="{CE3F726E-D1D3-44FE-B995-FF1DB3B48B2B}"
+ />
+ </file>
+</assembly>
new file mode 100644
--- /dev/null
+++ b/ipc/mscom/ActivationContext.cpp
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/mscom/ActivationContext.h"
+
+#include "mozilla/Assertions.h"
+#include "mozilla/DebugOnly.h"
+
+namespace mozilla {
+namespace mscom {
+
+ActivationContext::ActivationContext(HMODULE aLoadFromModule)
+ : mActCtx(INVALID_HANDLE_VALUE)
+ , mActivationCookie(0)
+{
+ ACTCTX actCtx = {sizeof(actCtx)};
+ actCtx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_HMODULE_VALID;
+ actCtx.lpResourceName = MAKEINTRESOURCE(2);
+ actCtx.hModule = aLoadFromModule;
+
+ mActCtx = ::CreateActCtx(&actCtx);
+ MOZ_ASSERT(mActCtx != INVALID_HANDLE_VALUE);
+ if (mActCtx == INVALID_HANDLE_VALUE) {
+ return;
+ }
+ if (!::ActivateActCtx(mActCtx, &mActivationCookie)) {
+ ::ReleaseActCtx(mActCtx);
+ mActCtx = INVALID_HANDLE_VALUE;
+ }
+}
+
+ActivationContext::~ActivationContext()
+{
+ if (mActCtx == INVALID_HANDLE_VALUE) {
+ return;
+ }
+ DebugOnly<BOOL> deactivated = ::DeactivateActCtx(0, mActivationCookie);
+ MOZ_ASSERT(deactivated);
+ ::ReleaseActCtx(mActCtx);
+}
+
+} // namespace mscom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/ipc/mscom/ActivationContext.h
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_mscom_ActivationContext_h
+#define mozilla_mscom_ActivationContext_h
+
+#include <windows.h>
+
+namespace mozilla {
+namespace mscom {
+
+class ActivationContext
+{
+public:
+ explicit ActivationContext(HMODULE aLoadFromModule);
+ ~ActivationContext();
+
+ explicit operator bool() const
+ {
+ return mActCtx != INVALID_HANDLE_VALUE;
+ }
+
+private:
+ HANDLE mActCtx;
+ ULONG_PTR mActivationCookie;
+};
+
+} // namespace mscom
+} // namespace mozilla
+
+#endif // mozilla_mscom_ActivationContext_h
+
--- a/ipc/mscom/Registration.cpp
+++ b/ipc/mscom/Registration.cpp
@@ -4,28 +4,30 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// COM registration data structures are built with C code, so we need to
// simulate that in our C++ code by defining CINTERFACE before including
// anything else that could possibly pull in Windows header files.
#define CINTERFACE
+#include "mozilla/mscom/ActivationContext.h"
#include "mozilla/mscom/EnsureMTA.h"
#include "mozilla/mscom/Registration.h"
#include "mozilla/mscom/Utils.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/Assertions.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/Move.h"
#include "mozilla/Mutex.h"
#include "mozilla/Pair.h"
#include "mozilla/StaticPtr.h"
#include "nsTArray.h"
+#include "nsWindowsHelpers.h"
#include <oaidl.h>
#include <objidl.h>
#include <rpcproxy.h>
#include <shlwapi.h>
/* This code MUST NOT use any non-inlined internal Mozilla APIs, as it will be
compiled into DLLs that COM may load into non-Mozilla processes! */
@@ -81,73 +83,70 @@ UniquePtr<RegisteredProxy>
RegisterProxy(const wchar_t* aLeafName, RegistrationFlags aFlags)
{
wchar_t modulePathBuf[MAX_PATH + 1] = {0};
if (!BuildLibPath(aFlags, modulePathBuf, ArrayLength(modulePathBuf),
aLeafName)) {
return nullptr;
}
- HMODULE proxyDll = LoadLibrary(modulePathBuf);
- if (!proxyDll) {
+ nsModuleHandle proxyDll(LoadLibrary(modulePathBuf));
+ if (!proxyDll.get()) {
return nullptr;
}
- auto DllGetClassObjectFn = reinterpret_cast<LPFNGETCLASSOBJECT>(
- GetProcAddress(proxyDll, "DllGetClassObject"));
- if (!DllGetClassObjectFn) {
- FreeLibrary(proxyDll);
+ // Instantiate an activation context so that CoGetClassObject will use any
+ // COM metadata embedded in proxyDll's manifest to resolve CLSIDs.
+ ActivationContext actCtx(proxyDll);
+ if (!actCtx) {
return nullptr;
}
auto GetProxyDllInfoFn = reinterpret_cast<GetProxyDllInfoFnPtr>(
GetProcAddress(proxyDll, "GetProxyDllInfo"));
if (!GetProxyDllInfoFn) {
- FreeLibrary(proxyDll);
return nullptr;
}
const ProxyFileInfo** proxyInfo = nullptr;
const CLSID* proxyClsid = nullptr;
GetProxyDllInfoFn(&proxyInfo, &proxyClsid);
if (!proxyInfo || !proxyClsid) {
- FreeLibrary(proxyDll);
return nullptr;
}
+ // We call CoGetClassObject instead of DllGetClassObject because it forces
+ // the COM runtime to manage the lifetime of the DLL.
IUnknown* classObject = nullptr;
- HRESULT hr = DllGetClassObjectFn(*proxyClsid, IID_IUnknown,
- (void**) &classObject);
+ HRESULT hr = CoGetClassObject(*proxyClsid, CLSCTX_INPROC_SERVER, nullptr,
+ IID_IUnknown, (void**) &classObject);
if (FAILED(hr)) {
- FreeLibrary(proxyDll);
return nullptr;
}
DWORD regCookie;
hr = CoRegisterClassObject(*proxyClsid, classObject, CLSCTX_INPROC_SERVER,
REGCLS_MULTIPLEUSE, ®Cookie);
if (FAILED(hr)) {
classObject->lpVtbl->Release(classObject);
- FreeLibrary(proxyDll);
return nullptr;
}
ITypeLib* typeLib = nullptr;
hr = LoadTypeLibEx(modulePathBuf, REGKIND_NONE, &typeLib);
MOZ_ASSERT(SUCCEEDED(hr));
if (FAILED(hr)) {
CoRevokeClassObject(regCookie);
classObject->lpVtbl->Release(classObject);
- FreeLibrary(proxyDll);
return nullptr;
}
// RegisteredProxy takes ownership of proxyDll, classObject, and typeLib
// references
- auto result(MakeUnique<RegisteredProxy>(reinterpret_cast<uintptr_t>(proxyDll),
+ auto result(MakeUnique<RegisteredProxy>(reinterpret_cast<uintptr_t>(proxyDll.disown()),
classObject, regCookie, typeLib));
while (*proxyInfo) {
const ProxyFileInfo& curInfo = **proxyInfo;
for (unsigned short i = 0, e = curInfo.TableSize; i < e; ++i) {
hr = CoRegisterPSClsid(*(curInfo.pStubVtblList[i]->header.piid),
*proxyClsid);
if (FAILED(hr)) {
--- a/ipc/mscom/moz.build
+++ b/ipc/mscom/moz.build
@@ -25,16 +25,17 @@ UNIFIED_SOURCES += [
]
if CONFIG['ACCESSIBILITY']:
DIRS += [
'test',
]
EXPORTS.mozilla.mscom += [
+ 'ActivationContext.h',
'DispatchForwarder.h',
'Interceptor.h',
'InterceptorLog.h',
'MainThreadHandoff.h',
'MainThreadInvoker.h',
'Registration.h',
'ThreadLocalObject.h',
'WeakRef.h',
@@ -42,16 +43,17 @@ if CONFIG['ACCESSIBILITY']:
SOURCES += [
'Interceptor.cpp',
'Registration.cpp',
'WeakRef.cpp',
]
UNIFIED_SOURCES += [
+ 'ActivationContext.cpp',
'DispatchForwarder.cpp',
'InterceptorLog.cpp',
'MainThreadHandoff.cpp',
'MainThreadInvoker.cpp',
'ThreadLocalObject.cpp',
]
LOCAL_INCLUDES += [