Bug 1293486: Add tearoff IDispatch handler to mscom interceptor; r?jimm
MozReview-Commit-ID: 9PSbpkNcOOh
new file mode 100644
--- /dev/null
+++ b/ipc/mscom/DispatchForwarder.cpp
@@ -0,0 +1,167 @@
+/* -*- 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/Move.h"
+#include "mozilla/mscom/DispatchForwarder.h"
+#include "mozilla/mscom/MainThreadInvoker.h"
+
+#include <oleauto.h>
+
+namespace mozilla {
+namespace mscom {
+
+/* static */ HRESULT
+DispatchForwarder::Create(IInterceptor* aInterceptor,
+ STAUniquePtr<IDispatch>& aTarget, IUnknown** aOutput)
+{
+ MOZ_ASSERT(aInterceptor && aOutput);
+ if (!aOutput) {
+ return E_INVALIDARG;
+ }
+ *aOutput = nullptr;
+ if (!aInterceptor) {
+ return E_INVALIDARG;
+ }
+ DispatchForwarder* forwarder = new DispatchForwarder(aInterceptor, aTarget);
+ HRESULT hr = forwarder->QueryInterface(IID_IDispatch, (void**) aOutput);
+ forwarder->Release();
+ return hr;
+}
+
+DispatchForwarder::DispatchForwarder(IInterceptor* aInterceptor,
+ STAUniquePtr<IDispatch>& aTarget)
+ : mRefCnt(1)
+ , mInterceptor(aInterceptor)
+ , mTarget(Move(aTarget))
+{
+}
+
+DispatchForwarder::~DispatchForwarder()
+{
+}
+
+HRESULT
+DispatchForwarder::QueryInterface(REFIID riid, void** ppv)
+{
+ if (!ppv) {
+ return E_INVALIDARG;
+ }
+
+ // Since this class implements a tearoff, any interfaces that are not
+ // IDispatch must be routed to the original object's QueryInterface.
+ // This is especially important for IUnknown since COM uses that interface
+ // to determine object identity.
+ if (riid != IID_IDispatch) {
+ return mInterceptor->QueryInterface(riid, ppv);
+ }
+
+ IUnknown* punk = static_cast<IDispatch*>(this);
+ *ppv = punk;
+ if (!punk) {
+ return E_NOINTERFACE;
+ }
+
+ punk->AddRef();
+ return S_OK;
+}
+
+ULONG
+DispatchForwarder::AddRef()
+{
+ return (ULONG) InterlockedIncrement((LONG*)&mRefCnt);
+}
+
+ULONG
+DispatchForwarder::Release()
+{
+ ULONG newRefCnt = (ULONG) InterlockedDecrement((LONG*)&mRefCnt);
+ if (newRefCnt == 0) {
+ delete this;
+ }
+ return newRefCnt;
+}
+
+HRESULT
+DispatchForwarder::GetTypeInfoCount(UINT *pctinfo)
+{
+ if (!pctinfo) {
+ return E_INVALIDARG;
+ }
+ *pctinfo = 1;
+ return S_OK;
+}
+
+HRESULT
+DispatchForwarder::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
+{
+ // ITypeInfo as implemented by COM is apartment-neutral, so we don't need
+ // to wrap it (yay!)
+ if (mTypeInfo) {
+ *ppTInfo = mTypeInfo.get();
+ mTypeInfo->AddRef();
+ return S_OK;
+ }
+ HRESULT hr = E_UNEXPECTED;
+ auto fn = [&]() -> void {
+ hr = mTarget->GetTypeInfo(iTInfo, lcid, ppTInfo);
+ };
+ MainThreadInvoker invoker;
+ if (!invoker.Invoke(NS_NewRunnableFunction(fn))) {
+ return E_UNEXPECTED;
+ }
+ if (FAILED(hr)) {
+ return hr;
+ }
+ mTypeInfo = *ppTInfo;
+ return hr;
+}
+
+HRESULT
+DispatchForwarder::GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames,
+ LCID lcid, DISPID *rgDispId)
+{
+ HRESULT hr = E_UNEXPECTED;
+ auto fn = [&]() -> void {
+ hr = mTarget->GetIDsOfNames(riid, rgszNames, cNames, lcid, rgDispId);
+ };
+ MainThreadInvoker invoker;
+ if (!invoker.Invoke(NS_NewRunnableFunction(fn))) {
+ return E_UNEXPECTED;
+ }
+ return hr;
+}
+
+HRESULT
+DispatchForwarder::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid,
+ WORD wFlags, DISPPARAMS *pDispParams,
+ VARIANT *pVarResult, EXCEPINFO *pExcepInfo,
+ UINT *puArgErr)
+{
+ HRESULT hr;
+ if (!mInterface) {
+ if (!mTypeInfo) {
+ return E_UNEXPECTED;
+ }
+ TYPEATTR* typeAttr = nullptr;
+ hr = mTypeInfo->GetTypeAttr(&typeAttr);
+ if (FAILED(hr)) {
+ return hr;
+ }
+ hr = mInterceptor->QueryInterface(typeAttr->guid,
+ (void**)getter_AddRefs(mInterface));
+ mTypeInfo->ReleaseTypeAttr(typeAttr);
+ if (FAILED(hr)) {
+ return hr;
+ }
+ }
+ // We don't invoke IDispatch on the target, but rather on the interceptor!
+ hr = ::DispInvoke(mInterface.get(), mTypeInfo, dispIdMember, wFlags,
+ pDispParams, pVarResult, pExcepInfo, puArgErr);
+ return hr;
+}
+
+} // namespace mscom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/ipc/mscom/DispatchForwarder.h
@@ -0,0 +1,81 @@
+/* -*- 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_DispatchForwarder_h
+#define mozilla_mscom_DispatchForwarder_h
+
+#include <oaidl.h>
+
+#include "mozilla/mscom/Interceptor.h"
+#include "mozilla/mscom/Ptr.h"
+
+namespace mozilla {
+namespace mscom {
+
+class DispatchForwarder : public IDispatch
+{
+public:
+ static HRESULT Create(IInterceptor* aInterceptor,
+ STAUniquePtr<IDispatch>& aTarget, IUnknown** aOutput);
+
+ // IUnknown
+ STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override;
+ STDMETHODIMP_(ULONG) AddRef() override;
+ STDMETHODIMP_(ULONG) Release() override;
+
+ // IDispatch
+ STDMETHODIMP GetTypeInfoCount(
+ /* [out] */ __RPC__out UINT *pctinfo) override;
+
+ STDMETHODIMP GetTypeInfo(
+ /* [in] */ UINT iTInfo,
+ /* [in] */ LCID lcid,
+ /* [out] */ __RPC__deref_out_opt ITypeInfo **ppTInfo) override;
+
+ STDMETHODIMP GetIDsOfNames(
+ /* [in] */ __RPC__in REFIID riid,
+ /* [size_is][in] */ __RPC__in_ecount_full(cNames) LPOLESTR *rgszNames,
+ /* [range][in] */ __RPC__in_range(0,16384) UINT cNames,
+ /* [in] */ LCID lcid,
+ /* [size_is][out] */ __RPC__out_ecount_full(cNames) DISPID *rgDispId)
+ override;
+
+ STDMETHODIMP Invoke(
+ /* [annotation][in] */
+ _In_ DISPID dispIdMember,
+ /* [annotation][in] */
+ _In_ REFIID riid,
+ /* [annotation][in] */
+ _In_ LCID lcid,
+ /* [annotation][in] */
+ _In_ WORD wFlags,
+ /* [annotation][out][in] */
+ _In_ DISPPARAMS *pDispParams,
+ /* [annotation][out] */
+ _Out_opt_ VARIANT *pVarResult,
+ /* [annotation][out] */
+ _Out_opt_ EXCEPINFO *pExcepInfo,
+ /* [annotation][out] */
+ _Out_opt_ UINT *puArgErr) override;
+
+private:
+ DispatchForwarder(IInterceptor* aInterceptor,
+ STAUniquePtr<IDispatch>& aTarget);
+ ~DispatchForwarder();
+
+private:
+ ULONG mRefCnt;
+ RefPtr<IInterceptor> mInterceptor;
+ STAUniquePtr<IDispatch> mTarget;
+ RefPtr<ITypeInfo> mTypeInfo;
+ RefPtr<IUnknown> mInterface;
+};
+
+} // namespace mscom
+} // namespace mozilla
+
+#endif // mozilla_mscom_DispatchForwarder_h
+
--- a/ipc/mscom/Interceptor.cpp
+++ b/ipc/mscom/Interceptor.cpp
@@ -3,16 +3,17 @@
/* 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/. */
#define INITGUID
#include "mozilla/mscom/Interceptor.h"
#include "mozilla/mscom/InterceptorLog.h"
+#include "mozilla/mscom/DispatchForwarder.h"
#include "mozilla/mscom/MainThreadInvoker.h"
#include "mozilla/mscom/Registration.h"
#include "mozilla/mscom/utils.h"
#include "MainThreadUtils.h"
#include "mozilla/Assertions.h"
#include "mozilla/DebugOnly.h"
#include "nsDirectoryServiceDefs.h"
#include "nsDirectoryServiceUtils.h"
@@ -269,16 +270,27 @@ HRESULT
Interceptor::ThreadSafeQueryInterface(REFIID aIid, IUnknown** aOutInterface)
{
if (aIid == IID_IInterceptor) {
*aOutInterface = static_cast<IInterceptor*>(this);
(*aOutInterface)->AddRef();
return S_OK;
}
+ if (aIid == IID_IDispatch) {
+ STAUniquePtr<IDispatch> disp;
+ IDispatch* rawDisp = nullptr;
+ HRESULT hr = QueryInterfaceTarget(aIid, (void**)&rawDisp);
+ if (FAILED(hr)) {
+ return hr;
+ }
+ disp.reset(rawDisp);
+ return DispatchForwarder::Create(this, disp, aOutInterface);
+ }
+
return GetInterceptorForIID(aIid, (void**)aOutInterface);
}
ULONG
Interceptor::AddRef()
{
return WeakReferenceSupport::AddRef();
}
--- a/ipc/mscom/moz.build
+++ b/ipc/mscom/moz.build
@@ -2,16 +2,17 @@
# vim: set filetype=python:
# 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/.
EXPORTS.mozilla.mscom += [
'COMApartmentRegion.h',
'COMPtrHolder.h',
+ 'DispatchForwarder.h',
'EnsureMTA.h',
'Interceptor.h',
'InterceptorLog.h',
'MainThreadHandoff.h',
'MainThreadInvoker.h',
'MainThreadRuntime.h',
'ProxyStream.h',
'Ptr.h',
@@ -23,16 +24,17 @@ EXPORTS.mozilla.mscom += [
SOURCES += [
'Interceptor.cpp',
'Registration.cpp',
'Utils.cpp',
'WeakRef.cpp',
]
UNIFIED_SOURCES += [
+ 'DispatchForwarder.cpp',
'EnsureMTA.cpp',
'InterceptorLog.cpp',
'MainThreadHandoff.cpp',
'MainThreadInvoker.cpp',
'MainThreadRuntime.cpp',
'ProxyStream.cpp',
]