The Complete Shapes.idl Listing

 < Free Open Study > 



To pull together the core IDL syntax examined thus far, here is the complete shapes.idl listing, defining IDraw, IShapeEdit, a custom enumeration, and CoHexagon:

// Shapes.idl import "oaidl.idl"; cpp_quote("// This is my custom enum") // The FILLTYPE enumeration. [uuid(442F32E0-E7EE-11d2-B8D2-0020781238D4), v1_enum,   helpstring("The FILLTYPE enumeration")] typedef enum FILLTYPE {      HATCH = 0,      SOLID = 1,      POLKADOT = 2 } FILLTYPE; // IShapeEdit. [object, uuid(442F32E2-E7EE-11d2-B8D2-0020781238D4),   helpstring("IShapeEdit allows you to modify a shape")] interface IShapeEdit : IUnknown {      [helpstring("Fill a shape")] HRESULT Fill([in] FILLTYPE fType);      [helpstring("Invert a shape")] HRESULT Inverse();      [helpstring("Stretch a shape by n")] HRESULT Stretch([in] int factor); }; // IDraw [object, uuid(4B475690-DE06-11d2-AAF4-00A0C9312D57),   helpstring("IDraw allows you to draw a shape")] interface IDraw : IUnknown {      [helpstring("Draw Partner!")] HRESULT Draw(); }; // The Shapes Library. [uuid(442F32E1-E7EE-11d2-B8D2-0020781238D4), version(1.0), helpstring("The Shapes Library")] library ShapesLibrary {      importlib("stdole32.tlb");      // CoHexagon.      [uuid(442F32E3-E7EE-11d2-B8D2-0020781238D4)]      coclass CoHexagon      {           [default] interface IDraw;           interface IShapeEdit;      }; };

Examining the MIDL-Generated Files

 On the CD   The Midl.exe processed shapes.idl file can be found on the companion CD-ROM under the Labs\Chapter 04\ShapesIDL subfolder.

Now that we have a complete IDL file, let's send shapes.idl file into the MIDL compiler and see what is generated. As you will notice, all IDL attributes come through as comments, and all cpp_quote statements as C++ code. As well, IDL imports become a preprocessor #include. To begin, shapes.h defines the C and C++ language mappings. Here is how our custom enumeration comes through (note the result of cpp_quote):

// This is my custom enum /* [helpstring][v1_enum][uuid] */ typedef enum FILLTYPE {    HATCH        = 0,      SOLID        = 1,      POLKADOT     = 2 }    FILLTYPE; 

IShapeEdit and IDraw are also defined in shapes.h and should look familiar given your knowledge of the COM macros. Recall that the MIDL_INTERFACE macro automatically inserts the struct keyword as part of the expansion. MIDL has generated both C++ and C language bindings. We won't be concerned with the C bindings. However, when you complete the next lab be sure to look them over (notice that the C++ compiler automatically generates a vTable). Here are the C++ definitions for each of the custom interfaces:

MIDL_INTERFACE("442F32E2-E7EE-11d2-B8D2-0020781238D4") IShapeEdit : public IUnknown { public:      virtual /* [helpstring] */      HRESULT STDMETHODCALLTYPE Fill( /* [in] */ FILLTYPE fType) = 0;      virtual /* [helpstring] */      HRESULT STDMETHODCALLTYPE Inverse( void) = 0;      virtual /* [helpstring] */      HRESULT STDMETHODCALLTYPE Stretch( /* [in] */ int factor) = 0; }; MIDL_INTERFACE("4B475690-DE06-11d2-AAF4-00A0C9312D57") IDraw : public IUnknown { public:      virtual /* [helpstring] */      HRESULT STDMETHODCALLTYPE Draw( void) = 0; };

shapes_i.c contains all the GUIDs defined in the IDL file. In our previous labs, you were maintaining a pair of IID files containing DEFINE_GUID macros. Using IDL, we have no need to do so, as we can simply #include the MIDL-generated *_i.c file whenever we need to refer to the GUID constants.

