This week I was working on a C++ program which used a lot of
COM pointers. I remembered I’ve seen an automation class somewhere, and after some searching I found it, it’s Microsoft’s
ComPtr template class. Although I liked the concept, it had too much fuss to me, so I was displeased in using it.
Oh well, here we go again: I wrote my own COM pointer automation class. Here it goes the full code of it, which I now share with the world:
#pragma once
#include <Windows.h>
#include <ObjBase.h>
template<typename T> class ComPtr {
public:
ComPtr() : _ptr(NULL) { }
ComPtr(const ComPtr& other) : _ptr(NULL) { operator=(other); }
~ComPtr() { this->release(); }
ComPtr& operator=(const ComPtr& other) {
if(this != &other) {
this->~ComPtr();
_ptr = other._ptr;
if(_ptr) _ptr->AddRef();
}
return *this;
}
void release() {
if(_ptr) {
_ptr->Release();
_ptr = NULL;
}
}
bool coCreateInstance(REFCLSID rclsid) {
return _ptr ? false :
SUCCEEDED(::CoCreateInstance(rclsid, 0, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&_ptr)));
}
bool coCreateInstance(REFCLSID rclsid, REFIID riid) {
return _ptr ? false :
SUCCEEDED(::CoCreateInstance(rclsid, 0, CLSCTX_INPROC_SERVER, riid, (void**)&_ptr));
}
template<typename COM_INTERFACE> bool queryInterface(REFIID riid, COM_INTERFACE **comPtr) {
return !_ptr ? false :
SUCCEEDED(_ptr->QueryInterface(riid, (void**)comPtr));
}
bool isNull() const { return _ptr == NULL; }
T& operator*() { return *_ptr; }
T* operator->() { return _ptr; }
T** operator&() { return &_ptr; }
operator T*() const { return _ptr; }
private:
T *_ptr;
};
Basically, by using this class I don’t have to worry about calling the
Release method. Most interestingly, I added two shorhand methods to ease my life,
coCreateInstance
and
queryInterface
. Here are an example illustrating the use of the ComPtr class, along with the cited methods:
{
ComPtr<IGraphBuilder> graph;
if(!graph.coCreateInstance(CLSID_FilterGraph))
OutputDebugString(L"Failed!");
ComPtr<IMediaControl> mediaCtrl;
if(!graph.queryInterface(IID_IMediaControl, &mediaCtrl))
OutputDebugString(L"Failed!");
graph->RenderFile(L"foo.avi", NULL); // sweet!
}
If you’re wondering about the usefulness of this ComPtr class, try to write the code above without it.