Bug 1399557: Add Environment to mscom::ProxyStream and define it for IAccessible; r=jimm
authorAaron Klotz <aklotz@mozilla.com>
Fri, 29 Sep 2017 15:41:28 -0600
changeset 426611 f76f2dcae8f17bb43ff125b82b36c70a6cc2334d
parent 426610 3eca597f346fda5899c7da9237b1b35327b312d0
child 426612 6a6d995fd636907288b6528ae6e3717cb47e7301
push id97
push userfmarier@mozilla.com
push dateSat, 14 Oct 2017 01:12:59 +0000
reviewersjimm
bugs1399557
milestone58.0a1
Bug 1399557: Add Environment to mscom::ProxyStream and define it for IAccessible; r=jimm MozReview-Commit-ID: 4wBjnFW9GRa
accessible/ipc/win/COMPtrTypes.h
ipc/mscom/ActivationContext.cpp
ipc/mscom/ActivationContext.h
ipc/mscom/COMPtrHolder.h
ipc/mscom/PassthruProxy.cpp
ipc/mscom/PassthruProxy.h
ipc/mscom/ProxyStream.cpp
ipc/mscom/ProxyStream.h
--- a/accessible/ipc/win/COMPtrTypes.h
+++ b/accessible/ipc/win/COMPtrTypes.h
@@ -3,24 +3,72 @@
 /* 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_a11y_COMPtrTypes_h
 #define mozilla_a11y_COMPtrTypes_h
 
 #include "mozilla/a11y/AccessibleHandler.h"
+#include "mozilla/a11y/Compatibility.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/mscom/ActivationContext.h"
 #include "mozilla/mscom/COMPtrHolder.h"
 #include "mozilla/NotNull.h"
 
 #include <oleacc.h>
 
 namespace mozilla {
 namespace a11y {
 
+class MOZ_RAII IAccessibleEnvironment : public mscom::ProxyStream::Environment
+{
+public:
+  IAccessibleEnvironment() = default;
+
+  bool Push() override
+  {
+    mActCtxRgn = GetActCtx();
+    return !!mActCtxRgn;
+  }
+
+  bool Pop() override
+  {
+    return mActCtxRgn.Deactivate();
+  }
+
+private:
+  static const mscom::ActivationContext& GetActCtx()
+  {
+    static const mscom::ActivationContext
+      sActCtx(Compatibility::GetActCtxResourceId());
+    MOZ_DIAGNOSTIC_ASSERT(sActCtx);
+    return sActCtx;
+  }
+
+private:
+  mscom::ActivationContextRegion mActCtxRgn;
+};
+
+} // namespace a11y
+
+namespace mscom {
+namespace detail {
+
+template<>
+struct EnvironmentSelector<IAccessible>
+{
+  typedef a11y::IAccessibleEnvironment Type;
+};
+
+} // namespace detail
+} // namespace mscom
+
+namespace a11y {
+
 typedef mozilla::mscom::COMPtrHolder<IAccessible, IID_IAccessible> IAccessibleHolder;
 typedef mozilla::mscom::COMPtrHolder<IDispatch, IID_IDispatch> IDispatchHolder;
 
 class Accessible;
 
 IAccessibleHolder
 CreateHolderFromAccessible(NotNull<Accessible*> aAccToWrap);
 
--- a/ipc/mscom/ActivationContext.cpp
+++ b/ipc/mscom/ActivationContext.cpp
@@ -163,45 +163,96 @@ ActivationContext::GetCurrentManifestPat
   aOutManifestPath = nsDependentString(assemblyInfo->lpAssemblyManifestPath,
                                        (assemblyInfo->ulManifestPathLength + 1) / sizeof(wchar_t));
 
   return S_OK;
 }
 
 #endif // defined(MOZILLA_INTERNAL_API)
 
+ActivationContextRegion::ActivationContextRegion()
+  : mActCookie(0)
+{
+}
+
 ActivationContextRegion::ActivationContextRegion(const ActivationContext& aActCtx)
   : mActCtx(aActCtx)
   , mActCookie(0)
 {
   Activate();
 }
 
+ActivationContextRegion&
+ActivationContextRegion::operator=(const ActivationContext& aActCtx)
+{
+  Deactivate();
+  mActCtx = aActCtx;
+  Activate();
+  return *this;
+}
+
 ActivationContextRegion::ActivationContextRegion(ActivationContext&& aActCtx)
   : mActCtx(Move(aActCtx))
   , mActCookie(0)
 {
   Activate();
 }
 
+ActivationContextRegion&
+ActivationContextRegion::operator=(ActivationContext&& aActCtx)
+{
+  Deactivate();
+  mActCtx = Move(aActCtx);
+  Activate();
+  return *this;
+}
+
+ActivationContextRegion::ActivationContextRegion(ActivationContextRegion&& aRgn)
+  : mActCtx(Move(aRgn.mActCtx))
+  , mActCookie(aRgn.mActCookie)
+{
+  aRgn.mActCookie = 0;
+}
+
+ActivationContextRegion&
+ActivationContextRegion::operator=(ActivationContextRegion&& aRgn)
+{
+  Deactivate();
+  mActCtx = Move(aRgn.mActCtx);
+  mActCookie = aRgn.mActCookie;
+  aRgn.mActCookie = 0;
+  return *this;
+}
+
 void
 ActivationContextRegion::Activate()
 {
   if (mActCtx.mActCtx == INVALID_HANDLE_VALUE) {
     return;
   }
 
-  DebugOnly<BOOL> activated = ::ActivateActCtx(mActCtx.mActCtx, &mActCookie);
-  MOZ_ASSERT(activated);
+  BOOL activated = ::ActivateActCtx(mActCtx.mActCtx, &mActCookie);
+  MOZ_DIAGNOSTIC_ASSERT(activated);
+}
+
+bool
+ActivationContextRegion::Deactivate()
+{
+  if (!mActCookie) {
+    return true;
+  }
+
+  BOOL deactivated = ::DeactivateActCtx(0, mActCookie);
+  MOZ_DIAGNOSTIC_ASSERT(deactivated);
+  if (deactivated) {
+    mActCookie = 0;
+  }
+
+  return !!deactivated;
 }
 
 ActivationContextRegion::~ActivationContextRegion()
 {
-  if (!mActCookie) {
-    return;
-  }
-
-  DebugOnly<BOOL> deactivated = ::DeactivateActCtx(0, mActCookie);
-  MOZ_ASSERT(deactivated);
+  Deactivate();
 }
 
 } // namespace mscom
 } // namespace mozilla
--- a/ipc/mscom/ActivationContext.h
+++ b/ipc/mscom/ActivationContext.h
@@ -18,16 +18,21 @@
 #include <windows.h>
 
 namespace mozilla {
 namespace mscom {
 
 class ActivationContext final
 {
 public:
+  ActivationContext()
+    : mActCtx(INVALID_HANDLE_VALUE)
+  {
+  }
+
   explicit ActivationContext(WORD aResourceId);
   explicit ActivationContext(HMODULE aLoadFromModule, WORD aResourceId = 2);
 
   ActivationContext(ActivationContext&& aOther);
   ActivationContext& operator=(ActivationContext&& aOther);
 
   ActivationContext(const ActivationContext& aOther);
   ActivationContext& operator=(const ActivationContext& aOther);
@@ -61,24 +66,38 @@ public:
   template <typename... Args>
   explicit ActivationContextRegion(Args... aArgs)
     : mActCtx(Forward<Args>(aArgs)...)
     , mActCookie(0)
   {
     Activate();
   }
 
+  ActivationContextRegion();
+
   explicit ActivationContextRegion(const ActivationContext& aActCtx);
+  ActivationContextRegion& operator=(const ActivationContext& aActCtx);
+
   explicit ActivationContextRegion(ActivationContext&& aActCtx);
+  ActivationContextRegion& operator=(ActivationContext&& aActCtx);
+
+  ActivationContextRegion(ActivationContextRegion&& aRgn);
+  ActivationContextRegion& operator=(ActivationContextRegion&& aRgn);
+
   ~ActivationContextRegion();
 
+  explicit operator bool() const
+  {
+    return !!mActCookie;
+  }
+
   ActivationContextRegion(const ActivationContextRegion&) = delete;
-  ActivationContextRegion(ActivationContextRegion&&) = delete;
   ActivationContextRegion& operator=(const ActivationContextRegion&) = delete;
-  ActivationContextRegion& operator=(ActivationContextRegion&&) = delete;
+
+  bool Deactivate();
 
 private:
   void Activate();
 
   ActivationContext mActCtx;
   ULONG_PTR         mActCookie;
 };
 
--- a/ipc/mscom/COMPtrHolder.h
+++ b/ipc/mscom/COMPtrHolder.h
@@ -24,43 +24,55 @@ namespace mozilla {
 namespace mscom {
 
 template<typename Interface, const IID& _IID>
 class COMPtrHolder
 {
 public:
   typedef ProxyUniquePtr<Interface> COMPtrType;
   typedef COMPtrHolder<Interface, _IID> ThisType;
+  typedef typename detail::EnvironmentSelector<Interface>::Type EnvType;
 
   COMPtrHolder() {}
 
   MOZ_IMPLICIT COMPtrHolder(decltype(nullptr))
   {
   }
 
   explicit COMPtrHolder(COMPtrType&& aPtr)
     : mPtr(Forward<COMPtrType>(aPtr))
   {
   }
 
+  COMPtrHolder(COMPtrType&& aPtr, const ActivationContext& aActCtx)
+    : mPtr(Forward<COMPtrType>(aPtr))
+    , mActCtx(aActCtx)
+  {
+  }
+
   Interface* Get() const
   {
     return mPtr.get();
   }
 
   MOZ_MUST_USE Interface* Release()
   {
     return mPtr.release();
   }
 
   void Set(COMPtrType&& aPtr)
   {
     mPtr = Forward<COMPtrType>(aPtr);
   }
 
+  void SetActCtx(const ActivationContext& aActCtx)
+  {
+    mActCtx = aActCtx;
+  }
+
 #if defined(MOZ_CONTENT_SANDBOX)
   // This method is const because we need to call it during IPC write, where
   // we are passed as a const argument. At higher sandboxing levels we need to
   // save this artifact from the serialization process for later deletion.
   void PreserveStream(PreservedStreamPtr aPtr) const
   {
     MOZ_ASSERT(!mMarshaledStream);
     mMarshaledStream = Move(aPtr);
@@ -118,17 +130,18 @@ public:
 
   bool IsNull() const
   {
     return !mPtr;
   }
 
 private:
   // This is mutable to facilitate the above operator= hack
-  mutable COMPtrType mPtr;
+  mutable COMPtrType  mPtr;
+  ActivationContext   mActCtx;
 
 #if defined(MOZ_CONTENT_SANDBOX)
   // This is mutable so that we may optionally store a reference to a marshaled
   // stream to be cleaned up later via PreserveStream().
   mutable PreservedStreamPtr mMarshaledStream;
 #endif // defined(MOZ_CONTENT_SANDBOX)
 };
 
@@ -146,21 +159,23 @@ struct ParamTraits<mozilla::mscom::COMPt
   {
 #if defined(MOZ_CONTENT_SANDBOX)
     static const bool sIsStreamPreservationNeeded =
       XRE_IsParentProcess() && mozilla::GetEffectiveContentSandboxLevel() >= 3;
 #else
     const bool sIsStreamPreservationNeeded = false;
 #endif // defined(MOZ_CONTENT_SANDBOX)
 
+    paramType::EnvType env;
+
     mozilla::mscom::ProxyStreamFlags flags = sIsStreamPreservationNeeded ?
          mozilla::mscom::ProxyStreamFlags::ePreservable :
          mozilla::mscom::ProxyStreamFlags::eDefault;
 
-    mozilla::mscom::ProxyStream proxyStream(_IID, aParam.Get(), flags);
+    mozilla::mscom::ProxyStream proxyStream(_IID, aParam.Get(), &env, flags);
     int bufLen;
     const BYTE* buf = proxyStream.GetBuffer(bufLen);
     MOZ_ASSERT(buf || !bufLen);
     aMsg->WriteInt(bufLen);
     if (bufLen) {
       aMsg->WriteBytes(reinterpret_cast<const char*>(buf), bufLen);
     }
 
@@ -188,17 +203,19 @@ struct ParamTraits<mozilla::mscom::COMPt
     mozilla::UniquePtr<BYTE[]> buf;
     if (length) {
       buf = mozilla::MakeUnique<BYTE[]>(length);
       if (!aMsg->ReadBytesInto(aIter, buf.get(), length)) {
         return false;
       }
     }
 
-    mozilla::mscom::ProxyStream proxyStream(_IID, buf.get(), length);
+    paramType::EnvType env;
+
+    mozilla::mscom::ProxyStream proxyStream(_IID, buf.get(), length, &env);
     if (!proxyStream.IsValid()) {
 #if defined(MOZ_CRASHREPORTER)
       CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ProxyStreamValid"),
                                          NS_LITERAL_CSTRING("false"));
 #endif // defined(MOZ_CRASHREPORTER)
       return false;
     }
 
--- a/ipc/mscom/PassthruProxy.cpp
+++ b/ipc/mscom/PassthruProxy.cpp
@@ -19,25 +19,25 @@ PassthruProxy::PassthruProxy()
   : mRefCnt(0)
   , mWrappedIid()
   , mVTableSize(0)
   , mVTable(nullptr)
   , mForgetPreservedStream(false)
 {
 }
 
-PassthruProxy::PassthruProxy(REFIID aIidToWrap, uint32_t aVTableSize,
-                             NotNull<IUnknown*> aObjToWrap)
+PassthruProxy::PassthruProxy(ProxyStream::Environment* aEnv, REFIID aIidToWrap,
+                             uint32_t aVTableSize, NotNull<IUnknown*> aObjToWrap)
   : mRefCnt(0)
   , mWrappedIid(aIidToWrap)
   , mVTableSize(aVTableSize)
   , mVTable(nullptr)
   , mForgetPreservedStream(false)
 {
-  ProxyStream proxyStream(aIidToWrap, aObjToWrap,
+  ProxyStream proxyStream(aIidToWrap, aObjToWrap, aEnv,
                           ProxyStreamFlags::ePreservable);
   mPreservedStream = Move(proxyStream.GetPreservedStream());
   MOZ_ASSERT(mPreservedStream);
 }
 
 PassthruProxy::~PassthruProxy()
 {
   if (mForgetPreservedStream) {
--- a/ipc/mscom/PassthruProxy.h
+++ b/ipc/mscom/PassthruProxy.h
@@ -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/. */
 
 #ifndef mozilla_mscom_PassthruProxy_h
 #define mozilla_mscom_PassthruProxy_h
 
 #include "mozilla/Atomics.h"
