IMarshal
The IMarshal
interface enables an COM object to define and manage the marshaling of its
interface pointers. The alternative is to use COM s default implementation, the
preferred choice in all but a few special cases (see When to Implement ).
Marshaling
is the process of packaging data into packets for transmission to a different
process or machine. 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. COM s 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. COM s 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.
When to Implement
Implement IMarshal
only when you believe that you can realize significant optimizations to
COM s default implementation. In practice, this will rarely be the case.
However, there are occasions where implementing IMarshal may be
preferred:
The objects you are writing
keep their state in shared memory. In this case, both the original process and
the client process uses proxies that refer to the shared memory. This type of
custom marshaling is possible only if the client process is on the same machine
as the original process. OLE-provided implementations of IStorage and IStream are examples of this type
of custom marshaling.
The objects you are writing are
immutable, that is, their state does not change after creation. Instead of
forwarding method calls to the original objects, you simply create copies of
those objects in the client process. This technique avoids the cost of switching
from one process to another. Some monikers are examples of immutable objects;
if you are implementing your own moniker class, you should evaluate the costs
and benefits of implementing IMarshal on your moniker objects.
Objects that themselves are proxy
objects can use custom marshaling to avoid creating proxies to proxies.
Instead, the existing proxy can refer new proxies back to the original object.
This capability is important for the sake of both efficiency and robustness.
Your server application wants
to manage how calls are made across the network without affecting the interface
exposed to clients. For example, if an end user were making changes to a
database record, the server might want to cache the changes until the user has
committed them all, at which time the entire transaction would be forwarded in
a single packet. Using a custom proxy would enable the caching and batching of
changes in this way.
When you
choose to implement IMarshal, you must do so for both your original
object and the proxy you create for it. When implementing the interface on
either object or proxy, you simply return E_NOTIMPL for the methods that are
not implemented.
COM uses your
implementation of IMarshal in the following manner: When it s necessary
to create a remote interface pointer to your object (that is, when a pointer to
your object is passed as an argument in a remote function call), COM queries
your object for the IMarshal interface. If your object implements it,
COM uses your IMarshal implementation to create the proxy object. If
your object does not implement IMarshal, COM uses its default
implementation.
How you
choose to structure the proxy is entirely up to you. You can write the proxy to
use whatever mechanisms you deem appropriate for communicating with the
original object. You can also create the proxy as either a stand-alone object
or as part of a larger aggregation such as a handler. However you choose to
structure the proxy, it must implement IMarshal to work at all. You must
also generate a CLSID for the proxy to be returned by your implementation of IMarshal::GetUnmarshalClass
on the original object.
When to Use
COM calls
this interface as part of system-provided marshaling support. COM s calls are
wrapped in calls to CoMarshalInterface
Methods in VTable Order
IUnknown Methods |
Description |
QueryInterface |
Returns
pointers to supported interfaces. |
AddRef |
Increments
reference count. |
Release |
Decrements
reference count. |
IMarshal
Methods |
Description |
GetUnmarshalClass |
Returns
CLSID of unmarshaling code. |
GetMarshalSizeMax |
Returns
size of buffer needed during marshaling. |
MarshalInterface |
Marshals an
interface pointer. |
UnmarshalInterface |
Unmarshals
an interface pointer. |
ReleaseMarshalData |
Destroys a
marshaled data packet. |
DisconnectObject |
Severs all
connections. |
See Also