Creating COM Objects with the Class Moniker (CoGetObject)

Author

Pavel Yosifovich has 25+ years as Software developer, trainer, consultant, author, and speaker. Co-author of “Windows Internals”. Author of “Windows Kernel Programming”, “Windows 10 System Programming, as well as System and kernel programming courses and “Windows Internals” series.

If you’ve done COM programming on Windows, CoCreateInstance is the obvious starting point to create an object. Pass a CLSID, get an object back. Done. But it’s worth knowing what’s underneath that call — and what alternatives exist — because one of them is genuinely interesting: the class moniker.

The Standard Way: CoCreateInstance

CoCreateInstance is syntactic sugar. At the end of the day, it calls CoGetClassObject with your class ID, which returns an IClassFactory implementation. Then it calls CreateInstance on that factory.

This is fine in most cases, but it means there’s a direct path you can take yourself: get the class factory, call CreateInstance directly. CoGetClassObject gives you that factory. CoCreateInstance just wraps the two steps for convenience using the most common class factory interface (IClassFactory).

Why does this matter? Because there’s another way to get that class factory — one that doesn’t involve a direct CLSID at the call site.

What Is a COM Moniker?

A moniker in COM is an object that implements IMoniker and knows how to locate or bind to another COM object, based on a string. That’s the compact definition. The longer version is that IMoniker has a lot of methods — around 23, in fact — covering everything from string display names to composite chaining.

The key idea is this: instead of saying “create me an object with this class ID,” you say “here’s a string, find or create whatever object that string represents.” The moniker does the parsing and binding work. More indirect, but more flexible.

Windows ships with several built-in moniker implementations. The class moniker is one of them, and it’s the simplest to demonstrate.

The Class Moniker and CoGetObject

The high-level way to use the class moniker is CoGetObject. It looks like this:

CComPtr cf;
CoGetObject(L"clsid:9BA05972-F6A8-11CF-A442-00A0C90A8F39", nullptr, IID_PPV_ARGS(&cf));

The clsid: part is the moniker name prefix. CoGetObject looks that up in the registry under HKCR\CLSID, finds a subkey literally named CLSID, reads the class ID stored there — which points to the class moniker implementation in combase.dll — and instantiates it. The class moniker then parses the CLSID out of the string and, when asked to bind, returns the class factory for that CLSID.

The result: you have an IClassFactory. Call CreateInstance on it the same way you would after CoGetClassObject. The object you get back is the same as what CoCreateInstance would return. Same implementation, same interface pointer.

One practical note: if the class is a singleton — like IShellWindows, which represents something global in the process — you will get the same pointer each time you call CreateInstance. That’s not a moniker artifact. That’s just how that class factory is implemented. But it’s worth knowing.

Why Use This?

A few reasons, depending on your scenario.

The straightforward one is generality. Instead of baking a CLSID into your code, you can store a moniker string in a config file or database, load it at runtime, and use CoGetObject to create the corresponding object. The creation code stays the same regardless of which class you’re targeting.

The less obvious one — and I’ll say it plainly: CoGetObject with a moniker string is less conspicuous than a direct CoCreateInstance call. If you’re thinking about what detection looks like, that matters. CoCreateInstance on a known suspicious CLSID is a straightforward indicator. A string passed to CoGetObject requires more analysis to trace back to the same class. That’s not a reason to use it maliciously — it’s a reason to understand it, because you will see it in code you analyze.

Windows master developer badge 1

$2,111

$1,478 or $150 X 10 payments

Windows Master Developer

Takes you from a “generic” C programmer to a master Windows programmer in user mode and kernel mode.

The Full Manual Path

CoGetObject is a convenience wrapper. Behind the scenes, it calls MkParseDisplayName. Doing it manually gives you more control and makes the mechanism visible.

The sequence looks like this:

IBindCtx* pbc = nullptr;
CreateBindCtx(0, &pbc);

ULONG chEaten = 0;
CComPtr moniker;
MkParseDisplayName(pbc, L"clsid:9BA05972-F6A8-11CF-A442-00A0C90A8F39", &chEaten, &moniker);

CComPtr cf;
moniker->BindToObject(pbc, nullptr, IID_PPV_ARGS(&cf));

MkParseDisplayName takes a string and returns an IMoniker. The chEaten parameter is how many characters were consumed during parsing — useful if you are chaining monikers, which you can do using an exclamation mark as a separator between moniker strings. The bind context is required; passing null is technically invalid. CreateBindCtx gives you a default one with no special properties, which is all you need here.

BindToObject is where the actual binding happens. The second parameter is for the “left moniker” in a chain — another IMoniker that provides additional context when monikers are composed together. In this case, null, because there is no chain.

That’s the whole thing. The result is the same IClassFactory you would get from CoGetClassObject or CoGetObject.

Registry Internals: How clsid: Gets Resolved

When MkParseDisplayName sees clsid:, it looks in HKCR\CLSID for a subkey literally named CLSID. The default value of that key is a class ID. MkParseDisplayName instantiates that class — which turns out to be the class moniker, listed as Class Moniker in the registry and implemented in combase.dll.

This is the general pattern for all named monikers. If you register a key named “process” under HKCR\CLSID, pointing to a class ID that implements IMoniker, then “process:1234" becomes a valid moniker string. Your IMoniker::BindToObject receives 1234 and can do whatever makes sense with it — open a process handle, look up an object by process ID, whatever the moniker contract requires.

That’s the extension mechanism. Writing a custom IMoniker implementation is something I’m cosidering for a future video.

What’s Next

If you want to go deeper on COM programming in the meantime, the full courses are at TrainSec: COM Programming 1 covers the foundations, and COM Programming 2 goes into more advanced patterns. Both are taught with working C++ code and real system examples.


blue depth

About the author

Pavel Yosifovich has 25+ years as Software developer, trainer, consultant, author, and speaker. Co-author of “Windows Internals”. Author of “Windows Kernel Programming”, “Windows 10 System Programming, as well as System and kernel programming courses and “Windows Internals” series.
Even more articles from the free knowledge library
Writing a Simple Key Logger

In this video, Pavel walks through how to implement a basic keylogger in Windows using GetKeyState, handling character normalization (Shift,

Read More