Basic Attributed Programming

team lib

Now that youve seen how to create a COM server by using attributes, this section will examine the use of attributes in more detail and provide a reference to the most commonly used attributes.

Creating Modules

When creating COM code with ATL, you have the choice of using a DLL, an EXE, or a Windows Service as the container for the coclasses. Each of these needs to provide a framework for hosting the coclasses it contains, and this framework is provided for you by the ATL Project Wizard. In previous versions of ATL, this would result in the creation of explicit code. For example, for a COM DLL project, you could seeand editthe definitions and implementation of the DllMain , DllGetClassObject , DllRegisterServer , DllUnregisterServer , and DllCanUnloadNow functions, and you could also see and edit the basic IDL library definition.

When using attributes, the stand-alone module attribute performs these functions. It generates the skeleton for the appropriate server type, and it defines the IDL library block that will contain the coclass definitions.

The module attribute can take a large number of parameters, as shown in Table 6-1.

Table 6-1: Parameters for the module Attribute

Parameter

Description

type

Defines the type of module that will be created. The value can be dll , exe , or service , with the default being dll .

name

The name of the library block.

uuid

The GUID for the library block. If this parameter is omitted, a GUID will automatically be generated.

version

The version number for the library block. The default value
is 1.0 .

lcid

Used to specify the 32-bit Windows National Language Support locale identifier for the library. This attribute identifies the locale for a type library and lets you use international characters inside the library block.

control

A Boolean value specifying whether all the coclasses in the library are controls.

helpstring

The help string for this library block.

helpstringdll

Specifies the DLL to be used for document-string lookups.

helpfile

The name of the help file for the type library.

helpcontext

The help context ID for this type library.

helpstringcontext

Specifies the context ID for a help topic.

hidden

Prevents the entire library from being displayed in a user - oriented browser , such as the Visual Basic Object Browser.

restricted

Members of the library cannot be used arbitrarily. This parameter is typically used to prevent access from scripting languages.

custom

Can be used to specify one or more custom attributes, each of which is defined by a GUID and a value.

resource_name

The resource ID of the .rgs file used to register the APPID of the DLL, executable, or service.

Using the module Attribute

You cannot use the module attribute with a completely empty parameter list. You must provide a minimum of a name parameter, in which case defaults will be assumed for all the other parameters:

 [module(name="MyObject")]; 

This bit of code will define a library block in the IDL using the name provided, and it will generate a GUID to represent the library ID and use a default version of 1.0. Heres the library block in the IDL that was generated from the module statement:

 [version(1.0),uuid(1a7833b4-e38a-32a6-a32e-d4c61bfb3305)] libraryMyObject { importlib("stdole2.tlb"); importlib("olepro32.dll"); } 

As well as creating the library block in the IDL file, the inclusion of a module attribute also creates a global object to manage the coclasses in the DLL or EXE. In previous versions of ATL, this object was called _Module and was of type CComModule . In Visual C++ .NET, the functionality provided by CComModule has been spread over a number of classes, as listed in Table 6-2.

Table 6-2: ATL Module Classes

Class

Description

CAtlBaseModule

CAtlBaseModule exposes data needed by most ATL applications, including the resource instance and the HINSTANCE of the module. This class inherits from the _ATL_BASE_MODULE structure, which contains module-specific data.

CAtlComModule

CAtlComModule implements a COM server module, providing basic registration and deregistration functionality for objects in the modules object map and for type libraries.

CAtlWinModule

CAtlWinModule provides support for ATL classes that have GUIs.

CAtlDebugInterfacesModule

CAtlDebugInterfacesModule provides support for debugging interfaces. This class is used in any ATL project that has defined the _ATL_DEBUG_QI symbol.

CAtlModule

CAtlModule provides basic functionality for all module types, including the Lock and Unlock methods used for threadsafe operation.

CAtlModuleT

CAtlModuleT is a template class that derives from CAtlModule . It acts as a base class for the following three module classes and contains basic registration functionality.

CAtlDllModuleT

CAtlDllModuleT is a template class that derives from CAtlModuleT . It provides support for DLL servers, including implementations of the DllMain function, plus the four functions always exported by DLL servers ( DllGetClassObject , DllRegisterServer , DllUnregisterServer , and DllCanUnloadNow ).

CAtlExeModuleT

CAtlExeModuleT is a template class that derives from CAtlModuleT . It provides support for EXE servers, including parsing the command line, registering and revoking class objects, and managing interaction with the message loop.

CAtlServiceModuleT

