|
|
//-----------------------------------------------------------------------------
//
//
// File:
// aqueue.cpp
// Description:
// Implementation of DLL Exports.
// Author: Mike Swafford (MikeSwa)
//
// History:
//
// Copyright (C) 1998 Microsoft Corporation
//
//-----------------------------------------------------------------------------
#include "aqprecmp.h"
#ifndef PLATINUM
#include "initguid.h"
#include <iadmw.h>
#endif //PLATINUM
#include "aqueue_i.c"
#include "aqintrnl_i.c"
#include "SMTPConn.h"
#include "qwiklist.h"
#include "fifoqimp.h"
#include <irtlmisc.h>
#include <iiscnfg.h>
#include <wrapmb.h>
#include <smtpinet.h>
#include <cat.h>
#include <aqinit.h>
#include "aqrpcsvr.h"
//Global vars used for shutdown
DWORD g_cInstances = 0; CShareLockNH g_slInit; //lock used for thread-safe initialization
//Global vars used for Dll init/shutdown (including Cat COM stuff)
LONG g_cDllInit = 0; BOOL g_fInit = FALSE; CShareLockNH g_slDllInit; BOOL g_fForceDllCanUnloadNowFailure = FALSE;
#define CALL_SERVICE_STATUS_CALLBACK \
pServiceStatusFn ? pServiceStatusFn(pvServiceContext) : 0
// SEO crap needed for aqdisp
#define _ATL_NO_DEBUG_CRT
#define _ASSERTE _ASSERT
#define _WINDLL
#include "atlbase.h"
extern CComModule _Module; #include "atlcom.h"
#undef _WINDLL
CComModule _Module; BEGIN_OBJECT_MAP(ObjectMap) END_OBJECT_MAP() #include <pudebug.h>
DEBUG_PRINTS *g_pDebug = NULL;
//---[ HrAdvQueueInitializeEx ]-------------------------------------------------
//
//
// Description:
// Aqueue.dll initialization function that provides in params for user name,
// domain, password, and service control callback functions.
// Parameters:
// IN pISMTPServer ptr to local delivery function / object
// IN dwServerInstance virtual server instance
// IN szUserName User name to log on DS with
// IN szDomainName Domain name to log on to DS with
// IN szPassword Password to authenticate to DS with
// IN pServiceStatusFn Server status callback function
// IN pvServiceContext Context to pass back for callback function
// OUT ppIAdvQueue returned IAdvQueue ptr
// OUT ppIConnectionManager returned IConnectionManager ptr
// OUT ppIAdvQueueConfig returned IAdvQueueConfig ptr
// OUT ppvContext Virtual server context
// Returns:
//
//
//-----------------------------------------------------------------------------
HRESULT HrAdvQueueInitializeEx( IN ISMTPServer *pISMTPServer, IN DWORD dwServerInstance, IN LPSTR szUserName, IN LPSTR szDomainName, IN LPSTR szPassword, IN PSRVFN pServiceStatusFn, IN PVOID pvServiceContext, OUT IAdvQueue **ppIAdvQueue, OUT IConnectionManager **ppIConnectionManager, OUT IAdvQueueConfig **ppIAdvQueueConfig, OUT PVOID *ppvContext) { TraceFunctEnterEx((LPARAM) NULL, "HrAdvQueueInitialize"); HRESULT hr = S_OK; CAQSvrInst *paqinst = NULL; CDomainMappingTable *pdmt = NULL; BOOL fLocked = FALSE; BOOL fInstanceCounted = FALSE;
#ifdef PLATINUM
BOOL fIisRtlInit = FALSE; BOOL fATQInit = FALSE; #endif
BOOL fAQDllInit = FALSE; BOOL fExchmemInit = FALSE; BOOL fCPoolInit = FALSE; BOOL fRpcInit = FALSE; BOOL fDSNInit = FALSE;
CALL_SERVICE_STATUS_CALLBACK; g_slInit.ExclusiveLock(); fLocked = TRUE;
if ((NULL == ppIAdvQueue) || (NULL == ppIConnectionManager) || (NULL == ppvContext) || (NULL == ppIAdvQueueConfig)) { hr = E_INVALIDARG; goto Exit; }
*ppvContext = NULL;
//
// Update global config information.
//
ReadGlobalRegistryConfiguration();
if (1 == InterlockedIncrement((PLONG) &g_cInstances)) { fInstanceCounted = TRUE; CALL_SERVICE_STATUS_CALLBACK;
#ifdef PLATINUM
//Initialize IISRTL
if (!InitializeIISRTL()) { hr = HRESULT_FROM_WIN32(GetLastError()); ErrorTrace((LPARAM) NULL, "ERROR: LISRTL Init failed with 0x%08X", hr); if (SUCCEEDED(hr)) hr = E_FAIL; goto Exit; } fIisRtlInit = TRUE;
//Initialize ATQ
if (!AtqInitialize(0)) { hr = HRESULT_FROM_WIN32(GetLastError()); ErrorTrace((LPARAM) NULL, "ERROR: ATQ Init failed with 0x%08X", hr); if (SUCCEEDED(hr)) hr = E_FAIL; goto Exit; } fATQInit = TRUE; #endif
hr = HrDllInitialize(); if (FAILED(hr)) { goto Exit; } fAQDllInit = TRUE;
//create CPool objects
if (!CQuickList::s_QuickListPool.ReserveMemory(10000, sizeof(CQuickList))) hr = E_OUTOFMEMORY;
if (!CSMTPConn::s_SMTPConnPool.ReserveMemory(g_cMaxConnections, sizeof(CSMTPConn))) hr = E_OUTOFMEMORY;
if (!CMsgRef::s_MsgRefPool.ReserveMemory(g_cMaxMsgObjects, MSGREF_STANDARD_CPOOL_SIZE)) hr = E_OUTOFMEMORY;
if (!CAQMsgGuidListEntry::s_MsgGuidListEntryPool.ReserveMemory(500, sizeof(CAQMsgGuidListEntry))) hr = E_OUTOFMEMORY;
if (!CAsyncWorkQueueItem::s_CAsyncWorkQueueItemPool.ReserveMemory(20000, sizeof(CAsyncWorkQueueItemAllocatorBlock))) hr = E_OUTOFMEMORY;
if (!CAddr::Pool.ReserveMemory(1000, sizeof(CAddr))) hr = E_OUTOFMEMORY;
if (!CAQSvrInst::CAQLocalDeliveryNotify::s_pool.ReserveMemory(g_cMaxPendingLocal, sizeof(CAQSvrInst::CAQLocalDeliveryNotify))) hr = E_OUTOFMEMORY;
if (!CBlockMemoryAccess::m_Pool.ReserveMemory(2000, sizeof(BLOCK_HEAP_NODE))) hr = E_OUTOFMEMORY;
if (FAILED(hr)) { ErrorTrace((LPARAM) NULL, "Error unable to initialize CPOOL"); goto Exit; }
fCPoolInit = TRUE;
hr = CDSNGenerator::HrStaticInit(); if(FAILED(hr)) { ErrorTrace((LPARAM) NULL, "CDSNGenerator::StaticInif failed hr %08lx", hr); goto Exit; } fDSNInit = TRUE;
//Initialize Queue Admin RPC interface
hr = CAQRpcSvrInst::HrInitializeAQRpc(); if (FAILED(hr)) goto Exit;
fRpcInit = TRUE;
}
if (!g_pslGlobals) { g_pslGlobals = new CShareLockNH(); if (NULL == g_pslGlobals) { hr = E_OUTOFMEMORY; goto Exit; } }
CALL_SERVICE_STATUS_CALLBACK; g_slInit.ExclusiveUnlock(); fLocked = FALSE;
CFifoQueue<CLinkMsgQueue *>::StaticInit(); CFifoQueue<CMsgRef *>::StaticInit(); CFifoQueue<IMailMsgProperties *>::StaticInit(); CFifoQueue<CAsyncWorkQueueItem *>::StaticInit();
//Create requested objects
CALL_SERVICE_STATUS_CALLBACK; paqinst = new CAQSvrInst(dwServerInstance, pISMTPServer); if (NULL == paqinst) { hr = E_OUTOFMEMORY; goto Exit; }
CALL_SERVICE_STATUS_CALLBACK; hr = paqinst->HrInitialize(szUserName, szDomainName, szPassword, pServiceStatusFn, pvServiceContext); if (FAILED(hr)) goto Exit;
//Create Connection Manager
CALL_SERVICE_STATUS_CALLBACK; hr = paqinst->HrGetIConnectionManager(ppIConnectionManager);
//Set Return values
*ppIAdvQueue = (IAdvQueue *) paqinst; //Already addref'd at creation
*ppIAdvQueueConfig = (IAdvQueueConfig *) paqinst; (*ppIAdvQueueConfig)->AddRef();
Exit: if (FAILED(hr)) { //Make sure that we clean up everything here
if (NULL != paqinst) paqinst->Release();
//If initialization failed... we should not count an
//instance as started
if (fInstanceCounted) InterlockedDecrement((PLONG) &g_cInstances);
#ifdef PLATINUM
if (fATQInit) AtqTerminate();
if (fIisRtlInit) TerminateIISRTL(); #endif
if (fAQDllInit) DllDeinitialize();
if (fCPoolInit) { //Release CPool objects
CAQSvrInst::CAQLocalDeliveryNotify::s_pool.ReleaseMemory(); CAddr::Pool.ReleaseMemory(); CQuickList::s_QuickListPool.ReleaseMemory(); CSMTPConn::s_SMTPConnPool.ReleaseMemory(); CMsgRef::s_MsgRefPool.ReleaseMemory(); CAQMsgGuidListEntry::s_MsgGuidListEntryPool.ReleaseMemory(); CAsyncWorkQueueItem::s_CAsyncWorkQueueItemPool.ReleaseMemory(); CBlockMemoryAccess::m_Pool.ReleaseMemory(); }
if (fDSNInit) CDSNGenerator::StaticDeinit();
if (fRpcInit) CAQRpcSvrInst::HrDeinitializeAQRpc(); } else { *ppvContext = (PVOID) paqinst; paqinst->AddRef(); }
if (fLocked) g_slInit.ExclusiveUnlock();
TraceFunctLeave(); return hr; }
//---[ HrAdvQueueInitialize ]---------------------------------------------------
//
//
// Description:
// Performs DLL-wide initialization
//
// Parameters:
// IN pISMTPServer ptr to local delivery function / object
// IN dwServerInstance virtual server instance
// OUT ppIAdvQueue returned IAdvQueue ptr
// OUT ppIConnectionManager returned IConnectionManager ptr
// OUT ppIAdvQueueConfig returned IAdvQueueConfig ptr
// OUT ppvContext Virtual server context
// Returns:
// S_OK on success
//
//-----------------------------------------------------------------------------
HRESULT HrAdvQueueInitialize( IN ISMTPServer *pISMTPServer, IN DWORD dwServerInstance, OUT IAdvQueue **ppIAdvQueue, OUT IConnectionManager **ppIConnectionManager, OUT IAdvQueueConfig **ppIAdvQueueConfig, OUT PVOID *ppvContext) { HRESULT hr = S_OK;
hr = HrAdvQueueInitializeEx(pISMTPServer, dwServerInstance, NULL, NULL, NULL, NULL, NULL, ppIAdvQueue, ppIConnectionManager, ppIAdvQueueConfig, ppvContext); return hr; }
//---[ HrAdvQueueDeinitializeEx ]------------------------------------------------
//
//
// Description:
// Performs DLL-wide Cleanup.
//
// Adds callback to service control manager.
//
// This MUST not be called until all DLL objects have been released.
//
// NOTE: There are several objects that are exported outside this DLL.
// The following are directly exported & should be released before the
// the Heap and CPool allocations are freed
// IAdvQueue
// IConnectionManager
// ISMTPConnection
// The Message Context also contains several references to internal objects,
// but does not need to be explicitly released (since these objects can only
// be accessed though the AckMessage() call).
// Parameters:
// PVOID pvContext Context that was returned by initialization
// function
// IN pServiceStatusFn Server status callback function
// IN pvServiceContext Context to pass back for callback function
// Returns:
// S_OK on success
//
//-----------------------------------------------------------------------------
HRESULT HrAdvQueueDeinitializeEx(IN PVOID pvContext, IN PSRVFN pServiceStatusFn, IN PVOID pvServiceContext) { TraceFunctEnterEx((LPARAM) NULL, "HrAdvQueueDeinitialize"); HRESULT hr = S_OK; HRESULT hrCurrent = S_OK; DWORD cRefs; DWORD dwWaitResult = WAIT_OBJECT_0; bool fDestroyHeap = true; DWORD dwShutdownTimeout = 0; //time to wait for shutdown
CAQSvrInst *paqinst; g_fForceDllCanUnloadNowFailure = TRUE; g_slInit.ExclusiveLock();
if (NULL != pvContext) { paqinst = (CAQSvrInst *) pvContext; hr = paqinst->HrDeinitialize();
cRefs = paqinst->Release(); DebugTrace((LPARAM) NULL, "There are %d refs remaining on the CMQ", cRefs); if (0 != cRefs) { _ASSERT(0 && "Someone has outstanding references to IAdvQueue or IAdvQueuConfig"); fDestroyHeap = false; } }
CFifoQueue<CLinkMsgQueue *>::StaticDeinit(); CFifoQueue<CMsgRef *>::StaticDeinit(); CFifoQueue<IMailMsgProperties *>::StaticDeinit(); CFifoQueue<CAsyncWorkQueueItem *>::StaticDeinit();
if (0 == InterlockedDecrement((PLONG) &g_cInstances)) { #ifdef PLATINUM
AtqTerminate(); #endif
if (fDestroyHeap) { delete g_pslGlobals; g_pslGlobals = NULL;
DllDeinitialize();
//Release CPool objects
CAQSvrInst::CAQLocalDeliveryNotify::s_pool.ReleaseMemory(); CAddr::Pool.ReleaseMemory(); CQuickList::s_QuickListPool.ReleaseMemory(); CSMTPConn::s_SMTPConnPool.ReleaseMemory(); CMsgRef::s_MsgRefPool.ReleaseMemory(); CAQMsgGuidListEntry::s_MsgGuidListEntryPool.ReleaseMemory(); CAsyncWorkQueueItem::s_CAsyncWorkQueueItemPool.ReleaseMemory(); CBlockMemoryAccess::m_Pool.ReleaseMemory(); } //
// Deinit DSN Generator
//
CDSNGenerator::StaticDeinit();
//Deinitialize Queue Admin RPC interface
hr = CAQRpcSvrInst::HrDeinitializeAQRpc();
#ifdef PLATINUM
TerminateIISRTL(); #endif
//Force mailmsg and other COM DLLs to go buh-bye
CoFreeUnusedLibraries(); }
g_slInit.ExclusiveUnlock(); TraceFunctLeave(); g_fForceDllCanUnloadNowFailure = FALSE; return hr; }
//---[ HrAdvQueueDeinitialize ]------------------------------------------------
//
//
// Description:
// Performs DLL-wide Cleanup.
//
// This MUST not be called until all DLL objects have been released.
//
// NOTE: There are several objects that are exported outside this DLL.
// The following are directly exported & should be released before the
// the Heap and CPool allocations are freed
// IAdvQueue
// IConnectionManager
// ISMTPConnection
// The Message Context also contains several references to internal objects,
// but does not need to be explicitly released (since these objects can only
// be accessed though the AckMessage() call).
// Parameters:
// PVOID pvContext Context that was returned by initialization
// function
// Returns:
// S_OK on success
//
//-----------------------------------------------------------------------------
HRESULT HrAdvQueueDeinitialize(PVOID pvContext) { return HrAdvQueueDeinitializeEx(pvContext, NULL, NULL); }
//---[ HrRegisterAdvQueueDll ]-------------------------------------------------
//
//
// Description:
// Sets metabase path of for advanced queuing DLL to this DLL.
// Parameters:
// hAQInstance - Handle passed into DLL main
// Returns:
// S_OK on success
// E_INVALIDARG if hAQInstance is NULL.
// Error codes from accessed metabase
// History:
// 7/30/99 - MikeSwa Created
//
//-----------------------------------------------------------------------------
HRESULT HrRegisterAdvQueueDll(HMODULE hAQInstance) { HRESULT hr = S_OK; WCHAR wszModule[512] = L""; METADATA_HANDLE hMDRootVS = NULL; METADATA_RECORD mdrData; DWORD dwErr = NO_ERROR; DWORD cbModule = 0; IMSAdminBase *pMSAdmin = NULL;
ZeroMemory(&mdrData, sizeof(METADATA_RECORD));
CoInitialize(NULL); InitAsyncTrace(); TraceFunctEnterEx((LPARAM) NULL, "HrRegisterAdvQueueDll");
if (!hAQInstance) { hr = E_INVALIDARG; ErrorTrace((LPARAM) NULL, "DLL Main did not save instance"); goto Exit; }
hr = CoCreateInstance(CLSID_MSAdminBase,NULL,CLSCTX_ALL,IID_IMSAdminBase,(void **) &pMSAdmin); if (FAILED(hr)) { ErrorTrace((LPARAM) NULL, "CoCreateInstance failed! hr = 0x%08X", hr); goto Exit; }
dwErr = GetModuleFileNameW(hAQInstance, wszModule, sizeof(wszModule)/sizeof(WCHAR)); //GetModuleFileName returns non-zero on success
if (0 == dwErr) { hr = HRESULT_FROM_WIN32(GetLastError()); ErrorTrace((LPARAM) NULL, "GetModule name failed - 0x%08X", hr); if (SUCCEEDED(hr)) hr = E_FAIL; goto Exit; }
cbModule = (wcslen(wszModule)+1)*sizeof(WCHAR);
hr = pMSAdmin->OpenKey( METADATA_MASTER_ROOT_HANDLE, L"LM/SMTPSVC/", METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE, 10000, &hMDRootVS);
if (FAILED(hr)) { ErrorTrace((LPARAM) NULL, "Could not open the key! - 0x%08x", hr); goto Exit; }
mdrData.dwMDIdentifier = MD_AQUEUE_DLL; mdrData.dwMDAttributes = METADATA_INHERIT; mdrData.dwMDUserType = IIS_MD_UT_SERVER; mdrData.dwMDDataType = STRING_METADATA; mdrData.dwMDDataLen = cbModule; mdrData.pbMDData = (PBYTE) wszModule; mdrData.dwMDDataTag = 0; hr = pMSAdmin->SetData( hMDRootVS, L"", &mdrData); if (FAILED(hr)) { ErrorTrace((LPARAM) NULL, "Could set the AQ DLL - 0x%08X", hr); goto Exit; }
Exit:
if (NULL != hMDRootVS) pMSAdmin->CloseKey(hMDRootVS);
if (pMSAdmin) { hr = pMSAdmin->SaveData(); if (FAILED(hr)) { ErrorTrace((LPARAM) NULL, "Error saving metabase data - 0x%08X", hr); } pMSAdmin->Release(); }
TraceFunctLeave(); TermAsyncTrace(); CoUninitialize(); return hr; }
//---[ HrUnregisterAdvQueueDll ]-----------------------------------------------
//
//
// Description:
// Removes the AdvQueue DLL setting from the metabase
// Parameters:
// -
// Returns:
// S_OK on success
// Error from MSAdminBase
// History:
// 8/2/99 - MikeSwa Created
//
//-----------------------------------------------------------------------------
HRESULT HrUnregisterAdvQueueDll() { HRESULT hr = S_OK; DWORD dwErr = NO_ERROR; METADATA_HANDLE hMDRootVS = NULL; IMSAdminBase *pMSAdmin = NULL;
CoInitialize(NULL); InitAsyncTrace(); TraceFunctEnterEx((LPARAM) NULL, "HrUnregisterAdvQueueDll");
hr = CoCreateInstance(CLSID_MSAdminBase,NULL,CLSCTX_ALL,IID_IMSAdminBase,(void **) &pMSAdmin); if (FAILED(hr)) { ErrorTrace((LPARAM) NULL, "CoCreateInstance failed! hr = 0x%08X", hr); goto Exit; }
hr = pMSAdmin->OpenKey( METADATA_MASTER_ROOT_HANDLE, L"LM/SMTPSVC/", METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE, 10000, &hMDRootVS);
if (FAILED(hr)) { ErrorTrace((LPARAM) NULL, "Could not open the key! - 0x%08x", hr); goto Exit; }
hr = pMSAdmin->DeleteData( hMDRootVS, L"", MD_AQUEUE_DLL, STRING_METADATA); if (FAILED(hr)) { ErrorTrace((LPARAM) NULL, "Could delete the AQ DLL - 0x%08X", hr); goto Exit; }
Exit:
if (NULL != hMDRootVS) pMSAdmin->CloseKey(hMDRootVS);
if (pMSAdmin) { hr = pMSAdmin->SaveData(); if (FAILED(hr)) { ErrorTrace((LPARAM) NULL, "Error saving metabase data - 0x%08X", hr); } pMSAdmin->Release(); }
TraceFunctLeave(); TermAsyncTrace(); CoUninitialize(); return hr; }
/////////////////////////////////////////////////////////////////////////////
// DLL Entry Point
extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/) { if (dwReason == DLL_PROCESS_ATTACH) { g_hAQInstance = hInstance; _Module.Init(ObjectMap, hInstance); DisableThreadLibraryCalls(hInstance); } else if (dwReason == DLL_PROCESS_DETACH) { _Module.Term(); }
return CatDllMain(hInstance, dwReason, NULL); // ok
}
/////////////////////////////////////////////////////////////////////////////
// DLL Entry Point
//
// Register COM objects
//
STDAPI DllRegisterServer() { HRESULT hr = S_OK; HRESULT hrCat = S_OK;
hr = HrRegisterAdvQueueDll(g_hAQInstance);
hrCat = RegisterCatServer();
if (SUCCEEDED(hr)) hr = hrCat;
return hr; }
//
// Unregister COM objects
//
STDAPI DllUnregisterServer() { HRESULT hr = S_OK; HRESULT hrCat = S_OK;
hr = HrUnregisterAdvQueueDll();
hrCat = UnregisterCatServer();
if (SUCCEEDED(hr)) hr = hrCat;
return hr; }
STDAPI DllCanUnloadNow() { HRESULT hr;
hr = DllCanUnloadCatNow(); if(hr == S_OK) { //
// Check aqueue COM objects (if any)
//
if (g_fForceDllCanUnloadNowFailure || g_cInstances) hr = S_FALSE; } return hr; }
STDAPI DllGetClassObject( const CLSID& clsid, const IID& iid, void** ppv) { HRESULT hr; //
// Check to see if clsid is an aqueue object (if any aqueue
// objects are cocreateable)
// Currently none are
//
// Pass to the cat
//
hr = DllGetCatClassObject( clsid, iid, ppv);
return hr; }
//+------------------------------------------------------------
//
// Function: HrDllInitialize
//
// Synopsis: Refcounted initialize of exchmem and tracing
// The logic for HrDllInitialize and DllDeInitialize depend on the
// facts that the callers always call HrDllInitialize first and only
// call DllDeInitialize once after each call to HrDllInitialize succeeds
//
// Arguments: NONE
//
// Returns:
// S_OK: Success
// E_OUTOFMEMORY
// error from exstrace
//
// History:
// jstamerj 1998/12/16 15:37:07: Created.
//
//-------------------------------------------------------------
HRESULT HrDllInitialize() { HRESULT hr = S_OK; LONG lNewCount;
//
// Increment inside a sharelock because of the following case:
// If multiple threads are calling initialize and one thread is
// actually doing the initialization, we don't want any threads to
// return from this function until the initialization is done
//
g_slDllInit.ShareLock();
lNewCount = InterlockedIncrement(&g_cDllInit);
//
// No matter what, we must Init before leaving this call
// Possible scenerios:
//
// lNewCount = 1, g_fInit = FALSE
// Normal initialization case
// lNewCount = 1, g_fInit = TRUE
// Another thread is in DllDeinitialize and we have a race to
// see who gets the exclusive lock first. If we get it first,
// DllInitialize will do nothing (since g_fInit is TRUE) and
// DllDeInitialize will do nothing (since g_cDllInit will be >
// 0)
// If DllDeInitialize gets the exclusive lock first, it will
// deinit and we will reinit
// lNewCount > 1, g_fInit = FALSE
// We need to get the exclusive lock to init (or to wait until
// another thread inits)
// lNewCount > 1, g_fInit = TRUE
// We're alrady initialized, continue.
//
if((lNewCount == 1) || (g_fInit == FALSE)) {
g_slDllInit.ShareUnlock(); g_slDllInit.ExclusiveLock();
if(g_fInit == FALSE) { //
// Initialize exchmem and tracing
//
InitAsyncTrace();
//
// Initialize exchmem
//
if(!TrHeapCreate()) {
hr = E_OUTOFMEMORY; TermAsyncTrace(); } if(SUCCEEDED(hr)) { g_fInit = TRUE; } else { InterlockedDecrement(&g_cDllInit); } } g_slDllInit.ExclusiveUnlock();
} else {
g_slDllInit.ShareUnlock(); } _ASSERT(g_fInit); return hr; }
//+------------------------------------------------------------
//
// Function: DllDeinitialize
//
// Synopsis: Refcounted deinitialize of exchmem and tracing
//
// Arguments: NONE
//
// Returns: NOTHING
//
// History:
// jstamerj 1998/12/16 15:46:32: Created.
//
//-------------------------------------------------------------
VOID DllDeinitialize() { //
// We don't need to do the decrement inside a sharelock because we
// don't care about blocking threads until the DLL is really
// DeInitialzied (whereas HrDllInitialize does care)
//
if(InterlockedDecrement(&g_cDllInit) == 0) {
g_slDllInit.ExclusiveLock(); //
// If the refcount is still zero, deinitialize
// If the refcount is non-zero, someone initialized before we
// got the exclusive lock, so do not deinitialize
//
if(g_cDllInit == 0) { //
// If this assert fires, then DllDeinitialize has been
// called before DllInitialize returned (or there is a
// DllInit/Deinit mismatch)
//
_ASSERT(g_fInit == TRUE);
//
// Termiante exchmem and tracing
//
if(!TrHeapDestroy()) {
TraceFunctEnter("DllDeinitialize"); ErrorTrace((LPARAM) 0, "Unable to Destroy Exchmem heap for Advanced Queuing"); TraceFunctLeave(); } TermAsyncTrace(); g_fInit = FALSE;
} else { //
// Someone called initialize between the time we
// decremented the count and got the exclusive lock. In
// this case we don't want to deinitialize
//
} g_slDllInit.ExclusiveUnlock(); } }
#include <atlimpl.cpp>
|