[Previous] [Contents] [Next]



  1. For example, DirectX, a set of specialized components for graphics programming in Microsoft Windows, does not use any COM+ component services because of its critical performance requirements.

Chapter One

  1. With the release of Windows NT 4.0 in 1996, COM gained the functionality necessary to invoke components that ran on remote computers connected via a network. This technology, at first called Distributed COM, is now an integral part of COM+ itself.

Chapter Two

  1. This calling convention specifies that parameters are pushed onto the stack from left to right and that the called function pops its own arguments from the stack before returning.
  2. IDL plays an important role in the development of COM+ objects, but it is not part of COM+. IDL is simply a tool used to help programmers define interfaces.
  3. The sun is expected to last only another 4.5 billion years, after which COM+ might lose some of its universal appeal.
  4. These calls are CoTaskMemAlloc, CoTaskMemFree, CoTaskMemRealloc, and the IMalloc methods of the task allocator object returned by CoGetMalloc.
  5. In early versions of OLE, applications could replace the default memory allocator by passing the address of a custom allocator object to CoInitializeEx. COM+ does not currently support applications replacing this allocator, and if the parameter is anything but NULL, CoInitializeEx returns an E_INVALIDARG error.
  6. The registry is a system-wide data store that contains information about the current user, machine configuration, application settings, and COM+ component information. You can view and edit the data in the registry with the registry editor utility, regedit.exe.
  7. This code will run without complaint in this case because our implementation of ISum runs in-process with the client. However, changing the object's v-table slightly or running the component outside of the client process where it would depend on the marshaling infrastructure of COM+ would make this code deadly.
  8. Actually, the compiler first converts this older C-style cast to a static_cast, but because that would cause an error in this case, the compiler silently demotes the cast to use the reinterpret_cast operator. The reinterpret_cast operator is a type-blind casting operator, which effectively is equivalent to the older C-style casts.
  9. Only the IUnknown interface pointer must have the same address returned by every call to QueryInterface, other interfaces are not subject to this same restriction. You can exploit this little-known loophole to create tear-off interfaces that come and go dynamically.
  10. Due to the potential for race conditions in multithreaded in-process components, COM+ might not immediately unload the DLL even if S_OK is returned by DllCanUnloadNow.
  11. For a discussion of this race condition, see the section, "Making DllGetClassObject and DllCanUnloadNow Thread-Safe," in Chapter 4.

  12. We are not suggesting that you actually write code like this, but it can be helpful to see that in the simple case of an in-process component, COM+ is not doing anything incredibly complex in CoCreateInstance.
  13. The COM+ SCM is often confused with the Windows 2000 Service Control Manager used to manage Win32 services.
  14. These functions are part of the Win32 API, not COM+, and because their names are relatively descriptive, they will not be described here in detail. See the Win32 reference documentation for more information.
  15. Incidentally, this is also how the Active Template Library (ATL) handles component registration needs.
  16. Specifically, the functions GetFileVersionInfoSize, GetFileVersionInfo, and VerQueryValue are used for this purpose. For sample code that uses these functions to check whether a component has the OLESelfRegister flag in its version information resource, see the CheckReg.dsw work-space file in the Samples\The IUnknown Interface\CheckReg folder on the companion CD.
  17. It is generally best to choose the leftmost base class when casting because some compilers, including Visual C++, place the leftmost base class at the top of the object layout and then do not require an adjustor thunk to manipulate the this pointer. This is why IMultiply is preferable to ISum for casting of the IUnknown interface pointer.
  18. The limitation is actually even more stringent because you cannot use aggregation across apartment boundaries. For details about the apartment models, see Chapter 4.

Chapter Three

  1. Visual Basic and Visual J++ automatically generate type libraries for components built in those languages.
  2. Not all IDL attributes are supported by the current implementation of type libraries in COM+. For details, see Chapter 16.
  3. Both Visual C++ and Visual J++ offer a similar feature.
  4. The LoadTypeLib function followed by RegisterTypeLib achieves the same result.
  5. In Java, source files are saved with the .java extension; files compiled to binary Java bytecode are saved with the .class extension.
  6. Actually, Visual J++ invokes a separate helper utility named jactivex.exe to read the type library and generate the Java to COM+ wrappers.
  7. The Microsoft Java VM's implementation of IUnknown, IExternalConnection, and ISupportErrorInfo cannot be overridden. However, Microsoft allows Java components to implement the IExternalConnectionSink interface, which notifies you when external connections are added and released.

