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