| Tenouk C & C++ | MFC Home | Active Template Library 4 | ATL and ActiveX Controls 1 | Download | Site Index |


 

 

 

 

 

 

An Introduction To Active Template Library (ATL) 5

 

 

 

 

 

 

Program examples compiled using Visual C++ 6.0 compiler on Windows XP Pro machine with Service Pack 2. Topics and sub topics for this tutorial are listed below. Don’t forget to read Tenouk’s small disclaimer. The supplementary notes for this tutorial are marshaling and intro to activeX control.

  1. ATL and QueryInterface()

  2. Making the Spaceship Go

  3. Adding Methods to an Interface

  4. Dual Interfaces

  5. ATL and IDispatch

  6. The IMotion and IVisual Interfaces

  7. Multiple Dual Interfaces

  8. Conclusion

  9. CComPtr class info

  10. CComQIPtr class info

 

 

ATL and QueryInterface()

 

It looks as though ATL took a cue from MFC for implementing QueryInterface(), ATL uses a lookup table just like MFC's version. Take a look at the middle of CAtlSpaceship's definition, you'll see a construct based on macros called the interface map. ATL's interface maps constitute its QueryInterface() mechanism. Clients use QueryInterface() to arbitrarily widen the connection to an object. That is, when a client needs a new interface, it calls QueryInterface() through an existing interface. The object then looks at the name of the requested interface and compares that name to all the interfaces implemented by the object. If the object implements the interface, the object hands the interface back to the client. Otherwise, QueryInterface() returns an error indicating that no interface was found. Traditional QueryInterface() implementations usually consist of long if-then statements. For example, a standard implementation of QueryInterface() for a multiple-inheritance COM class might look like this:

class CAtlSpaceship: public IDispatch, IAtlSpaceship

{

    HRESULT QueryInterface(RIID riid, void** ppv)

    {

        if(riid == IID_IDispatch)

            *ppv = (IDispatch*) this;

        else if(riid == IID_IAtlSpaceship || riid == IID_IUnknown)

            *ppv = (IAtlSpaceship *) this;

        else

        {

            *ppv = 0;

            return E_NOINTERFACE;

        }

 

        ((IUnknown*)(*ppv))->AddRef();

        return NOERROR;

    }

    // AddRef, Release, and other functions

};

 

As you'll see in a moment, ATL uses a lookup table instead of this conventional if-then statement. ATL's lookup table begins with a macro named BEGIN_COM_MAP. The listing below shows the full definition of BEGIN_COM_MAP.

 

