FAQ 34.11 How many ways are there to specify COM interfaces?

graphics/new_icon.gif

For better or worse there are several ways to define a COM interface.

Suppose we want to define the interface IStack, which provides facilities for pushing and popping integers. One technique is to define the COM interface as a C++ abstract base class.

 #include "wtypes.h" /* {FC3B3F61-BCEC-11D1-91FE-E1CBED988F66} */ DEFINE_GUID(IID_IStack,     0xFC3B3F61, 0xBCEC, 0x11D1, 0x91, 0xFE,     0xE1, 0xCB, 0xED, 0x98, 0x8F, 0x66); class IStack : public IUnknown { public:     virtual HRESULT Push(long value) = 0;     virtual HRESULT Pop(long* value) = 0;     virtual HRESULT Empty(long* flag) = 0; }; 

This technique would be the most familiar to C++ programmers. Notice how IStack is derived from IUnknown (all COM interfaces must be derived either directly or indirectly from IUnknown). The problem with this definition is that it is language specific and can't be used by callers written in other languages. Also you'd have to provide code for marshaling the parameters if the caller using IStack and the COM object implementing IStack were running in different processes.

Another technique is to define the interface using a set of COM-defined macros. This technique defines the interface in a manner that hides the differences between programming languages (e.g., C and C++) and operating systems (e.g., Windows and Macintosh).

 #include "wtypes.h" /* {FC3B3F61-BCEC-11D1-91FE-E1CBED988F66} */ DEFINE_GUID(IID_IStack,     0xFC3B3F61, 0xBCEC, 0x11D1, 0x91, 0xFE,     0xE1, 0xCB, 0xED, 0x98, 0x8F, 0x66); DECLARE_INTERFACE_(IStack, IUnknown) {     // *** IStack methods *** //     STDMETHOD(Push)  (THIS_ long  value) PURE;     STDMETHOD(Pop)   (THIS_ long* value) PURE;     STDMETHOD(Empty) (THIS_ long* flag) PURE; }; 

The tags such as DECLARE_INTERFACE_, STDMETHOD, THIS_, and PURE are COM macros that expand differently based on the operating system and programming language. This is a better approach than the pure C++ approach because it allows the same interface definition to be used in multiple environments without changes. But you'd still have to provide code for marshaling the parameters if the caller using IStack and the COM object implementing IStack were running in different processes.

A third technique is to define the interface using the Microsoft Interface Definition Language (MIDL). MIDL allows interfaces to be defined in a language-independent manner. MIDL is based on DCE's IDL syntax and includes extensions to support COM programming. MIDL is used for defining COM interfaces, defining what interfaces a COM class implements (see FAQ 34.12), defining dispatch interfaces (see FAQ 34.25), and generating type libraries (see FAQ 34.29). Here is the MIDL definition of the IStack interface.

 [   object,     uuid(FC3B3F61-BCEC-11D1-91FE-E1CBED988F66) ] interface IStack : IUnknown {     import "unknwn.idl";     HRESULT Push([in] long value);     HRESULT Pop([out, retval] long* pVal);     HRESULT Empty([out, retval] boolean* pVal); }; 

MDL has some major advantages.

  • MIDL is language independent.

  • MIDL clearly separates interface from implementation.

  • MIDL provides Microsoft-specific features that are not found in other IDLs.

  • The MIDL compiler can automatically generate proxies and stubs (see FAQ 34.15 for more information regarding proxies and stubs) capable of marshaling parameters across process boundaries. More specifically, for a caller running in one process to talk to a COM object in another process, the COM communication layer needs to understand the exact size and nature of the data involved in the interprocess communication. COM provides built-in support for marshaling standard interfaces (such as IUnknown). However, no such built-in support exists for custom interfaces (such as IStack). By defining a COM interface using MIDL and compiling it with the MIDL compiler, you get source code for a proxy/stub DLL as a by-product. The communication layer uses this proxy/stub pair to marshal parameters between objects and their callers.

MIDL also has some limitations, including the fact that it is relatively complex, all out parameters must be pointers (which is an issue only for programmers and programming languages who are pointer challenged), function name overloading is not supported, and the return type for methods in object interfaces must be an HRESULT (although methods can return any number of results by defining one or more parameters as out parameters or in/out parameters).

Define interfaces using MIDL when possible: it is the most general and the easiest to work with.



C++ FAQs
C Programming FAQs: Frequently Asked Questions
ISBN: 0201845199
EAN: 2147483647
Year: 2005
Pages: 566
Authors: Steve Summit

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net