Advertising

Using COM objects from ATL

Contents

Introduction

The whole point of COM is that you shouldn't need access to the source code of the COM object you are using. However, using COM objects from within your own ATL COM objects is not simple when you don't have the source code. The following steps will explain how to use the Type Library instead.

In the past Microsoft supported the use of the 'ATL Proxy Generator' in this situation. However, since Visual C++ 6, it is no longer being supplied, and they advise the use of the #import pre-processor directive only. For those who are interested, a previous version of this document explains the use of the 'ATL Proxy Generator'.

Using #import

Microsoft has added the #import pre-processor directive to their compiler. This directive - intended to mimic #include - takes a type library and generates wrapper code automatically at compile time. You can see the files it creates in your output directory - one with the '.tli' extension, and one with the '.tlh' extension.

I advise the use of the raw_native_types argument. In my experience this solves a lot of unnecessary problems. Refer to the documentation for details.

For instance:

#import "Example.tlb" raw_native_types

This will make a wrapper class available to your code. The name of the class is:   XXXXPtr, where XXXX is the name of the COM object described in the type library. One wrapper class will be created for each COM object in the package.

The wrapper class (and anything else created by #import) will be in a namespace whose name is formed from the type library filename (converted to capitals) and a 'Lib' suffix. For instance, if you are importing the IExampleThing interface from the Examples package, we could declare an instance of the wrapper class like so:

EXAMPLESLib::IExampleThingPtr m_ExampleThingWrapper;

Instantiating the COM object

Adding the member variable

You should add the wrapper to your ATL object as a  member variable.

For instance:

EXAMPLESLib::IExampleThingPtr m_ExampleThingWrapper;

Using CoCreateInstance

You should create an instance of the COM object in the FinalConstruct() method of your client ATL object. If your object does not already have a FinalConstruct() method you will need to add it manually.

For instance:

HRESULT FinalConstruct()
{
    HRESULT hr = ::CoCreateInstance( __uuidof(EXAMPLELib::Example), NULL, CLSCTX_ALL, __uuidof(EXAMPLELib::IExample), (void**)&m_ExampleThingWrapper);
    return hr;
}

Note the use of the EXAMPLELib namespace, and the __uuidof (2 underscores) macro to get the GUID of the object and of its interface.

Releasing the instance

You should release the instance of the COM object in the FinalRelease() method of your client ATL object. If your object does not already have a FinalRelease() method you will need to add it manually.

For instance:

void FinalRelease()       
{
     m_ExampleThingWrapper.Release();
}

Using the COM object's methods

This wrapper class is a smart pointer. You can access the interface's methods by using the indirection operator. The method's return argument will be returned as the return value.

For instance:

int iVal = m_ExampleThingWrapper->Foo(2, 3, 4);

Exceptions

If one of the COM methods does not succeed then the smart pointer will throw an exception of type _com_error, so you should catch this exception in a try/catch block.

For instance:

try
{
    ...
}
catch( _com_error& ex )
{
    ...
}
The _com_error object contains details about the HRESULT.

Copyright © Murray Cumming. Verbatim copying and distribution of this entire article is permitted in any medium, provided this notice is preserved.

Murray's Web Pages