9    Interface Remoting and Marshaling

In COM, clients communicate with objects solely through the use of vtable-based interface instances. The state of the object is manipulated by invoking functions on those interfaces. For each interface method, the object provides an implementation that does the appropriate manipulation of the object internals.

Interface remoting provides the infrastructure and mechanisms to allow a method invocation to return an interface pointer to an object that is in a different process, perhaps even on a different machine. The infrastructure that performs the remoting of interfaces is transparent to both the client and the object server. Neither the client or object server is necessarily aware that the other party is in fact in a different process.

This chapter first explains how interface remoting works giving mention to the interfaces and COM API functions involved. The specifications for the interfaces and the API functions themselves are given later in this chapter. There is also a brief discussion about concurrency management at the end of the chapter that involves an interface called IMessageFilter().

9.1    How Interface Remoting Works

The crux of the problem to be addressed in interface remoting can be stated as follows:

``Given an already existing remoted-interface connection between a client process and a server process, how can a method invocation through that connection return a new interface pointer so as to create a second remoted-interface connection between the two processes?''

We state the problem in this way so as to avoid for the moment the issue of how an initial connection is made between the client and the server process; we will return to that later.

Figure 9-1:  A Client and Server Process

Let's look at an example. Suppose we have an object in a server process which supports an interface IFoo, and that interface of the object (and IUnknown()) has sometime in the past been remoted to a client process through some means not here specified. In the client process, there is an object proxy which supports the exact same interfaces as does the original server object, but whose implementations of methods in those interfaces are special, in that they forward calls they receive on to calls on the real method implementations back in the server object. We say that the method implementations in the object proxy marshal the data, which is then conveyed to the server process, where it is unmarshaled. That is, ``marshaling'' refers to the packaging up of method arguments for transmission to a remote process; ``unmarshaling'' refers to the unpackaging of this data at the receiving end. Notice that in a given call, the method arguments are marshaled and unmarshaled in one direction, while the return values are marshaled and unmarshaled in the other direction.

For concreteness, let us suppose that the IFoo interface is defined as follows:

interface IFoo : IUnknown() {
 HRESULT ReturnABar([out]IBar **ppBar);
 };

If in the client process pFoo->ReturnABar(&pBar) is invoked, then the object proxy will forward this call on to the IFoo::ReturnABar method in the server object, which will do whatever this method is supposed to do in order to come up with some appropriate IBar*. The server object is then required to return this IBar* back to the client process. The act of doing this will end up creating a second connection between the two processes:

It is the procedure by which this second connection is established which is the subject of our discussion here. This process involves two steps:

Figure 9-2:  Establishing the Second Connection

  1. On the server side, the IBar* is packaged or marshaled into a data packet.

  2. The data packet is conveyed by some means to the client process, where the data it contains is unmarshaled to create the new object proxy.

[Footnote 43] The term ``marshaling'' is a general one that is applied in the industry to the packaging of any particular data type, not just interface pointers, into a data packet for transmission through an RPC infrastructure. Each different data type has different rules for how it is to marshaled: integers are to be stored in a certain way, strings are to be stored in a certain way, etc. [Footnote 43] Likewise, marshaled interface pointers are to be stored in a certain way; the Component Object Model function CoMarshalInterface contains the knowledge of how this is to be done (note that we will in this document not mention further any kind of marshaling other than marshaling of interface pointers; that subject is well-explored in existing RPC systems).

[Footnote 44] The process begins with the code doing the marshaling of the returned IBar* interface. This code has in hand a pointer to an interface that it knows in fact to be an IBar* and that it wishes to marshal. To do so it calls CoMarshalInterface. The first step in CoMarshalInterface involves finding out whether the object of which this is an interface in fact supports custom object marshaling (often simply referred to as ``custom marshaling''). Custom object marshaling is a mechanism that permits an object to be in control of creation of remote object proxies to itself. In certain situations, custom object marshaling can be used to create a more efficient object proxy than would otherwise be the case. [Footnote 44] Use of custom marshaling is completely optional on the object's part; if the object chooses not to support custom marshaling, then standard interface marshaling is used to marshal the IBar*. Standard interface marshaling uses a system-provided object proxy implementation (called the proxy manager) in the client process. This standard implementation is a generic piece of code, in that it can be used as the object proxy for any interface on any object. However, the act of marshaling (and unmarshaling) method arguments and return values is inherently interface-specific, since it is highly sensitive to the semantics and data types used in the particular methods in question. To accommodate this, the standard implementation dynamically loads in interface-specific pieces of code as needed in order to do the parameter marshaling.

We shall discuss in great detail in a moment how standard interface marshaling works. First, however, we shall review custom object marshaling, as this provides a solid framework in which standard marshaling can be better understood.

9.2    Architecture of Custom Object Marshaling

[Footnote 45] Imagine that we are presently in a piece of code whose job it is to marshal an interface pointer that it has in hand. For clarity, in what follows we'll refer to this piece of code as the ``original marshaling stub.'' The general case is that the original marshaling stub does not statically [Footnote 45] know the particular interface identifier (IID) to which the pointer conforms; the IID may be passed to this code as a second parameter. This is a common paradigm in the Component Object Model. Extant examples of this paradigm include:

IUnknown::QueryInterface(REFIID riid, void** ppvObject);
IOleItemContainer::GetObject(..., REFIID riid, void** ppvObject);
IClassFactory::CreateInstance(..., REFIID riid, void** ppvNewlyCreatedObject);

Let us assume the slightly less general case where the marshaling stub in fact does know a little bit about the IID: that the interface in fact derives from IUnknown(). This is a requirement for remoting: it is not possible to remote interfaces which are not derived from IUnknown().

To find out whether the object to which it has an interface supports custom marshaling, the original marshaling stub simply does a QueryInterface for the interface IMarshal(). That is, an object signifies that it wishes to do custom marshaling simply by implementing the IMarshal() interface. IMarshal() is defined as follows:

[
    local,
    object,
    uuid(00000003-0000-0000-C000-000000000046)
]
interface IMarshal() : IUnknown() {
 HRESULT GetUnmarshalClass ( [in] REFIID riid, [in, unique] void *pv, 
  [in] DWORD dwDestContext, [in, unique] void *pvDestContext,
  [in] DWORD mshlflags, [out] CLSID *pCid);
 HRESULT GetMarshalSizeMax ([in] REFIID riid, [in, unique] void *pv,
  [in] DWORD dwDestContext, [in, unique] void *pvDestContext,
   [in] DWORD mshlflags, [out] DWORD *pSize);
 HRESULT MarshalInterface ([in, unique] IStream() *pStm, [in] REFIID riid, [in, unique] void *pv,
  [in] DWORD dwDestContext, [in, unique] void *pvDestContext, [in] DWORD mshlflags);
 HRESULT UnmarshalInterface ( [in, unique] IStream() *pStm, [in] REFIID riid, [out] void **ppv);
 HRESULT ReleaseMarshalData ( [in, unique] IStream() *pStm);
 HRESULT DisconnectObject ( [in] DWORD dwReserved);
}

[Footnote 46] The idea is that if the object says ``Yes, I do want to do custom marshaling'' that the original marshaling stub will use this interface in order to carry out the task. The sequence of steps that carry this out is:

  1. Using GetUnmarshalClass, the original marshaling stub asks the object which kind of (i.e.: which class of) proxy object it would like to have created on its behalf in the client process.

  2. (optional on the part of the marshaling stub) Using GetMarshalSizeMax, the stub asks the object how big of a marshaling packet it will need. When asked, the object will return an upper bound on the amount of space it will need. [Footnote 46]

  3. The marshaling stub allocates a marshaling packet of appropriate size, then creates an IStream* which points into the buffer. Unless in the previous step the marshaling stub asked the object for an upper bound on the space needed, the IStream* must be able to grow its underlying buffer dynamically as IStream::Write() calls are made.

  4. The original marshaling stub asks the object to marshal its data using MarshalInterface.

We will discuss the methods of this interface in detail later in this chapter.

At this point, the contents of the memory buffer pointed to by the IStream* together with the class tag returned in step (1) comprises all the information necessary in order to be able to create the proxy object in the client process. It is the nature of remoting and marshaling that ``original marshaling stubs'' such as we have been discussing know how to communicate with the client process; recall that we are assuming that an initial connection between the two processes had already been established. The marshaling stub now communicates to the client process, by whatever means is appropriate, the class tag and the contents of the memory that contains the marshaled interface pointer. In the client process, the proxy object is created as an instance of the indicated class using the standard COM instance creation paradigm. IMarshal() is used as the initialization interface; the initialization method is IMarshal::UnmarshalInterface. The unmarshaling process looks something like the following:

void ExampleUnmarshal(CLSID& clsidProxyObject, IStream* pstm, IID& iidOriginallyMarshalled, void** ppvReturn)
{
IClassFactory* pcf;
IMarshal* pmsh;
CoGetClassObject(clsidProxyObject, CLSCTX_INPROC_HANDLER,  NULL, IID_IClassFactory, (void**)&pcf);
pcf->CreateInstance(NULL, IID_IMarshal, (void**)pmsh);
pmsh->UnmarshalInterface(pstm, iidOriginallyMarshalled, ppvReturn);
pmsh->ReleaseMarshalData(pstm)
pmsh->Release();
pcf->Release();
}

There are several important reasons why an object may choose to do custom marshaling.

9.3    Architecture of Standard Interface / Object Marshaling

[Footnote 47] [Footnote 48] If the object being marshaled [Footnote 47] chooses not to implement custom object marshaling, a ``default'' or ``standard'' object marshaling technique is used. An important part of this standard marshaling technique involves locating and loading the interface-specific pieces of code that are responsible for marshaling and unmarshaling remote calls to instances of that interface. We call these interface-specific pieces of code used in standard marshaling and unmarshaling ``interface proxies'' and ``interface stubs'' respectively. [Footnote 48] (It is important not to confuse interface proxies with the object proxy, which relates to the whole representative in the client process, rather than just one interface on that representative. We apologize for the subtleties of the terminology.)

The following figure gives a slightly simplified view of how the standard client- and server-side structures cooperate.

Figure 9-3:  Simplified Conceptual View of Client-Server Remoting Structures

When an interface of type IFoo needs to be remoted, a system registry is consulted under a key derived from IID_IFoo to locate a class id that implements the interface proxy and interface stub for the given interface. Both the interface proxies and the interface stubs for a given interface must be implemented by the same class. This class is typically either a system provided class that can provide marshaling support for any interface described in a type library or a class generated by the IDL compiler.

The IDL compiler is a tool whose input is a description of the function signatures and semantics of the interface, written in some ``interface description language,'' often known as ``IDL.'' However, while highly recommended and encouraged for accuracy's sake, the use of such a tool is by no means required; interface proxies and stubs are merely Component Object Model components which are used by the RPC infrastructure, and as such, can be written in any manner desired so long as the correct external contracts are upheld. From a logical perspective, it is ultimately the programmer who is the designer of a new interface who is responsible for ensuring that all interface proxies and stubs that ever exist agree on the representation of their marshaled data. The programmer has the freedom to achieve this by whatever means he sees fit, but with that freedom comes the responsibility for ensuring the compatibility.

[Footnote 49] In the figure, the ``stub manager'' is ``conceptual'' in the sense that while it useful in this documentation to have a term to refer to the pieces of code and state on in the server-side RPC infrastructure which service the remoting of a given object, there is no direct requirement that the code and state take any particular well-specified form. [Footnote 49] In contrast, on the client side, there is an identifiable piece of state and associated behavior which appears to the client code to be the one, whole object. The term ``proxy manager'' is used to refer to the COM Library provided code that manages the client object identity, etc., and which dynamically loads in interface proxies as needed (per QueryInterface() calls). The proxy manager implementation is intimate with the client-side RPC channel implementation, and the server-side RPC channel implementation is intimate with the stub manager implementation.

Interface proxies are created by the client-side COM Library infrastructure using a code sequence resembling the following:

clsid = LookUpInRegistry(key derived from iid)
CoGetClassObject(clsid, CLSCTX_SERVER, NULL, IID_IPSFactoryBuffer, &pPSFactory));
pPSFactory->CreateProxy(pUnkOuter, riid, &pProxy, &piid);

Interface stubs are created by the server-side RPC infrastructure using a code sequence resembling:

clsid = LookUpInRegistry(key derived from iid)
CoGetClassObject(clsid, CLSCTX_SERVER, NULL, IID_IPSFactoryBuffer, &pPSFactory));
pPSFactory->CreateStub(iid, pUnkServer, &pStub);

In particular, notice that the class object is talked-to with IPSFactoryBuffer() interface rather than the more common IClassFactory().

The interfaces mentioned here are as follows:

interface IPSFactoryBuffer() : IUnknown() {
 HRESULT CreateProxy(pUnkOuter, iid, ppProxy, ppv);
 HRESULT CreateStub(iid, pUnkServer, ppStub);
 };
interface IRpcChannelBuffer() : IUnknown() {
 HRESULT GetBuffer(pMessage, riid);
 HRESULT SendReceive(pMessage, pStatus);
 HRESULT FreeBuffer(pMessage);
 HRESULT GetDestCtx(pdwDestCtx, ppvDestCtx);
 HRESULT IsConnected();
 };
interface IRpcProxyBuffer() : IUnknown() {
 HRESULT Connect(pRpcChannelBuffer);
 void   Disconnect();
 };
interface IRpcStubBuffer() : IUnknown() {
 HRESULT  Connect(pUnkServer);
 void     Disconnect();
 HRESULT  Invoke(pMessage, pChannel);
 IRPCStubBuffer* IsIIDSupported(iid);
 ULONG   CountRefs();
 HRESULT  DebugServerQueryInterface(ppv);
 void    DebugServerRelease(pv);
 };

Suppose an interface proxy receives a method invocation on one of its interfaces (such as IFoo, IBar, or IBaz in the above figure). The interface proxy's implementation of this method first obtains a marshaling packet from its RPC channel using 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 method invocation across the ``wire'' to the corresponding interface stub. When IRpcChannelBuffer::SendReceive returns, the contents of buffer into which the arguments were marshaled will have been replaced by the return values marshaled from the interface stub. The interface proxy unmarshals the return values, invokes IRpcChannelBuffer::FreeBuffer to free the buffer, then returns the return values to the original caller of the method.

It is the implementation of IRpcChannelBuffer::SendReceive that actually sends the request over to the server process. It is only the channel who knows or cares how to identify the server process and object within that process to which the request should be sent; this encapsulation allows the architecture we are describing here to function for a variety of different kinds of channels: intra-machine channels, inter-machine channels (i.e.: across the network), etc. The channel implementation knows how to forward the request onto the appropriate stub manager object in the appropriate process. From the perspective of this specification, the channel and the stub manager are intimate with each other (and intimate with the proxy manager, for that matter). Through this intimacy, eventually the appropriate interface stub receives an IRpcStubBuffer::Invoke call. The 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 stub manager and the channel then cooperate to ferry the return data packet back to the interface proxy, who is still in the middle of IRpcChannelBuffer::SendReceive. IRpcChannelBuffer::SendReceive returns to the proxy, and we proceed as just described above.

When created, interface proxies are always aggregated into the larger object proxy: at interface-proxy-creation time, the proxy is given the IUnknown* to which it should delegate its QueryInterface, etc., calls, as per the usual aggregation rules. When connected, the interface proxy is also given (with IRpcProxyBuffer::Connect) a pointer to an IRpcChannelBuffer() interface instance. It is through this pointer that the interface proxy actually sends calls to the server process. Interface proxies bring a small twist to the normal everyday aggregation scenario. In aggregation, each interface supported by an aggregateable object is classified as either ``external'' or ``internal.'' External interfaces are the norm. They are the ones whose instances are exposed directly to the clients of the aggregate as whole. It is always the case that a QueryInterface that requests an external interface of an aggregated object should be delegated by the object to its controlling unknown (ditto for AddRef and Release). Internal interfaces, on the other hand, are never exposed to outside clients. Instead, they are solely for the use of the controlling unknown in manipulating the aggregated object. QueryInterface for internal interfaces should never be delegated to the controlling unknown (ditto again). In the common uses of aggregation, the IUnknown() interface on the object is the only internal interface. The twist that interface proxies bring is that IRpcProxyBuffer() is also an internal interface.

Interface stubs, by contrast with interface proxies, are not aggregated, since 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 (with IRpcStubBuffer::Connect) a pointer to the server object to which they should forward invocations that they receive.

A given interface proxy instance can if it chooses to do so service more than one interface. For example, in the above figure, one interface proxy could have chosen to service both IFoo and IBar. To accomplish this, in addition to installing itself under the appropriate registry entries, the proxy should support QueryInterface()ing from one supported interface (and from IUnknown() and IRpcProxyBuffer()) to the other interfaces, as usual. When the Proxy Manager in a given object proxy finds that it needs the interface proxy for some new interface that it doesn't already have, before it goes out to the registry to load in the appropriate code using the code sequence described above, it first does a QueryInterface for the new interface id (IID) on all of its existing interface proxies. If one of them supports the interface, then it is used rather than loading a new interface proxy.

Interface stub instances, too, can service more than one interface on a server object. However, the extent to which they can do so is quite restricted: a given interface stub instance may support one or more interfaces only if that set of interfaces has in fact a strict single-inheritance relationship. In short, a given interface stub needs to know how to interpret a given method number that it is asked to invoke without at that same time also being told the interface id (IID) in which that method belongs; the stub must already know the relevant IID. The IID which an interface stub is initially created to service is passed as parameter to IPSFactoryBuffer::CreateStub. After creation, the interface stub may from time to time be asked using IRpcStubBuffer::IsIIDSupported if it in fact would also like be used to service another IID. If the stub also supports the second IID, then it should return the appropriate IRpcStubBuffer* for that IID; otherwise, the stub buffer should return NULL. This permits the stub manager in certain cases to optimize the loading of interface stubs.

Both proxies and stubs will at various times 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 Component Object Model components, in that they should use the standard task allocator; see CoGetMalloc(). See also the earlier discussion regarding specific rules for passing in, out, and in out pointers.

On Microsoft Windows platforms, the ``key derived from IID'' under which the registry is consulted to learn the proxy/stub class is as follows:

Interfaces
 {IID}
  ProxyStubClsid32 = {CLSID}

Here {CLSID} is a shorthand for any class id; the actual value of the unique id is put between the {}'s; e.g. {DEADBEEF-DEAD-BEEF-C000-000000000046}; all digits are upper case hex and there can be no spaces. This string format for a unique id (without the {}'s) is the same as The Open Group's DCE TM standard and is the result of the StringFromCLSID() routine. {IID} is a shorthand for an interface id; this is similar to {CLSID}; StringFromIID() can be used to produce this string.

9.4    Architecture of Handler Marshaling

Handler marshaling is a third variation on marshaling, one closely related to standard marshaling. Colloquially, one can think of it as a middle ground between raw standard marshaling and full custom marshaling.

In handler marshaling, the object specifies that it would like to have some amount of client-side state; this is designated by the class returned by IStdMarshalInfo::GetClassForHandler. However, this handler class rather than fully taking over the remoting to the object instead aggregates in the default handler, which carries out the remoting in the standard manner as described above.

9.5    Standards for Marshaled Data Packets

In the architecture described here, nothing has yet to be said about representation or format standards for the data that gets placed in marshaling packets. There is a good reason for this. In the Component Object Model architecture, the only two parties that have to agree on what goes into a marshaling packet are the code that marshals the data into the packet and the code that unmarshals it out again: the interface proxies and the interface stubs. So long as we are dealing only with intra-machine procedure calls (i.e.: non-network), then we can reasonably assume that pairs of interface proxies and stubs are always installed together on the machine. In this situation, we have no need to specify a packet format standard; the packet format can safely be a private matter between the two piece of code.

However, once a network is involved, relying on the simultaneous installation of corresponding interface proxies and stubs (on different machines) is no longer a reasonable thing to do. Thus, when the a method invocation is in fact remoted over a network, it is strongly recommended that the data marshaled into the packet to conform to a published standard (NDR), though, as pointed out above, it is technically the interface-designer's responsibility to achieve this correspondence by whatever means he sees fit.

9.6    Creating an Initial Connection Between Processes

Earlier we said we would later discuss how an initial remoting connection is established between two processes. It is now time to have that discussion.

The real truth of the matter is that the initial connection is established by some means outside of the architecture that we have been discussing here. The minimal that is required is some primitive communication channel between the two processes. As such, we cannot hope to discuss all the possibilities. But we will point out some common ones.

One common approach is that initial connections are established just like other connections: an interface pointer is marshaled in the server process, the marshaled data packet is ferried the client process, and it is unmarshaled. The only twist is that the ferrying is done by some means other than the RPC mechanism which we've been describing. There are many ways this could be accomplished. The most important, by far is one where the marshaled data is passed as an out-parameter from an invocation on a well-known endpoint to a Service Control Manager.

9.7    Interface Remoting and Marshaling Interface Descriptions

9.7.1    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:

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() and CoUnmarshalInterface(). Your code typically will not need to call this interface. Special circumstances where you might choose to do so are discussed in the ``Notes to Callers'' section for each method.

Table 9-1:  IMarshal Methods in VTable Order

IUnknown Methods Description
QueryInterface() Returns pointers to supported interfaces.
AddRef() Increments reference count.
Release() Decrements reference count.

Table 9-2:  IMarshal Methods

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

IStdMarshalInfo()  

IMarshal::DisconnectObject()

NAME

IMarshal::DisconnectObject() - Forcibly releases all external connections to an object. The object's server calls the object's implementation of this method prior to shutting down.

Synopsis

#include <objidl.h>

HRESULT DisconnectObject(
        DWORD dwReserved );

Description

This method is implemented on the object, not the proxy.

Notes to Callers

The usual case in which this method is called occurs when an end user forcibly closes a COM server that has one or more running objects that implement IMarshal(). Prior to shutting down, the server calls the CoDisconnectObject() helper function to sever external connections to all its running objects. For each object that implements IMarshal(), however, this function calls IMarshal::DisconnectObject(), so that each object that manages its own marshaling can take steps to notify its proxy that it is about to shut down.

Notes to Implementors

As part of its normal shutdown code, a server should call the CoDisconnectObject() function, which in turn calls IMarshal::DisconnectObject(), on each of its running objects that implements IMarshal().

The outcome of any implementation of this method should be to enable a proxy to respond to all subsequent calls from its client by returning RPC_E_DISCONNECTED or CO_E_OBJECTNOTCONNECTED rather than attempting to forward the calls on to the original object. It is up to the client, of course, to destroy the proxy.

If you are implementing this method for an immutable object, such as a moniker, your implementation doesn't need to do anything because such objects are typically copied whole into the client's address space. Therefore, they have neither a proxy nor a connection to the original object. For more information on marshaling immutable objects, see IMarshal(), ``When to Implement.''

Parameters

dwReserved

[in] Reserved for future use; must be zero. To ensure compatibility with future use, DisConnectObject must not check for zero.

Return Values

The method supports the standard return value E_FAIL, as well as the following:

S_OK

The object was disconnected successfully.

See Also

CoDisconnectObject()  

IMarshal::GetMarshalSizeMax()

NAME

IMarshal::GetMarshalSizeMax() - Returns an upper bound on the number of bytes needed to marshal the specified interface pointer on the specified object.

Synopsis

#include <objidl.h>

HRESULT GetMarshalSizeMax(
        REFIID riid,
        void * pv,
        DWORD dwDestContext,
        void * pvDestContext,
        DWORD mshlflags,
        ULONG * pSize );

Description

This method is called indirectly, in a call to CoGetMarshalSizeMax(), by whatever code in the server process is responsible for marshaling a pointer to an interface on an object. This marshaling code is usually a stub generated by COM for one of several interfaces that can marshal a pointer to an interface implemented on an entirely different object. Examples include the IClassFactory() and IOleItemContainer() interfaces. For purposes of discussion, the code responsible for marshaling a pointer is here called the ``marshaling stub.''