As you may have guessed, whenever MIDL encounters a [uuid] attribute, a new GUID constant is declared. Here are the IID, CLSID, and LIBID GUIDs:

const IID IID_IShapeEdit = {0x442F32E2,0xE7EE,0x11d2,{0xB8,0xD2,0x00,0x20,0x78,0x12,0x38,0xD4}}; const IID IID_IDraw = {0x4B475690,0xDE06,0x11d2,{0xAA,0xF4,0x00,0xA0,0xC9,0x31,0x2D,0x57}}; const IID LIBID_ShapesLibrary = {0x442F32E1,0xE7EE,0x11d2,{0xB8,0xD2,0x00,0x20,0x78,0x12,0x38,0xD4}}; const CLSID CLSID_CoHexagon = {0x442F32E3,0xE7EE,0x11d2,{0xB8,0xD2,0x00,0x20,0x78,0x12,0x38,0xD4}};

Making Use of the MIDL-Generated Files

These two MIDL-generated files may be used in C or C++ based COM projects. In the server project we include shapes.h when creating coclass definitions:

// When you are creating your coclasses, include the MIDL-generated header // file to grab the C++ interface definitions. #include "shapes.h" class CoHexagon : public IDraw, public IShapeEdit {      // Use STDMETHODIMP/STDMETHODIMP_ as before }; 

Include shapes_i.c into the coclass implementation file to get the definition of IID_IShapeEdit and IID_IDraw for use in our QueryInterface() logic. As well, the server file which defines DllGetClassObject() will also need to reference this same file to get the correct CLSID constants.

In a COM client project, we need to include the same MIDL-generated files to allow us to make CoCreateInstance() calls as well as declare interface pointer variables:

// COM clients also make use of MIDL-generated files. #include "shapes_i.c"        // Contains GUIDs. #include "shapes.h"          // Contains interfaces definitions. void main(void) {      IDraw* pDraw;      ...      CoCreateInstance(CLSID_CoHexagon, NULL, CLSCTX_INPROC_SERVER, IID_IDraw,                     (void**)&pDraw);      ... }

So! As you can see, by defining all your COM servers in IDL, you are able to avoid having to maintain separate files which hold onto DEFINE_GUID statements and C++ interface definitions. Two of the MIDL-generated files can now be included in your COM server and COM client workspaces to get references to the correct GUIDs and interface definitions.

Summation of Core IDL Keywords

At this point, you have enough knowledge to create IDL interfaces, coclasses, and library statements. As you have seen, the MIDL-generated header *.h and *_i.c files provide the necessary C and C++ language bindings to build COM clients and COM servers. Before we begin working with our type information from the client's perception, here is a summary of all the IDL keywords examined so far.

IDL Keyword

Meaning in Life

cpp_quote

Injects C/C++ code into MIDL-generated header files.

enum, v1_enum

Used to create a custom enumeration of types. Use with the v1_enum attribute to transmit as 32-bit.

helpstring

Injects text descriptions into generated type libraries.

import

Used to bring in existing IDL definitions into the current IDL file.

importlib

Brings in binary type information into a library statement.

in, out, retval

Used to specify the direction of interface method parameters including a 'physical return' if the language mapping supports them.

interface

Used to declare a new COM interface (if colored by the uuid and object attributes)

library

Declares type information for the server.

object

Marks the interface as a COM interface, not a DCE-based interface

uuid

Binds a GUID to the given item.

Obviously Microsoft IDL is more sophisticated than this small set of keywords. Over the course of this book, we will see many additional aspects of IDL. For example, in Chapter 11 you will learn to build structures and arrays of IDL types. Do be aware that the full set of IDL keywords can be found in online help (do a keyword search for "MIDL Language Reference").

