, , , . . , , . , 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 // , " " }
, .
, , , . . , , . 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 .