To create a proxy for an object, COM requires two pieces of information from the original object: the amount of data to be written to the marshaling stream and the proxy's CLSID.

The marshaling stub obtains these two pieces of information with successive calls to CoGetMarshalSizeMax() and CoMarshalInterface().

Note to Callers

The marshaling stub, through a call to CoGetMarshalSizeMax(), calls the object's implementation of this method to preallocate the stream buffer that will be passed to IMarshal::MarshalInterface().

You do not explicitly call this method if you are:

In both cases, the MIDL-generated stub automatically makes the call.

If you are not using MIDL to define your own interface your marshaling stub does not have to call GetMarshalSizeMax, though doing so is highly recommended. An object knows better than an interface stub what the maximum size of a marshaling data packet is likely to be. Therefore, unless you are providing an automatically growing stream that is so efficient that the overhead of expanding it is insignificant, you should call this method even when implementing your own interfaces.

The value returned by this method is only guaranteed to be valid as long as the internal state of the object being marshaled does not change. Therefore, the actual marshaling should be done immediately after this function returns, or the stub runs the risk that the object, because of some change in state, might require more memory to marshal than it originally indicated.

Notes to Implementors

Your implementation of MarshalInterface will use this buffer to write marshaling data into the stream. If the buffer is too small, the marshaling operation will fail. Therefore, the value returned by this method must be a conservative estimate of the amount of data that will, in fact, be needed to marshal the interface. Violation of this requirement should be treated as a catastrophic error.

In a subsequent call to IMarshal::MarshalInterface(), your IMarshal() implementation cannot rely on the caller actually having called GetMarshalSizeMax beforehand. It must still be wary of STG_E_MEDIUMFULL errors returned by the stream and be prepared to handle them gracefully.

To ensure that your implementation of GetMarshalSizeMax will continue to work properly as new destination contexts are supported in the future, delegate marshaling to COM's default implementation for all dwDestContext values that your implementation does not understand. To delegate marshaling to COM's default implementation, call the CoGetStandardMarshal() function.

Parameters

riid

[in] Reference to the identifier of the interface to be marshaled.

pv

[in] Interface pointer to be marshaled; can be NULL.

dwDestContext

[in] Destination context where the specified interface is to be unmarshaled. Values for dwDestContext come from the enumeration MSHCTX. Currently, unmarshaling can occur either in another apartment of the current process (MSHCTX_INPROC) or in another process on the same computer as the current process (MSHCTX_LOCAL).

pvDestContext

[in] Reserved for future use; must be NULL.

mshlflags

[in] Flag indicating whether the data to be marshaled is to be transmitted back to the client process--the normal case--or written to a global table, where it can be retrieved by multiple clients. Valid values come from the MSHLFLAGS enumeration.

pSize

[out] Pointer to the upper bound on the amount of data to be written to the marshaling stream.

Return Values

The method supports the standard return value E_FAIL, as well as the following:

S_OK

The maximum size was returned successfully.

E_NOINTERFACE

The specified interface was not supported.

See Also

CoGetMarshalSizeMax(), IMarshal::MarshalInterface()  

IMarshal::GetUnmarshalClass()

NAME

IMarshal::GetUnmarshalClass() - Returns the CLSID that COM uses to locate the DLL containing the code for the corresponding proxy. COM loads this DLL to create an uninitialized instance of the proxy.

Synopsis

#include <objidl.h>

HRESULT GetUnmarshalClass(
        REFIID riid,
        void * pv,
        DWORD dwDestContext,
        void * pvDestContext,
        DWORD mshlflags,
        CLSID * pCid );

Description

This method is called by whatever code in the server process may be responsible for marshaling a pointer to an interface on an object. This marshaling code is usually a stub generated by COM for one of several interfaces that can marshal a pointer to an interface implemented on an entirely different object. Examples include the IClassFactory() and IOleItemContainer() interfaces. For purposes of this discussion, the code responsible for marshaling a pointer is called the ``marshaling stub.''

To create a proxy for an object, COM requires two pieces of information from the original object: the amount of data to be written to the marshaling stream and the proxy's CLSID.

The marshaling stub obtains these two pieces of information with successive calls to CoGetMarshalSizeMax() and CoMarshalInterface().

Note to Callers

The marshaling stub calls the object's implementation of this method to obtain the CLSID to be used in creating an instance of the proxy. The client, upon receiving the CLSID, loads the DLL listed for it in the system registry.

You do not explicitly call this method if you are:

In both cases, the stub automatically makes the call.

If you are not using MIDL to define your own interface, your stub must call this method, either directly or indirectly, to get the CLSID that the client-side COM Library needs to create a proxy for the object implementing the interface.

If the caller has a pointer to the interface to be marshaled, it should, as a matter of efficiency, use the pv parameter to pass that pointer. In this way, an implementation that may use such a pointer to determine the appropriate CLSID for the proxy does not have to call IUnknown::QueryInterface() on itself. If a caller does not have a pointer to the interface to be marshaled, it can pass NULL.

Notes to Implementors

COM calls GetUnmarshalClass to obtain the CLSID to be used for creating a proxy in the client process. The CLSID to be used for a proxy is normally not that of the original object (see ``Notes to Implementors'' for the exception), but one you will have generated (using the GUIDGEN.EXE tool supplied with the Win32 SDK) specifically for your proxy object.

Implement this method for each object that provides marshaling for one or more of its interfaces. The code responsible for marshaling the object writes the CLSID, along with the marshaling data, to a stream; COM extracts the CLSID and data from the stream on the receiving side.

If your proxy implementation consists simply of copying the entire original object into the client process, thereby eliminating the need to forward calls to the original object, the CLSID returned would be the same as that of the original object. This strategy, of course, is advisable only for objects that are not expected to change.

If the pv parameter is NULL and your implementation needs an interface pointer, it can call IUnknown::QueryInterface() on the current object to get it. The pv parameter exists merely to improve efficiency.

To ensure that your implementation of GetUnmarshalClass continues to work properly as new destination contexts are supported in the future, delegate marshaling to COM's default implementation for all dwDestContext values that your implementation does not handle. To delegate marshaling to COM's default implementation, call the CoGetStandardMarshal() function.

Parameters

riid

[in] Reference to the identifier of the interface to be marshaled.

pv

[in] Pointer to the interface to be marshaled; can be NULL if the caller does not have a pointer to the desired interface.

dwDestContext

[in] ``Destination context'' where the specified interface is to be unmarshaled. Values for dwDestContext come from the enumeration MSHCTX. Currently, unmarshaling can occur either in another apartment of the current process (MSHCTX_INPROC) or in another process on the same computer as the current process (MSHCTX_LOCAL).

pvDestContext

[in] Reserved for future use; must be NULL.

mshlflags

[in] Whether the data to be marshaled is to be transmitted back to the client process--the normal case--or written to a global table, where it can be retrieved by multiple clients. Valid values come from the MSHLFLAGS enumeration.

pCid

[out] Pointer to the CLSID to be used to create a proxy in the client process.

Return Values

Returns S_OK if successful; otherwise, S_FALSE.  

IMarshal::MarshalInterface()

NAME

IMarshal::MarshalInterface() - Writes into a stream the data required to initialize a proxy object in some client process.

Synopsis

#include <objidl.h>

HRESULT MarshalInterface(
        IStream * pStm,
        REFIID riid,
        void * pv,
        DWORD dwDestContext,
        void * pvDestContext,
        DWORD mshlflags );

Description

This method is called indirectly, in a call to CoMarshalInterface(), by whatever code in the server process may be responsible for marshaling a pointer to an interface on an object. This marshaling code is usually a stub generated by COM for one of several interfaces that can marshal a pointer to an interface implemented on an entirely different object. Examples include the IClassFactory() and IOleItemContainer() interfaces. For purposes of this discussion, the code responsible for marshaling a pointer is called the ``marshaling stub.''

Notes to Callers

Normally, rather than calling IMarshal::MarshalInterface() directly, your marshaling stub instead should call the CoMarshalInterface() function, which contains a call to this method. The stub makes this call to command an object to write its marshaling data into a stream. The stub then either passes the marshaling data back to the client process or writes it to a global table, where it can be unmarshaled by multiple clients. The stub's call to CoMarshalInterface() is normally preceded by a call to CoGetMarshalSizeMax(), to get the maximum size of the stream buffer into which the marshaling data will be written.

You do not explicitly call this method if you are:

In both cases, the MIDL-generated stub automatically makes the call.

If you are not using MIDL to define your own interface, your marshaling stub must call this method, either directly or indirectly.Your stub implementation should call MarshalInterface immediately after its previous call to IMarshal::GetMarshalSizeMax() returns. Because the value returned by GetMarshalSizeMax is guaranteed to be valid only so long as the internal state of the object being marshaled does not change, a delay in calling MarshalInterface runs the risk that the object will require a larger stream buffer than originally indicated.

If the caller has a pointer to the interface to be marshaled, it should, as a matter of efficiency, use the pv parameter to pass that pointer. In this way, an implementation that may use such a pointer to determine the appropriate CLSID for the proxy does not have to call IUnknown::QueryInterface() on itself. If a caller does not have a pointer to the interface to be marshaled, it can pass NULL.

Notes to Implementors

Your implementation of IMarshal::MarshalInterface() must write to the stream whatever data is needed to initialize the proxy on the receiving side. Such data would include a reference to the interface to be marshaled, a MSHLFLAGS value specifying whether the data should be returned to the client process or written to a global table, and whatever is needed to connect to the object, such as a named pipe, handle to a window, or pointer to an RPC channel.

Your implementation should not assume that the stream is large enough to hold all the data. Rather, it should gracefully handle a STG_E_MEDIUMFULL error. Just before exiting, your implementation should position the seek pointer in the stream immediately after the last byte of data written.

If the pv parameter is NULL and your implementation needs an interface pointer, it can call IUnknown::QueryInterface() on the current object to get it. The pv parameter exists merely to improve efficiency.

To ensure that your implementation of MarshalInterface continues to work properly as new destination contexts are supported in the future, delegate marshaling to COM's default implementation for all dwDestContext values that your implementation does not handle. To delegate marshaling to COM's default implementation, call the CoGetStandardMarshal() helper function.

Using the MSHLFLAGS enumeration, callers can specify whether an interface pointer is to be marshaled back to a single client or written to a global table, where it can be unmarshaled by multiple clients. You must make sure that your object can handle calls from the multiple proxies that might be created from the same initialization data.

Parameters

pStm

[in] Pointer to the stream to be used during marshaling.

riid

[in] Reference to the identifier of the interface to be marshaled. This interface must be derived from the IUnknown() interface.

pv

[in] Pointer to the interface pointer to be marshaled; can be NULL if the caller does not have a pointer to the desired interface.

dwDestContext

[in] Destination context where the specified interface is to be unmarshaled. Values for dwDestContext come from the enumeration MSHCTX. Currently, unmarshaling can occur either in another apartment of the current process (MSHCTX_INPROC) or in another process on the same computer as the current process (MSHCTX_LOCAL).

pvDestContext

[in] Reserved for future use; must be zero.

mshlflags

[in] Whether the data to be marshaled is to be transmitted back to the client process--the normal case--or written to a global table, where it can be retrieved by multiple clients. Valid values come from the MSHLFLAGS enumeration.

Return Values

The method supports the standard return value E_FAIL, as well as the following:

S_OK

The interface pointer was marshaled successfully.

E_NOINTERFACE

The specified interface is not supported.

STG_E_MEDIUMFULL

The stream is full.

See Also

CoGetStandardMarshal(), IMarshal::GetMarshalSizeMax(), IMarshal::GetUnmarshalClass(), IMarshal::UnmarshalInterface(), Writing a Custom Interface  

IMarshal::ReleaseMarshalData()

NAME

IMarshal::ReleaseMarshalData() - Destroys a marshaled data packet.

