[Previous] [Contents] [Next]

The New Moniker

The class moniker is powerful because it affords the programmer a way of dealing with coclasses using monikers. As we saw, one limitation of the class moniker is that it does not obey the parameters specified by the BIND_OPTS(2) structures. So to instantiate a coclass on a remote machine using the class moniker, we had to create a custom moniker (the marvelous moniker) that implemented the IClassActivator interface and called CoGetClassObject itself. Another peculiarity of the class moniker is that it always binds to the class object of the specified coclass, leaving the client to instantiate the object using IClassFactory::CreateInstance or whatever custom activation interface that class object happens to implement. Since the CreateInstance method cannot be called directly from Visual Basic, this means that Visual Basic developers cannot use the class moniker to instantiate a coclass whose class object implements the IClassFactory interface.

The new moniker was introduced to address many these issues. Rather than binding to the class object of the specified coclass, the new moniker operates more like the CoCreateInstance(Ex) function. After obtaining the class object, the new moniker automatically calls IClassFactory::CreateInstance to instantiate the desired coclass. This means that like the CoCreateInstance(Ex) function, the new moniker requires that the class object implement the IClassFactory interface; it cannot be used with custom activation interfaces such as IPrimeFactory. Unlike the class moniker, however, the new moniker obeys the parameters specified in the BIND_OPTS(2) structures. Therefore, you can use the new moniker to instantiate an object on a remote machine, as shown in the code fragment below:

COSERVERINFO csi = { 0, 0, 0, 0 };
csi.pwszName = L"RemoteMachineName";

BIND_OPTS2 bopts;
bopts.dwClassContext = CLSCTX_LOCAL_SERVER;
bopts.cbStruct = sizeof(BIND_OPTS2);
bopts.pServerInfo = &csi;

ISum* pSum = 0;
hr = CoGetObject(L"new:10000002-0000-0000-0000-000000000001", 
    &bopts, IID_ISum, (void**)&pSum);

// Now we can use the object--the new moniker has already 
// instantiated it.
int sum = 0;
hr = pSum->Sum(4, 9, &sum);
cout << "Client: Calling Sum() return value is " << sum << endl;

pSum->Release();

As a convenience, the new moniker also accepts ProgIDs in place of CLSIDs. For example, instead of specifying the CLSID of the InsideCOM coclass, you can simply use the ProgID Component.InsideCOM, as shown below:

hr = CoGetObject(L"new:Component.InsideCOM", &bopts, IID_ISum, 
    (void**)&pSum);

Because the new moniker automatically instantiates the coclass using the IClassFactory::CreateInstance method, you can easily use this moniker from Visual Basic with any standard class object that implements the IClassFactory interface, as shown below. Unfortunately, a Visual Basic client does not have the opportunity to set the BIND_OPTS(2) structure, so the new moniker can be used only for default activation based on registry information.

Private Sub Command1_Click()
    Dim ref As Component.InsideCOM
    Set ref = GetObject("new:Component.InsideCOM")

    ' Or use the CLSID.
    ' Set ref = _
    '     GetObject("new:10000002-0000-0000-0000-000000000001") 

    Print ref.Sum(5, 3)
End Sub