||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
instead of AddRef()/Release() in this class because we want to adjust the
refcount without causing any other side effects (like object destruction).
||This class encapsulates an "agile reference." These are references that
allow you to pass COM interfaces between apartments. When you have an
interface that you would like to pass between apartments, you wrap that
interface in an AgileReference and pass the agile reference instead. Then
you unwrap the interface by calling AgileReference::Resolve.
// In the multithreaded apartment, foo is an IFoo*
auto myAgileRef = MakeUnique<AgileReference>(IID_IFoo, foo);
// myAgileRef is passed to our main thread, which runs in a single-threaded
HRESULT hr = myAgileRef->Resolve(IID_IFoo, getter_AddRefs(foo));
// Now foo may be called from the main thread
||This constructor is to be used when we want to instantiate the object but
we do not yet know which type of apartment we want. Call Init() to
||This constructor just ensures that the MTA thread is up and running.
||COM ping functionality is enabled by default and is designed to free strong
references held by defunct client processes. However, this incurs a
significant performance penalty in a11y code due to large numbers of remote
objects being created and destroyed within a short period of time. Thus, we
turn off pings to improve performance.
ACHTUNG! When COM pings are disabled, Release calls from remote clients are
never sent to the server! If you use this marshaler, you *must* explicitly
disconnect clients using CoDisconnectObject when the object is no longer
relevant. Otherwise, references to the object will never be released, causing
||Determine whether this interface might be supported by objects using
This is used to avoid unnecessary cross-thread QueryInterface calls for
interfaces known to be unsupported.
Return S_OK if the interface might be supported, E_NOINTERFACE if it
definitely isn't supported.
||We don't use the normal XPCOM BaseAutoLock because we need the ability
to explicitly Unlock.
||The COM interceptor is the core functionality in mscom that allows us to
redirect method calls to different threads. It emulates the vtable of a
target interface. When a call is made on this emulated vtable, the call is
packaged up into an instance of the ICallFrame interface which may be passed
to other contexts for execution.
In order to accomplish this, COM itself provides the CoGetInterceptor
function, which instantiates an ICallInterceptor. Note, however, that
ICallInterceptor only works on a single interface; we need to be able to
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).
ACHTUNG! mscom::Interceptor uses FastMarshaler to disable COM garbage
collection. If you use this class, you *must* call
Interceptor::DisconnectRemotesForTarget when an object is no longer relevant.
Otherwise, the object will never be released, causing a leak.
||SyncRunnable implements different code paths depending on whether or not
we are running on a multiprocessor system. In the multiprocessor case, we
leave the thread in a spin loop while waiting for the main thread to execute
our runnable. Since spinning is pointless in the uniprocessor case, we block
on an event that is set by the main thread once it has finished the runnable.
||Given a buffer containing a serialized proxy to an interface with a handler,
this function strips out the handler and converts it to a standard one.
@param aStream IStream containing a serialized proxy.
There should be nothing else written to the stream past the
@param aStart Absolute position of the beginning of the OBJREF.
@param aEnd Absolute position of the end of the OBJREF.
@return true if the handler was successfully stripped, otherwise false.
||@return 0 if call is in-process or resolving the calling thread failed,
otherwise contains the thread id of the calling thread.
||IChannelHook exposes six methods: The Client* methods are called when
a client is sending an IPC request, whereas the Server* methods are called
when a server is receiving an IPC request.
For our purposes, we only care about the client-side methods. The COM
runtime invokes the methods in the following order:
1. ClientGetSize, where the hook specifies the size of its payload;
2. ClientFillBuffer, where the hook fills the channel's buffer with its
payload information. NOTE: This method is only called when ClientGetSize
specifies a non-zero payload size. For our purposes, since we are not
sending a payload, this method will never be called!
3. ClientNotify, when the response has been received from the server.
Since we want to use these hooks to record the beginning and end of a COM
IPC call, we use ClientGetSize for logging the start, and ClientNotify for
logging the end.
Finally, our implementation responds to any request matching our extension
ID, however we only care about main thread COM calls.
Further note that COM allows re-entrancy, however for our purposes we only
care about the outermost IPC call on the main thread, so we use the
mMainThreadORPCDepth variable to track that.
||The glue code in mozilla::mscom often needs to pass around interface pointers
belonging to a different apartment from the current one. We must not touch
the reference counts of those objects on the wrong apartment. By using these
UniquePtr specializations, we may ensure that the reference counts are always
||This code MUST NOT use any non-inlined internal Mozilla APIs, as it will be
compiled into DLLs that COM may load into non-Mozilla processes!
(1) The DLL exports GetProxyDllInfo. This is not exported by default; it must
be specified in the EXPORTS section of the DLL's module definition file.
||This function fails unless the entire string has been converted.
(eg, the string "FLAGS" will convert to 0xF but we will return false)
||These functions need to be defined in order for the types that use
mozilla::mscom::StructToStream and mozilla::mscom::StructFromStream to work.
||This code is used for (de)serializing data structures that have been
declared using midl, thus allowing us to use Microsoft RPC for marshaling
data for our COM handlers that may run in other processes that are not ours.
||Given a buffer, create a new IStream object.
@param aBuf Buffer containing data to initialize the stream. This parameter
may be nullptr, causing the stream to be created with aBufLen
bytes of uninitialized data.
@param aBufLen Length of data in aBuf, or desired stream size if aBuf is
@param aOutStream Outparam to receive the newly created stream.
@return HRESULT error code.
||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
@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.
||Thread-safe weak references for COM that works pre-Windows 8 and do not