#define BEGIN_COM_MAP(x) public:

    typedef x _ComMapClass;

    static HRESULT WINAPI _Cache(void* pv, REFIID iid, void** ppvObject, DWORD dw)

   {

        _ComMapClass* p = (_ComMapClass*)pv;

        p->Lock();

        HRESULT hRes = CComObjectRootBase::_Cache(pv, iid, ppvObject, dw);

        p->Unlock();

        return hRes;

    }

 

    IUnknown* GetRawUnknown()

    {

        ATLASSERT(_GetEntries()[0].pFunc == _ATL_SIMPLEMAPENTRY);

        return (IUnknown*)((int)this+_GetEntries()->dw);

    }

 

    _ATL_DECLARE_GET_UNKNOWN(x)

    HRESULT _InternalQueryInterface(REFIID iid, void** ppvObject)

    {

        return InternalQueryInterface(this, _GetEntries(), iid, ppvObject);

    }

 

    const static _ATL_INTMAP_ENTRY* WINAPI _GetEntries()

    {

    static const _ATL_INTMAP_ENTRY _entries[] = {

        DEBUG_QI_ENTRY(x)

        ...

        ...

        ...

    #define END_COM_MAP()   {NULL, 0, 0}};\

    return _entries;}

 

Each class that uses ATL for implementing IUnknown specifies an interface map to provide to InternalQueryInterface. ATL's interface maps consist of structures containing interface ID (GUID)/DWORD/function pointer tuples. The following listing shows the type named _ATL_INTMAP_ENTRY that contains these tuples.

struct _ATL_INTMAP_ENTRY

{

    const IID* piid;

    DWORD dw;

    _ATL_CREATORARGFUNC* pFunc;

};

The first member is the interface ID (a GUID), and the second member indicates what action to take when the interface is queried. There are three ways to interpret the third member. If pFunc is equal to the constant _ATL_SIMPLEMAPENTRY (the value 1), dw is an offset into the object. If pFunc is non-null but not equal to 1, pFunc indicates a function to be called when the interface is queried. If pFunc is NULL, dw indicates the end of the QueryInterface() lookup table. Notice that CAtlSpaceship uses COM_INTERFACE_ENTRY. This is the interface map entry for regular interfaces. Here's the raw macro:

#define offsetofclass(base, derived)

((DWORD)(static_cast<base*>((derived*)8))-8)

 

#define COM_INTERFACE_ENTRY(x)\

    {&_ATL_IIDOF(x), \

    offsetofclass(x, _ComMapClass), \

    _ATL_SIMPLEMAPENTRY}

COM_INTERFACE_ENTRY fills the _ATL_INTMAP_ENTRY structure with the interface's GUID. In addition, notice how offsetofclass casts the this pointer to the right kind of interface and fills the dw member with that value. Finally, COM_INTERFACE_ENTRY fills the last field with _ATL_SIMPLEMAPENTRY to indicate that dw points to an offset into the class. For example, the interface map for CAtlSpaceship looks like this after the preprocessor is done with it:

const static _ATL_INTMAP_ENTRY* __stdcall _GetEntries()

{

    static const _ATL_INTMAP_ENTRY _entries[] = {

        {&IID_IAtlSpaceship,

        ((DWORD)(static_cast< IAtlSpaceship*>((_ComMapClass*)8))-8),

        ((_ATL_CREATORARGFUNC*)1)},

        {&IID_IDispatch,

        ((DWORD)(static_cast<IDispatch*>((_ComMapClass*)8))-8),

        ((_ATL_CREATORARGFUNC*)1)},

        {0, 0, 0}

    };

    return _entries;

}

Right now, the CAtlSpaceship class supports two interfaces, IAtlSpaceship and IDispatch, so there are only two entries in the map.

CComObjectRootEx's implementation of InternalQueryInterface uses the _GetEntries() function as the second parameter. CComObjectRootEx::InternalQueryInterface uses a global ATL function named AtlInternalQueryInterface() to look up the interface in the map. AtlInternalQueryInterface() simply walks through the map trying to find the interface.

In addition to COM_INTERFACE_ENTRY, ATL includes 16 other macros for implementing composition techniques ranging from tear-off interfaces to COM aggregation. Now you'll see what it takes to beef up the IAtlSpaceship interface and add those two other interfaces, IMotion and IVisual. You'll also learn about the strange COM  best known as a dual interface.

 

Making the Spaceship Go

 

Now that you've got some ATL code staring you in the face, what can you do with it? This is COM, so the place to start is in the IDL file. Again, if you're a seasoned C++ developer, this is a new aspect of software development you're probably not used to. Remember that these days, software distribution and integration are becoming very important. You've been able to get away with hacking out C++ classes and throwing them into a project together because you (as a developer) know the entire picture. However, component technologies (like COM) change that. You as a developer no longer know the entire picture. Often you have only a component, you don't have the source code for the component. The only way to know how to talk to a component is through the interfaces it exposes.

Keep in mind that modern software developers use many different tools, not just C++. You've got Visual Basic developers, Java developers, Delphi developers, and C developers. COM is all about making the edges line up so that software pieces created by these various components can all integrate smoothly when they come together. In addition, distributing software remotely (either out-of-process on the same machine or even to a different machine) requires some sort of inter-process communication. That's why there's Interface Definition Language (IDL). Here's the default IDL file created by the ATL wizards with the new spaceship class:

// spaceshipsvr.idl : IDL source for spaceshipsvr.dll

//

 

// This file will be processed by the MIDL tool to

// produce the type library (spaceshipsvr.tlb) and marshalling code.

 

import "oaidl.idl";

import "ocidl.idl";

      [

            object,

            uuid(223FEA41-EE58-4833-A94A-B82147D9B6B4),

            dual,

            helpstring("IAtlSpaceship Interface"),

            pointer_default(unique)

      ]

      interface IAtlSpaceship : IDispatch

      {

      };

 

[

      uuid(2D1BB358-8D02-45C7-A3FE-3C47B9A1A4AB),

      version(1.0),

      helpstring("spaceshipsvr 1.0 Type Library")

]

library SPACESHIPSVRLib

{

      importlib("stdole32.tlb");

      importlib("stdole2.tlb");

 

      [

            uuid(334E82E8-1DBF-4E07-8D52-D71CF967FFB1),

            helpstring("AtlSpaceship Class")

      ]

      coclass AtlSpaceship

      {

            [default] interface IAtlSpaceship;

      };

};

 

The key concept involved here is that IDL is a purely declarative language. This language defines how other clients will talk to an object. Remember, you'll eventually run this code through the MIDL compiler to get a pure abstract base class (useful for C++ clients) and a type library (useful for Visual Basic and Java clients as well as others). If you understand plain C code, you're well on your way to understanding IDL. You might think of IDL as C with footnotes. The syntax of IDL dictates that attributes will always precede what they describe. For example, attributes precede items such as interface declarations, library declarations, and method parameters.

If you look at the IDL file, you'll notice that it begins by importing oaidl.idl and ocidl.idl. Importing these files is somewhat akin to including windows.h inside one of your C or C++ files. These IDL files include definitions for all of the basic COM infrastructures (including definitions for IUnknown and IDispatch).

An open square bracket ( [ ) follows the import statement. In IDL, square brackets always enclose attributes. The first element described in this IDL file is the IAtlSpaceship interface. However, before you can describe the interface, you need to apply some attributes to it. For example, it needs a name (a GUID), and you need to tell the MIDL compiler that this interface is COM-oriented rather than being used for standard RPC and that this is a dual interface (more on dual interfaces shortly). Next comes the actual interface itself. Notice how it appears very much like a normal C structure.

Once the interfaces are described in IDL, it is often useful to collect this information into a type library, which is what the next section of the IDL file does. Notice the type library section also begins with an open square bracket, designating that attributes are to follow. As always, the type library is a discrete "thing" in COM and as such requires a name (GUID). The library statement tells the MIDL compiler that this library includes a COM class named AtlSpaceship and that clients of this class can acquire the IAtlSpaceship interface.

 

Adding Methods to an Interface

 

Right now the IAtlSpaceship interface is pretty sparse. It looks like it could use a method or two. Let's add one. Notice that Visual C++ now extends ClassView to include COM interfaces. You can tell they're COM interfaces because of the little lollipop next to the symbol. Notice also that CAtlSpaceship derives from something named IAtlSpaceship. IAtlSpaceship is, of course, a COM interface. Double-clicking on IAtlSpaceship in the ClassView brings that specific section of the IDL into the editor window, as shown in Figure 24.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

-----------------------------------------------------------------------------------------------------------------------

Figure 24: Interfaces in ClassView.

 

Figure 24: Interfaces in ClassView.

 

At this point, you could begin typing the COM interface into the IDL file. If you add functions and methods this way (straight into the IDL file), you'll have to touch the AtlSpaceship.h and AtlSpaceship.cpp files and insert the methods by hand. A more effective way to add functions to the interface is through the ClassView. To edit the IDL through the ClassView, simply right-click the mouse on the interface within ClassView. Two items that appear in the context menu are Add Method and Add Property. Let's add a method named CallStarFleet. Figure 26 shows the dialog box that appears when adding a method. To add a method, simply type the name of the method, CallStarFleet into the Method Name text box. Then type the method parameters into the Parameters text box as shown below.

 

[in]float fStarDate, [out, retval]BSTR* pbstrRecipient

 

Here's where it helps to understand a little bit about IDL.

 

Figure 25: Adding method to interface.

 

Figure 25: Adding method to interface.

 

Figure 26: Adding method information.

 

Figure 26: Adding method information.

 

 

Remember that IDL's purpose is to provide completely unambiguous information about how methods can be invoked. In the standard C++ world, you could often get away with ambiguities like open-ended arrays because the caller and the callee shared the same stack frame, there was always a lot of wiggle room available. Now that method calls might eventually go over the wire, it's important to tell the remoting layer exactly what to expect when it encounters a COM interface. This is done by applying attributes to the method parameters (more square brackets).

The method call shown in Figure 26 (CallStartFleet()) has two parameters in its list, a floating point number indicating the stardate and a BSTR indicating who received the communication. Notice that the method definition spells out the parameter direction. The stardate is passed into the method call, designated by the [in] attribute. A BSTR identifying the recipient is passed back as a pointer to a BSTR. The [out] attribute indicates the direction of the parameter is from the object back to the client. The [retval] attribute indicates that you can assign the result of this method to a variable in higher languages supporting this feature.

 

Dual Interfaces

 

If you read through Module 24, you had a chance to see the IDispatch interface. IDispatch makes it possible to expose functionality (at the binary level) to environments such as VBScript that don't have a clue about vtables. For IDispatch to work, the client has to go through a lot of machinations before it can call Invoke(). The client first has to acquire the invocation tokens. Then the client has to set up the VARIANT arguments. On the object side, the object has to decode all those VARIANT parameters, make sure they're correct, put them on some sort of stack frame, and then make the function call. As you can imagine, all this work is complex and time-consuming. If you're writing a COM object and you expect some of your clients to use scripting languages and other clients to use languages like C++, you've got a dilemma. You've got to include IDispatch or you lock your scripting language clients out. If you provide only IDispatch, you make accessing your object from C++ very inconvenient. Of course, you can provide access through both IDispatch and a custom interface, but that involves a lot of bookkeeping work. Dual interfaces evolved to handle this problem.

A dual interface is simply IDispatch with functions pasted onto the end. For example, the IMotion interface described below is a valid dual interface:

interface IMotion : public IDispatch

{

    virtual HRESULT Fly() = 0;

    virtual HRESULT GetPosition() = 0;

};

Because IMotion derives from IDispatch, the first seven functions of IMotion are those of IDispatch. Clients who understand only IDispatch (VBScript for instance) look at the interface as just another version of IDispatch and feed DISPIDs to the Invoke function in the hopes of invoking a function. Clients who understand vtable-style custom interfaces look at the entire interface, ignore the middle four functions (the IDispatch functions), and concentrate on the first three functions (IUnknown) and the last three functions (the ones that represent the interface's core functions). Figure 27 shows the vtable layout of IMotion.

Most raw C++ implementations load the type library right away and delegate to ITypeInfo to perform the nasty task of implementing Invoke() and GetIDsOfNames(). To get an idea of how this works, see Kraig Brockschmidt's book Inside OLE, 2d. ed. (Microsoft Press, 1995) or Dale Rogerson's book Inside COM (Microsoft Press, 1997).

 

Figure 27:  The layout of a dual interface.

 

Figure 27:  The layout of a dual interface.

 

ATL and IDispatch

 

ATL's implementation of IDispatch delegates to the type library. ATL's implementation of IDispatch lives in the class IDispatchImpl. Objects that want to implement a dual interface include the IDispatchImpl template in the inheritance list like this:

 

class ATL_NO_VTABLE CAtlSpaceship :

    public CComObjectRootEx<CComSingleThreadModel>,

    public CComCoClass<CAtlSpaceship, &CLSID_AtlSpaceship>,

    public IDispatchImpl<IAtlSpaceship, &IID_IAtlSpaceship, &LIBID_SPACESHIPSVRLib>,

    public IDispatchImpl<IVisual, &IID_IVisual, &LIBID_SPACESHIPSVRLib>,

    public IDispatchImpl<IMotion, &IID_IMotion, &LIBID_SPACESHIPSVRLib>

{...};

 

In addition to including the IDispatchImpl template class in the inheritance list, the object includes entries for the dual interface and for IDispatch in the interface map so that QueryInterface() works properly:

 

BEGIN_COM_MAP(CAtlSpaceship)

    COM_INTERFACE_ENTRY(IAtlSpaceship)

    COM_INTERFACE_ENTRY(IDispatch)

END_COM_MAP()

 

As you can see, the IDispatchImpl template class arguments include the dual interface itself, the GUID for the interface, and the GUID representing the type library holding all the information about the interface. In addition to these template arguments, the IDispatchImpl class has some optional parameters not illustrated in Figure 27. The template parameter list also includes room for a major and minor version of the type library. Finally, the last template parameter is a class for managing the type information. ATL provides a default class named CComTypeInfoHolder.

In most raw C++ implementations of IDispatch, the class calls LoadTypeLib() and ITypeLib::GetTypeInfoOfGuid in the constructor and holds on to the ITypeInfo pointer for the life of the class. ATL's implementation does things a little differently by using the CComTypeInfoHolder class to help manage the ITypeInfo pointer. CComTypeInfoHolder maintains an ITypeInfo pointer as a data member and wraps the critical IDispatch-related functions GetIDsOfNames() and Invoke().

Clients acquire the dual interface by calling QueryInterface() for IID_IAtlSpaceship. The client can also get this interface by calling QueryInterface() for IDispatch. If the client calls CallStartFleet() on the interface, the client accesses those functions directly (as for any other COM interface).

When a client calls IDispatch::Invoke, the call lands inside IDispatchImpl's Invoke() function as you'd expect. From there, IDispatchImpl::Invoke delegates to the CComTypeInfoHolder class to perform the invocation, CComTypeInfoHolder's Invoke(). The CComTypeInfoHolder class doesn't call LoadTypeLib() until an actual call to Invoke() or GetIDsOfNames(). CComTypeInfoHolder has a member function named GetTI() that consults the Registry for the type information (using the GUID and any major/minor version numbers passed in as a template parameter). Then CComTypeInfoHolder calls ITypeLib::GetTypeInfo to get the information about the interface. At that point, the type information holder delegates to the type information pointer. IDispatchImpl implements IDispatch::GetIDsOfNames in the same manner.

 

The IMotion and IVisual Interfaces

 

To get this COM class up to snuff with the other versions (the raw C++ version and the MFC version described in Module 23), you need to add the IMotion and IVisible interfaces to the project and to the class. Unfortunately, at the present time the only way to get this to happen is by typing the interfaces in by hand (the ATL AppWizard gives you only one interface by default but Visual /Studio C++ .Net has improved this). Open the IDL file and position the cursor near the top (somewhere after the #import statements but before the library statement), and start typing interface definitions as described in the following paragraph.

Once you get the hang of IDL, your first instinct when describing an interface should be to insert an open square bracket. Remember that in IDL, distinct items get attributes. One of the most important attributes for an interface is the name, or the GUID. In addition, at the very least the interface has to have the object attribute to tell the MIDL compiler you're dealing with COM at this point (as opposed to regular RPC). You also want these interfaces to be dual interfaces. The keyword "dual" in the interface attributes indicates this and inserts certain Registry entries to get the universal marshaling working correctly. After the attributes are closed off with a closing square bracket, the interface keyword kicks in to describe the interface. You'll make IMotion a dual interface and IVisual a plain custom interface to illustrate how the two different types of interfaces are attached to the CSpaceship class. Here are the IMotion and IVisible interfaces described in IDL:

    [

        object,

        uuid(97B5C101-5299-11d1-8CAA-FD10872CC837),

        dual,

        helpstring("IMotion interface")

    ]

 

    interface IMotion : IDispatch

    {

        HRESULT Fly();

        HRESULT GetPosition([out,retval]long* nPosition);

    };

 

    [

        object,

        uuid(56F58464-52A4-11d1-8CAA-FD10872CC837),

        helpstring("IVisual interface")

    ]

 

    interface IVisual : IUnknown

    {

        HRESULT Display();

    };

 

Once the interfaces are described in IDL, you run the IDL through the MIDL compiler again. The MIDL compiler spits out a new copy of spaceshipsvr.h with the pure abstract base classes for IMotion and IVisual.

Now you need to add these interfaces to the CSpaceship class. There are two steps here. The first step is to create the interface part of the COM class's identity. Let's do the IMotion interface first. Adding the IMotion interface to CSpaceship is easy. Just use the IDispatchImpl template to provide an implementation of a dual interface like this:

class ATL_NO_VTABLE CAtlSpaceship :

    public CComObjectRootEx<CComSingleThreadModel>,

    public CComCoClass<CAtlSpaceship, &CLSID_AtlSpaceship>,

    public IDispatchImpl<IAtlSpaceship, &IID_IAtlSpaceship, &LIBID_SPACESHIPSVRLib>,

    public IDispatchImpl<IMotion, &IID_IMotion, &LIBID_SPACESHIPSVRLib>

{...};

The second step involves beefing up the interface map so the client can acquire the IMotion interface. However, having two dual interfaces in a single COM class brings up an interesting issue. When a client calls QueryInterface() for IMotion, the client should definitely get IMotion. However, when the client calls QueryInterface() for IDispatch, which version of IDispatch should the client get, IAtlSpaceship's dispatch interface or IMotion's dispatch interface?

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Multiple Dual Interfaces

 

Remember that all dual interfaces begin with the seven functions of IDispatch. A problem occurs whenever the client calls QueryInterface() for IID_IDispatch. As a developer, you need to choose which version of IDispatch to pass out. The interface map is where the QueryInterface() for IID_IDispatch is specified. ATL has a specific macro for handling the dual interface situation. First consider the interface map for CAtlSpaceship so far:

BEGIN_COM_MAP(CAtlSpaceship)

    COM_INTERFACE_ENTRY(IAtlSpaceship)

    COM_INTERFACE_ENTRY(IDispatch)

END_COM_MAP()

When the client calls QueryInterface(), ATL rips through the table trying to match the requested IID to one in the table. The interface map above handles two interfaces: IAtlSpaceship and IDispatch. If you want to add another dual interface to the CAtlSpaceship class, you need a different macro.

The macro handling multiple dispatch interfaces in an ATL-based COM class is named COM_INTERFACE_ENTRY2. To get QueryInterface() working correctly, all you need to do is decide which version of IDispatch the client should get when asking for IDispatch, like this:

BEGIN_COM_MAP(CAtlSpaceship)

    COM_INTERFACE_ENTRY(IAtlSpaceship)

    COM_INTERFACE_ENTRY(IMotion)

    COM_INTERFACE_ENTRY2(IDispatch, IAtlSpaceship)

END_COM_MAP()

In this case, a client asking for IDispatch gets a pointer to IAtlSpaceship (whose first seven functions include the IDispatch functions). Adding a non-dual interface to an ATL-based COM class is even easier. Just add the interface to the inheritance list like this:

class ATL_NO_VTABLE CAtlSpaceship :

    public CComObjectRootEx<CComSingleThreadModel>,

    public CComCoClass<CAtlSpaceship, &CLSID_AtlSpaceship>,

    public IDispatchImpl<IAtlSpaceship, &IID_IAtlSpaceship, &LIBID_SPACESHIPSVRLib>,

    public IDispatchImpl<IMotion, &IID_IMotion, &LIBID_SPACESHIPSVRLib>,

    public IVisual

{...};

Then add an interface map entry like this:

BEGIN_COM_MAP(CAtlSpaceship)

    COM_INTERFACE_ENTRY(IAtlSpaceship)

    COM_INTERFACE_ENTRY(IMotion)

    COM_INTERFACE_ENTRY2(IDispatch, IAtlSpaceship)

END_COM_MAP()

Then, repeat for IVisual interface.

 

Conclusion

 

There are a couple of key points in this module to remember. COM is a binary object model. Clients and objects agree on a binary layout (the interface). Once both parties agree on the layout, they talk together via the interface. The client is not at all concerned about how that interface is actually wired up. As long as the functions work as advertised, the client is happy. There are a number of ways to hook up COM interfaces, including multiply inheriting a single C++ class from several interfaces, using nested classes, or using a framework such as ATL.

ATL is Microsoft's framework for assembling small COM classes. ATL has two sides, some smart pointers to help with client-side coding and a complete framework for implementing COM classes. ATL implements IUnknown, IDispatch, and IClassFactory in templates provided through the library. In addition, ATL includes a wizard for helping you get started with a COM server and a wizard for inserting COM classes into your project. While ATL does a lot for you, it doesn't completely excuse you from learning the basics of how COM works. In fact, you'll be able to use ATL a lot more efficiently once you understand COM. In the next module, we'll take a look at how to use ATL to write ActiveX controls effectively. The following Table provides CComPtr class info:

 

Information

Description

The class

CComPtr.

The use

A smart pointer class for managing COM interface pointers.

The prototype

template<class T>

class CComPtr

The parameters

T - A COM interface specifying the type of pointer to be stored.

Method

CComPtr - The constructor.

Operator

operator = - Assigns a pointer to the member pointer.

The header file

atlcomcli.h

Remark

ATL uses CComPtr and CComQIPtr to manage COM interface pointers. Both are derived from CComPtrBase, and both perform automatic reference counting.

 

Table 1.

 

Next, the CComQIPtr class info:

 

Information

Description

The class

CComQIPtr.

The use

A smart pointer class for managing COM interface pointers.

The prototype

template<class T, const IID* piid = &__uuidof(T)>

class CComQIPtr: public CComPtr<T>

The parameters

T - A COM interface specifying the type of pointer to be stored.

piid - A pointer to the IID of T.

Method

CComQIPtr - Constructor.

Operator

operator = - Assigns a pointer to the member pointer.

The header file

atlcomcli.h

Remark

ATL uses CComQIPtr and CComPtr to manage COM interface pointers, both of which derive from CComPtrBase. Both classes perform automatic reference counting through calls to AddRef() and Release(). Overloaded operators handle pointer operations.

 

Table 1.

 

 

---------------End-----------

 

 

 

 

 

 

Further reading and digging:

  1. DCOM at MSDN.

  2. COM+ at MSDN.

  3. COM at MSDN.

  4. Win32 process, thread and synchronization story can be found starting from Module R.

  5. MSDN MFC 7.0 class library online documentation.

  6. MSDN MFC 9.0 class library online documentation - latest version.

  7. MSDN Library

  8. Windows data type.

  9. Win32 programming Tutorial.

  10. The best of C/C++, MFC, Windows and other related books.

  11. Unicode and Multibyte character set: Story and program examples.

 

 

 

 

 


 

| Tenouk C & C++ | MFC Home | Active Template Library 4 | ATL and ActiveX Controls 1 | Download | Site Index |