--- a/ipc/mscom/Aggregation.h
+++ b/ipc/mscom/Aggregation.h
@@ -4,16 +4,19 @@
* 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_Aggregation_h
#define mozilla_mscom_Aggregation_h
#include "mozilla/Attributes.h"
+#include <stddef.h>
+#include <unknwn.h>
+
namespace mozilla {
namespace mscom {
/**
* This is used for stabilizing a COM object's reference count during
* construction when that object aggregates other objects. Since the aggregated
* object(s) may AddRef() or Release(), we need to artifically boost the
* refcount to prevent premature destruction. Note that we increment/decrement
@@ -39,13 +42,58 @@ public:
StabilizedRefCount(StabilizedRefCount&&) = delete;
StabilizedRefCount& operator=(const StabilizedRefCount&) = delete;
StabilizedRefCount& operator=(StabilizedRefCount&&) = delete;
private:
RefCntT& mRefCnt;
};
+namespace detail {
+
+template <typename T>
+class InternalUnknown : public IUnknown
+{
+public:
+ STDMETHODIMP QueryInterface(REFIID aIid, void** aOutInterface) override
+ {
+ return This()->InternalQueryInterface(aIid, aOutInterface);
+ }
+
+ STDMETHODIMP_(ULONG) AddRef() override
+ {
+ return This()->InternalAddRef();
+ }
+
+ STDMETHODIMP_(ULONG) Release() override
+ {
+ return This()->InternalRelease();
+ }
+
+private:
+ T* This()
+ {
+ return reinterpret_cast<T*>(reinterpret_cast<char*>(this) -
+ offsetof(T, mInternalUnknown));
+ }
+};
+
+} // namespace detail
} // namespace mscom
} // namespace mozilla
+#define DECLARE_AGGREGATABLE(Type) \
+ public: \
+ STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override \
+ { return mOuter->QueryInterface(riid, ppv); } \
+ STDMETHODIMP_(ULONG) AddRef() override \
+ { return mOuter->AddRef(); } \
+ STDMETHODIMP_(ULONG) Release() override \
+ { return mOuter->Release(); } \
+ protected: \
+ STDMETHODIMP InternalQueryInterface(REFIID riid, void** ppv); \
+ STDMETHODIMP_(ULONG) InternalAddRef(); \
+ STDMETHODIMP_(ULONG) InternalRelease(); \
+ friend class mozilla::mscom::detail::InternalUnknown<Type>; \
+ mozilla::mscom::detail::InternalUnknown<Type> mInternalUnknown
+
#endif // mozilla_mscom_Aggregation_h
new file mode 100644
--- /dev/null
+++ b/ipc/mscom/IHandlerPayload.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_IHandlerPayload_h
+#define mozilla_mscom_IHandlerPayload_h
+
+#include <objidl.h>
+
+namespace mozilla {
+namespace mscom {
+
+struct HandlerPayload
+{
+ virtual STDMETHODIMP GetHandler(CLSID* aHandlerClsid) = 0;
+ virtual STDMETHODIMP GetHandlerPayloadSize(REFIID aIid,
+ IUnknown* aTarget,
+ DWORD* aOutPayloadSize) = 0;
+ virtual STDMETHODIMP WriteHandlerPayload(IStream* aStream, REFIID aIid,
+ IUnknown* aTarget) = 0;
+ virtual REFIID MarshalAs(REFIID aIid) = 0;
+};
+
+struct IHandlerPayload : public IUnknown
+ , public HandlerPayload
+{
+ virtual STDMETHODIMP Clone(IHandlerPayload** aOutNewPayload) = 0;
+};
+
+} // namespace mscom
+} // namespace mozilla
+
+#endif // mozilla_mscom_IHandlerPayload_h
--- a/ipc/mscom/Interceptor.cpp
+++ b/ipc/mscom/Interceptor.cpp
@@ -41,16 +41,17 @@ Interceptor::Create(STAUniquePtr<IUnknow
return intcpt->QueryInterface(aIid, aOutput);
}
Interceptor::Interceptor(STAUniquePtr<IUnknown> aTarget, IInterceptorSink* aSink)
: WeakReferenceSupport(WeakReferenceSupport::Flags::eDestroyOnMainThread)
, mTarget(Move(aTarget))
, mEventSink(aSink)
, mMutex("mozilla::mscom::Interceptor::mMutex")
+ , mStdMarshal(nullptr)
{
MOZ_ASSERT(aSink);
MOZ_ASSERT(!IsProxy(mTarget.get()));
RefPtr<IWeakReference> weakRef;
if (SUCCEEDED(GetWeakReference(getter_AddRefs(weakRef)))) {
aSink->SetInterceptor(weakRef);
}
}
@@ -62,16 +63,87 @@ Interceptor::~Interceptor()
MOZ_ASSERT(NS_IsMainThread());
for (uint32_t index = 0, len = mInterceptorMap.Length(); index < len; ++index) {
MapEntry& entry = mInterceptorMap[index];
entry.mInterceptor = nullptr;
entry.mTargetInterface->Release();
}
}
+HRESULT
+Interceptor::GetClassForHandler(DWORD aDestContext, void* aDestContextPtr,
+ CLSID* aHandlerClsid)
+{
+ if (aDestContextPtr || !aHandlerClsid ||
+ aDestContext == MSHCTX_DIFFERENTMACHINE) {
+ return E_INVALIDARG;
+ }
+ MOZ_ASSERT(mEventSink);
+ return mEventSink->GetHandler(aHandlerClsid);
+}
+
+HRESULT
+Interceptor::GetUnmarshalClass(REFIID riid, void* pv, DWORD dwDestContext,
+ void* pvDestContext, DWORD mshlflags,
+ CLSID* pCid)
+{
+ return mStdMarshal->GetUnmarshalClass(riid, pv, dwDestContext, pvDestContext,
+ mshlflags, pCid);
+}
+
+HRESULT
+Interceptor::GetMarshalSizeMax(REFIID riid, void* pv, DWORD dwDestContext,
+ void* pvDestContext, DWORD mshlflags,
+ DWORD* pSize)
+{
+ HRESULT hr = mStdMarshal->GetMarshalSizeMax(riid, pv, dwDestContext,
+ pvDestContext, mshlflags, pSize);
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ DWORD payloadSize = 0;
+ hr = mEventSink->GetHandlerPayloadSize(riid, mTarget.get(), &payloadSize);
+ *pSize += payloadSize;
+ return hr;
+}
+
+HRESULT
+Interceptor::MarshalInterface(IStream* pStm, REFIID riid, void* pv,
+ DWORD dwDestContext, void* pvDestContext,
+ DWORD mshlflags)
+{
+ HRESULT hr = mStdMarshal->MarshalInterface(pStm, riid, pv, dwDestContext,
+ pvDestContext, mshlflags);
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ return mEventSink->WriteHandlerPayload(pStm, riid, mTarget.get());
+}
+
+HRESULT
+Interceptor::UnmarshalInterface(IStream* pStm, REFIID riid,
+ void** ppv)
+{
+ return mStdMarshal->UnmarshalInterface(pStm, riid, ppv);
+}
+
+HRESULT
+Interceptor::ReleaseMarshalData(IStream* pStm)
+{
+ return mStdMarshal->ReleaseMarshalData(pStm);
+}
+
+HRESULT
+Interceptor::DisconnectObject(DWORD dwReserved)
+{
+ return mStdMarshal->DisconnectObject(dwReserved);
+}
+
Interceptor::MapEntry*
Interceptor::Lookup(REFIID aIid)
{
mMutex.AssertCurrentThreadOwns();
for (uint32_t index = 0, len = mInterceptorMap.Length(); index < len; ++index) {
if (mInterceptorMap[index].mIID == aIid) {
return &mInterceptorMap[index];
}
@@ -143,57 +215,60 @@ HRESULT
Interceptor::GetInterceptorForIID(REFIID aIid, void** aOutInterceptor)
{
if (!aOutInterceptor) {
return E_INVALIDARG;
}
if (aIid == IID_IUnknown) {
// Special case: When we see IUnknown, we just provide a reference to this
- *aOutInterceptor = static_cast<IInterceptor*>(this);
- AddRef();
+ RefPtr<IInterceptor> intcpt(this);
+ intcpt.forget(aOutInterceptor);
return S_OK;
}
+ REFIID interceptorIid = mEventSink->MarshalAs(aIid);
+
RefPtr<IUnknown> unkInterceptor;
IUnknown* interfaceForQILog = nullptr;
- // (1) Check to see if we already have an existing interceptor for aIid.
+ // (1) Check to see if we already have an existing interceptor for
+ // interceptorIid.
{ // Scope for lock
MutexAutoLock lock(mMutex);
- MapEntry* entry = Lookup(aIid);
+ MapEntry* entry = Lookup(interceptorIid);
if (entry) {
unkInterceptor = entry->mInterceptor;
interfaceForQILog = entry->mTargetInterface;
}
}
// (1a) A COM interceptor already exists for this interface, so all we need
// to do is run a QI on it.
if (unkInterceptor) {
// Technically we didn't actually execute a QI on the target interface, but
// for logging purposes we would like to record the fact that this interface
// was requested.
InterceptorLog::QI(S_OK, mTarget.get(), aIid, interfaceForQILog);
- return unkInterceptor->QueryInterface(aIid, aOutInterceptor);
+ return unkInterceptor->QueryInterface(interceptorIid, aOutInterceptor);
}
// (2) Obtain a new target interface.
// (2a) First, make sure that the target interface is available
// NB: We *MUST* query the correct interface! ICallEvents::Invoke casts its
// pvReceiver argument directly to the required interface! DO NOT assume
// that COM will use QI or upcast/downcast!
HRESULT hr;
STAUniquePtr<IUnknown> targetInterface;
IUnknown* rawTargetInterface = nullptr;
- hr = QueryInterfaceTarget(aIid, (void**)&rawTargetInterface);
+ hr = QueryInterfaceTarget(interceptorIid, (void**)&rawTargetInterface);
targetInterface.reset(rawTargetInterface);
InterceptorLog::QI(hr, mTarget.get(), aIid, targetInterface.get());
MOZ_ASSERT(SUCCEEDED(hr) || hr == E_NOINTERFACE);
if (FAILED(hr)) {
return hr;
}
// We *really* shouldn't be adding interceptors to proxies
@@ -201,17 +276,18 @@ Interceptor::GetInterceptorForIID(REFIID
// (3) Create a new COM interceptor to that interface that delegates its
// IUnknown to |this|.
// Raise the refcount for stabilization purposes during aggregation
RefPtr<IUnknown> kungFuDeathGrip(static_cast<IUnknown*>(
static_cast<WeakReferenceSupport*>(this)));
- hr = CreateInterceptor(aIid, kungFuDeathGrip, getter_AddRefs(unkInterceptor));
+ hr = CreateInterceptor(interceptorIid, kungFuDeathGrip,
+ getter_AddRefs(unkInterceptor));
if (FAILED(hr)) {
return hr;
}
// (4) Obtain the interceptor's ICallInterceptor interface and register our
// event sink.
RefPtr<ICallInterceptor> interceptor;
hr = unkInterceptor->QueryInterface(IID_ICallInterceptor,
@@ -226,31 +302,31 @@ Interceptor::GetInterceptorForIID(REFIID
}
// (5) Now that we have this new COM interceptor, insert it into the map.
{ // Scope for lock
MutexAutoLock lock(mMutex);
// We might have raced with another thread, so first check that we don't
// already have an entry for this
- MapEntry* entry = Lookup(aIid);
+ MapEntry* entry = Lookup(interceptorIid);
if (entry && entry->mInterceptor) {
unkInterceptor = entry->mInterceptor;
} else {
// MapEntry has a RefPtr to unkInterceptor, OTOH we must not touch the
// refcount for the target interface because we are just moving it into
// the map and its refcounting might not be thread-safe.
IUnknown* rawTargetInterface = targetInterface.release();
- mInterceptorMap.AppendElement(MapEntry(aIid,
+ mInterceptorMap.AppendElement(MapEntry(interceptorIid,
unkInterceptor,
rawTargetInterface));
}
}
- return unkInterceptor->QueryInterface(aIid, aOutInterceptor);
+ return unkInterceptor->QueryInterface(interceptorIid, aOutInterceptor);
}
HRESULT
Interceptor::QueryInterfaceTarget(REFIID aIid, void** aOutput)
{
// NB: This QI needs to run on the main thread because the target object
// is probably Gecko code that is not thread-safe. Note that this main
// thread invocation is *synchronous*.
@@ -270,19 +346,73 @@ HRESULT
Interceptor::QueryInterface(REFIID riid, void** ppv)
{
return WeakReferenceSupport::QueryInterface(riid, ppv);
}
HRESULT
Interceptor::ThreadSafeQueryInterface(REFIID aIid, IUnknown** aOutInterface)
{
+ if (aIid == IID_INoMarshal) {
+ // This entire library is designed around marshaling, so there's no point
+ // propagating this QI request all over the place!
+ return E_NOINTERFACE;
+ }
+
+ if (aIid == IID_IStdMarshalInfo) {
+ // Do not indicate that this interface is available unless we actually
+ // support it. We'll check that by looking for a successful call to
+ // IInterceptorSink::GetHandler()
+ CLSID dummy;
+ if (FAILED(mEventSink->GetHandler(&dummy))) {
+ return E_NOINTERFACE;
+ }
+
+ RefPtr<IStdMarshalInfo> std(this);
+ std.forget(aOutInterface);
+ return S_OK;
+ }
+
+ if (aIid == IID_IMarshal) {
+ // Do not indicate that this interface is available unless we actually
+ // support it. We'll check that by looking for a successful call to
+ // IInterceptorSink::GetHandler()
+ CLSID dummy;
+ if (FAILED(mEventSink->GetHandler(&dummy))) {
+ return E_NOINTERFACE;
+ }
+
+ if (!mStdMarshalUnk) {
+ HRESULT hr = ::CoGetStdMarshalEx(static_cast<IWeakReferenceSource*>(this),
+ SMEXF_SERVER,
+ getter_AddRefs(mStdMarshalUnk));
+ if (FAILED(hr)) {
+ return hr;
+ }
+ }
+
+ if (!mStdMarshal) {
+ HRESULT hr = mStdMarshalUnk->QueryInterface(IID_IMarshal,
+ (void**)&mStdMarshal);
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ // mStdMarshal is weak, so drop its refcount
+ mStdMarshal->Release();
+ }
+
+ RefPtr<IMarshal> marshal(this);
+ marshal.forget(aOutInterface);
+ return S_OK;
+ }
+
if (aIid == IID_IInterceptor) {
- *aOutInterface = static_cast<IInterceptor*>(this);
- (*aOutInterface)->AddRef();
+ RefPtr<IInterceptor> intcpt(this);
+ intcpt.forget(aOutInterface);
return S_OK;
}
if (aIid == IID_IDispatch) {
STAUniquePtr<IDispatch> disp;
IDispatch* rawDisp = nullptr;
HRESULT hr = QueryInterfaceTarget(aIid, (void**)&rawDisp);
if (FAILED(hr)) {
--- a/ipc/mscom/Interceptor.h
+++ b/ipc/mscom/Interceptor.h
@@ -1,34 +1,37 @@
/* -*- 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_interceptor_h
-#define mozilla_mscom_interceptor_h
+#ifndef mozilla_mscom_Interceptor_h
+#define mozilla_mscom_Interceptor_h
#include "mozilla/Move.h"
#include "mozilla/Mutex.h"
#include "nsTArray.h"
+#include "mozilla/mscom/IHandlerPayload.h"
#include "mozilla/mscom/Ptr.h"
#include "mozilla/mscom/WeakRef.h"
#include "mozilla/RefPtr.h"
+#include <objidl.h>
#include <callobj.h>
namespace mozilla {
namespace mscom {
// {8831EB53-A937-42BC-9921-B3E1121FDF86}
DEFINE_GUID(IID_IInterceptorSink,
0x8831eb53, 0xa937, 0x42bc, 0x99, 0x21, 0xb3, 0xe1, 0x12, 0x1f, 0xdf, 0x86);
struct IInterceptorSink : public ICallFrameEvents
+ , public HandlerPayload
{
virtual STDMETHODIMP SetInterceptor(IWeakReference* aInterceptor) = 0;
};
// {3710799B-ECA2-4165-B9B0-3FA1E4A9B230}
DEFINE_GUID(IID_IInterceptor,
0x3710799b, 0xeca2, 0x4165, 0xb9, 0xb0, 0x3f, 0xa1, 0xe4, 0xa9, 0xb2, 0x30);
@@ -52,27 +55,48 @@ struct IInterceptor : public IUnknown
* interpose QueryInterface calls so that we can instantiate a new
* ICallInterceptor for each new interface that is requested.
*
* We accomplish this by using COM aggregation, which means that the
* ICallInterceptor delegates its IUnknown implementation to its outer object
* (the mscom::Interceptor we implement and control).
*/
class Interceptor final : public WeakReferenceSupport
+ , public IStdMarshalInfo
+ , public IMarshal
, public IInterceptor
{
public:
static HRESULT Create(STAUniquePtr<IUnknown> aTarget, IInterceptorSink* aSink,
REFIID aIid, void** aOutput);
// IUnknown
STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override;
STDMETHODIMP_(ULONG) AddRef() override;
STDMETHODIMP_(ULONG) Release() override;
+ // IStdMarshalInfo
+ STDMETHODIMP GetClassForHandler(DWORD aDestContext, void* aDestContextPtr,
+ CLSID* aHandlerClsid) override;
+
+ // IMarshal
+ STDMETHODIMP GetUnmarshalClass(REFIID riid, void* pv, DWORD dwDestContext,
+ void* pvDestContext, DWORD mshlflags,
+ CLSID* pCid) override;
+ STDMETHODIMP GetMarshalSizeMax(REFIID riid, void* pv, DWORD dwDestContext,
+ void* pvDestContext, DWORD mshlflags,
+ DWORD* pSize) override;
+ STDMETHODIMP MarshalInterface(IStream* pStm, REFIID riid, void* pv,
+ DWORD dwDestContext, void* pvDestContext,
+ DWORD mshlflags) override;
+ STDMETHODIMP UnmarshalInterface(IStream* pStm, REFIID riid,
+ void** ppv) override;
+ STDMETHODIMP ReleaseMarshalData(IStream* pStm) override;
+ STDMETHODIMP DisconnectObject(DWORD dwReserved) override;
+
// IInterceptor
STDMETHODIMP GetTargetForIID(REFIID aIid, InterceptorTargetPtr& aTarget) override;
STDMETHODIMP GetInterceptorForIID(REFIID aIid, void** aOutInterceptor) override;
private:
struct MapEntry
{
MapEntry(REFIID aIid, IUnknown* aInterceptor, IUnknown* aTargetInterface)
@@ -95,16 +119,18 @@ private:
HRESULT CreateInterceptor(REFIID aIid, IUnknown* aOuter, IUnknown** aOutput);
private:
STAUniquePtr<IUnknown> mTarget;
RefPtr<IInterceptorSink> mEventSink;
mozilla::Mutex mMutex; // Guards mInterceptorMap
// Using a nsTArray since the # of interfaces is not going to be very high
nsTArray<MapEntry> mInterceptorMap;
+ RefPtr<IUnknown> mStdMarshalUnk;
+ IMarshal* mStdMarshal; // WEAK
};
template <typename InterfaceT>
inline HRESULT
CreateInterceptor(STAUniquePtr<InterfaceT> aTargetInterface,
IInterceptorSink* aEventSink,
InterfaceT** aOutInterface)
{
@@ -117,9 +143,9 @@ CreateInterceptor(STAUniquePtr<Interface
STAUniquePtr<IUnknown> targetUnknown(aTargetInterface.release());
return Interceptor::Create(Move(targetUnknown), aEventSink, iidTarget,
(void**)aOutInterface);
}
} // namespace mscom
} // namespace mozilla
-#endif // mozilla_mscom_interceptor_h
+#endif // mozilla_mscom_Interceptor_h
--- a/ipc/mscom/MainThreadHandoff.cpp
+++ b/ipc/mscom/MainThreadHandoff.cpp
@@ -1,69 +1,178 @@
/* -*- 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/MainThreadHandoff.h"
+#include "mozilla/Attributes.h"
#include "mozilla/Move.h"
+#include "mozilla/mscom/AgileReference.h"
#include "mozilla/mscom/InterceptorLog.h"
#include "mozilla/mscom/Registration.h"
#include "mozilla/mscom/Utils.h"
#include "mozilla/Assertions.h"
#include "mozilla/DebugOnly.h"
#include "nsThreadUtils.h"
using mozilla::DebugOnly;
+using mozilla::mscom::AgileReference;
namespace {
+class MOZ_NONHEAP_CLASS InParamWalker : private ICallFrameWalker
+{
+public:
+ InParamWalker()
+ : mPreHandoff(true)
+ {
+ }
+
+ void SetHandoffDone()
+ {
+ mPreHandoff = false;
+ mAgileRefsItr = mAgileRefs.begin();
+ }
+
+ HRESULT Walk(ICallFrame* aFrame)
+ {
+ MOZ_ASSERT(aFrame);
+ if (!aFrame) {
+ return E_INVALIDARG;
+ }
+
+ return aFrame->WalkFrame(CALLFRAME_WALK_IN, this);
+ }
+
+private:
+ // IUnknown
+ STDMETHODIMP QueryInterface(REFIID aIid, void** aOutInterface) override
+ {
+ if (!aOutInterface) {
+ return E_INVALIDARG;
+ }
+ *aOutInterface = nullptr;
+
+ if (aIid == IID_IUnknown || aIid == IID_ICallFrameWalker) {
+ *aOutInterface = static_cast<ICallFrameWalker*>(this);
+ return S_OK;
+ }
+
+ return E_NOINTERFACE;
+ }
+
+ STDMETHODIMP_(ULONG) AddRef() override
+ {
+ return 2;
+ }
+
+ STDMETHODIMP_(ULONG) Release() override
+ {
+ return 1;
+ }
+
+ // ICallFrameWalker
+ STDMETHODIMP OnWalkInterface(REFIID aIid, PVOID* aInterface, BOOL aIn,
+ BOOL aOut) override
+ {
+ MOZ_ASSERT(aIn);
+ if (!aIn) {
+ return E_UNEXPECTED;
+ }
+
+ IUnknown* origInterface = static_cast<IUnknown*>(*aInterface);
+ if (!origInterface) {
+ // Nothing to do
+ return S_OK;
+ }
+
+ if (mPreHandoff) {
+ mAgileRefs.AppendElement(AgileReference(aIid, origInterface));
+ return S_OK;
+ }
+
+ MOZ_ASSERT(mAgileRefsItr != mAgileRefs.end());
+ if (mAgileRefsItr == mAgileRefs.end()) {
+ return E_UNEXPECTED;
+ }
+
+ HRESULT hr = mAgileRefsItr->Resolve(aIid, aInterface);
+ MOZ_ASSERT(SUCCEEDED(hr));
+ if (SUCCEEDED(hr)) {
+ ++mAgileRefsItr;
+ }
+
+ return hr;
+ }
+
+ InParamWalker(const InParamWalker&) = delete;
+ InParamWalker(InParamWalker&&) = delete;
+ InParamWalker& operator=(const InParamWalker&) = delete;
+ InParamWalker& operator=(InParamWalker&&) = delete;
+
+private:
+ bool mPreHandoff;
+ AutoTArray<AgileReference, 1> mAgileRefs;
+ nsTArray<AgileReference>::iterator mAgileRefsItr;
+};
+
class HandoffRunnable : public mozilla::Runnable
{
public:
explicit HandoffRunnable(ICallFrame* aCallFrame, IUnknown* aTargetInterface)
: mCallFrame(aCallFrame)
, mTargetInterface(aTargetInterface)
, mResult(E_UNEXPECTED)
{
+ DebugOnly<HRESULT> hr = mInParamWalker.Walk(aCallFrame);
+ MOZ_ASSERT(SUCCEEDED(hr));
}
NS_IMETHOD Run() override
{
+ mInParamWalker.SetHandoffDone();
+ // We declare hr a DebugOnly because if mInParamWalker.Walk() fails, then
+ // mCallFrame->Invoke will fail anyway.
+ DebugOnly<HRESULT> hr = mInParamWalker.Walk(mCallFrame);
+ MOZ_ASSERT(SUCCEEDED(hr));
mResult = mCallFrame->Invoke(mTargetInterface);
return NS_OK;
}
HRESULT GetResult() const
{
return mResult;
}
private:
- ICallFrame* mCallFrame;
- IUnknown* mTargetInterface;
- HRESULT mResult;
+ ICallFrame* mCallFrame;
+ InParamWalker mInParamWalker;
+ IUnknown* mTargetInterface;
+ HRESULT mResult;
};
} // anonymous namespace
namespace mozilla {
namespace mscom {
/* static */ HRESULT
-MainThreadHandoff::Create(IInterceptorSink** aOutput)
+MainThreadHandoff::Create(IHandlerPayload* aHandlerPayload,
+ IInterceptorSink** aOutput)
{
- RefPtr<MainThreadHandoff> handoff(new MainThreadHandoff());
+ RefPtr<MainThreadHandoff> handoff(new MainThreadHandoff(aHandlerPayload));
return handoff->QueryInterface(IID_IInterceptorSink, (void**) aOutput);
}
-MainThreadHandoff::MainThreadHandoff()
+MainThreadHandoff::MainThreadHandoff(IHandlerPayload* aHandlerPayload)
: mRefCnt(0)
+ , mHandlerPayload(aHandlerPayload)
{
}
MainThreadHandoff::~MainThreadHandoff()
{
MOZ_ASSERT(NS_IsMainThread());
}
@@ -138,17 +247,17 @@ MainThreadHandoff::OnCall(ICallFrame* aF
}
InterceptorTargetPtr targetInterface;
hr = interceptor->GetTargetForIID(iid, targetInterface);
if (FAILED(hr)) {
return hr;
}
- // (2) Execute the method call syncrhonously on the main thread
+ // (2) Execute the method call synchronously on the main thread
RefPtr<HandoffRunnable> handoffInfo(new HandoffRunnable(aFrame,
targetInterface.get()));
MainThreadInvoker invoker;
if (!invoker.Invoke(do_AddRef(handoffInfo))) {
MOZ_ASSERT(false);
return E_UNEXPECTED;
}
hr = handoffInfo->GetResult();
@@ -292,16 +401,54 @@ MainThreadHandoff::FixArrayElements(ICal
HRESULT
MainThreadHandoff::SetInterceptor(IWeakReference* aInterceptor)
{
mInterceptor = aInterceptor;
return S_OK;
}
HRESULT
+MainThreadHandoff::GetHandler(CLSID* aHandlerClsid)
+{
+ if (!mHandlerPayload) {
+ return E_NOTIMPL;
+ }
+ return mHandlerPayload->GetHandler(aHandlerClsid);
+}
+
+HRESULT
+MainThreadHandoff::GetHandlerPayloadSize(REFIID aIid, IUnknown* aTarget,
+ DWORD* aOutPayloadSize)
+{
+ if (!mHandlerPayload) {
+ return E_NOTIMPL;
+ }
+ return mHandlerPayload->GetHandlerPayloadSize(aIid, aTarget, aOutPayloadSize);
+}
+
+HRESULT
+MainThreadHandoff::WriteHandlerPayload(IStream* aStream, REFIID aIid,
+ IUnknown* aTarget)
+{
+ if (!mHandlerPayload) {
+ return E_NOTIMPL;
+ }
+ return mHandlerPayload->WriteHandlerPayload(aStream, aIid, aTarget);
+}
+
+REFIID
+MainThreadHandoff::MarshalAs(REFIID aIid)
+{
+ if (!mHandlerPayload) {
+ return aIid;
+ }
+ return mHandlerPayload->MarshalAs(aIid);
+}
+
+HRESULT
MainThreadHandoff::OnWalkInterface(REFIID aIid, PVOID* aInterface,
BOOL aIsInParam, BOOL aIsOutParam)
{
MOZ_ASSERT(aInterface && aIsOutParam);
if (!aInterface || !aIsOutParam) {
return E_UNEXPECTED;
}
@@ -364,26 +511,37 @@ MainThreadHandoff::OnWalkInterface(REFII
if (FAILED(hr)) {
return hr;
}
*aInterface = intercepted;
return S_OK;
}
}
+ RefPtr<IHandlerPayload> payload;
+ if (mHandlerPayload) {
+ hr = mHandlerPayload->Clone(getter_AddRefs(payload));
+ MOZ_ASSERT(SUCCEEDED(hr));
+ if (FAILED(hr)) {
+ return hr;
+ }
+ }
+
// Now create a new MainThreadHandoff wrapper...
RefPtr<IInterceptorSink> handoff;
- hr = MainThreadHandoff::Create(getter_AddRefs(handoff));
+ hr = MainThreadHandoff::Create(payload, getter_AddRefs(handoff));
MOZ_ASSERT(SUCCEEDED(hr));
if (FAILED(hr)) {
return hr;
}
+ REFIID interceptorIid = payload ? payload->MarshalAs(aIid) : aIid;
+
RefPtr<IUnknown> wrapped;
- hr = Interceptor::Create(Move(origInterface), handoff, aIid,
+ hr = Interceptor::Create(Move(origInterface), handoff, interceptorIid,
getter_AddRefs(wrapped));
MOZ_ASSERT(SUCCEEDED(hr));
if (FAILED(hr)) {
return hr;
}
// And replace the original interface pointer with the wrapped one.
wrapped.forget(reinterpret_cast<IUnknown**>(aInterface));
--- a/ipc/mscom/MainThreadHandoff.h
+++ b/ipc/mscom/MainThreadHandoff.h
@@ -19,53 +19,72 @@ namespace mozilla {
namespace mscom {
struct ArrayData;
class MainThreadHandoff final : public IInterceptorSink
, public ICallFrameWalker
{
public:
- static HRESULT Create(IInterceptorSink** aOutput);
+ static HRESULT Create(IHandlerPayload* aHandlerPayload,
+ IInterceptorSink** aOutput);
template <typename Interface>
static HRESULT WrapInterface(STAUniquePtr<Interface> aTargetInterface,
Interface** aOutInterface)
{
+ return WrapInterface<Interface>(Move(aTargetInterface), nullptr,
+ aOutInterface);
+ }
+
+ template <typename Interface>
+ static HRESULT WrapInterface(STAUniquePtr<Interface> aTargetInterface,
+ IHandlerPayload* aHandlerPayload,
+ Interface** aOutInterface)
+ {
MOZ_ASSERT(!IsProxy(aTargetInterface.get()));
RefPtr<IInterceptorSink> handoff;
- HRESULT hr = MainThreadHandoff::Create(getter_AddRefs(handoff));
+ HRESULT hr = MainThreadHandoff::Create(aHandlerPayload,
+ getter_AddRefs(handoff));
if (FAILED(hr)) {
return hr;
}
return CreateInterceptor(Move(aTargetInterface), handoff, aOutInterface);
}
// IUnknown
STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override;
STDMETHODIMP_(ULONG) AddRef() override;
STDMETHODIMP_(ULONG) Release() override;
// ICallFrameEvents
STDMETHODIMP OnCall(ICallFrame* aFrame) override;
// IInterceptorSink
STDMETHODIMP SetInterceptor(IWeakReference* aInterceptor) override;
+ STDMETHODIMP GetHandler(CLSID* aHandlerClsid) override;
+ STDMETHODIMP GetHandlerPayloadSize(REFIID aIid,
+ IUnknown* aTarget,
+ DWORD* aOutPayloadSize) override;
+ STDMETHODIMP WriteHandlerPayload(IStream* aStream, REFIID aIid,
+ IUnknown* aTarget) override;
+ REFIID MarshalAs(REFIID aIid) override;
// ICallFrameWalker
STDMETHODIMP OnWalkInterface(REFIID aIid, PVOID* aInterface, BOOL aIsInParam,
BOOL aIsOutParam) override;
private:
- MainThreadHandoff();
+ explicit MainThreadHandoff(IHandlerPayload* aHandlerPayload);
~MainThreadHandoff();
HRESULT FixArrayElements(ICallFrame* aFrame,
const ArrayData& aArrayData);
private:
ULONG mRefCnt;
RefPtr<IWeakReference> mInterceptor;
+ RefPtr<IHandlerPayload> mHandlerPayload;
};
} // namespace mscom
} // namespace mozilla
#endif // mozilla_mscom_MainThreadHandoff_h
--- a/ipc/mscom/Registration.cpp
+++ b/ipc/mscom/Registration.cpp
@@ -364,26 +364,26 @@ RegisteredProxy::operator=(RegisteredPro
mRegCookie = aOther.mRegCookie;
aOther.mRegCookie = 0;
mTypeLib = aOther.mTypeLib;
aOther.mTypeLib = nullptr;
return *this;
}
HRESULT
-RegisteredProxy::GetTypeInfoForInterface(REFIID aIid,
- ITypeInfo** aOutTypeInfo) const
+RegisteredProxy::GetTypeInfoForGuid(REFGUID aGuid,
+ ITypeInfo** aOutTypeInfo) const
{
if (!aOutTypeInfo) {
return E_INVALIDARG;
}
if (!mTypeLib) {
return E_UNEXPECTED;
}
- return mTypeLib->lpVtbl->GetTypeInfoOfGuid(mTypeLib, aIid, aOutTypeInfo);
+ return mTypeLib->lpVtbl->GetTypeInfoOfGuid(mTypeLib, aGuid, aOutTypeInfo);
}
static StaticAutoPtr<Vector<RegisteredProxy*>> sRegistry;
namespace UseGetMutexForAccess {
// This must not be accessed directly; use GetMutex() instead
static CRITICAL_SECTION sMutex;
@@ -413,17 +413,17 @@ RegisteredProxy::Find(REFIID aIid, IType
{
AutoCriticalSection lock(GetMutex());
if (!sRegistry) {
return false;
}
for (auto&& proxy : *sRegistry) {
- if (SUCCEEDED(proxy->GetTypeInfoForInterface(aIid, aTypeInfo))) {
+ if (SUCCEEDED(proxy->GetTypeInfoForGuid(aIid, aTypeInfo))) {
return true;
}
}
return false;
}
/* static */ void
--- a/ipc/mscom/Registration.h
+++ b/ipc/mscom/Registration.h
@@ -31,17 +31,17 @@ public:
RegisteredProxy(IUnknown* aClassObject, uint32_t aRegCookie,
ITypeLib* aTypeLib);
explicit RegisteredProxy(ITypeLib* aTypeLib);
RegisteredProxy(RegisteredProxy&& aOther);
RegisteredProxy& operator=(RegisteredProxy&& aOther);
~RegisteredProxy();
- HRESULT GetTypeInfoForInterface(REFIID aIid, ITypeInfo** aOutTypeInfo) const;
+ HRESULT GetTypeInfoForGuid(REFGUID aGuid, ITypeInfo** aOutTypeInfo) const;
static bool Find(REFIID aIid, ITypeInfo** aOutTypeInfo);
private:
RegisteredProxy() = delete;
RegisteredProxy(RegisteredProxy&) = delete;
RegisteredProxy& operator=(RegisteredProxy&) = delete;
--- a/ipc/mscom/moz.build
+++ b/ipc/mscom/moz.build
@@ -24,16 +24,17 @@ UNIFIED_SOURCES += [
'ProxyStream.cpp',
'Utils.cpp',
]
if CONFIG['ACCESSIBILITY']:
EXPORTS.mozilla.mscom += [
'ActivationContext.h',
'DispatchForwarder.h',
+ 'IHandlerPayload.h',
'Interceptor.h',
'InterceptorLog.h',
'MainThreadHandoff.h',
'MainThreadInvoker.h',
'Registration.h',
'SpinEvent.h',
'StructStream.h',
'WeakRef.h',