Chapter Four

  1. The first version of COM to be multithreading was released in Microsoft Windows NT 3.51.
  2. Only executable STA components require a message loop; in-process components do not have message loops because the client application is responsible for processing window messages.
  3. CoGetCurrentProcess is recommended because it always returns a unique value identifying the current thread. The thread identifiers returned by the GetCurrentThreadId function can be reused as threads are created and destroyed.
  4. Some documentation incorrectly states that only the initial thread must call CoInitializeEx with the COINIT_MULTITHREADED flag, and that all other threads implicitly join the MTA. This technique might work in some cases, but it is not considered legal COM+ code.
  5. Actually, the MTA uses threads from the thread pool created and maintained by the RPC run-time libraries.
  6. CoMarshalInterface is discussed further in Chapter 15.
  7. IMarshal is the custom marshaling interface defined by COM+; it is covered in detail in Chapter 15.
  8. Contexts are a construct used primarily to distinguish between configured COM+ components that require different runtime services. They are covered later in this chapter.
  9. In Windows NT 4.0, the stubs of objects that aggregate the FTM are created in the apartment of the thread that marshaled the object out-of-process. This can cause an identity problem when the object is represented by multiple stubs in different apartments. In Windows 2000, the stubs of objects that aggregate the FTM are always created in the NA, which solves the identity problem. Since objects that aggregate the FTM are apartment-neutral, it doesn't matter which thread the call arrives on.
  10. Although the FTM is typically used by objects marked ThreadingModel = Both, this is in no way a requirement. The ThreadingModel setting basically determines only from which apartment your DllGetClassObject function is called.
  11. In-process components cannot set the Instancing property to SingleUse because multiple copies of a DLL cannot be loaded in a client's address space.

Chapter Five

  1. Automation has supplanted Dynamic Data Exchange (DDE), an earlier message-based protocol sometimes used for the same purpose.
  2. IDispatch is called a standard interface because Microsoft defined it as part of COM+. The proxy-stub code needed to marshal the IDispatch interface is contained in the oleaut32.dll file; this is important because it means that applications implementing the IDispatch interface don't have to provide their own marshaling code.
  3. When compiling the IDL file, MIDL will insert the flag TYPEFLAG_FOLEAUTOMATION in the type library file for each interface that has the oleautomation attribute. This flag is recognized by the RegisterTypeLib and LoadTypeLibEx functions.
  4. The correct VT_ prefixed constant is listed in the comment to the right of the types in the VARIANT structure.
  5. For ease of implementation, the interface designed for scripting clients is usually built as a dual interface.
  6. The sample is in the Samples\Automation\Collections folder on the companion CD.
  7. This parameter is described in the documentation as reserved; only the IID_NULL value is permitted.
  8. A more realistic implementation of IDispatchEx would assign DISPIDs sequentially and keep track of those that had been assigned.
  9. In the system header files, OLECHAR is defined as wchar_t.
  10. VARIANTARG is just another name for a VARIANT. The VARIANTARG type is used to pass parameters, while the VARIANT type carries the return value from a property or method call.
  11. CreateObject also offers the possibility for supplying an optional machine name parameter to instantiate remote components, in which case the CoCreateInstanceEx function is called.
  12. This is an implementation of the ECMA 262 language specification with some proprietary enhancements.
  13. HKCR is used as an abbreviation of the HKEY_CLASSES_ROOT key in the registry.
  14. This element is optional; if you leave it out, a looser syntax can be used when defining the scriptlet.

Chapter Seven

  1. Actually, if you need to retrieve many interfaces implemented by an object, you should use the QueryMultipleInterfaces method of the IMultiQI interface; for details, see Chapter 13.

Chapter Eight

  1. Actually, the first outgoing and incoming interfaces not marked with the restricted IDL attribute are assumed to be the defaults. The restricted attribute hides the specified interface from use in languages that rely on type libraries, such as Visual Basic and Java.
  2. A quacking sound can be heard whenever the B key is pressed. Readers of Kraig Brockschmidt's Inside OLE (Microsoft Press, 1995) will understand.
  3. Or perhaps it simply proves that Visual Basic is a most forgiving client.
  4. The type information is obtained via the IProvideClassInfo interface; see Chapter 9.
  5. It might help to refer back to Figure 8-3 you examine these steps. Note that step 1 in the list correlates to call number 2 in Figure 8-3 because here we are assuming that a client has already instantiated the object.

