IMarshal—Default Implementation

COM uses its own internal implementation of the IMarshal interface to marshal any object that does not provide its own implementation. COM makes this determination by querying the object for IMarshal. If the interface is missing, COM defaults to its internal implementation.

The COM default implementation of IMarshal uses a generic proxy for each object and creates individual stubs and proxies, as they are needed, for each interface implemented on the object. This mechanism is necessary because COM cannot know in advance what particular interfaces a given object may implement. Developers who do not use COM default marshaling, electing instead to write their own proxy and marshaling routines, know at compile time all the interfaces to be found on their objects and therefore understand exactly what marshaling code is required. COM, in providing marshaling support for all objects, must do so at run time.

The interface proxy resides in the client process; the interface stub resides in the server. Together, each pair handles all marshaling for the interface. The job of each interface proxy is to marshal arguments and unmarshal return values and out parameters that are passed back and forth in subsequent calls to its interface. The job of each interface stub is to unmarshal function arguments and pass them along to the original object and then marshal the return values and out parameters that the object returns.

Proxy and stub communicate by means of an RPC (remote procedure call) channel, which utilizes the system's RPC infrastructure for interprocess communication. The RPC channel implements a single interface, IRpcChannelBuffer, to which both interface proxies and stubs hold a pointer. The proxy and stub call the interface to obtain a marshaling packet, send the data to their counterpart, and destroy the packet when they are done. The interface stub also holds a pointer to the original object.

For any given interface, the proxy and stub are both implemented as instances of the same class, which is listed for each interface in the system registry under the label ProxyStubClsid32 (or ProxyStubClsid on 16-bit systems). This entry maps the interface's IID to the CLSID of its proxy and stub objects. When COM needs to marshal an interface, it looks in the system registry to obtain the appropriate CLSID. The server identified by this CLSID implements both the interface proxy and interface stub.

Most often, the class to which this CLSID refers is automatically generated by a tool whose input is a description of the function signatures and semantics of a given interface, written in some interface description language. While using such a language is highly recommended and encouraged for accuracy's sake, doing so is not required. Proxies and stubs are merely COM components used by the RPC infrastructure and, as such, can be written in any manner desired, as long as the correct external contracts are upheld. The programmer who designs a new interface is responsible for ensuring that all interface proxies and stubs that ever exist agree on the representation of their marshaled data.

When created, interface proxies are always aggregated into a larger proxy, which represents the object as a whole. This object proxy also aggregates the COM generic proxy object, which is known as the proxy manager. The proxy manager implements two interfaces: IUnknown and IMarshal. All of the other interfaces that may be implemented on an object are exposed in its object proxy through the aggregation of individual interface proxies. A client holding a pointer to the object proxy "believes" it holds a pointer to the actual object.

A proxy representing the object as a whole is required in the client process so that a client can distinguish calls to the same interfaces implemented on entirely different objects. Such a requirement does not exist in the server process, however, where the object itself resides, because all interface stubs communicate only with the objects for which they were created. No other connection is possible.

Interface stubs, by contrast with interface proxies, are not aggregated because there is no need that they appear to some external client to be part of a larger whole. When connected, an interface stub is given a pointer to the server object to which it should forward method invocations that it receives. Although it is useful to refer conceptually to a stub manager, meaning whatever pieces of code and state in the server-side RPC infrastructure that service the remoting of a given object, there is no direct requirement that the code and state take any particular, well-specified form.

The first time a client requests a pointer to an interface on a particular object, COM loads an IClassFactory stub in the server process and uses it to marshal the first pointer back to the client. In the client process, COM loads the generic proxy for the class factory object and calls its implementation of IMarshal to unmarshal that first pointer. COM then creates the first interface proxy and hands it a pointer to the RPC channel. Finally, COM returns the IClassFactory pointer to the client, which uses it to call IClassFactory::CreateInstance, passing it a reference to the interface.

Back in the server process, COM now creates a new instance of the object, along with a stub for the requested interface. This stub marshals the interface pointer back to the client process, where another object proxy is created, this time for the object itself. Also created is a proxy for the requested interface, a pointer to which is returned to the client. With subsequent calls to other interfaces on the object, COM will load the appropriate interface stubs and proxies as needed.

When a new interface proxy is created, COM hands it a pointer to the proxy manager's implementation of IUnknown, to which it delegates all QueryInterface calls. Each interface proxy implements two interfaces of its own: the interface it represents and IRpcProxyBuffer. The interface proxy exposes its own interface directly to clients, which can obtain its pointer by calling QueryInterface on the proxy manager. Only COM, however, can call IRpcProxyBuffer, which is used to connect and disconnect the proxy to the RPC channel. A client cannot query an interface proxy to obtain a pointer to the IRpcProxyBuffer interface.

On the server side, each interface stub implements IRpcStubBuffer. The server code acting as a stub manager calls IRpcStubBuffer::Connect and passes the interface stub the IUnknown pointer of its object.

When an interface proxy receives a method invocation, it obtains a marshaling packet from its RPC channel through a call to IRpcChannelBuffer::GetBuffer. The process of marshaling the arguments will copy data into the buffer. When marshaling is complete, the interface proxy invokes IRpcChannelBuffer::SendReceive to send the marshaled packet to the corresponding interface stub. When IRpcChannelBuffer::SendReceive returns, the buffer into which the arguments were marshaled will have been replaced by a new buffer containing the return values marshaled from the interface stub. The interface proxy unmarshals the return values, invokes IRpcChannelBuffer::FreeBuffer to free the buffer, and then returns the return values to the original caller of the method.

It is the implementation of IRpcChannelBuffer::SendReceive that actually sends the request to the server process and that knows how to identify the server process and, within that process, the object to which the request should be sent. The channel implementation also knows how to forward the request on to the appropriate stub manager in that process. The interface stub unmarshals the arguments from the provided buffer, invokes the indicated method on the server object, and marshals the return values back into a new buffer allocated by a call to IRpcchannelBuffer::GetBuffer. The channel then transmits the return data packet back to the interface proxy, which is still in the middle of IRpcchannelBuffer::SendReceive, which returns to the interface proxy.

A particular instance of an interface proxy can be used to service more than one interface, as long as the following conditions are met:

The IIDs of the affected interfaces must be mapped to the appropriate ProxyStubClsid in the system registry.

The interface proxy must support calls to QueryInterface from one supported interface to the other interfaces, as usual, as well as from IUnknown and IRpcProxyBuffer.

A single instance of an interface stub can also service more than one interface, but only if that set of interfaces has a strict single-inheritance relationship. This restriction exists because the stub can direct method invocations to multiple interfaces only where it knows in advance which methods are implemented on which interfaces.

At various times, proxies and stubs will have need to allocate or free memory. Interface proxies, for example, will need to allocate memory in which to return out parameters to their caller. In this respect, interface proxies and interface stubs are just normal COM components, in that they should use the standard task allocator. (See CoGetMalloc.)

You should use the COM default implementation of IMarshal except in those very few cases where your application has special requirements that the COM default implementation does not address, or where you can achieve optimizations over the marshaling code COM has provided. For examples of such special cases, see the "When to Implement" section for the IMarshal interface.