mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 19:35:51 +00:00
Bug 1390652: Part 3 - Add proxy wrapper that passes its inner proxy through content as a blob; r=jimm
MozReview-Commit-ID: A4pAyiuJUlz
This commit is contained in:
parent
153e6759b5
commit
d7d645f5c4
@ -15,6 +15,8 @@
|
||||
#if defined(XP_WIN)
|
||||
#include "AccessibleWrap.h"
|
||||
#include "Compatibility.h"
|
||||
#include "mozilla/mscom/PassthruProxy.h"
|
||||
#include "mozilla/mscom/Ptr.h"
|
||||
#include "nsWinUtils.h"
|
||||
#include "RootAccessible.h"
|
||||
#endif
|
||||
@ -630,11 +632,12 @@ DocAccessibleParent::MaybeInitWindowEmulation()
|
||||
|
||||
SetEmulatedWindowHandle(aHwnd);
|
||||
|
||||
IAccessible* rawHWNDAcc = nullptr;
|
||||
RefPtr<IAccessible> hwndAcc;
|
||||
if (SUCCEEDED(::AccessibleObjectFromWindow(aHwnd, OBJID_WINDOW,
|
||||
IID_IAccessible,
|
||||
(void**)&rawHWNDAcc))) {
|
||||
hWndAccHolder.Set(IDispatchHolder::COMPtrType(rawHWNDAcc));
|
||||
getter_AddRefs(hwndAcc)))) {
|
||||
RefPtr<IDispatch> wrapped(mscom::PassthruProxy::Wrap<IDispatch>(WrapNotNull(hwndAcc)));
|
||||
hWndAccHolder.Set(IDispatchHolder::COMPtrType(mscom::ToProxyUniquePtr(Move(wrapped))));
|
||||
}
|
||||
|
||||
Unused << SendEmulatedWindow(reinterpret_cast<uintptr_t>(mEmulatedWindowHandle),
|
||||
@ -668,11 +671,13 @@ DocAccessibleParent::SendParentCOMProxy()
|
||||
return;
|
||||
}
|
||||
|
||||
IAccessible* rawNative = nullptr;
|
||||
outerDoc->GetNativeInterface((void**) &rawNative);
|
||||
MOZ_ASSERT(rawNative);
|
||||
RefPtr<IAccessible> nativeAcc;
|
||||
outerDoc->GetNativeInterface(getter_AddRefs(nativeAcc));
|
||||
MOZ_ASSERT(nativeAcc);
|
||||
|
||||
IDispatchHolder::COMPtrType ptr(rawNative);
|
||||
RefPtr<IDispatch> wrapped(mscom::PassthruProxy::Wrap<IDispatch>(WrapNotNull(nativeAcc)));
|
||||
|
||||
IDispatchHolder::COMPtrType ptr(mscom::ToProxyUniquePtr(Move(wrapped)));
|
||||
IDispatchHolder holder(Move(ptr));
|
||||
if (!PDocAccessibleParent::SendParentCOMProxy(holder)) {
|
||||
return;
|
||||
|
424
ipc/mscom/PassthruProxy.cpp
Normal file
424
ipc/mscom/PassthruProxy.cpp
Normal file
@ -0,0 +1,424 @@
|
||||
/* -*- 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/PassthruProxy.h"
|
||||
#include "mozilla/mscom/ProxyStream.h"
|
||||
#include "VTableBuilder.h"
|
||||
|
||||
// {96EF5801-CE6D-416E-A50A-0C2959AEAE1C}
|
||||
static const GUID CLSID_PassthruProxy =
|
||||
{ 0x96ef5801, 0xce6d, 0x416e, { 0xa5, 0xa, 0xc, 0x29, 0x59, 0xae, 0xae, 0x1c } };
|
||||
|
||||
namespace mozilla {
|
||||
namespace mscom {
|
||||
|
||||
PassthruProxy::PassthruProxy()
|
||||
: mRefCnt(0)
|
||||
, mWrappedIid()
|
||||
, mVTableSize(0)
|
||||
, mVTable(nullptr)
|
||||
, mForgetPreservedStream(false)
|
||||
{
|
||||
}
|
||||
|
||||
PassthruProxy::PassthruProxy(REFIID aIidToWrap, uint32_t aVTableSize,
|
||||
NotNull<IUnknown*> aObjToWrap)
|
||||
: mRefCnt(0)
|
||||
, mWrappedIid(aIidToWrap)
|
||||
, mVTableSize(aVTableSize)
|
||||
, mVTable(nullptr)
|
||||
, mForgetPreservedStream(false)
|
||||
{
|
||||
ProxyStream proxyStream(aIidToWrap, aObjToWrap,
|
||||
ProxyStreamFlags::ePreservable);
|
||||
mPreservedStream = Move(proxyStream.GetPreservedStream());
|
||||
MOZ_ASSERT(mPreservedStream);
|
||||
}
|
||||
|
||||
PassthruProxy::~PassthruProxy()
|
||||
{
|
||||
if (mForgetPreservedStream) {
|
||||
// We want to release the ref without clearing marshal data
|
||||
IStream* stream = mPreservedStream.release();
|
||||
stream->Release();
|
||||
}
|
||||
|
||||
if (mVTable) {
|
||||
DeleteNullVTable(mVTable);
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT
|
||||
PassthruProxy::QueryProxyInterface(void** aOutInterface)
|
||||
{
|
||||
// Even though we don't really provide the methods for the interface that
|
||||
// we are proxying, we need to support it in QueryInterface. Instead we
|
||||
// return an interface that, other than IUnknown, contains nullptr for all of
|
||||
// its vtable entires. Obviously this interface is not intended to actually
|
||||
// be called, it just has to be there.
|
||||
|
||||
if (!mVTable) {
|
||||
MOZ_ASSERT(mVTableSize);
|
||||
mVTable = BuildNullVTable(static_cast<IMarshal*>(this), mVTableSize);
|
||||
MOZ_ASSERT(mVTable);
|
||||
}
|
||||
|
||||
*aOutInterface = mVTable;
|
||||
mVTable->AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
PassthruProxy::QueryInterface(REFIID aIid, void** aOutInterface)
|
||||
{
|
||||
if (!aOutInterface) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
*aOutInterface = nullptr;
|
||||
|
||||
if (aIid == IID_IUnknown || aIid == IID_IMarshal) {
|
||||
RefPtr<IMarshal> ptr(this);
|
||||
ptr.forget(aOutInterface);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (!IsInitialMarshal()) {
|
||||
// We implement IClientSecurity so that IsProxy() recognizes us as such
|
||||
if (aIid == IID_IClientSecurity) {
|
||||
RefPtr<IClientSecurity> ptr(this);
|
||||
ptr.forget(aOutInterface);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (aIid == mWrappedIid) {
|
||||
return QueryProxyInterface(aOutInterface);
|
||||
}
|
||||
}
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
ULONG
|
||||
PassthruProxy::AddRef()
|
||||
{
|
||||
return ++mRefCnt;
|
||||
}
|
||||
|
||||
ULONG
|
||||
PassthruProxy::Release()
|
||||
{
|
||||
ULONG result = --mRefCnt;
|
||||
if (!result) {
|
||||
delete this;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
PassthruProxy::GetUnmarshalClass(REFIID riid, void* pv, DWORD dwDestContext,
|
||||
void* pvDestContext, DWORD mshlflags,
|
||||
CLSID* pCid)
|
||||
{
|
||||
if (!pCid) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
if (IsInitialMarshal()) {
|
||||
// To properly use this class we need to be using TABLESTRONG marshaling
|
||||
MOZ_ASSERT(mshlflags & MSHLFLAGS_TABLESTRONG);
|
||||
|
||||
// When we're marshaling for the first time, we identify ourselves as the
|
||||
// class to use for unmarshaling.
|
||||
*pCid = CLSID_PassthruProxy;
|
||||
} else {
|
||||
// Subsequent marshals use the standard marshaler.
|
||||
*pCid = CLSID_StdMarshal;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
PassthruProxy::GetMarshalSizeMax(REFIID riid, void* pv, DWORD dwDestContext,
|
||||
void* pvDestContext, DWORD mshlflags,
|
||||
DWORD* pSize)
|
||||
{
|
||||
STATSTG statstg;
|
||||
HRESULT hr;
|
||||
|
||||
if (!IsInitialMarshal()) {
|
||||
// If we are not the initial marshal then we are just copying mStream out
|
||||
// to the marshal stream, so we just use mStream's size.
|
||||
hr = mStream->Stat(&statstg, STATFLAG_NONAME);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
*pSize = statstg.cbSize.LowPart;
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
// To properly use this class we need to be using TABLESTRONG marshaling
|
||||
MOZ_ASSERT(mshlflags & MSHLFLAGS_TABLESTRONG);
|
||||
|
||||
if (!mPreservedStream) {
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
hr = mPreservedStream->Stat(&statstg, STATFLAG_NONAME);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
*pSize = statstg.cbSize.LowPart + sizeof(mVTableSize) + sizeof(mWrappedIid);
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
PassthruProxy::MarshalInterface(IStream* pStm, REFIID riid, void* pv,
|
||||
DWORD dwDestContext, void* pvDestContext,
|
||||
DWORD mshlflags)
|
||||
{
|
||||
MOZ_ASSERT(riid == mWrappedIid);
|
||||
if (riid != mWrappedIid) {
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(pv == mVTable);
|
||||
if (pv != mVTable) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
HRESULT hr;
|
||||
RefPtr<IStream> cloned;
|
||||
|
||||
if (IsInitialMarshal()) {
|
||||
// To properly use this class we need to be using TABLESTRONG marshaling
|
||||
MOZ_ASSERT(mshlflags & MSHLFLAGS_TABLESTRONG);
|
||||
|
||||
if (!mPreservedStream) {
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
// We write out the vtable size and the IID so that the wrapped proxy knows
|
||||
// how to build its vtable on the content side.
|
||||
ULONG bytesWritten;
|
||||
hr = pStm->Write(&mVTableSize, sizeof(mVTableSize), &bytesWritten);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
if (bytesWritten != sizeof(mVTableSize)) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
hr = pStm->Write(&mWrappedIid, sizeof(mWrappedIid), &bytesWritten);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
if (bytesWritten != sizeof(mWrappedIid)) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
hr = mPreservedStream->Clone(getter_AddRefs(cloned));
|
||||
} else {
|
||||
hr = mStream->Clone(getter_AddRefs(cloned));
|
||||
}
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
STATSTG statstg;
|
||||
hr = cloned->Stat(&statstg, STATFLAG_NONAME);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
// Copy the proxy data
|
||||
hr = cloned->CopyTo(pStm, statstg.cbSize, nullptr, nullptr);
|
||||
|
||||
if (SUCCEEDED(hr) && IsInitialMarshal() && mPreservedStream &&
|
||||
(mshlflags & MSHLFLAGS_TABLESTRONG)) {
|
||||
// If we have successfully copied mPreservedStream at least once for a
|
||||
// MSHLFLAGS_TABLESTRONG marshal, then we want to forget our reference to it.
|
||||
// This is because the COM runtime will manage it from here on out.
|
||||
mForgetPreservedStream = true;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
PassthruProxy::UnmarshalInterface(IStream* pStm, REFIID riid, void** ppv)
|
||||
{
|
||||
// Read out the interface info that we copied during marshaling
|
||||
ULONG bytesRead;
|
||||
HRESULT hr = pStm->Read(&mVTableSize, sizeof(mVTableSize), &bytesRead);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
if (bytesRead != sizeof(mVTableSize)) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
hr = pStm->Read(&mWrappedIid, sizeof(mWrappedIid), &bytesRead);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
if (bytesRead != sizeof(mWrappedIid)) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
// Now we copy the proxy inside pStm into mStream
|
||||
hr = CopySerializedProxy(pStm, getter_AddRefs(mStream));
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return QueryInterface(riid, ppv);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
PassthruProxy::ReleaseMarshalData(IStream* pStm)
|
||||
{
|
||||
if (!IsInitialMarshal()) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (!pStm) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
if (mPreservedStream) {
|
||||
// If we still have mPreservedStream, then simply clearing it will release
|
||||
// its marshal data automagically.
|
||||
mPreservedStream = nullptr;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Skip past the metadata that we wrote during initial marshaling.
|
||||
LARGE_INTEGER seekTo;
|
||||
seekTo.QuadPart = sizeof(mVTableSize) + sizeof(mWrappedIid);
|
||||
HRESULT hr = pStm->Seek(seekTo, STREAM_SEEK_CUR, nullptr);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
// Now release the "inner" marshal data
|
||||
return ::CoReleaseMarshalData(pStm);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
PassthruProxy::DisconnectObject(DWORD dwReserved)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// The remainder of this code is just boilerplate COM stuff that provides the
|
||||
// association between CLSID_PassthruProxy and the PassthruProxy class itself.
|
||||
|
||||
class PassthruProxyClassObject final : public IClassFactory
|
||||
{
|
||||
public:
|
||||
PassthruProxyClassObject();
|
||||
|
||||
// IUnknown
|
||||
STDMETHODIMP QueryInterface(REFIID aIid, void** aOutInterface) override;
|
||||
STDMETHODIMP_(ULONG) AddRef() override;
|
||||
STDMETHODIMP_(ULONG) Release() override;
|
||||
|
||||
// IClassFactory
|
||||
STDMETHODIMP CreateInstance(IUnknown* aOuter, REFIID aIid, void** aOutObject) override;
|
||||
STDMETHODIMP LockServer(BOOL aLock) override;
|
||||
|
||||
private:
|
||||
~PassthruProxyClassObject() = default;
|
||||
|
||||
Atomic<ULONG> mRefCnt;
|
||||
};
|
||||
|
||||
PassthruProxyClassObject::PassthruProxyClassObject()
|
||||
: mRefCnt(0)
|
||||
{
|
||||
}
|
||||
|
||||
HRESULT
|
||||
PassthruProxyClassObject::QueryInterface(REFIID aIid, void** aOutInterface)
|
||||
{
|
||||
if (!aOutInterface) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
*aOutInterface = nullptr;
|
||||
|
||||
if (aIid == IID_IUnknown || aIid == IID_IClassFactory) {
|
||||
RefPtr<IClassFactory> ptr(this);
|
||||
ptr.forget(aOutInterface);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
ULONG
|
||||
PassthruProxyClassObject::AddRef()
|
||||
{
|
||||
return ++mRefCnt;
|
||||
}
|
||||
|
||||
ULONG
|
||||
PassthruProxyClassObject::Release()
|
||||
{
|
||||
ULONG result = --mRefCnt;
|
||||
if (!result) {
|
||||
delete this;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
PassthruProxyClassObject::CreateInstance(IUnknown* aOuter, REFIID aIid,
|
||||
void** aOutObject)
|
||||
{
|
||||
// We don't expect to aggregate
|
||||
MOZ_ASSERT(!aOuter);
|
||||
if (aOuter) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
RefPtr<PassthruProxy> ptr(new PassthruProxy());
|
||||
return ptr->QueryInterface(aIid, aOutObject);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
PassthruProxyClassObject::LockServer(BOOL aLock)
|
||||
{
|
||||
// No-op since xul.dll is always in memory
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
/* static */ HRESULT
|
||||
PassthruProxy::Register()
|
||||
{
|
||||
DWORD cookie;
|
||||
RefPtr<IClassFactory> classObj(new PassthruProxyClassObject());
|
||||
return ::CoRegisterClassObject(CLSID_PassthruProxy, classObj,
|
||||
CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE,
|
||||
&cookie);
|
||||
}
|
||||
|
||||
} // namespace mscom
|
||||
} // namespace mozilla
|
||||
|
||||
HRESULT
|
||||
RegisterPassthruProxy()
|
||||
{
|
||||
return mozilla::mscom::PassthruProxy::Register();
|
||||
}
|
113
ipc/mscom/PassthruProxy.h
Normal file
113
ipc/mscom/PassthruProxy.h
Normal file
@ -0,0 +1,113 @@
|
||||
/* -*- 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_PassthruProxy_h
|
||||
#define mozilla_mscom_PassthruProxy_h
|
||||
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/NotNull.h"
|
||||
|
||||
#include <objbase.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace mscom {
|
||||
namespace detail {
|
||||
|
||||
template <typename Iface>
|
||||
struct VTableSizer;
|
||||
|
||||
template <>
|
||||
struct VTableSizer<IDispatch>
|
||||
{
|
||||
enum {
|
||||
Size = 7
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
class PassthruProxy final : public IMarshal
|
||||
, public IClientSecurity
|
||||
{
|
||||
public:
|
||||
template <typename Iface>
|
||||
static RefPtr<Iface> Wrap(NotNull<Iface*> aIn)
|
||||
{
|
||||
static_assert(detail::VTableSizer<Iface>::Size >= 3, "VTable too small");
|
||||
|
||||
RefPtr<PassthruProxy> passthru(new PassthruProxy(__uuidof(Iface),
|
||||
detail::VTableSizer<Iface>::Size,
|
||||
aIn));
|
||||
|
||||
RefPtr<Iface> result;
|
||||
if (FAILED(passthru->QueryProxyInterface(getter_AddRefs(result)))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static HRESULT Register();
|
||||
|
||||
PassthruProxy();
|
||||
|
||||
// IUnknown
|
||||
STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override;
|
||||
STDMETHODIMP_(ULONG) AddRef() override;
|
||||
STDMETHODIMP_(ULONG) Release() 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;
|
||||
|
||||
// IClientSecurity - we don't actually implement this interface, but its
|
||||
// presence signals to mscom::IsProxy() that we are a proxy.
|
||||
STDMETHODIMP QueryBlanket(IUnknown* aProxy, DWORD* aAuthnSvc,
|
||||
DWORD* aAuthzSvc, OLECHAR** aSrvPrincName,
|
||||
DWORD* aAuthnLevel, DWORD* aImpLevel,
|
||||
void** aAuthInfo, DWORD* aCapabilities) override
|
||||
{ return E_NOTIMPL; }
|
||||
|
||||
STDMETHODIMP SetBlanket(IUnknown* aProxy, DWORD aAuthnSvc, DWORD aAuthzSvc,
|
||||
OLECHAR* aSrvPrincName, DWORD aAuthnLevel,
|
||||
DWORD aImpLevel, void* aAuthInfo, DWORD aCapabilities) override
|
||||
{ return E_NOTIMPL; }
|
||||
|
||||
STDMETHODIMP CopyProxy(IUnknown* aProxy, IUnknown** aOutCopy) override
|
||||
{ return E_NOTIMPL; }
|
||||
|
||||
private:
|
||||
PassthruProxy(REFIID aIidToWrap, uint32_t aVTableSize,
|
||||
NotNull<IUnknown*> aObjToWrap);
|
||||
~PassthruProxy();
|
||||
|
||||
bool IsInitialMarshal() const { return !mStream; }
|
||||
HRESULT QueryProxyInterface(void** aOutInterface);
|
||||
|
||||
Atomic<ULONG> mRefCnt;
|
||||
IID mWrappedIid;
|
||||
PreservedStreamPtr mPreservedStream;
|
||||
RefPtr<IStream> mStream;
|
||||
uint32_t mVTableSize;
|
||||
IUnknown* mVTable;
|
||||
bool mForgetPreservedStream;
|
||||
};
|
||||
|
||||
} // namespace mscom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_mscom_PassthruProxy_h
|
@ -25,6 +25,7 @@
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/mscom/EnsureMTA.h"
|
||||
HRESULT RegisterPassthruProxy();
|
||||
#else
|
||||
#include <stdlib.h>
|
||||
#endif // defined(MOZILLA_INTERNAL_API)
|
||||
@ -152,6 +153,16 @@ RegisterProxy()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
hr = RegisterPassthruProxy();
|
||||
MOZ_ASSERT(SUCCEEDED(hr));
|
||||
if (FAILED(hr)) {
|
||||
CoRevokeClassObject(regCookie);
|
||||
classObject->lpVtbl->Release(classObject);
|
||||
return nullptr;
|
||||
}
|
||||
#endif // defined(MOZILLA_INTERNAL_API)
|
||||
|
||||
// RegisteredProxy takes ownership of classObject and typeLib references
|
||||
auto result(MakeUnique<RegisteredProxy>(classObject, regCookie, typeLib));
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* -*- 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
|
||||
|
65
ipc/mscom/VTableBuilder.c
Normal file
65
ipc/mscom/VTableBuilder.c
Normal file
@ -0,0 +1,65 @@
|
||||
/* -*- 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 "VTableBuilder.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE
|
||||
QueryInterfaceThunk(IUnknown* aThis, REFIID aIid, void** aOutInterface)
|
||||
{
|
||||
void** table = (void**) aThis;
|
||||
IUnknown* real = (IUnknown*) table[1];
|
||||
return real->lpVtbl->QueryInterface(real, aIid, aOutInterface);
|
||||
}
|
||||
|
||||
static ULONG STDMETHODCALLTYPE
|
||||
AddRefThunk(IUnknown* aThis)
|
||||
{
|
||||
void** table = (void**) aThis;
|
||||
IUnknown* real = (IUnknown*) table[1];
|
||||
return real->lpVtbl->AddRef(real);
|
||||
}
|
||||
|
||||
static ULONG STDMETHODCALLTYPE
|
||||
ReleaseThunk(IUnknown* aThis)
|
||||
{
|
||||
void** table = (void**) aThis;
|
||||
IUnknown* real = (IUnknown*) table[1];
|
||||
return real->lpVtbl->Release(real);
|
||||
}
|
||||
|
||||
IUnknown*
|
||||
BuildNullVTable(IUnknown* aUnk, uint32_t aVtblSize)
|
||||
{
|
||||
void** table;
|
||||
|
||||
if (aVtblSize < 3) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// We need to allocate slots for two additional pointers: The |lpVtbl| pointer,
|
||||
// as well as |aUnk| which is needed to get |this| right when something calls
|
||||
// through one of the IUnknown thunks.
|
||||
table = calloc(aVtblSize + 2, sizeof(void*));
|
||||
|
||||
table[0] = &table[2]; // |lpVtbl|, points to the first entry of the vtable
|
||||
table[1] = aUnk; // |this|
|
||||
// Now the actual vtable entries for IUnknown
|
||||
table[2] = &QueryInterfaceThunk;
|
||||
table[3] = &AddRefThunk;
|
||||
table[4] = &ReleaseThunk;
|
||||
// Remaining entries are NULL thanks to calloc zero-initializing everything.
|
||||
|
||||
return (IUnknown*) table;
|
||||
}
|
||||
|
||||
void
|
||||
DeleteNullVTable(IUnknown* aUnk)
|
||||
{
|
||||
free(aUnk);
|
||||
}
|
||||
|
37
ipc/mscom/VTableBuilder.h
Normal file
37
ipc/mscom/VTableBuilder.h
Normal file
@ -0,0 +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_VTableBuilder_h
|
||||
#define mozilla_mscom_VTableBuilder_h
|
||||
|
||||
#include <stdint.h>
|
||||
#include <Unknwn.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This function constructs an interface with |aVtblSize| entries, where the
|
||||
* IUnknown methods are valid and redirect to |aUnk|. Other than the IUnknown
|
||||
* methods, the resulting interface is not intended to actually be called; the
|
||||
* remaining vtable entries are null pointers to enforce that.
|
||||
*
|
||||
* @param aUnk The IUnknown to which the null vtable will redirect its IUnknown
|
||||
* methods.
|
||||
* @param aVtblSize The total size of the vtable, including the IUnknown
|
||||
* entries (thus this parameter must be >= 3).
|
||||
* @return The resulting IUnknown, or nullptr on error.
|
||||
*/
|
||||
IUnknown* BuildNullVTable(IUnknown* aUnk, uint32_t aVtblSize);
|
||||
|
||||
void DeleteNullVTable(IUnknown* aUnk);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // mozilla_mscom_VTableBuilder_h
|
@ -14,17 +14,23 @@ EXPORTS.mozilla.mscom += [
|
||||
'MainThreadClientInfo.h',
|
||||
'MainThreadRuntime.h',
|
||||
'Objref.h',
|
||||
'PassthruProxy.h',
|
||||
'ProxyStream.h',
|
||||
'Ptr.h',
|
||||
'Utils.h',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
'VTableBuilder.c',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'AgileReference.cpp',
|
||||
'EnsureMTA.cpp',
|
||||
'MainThreadClientInfo.cpp',
|
||||
'MainThreadRuntime.cpp',
|
||||
'Objref.cpp',
|
||||
'PassthruProxy.cpp',
|
||||
'ProxyStream.cpp',
|
||||
'Utils.cpp',
|
||||
]
|
||||
|
Loading…
Reference in New Issue
Block a user