Synopsis

#include <objidl.h>

HRESULT ReleaseMarshalData(
        IStream * pStm );

Description

If an object's marshaled data packet does not get unmarshaled in the client process space, and the packet is no longer needed. The client calls ReleaseMarshalData on the proxy's IMarshal() implementation to instruct the object to destroy the data packet. The call occurs within the CoReleaseMarshalData() function. The data packet serves as an additional reference on the object, and releasing the data is like releasing an interface pointer by calling IUnknown::Release().

If the marshaled data packet somehow does not arrive in the client process, or ReleaseMarshalData is not successfully re-created in the proxy, COM can call this method on the object itself.

Notes to Callers

You will rarely if ever have occasion to call this method yourself. A possible exception would be if you were to implement IMarshal() on a class factory for a class object on which you are also implementing IMarshal(). In this case, if you are marshaling the object to a table, where it can be retrieved by multiple clients, you might, as part of your unmarshaling routine, call ReleaseMarshalData to release the data packet for each proxy.

Notes to Implementors

If your implementation stores state information about marshaled data packets, you can use this method to release the state information associated with the data packet represented by pStm. Your implementation should also position the seek pointer in the stream past the last byte of data.

Parameters

pStm

[in] Pointer to a stream that contains the data packet to be destroyed.

Return Values

The method supports the standard return value E_FAIL, as well as the following:

S_OK

The data packet was released successfully.

IStream() errors

This function can also return any of the stream-access error values for the IStream() interface.

See Also

CoUnMarshalInterface, CoReleaseMarshalData()  

IMarshal::UnmarshalInterface()

NAME

IMarshal::UnmarshalInterface() - Initializes a newly created proxy and returns an interface pointer to that proxy.

Synopsis

#include <objidl.h>

HRESULT UnmarshalInterface(
        IStream * pStm,
        REFIID riid,
        void ** ppv );

Description

The COM library in the process where unmarshaling is to occur calls the proxy's implementation of this method.

Notes to Callers

You do not call this method directly. There are, however, some situations in which you might call it indirectly through a call to CoUnmarshalInterface(). For example, if you are implementing a stub, your implementation would call CoUnmarshalInterface() when the stub receives an interface pointer as a parameter in a method call.

Notes to Implementors

The proxy's implementation should read the data written to the stream by the original object's implementation of IMarshal::MarshalInterface() and use that data to initialize the proxy object whose CLSID was returned by the marshaling stub's call to the original object's implementation of IMarshal::GetUnmarshalClass().

To return the appropriate interface pointer, the proxy implementation can simply call IUnknown::QueryInterface() on itself, passing the riid and ppv parameters. However, your implementation of UnmarshalInterface is free to create a different object and, if necessary, return a pointer to it.

Just before exiting, even if exiting with an error, your implementation should reposition the seek pointer in the stream immediately after the last byte of data read.

Parameters

pStm

[in] Pointer to the stream from which the interface pointer is to be unmarshaled.

riid

[in] Reference to the identifier of the interface to be unmarshaled.

ppv

[out] Indirect pointer to the interface.

Return Values

The method supports the standard return value E_FAIL, as well as the following:

S_OK

The interface pointer was unmarshaled successfully.

E_NOINTERFACE

The specified interface was not supported.

See Also

IMarshal::GetUnmarshalClass(), IMarshal::MarshalInterface()

9.7.2    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.

COM's 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's 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, in the server. Together, each pair handles all marshaling for its 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, 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, an internal interface 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 by no means required. Proxies and stubs are merely Component Object Model components used by the RPC infrastructure and, as such, can be written in any manner desired so 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 COM's 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 it uses 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(), an internal interface. 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, 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, so long as two conditions are met. First, the IIDs of the affected interfaces must be mapped to the the appropriate ProxyStubClsid in the system registry. Second, 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.

Both proxies and stubs will at various times 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).

When to Use

You should use COM's default implementation of IMarshal() except in those very few cases where your application has special requirements that COM's 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 IMarshal(), ``When to Implement.''

See Also

IMarshal()

9.7.3    IPSFactoryBuffer

IPSFactoryBuffer() is the interface through which proxies and stubs are created. It is used to create proxies and stubs that support IRpcProxyBuffer() and IRpcStubBuffer() respectively. Each proxy / stub DLL must support IPSFactory() interface on the class object accessible through its DllGetClassObject() entry point. As was described above, the registry is consulted under a key derived from the IID to be remoted in order to learn the proxy/stub class that handles the remoting of the indicated interface. The class object for this class is retrieved, asking for this interface. A proxy or a stub is then instantiated as appropriate.

interface IPSFactoryBuffer : IUnknown {
    HRESULT CreateProxy(pUnkOuter, iid, ppProxy, ppv);
    aHRESULT CreateStub(iid, pUnkServer, ppStub);
};

 

IPSFactoryBuffer::CreateProxy()

NAME

IPSFactoryBuffer::CreateProxy() - Create a new interface proxy object. This function returns both an IRpcProxy() instance and an instance of the interface which the proxy is being created to service in the first place. The newly created proxy is initially in the unconnected state.

Synopsis