CAtlServiceModuleT is a template class that derives from CAtlModuleT . It provides support for ATL servers implemented as Windows Services, with functionality that includes parsing the command line and installing, registering, and uninstalling the service.

The generated code will contain a module object called _AtlModule , which will be of one of the three CAtlXxxModuleT types: CAtlDllModuleT if the module type was given as dll (or if no type was specified), CAtlExeModuleT if the module type was given as exe , or CAtlServiceModuleT if the module type was given as service .

Tip 

You can see the generated code if you use the /Fx compiler switch, and examine the .mrg file that is created.

In addition, CAtlExeModuleT implements a timeout mechanism, which can be used to improve server performance in cases where large numbers of objects are being created and destroyed. The COM rules state that when the last object supported by a server has been destroyed , the server can exit. If the Boolean m_bDelayShutdown member of CAtlExeModuleT is set to true , the server will not shut down until the period specified by m_dwTimeOut has expired . The default timeout is 5 seconds.

The custom Attribute

This attribute provides a general mechanism for adding metadata to type libraries and can be applied to modules, interfaces, and coclasses. It takes two parameters:

  • A GUID that identifies the metadata

  • A value, which can be anything that will fit into a VARIANT

The GUID used to identify the metadata has no meaning except to clients that are looking for it. Use of this attribute on C++ classes will result in an equivalent IDL custom attribute being added to the IDL and compiled into the type library. Clients must use the type library interfaces ( ITypeLib and ITypeInfo ) to retrieve details of custom attributes.

