, , ÷ , . ÷ . ÷ , ø ÷ ÷, . ÷ , ø DllCanUnloadNow . , ÷ 3 , ÷ ÷ , ÷ , ø ø :
// 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); }
DllCanUnloadNow :
STDAPI DllCanUnloadNow() { return g_cLocks ? S_FALSE : S_OK; }
DllCanUnloadNow ÷, ø " " CoFreeUnusedLibraries .
÷ , - . - , ÷. ÷ , " ", , . ÷. ÷ Win32 Event, API- SetEvent :
void UnlockModule(void)
{
if (InterlockedDecrement(&g_cLocks) ==0) {
extern HANDLE g_heventShutdown;
SetEvent(g_heventShutdown);
}
}
÷ Windows MSG , API-. PostThreadMessage ÷ WM_QUIT :
void UnlockModule(void)
{
if (InterlockedDecrement(&g_cLocks) == 0) {
extern DWORD g_dwMainThreadID;
// set from main thread
// установлено из основного потока
PostThreadMessage(g_dwMainThreadID, WNLQUIT, О, 0);
}
}
STA , ÷ , API- PostQuitMessage :
void UnlockModule(void)
{
if (InterlockedDecrement(&g_cLocks) == 0)
PostQuitMessage(0);
}
.
÷ , ÷ . ÷ IClassFactory::LockServer(TRUE) . .
, , ø . :
STDMETHODIMP_(ULONG) MyClassObject::AddRef(void) {
LockModule();
// note outstanding reference
// отмечаем неосвобожденную ссылку
return 2;
// non-heap-based object
// объект, размещенный не в "куче"
}
STDMETHODIMP_(ULONG) MyClassObject::Release(void) {
UnlockModule();
// note destroyed reference
// отмечаем уничтоженную ссылку
return 1;
// non-heap-based object
// объект, размещенный не в "куче"
}
, DLL , ø , Release .
, ø AddRef Release . , ÷ COM , ÷ ÷ , - COM CoRegisterClassObject . , , ø COM . ÷, ÷ ÷÷ ÷ . ( self-imposed ) CoRevokeClassObject . , ÷ CoRevokeClassObject , ÷÷ , ÷ ÷, ÷ .
× ÷ ø , ø AddRef Release :
STDMETHODIMP_(ULONG) MyClassObject::AddRef(void) {
// ignore outstanding reference
// игнорируем неосвобожденную ссылку
return 2;
// non-heap-based object
// объект, размещенный не в "куче"
}
STDMETHODIMP_(ULONG) MyClassObject::Release(void) {
// ignore destroyed reference
// игнорируем уничтоженную ссылку
return 1;
// non-heap-based object
//объект, размещенный не в "куче"
}
÷, ÷ ÷÷ .
{% if main.adsdop %}{% include 'adsenceinline.tpl' %}{% endif %}÷, ÷ , , ÷ . ÷ . , ÷ , ø . ø AddRef Release , COM . ø ø , SCM . CoMarshalInterface . IExternalConnection , , ÷ ø , . , ÷ IExternalConnection , o :
STDMETHODIMP_(DWORD) MyClassObject::AddConnection(DWORD extconn, DWORD)
{
DWORD res = 0;
if (extconn & EXTCONN_STRONG) {
LockModule();
// note external reference
// записываем внешнюю ссылку
res = InterlockedIncrement(&m_cExtRef);
}
return res;
}
STDMETHODIMP_(DWORD) MyClassObject::ReleaseConnection(DWORD extconn, DWORD,
BOOL bLastReleaseKillsStub)
{
DWORD res = 0;
if (extconn & EXTCONN_STRONG) {
UnlockModule();
// note external reference
// записываем внешнюю ссылку
res = InterlockedDecrement(&m_cExtRef);
if (res == 0 & bLastReleaseKillsStub)
CoDisconnectObject((IExternalConnection*)this, 0);
}
return res;
}
, ÷ ÷÷ , ø , , COM, .
IExternalConnection COM , ø ÷ . ø ÷ ø ø . LockServer IClassFactory , ø ÷ , ÷ ÷ . ø ÷ ø LockServer , . :
IClassFactory *pcf = 0;
HRESULT hr = CoGetClassObject(CLSID_You, CLSCTX_LOCAL_SERVER,
О, IID_IClassFactory, (void**)&pcf);
if (SUCCEEDED(hr))
hr = pcf->LockServer(TRUE);
// keep server running?
// поддерживать выполнение сервера?
COM . , ÷ CoGetClassObject IClassFactory::LockServer . ÷ ÷ . , ø LockServer . ÷ :
IClassFactory *pcf = 0;
HRESULT hr = S_OK;
do {
if (pcf) pcf->Release();
hr = CoGetClassObject(CLSID_You, CLSCTX_LOCAL_SERVER,
0, IID_IClassFactory, (void**)&pcf);
if (FAILED(hr))
break;
hr = pcf->LockServer(TRUE);
// keep server running?
// поддерживать выполнение сервера?
} while (FAILED(hr));
, ÷ ÷ , LockServer ø. ø - CoGetClassObject LockServer , LockServer ø, , ÷ . Windows NT 3.51 ÷ .
, ÷ IExternalConnection , COM Windows NT 4.0 . ø CoGetClass0bject SCM IClassFactory::LockServer . ÷ ø IClassFactory , COM ÷ ÷ . IClassFactory COM, ÷ Windows NT 4.0, IExternalConnection .
, . , ÷ ø , , ÷ ÷ ( shutdown sequence ) . × CoRevokeClassObject . , , UnlockModule , . , ÷ , SetEvent PostThreadMessage , , , CoRevokeClassObject , . , , ÷ - ÷ . COM API-:
ULONG CoAddRefServerProcess(void); ULONG CoReleaseServerProcess(void);
÷÷ . COM, ÷ , ÷ ÷÷ . , CoReleaseServerProcess , ÷ , SCM, ÷ CLSID.
:
void LockModule(void)
{
CoAddRefServerProcess();
// COM maintains lock count
// COM устанавливает счетчик блокировок
}
void UnlockModule(void)
{
if (CoReleaseServerProcess() == 0)
SetEvent(g_heventShutdown);
}
, ÷ - . ø .
CoAddRefServerProcess / CoReleaseServerProcess . , ÷ CoReleaseServerProcess RPC ÷ SCM. SCM ÷ , CoReleaseServerProcess COM, , ÷ ÷ , SCM ø ÷ ( CO_E_SERVER_STOPPING ). SCM ÷ , , . , COM, , ÷ ÷ CoReleaseServerProcess . × , CO_E_SERVER_STOPPING IClassFactory::Create Instance , IPersistFile::Load ÷, , ÷ ÷ - . :
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 .