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

  1. //-----------------------------------------------------------------------------
  2. //
  3. //
  4. // File:
  5. // aqueue.cpp
  6. // Description:
  7. // Implementation of DLL Exports.
  8. // Author: Mike Swafford (MikeSwa)
  9. //
  10. // History:
  11. //
  12. // Copyright (C) 1998 Microsoft Corporation
  13. //
  14. //-----------------------------------------------------------------------------
  15. #include "aqprecmp.h"
  16. #ifndef PLATINUM
  17. #include "initguid.h"
  18. #include <iadmw.h>
  19. #endif //PLATINUM
  20. #include "aqueue_i.c"
  21. #include "aqintrnl_i.c"
  22. #include "SMTPConn.h"
  23. #include "qwiklist.h"
  24. #include "fifoqimp.h"
  25. #include <irtlmisc.h>
  26. #include <iiscnfg.h>
  27. #include <wrapmb.h>
  28. #include <smtpinet.h>
  29. #include <cat.h>
  30. #include <aqinit.h>
  31. #include "aqrpcsvr.h"
  32. //Global vars used for shutdown
  33. DWORD g_cInstances = 0;
  34. CShareLockNH g_slInit; //lock used for thread-safe initialization
  35. //Global vars used for Dll init/shutdown (including Cat COM stuff)
  36. LONG g_cDllInit = 0;
  37. BOOL g_fInit = FALSE;
  38. CShareLockNH g_slDllInit;
  39. BOOL g_fForceDllCanUnloadNowFailure = FALSE;
  40. #define CALL_SERVICE_STATUS_CALLBACK \
  41. pServiceStatusFn ? pServiceStatusFn(pvServiceContext) : 0
  42. // SEO crap needed for aqdisp
  43. #define _ATL_NO_DEBUG_CRT
  44. #define _ASSERTE _ASSERT
  45. #define _WINDLL
  46. #include "atlbase.h"
  47. extern CComModule _Module;
  48. #include "atlcom.h"
  49. #undef _WINDLL
  50. CComModule _Module;
  51. BEGIN_OBJECT_MAP(ObjectMap)
  52. END_OBJECT_MAP()
  53. #include <pudebug.h>
  54. DEBUG_PRINTS *g_pDebug = NULL;
  55. //---[ HrAdvQueueInitializeEx ]-------------------------------------------------
  56. //
  57. //
  58. // Description:
  59. // Aqueue.dll initialization function that provides in params for user name,
  60. // domain, password, and service control callback functions.
  61. // Parameters:
  62. // IN pISMTPServer ptr to local delivery function / object
  63. // IN dwServerInstance virtual server instance
  64. // IN szUserName User name to log on DS with
  65. // IN szDomainName Domain name to log on to DS with
  66. // IN szPassword Password to authenticate to DS with
  67. // IN pServiceStatusFn Server status callback function
  68. // IN pvServiceContext Context to pass back for callback function
  69. // OUT ppIAdvQueue returned IAdvQueue ptr
  70. // OUT ppIConnectionManager returned IConnectionManager ptr
  71. // OUT ppIAdvQueueConfig returned IAdvQueueConfig ptr
  72. // OUT ppvContext Virtual server context
  73. // Returns:
  74. //
  75. //
  76. //-----------------------------------------------------------------------------
  77. HRESULT HrAdvQueueInitializeEx(
  78. IN ISMTPServer *pISMTPServer,
  79. IN DWORD dwServerInstance,
  80. IN LPSTR szUserName,
  81. IN LPSTR szDomainName,
  82. IN LPSTR szPassword,
  83. IN PSRVFN pServiceStatusFn,
  84. IN PVOID pvServiceContext,
  85. OUT IAdvQueue **ppIAdvQueue,
  86. OUT IConnectionManager **ppIConnectionManager,
  87. OUT IAdvQueueConfig **ppIAdvQueueConfig,
  88. OUT PVOID *ppvContext)
  89. {
  90. TraceFunctEnterEx((LPARAM) NULL, "HrAdvQueueInitialize");
  91. HRESULT hr = S_OK;
  92. CAQSvrInst *paqinst = NULL;
  93. CDomainMappingTable *pdmt = NULL;
  94. BOOL fLocked = FALSE;
  95. BOOL fInstanceCounted = FALSE;
  96. #ifdef PLATINUM
  97. BOOL fIisRtlInit = FALSE;
  98. BOOL fATQInit = FALSE;
  99. #endif
  100. BOOL fAQDllInit = FALSE;
  101. BOOL fExchmemInit = FALSE;
  102. BOOL fCPoolInit = FALSE;
  103. BOOL fRpcInit = FALSE;
  104. BOOL fDSNInit = FALSE;
  105. CALL_SERVICE_STATUS_CALLBACK;
  106. g_slInit.ExclusiveLock();
  107. fLocked = TRUE;
  108. if ((NULL == ppIAdvQueue) ||
  109. (NULL == ppIConnectionManager) ||
  110. (NULL == ppvContext) ||
  111. (NULL == ppIAdvQueueConfig))
  112. {
  113. hr = E_INVALIDARG;
  114. goto Exit;
  115. }
  116. *ppvContext = NULL;
  117. //
  118. // Update global config information.
  119. //
  120. ReadGlobalRegistryConfiguration();
  121. if (1 == InterlockedIncrement((PLONG) &g_cInstances))
  122. {
  123. fInstanceCounted = TRUE;
  124. CALL_SERVICE_STATUS_CALLBACK;
  125. #ifdef PLATINUM
  126. //Initialize IISRTL
  127. if (!InitializeIISRTL())
  128. {
  129. hr = HRESULT_FROM_WIN32(GetLastError());
  130. ErrorTrace((LPARAM) NULL, "ERROR: LISRTL Init failed with 0x%08X", hr);
  131. if (SUCCEEDED(hr))
  132. hr = E_FAIL;
  133. goto Exit;
  134. }
  135. fIisRtlInit = TRUE;
  136. //Initialize ATQ
  137. if (!AtqInitialize(0))
  138. {
  139. hr = HRESULT_FROM_WIN32(GetLastError());
  140. ErrorTrace((LPARAM) NULL, "ERROR: ATQ Init failed with 0x%08X", hr);
  141. if (SUCCEEDED(hr))
  142. hr = E_FAIL;
  143. goto Exit;
  144. }
  145. fATQInit = TRUE;
  146. #endif
  147. hr = HrDllInitialize();
  148. if (FAILED(hr))
  149. {
  150. goto Exit;
  151. }
  152. fAQDllInit = TRUE;
  153. //create CPool objects
  154. if (!CQuickList::s_QuickListPool.ReserveMemory(10000, sizeof(CQuickList)))
  155. hr = E_OUTOFMEMORY;
  156. if (!CSMTPConn::s_SMTPConnPool.ReserveMemory(g_cMaxConnections, sizeof(CSMTPConn)))
  157. hr = E_OUTOFMEMORY;
  158. if (!CMsgRef::s_MsgRefPool.ReserveMemory(g_cMaxMsgObjects, MSGREF_STANDARD_CPOOL_SIZE))
  159. hr = E_OUTOFMEMORY;
  160. if (!CAQMsgGuidListEntry::s_MsgGuidListEntryPool.ReserveMemory(500, sizeof(CAQMsgGuidListEntry)))
  161. hr = E_OUTOFMEMORY;
  162. if (!CAsyncWorkQueueItem::s_CAsyncWorkQueueItemPool.ReserveMemory(20000, sizeof(CAsyncWorkQueueItemAllocatorBlock)))
  163. hr = E_OUTOFMEMORY;
  164. if (!CAddr::Pool.ReserveMemory(1000, sizeof(CAddr)))
  165. hr = E_OUTOFMEMORY;
  166. if (!CAQSvrInst::CAQLocalDeliveryNotify::s_pool.ReserveMemory(g_cMaxPendingLocal, sizeof(CAQSvrInst::CAQLocalDeliveryNotify)))
  167. hr = E_OUTOFMEMORY;
  168. if (!CBlockMemoryAccess::m_Pool.ReserveMemory(2000, sizeof(BLOCK_HEAP_NODE)))
  169. hr = E_OUTOFMEMORY;
  170. if (FAILED(hr))
  171. {
  172. ErrorTrace((LPARAM) NULL, "Error unable to initialize CPOOL");
  173. goto Exit;
  174. }
  175. fCPoolInit = TRUE;
  176. hr = CDSNGenerator::HrStaticInit();
  177. if(FAILED(hr))
  178. {
  179. ErrorTrace((LPARAM) NULL, "CDSNGenerator::StaticInif failed hr %08lx", hr);
  180. goto Exit;
  181. }
  182. fDSNInit = TRUE;
  183. //Initialize Queue Admin RPC interface
  184. hr = CAQRpcSvrInst::HrInitializeAQRpc();
  185. if (FAILED(hr))
  186. goto Exit;
  187. fRpcInit = TRUE;
  188. }
  189. if (!g_pslGlobals)
  190. {
  191. g_pslGlobals = new CShareLockNH();
  192. if (NULL == g_pslGlobals) {
  193. hr = E_OUTOFMEMORY;
  194. goto Exit;
  195. }
  196. }
  197. CALL_SERVICE_STATUS_CALLBACK;
  198. g_slInit.ExclusiveUnlock();
  199. fLocked = FALSE;
  200. CFifoQueue<CLinkMsgQueue *>::StaticInit();
  201. CFifoQueue<CMsgRef *>::StaticInit();
  202. CFifoQueue<IMailMsgProperties *>::StaticInit();
  203. CFifoQueue<CAsyncWorkQueueItem *>::StaticInit();
  204. //Create requested objects
  205. CALL_SERVICE_STATUS_CALLBACK;
  206. paqinst = new CAQSvrInst(dwServerInstance, pISMTPServer);
  207. if (NULL == paqinst)
  208. {
  209. hr = E_OUTOFMEMORY;
  210. goto Exit;
  211. }
  212. CALL_SERVICE_STATUS_CALLBACK;
  213. hr = paqinst->HrInitialize(szUserName, szDomainName, szPassword,
  214. pServiceStatusFn,
  215. pvServiceContext);
  216. if (FAILED(hr))
  217. goto Exit;
  218. //Create Connection Manager
  219. CALL_SERVICE_STATUS_CALLBACK;
  220. hr = paqinst->HrGetIConnectionManager(ppIConnectionManager);
  221. //Set Return values
  222. *ppIAdvQueue = (IAdvQueue *) paqinst; //Already addref'd at creation
  223. *ppIAdvQueueConfig = (IAdvQueueConfig *) paqinst;
  224. (*ppIAdvQueueConfig)->AddRef();
  225. Exit:
  226. if (FAILED(hr))
  227. {
  228. //Make sure that we clean up everything here
  229. if (NULL != paqinst)
  230. paqinst->Release();
  231. //If initialization failed... we should not count an
  232. //instance as started
  233. if (fInstanceCounted)
  234. InterlockedDecrement((PLONG) &g_cInstances);
  235. #ifdef PLATINUM
  236. if (fATQInit)
  237. AtqTerminate();
  238. if (fIisRtlInit)
  239. TerminateIISRTL();
  240. #endif
  241. if (fAQDllInit)
  242. DllDeinitialize();
  243. if (fCPoolInit)
  244. {
  245. //Release CPool objects
  246. CAQSvrInst::CAQLocalDeliveryNotify::s_pool.ReleaseMemory();
  247. CAddr::Pool.ReleaseMemory();
  248. CQuickList::s_QuickListPool.ReleaseMemory();
  249. CSMTPConn::s_SMTPConnPool.ReleaseMemory();
  250. CMsgRef::s_MsgRefPool.ReleaseMemory();
  251. CAQMsgGuidListEntry::s_MsgGuidListEntryPool.ReleaseMemory();
  252. CAsyncWorkQueueItem::s_CAsyncWorkQueueItemPool.ReleaseMemory();
  253. CBlockMemoryAccess::m_Pool.ReleaseMemory();
  254. }
  255. if (fDSNInit)
  256. CDSNGenerator::StaticDeinit();
  257. if (fRpcInit)
  258. CAQRpcSvrInst::HrDeinitializeAQRpc();
  259. }
  260. else
  261. {
  262. *ppvContext = (PVOID) paqinst;
  263. paqinst->AddRef();
  264. }
  265. if (fLocked)
  266. g_slInit.ExclusiveUnlock();
  267. TraceFunctLeave();
  268. return hr;
  269. }
  270. //---[ HrAdvQueueInitialize ]---------------------------------------------------
  271. //
  272. //
  273. // Description:
  274. // Performs DLL-wide initialization
  275. //
  276. // Parameters:
  277. // IN pISMTPServer ptr to local delivery function / object
  278. // IN dwServerInstance virtual server instance
  279. // OUT ppIAdvQueue returned IAdvQueue ptr
  280. // OUT ppIConnectionManager returned IConnectionManager ptr
  281. // OUT ppIAdvQueueConfig returned IAdvQueueConfig ptr
  282. // OUT ppvContext Virtual server context
  283. // Returns:
  284. // S_OK on success
  285. //
  286. //-----------------------------------------------------------------------------
  287. HRESULT HrAdvQueueInitialize(
  288. IN ISMTPServer *pISMTPServer,
  289. IN DWORD dwServerInstance,
  290. OUT IAdvQueue **ppIAdvQueue,
  291. OUT IConnectionManager **ppIConnectionManager,
  292. OUT IAdvQueueConfig **ppIAdvQueueConfig,
  293. OUT PVOID *ppvContext)
  294. {
  295. HRESULT hr = S_OK;
  296. hr = HrAdvQueueInitializeEx(pISMTPServer, dwServerInstance,
  297. NULL, NULL, NULL, NULL, NULL, ppIAdvQueue,
  298. ppIConnectionManager, ppIAdvQueueConfig, ppvContext);
  299. return hr;
  300. }
  301. //---[ HrAdvQueueDeinitializeEx ]------------------------------------------------
  302. //
  303. //
  304. // Description:
  305. // Performs DLL-wide Cleanup.
  306. //
  307. // Adds callback to service control manager.
  308. //
  309. // This MUST not be called until all DLL objects have been released.
  310. //
  311. // NOTE: There are several objects that are exported outside this DLL.
  312. // The following are directly exported & should be released before the
  313. // the Heap and CPool allocations are freed
  314. // IAdvQueue
  315. // IConnectionManager
  316. // ISMTPConnection
  317. // The Message Context also contains several references to internal objects,
  318. // but does not need to be explicitly released (since these objects can only
  319. // be accessed though the AckMessage() call).
  320. // Parameters:
  321. // PVOID pvContext Context that was returned by initialization
  322. // function
  323. // IN pServiceStatusFn Server status callback function
  324. // IN pvServiceContext Context to pass back for callback function
  325. // Returns:
  326. // S_OK on success
  327. //
  328. //-----------------------------------------------------------------------------
  329. HRESULT HrAdvQueueDeinitializeEx(IN PVOID pvContext,
  330. IN PSRVFN pServiceStatusFn,
  331. IN PVOID pvServiceContext)
  332. {
  333. TraceFunctEnterEx((LPARAM) NULL, "HrAdvQueueDeinitialize");
  334. HRESULT hr = S_OK;
  335. HRESULT hrCurrent = S_OK;
  336. DWORD cRefs;
  337. DWORD dwWaitResult = WAIT_OBJECT_0;
  338. bool fDestroyHeap = true;
  339. DWORD dwShutdownTimeout = 0; //time to wait for shutdown
  340. CAQSvrInst *paqinst;
  341. g_fForceDllCanUnloadNowFailure = TRUE;
  342. g_slInit.ExclusiveLock();
  343. if (NULL != pvContext)
  344. {
  345. paqinst = (CAQSvrInst *) pvContext;
  346. hr = paqinst->HrDeinitialize();
  347. cRefs = paqinst->Release();
  348. DebugTrace((LPARAM) NULL, "There are %d refs remaining on the CMQ", cRefs);
  349. if (0 != cRefs)
  350. {
  351. _ASSERT(0 && "Someone has outstanding references to IAdvQueue or IAdvQueuConfig");
  352. fDestroyHeap = false;
  353. }
  354. }
  355. CFifoQueue<CLinkMsgQueue *>::StaticDeinit();
  356. CFifoQueue<CMsgRef *>::StaticDeinit();
  357. CFifoQueue<IMailMsgProperties *>::StaticDeinit();
  358. CFifoQueue<CAsyncWorkQueueItem *>::StaticDeinit();
  359. if (0 == InterlockedDecrement((PLONG) &g_cInstances))
  360. {
  361. #ifdef PLATINUM
  362. AtqTerminate();
  363. #endif
  364. if (fDestroyHeap)
  365. {
  366. delete g_pslGlobals;
  367. g_pslGlobals = NULL;
  368. DllDeinitialize();
  369. //Release CPool objects
  370. CAQSvrInst::CAQLocalDeliveryNotify::s_pool.ReleaseMemory();
  371. CAddr::Pool.ReleaseMemory();
  372. CQuickList::s_QuickListPool.ReleaseMemory();
  373. CSMTPConn::s_SMTPConnPool.ReleaseMemory();
  374. CMsgRef::s_MsgRefPool.ReleaseMemory();
  375. CAQMsgGuidListEntry::s_MsgGuidListEntryPool.ReleaseMemory();
  376. CAsyncWorkQueueItem::s_CAsyncWorkQueueItemPool.ReleaseMemory();
  377. CBlockMemoryAccess::m_Pool.ReleaseMemory();
  378. }
  379. //
  380. // Deinit DSN Generator
  381. //
  382. CDSNGenerator::StaticDeinit();
  383. //Deinitialize Queue Admin RPC interface
  384. hr = CAQRpcSvrInst::HrDeinitializeAQRpc();
  385. #ifdef PLATINUM
  386. TerminateIISRTL();
  387. #endif
  388. //Force mailmsg and other COM DLLs to go buh-bye
  389. CoFreeUnusedLibraries();
  390. }
  391. g_slInit.ExclusiveUnlock();
  392. TraceFunctLeave();
  393. g_fForceDllCanUnloadNowFailure = FALSE;
  394. return hr;
  395. }
  396. //---[ HrAdvQueueDeinitialize ]------------------------------------------------
  397. //
  398. //
  399. // Description:
  400. // Performs DLL-wide Cleanup.
  401. //
  402. // This MUST not be called until all DLL objects have been released.
  403. //
  404. // NOTE: There are several objects that are exported outside this DLL.
  405. // The following are directly exported & should be released before the
  406. // the Heap and CPool allocations are freed
  407. // IAdvQueue
  408. // IConnectionManager
  409. // ISMTPConnection
  410. // The Message Context also contains several references to internal objects,
  411. // but does not need to be explicitly released (since these objects can only
  412. // be accessed though the AckMessage() call).
  413. // Parameters:
  414. // PVOID pvContext Context that was returned by initialization
  415. // function
  416. // Returns:
  417. // S_OK on success
  418. //
  419. //-----------------------------------------------------------------------------
  420. HRESULT HrAdvQueueDeinitialize(PVOID pvContext)
  421. {
  422. return HrAdvQueueDeinitializeEx(pvContext, NULL, NULL);
  423. }
  424. //---[ HrRegisterAdvQueueDll ]-------------------------------------------------
  425. //
  426. //
  427. // Description:
  428. // Sets metabase path of for advanced queuing DLL to this DLL.
  429. // Parameters:
  430. // hAQInstance - Handle passed into DLL main
  431. // Returns:
  432. // S_OK on success
  433. // E_INVALIDARG if hAQInstance is NULL.
  434. // Error codes from accessed metabase
  435. // History:
  436. // 7/30/99 - MikeSwa Created
  437. //
  438. //-----------------------------------------------------------------------------
  439. HRESULT HrRegisterAdvQueueDll(HMODULE hAQInstance)
  440. {
  441. HRESULT hr = S_OK;
  442. WCHAR wszModule[512] = L"";
  443. METADATA_HANDLE hMDRootVS = NULL;
  444. METADATA_RECORD mdrData;
  445. DWORD dwErr = NO_ERROR;
  446. DWORD cbModule = 0;
  447. IMSAdminBase *pMSAdmin = NULL;
  448. ZeroMemory(&mdrData, sizeof(METADATA_RECORD));
  449. CoInitialize(NULL);
  450. InitAsyncTrace();
  451. TraceFunctEnterEx((LPARAM) NULL, "HrRegisterAdvQueueDll");
  452. if (!hAQInstance)
  453. {
  454. hr = E_INVALIDARG;
  455. ErrorTrace((LPARAM) NULL, "DLL Main did not save instance");
  456. goto Exit;
  457. }
  458. hr = CoCreateInstance(CLSID_MSAdminBase,NULL,CLSCTX_ALL,IID_IMSAdminBase,(void **) &pMSAdmin);
  459. if (FAILED(hr))
  460. {
  461. ErrorTrace((LPARAM) NULL, "CoCreateInstance failed! hr = 0x%08X", hr);
  462. goto Exit;
  463. }
  464. dwErr = GetModuleFileNameW(hAQInstance,
  465. wszModule,
  466. sizeof(wszModule)/sizeof(WCHAR));
  467. //GetModuleFileName returns non-zero on success
  468. if (0 == dwErr)
  469. {
  470. hr = HRESULT_FROM_WIN32(GetLastError());
  471. ErrorTrace((LPARAM) NULL, "GetModule name failed - 0x%08X", hr);
  472. if (SUCCEEDED(hr)) hr = E_FAIL;
  473. goto Exit;
  474. }
  475. cbModule = (wcslen(wszModule)+1)*sizeof(WCHAR);
  476. hr = pMSAdmin->OpenKey( METADATA_MASTER_ROOT_HANDLE,
  477. L"LM/SMTPSVC/",
  478. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
  479. 10000,
  480. &hMDRootVS);
  481. if (FAILED(hr))
  482. {
  483. ErrorTrace((LPARAM) NULL, "Could not open the key! - 0x%08x", hr);
  484. goto Exit;
  485. }
  486. mdrData.dwMDIdentifier = MD_AQUEUE_DLL;
  487. mdrData.dwMDAttributes = METADATA_INHERIT;
  488. mdrData.dwMDUserType = IIS_MD_UT_SERVER;
  489. mdrData.dwMDDataType = STRING_METADATA;
  490. mdrData.dwMDDataLen = cbModule;
  491. mdrData.pbMDData = (PBYTE) wszModule;
  492. mdrData.dwMDDataTag = 0;
  493. hr = pMSAdmin->SetData( hMDRootVS, L"", &mdrData);
  494. if (FAILED(hr))
  495. {
  496. ErrorTrace((LPARAM) NULL, "Could set the AQ DLL - 0x%08X", hr);
  497. goto Exit;
  498. }
  499. Exit:
  500. if (NULL != hMDRootVS)
  501. pMSAdmin->CloseKey(hMDRootVS);
  502. if (pMSAdmin)
  503. {
  504. hr = pMSAdmin->SaveData();
  505. if (FAILED(hr))
  506. {
  507. ErrorTrace((LPARAM) NULL, "Error saving metabase data - 0x%08X", hr);
  508. }
  509. pMSAdmin->Release();
  510. }
  511. TraceFunctLeave();
  512. TermAsyncTrace();
  513. CoUninitialize();
  514. return hr;
  515. }
  516. //---[ HrUnregisterAdvQueueDll ]-----------------------------------------------
  517. //
  518. //
  519. // Description:
  520. // Removes the AdvQueue DLL setting from the metabase
  521. // Parameters:
  522. // -
  523. // Returns:
  524. // S_OK on success
  525. // Error from MSAdminBase
  526. // History:
  527. // 8/2/99 - MikeSwa Created
  528. //
  529. //-----------------------------------------------------------------------------
  530. HRESULT HrUnregisterAdvQueueDll()
  531. {
  532. HRESULT hr = S_OK;
  533. DWORD dwErr = NO_ERROR;
  534. METADATA_HANDLE hMDRootVS = NULL;
  535. IMSAdminBase *pMSAdmin = NULL;
  536. CoInitialize(NULL);
  537. InitAsyncTrace();
  538. TraceFunctEnterEx((LPARAM) NULL, "HrUnregisterAdvQueueDll");
  539. hr = CoCreateInstance(CLSID_MSAdminBase,NULL,CLSCTX_ALL,IID_IMSAdminBase,(void **) &pMSAdmin);
  540. if (FAILED(hr))
  541. {
  542. ErrorTrace((LPARAM) NULL, "CoCreateInstance failed! hr = 0x%08X", hr);
  543. goto Exit;
  544. }
  545. hr = pMSAdmin->OpenKey( METADATA_MASTER_ROOT_HANDLE,
  546. L"LM/SMTPSVC/",
  547. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
  548. 10000,
  549. &hMDRootVS);
  550. if (FAILED(hr))
  551. {
  552. ErrorTrace((LPARAM) NULL, "Could not open the key! - 0x%08x", hr);
  553. goto Exit;
  554. }
  555. hr = pMSAdmin->DeleteData( hMDRootVS, L"", MD_AQUEUE_DLL, STRING_METADATA);
  556. if (FAILED(hr))
  557. {
  558. ErrorTrace((LPARAM) NULL, "Could delete the AQ DLL - 0x%08X", hr);
  559. goto Exit;
  560. }
  561. Exit:
  562. if (NULL != hMDRootVS)
  563. pMSAdmin->CloseKey(hMDRootVS);
  564. if (pMSAdmin)
  565. {
  566. hr = pMSAdmin->SaveData();
  567. if (FAILED(hr))
  568. {
  569. ErrorTrace((LPARAM) NULL, "Error saving metabase data - 0x%08X", hr);
  570. }
  571. pMSAdmin->Release();
  572. }
  573. TraceFunctLeave();
  574. TermAsyncTrace();
  575. CoUninitialize();
  576. return hr;
  577. }
  578. /////////////////////////////////////////////////////////////////////////////
  579. // DLL Entry Point
  580. extern "C"
  581. BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
  582. {
  583. if (dwReason == DLL_PROCESS_ATTACH)
  584. {
  585. g_hAQInstance = hInstance;
  586. _Module.Init(ObjectMap, hInstance);
  587. DisableThreadLibraryCalls(hInstance);
  588. }
  589. else if (dwReason == DLL_PROCESS_DETACH)
  590. {
  591. _Module.Term();
  592. }
  593. return CatDllMain(hInstance, dwReason, NULL); // ok
  594. }
  595. /////////////////////////////////////////////////////////////////////////////
  596. // DLL Entry Point
  597. //
  598. // Register COM objects
  599. //
  600. STDAPI DllRegisterServer()
  601. {
  602. HRESULT hr = S_OK;
  603. HRESULT hrCat = S_OK;
  604. hr = HrRegisterAdvQueueDll(g_hAQInstance);
  605. hrCat = RegisterCatServer();
  606. if (SUCCEEDED(hr))
  607. hr = hrCat;
  608. return hr;
  609. }
  610. //
  611. // Unregister COM objects
  612. //
  613. STDAPI DllUnregisterServer()
  614. {
  615. HRESULT hr = S_OK;
  616. HRESULT hrCat = S_OK;
  617. hr = HrUnregisterAdvQueueDll();
  618. hrCat = UnregisterCatServer();
  619. if (SUCCEEDED(hr))
  620. hr = hrCat;
  621. return hr;
  622. }
  623. STDAPI DllCanUnloadNow()
  624. {
  625. HRESULT hr;
  626. hr = DllCanUnloadCatNow();
  627. if(hr == S_OK) {
  628. //
  629. // Check aqueue COM objects (if any)
  630. //
  631. if (g_fForceDllCanUnloadNowFailure || g_cInstances)
  632. hr = S_FALSE;
  633. }
  634. return hr;
  635. }
  636. STDAPI DllGetClassObject(
  637. const CLSID& clsid,
  638. const IID& iid,
  639. void** ppv)
  640. {
  641. HRESULT hr;
  642. //
  643. // Check to see if clsid is an aqueue object (if any aqueue
  644. // objects are cocreateable)
  645. // Currently none are
  646. //
  647. // Pass to the cat
  648. //
  649. hr = DllGetCatClassObject(
  650. clsid,
  651. iid,
  652. ppv);
  653. return hr;
  654. }
  655. //+------------------------------------------------------------
  656. //
  657. // Function: HrDllInitialize
  658. //
  659. // Synopsis: Refcounted initialize of exchmem and tracing
  660. // The logic for HrDllInitialize and DllDeInitialize depend on the
  661. // facts that the callers always call HrDllInitialize first and only
  662. // call DllDeInitialize once after each call to HrDllInitialize succeeds
  663. //
  664. // Arguments: NONE
  665. //
  666. // Returns:
  667. // S_OK: Success
  668. // E_OUTOFMEMORY
  669. // error from exstrace
  670. //
  671. // History:
  672. // jstamerj 1998/12/16 15:37:07: Created.
  673. //
  674. //-------------------------------------------------------------
  675. HRESULT HrDllInitialize()
  676. {
  677. HRESULT hr = S_OK;
  678. LONG lNewCount;
  679. //
  680. // Increment inside a sharelock because of the following case:
  681. // If multiple threads are calling initialize and one thread is
  682. // actually doing the initialization, we don't want any threads to
  683. // return from this function until the initialization is done
  684. //
  685. g_slDllInit.ShareLock();
  686. lNewCount = InterlockedIncrement(&g_cDllInit);
  687. //
  688. // No matter what, we must Init before leaving this call
  689. // Possible scenerios:
  690. //
  691. // lNewCount = 1, g_fInit = FALSE
  692. // Normal initialization case
  693. // lNewCount = 1, g_fInit = TRUE
  694. // Another thread is in DllDeinitialize and we have a race to
  695. // see who gets the exclusive lock first. If we get it first,
  696. // DllInitialize will do nothing (since g_fInit is TRUE) and
  697. // DllDeInitialize will do nothing (since g_cDllInit will be >
  698. // 0)
  699. // If DllDeInitialize gets the exclusive lock first, it will
  700. // deinit and we will reinit
  701. // lNewCount > 1, g_fInit = FALSE
  702. // We need to get the exclusive lock to init (or to wait until
  703. // another thread inits)
  704. // lNewCount > 1, g_fInit = TRUE
  705. // We're alrady initialized, continue.
  706. //
  707. if((lNewCount == 1) || (g_fInit == FALSE)) {
  708. g_slDllInit.ShareUnlock();
  709. g_slDllInit.ExclusiveLock();
  710. if(g_fInit == FALSE) {
  711. //
  712. // Initialize exchmem and tracing
  713. //
  714. InitAsyncTrace();
  715. //
  716. // Initialize exchmem
  717. //
  718. if(!TrHeapCreate()) {
  719. hr = E_OUTOFMEMORY;
  720. TermAsyncTrace();
  721. }
  722. if(SUCCEEDED(hr)) {
  723. g_fInit = TRUE;
  724. } else {
  725. InterlockedDecrement(&g_cDllInit);
  726. }
  727. }
  728. g_slDllInit.ExclusiveUnlock();
  729. } else {
  730. g_slDllInit.ShareUnlock();
  731. }
  732. _ASSERT(g_fInit);
  733. return hr;
  734. }
  735. //+------------------------------------------------------------
  736. //
  737. // Function: DllDeinitialize
  738. //
  739. // Synopsis: Refcounted deinitialize of exchmem and tracing
  740. //
  741. // Arguments: NONE
  742. //
  743. // Returns: NOTHING
  744. //
  745. // History:
  746. // jstamerj 1998/12/16 15:46:32: Created.
  747. //
  748. //-------------------------------------------------------------
  749. VOID DllDeinitialize()
  750. {
  751. //
  752. // We don't need to do the decrement inside a sharelock because we
  753. // don't care about blocking threads until the DLL is really
  754. // DeInitialzied (whereas HrDllInitialize does care)
  755. //
  756. if(InterlockedDecrement(&g_cDllInit) == 0) {
  757. g_slDllInit.ExclusiveLock();
  758. //
  759. // If the refcount is still zero, deinitialize
  760. // If the refcount is non-zero, someone initialized before we
  761. // got the exclusive lock, so do not deinitialize
  762. //
  763. if(g_cDllInit == 0) {
  764. //
  765. // If this assert fires, then DllDeinitialize has been
  766. // called before DllInitialize returned (or there is a
  767. // DllInit/Deinit mismatch)
  768. //
  769. _ASSERT(g_fInit == TRUE);
  770. //
  771. // Termiante exchmem and tracing
  772. //
  773. if(!TrHeapDestroy()) {
  774. TraceFunctEnter("DllDeinitialize");
  775. ErrorTrace((LPARAM) 0,
  776. "Unable to Destroy Exchmem heap for Advanced Queuing");
  777. TraceFunctLeave();
  778. }
  779. TermAsyncTrace();
  780. g_fInit = FALSE;
  781. } else {
  782. //
  783. // Someone called initialize between the time we
  784. // decremented the count and got the exclusive lock. In
  785. // this case we don't want to deinitialize
  786. //
  787. }
  788. g_slDllInit.ExclusiveUnlock();
  789. }
  790. }
  791. #include <atlimpl.cpp>