зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1393589: Refactor NOPING marshaling into its own class, mscom::FastMarshaler, and use it with IGeckoBackChannel; r=jimm
MozReview-Commit-ID: 9osDoYcvtWV --HG-- extra : rebase_source : 9ead42f1b0c79f11b15121274a996d33d7ad4830
This commit is contained in:
Родитель
d7d645f5c4
Коммит
5921c2115b
|
@ -16,6 +16,7 @@
|
|||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/mscom/AgileReference.h"
|
||||
#include "mozilla/mscom/FastMarshaler.h"
|
||||
#include "mozilla/mscom/MainThreadInvoker.h"
|
||||
#include "mozilla/mscom/Ptr.h"
|
||||
#include "mozilla/mscom/StructStream.h"
|
||||
|
@ -43,18 +44,25 @@ HandlerProvider::QueryInterface(REFIID riid, void** ppv)
|
|||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
RefPtr<IUnknown> punk;
|
||||
|
||||
if (riid == IID_IUnknown || riid == IID_IGeckoBackChannel) {
|
||||
punk = static_cast<IGeckoBackChannel*>(this);
|
||||
RefPtr<IUnknown> punk(static_cast<IGeckoBackChannel*>(this));
|
||||
punk.forget(ppv);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (!punk) {
|
||||
return E_NOINTERFACE;
|
||||
if (riid == IID_IMarshal) {
|
||||
if (!mFastMarshalUnk) {
|
||||
HRESULT hr = mscom::FastMarshaler::Create(
|
||||
static_cast<IGeckoBackChannel*>(this), getter_AddRefs(mFastMarshalUnk));
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
return mFastMarshalUnk->QueryInterface(riid, ppv);
|
||||
}
|
||||
|
||||
punk.forget(ppv);
|
||||
return S_OK;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
ULONG
|
||||
|
|
|
@ -67,6 +67,7 @@ private:
|
|||
const IID mTargetUnkIid;
|
||||
mscom::InterceptorTargetPtr<IUnknown> mTargetUnk; // Constant, main thread only
|
||||
UniquePtr<mscom::StructToStream> mSerializer;
|
||||
RefPtr<IUnknown> mFastMarshalUnk;
|
||||
};
|
||||
|
||||
} // namespace a11y
|
||||
|
|
|
@ -0,0 +1,190 @@
|
|||
/* -*- 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/FastMarshaler.h"
|
||||
|
||||
#include "mozilla/mscom/Utils.h"
|
||||
|
||||
#include <objbase.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace mscom {
|
||||
|
||||
HRESULT
|
||||
FastMarshaler::Create(IUnknown* aOuter,
|
||||
IUnknown** aOutMarshalerUnk)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsContentProcess());
|
||||
|
||||
if (!aOuter || !aOutMarshalerUnk) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
*aOutMarshalerUnk = nullptr;
|
||||
|
||||
HRESULT hr;
|
||||
RefPtr<FastMarshaler> fm(new FastMarshaler(aOuter, &hr));
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return fm->InternalQueryInterface(IID_IUnknown, (void**)aOutMarshalerUnk);
|
||||
}
|
||||
|
||||
FastMarshaler::FastMarshaler(IUnknown* aOuter,
|
||||
HRESULT* aResult)
|
||||
: mRefCnt(0)
|
||||
, mOuter(aOuter)
|
||||
, mStdMarshalWeak(nullptr)
|
||||
{
|
||||
*aResult = ::CoGetStdMarshalEx(aOuter, SMEXF_SERVER,
|
||||
getter_AddRefs(mStdMarshalUnk));
|
||||
if (FAILED(*aResult)) {
|
||||
return;
|
||||
}
|
||||
|
||||
*aResult = mStdMarshalUnk->QueryInterface(IID_IMarshal,
|
||||
(void**)&mStdMarshalWeak);
|
||||
if (FAILED(*aResult)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// mStdMarshalWeak is weak
|
||||
mStdMarshalWeak->Release();
|
||||
}
|
||||
|
||||
HRESULT
|
||||
FastMarshaler::InternalQueryInterface(REFIID riid, void** ppv)
|
||||
{
|
||||
if (!ppv) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
if (riid == IID_IUnknown) {
|
||||
RefPtr<IUnknown> punk(static_cast<IUnknown*>(&mInternalUnknown));
|
||||
punk.forget(ppv);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (riid == IID_IMarshal) {
|
||||
RefPtr<IMarshal> ptr(this);
|
||||
ptr.forget(ppv);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return mStdMarshalUnk->QueryInterface(riid, ppv);
|
||||
}
|
||||
|
||||
ULONG
|
||||
FastMarshaler::InternalAddRef()
|
||||
{
|
||||
return ++mRefCnt;
|
||||
}
|
||||
|
||||
ULONG
|
||||
FastMarshaler::InternalRelease()
|
||||
{
|
||||
ULONG result = --mRefCnt;
|
||||
if (!result) {
|
||||
delete this;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DWORD
|
||||
FastMarshaler::GetMarshalFlags(DWORD aDestContext, DWORD aMshlFlags)
|
||||
{
|
||||
// Only worry about local contexts.
|
||||
if (aDestContext != MSHCTX_LOCAL) {
|
||||
return aMshlFlags;
|
||||
}
|
||||
|
||||
if (!IsCallerExternalProcess()) {
|
||||
return aMshlFlags;
|
||||
}
|
||||
|
||||
// The caller is our parent main thread. Disable ping functionality.
|
||||
return aMshlFlags | MSHLFLAGS_NOPING;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
FastMarshaler::GetUnmarshalClass(REFIID riid, void* pv, DWORD dwDestContext,
|
||||
void* pvDestContext, DWORD mshlflags,
|
||||
CLSID* pCid)
|
||||
{
|
||||
if (!mStdMarshalWeak) {
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
return mStdMarshalWeak->GetUnmarshalClass(riid, pv, dwDestContext,
|
||||
pvDestContext,
|
||||
GetMarshalFlags(dwDestContext,
|
||||
mshlflags), pCid);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
FastMarshaler::GetMarshalSizeMax(REFIID riid, void* pv, DWORD dwDestContext,
|
||||
void* pvDestContext, DWORD mshlflags,
|
||||
DWORD* pSize)
|
||||
{
|
||||
if (!mStdMarshalWeak) {
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
return mStdMarshalWeak->GetMarshalSizeMax(riid, pv, dwDestContext,
|
||||
pvDestContext,
|
||||
GetMarshalFlags(dwDestContext,
|
||||
mshlflags), pSize);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
FastMarshaler::MarshalInterface(IStream* pStm, REFIID riid, void* pv,
|
||||
DWORD dwDestContext, void* pvDestContext,
|
||||
DWORD mshlflags)
|
||||
{
|
||||
if (!mStdMarshalWeak) {
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
return mStdMarshalWeak->MarshalInterface(pStm, riid, pv, dwDestContext,
|
||||
pvDestContext,
|
||||
GetMarshalFlags(dwDestContext,
|
||||
mshlflags));
|
||||
}
|
||||
|
||||
HRESULT
|
||||
FastMarshaler::UnmarshalInterface(IStream* pStm, REFIID riid, void** ppv)
|
||||
{
|
||||
if (!mStdMarshalWeak) {
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
return mStdMarshalWeak->UnmarshalInterface(pStm, riid, ppv);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
FastMarshaler::ReleaseMarshalData(IStream* pStm)
|
||||
{
|
||||
if (!mStdMarshalWeak) {
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
return mStdMarshalWeak->ReleaseMarshalData(pStm);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
FastMarshaler::DisconnectObject(DWORD dwReserved)
|
||||
{
|
||||
if (!mStdMarshalWeak) {
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
return mStdMarshalWeak->DisconnectObject(dwReserved);
|
||||
}
|
||||
|
||||
} // namespace mscom
|
||||
} // namespace mozilla
|
|
@ -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/. */
|
||||
|
||||
#ifndef mozilla_mscom_FastMarshaler_h
|
||||
#define mozilla_mscom_FastMarshaler_h
|
||||
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/mscom/Aggregation.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
#include <objidl.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace mscom {
|
||||
|
||||
/**
|
||||
* When we are marshaling to the parent process main thread, we want to turn
|
||||
* off COM's ping functionality. That functionality is designed to free
|
||||
* strong references held by defunct client processes. Since our content
|
||||
* processes cannot outlive our parent process, we turn off pings when we know
|
||||
* that the COM client is going to be our parent process. This provides a
|
||||
* significant performance boost in a11y code due to large numbers of remote
|
||||
* objects being created and destroyed within a short period of time.
|
||||
*/
|
||||
class FastMarshaler final : public IMarshal
|
||||
{
|
||||
public:
|
||||
static HRESULT Create(IUnknown* aOuter,
|
||||
IUnknown** aOutMarshalerUnk);
|
||||
|
||||
// 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;
|
||||
|
||||
private:
|
||||
FastMarshaler(IUnknown* aOuter, HRESULT* aResult);
|
||||
~FastMarshaler() = default;
|
||||
|
||||
static DWORD GetMarshalFlags(DWORD aDestContext, DWORD aMshlFlags);
|
||||
|
||||
Atomic<ULONG> mRefCnt;
|
||||
IUnknown* mOuter;
|
||||
RefPtr<IUnknown> mStdMarshalUnk;
|
||||
IMarshal* mStdMarshalWeak;
|
||||
DECLARE_AGGREGATABLE(FastMarshaler);
|
||||
};
|
||||
|
||||
} // namespace mscom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_mscom_FastMarshaler_h
|
|
@ -9,6 +9,7 @@
|
|||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/mscom/DispatchForwarder.h"
|
||||
#include "mozilla/mscom/FastMarshaler.h"
|
||||
#include "mozilla/mscom/Interceptor.h"
|
||||
#include "mozilla/mscom/InterceptorLog.h"
|
||||
#include "mozilla/mscom/MainThreadInvoker.h"
|
||||
|
@ -192,49 +193,13 @@ Interceptor::GetClassForHandler(DWORD aDestContext, void* aDestContextPtr,
|
|||
return mEventSink->GetHandler(WrapNotNull(aHandlerClsid));
|
||||
}
|
||||
|
||||
/**
|
||||
* When we are marshaling to the parent process main thread, we want to turn
|
||||
* off COM's ping functionality. That functionality is designed to free
|
||||
* strong references held by defunct client processes. Since our content
|
||||
* processes cannot outlive our parent process, we turn off pings when we know
|
||||
* that the COM client is going to be our parent process. This provides a
|
||||
* significant performance boost in a11y code due to large numbers of remote
|
||||
* objects being created and destroyed within a short period of time.
|
||||
*/
|
||||
DWORD
|
||||
Interceptor::GetMarshalFlags(DWORD aDestContext, DWORD aMarshalFlags)
|
||||
{
|
||||
// Only worry about local contexts.
|
||||
if (aDestContext != MSHCTX_LOCAL) {
|
||||
return aMarshalFlags;
|
||||
}
|
||||
|
||||
// Get the caller TID. We check for S_FALSE to ensure that the caller is a
|
||||
// different process from ours, which is the only scenario we care about.
|
||||
DWORD callerTid;
|
||||
if (::CoGetCallerTID(&callerTid) != S_FALSE) {
|
||||
return aMarshalFlags;
|
||||
}
|
||||
|
||||
// Now we compare the caller TID to our parent main thread TID.
|
||||
const DWORD chromeMainTid =
|
||||
dom::ContentChild::GetSingleton()->GetChromeMainThreadId();
|
||||
if (callerTid != chromeMainTid) {
|
||||
return aMarshalFlags;
|
||||
}
|
||||
|
||||
// The caller is our parent main thread. Disable ping functionality.
|
||||
return aMarshalFlags | MSHLFLAGS_NOPING;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
Interceptor::GetUnmarshalClass(REFIID riid, void* pv, DWORD dwDestContext,
|
||||
void* pvDestContext, DWORD mshlflags,
|
||||
CLSID* pCid)
|
||||
{
|
||||
return mStdMarshal->GetUnmarshalClass(riid, pv, dwDestContext, pvDestContext,
|
||||
GetMarshalFlags(dwDestContext,
|
||||
mshlflags), pCid);
|
||||
mshlflags, pCid);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
|
@ -243,10 +208,7 @@ Interceptor::GetMarshalSizeMax(REFIID riid, void* pv, DWORD dwDestContext,
|
|||
DWORD* pSize)
|
||||
{
|
||||
HRESULT hr = mStdMarshal->GetMarshalSizeMax(riid, pv, dwDestContext,
|
||||
pvDestContext,
|
||||
GetMarshalFlags(dwDestContext,
|
||||
mshlflags),
|
||||
pSize);
|
||||
pvDestContext, mshlflags, pSize);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
@ -285,44 +247,30 @@ Interceptor::MarshalInterface(IStream* pStm, REFIID riid, void* pv,
|
|||
#endif // defined(MOZ_MSCOM_REMARSHAL_NO_HANDLER)
|
||||
|
||||
hr = mStdMarshal->MarshalInterface(pStm, riid, pv, dwDestContext,
|
||||
pvDestContext,
|
||||
GetMarshalFlags(dwDestContext, mshlflags));
|
||||
pvDestContext, mshlflags);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
#if defined(MOZ_MSCOM_REMARSHAL_NO_HANDLER)
|
||||
if (XRE_IsContentProcess()) {
|
||||
const DWORD chromeMainTid =
|
||||
dom::ContentChild::GetSingleton()->GetChromeMainThreadId();
|
||||
if (XRE_IsContentProcess() && IsCallerExternalProcess()) {
|
||||
// The caller isn't our chrome process, so do not provide a handler.
|
||||
|
||||
/*
|
||||
* CoGetCallerTID() gives us the caller's thread ID when that thread resides
|
||||
* in a single-threaded apartment. Since our chrome main thread does live
|
||||
* inside an STA, we will therefore be able to check whether the caller TID
|
||||
* equals our chrome main thread TID. This enables us to distinguish
|
||||
* between our chrome thread vs other out-of-process callers.
|
||||
*/
|
||||
DWORD callerTid;
|
||||
if (::CoGetCallerTID(&callerTid) == S_FALSE && callerTid != chromeMainTid) {
|
||||
// The caller isn't our chrome process, so do not provide a handler.
|
||||
|
||||
// First, save the current position that marks the current end of the
|
||||
// OBJREF in the stream.
|
||||
ULARGE_INTEGER endPos;
|
||||
hr = pStm->Seek(seekTo, STREAM_SEEK_CUR, &endPos);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
// Now strip out the handler.
|
||||
if (!StripHandlerFromOBJREF(WrapNotNull(pStm), objrefPos.QuadPart,
|
||||
endPos.QuadPart)) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
// First, save the current position that marks the current end of the
|
||||
// OBJREF in the stream.
|
||||
ULARGE_INTEGER endPos;
|
||||
hr = pStm->Seek(seekTo, STREAM_SEEK_CUR, &endPos);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
// Now strip out the handler.
|
||||
if (!StripHandlerFromOBJREF(WrapNotNull(pStm), objrefPos.QuadPart,
|
||||
endPos.QuadPart)) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
#endif // defined(MOZ_MSCOM_REMARSHAL_NO_HANDLER)
|
||||
|
||||
|
@ -648,18 +596,24 @@ Interceptor::ThreadSafeQueryInterface(REFIID aIid, IUnknown** aOutInterface)
|
|||
}
|
||||
|
||||
if (aIid == IID_IMarshal) {
|
||||
HRESULT hr;
|
||||
|
||||
if (!mStdMarshalUnk) {
|
||||
HRESULT hr = ::CoGetStdMarshalEx(static_cast<IWeakReferenceSource*>(this),
|
||||
SMEXF_SERVER,
|
||||
getter_AddRefs(mStdMarshalUnk));
|
||||
if (XRE_IsContentProcess()) {
|
||||
hr = FastMarshaler::Create(static_cast<IWeakReferenceSource*>(this),
|
||||
getter_AddRefs(mStdMarshalUnk));
|
||||
} else {
|
||||
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);
|
||||
hr = mStdMarshalUnk->QueryInterface(IID_IMarshal, (void**)&mStdMarshal);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
|
|
@ -130,8 +130,6 @@ private:
|
|||
IUnknown** aOutInterface) override;
|
||||
HRESULT CreateInterceptor(REFIID aIid, IUnknown* aOuter, IUnknown** aOutput);
|
||||
|
||||
static DWORD GetMarshalFlags(DWORD aDestContext, DWORD aMarshalFlags);
|
||||
|
||||
private:
|
||||
InterceptorTargetPtr<IUnknown> mTarget;
|
||||
RefPtr<IInterceptorSink> mEventSink;
|
||||
|
|
|
@ -4,6 +4,10 @@
|
|||
* 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/. */
|
||||
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#endif
|
||||
|
||||
#if defined(ACCESSIBILITY)
|
||||
#include "mozilla/mscom/Registration.h"
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
|
@ -238,6 +242,31 @@ GUIDToString(REFGUID aGuid, nsAString& aOutString)
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
IsCallerExternalProcess()
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsContentProcess());
|
||||
|
||||
/**
|
||||
* CoGetCallerTID() gives us the caller's thread ID when that thread resides
|
||||
* in a single-threaded apartment. Since our chrome main thread does live
|
||||
* inside an STA, we will therefore be able to check whether the caller TID
|
||||
* equals our chrome main thread TID. This enables us to distinguish
|
||||
* between our chrome thread vs other out-of-process callers. We check for
|
||||
* S_FALSE to ensure that the caller is a different process from ours, which
|
||||
* is the only scenario that we care about.
|
||||
*/
|
||||
DWORD callerTid;
|
||||
if (::CoGetCallerTID(&callerTid) != S_FALSE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now check whether the caller is our parent process main thread.
|
||||
const DWORD parentMainTid =
|
||||
dom::ContentChild::GetSingleton()->GetChromeMainThreadId();
|
||||
return callerTid != parentMainTid;
|
||||
}
|
||||
|
||||
#endif // defined(MOZILLA_INTERNAL_API)
|
||||
|
||||
#if defined(ACCESSIBILITY)
|
||||
|
|
|
@ -48,6 +48,7 @@ uint32_t CopySerializedProxy(IStream* aInStream, IStream** aOutStream);
|
|||
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
void GUIDToString(REFGUID aGuid, nsAString& aOutString);
|
||||
bool IsCallerExternalProcess();
|
||||
#endif // defined(MOZILLA_INTERNAL_API)
|
||||
|
||||
#if defined(ACCESSIBILITY)
|
||||
|
|
|
@ -11,6 +11,7 @@ EXPORTS.mozilla.mscom += [
|
|||
'COMApartmentRegion.h',
|
||||
'COMPtrHolder.h',
|
||||
'EnsureMTA.h',
|
||||
'FastMarshaler.h',
|
||||
'MainThreadClientInfo.h',
|
||||
'MainThreadRuntime.h',
|
||||
'Objref.h',
|
||||
|
@ -27,6 +28,7 @@ SOURCES += [
|
|||
UNIFIED_SOURCES += [
|
||||
'AgileReference.cpp',
|
||||
'EnsureMTA.cpp',
|
||||
'FastMarshaler.cpp',
|
||||
'MainThreadClientInfo.cpp',
|
||||
'MainThreadRuntime.cpp',
|
||||
'Objref.cpp',
|
||||
|
|
Загрузка…
Ссылка в новой задаче