When you start ObjectUser, you'll see (after COM is initialized) a small window with a single menu. With the menu items on this menu you can do the following:
When you select the Create (CoGetClassObject) menu item, you end up in the IDM_OBJECTCREATECOGCO case of ObjectUserWndProc in OBJUSER.CPP. This selection provokes the execution of the following code (pApp is a pointer to the ObjectUser application structure that maintains variables such as m_pIUnknown, a pointer to the last Koala object created):
HRESULT hr;
LPCLASSFACTORY pIClassFactory;
DWORD dwClsCtx;
[Other code omitted]
case IDM_OBJECTCREATECOGCO:
if (NULL!=pApp->m_pIUnknown)
{
while (pApp->m_cRefOurs--)
ReleaseInterface(pApp->m_pIUnknown);
CoFreeUnusedLibraries();
}
dwClsCtx=(pApp->m_fEXE) ? CLSCTX_LOCAL_SERVER
: CLSCTX_INPROC_SERVER;
hr=CoGetClassObject(CLSID_Koala, dwClsCtx, NULL
, IID_IClassFactory, (PPVOID)&pIClassFactory);
if (SUCCEEDED(hr))
{
hr=pIClassFactory->CreateInstance(NULL
, IID_IUnknown, (PPVOID)&pApp->m_pIUnknown);
pIClassFactory->Release();
if (SUCCEEDED(hr))
{
pApp->Message(TEXT("Creation succeeded."));
pApp->m_cRefOurs=1;
}
else
pApp->Message(TEXT("Creation failed."));
}
else
pApp->Message(TEXT("CoGetClassObject failed."));
break;
The Create (CoCreateInstance) menu command does exactly the same thing in a more concise manner because we're creating only one instance of the object:
case IDM_OBJECTCREATECOCI:
if (NULL!=pApp->m_pIUnknown)
{
while (pApp->m_cRefOurs--)
ReleaseInterface(pApp->m_pIUnknown);
CoFreeUnusedLibraries();
}
//Simpler creation: use CoCreateInstance.
dwClsCtx=(pApp->m_fEXE) ? CLSCTX_LOCAL_SERVER
: CLSCTX_INPROC_SERVER;
hr=CoCreateInstance(CLSID_Koala, NULL, dwClsCtx
, IID_IUnknown, (PPVOID)&pApp->m_pIUnknown);
if (SUCCEEDED(hr))
{
pApp->Message(TEXT("Creation succeeded."));
pApp->m_cRefOurs=1;
}
else
pApp->Message(TEXT("Creation failed."));
break;
The two sequences of code produce exactly the same result: an IUnknown pointer to the new Koala instance. If an instance is already available, we first call m_pIUnknown->Release as many times as needed to free the object (through the ReleaseInterface macro in INC\INOLE.H) and then call CoFreeUnusedLibraries. This latter call allows you to watch what happens in the DKoala1 server's implementation of DllCanUnloadNow.
ObjectUser maintains in the variable pApp->m_cRefOurs a count of how many references it thinks it owns on the object. The counter is initially 0 but is set to 1 after creating an instance. ObjectUser's AddRef and Release menu items either increment or decrement this counter, after which ObjectUser displays the reference count returned from the object's function next to its own counter.
When you run ObjectUser with the DLL server option, you'll see that the object's reference count and ObjectUser's internal count are equal. But when you use the EXE server, you'll see something strange: the value returned by any call to AddRef might be something huge like 1336120 and remain that way no matter how many AddRef calls you make. In the same manner, this number is also returned from Release as long as the actual reference count is nonzero. Why is this? The specification for IUnknown::Release (described in Chapter 2) explicitly states that the client cannot attach any meaning to a nonzero return value. In addition, the client cannot really attach much meaning to a zero return value except for knowing that its own responsibility for the object is complete. In no way does the return value tell you whether the object has actually been destroyed—at most it tells you that the in-process proxy object has been destroyed and that you can no longer access the local or remote object to which you were connected. That object, however, could easily remain running if other clients are accessing it as well.
To prevent clients from reading too much into the return value from AddRef and Release, proxy objects generally return some large constant unless the proxy is destroyed, in which case Release returns 0. Of course, because proxy objects are not used with in-process servers such as DKoala1, a client will generally get back the actual object reference count. In any case, clients can't do very much with the information.