Enables a COM object to define and manage the marshaling of its interface pointers.
The IMarshal interface has these methods.
|IMarshal::DisconnectObject||Releases all connections to an object. The object's server calls the object's implementation of this method prior to shutting down.|
|IMarshal::GetMarshalSizeMax||Retrieves the maximum size of the buffer that will be needed during marshaling.|
|IMarshal::GetUnmarshalClass||Retrieves the CLSID of the unmarshaling code.|
|IMarshal::MarshalInterface||Marshals an interface pointer.|
|IMarshal::ReleaseMarshalData||Destroys a marshaled data packet.|
|IMarshal::UnmarshalInterface||Unmarshals an interface pointer.|
Marshaling is the process of packaging data into packets for transmission to a different process or computer. Unmarshaling is the process of recovering that data at the receiving end. In any given call, method arguments are marshaled and unmarshaled in one direction, while return values are marshaled and unmarshaled in the other.
Although marshaling applies to all data types, interface pointers require special handling. The fundamental problem is how client code running in one address space can correctly dereference a pointer to an interface on an object residing in a different address space. The COM solution is for a client application to communicate with the original object through a surrogate object, or proxy, which lives in the client's process. The proxy holds a reference to an interface on the original object and hands the client a pointer to an interface on itself. When the client calls an interface method on the original object, its call is actually going to the proxy. Therefore, from the client's point of view, all calls are in-process.
On receiving a call, the proxy marshals the method arguments and through some means of interprocess communication, such as RPC, passes them along to code in the server process, which unmarshals the arguments and passes them to the original object. This same code marshals return values for transmission back to the proxy, which unmarshals the values and passes them to the client application.
IMarshal provides methods for creating, initializing, and managing a proxy in a client process; it does not dictate how the proxy should communicate with the original object. The COM default implementation of IMarshal uses RPC. When you implement this interface yourself, you are free to choose any method of interprocess communication you deem to be appropriate for your application—shared memory, named pipe, window handle, RPC—in short, whatever works.
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. 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.
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.)
|Windows version||Windows 2000 Professional [desktop apps | UWP apps] Windows 2000 Server [desktop apps | UWP apps]|
|Header||objidl.h (include ObjIdl.h)|