IMoniker

A moniker is a system object that identifies a COM object. Win32 has several functions for creating them, see references.

A moniker is bound to its target in a binding context, an object that implements IBindCtx.

Basic Usage

Monikers usually work under the hood. CoGetObject is a convenience function that retrieves an object from its display name. It calls MkParseDisplayName to get the moniker, then IMoniker::BindToObject to get the underlying object. Here’s some pseudo code for that.

HRESULT __stdcall CoGetObject(LPCWSTR pszDisplayName, 
    BIND_OPTS* pBindOptions, REFIID riid, void** ppv)
{
    HRESULT hr = 0;

    // Create the bind context.
    IBindCtx* pBindCtx = 0;
    hr = CreateBindCtx(0&pBindCtx);

    // Call MkParseDisplayName with the user's string.
    ULONG chEaten;
    IMoniker* pMoniker = 0;
    hr = MkParseDisplayName(pBindCtx, pszDisplayName, 
        &chEaten, &pMoniker);

    // Set the bind options requested by the caller.
    hr = pBindCtx->SetBindOptions(pBindOptions);

    // Call IMoniker::BindToObject to get the user's object.
    hr = pMoniker->BindToObject(pBindCtx, NULL, riid, ppv);

    // Release stuff.
    pMoniker->Release();
    pBindCtx->Release();

    return hr;
}

Class Moniker

One use case of monikers is when you want to create an object with ‘constructor’ arguments. Internally, CoCreateInstance is a thin wrapper that calls CoGetClassObject, passing in the IID of the default IClassFactory, which does not support arguments.

We can work around this in C++ by calling CoGetClassObject directly and passing in the IID of a custom class factory:

interface IPrimeFactory : IUnknown
{
    HRESULT CreatePrime([in] int starting_prime, [out, retval]IPrime** ppPrime);
};
IPrimeFactory* pPrimeFactory;
CoGetClassObject(CLSID_Prime, CLSCTX_SERVER, NULL, IID_IPrimeFactory, (void**)&pPrimeFactory);
IPrime* pPrime;
pPrimeFactory->CreatePrime(7&pPrime);
pPrimeFactory->Release();

But to get to the factory interface from a scripting language, a moniker is needed. First the C++:

// We always need a bind context.
IBindCtx* pBindCtx;
CreateBindCtx(0&pBindCtx);

// Convert the string to a moniker.
ULONG eaten;
IMoniker* pMoniker;
OLECHAR string[] = 
    L"clsid:10000013-0000-0000-0000-000000000001";
MkParseDisplayName(pBindCtx, string, &eaten, &pMoniker);

 // Bind the moniker to the named object.
IPrimeFactory* pPrimeFactory;
pMoniker->BindToObject(pBindCtx, NULL, IID_IPrimeFactory, 
    (void**)&pPrimeFactory);

// Use the custom class object to create a Prime object.
IPrime* pPrime;
pPrimeFactory->CreatePrime(7&pPrime);

// Now we have a Prime object.
int next_prime;
pPrime->GetNextPrime(&next_prime);
cout << next_prime << endl; // Displays 11

// Release all.
pPrimeFactory->Release();
pPrime->Release();
pBindCtx->Release();
pMoniker->Release();

The corresponding script looks something like this:

Dim myPrimeFactory As IPrimeFactory
Dim myPrime As IPrime

' Call MkParseDisplayName and IMoniker::BindToObject.
Set myPrimeFactory = _
    GetObject("clsid:10000013-0000-0000-0000-000000000001")

' Call IPrimeFactory::CreatePrime.
Set myPrime = myPrimeFactory.CreatePrime(7)

' Call IPrime::GetNextPrime.
Print myPrime.GetNextPrime      ' Displays 11

References