Chapter Nine

  1. See Appendix A for more information about RPCs.
  2. Type libraries do not accurately represent the IDL interface definition in certain cases; see Chapter 16 for details.
  3. A Visual Basic or Java program can read the information stored in an existing type library by setting a reference to the TypeLib Information (tlbinf32.dll) component, as described later in this chapter.
  4. The obsolete CreateTypeLib function creates a type library in the older format and returns a pointer to the ICreateTypeLib interface.
  5. The CreateTypeLib2 function creates type libraries using the memory-mapped file capabilities of Win32.
  6. Of course, we recommend that you consider using MIDL if your future component development plans call for a type library.

Chapter Ten

  1. Stream objects that require only simple sequential access implement the ISequentialStream interface. Typically, the ISequentialStream interface is not implemented by itself. Instead, a more sophisticated stream object implements the ISequentialStream::Read and ISequentialStream::Write methods as part of an IStream interface implementation. For example, the stream object implemented as part of the structured storage service fails when QueryInterface is called for the ISequentialStream interface; calling QueryInterface for IStream succeeds.
  2. The GetHGlobalFromStream function returns a pointer to the memory block allocated by the CreateStreamOnHGlobal function.
  3. The GetSizeMax method is not applicable to property bag objects; the IsDirty method was added to the IPersistPropertyBag2 interface—although Visual Basic does not currently implement this interface.
  4. The enhanced version of this interface, IPropertyBag2, has several new methods.
  5. This indicates that the object always thinks it's dirty.

Chapter Eleven

  1. When instantiating an object on a remote machine, the system provides an optimization of CoCreateInstance. Instead of making two round-trips (one for CoGetClassObject and another for IClassFactory::CreateInstance), the Service Control Manager (SCM) on the remote machine executes these steps and returns the desired pointer to the caller.
  2. It is customary, but not required, to name custom activation interfaces in the form of IThingFactory, where Thing is the name of the coclass being instantiated by the class object.
  3. Executable components that implement custom activation interfaces in place of IClassFactory have special lifetime issues that you must address. For more information, see the section titled "Managing the Lifetime of an Executable Component" in Chapter 13.
  4. Currently the class moniker does not honor the BIND_OPTS2.pServerInfo member.
  5. Although it was undocumented until recently, the CoGetObject function is now a legitimate member of the COM+ run-time library.
  6. The GetObject function has an additional code path executed for file monikers and objects registered in the Running Object Table, which is not discussed here.
  7. Visual Basic can access any custom activation interface as long as it uses Automation-compatible types. Interestingly, this restriction means that IClassFactory is not directly accessible to Visual Basic programmers.
  8. Although no implementation of the IClassActivator interface currently exists in a system-supplied moniker, Microsoft might provide one in the future.
  9. ProgIDs are not case sensitive.
  10. The class moniker could simply have used the COSERVERINFO information defined in the BIND_OPTS2 structure to achieve the same result. However, the class moniker does not currently use this information when binding to a class object.

Chapter Twelve

  1. COM+ also provides an alternative version of the standard surrogate, dllhst3g.exe, that supports a 3-GB user-mode address space.
  2. Modern components, which were designed for use in a distributed environment, normally offer their own configuration options and thus have no use for the Distributed COM Configuration utility.
  3. These data types are listed in the section titled "Automation Types" in Chapter 5.

Chapter Thirteen

  1. The COM+ run-time environment supports only in-process components.
  2. Actually, they run in a separate window station. See Chapter 18 for details.
  3. Alternatively, you can use the RegisterServerEx function (also provided in registry.cpp on the companion CD) to configure the registry information based on a tabular data structure. See Chapter 2 for details.
  4. By instance objects, we mean regular COM+ objects that are not class objects.
  5. For more information about the stub manager, see Chapter 15.
  6. The CoDisconnectObject function terminates all client connections. See Chapter 14.
  7. Note that singletons are not supported by the COM+ run-time environment.
  8. Custom class objects are discussed in detail in Chapter 11.

Chapter Fourteen

  1. See the appendix for details.
  2. For more on NDR, see the sidebar titled "Network Data Representation"
  3. The system also provides a built-in implementation of custom marshaling called standard marshaling, which is described in Chapter 15.
  4. For information on how to embed proxy and stub code in an application, see Chapter 13.
  5. We'll describe how to use custom marshaling to implement marshal-by-value semantics later in this chapter.
  6. CoMarshalInterface first calls QueryInterface for your IUnknown interface pointer several times as part of its standard stub creation and identity testing.
  7. An object that implements the IStream interface
  8. See Chapter 11 for more information on the ROT.
  9. If standard marshaling is used, the CLSID in the stream is CLSID_StdMarshal, or {00000017-0000-0000-C000-000000000046}.
  10. This optimization is discussed further in Chapter 19.
  11. For information about object persistence, see Chapter 10.

