Monday, October 26, 2009

ATL Removal: Part 4 – Replacing CComPtr with _com_ptr_t

CComPtr (a.k.a. smart pointer) is another helpful template class provided in ATL that is intended to make COM programming easier. CComPtr wraps and abstracts the com object and does all of the lifetime management stuff automatically for you like calling AddRef and Release. Lifetime management is not that tricky to do it on your own. A pattern I like to use is call AddRef when I get passed a com object that I need to use, and then call Release when I am done using it. It’s not very complicated to get it right. Also, just because you are using a CComPtr, it is possible to still screw up the ref count and cause leaks or double frees, so you still need to know what you are doing with them to avoid these issues. Let’s move on to the topic at hand, replacing CComPtr.

Trying to just get rid of CComPtrs and code straight com objects could be a pain since it more about redoing the entire coding pattern of the project instead of modifying declarations. If you don’t want to depend on ATL in the sense that your binary doesn't load the ATL dlls, the it is fine to still include the .h file, but if you want to purge ATL altogether, read on. Keep in mind _com_ptr_t doesn't do everything that ATL smart pointers, so some extra manual work may still be required.

Luckily there is compiler support for non-ATL smart pointers in the form of _com_ptr_t that will allow us to change the declarations instead of the coding pattern.

So this is what a declaration might look like before:

CComPtr m_spYourInterface;

And this is what it would look like afterwards:

_com_ptr_t<_com_iiid<> > m_spYourInterface;

Additionally you will need to add comip.h to your stdafx.h file, and USE_MSVCRT=1 comsuppw.lib to your TARGETLIBS in the sources file to get your project to compile and link.

Here are some errors you might hit:

file.cpp(776) : error C2039: 'CopyTo' : is not a member of '_com_ptr_t<_iiid>'

The code looks something like this:

hr = m_spObject.CopyTo( ppObject );

Change it to this:

if (
m_spObject) m_spObject.AddRef();
*ppObject = m_spObject;

I guess _com_ptr_t<_iiid> does not provide that method, but the little AddRef and assignment does the same thing.

You might see this linking error as well:
error LNK2001: unresolved external symbol "void __stdcall _com_issue_error(long)" (?

You need to make sure you enable compiler support for _com_ptr_t smart pointers. Add the following to your sources file:


No comments:

Post a Comment