As an example of the use of this attribute, consider the following fragment of Visual C# code, which is generated when a .NET component is being exported for use as a COM object:

 [ odl,uuid(FEDF4CC0-E0ED-3DC4-ABE7-E5B4BBC78D84), hidden,dual,nonextensible,oleautomation, custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9,ExportVb.Class1) ] interface_Class1:IDispatch{ //... }; 

For exported .NET components , the custom attribute is used to specify the namespace to which the .NET component belongs. When the COM Callable Wrapper (CCW) is created to expose a .NET instance as a COM object, the CCW can find the namespace information from the type library.

Creating Interfaces

In previous versions of ATL, interfaces were defined directly in IDL and implemented in the ATL source class. Wizard support in Visual Studio would add implementation code to the ATL class files, but there were several disadvantages with the way this process worked. First there was often a lot of manual work to be done, especially when adding extra interfaces to a class. Second, doing anything out of the ordinary required a detailed knowledge of IDL. This was unsatisfactory because IDL is a complex and subtle language, requiring extra knowledge and skills on the part of the C++ programmer.

Using attributes, the programmer now codes an interface definition directly in C++, using attributes to provide all the information that would have been given in the IDL file. In many cases, there is a one-to-one mapping between .NET COM attributes and IDL constructs, so if you already know how to construct and edit IDL, youll be able to quickly transfer to using attributes.

As the previous walkthrough explained, COM interfaces are defined using the new __interface keyword. Interfaces defined in this way have the following properties:

  • They can inherit from zero or more base interfaces.

  • They cannot inherit from a base class.

  • They can contain only public, pure virtual methods.

  • They cannot contain constructors or destructors.

  • They cannot define overloaded functions or operator overloads.

  • They cannot contain static methods.

  • They cannot contain data members, although pure virtual properties are allowed.

  • Methods use the __stdcall calling convention.

Note that the __interface keyword is not only used for COM interface definitions, it can also be used for defining both managed and unmanaged C++ interfaces. To define a COM interface, you need to apply the object attribute to the interface definition, as you also have to do in IDL interface definitions.

 //Anon-COMinterface __interfaceINonCOM { //Interfacedefinition }; //ACOMinterface [object] __interfaceICOM:IUnknown { //Interfacedefinition }; 

Once the compiler sees the object attribute, it will apply the rules that COM interfaces and interface methods have to follow. For example, since all COM interfaces are based on IUnknown , COM interfaces defined using __interface must inherit from IUnknown or another COM base interface.

Attributes are used to provide information to the compiler to enable it to generate an IDL file for compilation by MIDL. The attributes that can be used with interfaces are shown in Table 6-3, and you will see that they parallel many attributes used in an IDL interface definition.

Table 6-3: Attributes Used with Interfaces

Attribute

Description

async_uuid

Generates both synchronous and asynchronous versions of the interface. A GUID must be provided to be used as the interface ID for the asynchronous interface.

custom

Inserts one or more IDL custom attributes, each of which is identified by a GUID and a value.

dispinterface

Defines an interface as being a pure dispatch interface, only usable by late-bound clients. Dispinterfaces must have IDispatch at the top of their inheritance hierarchy.

dual

Defines an interface as being a dual interface, usable by early- bound or late-bound clients. Dual interfaces must have IDispatch at the top of their inheritance hierarchy.

export

Indicates that an interface should be included in the IDL. This attribute is not normally needed, as COM interface definitions are automatically included in the generated IDL.

helpcontext

The help context ID for this interface.

helpfile

The help file for this interface.

helpstring

The help string to display for the interface.

helpstringcontext

The help context ID for this interface.

hidden

Adds the hidden IDL attribute to the interface, indicating that it should not be shown in the Visual Basic Object Browser.

library_block

By default, only interfaces that are used in coclass definitions are compiled into the type library. An interface tagged with the library_block attribute will be placed in the library block in the IDL, and therefore compiled into the type library regardless of whether it is referenced by a coclass.

local

The local attribute can be used on an interface to cause the MIDL compiler only to create header files.

nonextensible

When applied to an Automation interface, this attribute indicates that the interface cannot be extended at run time.

object

Defines the interface as being a COM interface, as opposed to being a managed or unmanaged non-COM interface. All COM interface definitions will include this attribute.

odl

Marks the interface as an ODL interface. This attribute is supported only for backward compatibility and is not required.

oleautomation

Marks an interface as being compatible with OLE Automation. This means the parameters and return types for methods in the interface must be Automation-compatible.

pointer_default

Specifies the default pointer attribute for pointers used in this interface. This attribute can take one of three parameters: ptr , ref , or unique . These correspond to the equivalent IDL pointer attributes.

restricted

Denotes that an interface cannot be called arbitrarily. This attribute is used to restrict the interfaces that can be used from scripting languages.

uuid

Specifies an interface ID for the interface. If this attribute is not supplied, a GUID will automatically be generated.

The sample code in the earlier section Adding Interface and Coclass Definitions showed how these attributes can be applied to an interface.

Defining Interface Methods

An interface is a collection of pure virtual function definitions, but you dont use C++ virtual function syntax to declare them. You declare them as simple function prototypes , and they will be assumed to be public and pure virtual, as shown in the following example:

 //ACOMinterface [object] __interfaceICOM:IUnknown { //Methodisassumedtobepublicandpurevirtual HRESULTAMethod(intn); }; 

COM interface methods are required to return HRESULT s, and the compiler will issue an error if you try to use any other return type in an interface that has the object attribute.

Table 6-4 lists the most common attributes that can be used on methods, parameters and return types.

Table 6-4: Attributes That Can Be Applied to Interface Methods

Attribute

Description

bindable

Indicates that a property supports data binding.

helpstring

Provides a help string for a method.

hidden

Indicates that an interface method should not appear in object browser utilities.

id

Provides a dispatch ID (dispID) for a method.

in

Indicates that a method parameter should be marshaled from the caller to the callee.

local

Denotes a local method for which no marshalling code is generated.

nonbrowsable

Indicates that an interface method should not appear in object browser utilities.

out

Indicates that a method parameter should be marshaled from the callee back to the caller.

propget

Used to label property accessor methods.

propput

Used to label property setting methods.

propputref

Used to label a property setting method that uses a reference rather than a value.

ptr

Designates a pointer as a full pointer, which can be null, and can change its value.

retval

Indicates that a method parameter can be used as a function return value. There can be only one [retval] parameter, and it must be the last parameter in the methods parameter list.

string

Indicates that an array of, or pointer to, types char , wchar_t , or byte should be treated as a C-style null- terminated string.

synchronize

Causes the method to be synchronized, via calls to Lock and Unlock placed at the beginning and end of the method code.

Interface methods defined using attributes look similar to their IDL counterparts and use the same rulesfor example, out parameters must be pointers, and the retval parameter must occur at the end of the parameter list. The following code sample illustrates this:

 //Exampleattributedinterfacemethod [id(3),helpstring("methodSquare")]HRESULTSquare([in]SHORTval,[out,retval]LONG*pResult); 

Dispatch Interfaces

Interfaces can be marked with the dual or dispinterface attributes to show that they can be called by late-bound clients using Automation. All methods in dispatch interfaces must define dispatch IDs (dispIDs) for their methods. These IDs are positive integers.

You use the id attribute to assign dispIDs to methods within an interface definition:

 [id(2)]HRESULTMethodOne(); [id(3)]HRESULTMethodTwo(); 

The compiler will check for duplicate dispIDs, and if any are found, MIDL compilation will fail.

Handling Arrays

You might notice that the list of interface method attributes does not contain any IDL attributes used when passing arrays by pointer ( size_is , length_is , and so on). Although these are not listed as COM attributes, you can still use them when defining methods in COM interfaces, and they will be passed through into the generated IDL. For example, heres the definition of a method that computes the sum of an array of values:

 HRESULTSum([in]shortnVals,[in,size_is(nVals)]short*pArray, [out,retval]long*pSum); 

Creating Coclasses

The coclass attribute is used to mark a class that implements a COM coclass. The attribute can be applied to classes and structs, and it takes no arguments. In its simplest form, it can be used alone, like this:

 [coclass] classMyComClass:publicISomeInterface { //... }; 

When the coclass attribute is applied to a class in an ATL project, the following changes will be made to the class:

  • ATL base classes are added.

  • If the class inherits from any dual interfaces that are not defined using attributes, these dual interfaces are replaced with the corresponding IDispatchImpl class. If a base dual interface is defined using attributes, the interface is not modified in the base class list.

  • A COM map is added, listing all interfaces implemented by the target class, all interfaces specified using com_interface_entry attributes, and those introduced via aggregates attributes.

  • An OBJECT_ENTRY_AUTO entry is placed in the COM map, which has the effect of entering the class into the COM map, updating the registry, and creating an instance of the object.

The following base classes will be added in the generated code:

  • CComCoClass , to implement the class factory and aggregation behavior.

  • CComObjectRootEx , to provide behavior specific to the threading model. If no threading attribute is provided, apartment-model threading is assumed.

  • IProvideClassInfo2Impl , to provide a default implementation of the IProvideClassInfo and IProvideClassInfo2 interfaces. If the noncreatable attribute is specified for the class, IProvideClassInfo2Impl will not be added as a base class.

These classes provide, among other features, registry entry handling (autoregistration), a class factory, and an IUnknown implementation.

The use of the coclass attribute also adds a number of member functions to the target class:

  • UpdateRegistry , to register the class factory for the class.

  • GetObjectCLSID , to return the components CLSID.

  • GetObjectFriendlyName , to return a string of the form target_class_name Object. This function can be explicitly overridden to return another name.

  • GetProgID , to return a string containing the components progID.

  • GetVersionIndependentProgID , to return a string containing the components version-independent progID.

Table 6-5 lists the attributes that can be used on coclasses.

Table 6-5: Attributes That Can Be Applied to coclasses

Attribute

Description

aggregatable

This attribute denotes that a coclass can be aggregated. See the upcoming Handling Aggregation section for more details.

aggregates

This attribute specifies the COM coclasses that a coclass will aggregate. See the upcoming Handling Aggregation section for more details.

coclass

Specifies that a C++ class implements a COM coclass.

com_interface_entry

Adds an entry to the COM_MAP for the class.

control

Specifies that a coclass implements an ActiveX control.

custom

Adds a custom entry to the type library.

default

Indicates which interfaces should be used as the default interfaces for the coclass.

event_source

Denotes an event source. See the upcoming Events section for details on how this attribute is used.

event_receiver

Denotes that this class receives events. See the upcoming Events section for details on how this attribute is used.

helpcontext

Provides a context ID within a help file that can be accessed for more help about the class.

helpfile

Provides the name of the help file associated with this class.

helpstring

Provides a help string that can be displayed in object browsers and other end-user tools.

helpstringcontext

Specifies the ID of a help topic in an .hlp or a .chm help file.

hidden

Indicates that this item should not be displayed in object browsers and other end-user tools.

implements

By default, only COM interfaces that are base classes are added to the IDL coclass definition. This attribute forces other interfaces to be added to the IDL definition, even if they are not bases.

implements_category

Adds an implemented category to the CATEGORY map for the class. Clients can query this map at run time to determine the categories that are implemented by a class.

licensed

Indicates that this class uses the ActiveX licensing model and must be created using the IClassFactory2 interface.

noncreatable

Specifies that this class cannot be created by COM. This attribute is normally used on COM types that are created by other methods, such as the C++ new operator.

progid

Adds a progID for the class. The parameter to this class is a string containing the progID in the usual typelib.coclass.version format.

registration_script

Supplies the path to a registration script (.rgs) file that will be used to register the class. If this attribute is not supplied, a default registration script will be generated. To disable automatic registration, use this attribute with the special path none .

requires_category

Adds a required category to the CATEGORY map for the class. Clients can query this map at run time to determine the categories that need to be implemented by users of a class.

restricted

Indicates that this coclass cannot be used arbitrarily. This attribute is used to restrict the use of classes by scripting clients.

source

Defines the outgoing (source) interfaces supported by a class. See the upcoming Events section for details on how this attribute is used.

support_error_info

Adds support for the ISupportErrorInfo interface to the class. See the upcoming Handling Errors section for more details.

threading

Specifies the threading model for a class. The parameter for this attribute can be one of the following values: apartment , neutral , single , free , or both .

uuid

Specifies a CLSID for the class, as a string. If this attribute is not used, a CLSID will automatically be generated for the class.

version

Specifies a version for the class, which will be used to provide the type library block version.

vi_progid

Specifies a progID without a version.

Default Interfaces

COM coclasses support default incoming and outgoing interfaces so that client codeespecially Visual Basic 6can simply create an object without specifying which interface on the object is to be used. These are indicated by applying the default attribute to the C++ class, as shown in the following code fragment:

 [ coclass, default(ITwo) ] classMyComClass:publicIOne,publicITwo { //... }; 

If your class implements source interfaces, you can provide a second parameter that specifies the default source interface. If you dont use the default attribute, the first base interface will be taken as the default outgoing interface, and the first source interface will be taken as the default source.

Stand-Alone Attributes

A number of COM- related attributes are not applied to classes, interfaces, or methods, but are used as stand-alone attributes. Table 6-6 lists all the stand- alone attributes.

Table 6-6: Stand-Alone Attributes

Attribute

Description

cpp_quote

This attribute is used to pass quoted strings through MIDL compilation into the generated header files. Quotes are stripped from the string before it is inserted into the header file.

custom

Inserts a custom IDL attribute into the IDL file.

emitidl

Determines how IDL generation proceeds. See the upcoming The emitidl Attribute section for further details.

idl_quote

Some IDL constructs are not implemented via attributes. The idl_quote attribute lets you pass unsupported IDL constructs directly into the generated IDL file.

import

Places a #import statement in the IDL that causes the inclusion of another .idl, .odl, or header file.

importidl

Merges the content of another .idl file. Any IDL inside the library block of the inserted file is merged into the library block of the file in which the importidl attribute occurs. IDL outside the library block will be placed outside the library block of the file in which the importidl attribute occurs.

importlib

Imports types from another type library so that they can be referenced in IDL.

include

Causes a #include statement to be placed in the IDL after the import "docobj.idl" statement.

includelib

Causes an IDL or .h file to be included in the generated IDL after the importlib statement. This attribute is repeatable.

module

Declares a module. See the Creating Modules section earlier in the chapter for more details.

no_injected_text

Can be used to prevent the compiler from injecting text. This is placed in the merged code generated by the /Fx compiler option, and ensures that attributes will not be processed a second time if the merge file is compiled.

pragma

This attribute is used to pass a string to the generated header files without any processing by the MIDL compiler. The pragma pack attribute can be used to control how the MIDL compiler will pack structures.

Because these attributes are not part of any other C++ construct, they form statements in their own right and will therefore always end with a semicolon when used in code. For example, look at this code:

 [module(dll,uuid="{1D196988-3060-486E-A4AC-38F9685D3BF7}", name="SimpleObject", helpstring="SimpleObject1.0TypeLibrary", resource_name="IDR_SIMPLEOBJECT")]; 

The emitidl Attribute

The emitidl attribute controls how IDL attributes will be processed. The format of this attribute is shown in the following code fragment:

 [emitidl(  value  ,defaultimports=  boolean  ]; 

The value parameter can take one of four values:

  • true , meaning that IDL attributes encountered in the code will be processed and added to the generated IDL file. This is the default if this value is omitted.

  • false , meaning that IDL attributes encountered in the code will not be processed.

  • restricted , meaning that IDL attributes can be present in a file that doesnt include a module attribute. No IDL file will be generated.

  • forced , meaning that the file must contain a module attribute if it also contains IDL attributes.

The defaultimports named parameter is optional and takes a Boolean value. If the value is false , the standard docobj.idl file (which contains all the Microsoft-defined COM and OLE IDL) will not be implicitly included in the generated IDL. If you want to include any standard IDL filessuch as ocidl.idl youll have to include them manually.

If the value of defaultimports is true , docobj.idl will be included. If an .idl file with the same name as an .h file that you #include into your source code is found in the same directory as the .h file, the generated .idl file will contain an import statement for that .idl file. Here is an example showing how the emitidl attribute can be used:

 [emitidl(true,defaultimports=true]; 
 
team lib


COM Programming with Microsoft .NET
COM Programming with Microsoft .NET
ISBN: 0735618755
EAN: 2147483647
Year: 2006
Pages: 140

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