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.

1063 lines
29 KiB

  1. //=======================================================================
  2. //
  3. // Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
  4. //
  5. // File: engmain.cpp
  6. //
  7. // Description:
  8. //
  9. // DllMain and globals for the IUEngine DLL
  10. //
  11. //=======================================================================
  12. #include "iuengine.h"
  13. #include "iucommon.h"
  14. #include "download.h"
  15. #include <limits.h>
  16. //***********************************************************************
  17. //
  18. // The following definitions are copied from IUCtl.IDL.
  19. // If IUCtl.IDL is changed, these constants need to be
  20. // changed accordingly
  21. //
  22. //***********************************************************************
  23. /**
  24. * the following two groups of constants can be used to construct
  25. * lMode parameter of the following APIs:
  26. * Download()
  27. * DownloadAsync()
  28. * Install()
  29. * InstallAsync()
  30. *
  31. * Obviousely, you can only pick one from each group to make up
  32. * lMode parameter.
  33. *
  34. */
  35. const LONG UPDATE_NOTIFICATION_DEFAULT = 0x00000000;
  36. const LONG UPDATE_NOTIFICATION_ANYPROGRESS = 0x00000000;
  37. const LONG UPDATE_NOTIFICATION_COMPLETEONLY = 0x00010000;
  38. const LONG UPDATE_NOTIFICATION_1PCT = 0x00020000;
  39. const LONG UPDATE_NOTIFICATION_5PCT = 0x00040000;
  40. const LONG UPDATE_NOTIFICATION_10PCT = 0x00080000;
  41. /**
  42. * constant can also be used for SetOperationMode() and GetOperationMode()
  43. */
  44. const LONG UPDATE_MODE_THROTTLE = 0x00000100;
  45. /**
  46. * constant can be used by Download() and DownloadAsync(), which will
  47. * tell these API's to use Corporate directory structure for destination folder.
  48. */
  49. const LONG UPDATE_CORPORATE_MODE = 0x00000200;
  50. /**
  51. * constant can be used by Install() and InstallAsync(). Will disable all
  52. * internet related features
  53. */
  54. const LONG UPDATE_OFFLINE_MODE = 0x00000400;
  55. /**
  56. * constants for SetOperationMode() API
  57. */
  58. const LONG UPDATE_COMMAND_PAUSE = 0x00000001;
  59. const LONG UPDATE_COMMAND_RESUME = 0x00000002;
  60. const LONG UPDATE_COMMAND_CANCEL = 0x00000004;
  61. /**
  62. * constants for GetOperationMode() API
  63. */
  64. const LONG UPDATE_MODE_PAUSED = 0x00000001;
  65. const LONG UPDATE_MODE_RUNNING = 0x00000002;
  66. const LONG UPDATE_MODE_NOTEXISTS = 0x00000004;
  67. /**
  68. * constants for SetProperty() and GetProperty() API
  69. */
  70. const LONG UPDATE_PROP_USECOMPRESSION = 0x00000020;
  71. const LONG UPDATE_PROP_OFFLINEMODE = 0x00000080;
  72. /**
  73. * constants for BrowseForFolder() API
  74. * IUBROWSE_WRITE_ACCESS - validate write access on selected folder
  75. * IUBROWSE_AFFECT_UI - write-access validation affect OK button enable/disable
  76. * IUBROWSE_NOBROWSE - do not show browse folder dialog box. validate path passed-in only
  77. *
  78. * default:
  79. * pop up browse folder dialog box, not doing any write-access validation
  80. *
  81. */
  82. const LONG IUBROWSE_WRITE_ACCESS = 1;
  83. const LONG IUBROWSE_AFFECT_UI = 2;
  84. const LONG IUBROWSE_NOBROWSE = 4;
  85. CEngUpdate* g_pCDMEngUpdate; // single global instance used by CDM within the process
  86. CRITICAL_SECTION g_csCDM; // used to serialize access to g_pCDMEngUpdate
  87. CRITICAL_SECTION g_csGlobalClasses; // used to serialize access to CSchemaKeys::Initialize() and
  88. BOOL gfInit_csCDM, gfInit_csGC;
  89. // CSchemaKeys::Uninitialize()
  90. ULONG g_ulGlobalClassRefCount; // Reference count to track how many CEngUpdate instances are
  91. // using the g_pGlobalSchemaKeys object
  92. LONG g_lDoOnceOnLoadGuard; // Used to prevent AsyncExtraWorkUponEngineLoad() from doing
  93. // any work after the first time it is called.
  94. //
  95. // Used to control shutdown of global threads
  96. //
  97. LONG g_lThreadCounter;
  98. HANDLE g_evtNeedToQuit;
  99. CUrlAgent *g_pUrlAgent = NULL;
  100. BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpvReserved)
  101. {
  102. if (dwReason == DLL_PROCESS_ATTACH)
  103. {
  104. //
  105. // create a global CUrlAgent object
  106. //
  107. if (NULL == (g_pUrlAgent = new CUrlAgent) ||
  108. FAILED(g_pUrlAgent->PopulateData()))
  109. {
  110. return FALSE;
  111. }
  112. DisableThreadLibraryCalls(hInstance);
  113. g_hinst = hInstance;
  114. gfInit_csCDM = SafeInitializeCriticalSection(&g_csCDM);
  115. gfInit_csGC = SafeInitializeCriticalSection(&g_csGlobalClasses);
  116. //
  117. // each global thread when started, should increase this counter
  118. // before exit, should decrease this counter,
  119. // such that ShutdownGlobalThreads() knows when it can return
  120. //
  121. g_lThreadCounter = 0;
  122. //
  123. // create a manual-reset event with init state non-signaled.
  124. // each global thread will check this event, when signalled, it means
  125. // the thread should exit ASAP.
  126. //
  127. g_evtNeedToQuit = CreateEvent(NULL, TRUE, FALSE, NULL);
  128. //
  129. // Initialize free logging
  130. //
  131. InitFreeLogging(_T("IUENGINE"));
  132. LogMessage("Starting");
  133. if (!gfInit_csCDM ||!gfInit_csGC)
  134. {
  135. LogError(E_FAIL, "InitializeCriticalSection");
  136. return FALSE;
  137. }
  138. }
  139. else if (dwReason == DLL_PROCESS_DETACH)
  140. {
  141. if (NULL != g_evtNeedToQuit)
  142. {
  143. CloseHandle(g_evtNeedToQuit);
  144. }
  145. if (NULL != g_pUrlAgent)
  146. {
  147. delete g_pUrlAgent;
  148. }
  149. if (gfInit_csCDM)
  150. {
  151. DeleteCriticalSection(&g_csCDM);
  152. }
  153. if (gfInit_csGC)
  154. {
  155. DeleteCriticalSection(&g_csGlobalClasses);
  156. }
  157. //
  158. // Shutdown free logging
  159. //
  160. LogMessage("Shutting down");
  161. TermFreeLogging();
  162. }
  163. return TRUE;
  164. }
  165. // ----------------------------------------------------------------------
  166. //
  167. // DLL API: CompleteSelfUpdateProcess()
  168. //
  169. // call by IUCtl.dll after downloading the new IUEngine.dll to complete
  170. // any selfupdate steps beyond update the engine itself.
  171. //
  172. // ----------------------------------------------------------------------
  173. HRESULT WINAPI CompleteSelfUpdateProcess()
  174. {
  175. LOG_Block("CompleteSelfUpdateProcess()");
  176. HRESULT hr = S_OK;
  177. // Nothing to do yet, just return S_OK.
  178. LogMessage("IUEngine update completed");
  179. return hr;
  180. }
  181. // ----------------------------------------------------------------------
  182. //
  183. // DLL API: PingIUEngineUpdateStatus
  184. //
  185. // Used by iuctl.dll to ping status of iuengine.dll supdate
  186. //
  187. // ----------------------------------------------------------------------
  188. HRESULT WINAPI PingIUEngineUpdateStatus(
  189. PHANDLE phQuitEvents, // ptr to handles for cancelling the operation
  190. UINT nQuitEventCount, // number of handles
  191. LPCTSTR ptszLiveServerUrl,
  192. LPCTSTR ptszCorpServerUrl,
  193. DWORD dwError, // error code
  194. LPCTSTR ptszClientName // client name string
  195. )
  196. {
  197. HRESULT hr;
  198. if (NULL == phQuitEvents || 1 > nQuitEventCount)
  199. {
  200. return E_INVALIDARG;
  201. }
  202. CUrlLog pingSvr(
  203. NULL == ptszClientName ? _T("iu") : ptszClientName,
  204. ptszLiveServerUrl,
  205. ptszCorpServerUrl);
  206. hr = pingSvr.Ping(
  207. TRUE, // force online
  208. URLLOGDESTINATION_DEFAULT, // going to live or corp WU server
  209. phQuitEvents, // pt to cancel events
  210. nQuitEventCount, // number of events
  211. URLLOGACTIVITY_Initialization, // activity
  212. SUCCEEDED(dwError) ? URLLOGSTATUS_Success : URLLOGSTATUS_Failed, // status code
  213. dwError // error code
  214. );
  215. return hr;
  216. }
  217. // ----------------------------------------------------------------------
  218. //
  219. // DLL API: CreateEngUpdateInstance()
  220. //
  221. // Returns a CEngUpdate instance pointer cast to HIUENGINE, or NULL if it fails.
  222. //
  223. // ----------------------------------------------------------------------
  224. HIUENGINE WINAPI CreateEngUpdateInstance()
  225. {
  226. LOG_Block("CreateEngUpdateInstance");
  227. return reinterpret_cast<HIUENGINE>(new CEngUpdate);
  228. }
  229. // ----------------------------------------------------------------------
  230. //
  231. // DLL API: DeleteEngUpdateInstance()
  232. //
  233. // Returns a CEngUpdate instance pointer, or NULL if it fails.
  234. //
  235. // ----------------------------------------------------------------------
  236. void WINAPI DeleteEngUpdateInstance(HIUENGINE hIUEngine)
  237. {
  238. LOG_Block("DeleteEngUpdateInstance");
  239. if (NULL != hIUEngine)
  240. {
  241. delete (reinterpret_cast<CEngUpdate*>(hIUEngine));
  242. }
  243. }
  244. // ----------------------------------------------------------------------
  245. //
  246. // DLL API: Stubs to export CEngUpdate functionality across DLL boundry
  247. //
  248. // ----------------------------------------------------------------------
  249. HRESULT EngGetSystemSpec(HIUENGINE hIUEngine, BSTR bstrXmlClasses, DWORD dwFlags, BSTR *pbstrXmlDetectionResult)
  250. {
  251. if (NULL == hIUEngine)
  252. {
  253. return E_INVALIDARG;
  254. }
  255. return (reinterpret_cast<CEngUpdate*>(hIUEngine))->GetSystemSpec(bstrXmlClasses, dwFlags, pbstrXmlDetectionResult);
  256. }
  257. HRESULT EngGetManifest(HIUENGINE hIUEngine, BSTR bstrXmlClientInfo, BSTR bstrXmlSystemSpec, BSTR bstrXmlQuery, DWORD dwFlags, BSTR *pbstrXmlCatalog)
  258. {
  259. if (NULL == hIUEngine)
  260. {
  261. return E_INVALIDARG;
  262. }
  263. return (reinterpret_cast<CEngUpdate*>(hIUEngine))->GetManifest(bstrXmlClientInfo, bstrXmlSystemSpec, bstrXmlQuery, dwFlags, pbstrXmlCatalog);
  264. }
  265. HRESULT EngDetect(HIUENGINE hIUEngine, BSTR bstrXmlCatalog, DWORD dwFlags, BSTR *pbstrXmlItems)
  266. {
  267. if (NULL == hIUEngine)
  268. {
  269. return E_INVALIDARG;
  270. }
  271. return (reinterpret_cast<CEngUpdate*>(hIUEngine))->Detect(bstrXmlCatalog, dwFlags, pbstrXmlItems);
  272. }
  273. HRESULT EngDownload(HIUENGINE hIUEngine,BSTR bstrXmlClientInfo, BSTR bstrXmlCatalog, BSTR bstrDestinationFolder,
  274. LONG lMode, IUnknown *punkProgressListener, HWND hWnd, BSTR *pbstrXmlItems)
  275. {
  276. if (NULL == hIUEngine)
  277. {
  278. return E_INVALIDARG;
  279. }
  280. return (reinterpret_cast<CEngUpdate*>(hIUEngine))->Download(bstrXmlClientInfo, bstrXmlCatalog, bstrDestinationFolder,
  281. lMode, punkProgressListener, hWnd, pbstrXmlItems);
  282. }
  283. HRESULT EngDownloadAsync(HIUENGINE hIUEngine,BSTR bstrXmlClientInfo, BSTR bstrXmlCatalog,
  284. BSTR bstrDestinationFolder, LONG lMode, IUnknown *punkProgressListener,
  285. HWND hWnd, BSTR bstrUuidOperation, BSTR *pbstrUuidOperation)
  286. {
  287. if (NULL == hIUEngine)
  288. {
  289. return E_INVALIDARG;
  290. }
  291. return (reinterpret_cast<CEngUpdate*>(hIUEngine))->DownloadAsync(bstrXmlClientInfo, bstrXmlCatalog,
  292. bstrDestinationFolder, lMode, punkProgressListener,
  293. hWnd, bstrUuidOperation, pbstrUuidOperation);
  294. }
  295. HRESULT EngInstall(HIUENGINE hIUEngine,
  296. BSTR bstrXmlClientInfo,
  297. BSTR bstrXmlCatalog,
  298. BSTR bstrXmlDownloadedItems,
  299. LONG lMode,
  300. IUnknown *punkProgressListener,
  301. HWND hWnd,
  302. BSTR *pbstrXmlItems)
  303. {
  304. if (NULL == hIUEngine)
  305. {
  306. return E_INVALIDARG;
  307. }
  308. return (reinterpret_cast<CEngUpdate*>(hIUEngine))->Install(bstrXmlClientInfo,
  309. bstrXmlCatalog,
  310. bstrXmlDownloadedItems,
  311. lMode,
  312. punkProgressListener,
  313. hWnd,
  314. pbstrXmlItems);
  315. }
  316. HRESULT EngInstallAsync(HIUENGINE hIUEngine,
  317. BSTR bstrXmlClientInfo,
  318. BSTR bstrXmlCatalog,
  319. BSTR bstrXmlDownloadedItems,
  320. LONG lMode,
  321. IUnknown *punkProgressListener,
  322. HWND hWnd,
  323. BSTR bstrUuidOperation,
  324. BSTR *pbstrUuidOperation)
  325. {
  326. if (NULL == hIUEngine)
  327. {
  328. return E_INVALIDARG;
  329. }
  330. return (reinterpret_cast<CEngUpdate*>(hIUEngine))->InstallAsync(bstrXmlClientInfo,
  331. bstrXmlCatalog,
  332. bstrXmlDownloadedItems,
  333. lMode,
  334. punkProgressListener,
  335. hWnd,
  336. bstrUuidOperation,
  337. pbstrUuidOperation);
  338. }
  339. HRESULT EngSetOperationMode(HIUENGINE hIUEngine, BSTR bstrUuidOperation, LONG lMode)
  340. {
  341. //
  342. // 502965 Windows Error Reporting bucket 2096553: Hang following NEWDEV.DLL!CancelDriverSearch
  343. //
  344. // Special-case this function for NULL == hIUEngine to allow access
  345. // by CDM to g_pCDMEngUpdate for CDM.DLL's in .NET Server / SP1 and later
  346. //
  347. if (NULL == hIUEngine)
  348. {
  349. if (NULL == g_pCDMEngUpdate)
  350. {
  351. return E_INVALIDARG;
  352. }
  353. else
  354. {
  355. return g_pCDMEngUpdate->SetOperationMode(bstrUuidOperation, lMode);
  356. }
  357. }
  358. else
  359. {
  360. //
  361. // Normal case (instance handle passed in)
  362. //
  363. return (reinterpret_cast<CEngUpdate*>(hIUEngine))->SetOperationMode(bstrUuidOperation, lMode);
  364. }
  365. }
  366. HRESULT EngGetOperationMode(HIUENGINE hIUEngine, BSTR bstrUuidOperation, LONG* plMode)
  367. {
  368. if (NULL == hIUEngine)
  369. {
  370. return E_INVALIDARG;
  371. }
  372. return (reinterpret_cast<CEngUpdate*>(hIUEngine))->GetOperationMode(bstrUuidOperation, plMode);
  373. }
  374. HRESULT EngGetHistory(HIUENGINE hIUEngine,
  375. BSTR bstrDateTimeFrom,
  376. BSTR bstrDateTimeTo,
  377. BSTR bstrClient,
  378. BSTR bstrPath,
  379. BSTR* pbstrLog)
  380. {
  381. if (NULL == hIUEngine)
  382. {
  383. return E_INVALIDARG;
  384. }
  385. return (reinterpret_cast<CEngUpdate*>(hIUEngine))->GetHistory(bstrDateTimeFrom, bstrDateTimeTo, bstrClient, bstrPath, pbstrLog);
  386. }
  387. HRESULT EngBrowseForFolder(HIUENGINE hIUEngine,
  388. BSTR bstrStartFolder,
  389. LONG flag,
  390. BSTR* pbstrFolder)
  391. {
  392. if (NULL == hIUEngine)
  393. {
  394. return E_INVALIDARG;
  395. }
  396. return (reinterpret_cast<CEngUpdate*>(hIUEngine))->BrowseForFolder(bstrStartFolder, flag, pbstrFolder);
  397. }
  398. HRESULT EngRebootMachine(HIUENGINE hIUEngine)
  399. {
  400. if (NULL == hIUEngine)
  401. {
  402. return E_INVALIDARG;
  403. }
  404. return (reinterpret_cast<CEngUpdate*>(hIUEngine))->RebootMachine();
  405. }
  406. // ----------------------------------------------------------------------
  407. //
  408. // DLL API: CreateGlobalCDMEngUpdateInstance()
  409. //
  410. // Initializes the single (global) CEngUpdate instance to be used by CDM
  411. //
  412. // ----------------------------------------------------------------------
  413. HRESULT WINAPI CreateGlobalCDMEngUpdateInstance()
  414. {
  415. LOG_Block("CreateGlobalCDMEngUpdateInstance");
  416. HRESULT hr = S_OK;
  417. EnterCriticalSection(&g_csCDM);
  418. if (NULL != g_pCDMEngUpdate)
  419. {
  420. LOG_Error(_T("Another thread in process is already using CDM functionality"));
  421. hr = E_ACCESSDENIED;
  422. goto CleanUp;
  423. }
  424. CleanUpFailedAllocSetHrMsg(g_pCDMEngUpdate = new CEngUpdate);
  425. CleanUp:
  426. LeaveCriticalSection(&g_csCDM);
  427. return hr;
  428. }
  429. // ----------------------------------------------------------------------
  430. //
  431. // DLL API: DeleteGlobalCDMEngUpdateInstance()
  432. //
  433. // Deletes the single (global) CEngUpdate instance used by CDM.
  434. //
  435. // ----------------------------------------------------------------------
  436. HRESULT WINAPI DeleteGlobalCDMEngUpdateInstance()
  437. {
  438. LOG_Block("DeleteGlobalCDMEngUpdateInstance");
  439. HRESULT hr = S_OK;
  440. EnterCriticalSection(&g_csCDM);
  441. //
  442. // Unfortunately (due to backwards compatibility with XPClient V4 CDM)
  443. // we can't tell if this was reached via CDM calling UnloadIUEngine
  444. // or some other client (e.g. AU) within the scope of a CDM instance.
  445. //
  446. // As a result, CDM's instance could get deleted at the wrong time
  447. // causing further calls to CDM to fail with E_INVALIDARG. Nothing
  448. // we can do about it because we reach hear after the other client's
  449. // instance is already deleted, so we can't use g_ulGlobalClassRefCount
  450. // as a guard against this. However AU and CDM should never be in the
  451. // same process, so we should be OK. CDM will coexist with instances
  452. // created via the iuctl COM object since they never call then old
  453. // ShutdownThreads export.
  454. //
  455. if (NULL != g_pCDMEngUpdate)
  456. {
  457. delete g_pCDMEngUpdate;
  458. g_pCDMEngUpdate = NULL;
  459. LOG_Driver(_T("CDM's global instance of CEngUpdate was deleted"));
  460. }
  461. //
  462. // ELSE this would be the case when iuctl!UnLoadIUEngine is
  463. // called from a client other than CDM, such as AU
  464. //
  465. LeaveCriticalSection(&g_csCDM);
  466. return hr;
  467. }
  468. CEngUpdate::CEngUpdate()
  469. {
  470. LOG_Block("CEngUpdate::CEngUpdate");
  471. HRESULT hr;
  472. //
  473. // each thread when start, should increase this counter
  474. // before exit, should decrease this counter,
  475. // such that ShutdownInstanceThreads() knows when it can return
  476. //
  477. m_lThreadCounter = 0;
  478. //
  479. // create a manual-reset event with init state non-signaled.
  480. // each thread will check this event, when signalled, it means
  481. // the thread should exit ASAP.
  482. //
  483. m_evtNeedToQuit = CreateEvent(NULL, TRUE, FALSE, NULL);
  484. //
  485. // If needed, create a global CSchemaKeys object, but always
  486. // keep global ref count so we know when to delete
  487. //
  488. EnterCriticalSection(&g_csGlobalClasses);
  489. //
  490. // Construct the global object
  491. //
  492. if (NULL == g_pGlobalSchemaKeys)
  493. {
  494. g_pGlobalSchemaKeys = new CSchemaKeys;
  495. }
  496. #if defined(DBG)
  497. //
  498. // We don't worry about this for practical purposes (will fail to construct
  499. // CEngUpdate before we reach this limit), but maybe on ia64 with huge
  500. // amounts of memory in a test scenario?
  501. //
  502. if (ULONG_MAX == g_ulGlobalClassRefCount)
  503. {
  504. LOG_Error(_T("g_ulGlobalClassRefCount is already ULONG_MAX and we are trying to add another"));
  505. }
  506. #endif
  507. g_ulGlobalClassRefCount++;
  508. LOG_Out(_T("g_ulGlobalClassRefCount is now %d"), g_ulGlobalClassRefCount);
  509. LeaveCriticalSection(&g_csGlobalClasses);
  510. }
  511. CEngUpdate::~CEngUpdate()
  512. {
  513. LOG_Block("CEngUpdate::~CEngUpdate");
  514. HRESULT hr;
  515. //
  516. // First shut down any outstanding threads
  517. //
  518. this->ShutdownInstanceThreads();
  519. if (NULL != m_evtNeedToQuit)
  520. {
  521. CloseHandle(m_evtNeedToQuit);
  522. }
  523. //
  524. // Always Uninitialize global CSchemaKeys object
  525. //
  526. EnterCriticalSection(&g_csGlobalClasses);
  527. #if defined(DBG)
  528. //
  529. // Paranoid check for coding error
  530. //
  531. if (0 == g_ulGlobalClassRefCount)
  532. {
  533. LOG_Error(_T("Unbalanced calls to CEngUpdate ctor and dtor"));
  534. }
  535. #endif
  536. g_ulGlobalClassRefCount--;
  537. LOG_Out(_T("g_ulGlobalClassRefCount is now %d"), g_ulGlobalClassRefCount);
  538. if (0 == g_ulGlobalClassRefCount)
  539. {
  540. //
  541. // The last CEngUpdate instance is going away, delete the
  542. // global CSchemaKeys object
  543. //
  544. if (NULL != g_pGlobalSchemaKeys)
  545. {
  546. delete g_pGlobalSchemaKeys;
  547. g_pGlobalSchemaKeys = NULL;
  548. }
  549. else
  550. {
  551. LOG_Error(_T("Unexpected NULL == g_pGlobalSchemaKeys"));
  552. }
  553. CleanupDownloadLib();
  554. }
  555. LeaveCriticalSection(&g_csGlobalClasses);
  556. }
  557. // ----------------------------------------------------------------------
  558. //
  559. // ShutdownInstanceThreads()
  560. //
  561. // called by CEngUpdate::~CEngUpdate to shut down any outstanding
  562. // threads before the control can end
  563. //
  564. // ----------------------------------------------------------------------
  565. void WINAPI CEngUpdate::ShutdownInstanceThreads()
  566. {
  567. LOG_Block("ShutdownInstanceThreads");
  568. if (NULL != m_evtNeedToQuit)
  569. {
  570. //
  571. // notify all threads go away
  572. //
  573. SetEvent(m_evtNeedToQuit);
  574. LOG_Out(_T("Shutdown event has been signalled"));
  575. //
  576. // wait all threads to quit
  577. // I don't think we should have a time limit here
  578. // since if we quit before all threads quit,
  579. // it's almost sure that AV will happen.
  580. //
  581. MSG msg;
  582. while (m_lThreadCounter > 0)
  583. {
  584. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  585. {
  586. TranslateMessage(&msg);
  587. DispatchMessage(&msg);
  588. }
  589. }
  590. LOG_Out(_T("All threads appeared gone."));
  591. //
  592. // reset the signal
  593. //
  594. ResetEvent(m_evtNeedToQuit);
  595. }
  596. }
  597. HRESULT CEngUpdate::RebootMachine()
  598. {
  599. LOG_Block("RebootMachine()");
  600. HRESULT hr = S_OK;
  601. DWORD dwRet;
  602. OSVERSIONINFO osvi;
  603. osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  604. GetVersionEx(&osvi);
  605. // Check if we're running on NT, if we are, we need to see if we have Privileges to Reboot
  606. if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)
  607. {
  608. HANDLE hToken;
  609. TOKEN_PRIVILEGES tkp;
  610. if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
  611. {
  612. dwRet = GetLastError();
  613. LOG_ErrorMsg(dwRet);
  614. hr = HRESULT_FROM_WIN32(dwRet);
  615. return hr;
  616. }
  617. LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid);
  618. tkp.PrivilegeCount = 1;
  619. tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  620. if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0))
  621. {
  622. dwRet = GetLastError();
  623. LOG_ErrorMsg(dwRet);
  624. hr = HRESULT_FROM_WIN32(dwRet);
  625. return hr;
  626. }
  627. }
  628. //
  629. // shutdown the system and force all applications to close
  630. //
  631. ExitWindowsEx(EWX_REBOOT, 0);
  632. return hr;
  633. }
  634. // ----------------------------------------------------------------------
  635. //
  636. // DLL Public API: ShutdownThreads()
  637. //
  638. // called by unlockengine form control to shut down any outstanding
  639. // threads before the control can end
  640. //
  641. // ----------------------------------------------------------------------
  642. void WINAPI ShutdownThreads()
  643. {
  644. LOG_Block("ShutdownThreads");
  645. //
  646. // To maintain XPClient V4 CDM compatibility with the iuengine.dll, we
  647. // use the following hack to create and delete the global instance
  648. // of CEngUpdate:
  649. //
  650. // After CDM calls LoadIUEngine, it calls SetGlobalOfflineFlag,
  651. // which we hook and call CreateGlkobalCDMEngUpdateInstance.
  652. //
  653. // When CDM calls UnLoadIUEngine, the function calls the old
  654. // single-instance ShutdownThreads export, which we now use
  655. // to call DeleteGlobalCDMEngUpdateInstance. CEngUpdate does
  656. // its own ShutdownThreads call in it's destructor.
  657. //
  658. DeleteGlobalCDMEngUpdateInstance();
  659. //
  660. // If we are the last client, shutdown the global threads
  661. //
  662. ShutdownGlobalThreads();
  663. }
  664. void WINAPI ShutdownGlobalThreads()
  665. {
  666. LOG_Block("ShutdownGlobalThreads");
  667. //
  668. // Now shut down any global (not CEngUpdate instance) threads
  669. // if there are no CEngUpdate instances left (last client is exiting)
  670. //
  671. if (NULL != g_evtNeedToQuit && 0 == g_ulGlobalClassRefCount)
  672. {
  673. //
  674. // notify all threads go away
  675. //
  676. SetEvent(g_evtNeedToQuit);
  677. LOG_Out(_T("Shutdown event has been signalled"));
  678. //
  679. // wait all threads to quit
  680. // I don't think we should have a time limit here
  681. // since if we quit before all threads quit,
  682. // it's almost sure that AV will happen.
  683. //
  684. MSG msg;
  685. while (g_lThreadCounter > 0)
  686. {
  687. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  688. {
  689. TranslateMessage(&msg);
  690. DispatchMessage(&msg);
  691. }
  692. }
  693. LOG_Out(_T("All global threads appear gone."));
  694. //
  695. // reset the signal
  696. //
  697. ResetEvent(g_evtNeedToQuit);
  698. }
  699. }
  700. COperationMgr::COperationMgr() : m_pOperationInfoList(NULL)
  701. {
  702. }
  703. COperationMgr::~COperationMgr()
  704. {
  705. PIUOPERATIONINFO pCurrent = m_pOperationInfoList;
  706. PIUOPERATIONINFO pNext;
  707. while (pCurrent)
  708. {
  709. pNext = pCurrent->pNext;
  710. if (NULL != pCurrent->bstrOperationResult)
  711. {
  712. SafeSysFreeString(pCurrent->bstrOperationResult);
  713. }
  714. HeapFree(GetProcessHeap(), 0, pCurrent);
  715. pCurrent = pNext;
  716. }
  717. }
  718. BOOL COperationMgr::AddOperation(LPCTSTR pszOperationID, LONG lUpdateMask)
  719. {
  720. PIUOPERATIONINFO pCurrent = m_pOperationInfoList;
  721. PIUOPERATIONINFO pLastOperation = NULL;
  722. PIUOPERATIONINFO pNewOperation = NULL;
  723. if (NULL == pszOperationID)
  724. {
  725. return FALSE;
  726. }
  727. // try to find the operation if its already here
  728. while (pCurrent)
  729. {
  730. pLastOperation = pCurrent;
  731. if (0 == StrCmpI(pszOperationID, pCurrent->szOperationUUID))
  732. {
  733. // match
  734. break;
  735. }
  736. pCurrent = pCurrent->pNext;
  737. }
  738. if (NULL == pCurrent)
  739. {
  740. // not found, or no operations in list yet
  741. pNewOperation = (IUOPERATIONINFO *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IUOPERATIONINFO));
  742. if (NULL == pNewOperation)
  743. {
  744. // out of memory, can't persist operation info..
  745. return FALSE;
  746. }
  747. lstrcpyn(pNewOperation->szOperationUUID, pszOperationID, ARRAYSIZE(pNewOperation->szOperationUUID));
  748. pNewOperation->lUpdateMask = lUpdateMask;
  749. if (NULL == m_pOperationInfoList)
  750. {
  751. m_pOperationInfoList = pNewOperation;
  752. }
  753. else
  754. {
  755. if (NULL != pLastOperation)
  756. {
  757. pLastOperation->pNext = pNewOperation;
  758. }
  759. }
  760. }
  761. else
  762. {
  763. // found the existing operation.. update it.
  764. pCurrent->lUpdateMask = lUpdateMask;
  765. SafeSysFreeString(pCurrent->bstrOperationResult); // reset result, new download request
  766. }
  767. return TRUE;
  768. }
  769. BOOL COperationMgr::FindOperation(LPCTSTR pszOperationID, PLONG plUpdateMask, BSTR *pbstrOperationResult)
  770. {
  771. BOOL fFound = FALSE;
  772. PIUOPERATIONINFO pCurrent = m_pOperationInfoList;
  773. if (NULL == pszOperationID)
  774. {
  775. return FALSE;
  776. }
  777. while (pCurrent)
  778. {
  779. if (0 == StrCmpI(pszOperationID, pCurrent->szOperationUUID))
  780. {
  781. fFound = TRUE;
  782. break;
  783. }
  784. pCurrent = pCurrent->pNext;
  785. }
  786. if (pCurrent)
  787. {
  788. if (plUpdateMask)
  789. *plUpdateMask = pCurrent->lUpdateMask;
  790. if (pbstrOperationResult)
  791. {
  792. if (NULL != pCurrent->bstrOperationResult)
  793. {
  794. *pbstrOperationResult = SysAllocString(pCurrent->bstrOperationResult);
  795. }
  796. else
  797. {
  798. *pbstrOperationResult = NULL;
  799. }
  800. }
  801. }
  802. return fFound;
  803. }
  804. BOOL COperationMgr::RemoveOperation(LPCTSTR pszOperationID)
  805. {
  806. PIUOPERATIONINFO pCurrent = m_pOperationInfoList;
  807. PIUOPERATIONINFO pLastOperation = NULL;
  808. if (NULL == pszOperationID)
  809. {
  810. return FALSE;
  811. }
  812. while (pCurrent)
  813. {
  814. if (0 == StrCmpI(pszOperationID, pCurrent->szOperationUUID))
  815. {
  816. break;
  817. }
  818. pLastOperation = pCurrent;
  819. pCurrent = pCurrent->pNext;
  820. }
  821. if (NULL == pCurrent)
  822. {
  823. return FALSE; // not found
  824. }
  825. else
  826. {
  827. if (pCurrent == m_pOperationInfoList) // only operation in list
  828. {
  829. m_pOperationInfoList = NULL;
  830. }
  831. else
  832. {
  833. pLastOperation->pNext = pCurrent->pNext;
  834. }
  835. }
  836. SafeSysFreeString(pCurrent->bstrOperationResult);
  837. HeapFree(GetProcessHeap(), 0, pCurrent);
  838. return TRUE;
  839. }
  840. BOOL COperationMgr::UpdateOperation(LPCTSTR pszOperationID, LONG lUpdateMask, BSTR bstrOperationResult)
  841. {
  842. PIUOPERATIONINFO pCurrent = m_pOperationInfoList;
  843. if (NULL == pszOperationID)
  844. {
  845. return FALSE;
  846. }
  847. while (pCurrent)
  848. {
  849. if (0 == StrCmpI(pszOperationID, pCurrent->szOperationUUID))
  850. {
  851. break;
  852. }
  853. pCurrent = pCurrent->pNext;
  854. }
  855. if (NULL == pCurrent)
  856. {
  857. return FALSE; // not found
  858. }
  859. pCurrent->lUpdateMask = lUpdateMask;
  860. SafeSysFreeString(pCurrent->bstrOperationResult);
  861. if (NULL != bstrOperationResult)
  862. {
  863. pCurrent->bstrOperationResult = SysAllocString(bstrOperationResult);
  864. }
  865. return TRUE;
  866. }
  867. /////////////////////////////////////////////////////////////////////////////
  868. // WUPostMessageAndBlock()
  869. //
  870. // Since COM doesn't like to have COM calls made while processing a SendMessage
  871. // message, we need to use PostMessage instead. However, using PostMessage
  872. // isn't synchronous, so what we need to do is create an event, do the post,
  873. // and wait on the event. When the WndProc at the other end of the post is
  874. // done, it will signal the event and we can unblock.
  875. // Input:
  876. // hwnd: hwnd to post to
  877. // Msg: message value
  878. // pevtData: pointer to an EventData structure to send as the LPARAM. We fill
  879. // in the hevDoneWithMessage field with the event we allocate.
  880. // Return:
  881. // TRUE if we successfully waited for the message processing to complete
  882. // and FALSE otherwise
  883. //
  884. /////////////////////////////////////////////////////////////////////////////
  885. BOOL WUPostEventAndBlock(HWND hwnd, UINT Msg, EventData *pevtData)
  886. {
  887. BOOL fRet = TRUE;
  888. // ok, so this is funky: if we are in the thread that owns the HWND, then
  889. // just maintain previous semantics and call SendMessage (yes, this means
  890. // effectively not fixing the bug for this case, but nobody should be
  891. // using the synchronus download or install functions.)
  892. if (GetWindowThreadProcessId(hwnd, NULL) == GetCurrentThreadId())
  893. {
  894. SendMessage(hwnd, Msg, 0, (LPARAM)pevtData);
  895. }
  896. else
  897. {
  898. DWORD dw;
  899. // alloc the event we're going to wait on & fill in the field of the
  900. // EventData structure. If this fails, we can't really go on, so
  901. // bail
  902. pevtData->hevDoneWithMessage = CreateEvent(NULL, FALSE, FALSE, NULL);
  903. if (pevtData->hevDoneWithMessage == NULL)
  904. return TRUE;
  905. // do the post
  906. PostMessage(hwnd, Msg, 0, (LPARAM)pevtData);
  907. // wait for the WndProc to signal that it's done.
  908. dw = WaitForSingleObject(pevtData->hevDoneWithMessage, INFINITE);
  909. // cleanup & return
  910. CloseHandle(pevtData->hevDoneWithMessage);
  911. pevtData->hevDoneWithMessage = NULL;
  912. fRet = (dw == WAIT_OBJECT_0);
  913. }
  914. return fRet;
  915. }