Chapter Fifteen

  1. Figure 15-1 shows the stub manager for conceptual purposes; the stub manager does not actually exist as a separate entity.
  2. Standard aggregation is done via the IClassFactory interface; proxy/stub components use the IPSFactoryBuffer interface. Both types of aggregation follow the same principles as described in Chapter 2.
  3. See the original COM specification for more information about the recommended implementation of these functions.

Chapter Sixteen

  1. See Chapter 14 for information on the NDR transfer syntax.
  2. Java hedges by passing primitive types by value but user-defined types by reference.

Chapter Seventeen

  1. The CoDisableCallCancellation function disables cancellation of synchronous method calls made on the calling thread.

Chapter Eighteen

  1. You can use programmatic security—discussed later in this chapter in the section titled "Programmatic Security"—to override both default and component security settings in the registry.
  2. Chapter 19 includes more information about secure reference counting.
  3. An administrator can give the system account network privileges by setting the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters\RestrictNullSessionAccess registry value to 0, but this technique is not generally recommended because it significantly compromises system security.
  4. All components written in Microsoft Visual Basic do this.
  5. Chapter 12 covers the AppID registry key in more detail.
  6. Note that you cannot use the launching user identity setting when security is turned off in this way.
  7. The format of the security information produced by the DCOMAccessControl object is not the same as that produced by the Win32 API security functions. While COM+ itself supports both formats, the Distributed COM Configuration utility on Windows NT and Windows 2000 is unable to read security information created by the DCOMAccessControl object.
  8. For information on how to set this up, see the section titled "Activation Credentials: The COAUTHINFO Structure" later in this chapter.
  9. For more information about how to configure these settings, see the section titled "Declarative Security: The Registry" earlier in this chapter.
  10. The IClientSecurity interface is described later in this chapter.
  11. The IAccessControl::SetOwner method is currently not implemented by the DCOMAccessControl object.
  12. This field is covered in the section titled "Remote Instantiation" in Chapter 13.
  13. Note that during an asynchronous call, the server cannot impersonate the client after the server's call to ISynchronize::Signal completes, even if the Begin_ method has not yet completed. For example, if a client calls the Begin_ method and the server calls ISynchronize::Signal to indicate that it is finished processing, even if work remains to be done in the Begin_ method, the server cannot impersonate the client after the call to ISynchronize::Signal. If the server impersonates the client before it calls ISynchronize::Signal, the impersonation token is not removed from the thread until the server calls IServerSecurity::RevertToSelf or until the Begin_ method returns, whichever comes first. See Chapter 17 for more information on asynchronous calls.

Chapter Nineteen

  1. We'll leave it as an exercise for you to develop a Network Monitor parser DLL that understands the ORPC protocol.
  2. In other versions of Windows, the SCM is named rpcss.exe.
  3. Remote activation works only in Windows NT and Windows 2000. Windows 95 and Windows 98 lack the necessary security infrastructure.
  4. RPC string bindings are discussed in greater detail in the Appendix.
  5. In Windows 95 and Windows 98, this functionality is available in a separate utility named ciscnfg.exe.
  6. Also, tunneling TCP/IP works only if the proxy servers and firewalls permit TCP/IP traffic over a port opened to HTTP.
  7. You can disable this option to block any potential Internet access to COM+ components.
  8. You can use channel hooks to pass extra data in the COM+ channel; see the section titled "Channel Hooks" later in this chapter.
  9. See Chapter 16 for a description of IDL keywords.
  10. Chapters 14 and 15 cover these three types of marshaling in detail.
  11. See the section titled "Garbage Collection" later in this chapter.
  12. This optimization technique is covered later in this chapter in the section titled "The IRemUnknown Interface."
  13. The details of this translation are covered later in this chapter in the section titled "The OXID Resolver."
  14. The NCA prefix for each tower identifier is short for Network Computing Architecture. CN stands for a connection-oriented protocol, and DG stands for a connectionless, datagram-based protocol.


  1. In RPC the term stub is used on both the client and server sides. A client stub in RPC is conceptually equivalent to a proxy in COM.