+#include "mozilla/mscom/ProxyStream.h"
 #include "mozilla/mscom/Ptr.h"
 #include "mozilla/NotNull.h"
 
 #include <objbase.h>
 
 namespace mozilla {
 namespace mscom {
 namespace detail {
@@ -34,17 +35,19 @@ class PassthruProxy final : public IMars
                           , 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::EnvironmentSelector<Iface>::Type env;
+
+    RefPtr<PassthruProxy> passthru(new PassthruProxy(&env, __uuidof(Iface),
                                                      detail::VTableSizer<Iface>::Size,
                                                      aIn));
 
     RefPtr<Iface> result;
     if (FAILED(passthru->QueryProxyInterface(getter_AddRefs(result)))) {
       return nullptr;
     }
 
@@ -87,18 +90,18 @@ public:
                           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(ProxyStream::Environment* aEnv, 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;
--- a/ipc/mscom/ProxyStream.cpp
+++ b/ipc/mscom/ProxyStream.cpp
@@ -8,16 +8,17 @@
 #if defined(ACCESSIBILITY) && defined(MOZ_CRASHREPORTER)
 #include "HandlerData.h"
 #include "mozilla/a11y/Platform.h"
 #include "mozilla/mscom/ActivationContext.h"
 #endif // defined(ACCESSIBILITY) && defined(MOZ_CRASHREPORTER)
 #include "mozilla/mscom/EnsureMTA.h"
 #include "mozilla/mscom/ProxyStream.h"
 #include "mozilla/mscom/Utils.h"
+#include "mozilla/ScopeExit.h"
 
 #if defined(MOZ_CRASHREPORTER)
 #include "mozilla/mscom/Objref.h"
 #include "nsExceptionHandler.h"
 #include "nsPrintfCString.h"
 #include "RegistrationAnnotator.h"
 #endif
 
@@ -34,17 +35,17 @@ ProxyStream::ProxyStream()
   , mBufSize(0)
   , mPreserveStream(false)
 {
 }
 
 // GetBuffer() fails with this variant, but that's okay because we're just
 // reconstructing the stream from a buffer anyway.
 ProxyStream::ProxyStream(REFIID aIID, const BYTE* aInitBuf,
-                         const int aInitBufSize)
+                         const int aInitBufSize, Environment* aEnv)
   : mGlobalLockedBuf(nullptr)
   , mHGlobal(nullptr)
   , mBufSize(aInitBufSize)
   , mPreserveStream(false)
 {
 #if defined(MOZ_CRASHREPORTER)
   NS_NAMED_LITERAL_CSTRING(kCrashReportKey, "ProxyStreamUnmarshalStatus");
 #endif
@@ -88,21 +89,38 @@ ProxyStream::ProxyStream(REFIID aIID, co
 
   HRESULT unmarshalResult = S_OK;
 
   // We need to convert to an interface here otherwise we mess up const
   // correctness with IPDL. We'll request an IUnknown and then QI the
   // actual interface later.
 
 #if defined(ACCESSIBILITY) && defined(MOZ_CRASHREPORTER)
-  auto marshalFn = [this, &strActCtx, &manifestPath, &unmarshalResult, &aIID]() -> void
+  auto marshalFn = [this, &strActCtx, &manifestPath, &unmarshalResult, &aIID, aEnv]() -> void
 #else
-  auto marshalFn = [this, &unmarshalResult, &aIID]() -> void
+  auto marshalFn = [this, &unmarshalResult, &aIID, aEnv]() -> void
 #endif // defined(ACCESSIBILITY) && defined(MOZ_CRASHREPORTER)
   {
+    if (aEnv) {
+      bool pushOk = aEnv->Push();
+      MOZ_DIAGNOSTIC_ASSERT(pushOk);
+      if (!pushOk) {
+        return;
+      }
+    }
+
+    auto popEnv = MakeScopeExit([aEnv]() -> void {
+      if (!aEnv) {
+        return;
+      }
+
+      bool popOk = aEnv->Pop();
+      MOZ_DIAGNOSTIC_ASSERT(popOk);
+    });
+
 #if defined(ACCESSIBILITY) && defined(MOZ_CRASHREPORTER)
     auto curActCtx = ActivationContext::GetCurrent();
     if (curActCtx.isOk()) {
       strActCtx.AppendPrintf("0x%p", curActCtx.unwrap());
     } else {
       strActCtx.AppendPrintf("HRESULT 0x%08X", curActCtx.unwrapErr());
     }
 
@@ -264,17 +282,17 @@ ProxyStream::GetInterface(void** aOutInt
   if (!aOutInterface) {
     return false;
   }
 
   *aOutInterface = mUnmarshaledProxy.release();
   return true;
 }
 
-ProxyStream::ProxyStream(REFIID aIID, IUnknown* aObject,
+ProxyStream::ProxyStream(REFIID aIID, IUnknown* aObject, Environment* aEnv,
                          ProxyStreamFlags aFlags)
   : mGlobalLockedBuf(nullptr)
   , mHGlobal(nullptr)
   , mBufSize(0)
   , mPreserveStream(aFlags & ProxyStreamFlags::ePreservable)
 {
   if (!aObject) {
     return;
@@ -290,23 +308,40 @@ ProxyStream::ProxyStream(REFIID aIID, IU
   HRESULT statResult = S_OK;
   HRESULT getHGlobalResult = S_OK;
 
 #if defined(MOZ_CRASHREPORTER)
   nsAutoString manifestPath;
 
   auto marshalFn = [this, &aIID, aObject, mshlFlags, &stream, &streamSize,
                     &hglobal, &createStreamResult, &marshalResult, &statResult,
-                    &getHGlobalResult, &manifestPath]() -> void
+                    &getHGlobalResult, aEnv, &manifestPath]() -> void
 #else
   auto marshalFn = [this, &aIID, aObject, mshlFlags, &stream, &streamSize,
                     &hglobal, &createStreamResult, &marshalResult, &statResult,
-                    &getHGlobalResult]() -> void
+                    &getHGlobalResult, aEnv]() -> void
 #endif // defined(MOZ_CRASHREPORTER)
   {
+    if (aEnv) {
+      bool pushOk = aEnv->Push();
+      MOZ_DIAGNOSTIC_ASSERT(pushOk);
+      if (!pushOk) {
+        return;
+      }
+    }
+
+    auto popEnv = MakeScopeExit([aEnv]() -> void {
+      if (!aEnv) {
+        return;
+      }
+
+      bool popOk = aEnv->Pop();
+      MOZ_DIAGNOSTIC_ASSERT(popOk);
+    });
+
     createStreamResult = ::CreateStreamOnHGlobal(nullptr, TRUE,
                                                  getter_AddRefs(stream));
     if (FAILED(createStreamResult)) {
       return;
     }
 
 #if defined(MOZ_CRASHREPORTER)
     ActivationContext::GetCurrentManifestPath(manifestPath);
--- a/ipc/mscom/ProxyStream.h
+++ b/ipc/mscom/ProxyStream.h
@@ -25,20 +25,36 @@ enum class ProxyStreamFlags : uint32_t
   ePreservable = 1
 };
 
 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(ProxyStreamFlags);
 
 class ProxyStream final
 {
 public:
+  class MOZ_RAII Environment
+  {
+  public:
+    virtual ~Environment() = default;
+    virtual bool Push() = 0;
+    virtual bool Pop() = 0;
+  };
+
+  class MOZ_RAII DefaultEnvironment : public Environment
+  {
+  public:
+    bool Push() override { return true; }
+    bool Pop() override { return true; }
+  };
+
   ProxyStream();
-  ProxyStream(REFIID aIID, IUnknown* aObject,
+  ProxyStream(REFIID aIID, IUnknown* aObject, Environment* aEnv,
               ProxyStreamFlags aFlags = ProxyStreamFlags::eDefault);
-  ProxyStream(REFIID aIID, const BYTE* aInitBuf, const int aInitBufSize);
+  ProxyStream(REFIID aIID, const BYTE* aInitBuf, const int aInitBufSize,
+              Environment* aEnv);
 
   ~ProxyStream();
 
   // Not copyable because this would mess up the COM marshaling.
   ProxyStream(const ProxyStream& aOther) = delete;
   ProxyStream& operator=(const ProxyStream& aOther) = delete;
 
   ProxyStream(ProxyStream&& aOther);
@@ -63,12 +79,21 @@ private:
   RefPtr<IStream> mStream;
   BYTE*           mGlobalLockedBuf;
   HGLOBAL         mHGlobal;
   int             mBufSize;
   ProxyUniquePtr<IUnknown> mUnmarshaledProxy;
   bool            mPreserveStream;
 };
 
+namespace detail {
+
+template <typename Interface>
+struct EnvironmentSelector
+{
+  typedef ProxyStream::DefaultEnvironment Type;
+};
+
+} // namespace detail
 } // namespace mscom
 } // namespace mozilla
 
 #endif // mozilla_mscom_ProxyStream_h