Source code of Windows XP (NT5)
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.

1263 lines
38 KiB

  1. #include "stdafx.h"
  2. #include "iudl.h"
  3. #include "selfupd.h"
  4. #include <iucommon.h>
  5. #include <osdet.h>
  6. #include <logging.h>
  7. #include <shlwapi.h>
  8. #include <fileutil.h>
  9. #include <iu.h>
  10. #include "update.h"
  11. #include <WaitUtil.h>
  12. #include <UrlAgent.h>
  13. #include <RedirectUtil.h>
  14. #include "wusafefn.h"
  15. inline DWORD StartSelfUpdateProcess(HANDLE evtQuit, CUpdate* pUpdateComClass, IUnknown* punkUpdateCompleteListener);
  16. DWORD WINAPI MonitorUpdateCompleteProc(LPVOID lpv);
  17. const TCHAR IDENTCAB[] = _T("iuident.cab");
  18. const CHAR SZ_SELF_UPDATE_CHECK[] = "Checking to see if new version of Windows Update software available";
  19. extern HANDLE g_hEngineLoadQuit;
  20. extern CIUUrlAgent *g_pIUUrlAgent;
  21. extern CRITICAL_SECTION g_csUrlAgent;
  22. typedef struct _MONITOR_DATA {
  23. HANDLE hProcess;
  24. HANDLE evtControlQuit;
  25. CUpdate* pUpdateComClass;
  26. IUnknown* punkCallback;
  27. } MONITOR_DATA, *PMONITOR_DATA;
  28. //
  29. // include declaration for interface IUpdateCompleteListener
  30. //
  31. #ifndef __IUpdateCompleteListener_INTERFACE_DEFINED__
  32. #define __IUpdateCompleteListener_INTERFACE_DEFINED__
  33. /* interface IUpdateCompleteListener */
  34. /* [unique][helpstring][uuid][object] */
  35. EXTERN_C const IID IID_IUpdateCompleteListener;
  36. #if defined(__cplusplus) && !defined(CINTERFACE)
  37. MIDL_INTERFACE("1C06B895-E4C8-48eb-9E03-15A53B43B6CA")
  38. IUpdateCompleteListener : public IUnknown
  39. {
  40. public:
  41. virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE OnComplete(
  42. /* [in] */ LONG lErrorCode) = 0;
  43. };
  44. #else /* C style interface */
  45. typedef struct IUpdateCompleteListenerVtbl
  46. {
  47. BEGIN_INTERFACE
  48. HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
  49. IUpdateCompleteListener * This,
  50. /* [in] */ REFIID riid,
  51. /* [iid_is][out] */ void **ppvObject);
  52. ULONG ( STDMETHODCALLTYPE *AddRef )(
  53. IUpdateCompleteListener * This);
  54. ULONG ( STDMETHODCALLTYPE *Release )(
  55. IUpdateCompleteListener * This);
  56. /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *OnComplete )(
  57. IUpdateCompleteListener * This,
  58. /* [in] */ LONG lErrorCode);
  59. END_INTERFACE
  60. } IUpdateCompleteListenerVtbl;
  61. interface IUpdateCompleteListener
  62. {
  63. CONST_VTBL struct IUpdateCompleteListenerVtbl *lpVtbl;
  64. };
  65. #ifdef COBJMACROS
  66. #define IUpdateCompleteListener_QueryInterface(This,riid,ppvObject) \
  67. (This)->lpVtbl -> QueryInterface(This,riid,ppvObject)
  68. #define IUpdateCompleteListener_AddRef(This) \
  69. (This)->lpVtbl -> AddRef(This)
  70. #define IUpdateCompleteListener_Release(This) \
  71. (This)->lpVtbl -> Release(This)
  72. #define IUpdateCompleteListener_OnComplete(This,lErrorCode) \
  73. (This)->lpVtbl -> OnComplete(This,lErrorCode)
  74. #endif /* COBJMACROS */
  75. #endif /* C style interface */
  76. /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IUpdateCompleteListener_OnComplete_Proxy(
  77. IUpdateCompleteListener * This,
  78. /* [in] */ LONG lErrorCode);
  79. void __RPC_STUB IUpdateCompleteListener_OnComplete_Stub(
  80. IRpcStubBuffer *This,
  81. IRpcChannelBuffer *_pRpcChannelBuffer,
  82. PRPC_MESSAGE _pRpcMessage,
  83. DWORD *_pdwStubPhase);
  84. #endif /* __IUpdateCompleteListener_INTERFACE_DEFINED__ */
  85. /////////////////////////////////////////////////////////////////////////////
  86. // SelfUpdateCheck()
  87. //
  88. // Determines if a SelfUpdate is needed, or if a SelfUpdate is already in process.
  89. // If one is already in process this will immediately return. If one is needed
  90. // it either perform the selfupdate (synchronous), or launch a rundll32.exe process
  91. // and have it call the BeginSelfUpdate() entrypoint to start the selfupdate (asynchronous)
  92. //
  93. // Return S_FALSE is asked not to update engine but this func found engine
  94. // needs to be updated.
  95. //
  96. /////////////////////////////////////////////////////////////////////////////
  97. HRESULT SelfUpdateCheck(BOOL fSynch, BOOL fStartUpdate, HANDLE evtQuit, CUpdate* pUpdateComClass, IUnknown* punkUpdateCompleteListener)
  98. {
  99. LOG_Block("SelfUpdateCheck()");
  100. HRESULT hr = S_OK;
  101. int iRet = 0;
  102. DWORD dwRet;
  103. DWORD dwWaitResult;
  104. DWORD dwStatus = 0;
  105. DWORD dwSize = 0;
  106. BOOL fSelfUpdateAvailable = FALSE;
  107. BOOL fAsyncSelfUpdateStarted = FALSE;
  108. BOOL fBetaSelfUpdate = FALSE;
  109. TCHAR szEngineClientVersion[64];
  110. TCHAR szEngineServerVersion[64];
  111. char szAnsiEngineServerVersion[64];
  112. TCHAR szIUDir[MAX_PATH];
  113. TCHAR szIdentFile[MAX_PATH];
  114. TCHAR szSystemDir[MAX_PATH+1];
  115. TCHAR szEngineDllPath[MAX_PATH+1];
  116. FILE_VERSION fvClientEngine, fvServerEngine;
  117. HANDLE hDownloadEvent = NULL;
  118. HANDLE hDownloadEventSync = NULL;
  119. HANDLE hMutex = NULL;
  120. HKEY hkey = NULL;
  121. MSG msg;
  122. DWORD dwTickStart, dwTickCurrent, dwTickEnd;
  123. HANDLE aHandles[2];
  124. if (!fSynch && fStartUpdate && NULL == pUpdateComClass)
  125. {
  126. //
  127. // if to do asynchronized update but the COM class pointer not passed in, then
  128. // even we succeed we can not pump up the init state of that class so that COM object
  129. // will still not usable.
  130. //
  131. hr = E_INVALIDARG;
  132. goto CleanUp;
  133. }
  134. // The synchronization between multiple processes running the IU control and doing the selfupdate
  135. // process is reasonably complex. We do this by using two synchronization objects. A named Mutex which protects
  136. // the 'selfupdate checking' process, and a named Event that protects against orphaned selfupdate processes caused
  137. // by reboots during a selfupdate.
  138. hDownloadEvent = CreateEvent(NULL, TRUE, TRUE, IU_EVENT_SELFUPDATE_IN_PROGRESS);
  139. if (NULL == hDownloadEvent)
  140. {
  141. dwRet = GetLastError();
  142. LOG_ErrorMsg(dwRet);
  143. hr = HRESULT_FROM_WIN32(dwRet);
  144. goto CleanUp;
  145. }
  146. hDownloadEventSync = CreateEvent(NULL, TRUE, FALSE, IU_EVENT_SELFUPDATE_EVENT_SYNC);
  147. if (NULL == hDownloadEventSync)
  148. {
  149. dwRet = GetLastError();
  150. LOG_ErrorMsg(dwRet);
  151. hr = HRESULT_FROM_WIN32(hr);
  152. goto CleanUp;
  153. }
  154. // First check to see if a selfupdate is already in process.. This is done by
  155. // checking a regkey for the current selfupdate state. We use a Mutex to synchronize
  156. // reading/writing to the registry key to ensure that only one process is attempting
  157. // the selfupdate. We don't care whether we had to create the mutex, or whether it was
  158. // already created, so as long as it succeeds, we'll use it.
  159. hMutex = CreateMutex(NULL, FALSE, IU_MUTEX_SELFUPDATE_REGCHECK);
  160. if (NULL == hMutex)
  161. {
  162. dwRet = GetLastError();
  163. LOG_ErrorMsg(dwRet);
  164. hr = HRESULT_FROM_WIN32(dwRet);
  165. goto CleanUp;
  166. }
  167. // We're ready to start the selfupdate check process. We'll request the mutex. This helper function
  168. // does a while loop checking every second (1000ms) for a timeout to elapse (calculated with GetTickCount()),
  169. // or for the object to be satisfied. This function should either return a timeout result, a WAIT_OBJECT_0
  170. // for the index 0 object, or else we got the event/mutex we were waiting for.
  171. aHandles[0] = g_hEngineLoadQuit; // index 0
  172. aHandles[1] = hMutex;
  173. dwWaitResult = MyMsgWaitForMultipleObjects(ARRAYSIZE(aHandles), aHandles, FALSE, /*30 seconds*/ 30000, QS_ALLINPUT);
  174. if (WAIT_TIMEOUT == dwWaitResult)
  175. {
  176. LOG_ErrorMsg(IU_SELFUPDATE_TIMEOUT);
  177. hr = IU_SELFUPDATE_TIMEOUT;
  178. goto CleanUp;
  179. }
  180. if (WAIT_OBJECT_0 == dwWaitResult)
  181. {
  182. hr = E_ABORT;
  183. LOG_ErrorMsg(hr);
  184. goto CleanUp;
  185. }
  186. if (ERROR_REQUEST_ABORTED == dwWaitResult) // this indicates we processed a QUIT message while waiting.
  187. {
  188. // not an error
  189. goto CleanUp;
  190. }
  191. dwRet = RegCreateKeyEx(HKEY_LOCAL_MACHINE, REGKEY_IUCTL, 0, _T(""), REG_OPTION_NON_VOLATILE,
  192. KEY_READ | KEY_WRITE, NULL, &hkey, &dwStatus);
  193. if (ERROR_SUCCESS != dwRet)
  194. {
  195. LOG_ErrorMsg(dwRet);
  196. hr = HRESULT_FROM_WIN32(dwRet);
  197. goto CleanUp;
  198. }
  199. // if the previous call to RegCreateKeyEx indicated it 'created' the key then we need to set the default
  200. // status to 0.
  201. if (REG_CREATED_NEW_KEY == dwStatus)
  202. {
  203. dwStatus = SELFUPDATE_NONE;
  204. dwRet = RegSetValueEx(hkey, REGVAL_SELFUPDATESTATUS, 0, REG_DWORD, (LPBYTE)&dwStatus, sizeof(dwStatus));
  205. }
  206. else
  207. {
  208. // Check for Beta IU SelfUpdate Handling Requested
  209. dwStatus = 0;
  210. dwSize = sizeof(dwStatus);
  211. dwRet = RegQueryValueEx(hkey, REGVAL_BETASELFUPDATE, NULL, NULL, (LPBYTE)&dwStatus, &dwSize);
  212. if (1 == dwStatus)
  213. {
  214. fBetaSelfUpdate = TRUE;
  215. }
  216. dwStatus = SELFUPDATE_NONE;
  217. dwSize = sizeof(dwStatus);
  218. dwRet = RegQueryValueEx(hkey, REGVAL_SELFUPDATESTATUS, NULL, NULL, (LPBYTE)&dwStatus, &dwSize);
  219. }
  220. // check the result of the QueryValue/SetValue call -
  221. if (ERROR_SUCCESS != dwRet && 2 != dwRet)
  222. {
  223. //
  224. // if dwRet == 2, it's the case that IUControl key exist, but SelfUpdate value not exist,
  225. //
  226. LOG_ErrorMsg(dwRet);
  227. hr = HRESULT_FROM_WIN32(dwRet);
  228. goto CleanUp;
  229. }
  230. if (WAIT_TIMEOUT != WaitForSingleObject(g_hEngineLoadQuit, 0))
  231. {
  232. LOG_ErrorMsg(E_ABORT);
  233. hr = E_ABORT;
  234. goto CleanUp;
  235. }
  236. switch (dwStatus)
  237. {
  238. case SELFUPDATE_NONE:
  239. {
  240. // First find out the version of the Engine on the server.
  241. GetIndustryUpdateDirectory(szIUDir);
  242. hr=PathCchCombine(szIdentFile,ARRAYSIZE(szIdentFile),szIUDir,IDENTTXT);
  243. if(FAILED(hr))
  244. {
  245. LOG_ErrorMsg(hr);
  246. goto CleanUp;
  247. }
  248. GetPrivateProfileString(fBetaSelfUpdate ? IDENT_IUBETASELFUPDATE : IDENT_IUSELFUPDATE,
  249. IDENT_VERSION,
  250. _T(""),
  251. szEngineServerVersion,
  252. ARRAYSIZE(szEngineServerVersion),
  253. szIdentFile);
  254. if ('\0' == szEngineServerVersion[0])
  255. {
  256. // no selfupdate available, no server version information
  257. hr = S_OK;
  258. goto CleanUp;
  259. }
  260. GetSystemDirectory(szSystemDir, ARRAYSIZE(szSystemDir));
  261. hr=PathCchCombine(szEngineDllPath,ARRAYSIZE(szEngineDllPath),szSystemDir, ENGINEDLL);
  262. if(FAILED(hr))
  263. {
  264. LOG_ErrorMsg(hr);
  265. goto CleanUp;
  266. }
  267. if (GetFileVersion(szEngineDllPath, &fvClientEngine))
  268. {
  269. // T2A requires Structured Exception Handling (because it uses alloca which can throw, so we avoid it and
  270. // do it the simple way.
  271. #ifdef UNICODE
  272. WideCharToMultiByte(CP_ACP, 0, szEngineServerVersion, -1, szAnsiEngineServerVersion,
  273. sizeof(szAnsiEngineServerVersion), NULL, NULL);
  274. if (!ConvertStringVerToFileVer(szAnsiEngineServerVersion, &fvServerEngine))
  275. #else
  276. if (!ConvertStringVerToFileVer(szEngineServerVersion, &fvServerEngine))
  277. #endif
  278. {
  279. LOG_ErrorMsg(IU_SELFUPDATE_FAILED);
  280. hr = IU_SELFUPDATE_FAILED;
  281. goto CleanUp;
  282. }
  283. iRet = CompareFileVersion(fvClientEngine, fvServerEngine);
  284. if (iRet == 0)
  285. {
  286. // IUEngine Versions are the same
  287. fSelfUpdateAvailable = FALSE;
  288. }
  289. else if (iRet > 0)
  290. {
  291. LOG_Internet(_T("Version of IUEngine on Client is NEWER than IUEngine on Server"));
  292. fSelfUpdateAvailable = FALSE;
  293. }
  294. else
  295. {
  296. // IUEngine Version on the Server is newer
  297. LOG_Internet(_T("New Version (%s) of IUEngine on Server Found."), szEngineServerVersion);
  298. #if defined(UNICODE) || defined(_UNICODE)
  299. LogMessage("IUEngine on Server is newer version (%ls)", szEngineServerVersion);
  300. #else
  301. LogMessage("IUEngine on Server is newer version (%s)", szEngineServerVersion);
  302. #endif
  303. fSelfUpdateAvailable = TRUE;
  304. }
  305. }
  306. else
  307. {
  308. // no version information found on local file, probably should do a selfupdate anyway.
  309. LOG_Internet(_T("No Version Information On Local IUEngine, SelfUpdating to Server Version"));
  310. fSelfUpdateAvailable = TRUE;
  311. }
  312. if (WAIT_TIMEOUT != WaitForSingleObject(g_hEngineLoadQuit, 0))
  313. {
  314. LOG_ErrorMsg(E_ABORT);
  315. hr = E_ABORT;
  316. goto CleanUp;
  317. }
  318. if (fSelfUpdateAvailable)
  319. {
  320. if (fStartUpdate)
  321. {
  322. dwStatus = SELFUPDATE_IN_PROGRESS;
  323. dwRet = RegSetValueEx(hkey, REGVAL_SELFUPDATESTATUS, 0, REG_DWORD, (LPBYTE)&dwStatus, sizeof(dwStatus));
  324. RegCloseKey(hkey); // done with the reg key now.
  325. hkey = NULL;
  326. // The default state of the DownloadEvent is Signaled (TRUE). If a Process is 'actually' working on the
  327. // SelfUpdate Process this Event Needs to be Reset to FALSE. Any time a client determines that a selfupdate
  328. // 'should' be in progress (from the regkey status) it should check the Event state, if it is signaled (TRUE)
  329. // then there was probably a reboot during the selfupdate, it should restart the selfupdate process itself.
  330. ResetEvent(hDownloadEvent); // mark that this Process will Perform the SelfUpdate by Resetting the Download Event
  331. ReleaseMutex(hMutex); // we are now done with the selfupdate check, both the event and the registry values are set
  332. // properly.
  333. CloseHandle(hMutex);
  334. hMutex = NULL;
  335. if (fSynch)
  336. {
  337. hr = BeginSelfUpdate();
  338. if (FAILED(hr))
  339. {
  340. LOG_Error(_T("BeginSelfUpdate Failed"));
  341. goto CleanUp;
  342. }
  343. }
  344. else
  345. {
  346. fAsyncSelfUpdateStarted = TRUE;
  347. // launch SelfUpdate Asynchronously.
  348. dwRet = StartSelfUpdateProcess(evtQuit, pUpdateComClass, punkUpdateCompleteListener); // inline function
  349. if (ERROR_SUCCESS != dwRet)
  350. {
  351. LOG_ErrorMsg(dwRet);
  352. hr = HRESULT_FROM_WIN32(dwRet);
  353. goto CleanUp;
  354. }
  355. }
  356. }
  357. else
  358. {
  359. //
  360. // in case we are asked to check update info only,
  361. // we signal back the result as S_FALSE for
  362. // engine update avail
  363. //
  364. hr = S_FALSE;
  365. }
  366. }
  367. else
  368. {
  369. //
  370. // somehow, no update needed. must be other process finished it.
  371. //
  372. if (fStartUpdate)
  373. {
  374. hr = IU_SELFUPDATE_USENEWDLL;
  375. goto CleanUp;
  376. }
  377. }
  378. break;
  379. }
  380. case SELFUPDATE_COMPLETE_UPDATE_BINARY_REQUIRED:
  381. {
  382. // As selfupdate has already been completed, but we're waiting to be able to rename the DLL.
  383. // In this case we'll tell the control to load the enginenew.dll.
  384. LOG_Internet(_T("SelfUpdate Already Complete, Updated Binary Available, Waiting for Rename."));
  385. hr = IU_SELFUPDATE_USENEWDLL;
  386. goto CleanUp;
  387. }
  388. case SELFUPDATE_IN_PROGRESS:
  389. default:
  390. {
  391. if (!fStartUpdate)
  392. {
  393. //
  394. // if asked to check update status but not to do actual update,
  395. // then this reg key flag tells the engine not update complete yet.
  396. //
  397. hr = S_FALSE; // signal TRUE for engine need update
  398. goto CleanUp;
  399. }
  400. if (WAIT_TIMEOUT != WaitForSingleObject(g_hEngineLoadQuit, 0))
  401. {
  402. LOG_ErrorMsg(E_ABORT);
  403. hr = E_ABORT;
  404. goto CleanUp;
  405. }
  406. // The RegKey indicates that a SelfUpdate is in Progress Now. We need to make sure this is
  407. // actually true. If a previous attempt at selfupdate was aborted because the machine rebooted
  408. // we could be in a false state. The 'default' state of teh DownloadEvent is Signaled (TRUE).
  409. // If the current State is TRUE then the SelfUpdate is actually 'NOT' in progress.
  410. // Find out the current state of the DownloadEvent
  411. dwWaitResult = WaitForSingleObject(hDownloadEvent, 0);
  412. if (WAIT_OBJECT_0 == dwWaitResult)
  413. {
  414. // The Event State is still Signaled (TRUE), so the selfupdate is not in progress
  415. ResetEvent(hDownloadEvent); // mark that this Process will Perform the SelfUpdate by Resetting the Download Event
  416. ReleaseMutex(hMutex);
  417. CloseHandle(hMutex);
  418. hMutex = NULL;
  419. if (fSynch)
  420. {
  421. hr = BeginSelfUpdate();
  422. if (FAILED(hr))
  423. {
  424. LOG_Error(_T("BeginSelfUpdate Failed"));
  425. goto CleanUp;
  426. }
  427. }
  428. else
  429. {
  430. fAsyncSelfUpdateStarted = TRUE;
  431. // launch SelfUpdate Asynchronously.
  432. dwRet = StartSelfUpdateProcess(evtQuit, pUpdateComClass, punkUpdateCompleteListener); // inline function
  433. if (ERROR_SUCCESS != dwRet)
  434. {
  435. LOG_ErrorMsg(dwRet);
  436. hr = HRESULT_FROM_WIN32(dwRet);
  437. goto CleanUp;
  438. }
  439. }
  440. }
  441. else
  442. {
  443. // The Event State is not Signaled (FALSE), everythings ok with the current selfupdate
  444. // Now we need to either start a thread to wait for the complete and immediately return, 'or'
  445. // wait for the selfupdate to finish (synchronous or asynchronous selfupdate).
  446. if (fSynch)
  447. {
  448. // we need to wait for the event to change back to signaled state. Should indicate the
  449. // selfupdate is finished.
  450. // before we start the wait, we will release our mutex, since we really aren't doing anything
  451. // with the registry anymore
  452. ReleaseMutex(hMutex);
  453. CloseHandle(hMutex);
  454. hMutex = NULL;
  455. aHandles[0] = g_hEngineLoadQuit; // index 0
  456. aHandles[1] = hDownloadEvent;
  457. dwWaitResult = MyMsgWaitForMultipleObjects(ARRAYSIZE(aHandles), aHandles, FALSE, /*120 seconds*/ 120000, QS_ALLINPUT);
  458. if (WAIT_TIMEOUT == dwWaitResult)
  459. {
  460. // Timed Out Waiting for SelfUpdate to Complete. May just be really slow, go ahead
  461. // and use the old DLL for now.
  462. LOG_ErrorMsg(IU_SELFUPDATE_TIMEOUT);
  463. hr = IU_SELFUPDATE_TIMEOUT;
  464. goto CleanUp;
  465. }
  466. if (ERROR_REQUEST_ABORTED == dwWaitResult)
  467. {
  468. goto CleanUp;
  469. }
  470. if (WAIT_OBJECT_0 == dwWaitResult)
  471. {
  472. //
  473. // index 0 (g_hEngineLoadQuit) was signaled
  474. //
  475. hr = E_ABORT;
  476. LOG_ErrorMsg(hr);
  477. goto CleanUp;
  478. }
  479. hr = IU_SELFUPDATE_USENEWDLL;
  480. goto CleanUp;
  481. }
  482. else
  483. {
  484. //
  485. // asked to update in async mode, but found someone else
  486. // already started the update process
  487. //
  488. PMONITOR_DATA pMonitorData = (PMONITOR_DATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MONITOR_DATA));
  489. if (NULL == pMonitorData)
  490. {
  491. hr = E_OUTOFMEMORY;
  492. LOG_ErrorMsg(hr);
  493. goto CleanUp;
  494. }
  495. else
  496. {
  497. DWORD dwThreadId = 0;
  498. hr = S_OK;
  499. pMonitorData->hProcess = hDownloadEvent;
  500. pMonitorData->evtControlQuit = evtQuit;
  501. pMonitorData->pUpdateComClass = pUpdateComClass;
  502. pMonitorData->punkCallback = punkUpdateCompleteListener;
  503. HANDLE hThread = NULL;
  504. hThread = CreateThread(NULL, 0, MonitorUpdateCompleteProc, pMonitorData, 0, &dwThreadId);
  505. if (NULL == hThread)
  506. {
  507. HeapFree(GetProcessHeap(), 0, pMonitorData);
  508. //
  509. // otherwise, the memory allocated will be released by the thread procedure
  510. //
  511. hr = HRESULT_FROM_WIN32(GetLastError());
  512. LOG_ErrorMsg(hr);
  513. goto CleanUp;
  514. }
  515. else
  516. {
  517. CloseHandle(hThread); // don't leak the thread handle
  518. }
  519. }
  520. goto CleanUp;
  521. }
  522. }
  523. break;
  524. }
  525. }
  526. CleanUp:
  527. // always release the mutex, there are cases during the selfupdate check that can fail, in which
  528. // case they fall through to here. If the mutex is free'd when its not ours the call simply fails.
  529. if (NULL != hMutex)
  530. {
  531. ReleaseMutex(hMutex);
  532. CloseHandle(hMutex);
  533. hMutex = NULL;
  534. }
  535. if (fAsyncSelfUpdateStarted)
  536. {
  537. // if an Asynchronous SelfUpdate has been started we want to wait for it to
  538. // get the DownloadEvent before we close it. There would be a possible Race
  539. // condition where the selfupdate process would 'create' the event, instead
  540. // of 'opening' the event in its 'reset' state. If this happened another
  541. // process could come along, find that the event state is signaled instead of
  542. // reset and assume the selfupdate process had terminated.
  543. // Wait for the DownloadEventSync event to be signaled. We'll put a timeout of
  544. // 30 seconds (should be more than sufficient for the new process to start and
  545. // set the event).
  546. aHandles[0] = g_hEngineLoadQuit; // index 0
  547. aHandles[1] = hDownloadEventSync;
  548. dwWaitResult = MyMsgWaitForMultipleObjects(ARRAYSIZE(aHandles), aHandles, FALSE, /*30 seconds*/ 30000, QS_ALLINPUT);
  549. if (WAIT_TIMEOUT == dwWaitResult)
  550. {
  551. // go ahead and log that we timed out waiting.
  552. LOG_Internet(_T("Timeout Elapsed while waiting for SelfUpdate Process to open the DownloadSync Event"));
  553. }
  554. if (ERROR_REQUEST_ABORTED == dwWaitResult)
  555. {
  556. // go ahead and log that a WM_QUIT, WM_CLOSE, or WM_DESTROY.
  557. LOG_Internet(_T("Received WM_QUIT, WM_CLOSE, or WM_DESTROY while waiting for SelfUpdate Process to open the DownloadSync Event"));
  558. }
  559. if (WAIT_OBJECT_0 == dwWaitResult)
  560. {
  561. LOG_Internet(_T("g_hEngineLoadQuit signaled while waiting for SelfUpdate Process to open the DownloadSync Event"));
  562. hr = E_ABORT;
  563. }
  564. }
  565. if (NULL != hDownloadEvent)
  566. {
  567. CloseHandle(hDownloadEvent);
  568. hDownloadEvent = NULL;
  569. }
  570. if (NULL != hDownloadEventSync)
  571. {
  572. CloseHandle(hDownloadEventSync);
  573. hDownloadEventSync = NULL;
  574. }
  575. if (NULL != hkey)
  576. {
  577. RegCloseKey(hkey);
  578. }
  579. if (SUCCEEDED(hr))
  580. {
  581. LogMessage(SZ_SELF_UPDATE_CHECK);
  582. }
  583. else
  584. {
  585. LogError(hr, SZ_SELF_UPDATE_CHECK);
  586. }
  587. return hr;
  588. }
  589. inline DWORD StartSelfUpdateProcess(HANDLE evtQuit, CUpdate* pUpdateComClass, IUnknown* punkUpdateCompleteListener)
  590. {
  591. TCHAR szRunDll32Path[MAX_PATH+1];
  592. TCHAR szCommandLine[MAX_PATH+1];
  593. TCHAR szDirectory[MAX_PATH+1];
  594. PROCESS_INFORMATION pi;
  595. STARTUPINFO si;
  596. DWORD dwRet = ERROR_SUCCESS;
  597. DWORD dwThreadId;
  598. PMONITOR_DATA pMonitorData;
  599. HRESULT hr=S_OK;
  600. if (0 == GetSystemDirectory(szDirectory, ARRAYSIZE(szDirectory)))
  601. {
  602. return GetLastError();
  603. }
  604. hr=PathCchCombine(szRunDll32Path,ARRAYSIZE(szRunDll32Path),szDirectory, RUNDLL32);
  605. if(FAILED(hr))
  606. return HRESULT_CODE(hr);
  607. if (!FileExists(szRunDll32Path))
  608. {
  609. // probably running on W9x, look in the Windows Folder Instead
  610. if (0 == GetWindowsDirectory(szDirectory, ARRAYSIZE(szDirectory)))
  611. {
  612. return GetLastError();
  613. }
  614. hr=PathCchCombine(szRunDll32Path,ARRAYSIZE(szRunDll32Path),szDirectory, RUNDLL32);
  615. if(FAILED(hr))
  616. return HRESULT_CODE(hr);
  617. if (!FileExists(szRunDll32Path))
  618. {
  619. // we're toast.. can't find rundll32.exe .. bye-bye
  620. return ERROR_FILE_NOT_FOUND;
  621. }
  622. }
  623. // now form the path to the iuctl.dll .. we'll trust nothing and 'get' the module filename
  624. // instead of assuming its in the system folder.
  625. GetModuleFileName(GetModuleHandle(IUCTL), szDirectory, ARRAYSIZE(szDirectory));
  626. hr=StringCchPrintfEx(szCommandLine,ARRAYSIZE(szCommandLine),NULL,NULL,MISTSAFE_STRING_FLAGS,_T("\"%s\" \"%s\"%s"), szRunDll32Path, szDirectory, RUNDLLCOMMANDLINE);
  627. if(FAILED(hr))
  628. return HRESULT_CODE(hr);
  629. ZeroMemory(&si, sizeof(si));
  630. si.cb = sizeof(si);
  631. if (!CreateProcess(NULL, szCommandLine, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi))
  632. {
  633. dwRet = GetLastError();
  634. return dwRet;
  635. }
  636. //
  637. // create a thread that can be used to monitor the completeness of
  638. // this update process
  639. //
  640. pMonitorData = (PMONITOR_DATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MONITOR_DATA));
  641. if (NULL != pMonitorData)
  642. {
  643. pMonitorData->hProcess = pi.hProcess; // return process handle so we know when it's done
  644. pMonitorData->evtControlQuit = evtQuit;
  645. pMonitorData->pUpdateComClass = pUpdateComClass;
  646. pMonitorData->punkCallback = punkUpdateCompleteListener;
  647. HANDLE hThread = NULL;
  648. hThread = CreateThread(NULL, 0, MonitorUpdateCompleteProc, pMonitorData, 0, &dwThreadId);
  649. if (NULL == hThread)
  650. {
  651. HeapFree(GetProcessHeap(), 0, pMonitorData);
  652. //
  653. // otherwise, the memory allocated will be released by the thread procedure
  654. //
  655. }
  656. else
  657. {
  658. CloseHandle(hThread);
  659. }
  660. }
  661. return dwRet;
  662. }
  663. /////////////////////////////////////////////////////////////////////////////
  664. //
  665. // thread procedure to determine when to signal caller
  666. // the update process has be gone
  667. //
  668. /////////////////////////////////////////////////////////////////////////////
  669. DWORD WINAPI MonitorUpdateCompleteProc(LPVOID lpv)
  670. {
  671. HRESULT hr;
  672. HWND hWnd;
  673. CUpdate* pUpdateClass = NULL;
  674. IUnknown* punkCallback = NULL;
  675. PMONITOR_DATA pData;
  676. HANDLE hEvents[2];
  677. DWORD dwRet, dwErr = 0;
  678. MSG msg;
  679. LOG_Block("MonitorUpdateCompleteProc");
  680. if (NULL == lpv)
  681. {
  682. LOG_ErrorMsg(E_INVALIDARG);
  683. return 0x1; // impossible!
  684. }
  685. pData = (PMONITOR_DATA) lpv;
  686. hEvents[0] = pData->hProcess;
  687. hEvents[1] = pData->evtControlQuit;
  688. punkCallback = pData->punkCallback;
  689. pUpdateClass = pData->pUpdateComClass;
  690. if (pUpdateClass)
  691. {
  692. hWnd = pUpdateClass->GetEventWndClass().GetEvtHWnd();
  693. }
  694. //
  695. // this data allcoated by parent thread, we are responsible to release it
  696. //
  697. HeapFree(GetProcessHeap(), 0, lpv);
  698. if (NULL == pUpdateClass)
  699. {
  700. //
  701. // even we catch the update completeness, without this pointer we can not
  702. // modify the init state so this COM will still not usable. We bail
  703. //
  704. return 0;
  705. }
  706. //
  707. // wait till process gone or quit signal
  708. //
  709. while (TRUE)
  710. {
  711. dwRet = MsgWaitForMultipleObjects(ARRAYSIZE(hEvents), hEvents, FALSE, INFINITE, QS_ALLINPUT);
  712. switch (dwRet)
  713. {
  714. case WAIT_OBJECT_0:
  715. //
  716. // process done, get return code
  717. //
  718. GetExitCodeProcess(hEvents[0], &dwErr);
  719. if (0x0 == dwErr)
  720. {
  721. //
  722. // we are done with no error, then pump the
  723. // init state to ready state
  724. //
  725. dwErr = pUpdateClass->ChangeControlInitState(2);
  726. }
  727. //
  728. // signal event
  729. //
  730. if (NULL != hWnd)
  731. {
  732. PostMessage(hWnd, UM_EVENT_SELFUPDATE_COMPLETE, 0, (LPARAM)dwErr);
  733. LOG_Out(_T("Fired event OnComplete()"));
  734. }
  735. //
  736. // signal callback
  737. //
  738. if (NULL != punkCallback)
  739. {
  740. IUpdateCompleteListener* pCallback = NULL;
  741. if (FAILED(hr = punkCallback->QueryInterface(IID_IUpdateCompleteListener, (void**) &pCallback)))
  742. {
  743. LOG_ErrorMsg(hr);
  744. }
  745. else
  746. {
  747. pCallback->OnComplete(dwErr);
  748. pCallback->Release();
  749. LOG_Out(_T("Returned from callback API OnComplete()"));
  750. }
  751. }
  752. return 0;
  753. break;
  754. case WAIT_OBJECT_0 + 1:
  755. //
  756. // got global Quit event
  757. //
  758. LOG_Out(_T("Found quit event!"));
  759. return 1;
  760. break;
  761. case WAIT_OBJECT_0 + ARRAYSIZE(hEvents):
  762. //
  763. // got message
  764. //
  765. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  766. {
  767. if (WM_QUIT == msg.message)
  768. {
  769. LOG_Out(_T("Found WM_QUIT message. Leaving..."));
  770. return 1;
  771. }
  772. DispatchMessage(&msg);
  773. }
  774. break;
  775. }
  776. }
  777. return 0; // never reach here
  778. }
  779. HRESULT BeginSelfUpdate()
  780. {
  781. LOG_Block("BeginSelfUpdate()");
  782. DWORD dwRet;
  783. DWORD dwStatus;
  784. DWORD dwSize;
  785. HRESULT hr = S_OK;
  786. HKEY hkey = NULL; // PreFast
  787. TCHAR szIUDir[MAX_PATH+1];
  788. TCHAR szLocalPath[MAX_PATH+1];
  789. TCHAR szSystemDir[MAX_PATH+1];
  790. TCHAR szTargetDLLName[MAX_PATH+1];
  791. LPTSTR pszSelfUpdateCabUrl = NULL;
  792. HANDLE hDownloadEventSync = NULL; // PreFast
  793. HANDLE hDownloadEvent = NULL; // PreFast
  794. HANDLE hMutex = NULL; // PreFast
  795. MSG msg;
  796. BOOL fBetaSelfUpdate = FALSE;
  797. HMODULE hNewEngine = NULL;
  798. PFN_CompleteSelfUpdateProcess fpnCompleteSelfUpdateProcess = NULL;
  799. // The SelfUpdate process is done while the SELFUPDATE_IN_PROGRESS event is 'reset'. We
  800. // do everything we can to make sure we 'open' this event in the reset state, but if for
  801. // some reason the event is not there we will create it in the reset state.
  802. hDownloadEvent = CreateEvent(NULL, TRUE, FALSE, IU_EVENT_SELFUPDATE_IN_PROGRESS);
  803. if (NULL == hDownloadEvent)
  804. {
  805. dwRet = GetLastError();
  806. LOG_ErrorMsg(dwRet);
  807. hr = HRESULT_FROM_WIN32(dwRet);
  808. goto CleanUp;
  809. }
  810. // The SELFUPDATE_EVENT_SYNC is the mechanism we use to 'try' to keep the SELFUPDATE_IN_PROGRESS
  811. // event alive and in the 'reset' state until this function can open it and keep it in that state.
  812. // This should prevent a race condition caused when the SelfUpdateCheck function closes the Event
  813. // before this function can open it. If this happens another process could start the selfupdate check
  814. // process and find the SELFUPDATE_IN_PROGRESS event in the wrong state.
  815. hDownloadEventSync = CreateEvent(NULL, TRUE, FALSE, IU_EVENT_SELFUPDATE_EVENT_SYNC);
  816. if (NULL == hDownloadEventSync)
  817. {
  818. dwRet = GetLastError();
  819. LOG_ErrorMsg(dwRet);
  820. hr = HRESULT_FROM_WIN32(hr);
  821. goto CleanUp;
  822. }
  823. // tell the SelfUpdateCheck client that we have the SELFUPDATE_IN_PROGRESS event, so it can
  824. // release its handle to it.
  825. SetEvent(hDownloadEventSync);
  826. // release our handle to the SELFUPDATE_EVENT_SYNC event.
  827. CloseHandle(hDownloadEventSync);
  828. hDownloadEventSync = NULL;
  829. // Get Self-Update Server URL
  830. pszSelfUpdateCabUrl = (LPTSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, INTERNET_MAX_URL_LENGTH * sizeof(TCHAR));
  831. CleanUpFailedAllocSetHrMsg(pszSelfUpdateCabUrl);
  832. EnterCriticalSection(&g_csUrlAgent);
  833. if (FAILED(hr = g_pIUUrlAgent->PopulateData()))
  834. {
  835. LOG_Error(_T("failed to populate data in g_pIUUrlAgent (%lx)"), hr);
  836. }
  837. LeaveCriticalSection(&g_csUrlAgent);
  838. CleanUpIfFailedAndMsg(g_pIUUrlAgent->GetSelfUpdateServer(pszSelfUpdateCabUrl, INTERNET_MAX_URL_LENGTH));
  839. // Download the SelfUpdate CAB
  840. GetIndustryUpdateDirectory(szIUDir);
  841. hr=PathCchCombine(szLocalPath,ARRAYSIZE(szLocalPath),szIUDir, ENGINECAB);
  842. if (FAILED(hr))
  843. {
  844. LOG_ErrorMsg(hr);
  845. goto CleanUp;
  846. }
  847. hr = IUDownloadFile(pszSelfUpdateCabUrl, szLocalPath, TRUE, TRUE);
  848. if (FAILED(hr))
  849. {
  850. LOG_ErrorMsg(hr);
  851. goto CleanUp;
  852. }
  853. DeleteFile(szLocalPath); // clean up the CAB in the IU Folder
  854. // Now we 'should' have IUENGINE.DLL from the SelfUpdate CAB in the IU Folder.
  855. // IUENGINE.DLL is self-signed so we don't need a Catalog File (IUENGINE.CAT)
  856. // NTRAID#NTBUG9-435844-2001/07/16-waltw WU: IU: IUCTL: Remove code to register CAT file when updating iuengine.dll
  857. // Copy the DLL to the new Engine DLL Name
  858. GetSystemDirectory(szSystemDir, ARRAYSIZE(szSystemDir));
  859. hr=PathCchCombine(szTargetDLLName,ARRAYSIZE(szTargetDLLName), szSystemDir, ENGINENEWDLL);
  860. if (FAILED(hr))
  861. {
  862. LOG_ErrorMsg(hr);
  863. goto CleanUp;
  864. }
  865. hr=PathCchCombine(szLocalPath,ARRAYSIZE(szLocalPath),szIUDir, ENGINEDLL);
  866. if (FAILED(hr))
  867. {
  868. LOG_ErrorMsg(hr);
  869. goto CleanUp;
  870. }
  871. CopyFile(szLocalPath, szTargetDLLName, FALSE);
  872. DeleteFile(szLocalPath); // clean up the DLL in the IU Folder now that its been copied to the systemdir.
  873. // Now We've successfully downloaded the new IUEngine - we need to call an entry point in this Engine to
  874. // Chain any SelfUpdate steps the Engine needs to do. It is possible the engine may need to download an
  875. // additional component, or do some registry configuration work. So we'll load the new Engine and call the
  876. // CompleteSelfUpdateProcess entrypoint.
  877. //
  878. // We don't need LoadLibraryFromSystemDir here since we have the full path and
  879. // iuengine isn't a Side-By-Side module.
  880. hNewEngine = LoadLibrary(szTargetDLLName);
  881. if (NULL == hNewEngine)
  882. {
  883. dwRet = GetLastError();
  884. LOG_ErrorMsg(dwRet);
  885. hr = HRESULT_FROM_WIN32(dwRet);
  886. goto CleanUp;
  887. }
  888. fpnCompleteSelfUpdateProcess = (PFN_CompleteSelfUpdateProcess) GetProcAddress(hNewEngine, "CompleteSelfUpdateProcess");
  889. if (NULL == fpnCompleteSelfUpdateProcess)
  890. {
  891. LOG_ErrorMsg(ERROR_INVALID_DLL);
  892. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DLL);
  893. goto CleanUp;
  894. }
  895. // Call the New Engine to let it finish its SelfUpdate Process
  896. hr = fpnCompleteSelfUpdateProcess();
  897. if (FAILED(hr))
  898. {
  899. LOG_ErrorMsg(hr);
  900. goto CleanUp;
  901. }
  902. // Now update the registry information about the SelfUpdate process being Complete
  903. hMutex = CreateMutex(NULL, FALSE, IU_MUTEX_SELFUPDATE_REGCHECK);
  904. if (NULL == hMutex)
  905. {
  906. dwRet = GetLastError();
  907. LOG_ErrorMsg(dwRet);
  908. hr = HRESULT_FROM_WIN32(dwRet);
  909. goto CleanUp;
  910. }
  911. HANDLE aHandles[2];
  912. aHandles[0] = g_hEngineLoadQuit; // index 0
  913. aHandles[1] = hMutex;
  914. // Finish the Registry Settings
  915. dwRet= MyMsgWaitForMultipleObjects(ARRAYSIZE(aHandles), aHandles, FALSE, /*30 seconds*/ 30000, QS_ALLINPUT);
  916. if (WAIT_TIMEOUT == dwRet)
  917. {
  918. LOG_Internet(_T("Timed Out while waiting for IU_MUTEX_SELFUPDATE_REGCHECK Mutex"));
  919. // NOTE: If we failed to RegCheck Mutex after 30 seconds something is probably wrong in another
  920. // process. However, we don't want to leave the registry showing a selfupdate is still in progress
  921. // so we'll just go ahead and update the registry.
  922. }
  923. if (ERROR_REQUEST_ABORTED == dwRet)
  924. {
  925. goto CleanUp;
  926. }
  927. if (WAIT_OBJECT_0 == dwRet)
  928. {
  929. //
  930. // index 0 (g_hEngineLoadQuit) was signaled
  931. //
  932. hr = E_ABORT;
  933. LOG_ErrorMsg(hr);
  934. goto CleanUp;
  935. }
  936. dwRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_IUCTL, 0, KEY_READ | KEY_WRITE, &hkey);
  937. if (ERROR_SUCCESS != dwRet)
  938. {
  939. LOG_ErrorMsg(dwRet);
  940. hr = HRESULT_FROM_WIN32(dwRet);
  941. goto CleanUp;
  942. }
  943. dwStatus = SELFUPDATE_COMPLETE_UPDATE_BINARY_REQUIRED;
  944. dwRet = RegSetValueEx(hkey, REGVAL_SELFUPDATESTATUS, 0, REG_DWORD, (LPBYTE)&dwStatus, sizeof(dwStatus));
  945. if (ERROR_SUCCESS != dwRet)
  946. {
  947. LOG_ErrorMsg(dwRet);
  948. hr = HRESULT_FROM_WIN32(dwRet);
  949. }
  950. CleanUp:
  951. if (NULL != hNewEngine)
  952. {
  953. FreeLibrary(hNewEngine);
  954. hNewEngine = NULL;
  955. }
  956. if (NULL != hMutex)
  957. {
  958. ReleaseMutex(hMutex); // doesn't matter whether we got the mutex or not, if we didn't this will just fail.
  959. CloseHandle(hMutex);
  960. hMutex = NULL;
  961. }
  962. if (NULL != hDownloadEvent)
  963. {
  964. // Tell any clients that are waiting for the selfupdate process to finish that we're now done.
  965. SetEvent(hDownloadEvent);
  966. CloseHandle(hDownloadEvent);
  967. hDownloadEvent = NULL;
  968. }
  969. if (NULL != hDownloadEventSync)
  970. {
  971. CloseHandle(hDownloadEventSync);
  972. hDownloadEventSync = NULL;
  973. }
  974. if (NULL != hkey)
  975. {
  976. RegCloseKey(hkey);
  977. }
  978. SafeHeapFree(pszSelfUpdateCabUrl);
  979. return hr;
  980. }
  981. HRESULT PingEngineUpdate(
  982. HMODULE hEngineModule,
  983. PHANDLE phQuitEvents,
  984. UINT nQuitEventCount,
  985. LPCTSTR ptszLiveServerUrl,
  986. LPCTSTR ptszCorpServerUrl,
  987. DWORD dwError,
  988. LPCTSTR ptszClientName
  989. )
  990. {
  991. LOG_Block("PingEngineUpdate");
  992. HRESULT hr;
  993. BOOL fFreeEngModule = FALSE;
  994. PFN_PingIUEngineUpdateStatus pfnPingIUEngineUpdateStatus;
  995. if (NULL == hEngineModule)
  996. {
  997. // try loading iuenginenew.dll first
  998. hEngineModule = LoadLibraryFromSystemDir(_T("iuenginenew.dll"));
  999. if (NULL != hEngineModule)
  1000. {
  1001. LOG_Internet(_T("Loaded IUENGINENEW.DLL"));
  1002. }
  1003. else
  1004. {
  1005. LOG_Internet(_T("Loaded IUENGINE.DLL"));
  1006. hEngineModule = LoadLibraryFromSystemDir(_T("iuengine.dll"));
  1007. }
  1008. //
  1009. // If load engine succeeded, we'll need to unload it later
  1010. //
  1011. if (NULL != hEngineModule)
  1012. {
  1013. fFreeEngModule = TRUE;
  1014. }
  1015. else
  1016. {
  1017. hr = HRESULT_FROM_WIN32(GetLastError());
  1018. LOG_ErrorMsg(hr);
  1019. }
  1020. }
  1021. //
  1022. // If we got an iuengine.dll (either passed in or loaded ourselves), call PingIUEngineUpdateStatus
  1023. //
  1024. if (NULL != hEngineModule)
  1025. {
  1026. pfnPingIUEngineUpdateStatus = (PFN_PingIUEngineUpdateStatus) GetProcAddress(hEngineModule, "PingIUEngineUpdateStatus");
  1027. if (NULL != pfnPingIUEngineUpdateStatus)
  1028. {
  1029. hr = pfnPingIUEngineUpdateStatus(
  1030. phQuitEvents,
  1031. nQuitEventCount,
  1032. ptszLiveServerUrl,
  1033. ptszCorpServerUrl,
  1034. dwError,
  1035. ptszClientName
  1036. );
  1037. }
  1038. else
  1039. {
  1040. hr = HRESULT_FROM_WIN32(GetLastError());
  1041. LOG_ErrorMsg(hr);
  1042. }
  1043. }
  1044. if (TRUE == fFreeEngModule)
  1045. {
  1046. FreeLibrary(hEngineModule);
  1047. }
  1048. return hr;
  1049. }
  1050. //
  1051. // this function wraps up DownloadIUIdent() and CIUUrlAgent::PopulateData(), since we use it
  1052. // in both selfupd.cpp and loadengine.cpp.
  1053. //
  1054. HRESULT DownloadIUIdent_PopulateData()
  1055. {
  1056. LOG_Block("DownloadIUIdent_PopulateData");
  1057. HRESULT hr = S_OK;
  1058. //
  1059. // Look for any specified iuident Server Location in the Registry (Overrides Default)
  1060. //
  1061. LPTSTR pszTempUrlBuffer = (LPTSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, INTERNET_MAX_URL_LENGTH * sizeof(TCHAR));
  1062. CleanUpFailedAllocSetHrMsg(pszTempUrlBuffer);
  1063. if (FAILED(hr = g_pIUUrlAgent->GetOriginalIdentServer(pszTempUrlBuffer, INTERNET_MAX_URL_LENGTH)))
  1064. {
  1065. LOG_Error(_T("failed to get original ident server URL (%lx)"), hr);
  1066. goto CleanUp;
  1067. }
  1068. TCHAR szIUDir[MAX_PATH];
  1069. //GetIndustryUpdateDirectory(szIUDir);
  1070. //
  1071. // ensure WU directory exist and correctly ACL'ed
  1072. //
  1073. CleanUpIfFalseAndSetHrMsg(!GetWUDirectory(szIUDir, ARRAYSIZE(szIUDir), TRUE), HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND));
  1074. hr = CreateDirectoryAndSetACLs(szIUDir, TRUE);
  1075. CleanUpIfFailedAndMsg(hr);
  1076. if (FAILED(hr = DownloadIUIdent(
  1077. g_hEngineLoadQuit,
  1078. pszTempUrlBuffer,
  1079. szIUDir,
  1080. 0,
  1081. (S_OK == g_pIUUrlAgent->IsIdentFromPolicy()))))
  1082. {
  1083. LOG_Error(_T("iuident download failed (%lx)"), hr);
  1084. goto CleanUp;
  1085. }
  1086. EnterCriticalSection(&g_csUrlAgent);
  1087. if (FAILED(hr = g_pIUUrlAgent->PopulateData()))
  1088. {
  1089. LOG_Error(_T("failed to populate data in g_pIUUrlAgent (%lx)"), hr);
  1090. }
  1091. LeaveCriticalSection(&g_csUrlAgent);
  1092. CleanUp:
  1093. SafeHeapFree(pszTempUrlBuffer);
  1094. return hr;
  1095. }