Let's now take a closer look at how the DCOM magic works. When a client creates an object instance supported by a local
server, this is what happens:.EXE
CoCreateInstance()
on a CLSID supported by a local server.
The SCM is a process whose sole purpose in life is to locate implementations or specific instances of requested COM classes. Because of this, it's a close friend of the system registry where all the CLSIDs to implementation mappings are kept persistently. This SCM is typically named
on Windows 95 and Windows NT systems.Rpcss.exe
Once a client is connected to an instance of a COM class, it holds an interface pointer to an interface proxy. With this interface proxy, the client may obtain other interface pointers (using
recall that all interfaces must implement QueryInterface()—
) or call methods of the interface directly). When such methods are invoked, the COM runtime must send all the arguments for the method from the client process to the local server process. This requires the use of a type of interprocess communications supported by the underlying operating system. In the case of COM, the mechanism used is Distributed Computing Environment Remote Procedure Calls (DCE RPC). DCE RPC has several nice features:IUnknown::QueryInterface()
COM and DCOM leverage heavily on these capabilities.
Note: COM actually will attempt to use lightweight RPC (LRPC) whenever possible when the two communicating objects/components are residing on the same machine and OS. LRPC is a Microsoft proprietary variant of RPC which has the exact same calling syntax as the DCE RPC runtime (thus the seamless interchangeability) but is optimized to reduce data copying and eliminate access to the networking code altogether.
When we put the RPC layer into the picture during a method invocation, the situation becomes a bit more complex. Namely, the call is now 'cross-process' or 'cross-machine'. The actual call is delivered to an object within the current process called an Interface Proxy. The following diagram shows the activities that will occur:
Note that there are many more subtleties associated with the marshaling action than the simple description implies. For example, if a pointer to a data item is marshaled across two processes, just sending the value of the pointer itself is useless since the receiver lives in a totally separate process/addressing space. Instead, the actual data item itself must be sent across the wire and a pointer to it reconstructed within the receiver process in order for the marshaling to work.
Now is a good time to find out what the interface proxies and stubs are. Under the COM model, they are actually small COM objects. The code for these objects was created automatically when we ran our original IDL (interface description language) through the MIDL compiler. Based on the data type of the method arguments and return values, the MIDL compiler creates these marshalling proxy/stub pairs for communicating between processes. One pair of proxy/stub classes is created for each interface. If you look back in Chapter 7 where we created a local server called
, you'll find a file called ATLFinder.EXE
You can actually perform:ATLFINDERPS.MK.
NMAKE –F ATLFINDERPS.MK
in a DOS box to create and register the proxy/stub for marshalling of the interfaces supported by the
local server. To satisfy your curiosity, look in your Chapter 7 working directory for the ATLFinder.EXE
project and find the ATLFinder.EXE
file to see what MIDL generated proxy/stub code physically looks like.ATLFinder_p.c
So far we've focused on the conceptual view of providing proxy and stub code for interface method invocation across processes, and indeed it was the way that it was done for a period of time. With DCOM, though, Microsoft has introduced automatic type-library based marshaling. Automatic type-library marshaling actually builds these proxy and stub objects on the fly from type library information obtained on an interface. What we see here is actually a reuse of the marshaling technology Microsoft had been using for OLE Automation. As long as the data type that needs to be marshaled is compatible with OLE Automation (which essentially means all the data types that a
can hold), you don't even need the MIDL generated proxy/stub code.VARIANT