See the question and my original answer on StackOverflow

If you work with Visual Studio, there is a cool #import directive that generates wrappers that ease COM when a Type Library is available.

Most of the time the Type Library is included in the COM object itself (the DLL that serves the object you're after) or in a .TLB aside the DLL. Here is a simple example with the scripting object which resides in C:\Windows\System32\scrrun.dll:

#include "stdafx.h"

// import the .TLB that's compiled in scrrun.dll
#import "C:\Windows\System32\scrrun.dll" \
    rename("FreeSpace", "FreeSpace2") // avoid name collision with Windows SDK's GetFreeSpace macro, this is specific to scrrun.dll

using namespace Scripting;

// sample usage of Scripting.Dictionary
void CreateDicAndAdd()
{
    IDictionaryPtr ptr(__uuidof(Dictionary)); // create an instance of the Dictionary coclass and get an IDictionary pointer back
    _variant_t foo = L"foo";
    _variant_t bar = L"bar";
    ptr->Add(&foo, &bar); // call the Add method

    wprintf(L"%i\n", ptr->Count); // call the Count property (wrapper that was generated automatically)

    _variant_t outBar;
    ptr->get_Item(&foo, &outBar); // get the item for "foo"

    // here we know it's a string (outBar.vt could tell you, in case you didn't know)
    // in fact, it's a BSTR, but a BSTR is also a LPWSTR
    // (the reverse is false, welcome to Automation :-)
    wprintf(L"%s\n", outBar.bstrVal);
}

// sample driver code.
int main()
{
    CoInitialize(NULL);
    CreateDicAndAdd();
    CoUninitialize();
    return 0;
}

What's cool is all these wrappers (_variant_t, IDictionaryPtr, etc.) are smart, meaning you don't have to explicitely release or dispose them. In the end, it's very similar to how you would program COM with higher level languages (VBScript, JScript, C#, etc.)