Unloading .EXE Servers
A server application is responsible for unloading itself, simply by terminating and exiting its main entry function,8. when the shutdown conditions are met, including whether or not the user has control. In the ongoing example of this chapter, this would involve detecting the proper shutdown conditions whenever an object is destroyed (in the suggested ObjectDestroyed function) or whenever the last lock is removed (in IClassFactory::LockServer).
//User control flag
BOOL g_fUser=FALSE;
void ObjectDestroyed(void) {
g_cObj--;
if (0L==g_cObj && 0L==g_cLock && !g_fUser)
//Begin shutdown
return;
}
HRESULT CTextRenderFactory::LockServer(BOOL fLock) {
if (fLock)
g_cLock++; // for single threaded app only, of course
else {
g_cLock--;
if (0L==g_cObj && 0L==g_cLock && !g_fUser)
//Begin shutdown
}
return NOERROR;
}
If desired, you can of course centralize the shutdown conditions by artificially incrementing the object count in IClassFactory::LockServer and directly calling ObjectDestroyed. That way you do not need redundant code in both functions.
During shutdown, the server is responsible for calling CoRevokeClassObject on all previously registered class factories and for calling CoUninitialize like any COM application.
A server application only needs a "user-control" flag if it becomes visible in some way and also allows the user to perform some action which would necessitate the application stays running regardless of any other conditions. For example, the server might be running to service an object for a client and the user opens another file in that same application. Since the user is the only agent who can close the file, the user control flag is set to TRUE meaning that the user must explicitly close the application: no automatic shutdown is possible.
If a server is visible and under user control, there is the possibility that clients have connections to objects within that server when the user explicitly closes the application. In that situation the server can take one of two actions:
- Simply hide the application and reset the user control flag to FALSE such that the server will automatically shut down when all objects and locks are released.
- Terminate the application but call CoDisconnectObject for each object in service to forcibly disconnect all clients.
The second option, though more brutal, is necessary in some situations. The CoDisconnectObject function exists to insure that all external reference counts to the server's objects are released such that the server can release its own references and destroy all objects.