STDMETHODIMP MyClassObject::CreateInstance(IUnknown *puo, REFIID riid, void **ppv) {
LockModule();
// ensure we don't shut down while in call
// убеждаемся в том, что не прекращаем работу
// во время вызова
HRESULT hr; *ppv = 0;
// shutdown initiated?
// процесс останова запущен?
DWORD dw = WaitForSingleObject(g_heventShutdown, 0);
if (dw == WAIT_OBJECT_0) hr = CO_E_SERVER_STOPPING;
else {
// normal CreateInstance implementation
// нормальная реализация CreateInstance
}
UnlockModule();
return hr;
}
Во время написания этого текста ни одна из коммерческих библиотек классов COM не реализовывала этот способ.
Снова о времени жизни сервера
В примере, показанном в предыдущем разделе, не было точно показано, как и когда должен прекратить работу серверный процесс. В общем случае серверный процесс сам контролирует свое время жизни и может прекратить работу в любой выбранный им момент. Хотя для серверного процесса и допустимо неограниченное время работы, большинство из них предпочитают выключаться, когда не осталось неосвобожденных ссылок на их объекты или объекты класса. Это аналогично стратегии, используемой большинством внутрипроцессных серверов в их реализации
// reasons to remain loaded
// причины оставаться загруженными
LONG g_cLocks = 0;
// called from AddRef + IClassFactory::LockServer(TRUE)
// вызвано из AddRef + IClassFactory::LockServer(TRUE)
void LockModule(void) {
InterlockedIncrement(&g_cLocks);
}
// called from Release + IClassFactory::LockServer(FALSE)
// вызвано из Release + IClassFactory::LockServer(FALSE)
void UnlockModule(void) { InterlockedDecrement(&g_cLocks);
}
Это сделало реализацию
STDAPI DllCanUnloadNow()
{
return g_cLocks ? S_FALSE : S_OK;
}
Подпрограмму
Имеются некоторые различия в том, как ЕХЕ-серверы прекращают работу серверов. Во-первых, обязанностью серверного процесса является упреждающее инициирование процесса своего выключения. В отличие от внутрипроцессных серверов, здесь не существует «сборщика мусора», который запросил бы внепроцессный сервер, желает ли он прекратить работу. Вместо этого серверный процесс должен в подходящий момент явно запустить процесс своего выключения. Если для выключения сервера используется событие Win32 Event, то процесс должен вызвать API-функцию
void UnlockModule(void) {
if (InterlockedDecrement(&g_cLocks) ==0) {
extern HANDLE g_heventShutdown;
SetEvent(g_heventShutdown);
}
}
Если вместо серверного основного потока обслуживается очередь событий
void UnlockModule(void) {
if (InterlockedDecrement(&g_cLocks) == 0) {
extern DWORD g_dwMainThreadID;
// set from main thread