Advertising

Using COM objects from ATL (Using the ATL Proxy Generator)

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.

Please note that Microsoft no longer supply the 'ATL Proxy Generator' with Visual C++. See the newer version of this document.

Creating the Wrapper class

To create the wrapper choose 'Add To Project' | 'Components and Controls' from the Project menu.

Open 'Developer Studio Components', then select 'ATL Proxy Generator' and click [Insert]. Agree to insert.

In the ATL Proxy Generator dialog click the [...] button and select the Type Library. This is usually a file with a '.tlb' extension supplied with the dll/exe/ocx, or it may be contained within the dll/exe/ocx file.

One or more interfaces from the COM object will be shown on the left. Select the interfaces you want by moving them to the right. This explanation will continue with the assumption that you selected only one.

Select 'Smart Pointer' and click [Insert].

You may now specify the name of the header file which will be created. I suggest you prefix the name of this header file with 'CProxyI' to avoid any confusion. e.g. 'CProxyIExample'. Note that this is a wrapper for an interface, and each object may have several interfaces.

You should add this new file to your project in the Files tab of the Workspace.

Modifying the Wrapper class so it compiles

Unfortunately this wrapper will probably not compile as it stands. There are several constants in the the auto-generated code which are not defined. You need to make the following changes:

Using #import

Add an #import line at the top of the header file. The #import directive is a Microsoft-specific keyword which actually creates some source files and automatically includes them. These files are placed in your debug/release folder when you build your project.

For instance: #import "Example.tlb" raw_native_types raw_interfaces_only

You may need to specify the path to the tlb file if it isn't in your project directory. Of course you could copy it in to the project directory, but you must make sure that it stays up-to-date.

The 'raw_native_types raw_interfaces_only' arguments modify the source code created by the #import directive. In my experience using them solves a lot of unnecessary problems. Refer to the documentation for details.

Using the lib namespace

You will also need to modify the first line of the wrapper class.

For instance, change:

// CProxyIExample
class CProxyIExample : public CComPtr<IExample>

To:

/ CProxyIExample
class CProxyIExample : public CComPtr<EXAMPLELib::IExample>

Note: ExampleLib is the namespace in which the #import code is placed.

Instantiating the COM object

Adding the member variable

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

For instance: CProxyIExample m_Proxy_IExample;

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_Proxy_IExample );
     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_Proxy_IExample.Release();
}

Using the COM object's methods

The auto-generated proxy class should contain methods for each of the COM methods in the interface. These will return an HRESULT value, which you should test with the SUCCEEDED macro.

Any return parameters will have to be allocated before using them in the method call. This applies particularly to BSTRs and VARIANTs.

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