Harlinn Windows on CodePlex[^]
Microsoft Component Object Model, COM, is a mechanism providing binary interoperability between software components, and as far as I know, it’s the most successful standard for interoperability ever conceived.
COM is a fundamental part of Windows and .Net. .Net developers write software that uses COM all the time, even if they’re not consciously aware of this, and most software written for the .Net platform can easily expose it’s functionality to unmanaged code using COM by just selecting the ‘Make assembly COM-Visible’ check box found by clicking the ‘Assembly Information…’ button on the project properties ‘Application’ page.
Over the years Microsoft has added a significant number of APIs’ to Windows based on COM, and for C++ developers using them is sometimes a bit cumbersome. As a developer you’re obviously expected to check for program errors, and most COM based APIs’ return a
HRESULT conveying information about whether a call succeeded or not. Normally a negative value indicates that an error occurred, but not every API follows this convention – .Net on the other hand transparently converts errors to into exceptions, improving the whole development experience.
One of the fundamental features of COM is object lifetime management, which is implemented using reference counting, so COM requires C++ developers to explicitly decrement the reference count of an object when they no longer needs it:
HRESULT hr = CoCreateInstance(CLSID_WICImagingFactory1,
Release() which is one of three functions that’s part of all interfaces:
virtual HRESULT __stdcall QueryInterface(REFIID riid, void **ppvObject) = 0;
virtual ULONG __stdcall AddRef( void ) = 0;
virtual ULONG __stdcall Release( void ) = 0;
IUnknown is no longer declared exactly like this, it’s technically a correct definition of the interface, and so is this:
typedef struct IUnknownVtbl
HRESULT ( __stdcall *QueryInterface )( IUnknown * This, REFIID riid, void **ppvObject);
ULONG ( __stdcall *AddRef )( IUnknown * This );
ULONG ( __stdcall *Release )( IUnknown * This );
typedef struct tagIUnknown
struct IUnknownVtbl *lpVtbl;
Which tells us one fundamental thing about COM interfaces: An interface is just a C++ class consisting of pure virtual functions – which really is just a structure containing a single pointer to a structure containing nothing but function pointers.
When we create a new interface:
class IClassFactory : public IUnknown
virtual HRESULT __stdcall CreateInstance( IUnknown *pUnkOuter, REFIID riid, void **ppvObject) = 0;
virtual HRESULT __stdcall LockServer( BOOL fLock) = 0;
We declare that interface as a class derived from
IUnknown, containing only pure virtual functions, which is the same as:
typedef struct IClassFactoryVtbl
HRESULT ( __stdcall *QueryInterface )( IClassFactory * This, REFIID riid, void **ppvObject);
ULONG ( __stdcall *AddRef )( IClassFactory * This );
ULONG ( __stdcall *Release )( IClassFactory * This);
HRESULT ( __stdcall *CreateInstance )( IClassFactory * This,IUnknown *pUnkOuter,
REFIID riid, void **ppvObject);
HRESULT ( __stdcall *LockServer )( IClassFactory * This, BOOL fLock);
typedef struct tagIClassFactory
struct IClassFactoryVtbl *lpVtbl;
Note that the order of the function pointers is the same as the order of the pure virtual function declarations for the C++ representation of the interface. Those from
IUnknown come first, and then come the function pointers representing the two functions added to the interface by the
IUnknown is deceptively simple, but if you stop and think about it, you’ll realize that it’s quite elegant.
Release() provides the functionality required for lifetime management, while
QueryInterface allows us to access all the interfaces implemented for the object:
void foo(IUnknown* pUnknownForWICImagingFactory1)
IWICImagingFactory* pIWICFactory = nullptr;
HRESULT hr = pUnknownForWICImagingFactory1->QueryInterface(IID_IWICImagingFactory,
The one really important thing to remember is that you must always call
Release() for the interfaces you acquire through QueryInterface, or any other COM API function.
Included with this article is the source code for a library that I’m developing, that makes COM client development in C++ somewhat similar to how .Net developers experience COM development.
The following function opens the Common Item Dialog, letting the user select an image which is then loaded and converted into a DIB section using the Windows Imaging Component.
auto fileOpenDialog = harlinn::windows::FileOpenDialog::Create();
auto item = fileOpenDialog->GetResult();
String fileName = item.GetDisplayName(SIGDN_FILESYSPATH);
bitMap = BitmapHandle::LoadFromFile(fileName);
The library contains wrappers for a significant number of Windows API COM interfaces, covering:
- Windows Imaging Component
- Windows Property System
- Core COM interfaces
When we use .Net to access a COM based API things are a little easier, as .Net performs this error checking for us, and in case of a failure .Net converts it into an exception that is thrown before control is returned to our code. That’s actually a pretty nifty service provided by .Net, because when we go native, as in this function:
HRESULT DemoApp::ConvertBitmapSource(HWND hWnd, IWICBitmapSource **ppToRenderBitmapSource)
*ppToRenderBitmapSource = NULL;
HRESULT hr = S_OK;
hr = GetClientRect(hWnd, &rcClient) ? S_OK: E_FAIL;
IWICBitmapScaler *pScaler = NULL;
hr = m_pIWICFactory->CreateBitmapScaler(&pScaler);
hr = pScaler->Initialize(m_pOriginalBitmapSource, rcClient.right - rcClient.left,
rcClient.bottom - rcClient.top, WICBitmapInterpolationModeFant);
IWICFormatConverter *pConverter = NULL;
hr = m_pIWICFactory->CreateFormatConverter(&pConverter);
hr = pConverter->Initialize(pScaler,GUID_WICPixelFormat32bppBGR,
hr = pConverter->QueryInterface(IID_PPV_ARGS(ppToRenderBitmapSource));
There are suddenly a lot of things going on that has to do with object lifetime and error handling. Not only does .Net convert errors into exceptions, it also manages the lifetime of our references.
To solve the lifetime part of the problem, it’s common to use smart interface pointer classes, like
CComPtr<>, which works as far as lifetime is concerned, but we still have to check the HRESULT, because the smart interface pointer does its magic by implementing
T* operator -> () const, providing access to the interface.
I would like to be able to implement it like this:
BitmapSource DemoApp::ConvertBitmapSource(std::shared_ptr<Control> theControl)
RECT rect = theControl->GetClientRect();
auto scaler = imagingFactory.CreateBitmapScaler();
scaler.Initialize(originalBitmapSource, rect.right - rect.left,
rect.bottom - rect.top, BitmapInterpolationMode::Fant);
auto converter = imagingFactory.CreateFormatConverter();
Or event better, like this:
BitmapSource DemoApp::ConvertBitmapSource(std::shared_ptr<Control> theControl)
RECT rect = theControl->GetClientRect();
Scale(rect.right - rect.left, rect.bottom - rect.top).
The above illustrates how I would expect a well-designed C++ API to work, letting me focus on what I want to do with a particular piece of code, not error handling and lifetime management.
Error handling and lifetime management still has to be performed, but behind the scenes, somewhat alike to what .Net developers can take for granted when they work with COM.
The Façade Pattern
The facade pattern is a software design pattern often used with object-oriented programming. The name refers to an architectural façade – it’s what you’re able to see from the outside. A facade is an object that provides a simplified interface to the developer, hiding the complexity of interacting with a larger piece of code, such as a class library. A facade object can:
- Make a software library easier to use, understand and test, since the facade provides convenient methods for common tasks.
- Make the library more readable, for the similar reasons.
- Reduce dependencies of outside code on the inner workings of a library. Since the client code uses the facade, this also adds more flexibility to the development process.
- Wrap a poorly designed collection of APIs with a single well-designed API.
As the last implementation of
ConvertBitmapSource demonstrates, this can radically simplify the development process while at the same time improve the robustness of our application.
Since COM interfaces inherit the IUnknown interface allowing us to access all the other interfaces implemented by the underlying object, that’s a significant piece of functionality that we want for our façade objects too.
Unknown unknown = renderTarget;
rt = unknown.As<graphics::RenderTarget>();
In the above code a
renderTarget, is assigned to an
unknown. Afterwards the
Is<T>() function is used to determine whether
unknown is something that can be successfully converted to an object of type
graphics::RenderTarget – which is done using the
Meaning we’re able to perform significant COM related operations in a straight forward manner, without really being concerned with any details related to what actually makes this work.
Most of the
Unknown class was introduced in Rendering text with Direct2D & DirectWrite[^], but then with a focus on how to properly implement the move constructor and move assignment operator.
typedef IUnknown InterfaceType;
explicit Unknown(IUnknown* theUnknown, bool addref = false);
Unknown(REFIID iid, const Unknown& theUnknown, bool throwIfNoInterface = true );
Unknown(const Unknown& other);
operator bool() const;
Unknown& operator = (const Unknown& other);
Unknown& operator = (Unknown&& other);
Unknown& Reset(IUnknown* other = nullptr, bool addRef = false);
T As() const;
bool Is() const;
static T CoCreateInstanceFromClassId(const CLSID& clsid, DWORD classContext = CLSCTX_INPROC_SERVER);
static T CoCreateInstanceFromClassId(const String& clsid, DWORD classContext = CLSCTX_INPROC_SERVER);
static T CoCreateInstanceFromProgId(const String& progId, DWORD classContext = CLSCTX_INPROC_SERVER);
The constructor used during conversion takes three arguments:
REFIID iid – identifying the requested interface
const Unknown& theUnknown – the object holding a reference to the object we want to retrieve another interface for.
bool throwIfNoInterface – indicates whether the constructor will throw an exception if the requested interface is not available on the object.
Unknown(REFIID iid, const Unknown& theUnknown, bool throwIfNoInterface = true )
if( theUnknown )
IUnknown* pInterface = nullptr;
auto hr = theUnknown.unknown->QueryInterface(iid,(void**)&pInterface);
if((throwIfNoInterface == false)&&(hr == E_NOINTERFACE))
unknown = pInterface;
A derived class will typically provide a similar constructor for use by descendants:
BitmapSource (REFIID iid, const Unknown& theUnknown, bool throwIfNoInterface = true );
And one that uses
__uuidof(InterfaceType) to get the
REFIID identifying the interface for the object under construction.
BitmapSource (const Unknown& theUnknown, bool throwIfNoInterface = true )
: Base ( __uuidof(InterfaceType), theUnknown, throwIfNoInterface )
Now we have the building blocks required to implement the
As<T>() const function:
T As() const
const Unknown& self = *this;
which enables conversion from one interface wrapper type to another, as long as they satisfy the requirements we've been through.
Is<T>() const function uses the same mechanism to query whether an object can be converted to another object type:
bool Is() const
T::InterfaceType* pInterface = nullptr;
auto hr = unknown->QueryInterface(__uuidof(T::InterfaceType),(void**)&pInterface);
if(hr == S_OK )
So far we’ve implemented a simple mechanism that provides important functionality for our COM wrapper facades – making them pretty flexible.
Implementing a wrapper function
The signature of the
IEnumUnknown::Clone is typical for a COM API function:
virtual HRESULT STDMETHODCALLTYPE Clone(
__RPC__deref_out_opt IEnumUnknown **ppenum) = 0;
And our wrapper is implemented as follows:
auto pInterface = GetInterface();
IEnumUnknown* pClone = nullptr;
auto hr = pInterface->Clone(&pClone);
GetInterface() function will return a pointer to the
IEnumUnknown interface, or throw an exception if no interface pointer is assigned to the object. We then proceed to call the COM interface and check whether an error occured.
CheckHRESULT will throw an exception if
hr is < 0.
If everything went well, we construct and return an EnumUnknown object.
By implementing facade classes for COM APIs’ we’re able to improve the COM client development experience in a way that makes our applications more maintainable and robust, and the good thing is that it isn’t all that difficult.
If you’ve never used C++ templates, this also demonstrates that you can get a lot of mileage out of very little code – and that it doesn’t have to be complicated to be useful.
- 1. of November 2012 - initial posting
- 15. of November 2012 - Library update - have a look at Windows Development in C++, working with menus[^] for a list of changes made to the library
- 18. of November 2012 - Library update
- 21. of November 2012 - Library update
- 22. of November 2012 - Library update
- 30. of November 2012 - Library update