HRESULT IPSFactoryBuffer::CreateProxy((
        IUnknown * pUnkOuter,
        REFIID iid,
        IRpcProxyBuffer ** ppProxy,
        void ** ppv );

Parameters

pUnkOuter

The controlling unknown of the aggregate in which the proxy is being created.

iid

The interface id which the proxy is being created to service, and of which an instance should be returned through ppv.

ppProxy

On exit, contains the new IRpcProxyBuffer() instance.

ppv

On exit, contains an interface pointer of type indicated by iid.

Return Values

S_OK

E_OUTOFMEMORY

E_NOINTERFACE

E_UNEXPECTED

 

IPSFactoryBuffer::CreateStub()

NAME

IPSFactoryBuffer::CreateStub() - Create a new interface stub object. The stub is created in the connected state on the object indicated by pUnkServer.

Synopsis

HRESULT IPSFactoryBuffer::CreateStub((
        REFIID iid,
        IUnknown * pUnkServer,
        IRpcStubBuffer ** ppStub );

Description

If pUnkServer is non-NULL, then before this function returns the stub must verify (by using QueryInterface()) that the server object in fact supports the interface indicated by iid. If it does not, then this function should fail with the error E_NOINTERFACE.

Parameters

iid

The interface that the stub is being created to service

pUnkServer

The server object that is being remoted. The stub should delegate incoming calls (see IRpcStubBuffer::Invoke()) to the appropriate interface on this object. pUnkServer may legally be NULL, in which case the caller is responsible for later calling IRpcStubBuffer::Connect() before using IRpcStubBuffer::Invoke().

ppStub

The place at which the newly create stub is to be returned.

Return Values

S_OK

E_OUTOFMEMORY

E_NOINTERFACE

E_UNEXPECTED

9.7.4    IRpcChannelBuffer

IRpcChannelBuffer() is the interface through which interface proxies send calls through to the corresponding interface stub. This interface is implemented by the RPC infrastructure. The infrastructure provides an instance of this interface to interface proxies in IRpcProxyBuffer::Connect(). The interface proxies hold on to this instance and use it each time they receive an incoming call.

interface IRpcChannelBuffer : IUnknown {
   HRESULT GetBuffer(pMessage, riid);
   HRESULT SendReceive(pMessage, pStatus);
   HRESULT FreeBuffer(pMessage);
   HRESULT GetDestCtx(pdwDestCtx, ppvDestCtx);
   HRESULT IsConnected();
};

9.7.4.1    RPCOLEMESSAGE and related structures

[Footnote 50] Common to several of the methods in IRpcChannelBuffer() is a data structure of type RPCOLEMESSAGE. This structure is defined as is show below. The structure is to be packed so that there are no holes in its memory layout.

typedef struct RPCOLEMESSAGE {
   void *    reserved1;
   RPCOLEDATAREP  dataRepresentation; // in NDR transfer syntax: info about endianness, etc.
   void  *    pvBuffer;               // memory buffer used for marshalling
   ULONG    cbBuffer;                 // size of the marshalling buffer
   aULONG    iMethod;                 // the method number being invoked
   void  *    reserved2[5];
   ULONG    rpcFlags;
} on the ultimate destination machine MESSAGE;
[Footnote 50]

The most significant member of this structure is pvBuffer. It is through the memory buffer to which pvBuffer points that marshaled method arguments are transferred. cbBuffer is used to indicate the size of the buffer. iMethod is indicates a particular method number within the interface being invoked. The IID of that interface is identified through other means: on the client side as a parameter to GetBuffer, and on the server side as part of the internal state of each interface stub.

At all times all reserved values in this structure are to be initialized to zero by non-RPC-infrastructure parties (i.e.: parties other than the channel / RPC runtime implementor) who allocate RPCOLEMESSAGE structures. However, the RPC channel (more generally, the RPC runtime infrastructure) is free to modify these reserved fields. Therefore, once initialized, the reserved fields must be ignored by the initializing code; they cannot be relied on to remain as zero. Further, there are very carefully specified rules as to what values in these structures may or may not be modified at various times and by which parties. In almost all cases, aside from actually reading and writing data from the marshaling buffer, which is done by proxies and stubs, only the channel may change these fields. See the individual method descriptions for details.

Readers familiar with the connection-oriented DCE protocol may notice that the ``transfer syntax'' used for marshaling the arguments, the particular set of rules and conventions according to which data is marshaled, is not explicitly called out. Architecturally speaking, it is only the interface proxy for a given interface and its corresponding interface stub that cares at all about what set of marshaling rules is in fact used. However, in the general case these interface proxies and stubs may be installed on different machines with a network in the middle, be written by different development organizations on different operating systems, etc. Accordingly, in cases where the author of an interface proxy for a given IID cannot guarantee that all copies of the corresponding interface stub are in fact always revised and updated in synchrony with his interface proxy, a well-defined convention should be used for the transfer syntax. Indeed, formal transfer syntax standards exist for this purpose. The one most commonly used is known as ``Network Data Representation'' (NDR), originally developed by Apollo Corporation and subsequently enhanced and adopted by The Open Group as part of their Distributed Computing Environment (DCE).

When NDR transfer syntax is used (and whether it is in use or not is implicitly known by the proxy or stub), the member dataRepresentation provides further information about the rules by which data in the buffer is marshaled. NDR is a ``multi-canonical'' standard, meaning that rather than adopting one standard for things like byte-order, character set, etc., multiple standards (a fixed set of them) are accommodated. Specifically, this is accommodated by a ``reader make right'' policy: the writer / marshaler of the data is free to write the data in any of the supported variations and the reader / unmarshaler is expected to be able to read any of them. The particular data type in use is conveyed in an RPCOLEDATAREP structure, which is defined as follows. Note that this structure, too, is packed; the size of the entire structure is exactly four bytes. The actual layout of the structure in all cases always corresponds to the data representation value as defined in the DCE standard; the particular structure shown here is equivalent to that layout in Microsoft's and other common compilers.

typedef RPCOLEDATAREP {
   UINT  uCharacterRep  : 4;  // least signficant nibble of first byte
   UINT  uByteOrder  : 4;     // most signficant nibble of first byte
   BYTE  uFloatRep;
   BYTE  uReserved;
   BYTE  uReserved2;
} RPCOLEDATAREP;

The values which may legally be found in these fields are as shown in Table . Further information on the interpretation of this field can be found in the NDR Transfer Syntax standards documentation.

Table 9-3:  Interpretation of dataPresentation

Field Name Meaning of Field Value in field Interpretation
uCharacterRep determines interpretation of single-byte-character valued and single-byte-string valued entities 0 1 ASCII EBCDIC
uByteOrder integer and floating point byte order 0 1 Big-endian (Motorola) Little-endian (Intel)
uFloatRep representation of floating point numbers 0 1 2 3 IEEE VAX Cray IBM

 

IRpcChannelBuffer::GetBuffer()

NAME

IRpcChannelBuffer::GetBuffer() - This method returns a buffer into which data can be marshaled for subsequent transmission over the wire. It is used both by interface proxies and by interface stubs, the former to marshal the incoming arguments for transmission to the server, and the latter to marshal the return values back to the client.

Synopsis

HRESULT IRpcChannelBuffer::GetBuffer((
        RPCOLEMESSAGE * pMessage,
        REFIID iid );

Description

[Footnote 51] Upon receipt of an incoming call from the client of the proxy object, interface proxies use GetBuffer to get a buffer into which they can marshaling the incoming arguments. A new buffer must be obtained for every call operation; old buffers cannot be reused by the interface proxy. The proxy needs to ask for and correctly manage a new buffer even if he himself does not have arguments to marshal (i.e.: a void argument list). [Footnote 51] Having marshaled the arguments, the interface proxy then calls SendReceive to actually invoke the operation. Upon return from SendReceive, the buffer no longer contains the marshaled arguments but instead contains the marshaled return values (and out parameter values). The interface proxy unmarshals these values, calls FreeBuffer to free the buffer, then returns to its calling client.

On the server side (in interface stubs), the sequence is somewhat different. The server side will not be explored further here; see instead the description of IRpcStubBuffer::Invoke() for details.

On the client side, the RPCOLEMESSAGE structure argument to GetBuffer has been allocated and initialized by the caller (or by some other party on the caller's behalf). Interface proxies are to initialize the members of this structure as follows.

1.  RPCOLEMESSAGE Initialization

Member Name Value to initalize to
reserved members as always, reserved values must be initialized to zero / NULL.
pvBuffer must be NULL.
cbBuffer the size in bytes that the channel should allocate for the buffer; that is, the maximum size in bytes needed to marshal the arguments. The interface proxy will have determined this information by considering the function signature and the particular argument values passed in. It is explicitly legal to have this value be zero, indicating that that the caller does not himself require a memory buffer.
iMethod the zero-based method number in the interface iid which is being invoked
dataRepresentation if NDR transfer syntax is being used, then this indicates the byte order, etc., by which the caller will marshal data into the returned buffer.
rpcFlags The caller should pass zero (this structure is handled internally).

[Footnote 52] If the GetBuffer function is successful, then upon function exit pvBuffer will have been changed by the channel to point to a memory buffer of (at least) cbBuffer bytes in size into which the method arguments can now be marshaled (if cbBuffer was zero, pvBuffer may or may not be NULL). The reserved fields in the RPCOLEMESSAGE structure may or may not have been changed by the channel. However, neither the cbBuffer nor iMethod fields of RPCOLEMESSAGE will have been changed; the channel treats these as read-only. [Footnote 52] Furthermore, until such time as the now-allocated memory buffer is subsequently freed (see SendReceive and FreeBuffer), no party other than the channel may modify any of the data accessible from pMessage with the lone exceptions of the data pointed to by pvBuffer and the member cbBuffer, which may be modified only in limited ways; see below.

Parameters

pMessage

A message structure initialized as discussed above.

iid

The interface identifier of the interface being invoked.

Return Values

S_OK

E_OUTOFMEMORY

E_UNEXPECTED

 

IRpcChannelBuffer::SendReceive()

NAME

IRpcChannelBuffer::SendReceive() - Cause an invocation to be sent across to the server process. The caller will have first obtained access to a transmission packet in which to marshal the arguments by calling IRpcChannelBuffer::GetBuffer(). The same pMessage structure passed as an argument into that function is passed here to the channel a second time.

Synopsis

HRESULT IRpcChannelBuffer::SendReceive((
        RPCOLEMESSAGE * pMessage,
        ULONG * pStatus );

Description

In the intervening time period, the method arguments will have been marshaled into the buffer pointed to by pMessage->pvBuffer. However, the pvBuffer pointer parameter must on entry to SendReceive be exactly as it was when returned from GetBuffer. That is, it must point to the start of the memory buffer. The caller should in addition set pMessage->cbBuffer to the number of bytes actually written into the buffer (zero is explicitly a legal value). No other values accessible from pMessage may be different than they were on exit from GetBuffer.

Upon successful exit from SendReceive, the incoming buffer pointed to by pvBuffer will have been freed by the channel. In its place will be found a buffer containing the marshaled return values / out parameters from the interface stub: pMessage->pvBuffer points to the new buffer, and pMessage->cbBuffer indicates the size thereof. If there are no such return values, then pMessage->cbBuffer is set to zero, while pMessage->pvBuffer may or may not be NULL.

[Footnote 53] On error exit from SendReceive, [Footnote 53] the incoming buffer pointed to by pvBuffer may or may not have been freed. If it has been freed, then on error exit pMessage->pvBuffer is set to NULL and pMessage->cbBuffer is set to zero. If in contrast, pMessage->pvBuffer is on error exit not NULL, then that pointer, the data to which it points, and the value pMessage->cbBuffer will contain exactly as they did on entry; that is, the marshaled arguments will not have been touched. Thus, on error exit from SendReceive, in no case are any marshaled return values passed back; if a marshaling buffer is in fact returned, then it contains the marshaled arguments as they were on entry.

The exact cases on error exit when the incoming buffer has or has not been freed needs careful attention. There are three cases:

  1. The channel implementation knows with certainty either that all of the incoming data was successfully unmarshaled or that if any errors occurred during unmarshaling that the interface stub correctly cleaned up. In practical terms, this condition is equivalent to the stub manager having actually called IRpcStubBuffer::Invoke() on the appropriate interface stub.

    In this case, on exit from SendReceive the incoming arguments will always have been freed.

  2. The channel implementation knows with certainty the situation in case 1) has not occurred.

    In this case, on exit from SendReceive, the incoming arguments will never have been freed.

  3. The channel implementation does not know with certainty that either of the above two cases has occurred.

    In this case, on exit from SendReceive, the incoming arguments will always have been freed. This is a possible resource leakage (due to, for example, CoReleaseMarshalData() calls that never get made), but it safely avoids freeing resources that should not be freed.

If pMessage->pvBuffer is returned as non-NULL, then the caller is responsible for subsequently freeing it; see FreeBuffer. A returned non-NULL pMessage->pvBuffer may in general legally be (and will commonly be, the success case) different than the (non-NULL) value on entry; i.e.: the buffer may be legally be reallocated. Further, between the return from SendReceive and the subsequent freeing call no data accessible from pMessage may be modified, with the possible exception of the data actually in the memory buffer.

Upon successful exit from SendReceive, the pMessage->dataRepresentation field will have been modified to contain whatever was returned by the interface stub in field of the same name value on exit to IRpcStubBuffer::Invoke(). This is particularly important when NDR transfer syntax is used, as dataRepresentation indicates critical things (such as byte order) which apply to the marshaled return / out values. Upon error exit from SendReceive, pMessage->dataRepresentation is undefined.

Parameters

pMessage

Message structure containing info to transmit to server.

pStatus

May legally be NULL. If non-NULL, then if either 1) an RPC-infrastructure-detected server-object fault (e.g.: a server object bug caused an exception which was caught by the RPC infrastructure) or 2) an RPC communications failure occurs, then at this location a status code is written which describes what happened. In the two error cases, the errors E_RPCFAULT and E_RPCSTATUS are (respectively) returned (and are always returned when these errors occur, irrespective of the NULL-ness of pStatus).

Return Values

S_OK

E_RPCFAULT

E_RPCSTATUS

 

IRpcChannelBuffer::FreeBuffer()

NAME

IRpcChannelBuffer::FreeBuffer() - Free a memory buffer in pMessage->pvBuffer that was previously allocated by the channel.

Synopsis

HRESULT IRpcChannelBuffer::FreeBuffer((
        RPCOLEMESSAGE * pMessage );

Description

At various times the RPC channel allocates a memory buffer and returns control of same to a calling client. Both GetBuffer and SendReceive do so, for example. FreeBuffer is the means by which said calling client informs the channel that it is done with the buffer.

On function entry, the buffer which is to be freed is pMessage->pvBuffer, which explicitly may or may not be NULL. If pMessage->pvBuffer is non-NULL, then FreeBuffer frees the buffer, NULLs the pointer, and returns NOERROR; if pMessage->pvBuffer is NULL, then FreeBuffer simply returns NOERROR (i.e.: passing NULL is not an error). Thus, on function exit, pMessage->pvBuffer is always NULL. Note that pMessage->cbBuffer is never looked at or changed.

There are strict rules as to what data accessible from pMessage may have been modified in the intervening time between the time the buffer was allocated and the call to FreeBuffer. In short, very little modification is permitted; see above and below for precise details.

Parameters

pMessage

Pointer to structure containing pointer to buffer to free.

Return Values

S_OK

E_UNEXPECTED

 

IRpcChannelBuffer::GetDestCtx()

NAME

IRpcChannelBuffer::GetDestCtx() - Return the destination context for this RPC channel. The destination context here is as specified in the description of the IMarshal() interface.

Synopsis

HRESULT IRpcChannelBuffer::GetDestCtx((
        DWORD * pdwDestCtx,
        void ** ppvDestCtx );

Parameters

[Footnote 54]

pdwDestCtx

the place at which the destination context is to be returned.

ppvDestCtx

May be NULL. If non-NULL, then this is the place at which auxiliary information associated with certain destination contexts will be returned. Interface proxies may not hold on to this returned pointer in their internal state; rather, they must assume that a subsequent call to IRpcChannel::Call may in fact invalidate a previously returned destination context. [Footnote 54]

Return Values

S_OK

E_OUTOFMEMORY

E_UNEXPECTED

 

IRpcChannelBuffer::IsConnected()

NAME

IRpcChannelBuffer::IsConnected() - Answers as to whether the RPC channel is still connected to the other side. A negative reply is definitive: the connection to server end has definitely been terminated. A positive reply is tentative: the server end may or may not be still up. Interface proxies can if they wish use this method as an optimization by which they can quickly return an error condition.

Synopsis

HRESULT IRpcChannelBuffer::IsConnected((
         );

Return Values

S_OK

S_FALSE

No error values may be returned.

9.7.5    IRpcProxyBuffer

IRpcProxyBuffer() interface is the interface by which the client-side infrastructure (i.e. the proxy manager) talks to the interface proxy instances that it manages. When created, proxies are aggregated into some larger object as per the normal creation process (where pUnkOuter in IPSFactoryBuffer::CreateProxy is non-NULL). The controlling unknown will then QueryInterface to the interface that it wishes to expose from the interface proxy.

interface IRpcProxyBuffer : IUnknown {
    virtual HRESULT Connect(pRpcChannelBuffer) = 0;
    virtual void   Disconnect() = 0;
};

 

IRpcProxyBuffer::Connect()

NAME

IRpcProxyBuffer::Connect() - Connect the interface proxy to the indicated RPC channel. The proxy should hold on to the channel, AddRefing it as per the usual rules. If the proxy is currently connected, then this call fails (with E_UNEXPECTED); call Disconnect first if in doubt.

Synopsis

HRESULT IRpcProxyBuffer::Connect((
        IRpcChannelBuffer * pRpcChannelBuffer );

Parameters

pRpcChannelBuffer

The RPC channel that the interface proxy is to use to effect invocations to the server object. May not be NULL.

Return Values

S_OK

E_OUTOFMEMORY

E_NOINTERFACE

E_UNEXPECTED

 

IRpcProxyBuffer::Disconnect()

NAME

IRpcProxyBuffer::Disconnect() - Informs the proxy that it should disconnect itself from any RPC channel that it may currently be holding on to. This will involve Releaseing the IRpcChannel pointer to counteract the AddRef done in IRpcProxy::Connect. Note that this function does not return a value.

Synopsis

void IRpcProxyBuffer::Disconnect((
         );

9.7.6    IRpcStubBuffer

IRpcStubBuffer() is the interface used on the server side by the RPC runtime infrastructure (herein referred to loosely as the ``channel'') to communicate with interface stubs that it dynamically loads into a server process.

interface IRpcStubBuffer : IUnknown {
    virtual HRESULT  Connect(pUnkServer) = 0;
    virtual void     Disconnect() = 0;
    virtual HRESULT  Invoke(pMessage, pChannel) = 0;
    virtual IRpcStubBuffer* IsIIDSupported(iid) = 0;
    virtual ULONG   CountRefs() = 0;
    virtual HRESULT  DebugServerQueryInterface(ppv) = 0;
    virtual void    DebugServerRelease(pv) = 0;
};

 

IRpcStubBuffer::Connect()

NAME

IRpcStubBuffer::Connect() - Informs the interface stub of server object to which it is now to be connected, and to which it should forward all subsequent Invoke operations. The stub will have to QueryInterface on pUnkServer to obtain access to appropriate interfaces. The stub will of course follow the normal AddRef rules when it stores pointers to the server object in its internal state.

Synopsis

HRESULT IRpcStubBuffer::Connect((
        IUnknown * pUnkServer );

Description

If the stub is currently connected, then this call fails with E_UNEXPECTED.

Parameters

pUnkServer

The new server object to which this stub is now to be connected.

Return Values

S_OK

E_OUTOFMEMORY

E_NOINTERFACE

E_UNEXPECTED

 

IRpcStubBuffer::Disconnect()

NAME

IRpcStubBuffer::Disconnect() - Informs the stub that it should disconnect itself from any server object that it may currently be holding on to. Notice that this function does not return a value.

Synopsis

void IRpcStubBuffer::Disconnect((
         );

 

IRpcStubBuffer::Invoke()

NAME

IRpcStubBuffer::Invoke() - Invoke the pMessage->iMethodth method in the server object interface instance to which this interface stub is currently connected. The RPC runtime infrastructure (the ``channel'') calls this method on the appropriate interface stub upon receipt of an incoming request from some remote client.

Synopsis

HRESULT IRpcStubBuffer::Invoke((
        RPCOLEMESSAGE * pMessage,
        IRpcChannelBuffer * pChannel );

Description

On entry, the members of pMessage are set as follows:

1.  Initial pMessage Values

Member Name Value on entry to Invoke
reserved members indeterminate. These members are neither to be read nor to be changed by the stub.
pvBuffer points to a buffer which contains the marshaled incoming arguments. In the case that there are no such arguments (i.e.: cbBuffer == 0), pvBuffer may be NULL, but will not necessarily be so.
cbBuffer the size in bytes of the memory buffer to which pvBuffer points. If pvBuffer is NULL, then cbBuffer will be zero (but the converse is not necessarily true, as was mentioned in pvBuffer).
iMethod the zero-based method number in the interface which is being invoked
dataRepresentation if NDR transfer syntax is being used, then this indicates the byte order, etc., according to which the data in pvBuffer has been marshaled.
rpcFlags indeterminate. Neither to be read nor to be changed by the stub.

The stub is to do the following:

[Footnote 55] Errors may of course occur at various places in this process. [Footnote 55]Such errors will cause the stub to return an error from Invoke rather than NOERROR. In cases where such an error code is returned, it is the stub's responsibility to have cleaned up any data and other resources allocated by the unmarshaling and marshaling processes or returned as out values from the server object. However, the stub is not responsible for invoking FreeBuffer to free the actual marshaling buffer (i.e.: it is illegal for the stub to do so); rather, on error return from Invoke the caller of Invoke will ignore pvBuffer, and will also free it if non-NULL. Having made that general statement as to the exit conditions of Invoke, let us examine its operation in greater detail.

If the stub cannot deal with the indicated dataRepresentation, it is to return RPC_E_SERVER_INVALIDDATAREP. If it understands the data representation, the stub is to then unmarshal the arguments from the buffer provided in pMessage->pvBuffer, the size of which is passed in pMessage->cbBuffer. If the argument data cannot be completely unmarshaled, the server is to free any partially unmarshaled data, then return RPC_E_SERVER_CANTUNMARSHALDATA from Invoke.

If the data is successfully completely unmarshaled, then the interface stub is to invoke the designated method in the designated interface on the server object. Note that the incoming pvBuffer memory buffer is at this time still valid, and that therefore the stub may if it wishes and if appropriate for the argument and data representations in question pass to the server object pointers which point directly into this buffer. The memory allocation and data copying that is thus avoided can at times be a significant performance optimization.

[Footnote 56] [Footnote 57] [Footnote 58] Once the invocation of the server object returns, the stub is to marshal the return value and out parameters returned from the server back to the client. It does so irrespective of whether the server object invocation returned an error or success code; that is, the stub marshals back to the client whatever the server object returned. [Footnote 56] The stub gets a reply buffer into which to do this marshaling by calling pChannel->GetBuffer, passing in the pMessage structure that it received in Invoke. Before calling GetBuffer, the stub is to set the cbBuffer member to the size that it requires for the to-be-allocated reply buffer. Zero is explicitly a legal value for cbBuffer, and the stub must always call GetBuffer (more precisely, to be clear about the error case: the stub must always call GetBuffer if the server object method has actually been invoked) [Footnote 57] to allocate a reply buffer, even if the stub itself does not require one (such as would be the case if for a void-returning function with no out parameters). The stub must also set dataRepresentation as appropriate for the standard by which it intends to marshal the returning values (or would marshal them if there were some). [Footnote 58] Aside from cbBuffer, dataRepresentation and possibly the contents of the bytes inside the memory buffer, on entry to GetBuffer no other data accessible from pMessage may be different than they were on entry to Invoke.

Before it allocates a reply buffer, the call to GetBuffer has the side effect of freeing the memory buffer to which pvBuffer presently points. Thus, the act by the interface stub of allocating a reply buffer for the return values necessarily terminates access by the stub to the incoming marshaled arguments.

If GetBuffer successfully allocates a reply buffer (see GetBuffer for a description of how the stub determines this), then the stub is to marshal the return value and returned out parameters into the buffer according to the rules of the transfer syntax. Once this is complete, the stub is to set the cbBuffer member to the number of bytes it actually marshaled (if it marshaled nothing, then it must explicitly set this to zero (but see also GetBuffer)), and then return NOERROR from Invoke.

If an error occurs during the unmarshaling of the incoming arguments or the marshaling of the return values, then the interface stub is responsible for correctly freeing any resources consumed by the marshaled data. See in particular CoReleaseMarshalData. See also the discussion of this topic in IRpcChannelBuffer::SendRecieve.

Parameters

pMessage

Channel-allocated message structure.

pChannel

The channel to use for buffer management, etc.

Return Values

S_OK

RPC_E_SERVER_INVALIDDATAREP

RPC_E_SERVER_CANTUNMARSHALDATA

RPC_E_SERVER_CANTMARSHALDATA

 

IRpcStubBuffer::IsIIDSupported()

NAME

IRpcStubBuffer::IsIIDSupported() - Answer whether this stub is designed to handle the unmarshaling of the indicated interface.

Synopsis

IRpcStubBuffer* IRpcStubBuffer::IsIIDSupported((
        REFIID iid );

Description

If the stub buffer supports the specified IID, then it should return an appropriate IRpcStubBuffer* for that interface. Otherwise, it should return NULL.

When presented with the need to remote a new IID on a given object, the RPC runtime typically calls this function on all the presently-connected interface stubs in an attempt to locate one that can handle the marshaling for the request before it goes to the trouble of creating a new stub.

As in IPSFactoryBuffer::CreateStub, if this stub is presently connected to a server object, then not only must this function verify that the stub can handle the requested interface id, but it must also verify (using QueryInterface) that the connected server object in fact supports the indicated interface (depending on the IID and previous interface servicing requests, it may have already done so).

A common special case is the following: interface stubs which are designed to only support one interface id (as most are designed to do) can simply check if iid designates the one interface that they handle. If not, return FALSE. Otherwise, then if connected check that the server object supports the interface. Otherwise return TRUE.

Parameters

iid

The interface that the caller wishes to know if the stub can handle. iid is never to be IID_IUnknown.

Return Values

See below.  

IRpcStubBuffer::CountRefs()

NAME

IRpcStubBuffer::CountRefs() - Return the total number of references that this stub interface instance has on the server object.

Synopsis

ULONG IRpcStub::CountRefs(
         );

Return Values

integer value

The number of such references.

 

IRpcStubBuffer::DebugServerQueryInterface()

NAME

IRpcStubBuffer::DebugServerQueryInterface() - This function exists in order to facilitate the support of debuggers which wish to provide transparency when single-stepping, etc., across remote invocations on objects. As such, the semantics of this function are a little strange in order to avoid the unnecessarily disturbing the state of the actual server object.

Synopsis

HRESULT IRpcStubBuffer::DebugServerQueryInterface((
        void ** ppv );

Description

If the stub is not presently connected then set *ppv to NULL (per the usual error-case convention) and return E_UNEXPECTED. If connected but this stub does not support the indicated interface (in the sense expressed in IsIIDSupported), then (set *ppv to NULL and) return E_NOINTERFACE instead.

Otherwise, return the interface pointer on the connected server object which would be used by an immediate subsequent invocation of Invoke on this interface stub DebugServerQueryInterface is analogous to invoking QueryInterface on the server itself with the important difference that the caller will later call DebugServerRelease to indicate that he is done with the pointer instead of releasing the returned pointer himself. It is required that DebugServerRelease be called before the interface stub itself is destroyed or, in fact, before it is disconnected.

In the vast majority of interface stub implementations, DebugServerQueryInterface can therefore be implemented simply by returning an internal state variable inside the interface stub itself without doing an AddRef on the server or otherwise running any code in the actual server object. In such implementations, DebugServerRelease will be a completely empty no-op. The other rational implementation is one where DebugServerQueryInterface does a QueryInterface on the server object and DebugServerRelease does a corresponding Release, but as this actually runs server code, the former implementation is highly preferred if at all achievable.

Parameters

ppv

The place at which the interface pointer is to be returned.

Return Values

S_OK

E_NOINTERFACE

E_UNEXPECTED

 

IRpcStubBuffer::DebugServerRelease()

NAME

IRpcStubBuffer::DebugServerRelease() - Indicate that an interface pointer returned previously from DebugServerQueryInterface is no longer needed by the caller. In most implementations, DebugServerRelease is a completely empty no-op; see the description of DebugServerQueryInterface for details.

Synopsis

void IRpcStubBuffer::DebugServerRelease((
        pv );

9.7.7    IStdMarshalInfo

The IStdMarshalInfo() interface returns the CLSID identifying the handler to be used in the destination process during standard marshaling.

An object that uses COM's default implementation of IMarshal() does not provide its own proxy but, by implementing IStdMarshalInfo(), can nevertheless specify a handler to be loaded in the client process. Such a handler would typically handle certain requests in-process and use OLE's default marshaling to delegate others back to the original object.

To create an instance of an object in some client process, COM must first determine whether the object uses default marshaling or its own implementation. If the object uses default marshaling, COM then queries the object to determine whether it uses a special handler or, simply, COM's default proxy. To get the CLSID of the handler to be loaded, COM queries the object for the IStdMarshalInfo() interface and then the IPersist() interface. If neither interface is supported, a standard handler is used.

When to Implement

If you are writing a server application that supports class emulation (that is, if your server can manipulate objects of another type in response to the Activate As option in the Convert dialog box), you must implement the IStdMarshalInfo() interface in order to return the CLSID of the handler to be used for the object.

Note that your handler must aggregate the default handler.

When to Use

You typically don't call this interface yourself. COM queries for this interface when performing standard marshaling.

Table 9-4:  IStdMarshalInfo Methods in VTable Order

IUnknown Methods Description
QueryInterface() Returns pointers to supported interfaces.
AddRef() Increments reference count.
Release() Decrements reference count.

Table 9-5:  IStdMarshalInfo Methods

IStdMarshalInfo() Method Description
GetClassForHandler Obtains the class identifier of the object handler in the destination process.

See Also

IMarshal()  

IStdMarshalInfo::GetClassForHandler()

NAME

IStdMarshalInfo::GetClassForHandler() - Retrieves the CLSID of the object handler to be used in the destination process during standard marshaling.

Synopsis

#include <objidl.h>

HRESULT GetClassForHandler(
        DWORD dwDestContext,
        void * pvDestContext,
        CLSID * pClsid );

Parameters

dwDestContext

[in] Destination context, that is, the process in which the unmarshaling will be done. The legal values for dwDestContext are taken from the enumeration MSHCTX. For information on the MSHCTX enumeration, see the ``Data Structures'' section.

pvDestContext

[in] Reserved for future use; must be NULL.

pClsid

[out] Pointer to the handler's CLSID.

Return Values

This method supports the standard return values E_INVALIDARG, E_OUTOFMEMORY, and E_UNEXPECTED, as well as the following:

S_OK

The CLSID was retrieved successfully.

9.8    Interface Remoting and Marshaling API Descriptions

 

CoGetMarshalSizeMax()

NAME

CoGetMarshalSizeMax() - Returns an upper bound on the number of bytes needed to marshal the specified interface pointer to the specified object.

Synopsis

#include <objbase.h>

STDAPI CoGetMarshalSizeMax((
        ULONG * pulSize,
        REFIID riid,
        IUnknown * pUnk,
        DWORD dwDestContext,
        LPVOID pvDestContext,
        DWORD mshlflags );

Description

This function performs the following tasks:

  1. Queries the object for an IMarshal() pointer or, if the object does not implement IMarshal(), gets a pointer to COM's standard marshaler.

  2. Using whichever pointer is obtained in the preceding step, calls IMarshal::GetMarshalSizeMax().

  3. Adds to the value returned by the call to GetMarshalSizeMax the size of the marshaling data header and, possibly, that of the proxy CLSID to obtain the maximum size in bytes of the amount of data to be written to the marshaling stream.

You do not explicitly call this function unless you are implementing IMarshal(), in which case your marshaling stub should call this function to get the correct size of the data packet to be marshaled.

The value returned by this method is guaranteed to be valid only as long as the internal state of the object being marshaled does not change. Therefore, the actual marshaling should be done immediately after this function returns, or the stub runs the risk that the object, because of some change in state, might require more memory to marshal than it originally indicated.

Parameters

pulSize

[out] Pointer to the upper-bound value on the size, in bytes, of the data packet to be written to the marshaling stream; a value of zero means that the size of the packet is unknown.

riid

[in] Reference to the identifier of the interface whose pointer is to be marshaled. This interface must be derived from the IUnknown() interface.

pUnk

[in] Pointer to the interface to be marshaled. This interface must be derived from the IUnknown() interface.

dwDestContext

[in] Destination context where the specified interface is to be unmarshaled. Values for dwDestContext come from the enumeration MSHCTX.

pvDestContext

[in] Reserved for future use; must be NULL.

mshlflags

[in] Flag indicating whether the data to be marshaled is to be transmitted back to the client process the normal case or written to a global table, where it can be retrieved by multiple clients. Values come from the enumeration MSHLFLAGS.

Return Values

This function supports the standard return value E_UNEXPECTED, as well as the following:

S_OK

The upper bound was returned successfully.

CO_E_NOTINITIALIZED

The CoInitialize() function was not called on the current thread before this function was called.

See Also

CoMarshalInterface(), IMarshal::GetMarshalSizeMax()  

CoGetStandardMarshal()

NAME

CoGetStandardMarshal() - Creates a default, or standard, marshaling object in either the client process or the server process, depending on the caller, and returns a pointer to that object's IMarshal() implementation.

Synopsis

#include <objbase.h>

STDAPI CoGetStandardMarshal((
        REFIID riid,
        IUnknown * pUnk,
        DWORD dwDestContext,
        LPVOID pvDestContext,
        DWORD mshlflags,
        LPMARSHAL * ppMarshal );

Description

The CoGetStandardMarshal() function creates a default, or standard, marshaling object in either the client process or the server process, as may be necessary, and returns that object's IMarshal() pointer to the caller. If you implement IMarshal(), you may want your implementation to call CoGetStandardMarshal() as a way of delegating to COM's default implementation any destination contexts that you don't fully understand or want to handle. Otherwise, you can ignore this function, which COM calls as part of its internal marshaling procedures.

When the COM library in the client process receives a marshaled interface pointer, it looks for a CLSID to be used in creating a proxy for the purposes of unmarshaling the packet. If the packet does not contain a CLSID for the proxy, COM calls CoGetStandardMarshal, passing a NULL pUnk value. This function creates a standard proxy in the client process and returns a pointer to that proxy's implementation of IMarshal(). COM uses this pointer to call CoUnmarshalInterface() to retrieve the pointer to the requested interface.

If your COM server application's implementation of IMarshal() calls CoGetStandardMarshal(), you should pass both the IID of (riid), and a pointer to (pUnk), the interface being requested.

This function performs the following tasks:

  1. Determines whether pUnk is NULL.

  2. If pUnk is NULL, creates a standard interface proxy in the client process for the specified riid and returns the proxy's IMarshal() pointer.

  3. If pUnk is not NULL, checks to see if a marshaler for the object already exists, creates a new one if necessary, and returns the marshaler's IMarshal() pointer.

Parameters

riid

[in] Reference to the identifier of the interface whose pointer is to be marshaled. This interface must be derived from the IUnknown() interface.

pUnk

[in] Pointer to the interface to be marshaled.

dwDestContext

[in] Destination context where the specified interface is to be unmarshaled. Values for dwDestContext come from the enumeration MSHCTX. Currently, unmarshaling can occur either in another apartment of the current process (MSHCTX_INPROC) or in another process on the same computer as the current process (MSHCTX_LOCAL).

pvDestContext

[in] Reserved for future use; must be NULL.

mshlflags

[in] Flag indicating whether the data to be marshaled is to be transmitted back to the client process the normal case or written to a global table, where it can be retrieved by multiple clients. Valid values come from the MSHLFLAGS enumeration.

ppMarshal

[out] Indirect address of IMarshal* pointer variable that receives the interface pointer to the standard marshaler.

Return Values

This function supports the standard return values E_FAIL, E_OUTOFMEMORY and E_UNEXPECTED, as well as the following:

S_OK

The IMarshal() instance was returned successfully.

CO_E_NOTINITIALIZED

The CoInitialize() or OleInitialize function was not called on the current thread before this function was called.

See Also

IMarshal()  

CoGetPSClsid()

NAME

CoGetPSClsid() - This function returns the CLSID of the DLL that implements the proxy and stub for the specified interface

Synopsis

#include <objbase.h>

WINOLEAPI CoGetPSClsid((
        REFIID riid,
        CLSID * pclsid );

Description

The CoGetPSClsid() function looks at the HKEY_CLASSES_ROOT\Interfaces\{ string form of riid }\ProxyStubClsid32 key in the registry to determine the CLSID of the DLL to load in order to create the proxy and stub for the interface specified by riid. This function also returns the CLSID for any interface IID registered by CoRegisterPSClsid() within the current process.

Parameters

riid

[in] The interface whose proxy/stub CLSID is to be returned.

pclsid

[out] Where to store the proxy/stub CLSID for the interface specified by riid.

Return Values

S_OK

The proxy/stub CLSID was successfully returned.

E_INVALIDARG

One of the parameters is invalid.

E_OUTOFMEMORY

There is insufficient memory to complete this operation.

See Also

CoRegisterPSClsid()  

CoMarshalHresult()

NAME

CoMarshalHresult() - Marshals an HRESULT to the specified stream, from which it can be unmarshaled using the CoUnmarshalHresult function.

Synopsis

#include <objbase.h>

STDAPI CoMarshalHresult(
        IStream * pStm,
        HRESULT hresult );

Description

An HRESULT is process-specific, so an HRESULT that is valid in one process might not be valid in another. If you are writing your own implementation of IMarshal() and need to marshal an HRESULT from one process to another, either as a parameter or a return code, you must call this function. In other circumstances, you will have no need to call this function.

This function perfoms the following tasks:

  1. Writes an HRESULT to a stream.

  2. Returns an IStream() pointer to that stream.

Parameters

pStm

[in] Pointer to the marshaling stream.

hresult

[in] HRESULT in the originating process.

Return Values

This function supports the standard return values E_OUTOFMEMORY and E_UNEXPECTED, as well as the following:

S_OK

The HRESULT was marshaled successfully.

STG_E_INVALIDPOINTER

Bad pointer passed in for pStm.

STG_E_MEDIUMFULL

The medium is full.

See Also

CoUnmarshalHresult, IStream()  

CoMarshalInterface()

NAME

CoMarshalInterface() - Writes into a stream the data required to initialize a proxy object in some client process. The COM library in the client process calls the CoUnmarshalInterface() function to extract the data and initialize the proxy. CoMarshalInterface() can marshal only interfaces derived from IUnknown().

Synopsis

#include <objbase.h>

STDAPI CoMarshalInterface((
        IStream * pStm,
        REFIID riid,
        IUnknown * pUnk,
        DWORD dwDestContext,
        void * pvDestContext,
        DWORD mshlflags );

Description

The CoMarshalInterface() function marshals the interface referred to by riid on the object whose IUnknown() implementation is pointed to by pUnk. To do so, the CoMarshalInterface() function performs the following tasks:

  1. Queries the object for a pointer to the IMarshal() interface. If the object does not implement IMarshal(), meaning that it relies on COM to provide marshaling support, CoMarshalInterface() gets a pointer to COM's default implementation of IMarshal().

  2. Gets the CLSID of the object's proxy by calling IMarshal::GetUnmarshalClass(), using whichever IMarshal() interface pointer has been returned.

  3. Writes the CLSID of the proxy to the stream to be used for marshaling.

  4. Marshals the interface pointer by calling IMarshal::MarshalInterface().

If you are implementing existing COM interfaces or defining your own interfaces using the Microsoft Interface Definition Language (MIDL), the MIDL-generated proxies and stubs call CoMarshalInterface() for you. If you are writing your own proxies and stubs, your proxy code and stub code should each call CoMarshalInterface() to correctly marshal interface pointers. Calling IMarshal() directly from your proxy and stub code is not recommended.

If you are writing your own implementation of IMarshal(), and your proxy needs access to a private object, you can include an interface pointer to that object as part of the data you write to the stream. In such situations, if you want to use COM's default marshaling implementation when passing the interface pointer, you can call CoMarshalInterface() on the object to do so.

Parameters

pStm

[in] Pointer to the stream to be used during marshaling.

riid

[in] Reference to the identifier of the interface to be marshaled. This interface must be derived from the IUnknown() interface.

pUnk

[in] Pointer to the interface to be marshaled; can be NULL if the caller does not have a pointer to the desired interface. This interface must be derived from the IUnknown() interface.

dwDestContext

[in] Destination context where the specified interface is to be unmarshaled. Values for dwDestContext come from the enumeration MSHCTX. Currently, unmarshaling can occur either in another apartment of the current process (MSHCTX_INPROC) or in another process on the same computer as the current process (MSHCTX_LOCAL).

pvDestContext

[in] Reserved for future use; must be NULL.

mshlflags

[in] Flag specifying whether the data to be marshaled is to be transmitted back to the client process the normal case or written to a global table, where it can be retrieved by multiple clients. Values come from the MSHLFLAGS enumeration.

Return Values

This function supports the standard return values E_FAIL, E_OUTOFMEMORY, and E_UNEXPECTED, as well as the following:

S_OK

The interface pointer was marshaled successfully.

CO_E_NOTINITIALIZED

The CoInitialize() or OleInitialize function was not called on the current thread before this function was called.

IStream() errors

This function can also return any of the stream-access error values returned by the IStream() interface.

See Also

CoUnmarshalInterface(), IMarshal::MarshalInterface()  

CoRegisterPSClsid()

NAME

CoRegisterPSClsid() - Enables a downloaded DLL to register its custom interfaces within its running process so that the marshaling code will be able to marshal those interfaces.

Synopsis

#include <objbase.h>

WINOLEAPI CoRegisterPSCLsid(
        REFIID riid,
        REFCLSID rclsid );

Description

Normally the code responsible for marshaling an interface pointer into the current running process reads the HKEY_CLASSES_ROOT\Interfaces section of the registry to obtain the CLSID of the DLL containing the ProxyStub code to be loaded. To obtain the ProxyStub CLSIDs for an existing interface, the code calls the CoGetPSClsid() function.

In some cases, however, it may be desirable or necessary for an in-process handler or in-process server to make its custom interfaces available without writing to the registry. A DLL downloaded across a network may not even have permission to access the local registry, and because the code originated on another machine, the user, for security purposes, may want to run it in a restricted environment. Or a DLL may have custom interfaces that it uses to talk to a remote server and may also include the ProxyStub code for those interfaces. In such cases, a DLL needs an alternative way to register its interfaces. CoRegisterPSClsid(), used in conjunction with CoRegisterClassObject(), provides that alternative.

A DLL would normally call CoRegisterPSClsid() as shown in the following code fragment:

HRESULT RegisterMyCustomInterface(DWORD *pdwRegistrationKey)
{
    HRESULT hr = CoRegisterClassObject(CLSID_MyProxyStubClsid,
        pIPSFactoryBuffer,
        CLSCTX_INPROC_SERVER,
        REGCLS_MULTIPLEUSE
        pdwRegistrationKey);
    if(SUCCEEDED)(hr))
    {
        hr = CoRegisterPSClsid(IID_MyCustomInterface,
             CLSID_MyProxyStubClsid);
    }
    return hr;
}

Parameters

riid

[in] Points to the IID of the interface to be registered.

rclsid

[in] Points to the CLSID of the DLL that contains the proxy/stub code for the custom interface specified by riid.

Return Values

S_OK

The custom interface was successfully registered.

E_INVALIDARG

One of the parameters is invalid.

E_OUTOFMEMORY

There is insufficient memory to complete this operation.

See Also

CoGetPSClsid(), CoRegisterClassObject()  

CoReleaseMarshalData()

NAME

CoReleaseMarshalData() - Destroys a previously marshaled data packet.

Synopsis

#include <objbase.h>

STDAPI CoReleaseMarshalData((
        IStream * pStm );

Description

The CoReleaseMarshalData() function performs the following tasks:

  1. The function reads a CLSID from the stream.

  2. If COM's default marshaling implementation is being used, the function gets an IMarshal() pointer to an instance of the standard unmarshaler. If custom marshaling is being used, the function creates a proxy by calling the CoCreateInstance() function, passing the CLSID it read from the stream, and requesting an IMarshal() interface pointer to the newly created proxy.

  3. Using whichever IMarshal() interface pointer it has acquired, the function calls IMarshal::ReleaseMarshalData().

You typically do not call this function. The only situation in which you might need to call this function is if you use custom marshaling (write and use your own implementation of IMarshal()). Examples of when CoReleaseMarshalData() should be called include the following situations:

As an analogy, the data packet can be thought of as a reference to the original object, just as if it were another interface pointer being held on the object. Like a real interface pointer, that data packet must be released at some point. The use of IMarshal::ReleaseMarshalData() to release data packets is analogous to the use of IUnknown::Release() to release interface pointers.

Note that you do not need to call CoReleaseMarshalData() after a successful call of the CoUnmarshalInterface() function; that function releases the marshal data as part of the processing that it does.

Parameters

pStm

[in] Pointer to the stream that contains the data packet to be destroyed.

Return Values

This function supports the standard return values E_FAIL, E_INVALIDARG, E_OUTOFMEMORY, and E_UNEXPECTED, as well as the following:

S_OK

The data packet was successfully destroyed.

STG_E_INVALIDPOINTER

An IStream() error dealing with the pStm parameter.

CO_E_NOTINITIALIZED

The CoInitialize() or OleInitialize function was not called on the current thread before this function was called.

See Also

IMarshal::ReleaseMarshalData()  

CoUnmarshalHresult()

NAME

CoUnmarshalHresult() - Unmarshals an HRESULT type from the specified stream.

Synopsis

#include <objbase.h>

STDAPI CoUnmarshalHresult(
        LPSTREAM pStm,
        HRESULT * phresult );

Description

You do not explicitly call this function unless you are performing custom marshaling (that is, writing your own implementation of IMarshal()), and your implementation needs to unmarshal an HRESULT.

You must use CoUnmarshalHresult to unmarshal HRESULTs previously marshaled by a call to the CoMarshalHresult function.

This function performs the following tasks:

  1. Reads an HRESULT from a stream.

  2. Returns the HRESULT.

Parameters

pStm

[in] Pointer to the stream from which the HRESULT is to be unmarshaled.

phresult

[out] Pointer to the unmarshaled HRESULT.

Return Values

This function supports the standard return values E_OUTOFMEMORY and E_UNEXPECTED, as well as the following:

S_OK

The HRESULT was unmarshaled successfully.

STG_E_INVALIDPOINTER

pStm is an invalid pointer.

See Also

CoMarshalHresult, IStream()  

CoUnmarshalInterface()

NAME

CoUnmarshalInterface() - Initializes a newly created proxy using data written into the stream by a previous call to the CoMarshalInterface() function, and returns an interface pointer to that proxy.

Synopsis

#include <objbase.h>

STDAPI CoUnmarshalInterface((
        IStream * pStm,
        REFIID riid,
        void ** ppv );

Description

The CoUnmarshalInterface() function performs the following tasks:

  1. Reads from the stream the CLSID to be used to create an instance of the proxy.

  2. Gets an IMarshal() pointer to the proxy that is to do the unmarshaling. If the object uses COM's default marshaling implementation, the pointer thus obtained is to an instance of the generic proxy object. If the marshaling is occurring between two threads in the same process, the pointer is to an instance of the in-process free threaded marshaler. If the object provides its own marshaling code, CoUnmarshalInterface() calls the CoCreateInstance() function, passing the CLSID it read from the marshaling stream. CoCreateInstance() creates an instance of the object's proxy and returns an IMarshal() interface pointer to the proxy.

  3. Using whichever IMarshal() interface pointer it has acquired, the function then calls IMarshal::UnmarshalInterface() and, if appropriate, IMarshal::ReleaseMarshalData().

The primary caller of this function is COM itself, from within interface proxies or stubs that unmarshal an interface pointer. There are, however, some situations in which you might call CoUnmarshalInterface(). For example, if you are implementing a stub, your implementation would call CoUnmarshalInterface() when the stub receives an interface pointer as a parameter in a method call.

Parameters

pStm

[in] Pointer to the stream from which the interface is to be unmarshaled.

riid

[in] Reference to the identifier of the interface to be unmarshaled.

ppv

[out] Address of pointer variable that receives the interface pointer requested in riid. Upon successful return, *ppvcontains the requested interface pointer for the unmarshaled interface.

Return Values

This function supports the standard return value E_FAIL, as well as the following:

S_OK

The interface pointer was unmarshaled successfully.

STG_E_INVALIDPOINTER

pStm is an invalid pointer.

CO_E_NOTINITIALIZED

The CoInitialize() function was not called on the current thread before this function was called.

CO_E_OBJNOTCONNECTED

The object application has been disconnected from the remoting system (for example, as a result of a call to the CoDisconnectObject() function).

REGDB_E_CLASSNOTREG

An error occurred reading the registration database.

E_NOINTERFACE

The final QueryInterface() of this function for the requested interface returned E_NOINTERFACE.

CoCreateInstance() errors

An error occurred when creating the handler.

See Also

CoMarshalInterface(), IMarshal::UnmarshalInterface()

9.9    Interface Remoting and Marshaling Enumeration Definitions

9.9.1    EXTCONN

The EXTCONN enumeration specifies the type of external connection existing on an embedded object. Currently, the only supported type is EXTCONN_STRONG, meaning that the external connection is a link. This EXTCONN constant is used in the IExternalConnection::AddConnection() and IExternalConnection::ReleaseConnection() methods.

typedef enum tagEXTCONN 
{ 
    EXTCONN_STRONG      = 0X0001, 
    EXTCONN_WEAK        = 0X0002, 
    EXTCONN_CALLABLE    = 0X0004 
} EXTCONN;

Elements

EXTCONN_STRONG

If this value is specified, the external connection must keep the object alive until all strong external connections are cleared through IExternalConnection::ReleaseConnection().

EXTCONN_WEAK

This value is currently not used.

EXTCONN_CALLABLE

This value is currently not used.

9.9.2    MSHCTX

The MSHCTX enumeration constants specify the destination context, which is the process in which the unmarshaling is to be done. These flags are used in the IMarshal() and IStdMarshalInfo() interfaces and in the CoMarshalInterface() and CoGetStandardMarshal() functions.

MSHCTX is defined in WTYPES.IDL and in WTYPES.H].

typedef enum tagMSHCTX 
{ 
    MSHCTX_LOCAL               = 0, 
    MSHCTX_NOSHAREDMEM         = 1, 
    MSHCTX_DIFFERENTMACHINE    = 2, 
    MSHCTX_INPROC              = 3 
} MSHCTX;

Elements

MSHCTX_LOCAL

The unmarshaling process is local and has shared memory access with the marshaling process.

MSHCTX_NOSHAREDMEM

The unmarshaling process does not have shared memory access with the marshaling process.

MSHCTX_DIFFERENTMACHINE

The unmarshaling process is on a different machine. The marshaling code cannot assume that a particular piece of application code is installed on that machine.

MSHCTX_INPROC

The unmarshaling will be done in another apartment in the same process. If your object supports multiple threads, your custom marshaler can pass a direct pointer instead of creating a proxy object.

See Also

CoGetStandardMarshal(), CoMarshalInterface(), IMarshal(), IStdMarshalInfo()

9.9.3    MSHLFLAGS

The MSHLFLAGS enumeration constants determine why the marshaling is to be done. These flags are used in the IMarshal() interface and the CoMarshalInterface() and CoGetStandardMarshal() functions.

MSHFLAGS is defined in WTYPES.IDL and WTYPES.H].

typedef enum tagMSHLFLAGS 
{ 
    MSHLFLAGS_NORMAL         = 0, 
    MSHLFLAGS_TABLESTRONG    = 1, 
    MSHLFLAGS_TABLEWEAK      = 2 
} MSHLFLAGS;

Elements

MSHLFLAGS_NORMAL

The marshaling is occurring because an interface pointer is being passed from one process to another. This is the normal case. The data packet produced by the marshaling process will be unmarshaled in the destination process. The marshaled data packet can be unmarshaled just once, or not at all. If the receiver unmarshals the data packet successfully, the CoReleaseMarshalData() function is automatically called on the data packet as part of the unmarshaling process. If the receiver does not or cannot unmarshal the data packet, the sender must call the CoReleaseMarshalData() function on the data packet.

MSHLFLAGS_TABLESTRONG

The marshaling is occurring because the data packet is to be stored in a globally accessible table from which it can be unmarshaled one or more times, or not at all. The presence of the data packet in the table counts as a strong reference to the interface being marshaled, meaning that it is sufficient to keep the object alive. When the data packet is removed from the table, the table implementer must call the CoReleaseMarshalData() function on the data packet.

MSHLFLAGS_TABLESTRONG is used by the RegisterDragDrop function when registering a window as a drop target. This keeps the window registered as a drop target no matter how many times the end user drags across the window. The RevokeDragDrop function calls CoReleaseMarshalData().

MSHLFLAGS_TABLEWEAK

The marshaling is occurring because the data packet is to be stored in a globally accessible table from which it can be unmarshaled one or more times, or not at all. However, the presence of the data packet in the table acts as a weak reference to the interface being marshaled, meaning that it is not sufficient to keep the object alive. When the data packet is removed from the table, the table implementer must call the CoReleaseMarshalData() function on the data packet.

MSHLFLAGS_TABLEWEAK is typically used when registering an object in the Running Object Table (ROT). This prevents the object's entry in the ROT from keeping the object alive in the absence of any other connections. See IRunningObjectTable::Register() for more information.

See Also

CoGetStandardMarshal(), CoMarshalInterface(), CoReleaseMarshalData()