Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

921 lines
26 KiB

//-----------------------------------------------------------------------------
//
//
// 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>