Note
Clicking on a [Return] link takes you to the first reference to the footnote you are returning from. If there are multiple references to that footnote, this might not be the place you came from.
The word ``moniker'' is a synonym for ``nickname.'' [Return]
``Easy'' is a relative term: without COM, some sorts of programming are simply not possible and thus the term ``easy'' is utterly empty. [Return]
The term ``interface'' is used in a very similar sense in the Common Object Request Broker Architecture (CORBA) design of the Object Management Group. In both cases the idea of an ``interface'' is a signature of functions and, implicitly, capabilities, entirely abstracted from the implementation. The major difference between COM and CORBA at this high level is that CORBA objects have one and only one interface while COM objects can have many interfaces simultaneously. DCE RPC (from The Open Group) uses the term ``interface'' in a similar manner. [Return]
Indeed, in principle the intrinsic method
dispatch overhead of COM is in fact
less
than the intrinsic
overhead of C++ multiple inheritance method invocations.
In a multiple inheritance
situation, C++ must on every method invocation adjust the pointer to be
appropriate for the actual method which is to be executed.
In a COM object
which supports multiple interfaces, which is directly analogous to the multiple
inheritance situation, one must of course also do a similar sort of adjustment,
and this is done in the
QueryInterface()
method.
However,
when using a given
interface on the object, one can invoke
QueryInterface()
once and use the
returned pointer many times.
Thus, the cost of the
QueryInterface()
operation can
be amortized over all the subsequent usage, resulting in less overall dispatch
overhead.
Be aware, however, that this distinction is completely academic.
In
almost all real word situations, both dispatch mechanisms provide more than
adequate performance.
[Return]
There can be subtle differences in the flow-of-control between calling in-process and out-of-process objects. In particular, an out-of-process object call may result in a call-back prior to the completion of the original call. COM provides standard mechanisms to deal with call-backs and reentrancy; even on single-threaded operating systems. Without such standards, true interoperability between out-of-process objects (of which cross-network objects is just a typical case) is impossible. [Return]
Although ``class'' and ``type'' can often be used interchangeably, in COM a ``type'' is the total signature of an object, which is the union of the interfaces that the object supports. ``Class'' is a particular implementation of a type, and can include certain unique implementation-specific attributes such as product name, icon, etc. For example, the ``chart'' type (identified by a GUID by whomever first defines that particular combination of interfaces) might be supported by Lotus 1-2-3 for Windows and Microsoft Excel for the Macintosh, each of which are separate classes. Normally, types are polymorphic; any consumer of the services provided by interfaces making up the type can use any class that implements the type. [Return]
As an illustration of how unique GUIDs are consider that one could generate 10 million GUIDs a second until the year 5770 AD and each one would be unique. [Return]
See, for example, Richard Helm (Senior Researcher, IBM Thomas J. Watson Research Center), Ensuring Semantic Integrity of Reusable Objects (Panel), OOPSLA '92 Conference Proceedings, p.300; John Lamping (Xerox PARC), Typing the Specialization Interface, OOPSLA '93 Conference Proceedings, p.201. [Return]
Readers interested in this issue should examine the ``connectable object'' architecture described in Chapter 12. Connectable objects enable an event model that provides a standard, powerful convention for a COM object to signal to any interested client that is about to do something, that is doing something, and that it is finished doing something. The model also allows clients to cancel the event outright or to cancel it in favor of an ``overriding'' event supplied by the client. This event model coupled with a few additional conventions could provide COM with all the traditional features of implementation inheritance and more without the traditional risks. For an interesting discussion of the problems of traditional implementation inheritance as well as a description of how an inheritance system might provide robust type-safety, see Hauck, Inheritance Modeled with Explicit Bindings: An Approach to Typed Inheritance, OOPSLA '93 Conference Proceedings, p.231. [Return]
Connecting to objects through an ``intelligent/persistent name'' (moniker) falls into this category. [Return]
Not only are there situations where there is a need for designs optimized for cross network efficiency, but there are also cases where in-process efficiency is more important. Just as COM provides mechanisms whereby the remote case can be optimized (custom marshaling) it also allows for the design of interfaces that are optimized for the in-process case. [Return]
Any internally-used memory in COM and in-process objects can use any allocation scheme desired, but the COM memory allocator is a handy, efficient, and thread-safe allocator. [Return]
This rule is stronger than it might seem to need to be in order to promote more robust application interoperability. [Return]
Commonly pronounced ``scum.'' [Return]
Strictly speaking, the ``handler'' is simply the representative of a remote object that resides in the client's process and which internally contains the remote connection. There is thus always a handler present when remoting is being done, though very often the handler is a trivial one which merely forwards all calls. In that sense, ``handler'' is synonymous with the terms ``proxy object'' or ``object proxy.'' In practice the term ``handler'' tends to be used more when there is in fact a non-trivial handler, with ``proxy'' usually used when the handler is in fact trivial. [Return]
Readers more familiar with RPC than with COM will recognize "client stub" and "server stub" rather than "proxy" and "stub" but the phrases are analogous. [Return]
ActiveX Controls use the Connectable Objects mechanisms extensively. [Return]
Note that this usage of the term multicasting may differ from what some readers are accustomed to. In some systems multicasting is used to describe a connection-less broadcast. Connectable objects are obviously connection oriented. [Return]
This specification recommends that the COM implementation on a given platform (Windows, Macintosh, etc.) includes a standard storage implementation for use by all applications. [Return]
This mechanism, in fact, was employed by compound documents in Microsoft's OLE version 1.0. The problems described here were some of the major limitations of OLE 1.0 which provided much of the impetus for COM's Persistent Storage technology. [Return]
The application would only create year, month, and day substorages for those days that had information in them, that is, the diary application would create sparse storage for efficiency. [Return]
Case sensitivity is a locale-sensitive
operation: some characters compare case-insenstive-equal in some locales and
-not-equal in others.
In an
IStorage()
implementation,
the case-insenstive
comparision is done with respect to the current locale in which the system
is
presently running.
This has implications on the use of
IStorage()
names for those
who wish to create globally portable documents.
[Return]
The word ``moniker'' is a synonym for ``nickname.'' [Return]
One of the few instances of inheritance
from one major interface to another, which the
IMoniker()
designer
later decided was actually less preferable to having a moniker implement
IMoniker()
and
IPersistStream()
separately.
See the first footnote in Section
Section 9.1
in
Chapter 9.
[Return]
OLE for Real-Time Market Data was formerly called the ``WOSA Extensions for Real Time Market Data''. More information on this and other industry specific extensions to OLE is available from Microsoft. [Return]
Astute readers will wonder why Uniform Data Transfer is defined using the Connectable Objects interfaced described previously. The reason is simple: UDT was designed as part of the original OLE 2.0 specification in 1991, and Connectable Objects were not introduced until the release of the OLE Controls specification in 1993. [Return]
Assuming the platform supports attaching resources to binary images. [Return]
The ``Microsoft Object Mapping'' is an
open specification describing the detailed layout of C++ objects.
It is supported
by the MS C/C++ compiler, as well as C++ compilers from other vendors including
Borland, Symantec, Watcom, , and others.
This is also the location of the
this pointer as placed by CFront when using the traditional right-to-left
__cdecl
calling sequence.
Thus, we achieve a large degree of interoperability.
[Return]
Usually this data
follows
the
pVtbl
pointer, but this is not required.
It is perfectly
legal for object-specific data to precede the vtbl pointer, and this in fact
will be common with many C++ compilers.
[Return]
And, indeed, this syntax will at times be somewhat abused. [Return]
Of course, if a client timed the call it might be able to discern a performance penalty if it had both in-process and out-of-process objects to compare. [Return]
Though be aware that the use of the term GUID on page 587 is regrettably not the same as its usage in this specification. In this specification, the term GUID is used to refer to all identifiers that are ``interoperable'' with UUIDs as defined on p586; p587 uses the term to refer to one specific central-authority allocation scheme. Apologies to those who may be confused by this state of affairs. [Return]
There are in fact more general cases than
illustrated here involving n-way rather than 2-way interactions of matched
AddRef()
/
Release()
pairs, but that will not
be elaborated on here.
[Return]
The connection point interfaces introduced in the OLE Controls specification are a real world example of this concept. [Return]
``This'' is the appropriate thing to
AddRef
in an object implementation using the approach of multiply
inheriting from the suite of interfaces supported by the object; more complex
implementation strategies will need to modify this appropriately.
[Return]
An ``outgoing'' interface is one that an object defines itself but for which the object is itself a client. Another piece of code called the ``sink'' (generically) implements the outgoing interface such that the object can call the sink. [Return]
Do not use this CLSID for your own purposes-it is simply an example. See Section Section 19.2. [Return]
In other words, the client may initialize
the object by telling it to read text from a file or by handing text to it
through IDataObject::SetData
.
Either way, the object now has some
text to render graphically or to save to a file.
[Return]
In general, though, precisely, one can invent interfaces which choose to violate this rule. However, such interfaces are, for example, unlikely to have their remoting proxies and stubs generated with common tools. [Return]
On Win32 platforms this message sink is a window. [Return]
Of course, on other platforms the mechanism for associating resources with a binary are platform dependent. [Return]
An interface with such an
IUnknown()
is sometimes called an ``inner'' interface on the aggregated object.
There may, in general, be several inner interfaces on an object.
IRpcProxyBuffer()
, for example, is one.
This is a property of the
interface itself, not the implementation.
[Return]
In fact, there exist several standard sets of rules, each promoted by a different organization. Two common such sets of rules are known as ``Network Data Representation'' (NDR) and ``External Data Representation'' (XDR) chiefly promoted respectively by The Open Group and Sun Microsystems. ASN.1 is another standard for the same sort of technology. [Return]
Notice here that we're only discussing the marshaling of pointers to interfaces, and that the term ``custom object marshaling'' applies only to the marshaling of this data type. In general in a given remote procedure call the many other kinds of data which appear as function parameters also needs to be marshaled: strings, integers, structures, etc. We shall not concern ourselves here with such other data types, but instead concentrate our discussion on marshaling interface pointers. [Return]
i.e.: at compile time of the original marshaling stub [Return]
That is, it is explicitly legal for the
caller of
GetMarshalSizeMax
to allocate a fixed size marshaling
buffer containing no more than the indicated upper bound number of bytes.
[Return]
Astute readers will notice an abuse of terminology here: what is really being marshaled in hand is one particular interface on the object, not the whole object, though in fact in the remote process access to the whole process is indeed obtained: new interfaces on the object will be marshaled later as needed. We trust that this will not lead to too much confusion. [Return]
Other RPC systems sometimes instead call these ``client side stubs'' and ``server side stubs.'' Sometimes we mix things up a bit and refer to ``proxy interfaces'' and ``stub interfaces'' instead of ``interface proxies'' and ``interface stubs.'' [Return]
There are, however, implied requirements
for the existence of some piece of code / state that manages the
entire set ofexternal remoting connections for a given object.
See
CoLockObjectExternal()
, for example.
[Return]
The layout of this structure is as odd as it is for historical reasons. Apologies are extended to those whose design aesthetics are offended. [Return]
This permits the channel to behind-the-scenes add additional space into the buffer. Such a capability is needed, for example, in order to support remote debugging. [Return]
The fact that cbBuffer is unchanged can be of particular use to interface stubs. See IRpcStubBuffer::Invoke. [Return]
That is, if
SendReceive
returns an error.
Note that this does
NOT
indicate an
error returned from the function invocation on the server object, for in that
case
SendReceive
returns success; rather, it indicates
an error that occurred somewhere in the RPC transmission.
[Return]
It is possible that in the future a less restrictive rule as to the duration in which the interface proxy may hold on to ppvDestCtxt may be established, such as (perhaps) guaranteeing that the pointer is valid for the lifetime of the interface proxy itself. However, as it stands today, the rule, as stated here, is in fact the law. [Return]
Be careful with the terminology here: we are not talking at all about what values are returned from the invocation of the server object, but rather only about errors that occur in the unmarshaling and marshaling process itself. [Return]
However, debugging versions of the stub may if they wish to at this time check that certain details of the contract of the interface have been upheld. A common example of this is checking that on error return from the server allocated out-values are explicitly NULLed, a policy which is common to many interfaces. This is simply in the interest of improving the debug capabilities. It is illegal, however, to do such things in non-debug versions of stubs; they must always simply marshal back whatever the server returned. [Return]
This policy exists in order to enable behind-the-scenes things such as debugging support to function in all cases. [Return]
Presently, this is only significant if NDR transfer syntax is in use. In NDR, it is explicitly the case that the return values may be marshaled using a different data representation than was used for the incoming arguments. [Return]
The name ``HRESULT
''
is retained for historical reasons.
Readers
familiar with programming COM on the Windows platform will note that
HRESULT
is
analogous to
SCODE
.
[Return]
As of this writing, said body is Microsoft Corporation. [Return]
``elt'' by itself in the function prototypes is just ``element'' [Return]
Think of ``rgelt'' as short for ``range of elt'', signifying an array. [Return]
An ``outgoing'' interface is one that an object defines itself but for which the object is itself a client. Another piece of code called the ``sink'' (generically) implements the outgoing interface such that the object can call the sink. [Return]
This function also takes some parameters that provide contextual information to the binding process which we shall get to in a moment. [Return]
More precisely, it may not have a debugger attached to it: depending on the debugger's implementation and the relative location of the two processes with respect to machine boundaries, a new debugger instance may or may not need to be created. The main point is that the process wasn't being debugged. [Return]
That is, in the channel implementation
approach described here, which uses only one memory buffer.
Another channel
implementation approach would use two separate buffers, one to give back to
the interface proxy, and another independent one for the debug information.
Such an implementation would only need to call
DebugORPCClientGetBufferSize
in its
IRpcChannellBuffer::SendReceive
implementation
immediately before calling
DebugORPCClientFillBuffer
.
While
perfectly legal, this will not be elaborated further here, though in fact
this is the implementation likely to be used in practice, given how the debug
data is to be transmitted in the COM Network Protocol.
We trust that readers
can accommodate our pedagogical style; apologies to those who cannot.
[Return]
Some control as to whether this is to be actually carried out is provided by the first four bytes of the incoming debug data. [Return]
This is important in error handling cases to allow us to ensure that breakpoints are always cleared correctly. [Return]
``MARB'' is ``Mike Alex Rico Bob,'' arranged in an order such that it makes a goofy-sounding syllable. Call us whimsical. [Return]
This is so segment names such as
.orpc1
,
.orpc2
...
can be used if the remoting
code needs to be split up into different segments for swap tuning, etc.
[Return]
It is not guaranteed that an RPC call will happen for every such transition. The debugger should deal with the case where it receives no notification about an RPC call. [Return]
In Windows NT, the registry is securable. [Return]
One can think of this as IDL with a) default packing override, and b) the ability to have a union keyed by a GUID. This will be made more precise in future drafts of this specification. [Return]
This is presently Microsoft Corporation. [Return]
By definition one cannot, for example, write a source-portable DCE IDL compiler, for the code that calls SendReceive in the proxies is implementation-specific. [Return]
Microsoft has in its MIDL specification language defined additional extensions to DCE IDL; however, these are orthogonal to the subject of COM interface, and thus are not dealt with here. [Return]
This is a non-COM-related Microsoft extension, shown here for completeness. [Return]
Historically the library statement was supported only in a variant of IDL called ODL that was central to OLE Automation. [Return]