Now that we are able to describe the functionality of our COM server in a language-neutral manner, we will spend the remainder of this chapter examining how Visual Basic, Java, and C++ clients can access this type information. But first, we need to register a server's type information to allow these other languages to access its functionality.

Registering Your Type Information: HKEY_CLASSES_ROOT\TypeLib

The key to COM's language independence is the MIDL-generated *.tlb file, which is simply the binary equivalent of the associated IDL code. Before languages such as VB and Java can make use of a COM object, they must be able to reference a server's type information. HKEY_CLASSES_ROOT (HKCR) maintains a separate key named TypeLib which holds all the relevant information about your *.tlb files on your system.

To enter the correct information under HKCR\TypeLib, we will need to extend our server's REG file and remerge this file into the system registry. Of course, once we begin working with ATL, this process is automated on your behalf using the ATL registry scripting language and COM library calls.

To update a REG file to account for type information, you must specify the LIBID, current version, and a friendly text string describing the type information. The LIBID can be obtained from the [uuid] attribute of the library statement in your IDL file. The version information should match the value assigned in the [version] attribute. Here are the relevant pieces of your IDL file that need to be placed into the registry:

// We need the LIBID when building entries for HKCR\TypeLib. [      uuid(442F32E1-E7EE-11d2-B8D2-0020781238D4), version(1.0),      helpstring("The Shapes Library") ] library ShapesLibrary { ... }

To enter the LIBID and version, update the REG as the following:

; Format is: HKCR\TypeLib\{<guid>}\version = string name. ; HKEY_CLASSES_ROOT\TypeLib\{442F32E1-E7EE-11d2-B8D2-0020781238D4} \1.0 = Shapes Server Type Lib

Next, under "HKCR\TypeLib\{guid}\version" we need to add another subkey that specifies the language ID of the type library (that would be a human language, not a programming language). After this subkey is the Win32 path to the *.tlb file itself:

; Format is: HKCR\TypeLib\{<guid>}\version\language ID\Win32 = <path> ; HKEY_CLASSES_ROOT\TypeLib\{442F32E1-E7EE-11d2-B8D2-0020781238D4}\1.0\0\Win32 =  E:\Chapter 04\ShapeServer\Debug\ShapesServer.tlb 

These two registry entries are all we technically need; however, most TypeLib listings also specify the optional Flags and HelpDir subkeys. Our server has no flags, and no help file, but for the sake of completion here are the final TypeLib entries (if it did have a help file, we would enter the path to that file):

; Optional TypeLib entries. ; HKEY_CLASSES_ROOT\TypeLib\{442F32E1-E7EE-11d2-B8D2-0020781238D4}\1.0\FLAGS = 0 HKEY_CLASSES_ROOT\TypeLib\{442F32E1-E7EE-11d2-B8D2-0020781238D4}\1.0\HELPDIR

When you merge this updated *.reg file you will see the following listing under HKCR\TypeLib:

click to expand
Figure 4-4: HKCR\TypeLib entries for our Shape server type information.

To fully merge our type information, we should go back to HKCR\CLSID and enter a TypeLib subkey. In this way, SCM can easily find the type information from within the scope of the COM object's CLSID. As a rule of thumb, always identify the correct type library for each and every coclass defined within the server:

; Your coclasses should specify which type library they are defined in. ; HKEY_CLASSES_ROOT\CLSID\{442F32E3-E7EE-11d2-B8D2-0020781238D4}\TypeLib =  {442F32E1-E7EE-11d2-B8D2-0020781238D4}

Now that we have entered the relevant information for our server's type information into the registry, we are ready to allow other COM-enabled languages to access our functionality. But first, allow me to introduce RegEdit's big brother, the OLE/COM Object Viewer.



 < Free Open Study > 



Developer's Workshop to COM and ATL 3.0
Developers Workshop to COM and ATL 3.0
ISBN: 1556227043
EAN: 2147483647
Year: 2000
Pages: 171

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