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.

654 lines
17 KiB

  1. #include "wsdueng.h"
  2. HINSTANCE g_hinst;
  3. CDynamicUpdate *g_pDynamicUpdate = NULL;
  4. DWORD WaitAndPumpMessages(DWORD nCount, LPHANDLE pHandles, DWORD dwWakeMask);
  5. BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpvReserved)
  6. {
  7. if (dwReason == DLL_PROCESS_ATTACH)
  8. {
  9. DisableThreadLibraryCalls(hInstance);
  10. g_hinst = hInstance;
  11. }
  12. else if (dwReason == DLL_PROCESS_DETACH)
  13. {
  14. ;
  15. }
  16. return TRUE;
  17. }
  18. // Required function to be able to link CDMLIB..
  19. HMODULE GetModule()
  20. {
  21. return g_hinst;
  22. }
  23. // --------------------------------------------------------------------------
  24. // Function Name: SetEstimatedDownloadSpeed
  25. // Function Description: Sets the Download speed used for download time estimates
  26. //
  27. // Function Returns:
  28. // Nothing
  29. //
  30. void WINAPI SetEstimatedDownloadSpeed(DWORD dwBytesPerSecond)
  31. {
  32. if (NULL != g_pDynamicUpdate)
  33. g_pDynamicUpdate->m_dwDownloadSpeedInBytesPerSecond = dwBytesPerSecond;
  34. }
  35. // --------------------------------------------------------------------------
  36. // Function Name: DuInitializeA
  37. // Function Description: Initializes the DynamicUpdate class and converts the OSVERSIONINFO information into a Platform ID
  38. //
  39. // Function Returns:
  40. // INVALID_HANDLE_VALUE if it fails
  41. // HANDLE value of 1 if it succeeds
  42. //
  43. // NOTE: The use of a HANDLE could allow us to return the address of the DynamicUpdate Object, which was originally intended, but it seemed simpler
  44. // to just use a global..
  45. HANDLE WINAPI DuInitializeA(IN LPCSTR pszBasePath, IN LPCSTR pszTempPath, POSVERSIONINFOEXA posviTargetOS, IN LPCSTR pszTargetArch,
  46. IN LCID lcidTargetLocale, IN BOOL fUnattend, IN BOOL fUpgrade, IN PWINNT32QUERY pfnWinnt32QueryCallback)
  47. {
  48. LOG_block("DuInitializeA in DuEng");
  49. // parameter validation
  50. // RogerJ, October 5th, 2000
  51. if (!pfnWinnt32QueryCallback)
  52. {
  53. LOG_error("Callback function pointer invalid");
  54. SetLastError(ERROR_INVALID_PARAMETER);
  55. return INVALID_HANDLE_VALUE;
  56. }
  57. // DONE RogerJ
  58. // parse the OSVERSIONINFO struct for the platform ID
  59. int iPlatformID = 0;
  60. // The TargetOS Platform ID is based on a couple of things.
  61. // The Whister Platform ID is the OSVERSIONINFOEX structure with the fields dwMajorVersion and dwMinorVersion set to 5.1
  62. // The other identifier in the platform ID is whether its i386 or ia64 (64bit) .. This is defined in the pszTargetArch String
  63. if (5 == posviTargetOS->dwMajorVersion)
  64. {
  65. if (1 == posviTargetOS->dwMinorVersion)
  66. {
  67. // Whistler
  68. if (NULL != StrStrI(pszTargetArch, "i386"))
  69. {
  70. iPlatformID = 18; // Whistler x86 (normal)
  71. }
  72. else if (NULL != StrStrI(pszTargetArch, "ia64"))
  73. {
  74. iPlatformID = 19; // Whistler ia64 (64bit)
  75. }
  76. }
  77. else if (2 == posviTargetOS->dwMinorVersion)
  78. {
  79. // Whistler
  80. if (NULL != StrStrI(pszTargetArch, "i386"))
  81. {
  82. iPlatformID = 18; // Whistler x86 (normal)
  83. }
  84. else if (NULL != StrStrI(pszTargetArch, "ia64"))
  85. {
  86. iPlatformID = 19; // Whistler ia64 (64bit)
  87. }
  88. }
  89. }
  90. if (0 == iPlatformID)
  91. {
  92. // No known Platform ID for DynamicUpdate was found.. Return Error
  93. return INVALID_HANDLE_VALUE;
  94. }
  95. WORD wPlatformSKU = posviTargetOS->wSuiteMask;
  96. if (g_pDynamicUpdate)
  97. {
  98. // a former call to this function has already initialized an instance of CDynamicUpdate class
  99. delete g_pDynamicUpdate;
  100. g_pDynamicUpdate = NULL;
  101. }
  102. g_pDynamicUpdate = new CDynamicUpdate(iPlatformID, lcidTargetLocale, wPlatformSKU, pszTempPath,
  103. pszBasePath, pfnWinnt32QueryCallback, posviTargetOS);
  104. if (NULL == g_pDynamicUpdate)
  105. {
  106. return INVALID_HANDLE_VALUE;
  107. }
  108. return (HANDLE)1;
  109. }
  110. // --------------------------------------------------------------------------
  111. // Function Name: DuDoDetection
  112. // Function Description: Searches the Catalogs on the WU Site to find Updates for setup
  113. //
  114. // Function Returns:
  115. // FALSE if there are no items OR there is an error.. Use GetLastError() for more information.
  116. // TRUE if it succeeds and there are items to download.
  117. //
  118. // Comment: If return value is FALSE and GetLastError return ERROR_NO_MORE_ITEMS there are no items to download.
  119. //
  120. // Modified by RogerJ October 6th, 2000
  121. // --- Added Driver Detection
  122. BOOL WINAPI DuDoDetection(IN HANDLE hConnection, OUT PDWORD pdwEstimatedTime, OUT PDWORD pdwEstimatedSize)
  123. {
  124. LOG_block("DuDoDetection in DuEng");
  125. DWORD dwRetSetup, dwRetDriver;
  126. dwRetSetup = dwRetDriver = 0;
  127. if (NULL == g_pDynamicUpdate)
  128. return FALSE;
  129. g_pDynamicUpdate->ClearDownloadItemList();
  130. dwRetSetup = g_pDynamicUpdate->DoSetupUpdateDetection();
  131. if (ERROR_SUCCESS != dwRetSetup)
  132. {
  133. LOG_error("Failed to get setup update item! --- %d", dwRetSetup);
  134. g_pDynamicUpdate->PingBack(DU_PINGBACK_SETUPDETECTIONFAILED, 0, NULL, FALSE);
  135. }
  136. // do driver detection here
  137. if (!g_pDynamicUpdate->DoDriverDetection() ||
  138. !g_pDynamicUpdate->DoWindowsUpdateDriverDetection())
  139. {
  140. LOG_error("Failed to detect driver!");
  141. dwRetDriver = GetLastError();
  142. g_pDynamicUpdate->PingBack(DU_PINGBACK_DRIVERDETECTIONFAILED, 0, NULL, FALSE);
  143. }
  144. if (dwRetSetup && dwRetDriver)
  145. {
  146. LOG_error("Both Setup item and Driver detection failed");
  147. return FALSE;
  148. }
  149. if (g_pDynamicUpdate->m_dwDownloadItemCount > 0)
  150. {
  151. g_pDynamicUpdate->UpdateDownloadItemSize();
  152. *pdwEstimatedSize = g_pDynamicUpdate->m_dwTotalDownloadSize; // size in bytes
  153. // Time Estimate is based on roughly how long it took us to download the data files.
  154. if (0 == g_pDynamicUpdate->m_dwDownloadSpeedInBytesPerSecond)
  155. g_pDynamicUpdate->m_dwDownloadSpeedInBytesPerSecond = 2048; // default to 120k per minute, (2048 bytes per second).
  156. *pdwEstimatedTime = g_pDynamicUpdate->m_dwTotalDownloadSize / g_pDynamicUpdate->m_dwDownloadSpeedInBytesPerSecond; // number of seconds
  157. if (*pdwEstimatedTime == 0)
  158. *pdwEstimatedTime = 1; // at least one second
  159. if (dwRetSetup)
  160. SetLastError(dwRetSetup);
  161. if (dwRetDriver)
  162. SetLastError(dwRetDriver);
  163. return TRUE;
  164. }
  165. else
  166. {
  167. // initialize the size and time for setup
  168. *pdwEstimatedTime = 1;
  169. *pdwEstimatedSize = 0;
  170. // At this point there was no error, but we have no items to download,
  171. SetLastError(ERROR_NO_MORE_ITEMS);
  172. return TRUE;
  173. }
  174. }
  175. // --------------------------------------------------------------------------
  176. //
  177. //
  178. //
  179. //
  180. //
  181. //
  182. // --------------------------------------------------------------------------
  183. BOOL WINAPI DuBeginDownload(IN HANDLE hConnection, IN HWND hwndNotify)
  184. {
  185. if ((NULL == g_pDynamicUpdate) || (NULL == hwndNotify))
  186. {
  187. SetLastError(ERROR_INVALID_HANDLE);
  188. return FALSE;
  189. }
  190. if (0 == g_pDynamicUpdate->m_dwDownloadItemCount)
  191. {
  192. SetLastError(ERROR_NO_MORE_ITEMS);
  193. PostMessage(hwndNotify, WM_DYNAMIC_UPDATE_COMPLETE, (WPARAM) DU_STATUS_SUCCESS, (LPARAM) NULL);
  194. return TRUE;
  195. }
  196. g_pDynamicUpdate->SetCallbackHWND(hwndNotify);
  197. g_pDynamicUpdate->SetAbortDownload(FALSE);
  198. if (ERROR_SUCCESS != g_pDynamicUpdate->DownloadFilesAsync())
  199. {
  200. return FALSE;
  201. }
  202. return TRUE; // download has been started
  203. }
  204. // --------------------------------------------------------------------------
  205. //
  206. //
  207. //
  208. //
  209. //
  210. //
  211. // --------------------------------------------------------------------------
  212. void WINAPI DuAbortDownload(IN HANDLE hConnection)
  213. {
  214. if (NULL == g_pDynamicUpdate)
  215. return;
  216. g_pDynamicUpdate->SetAbortDownload(TRUE);
  217. return;
  218. }
  219. // --------------------------------------------------------------------------
  220. //
  221. //
  222. //
  223. //
  224. //
  225. //
  226. // --------------------------------------------------------------------------
  227. void WINAPI DuUninitialize(IN HANDLE hConnection)
  228. {
  229. if (NULL == g_pDynamicUpdate)
  230. return;
  231. // We want to hold up the Uninitialize process until any other Threads
  232. // specifically the Download Thread. We are going to wait on the DownloadThreadProc
  233. // thread handle if it exists. Once the thread finishes, the wait proc will exit
  234. // and we can continue.
  235. if (NULL != g_pDynamicUpdate->m_hDownloadThreadProc)
  236. WaitAndPumpMessages(1, &g_pDynamicUpdate->m_hDownloadThreadProc, QS_ALLINPUT);
  237. delete g_pDynamicUpdate;
  238. g_pDynamicUpdate = NULL;
  239. LOG_close();
  240. return;
  241. }
  242. // --------------------------------------------------------------------------
  243. //
  244. //
  245. //
  246. //
  247. //
  248. //
  249. // --------------------------------------------------------------------------
  250. CDynamicUpdate::CDynamicUpdate(int iPlatformID, LCID lcidLocaleID, WORD wPlatformSKU, LPCSTR pszTempPath, LPCSTR pszDownloadPath, PWINNT32QUERY pfnWinnt32QueryCallback,
  251. POSVERSIONINFOEXA pVersionInfo)
  252. : m_iPlatformID(iPlatformID),
  253. m_lcidLocaleID(lcidLocaleID),
  254. m_wPlatformSKU(wPlatformSKU),
  255. m_hwndClientNotify(NULL),
  256. m_pDownloadItemList(NULL),
  257. m_dwDownloadItemCount(0),
  258. m_dwTotalDownloadSize(0),
  259. m_dwCurrentBytesDownloaded(0),
  260. m_hInternet(NULL),
  261. m_hConnect(NULL),
  262. m_hOpenRequest(NULL),
  263. m_pV3(NULL),
  264. m_fAbortDownload(FALSE),
  265. m_dwLastPercentComplete(0),
  266. m_dwDownloadSpeedInBytesPerSecond(0),
  267. m_hDownloadThreadProc(NULL),
  268. m_pfnWinNT32Query(pfnWinnt32QueryCallback)
  269. {
  270. (void)FixUpV3LocaleID(); // BUG: 435184 - Map 0c0a to 040a for V3 purposes
  271. if (NULL != pszTempPath)
  272. {
  273. lstrcpy(m_szTempPath, pszTempPath);
  274. }
  275. if (NULL != pszDownloadPath)
  276. {
  277. lstrcpy(m_szDownloadPath, pszDownloadPath);
  278. }
  279. lstrcpy(m_szCurrentConnectedServer, ""); // initialize to null.
  280. CopyMemory((PVOID)&m_VersionInfo, (PVOID)pVersionInfo, sizeof(OSVERSIONINFOEXA));
  281. InitializeCriticalSection(&m_cs);
  282. InitializeCriticalSection(&m_csDownload);
  283. // m_hDevInfo = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_PRESENT | DIGCF_ALLCLASSES);
  284. }
  285. // --------------------------------------------------------------------------
  286. //
  287. //
  288. //
  289. //
  290. //
  291. //
  292. // --------------------------------------------------------------------------
  293. CDynamicUpdate::~CDynamicUpdate()
  294. {
  295. ClearDownloadItemList(); // free up any memory in the download list
  296. m_arrayHardwareId.RemoveAll();
  297. if (m_pV3) delete m_pV3;
  298. m_pV3 = NULL;
  299. DeleteCriticalSection(&m_cs);
  300. DeleteCriticalSection(&m_csDownload);
  301. SafeInternetCloseHandle(m_hOpenRequest);
  302. SafeInternetCloseHandle(m_hConnect);
  303. SafeInternetCloseHandle(m_hInternet);
  304. SafeCloseHandle(m_hDownloadThreadProc);
  305. }
  306. LPSTR CDynamicUpdate::DuUrlCombine(LPSTR pszDest, LPCSTR pszBase, LPCSTR pszAdd)
  307. {
  308. if ((NULL == pszDest) || (NULL == pszBase) || (NULL == pszAdd))
  309. {
  310. return NULL;
  311. }
  312. lstrcpy(pszDest, pszBase);
  313. int iLen = lstrlen(pszDest);
  314. if ('/' == pszDest[iLen - 1])
  315. {
  316. // already has a trailing slash, check the 'add' string for a preceding slash
  317. if ('/' == *pszAdd)
  318. {
  319. // has a preceding slash, skip it.
  320. lstrcat(pszDest, pszAdd + 1);
  321. }
  322. else
  323. {
  324. lstrcat(pszDest, pszAdd);
  325. }
  326. }
  327. else
  328. {
  329. // no trailing slash, check the add string for a preceding slash
  330. if ('/' == *pszAdd)
  331. {
  332. // has a preceding slash, Add Normally
  333. lstrcat(pszDest, pszAdd);
  334. }
  335. else
  336. {
  337. lstrcat(pszDest, "/");
  338. lstrcat(pszDest, pszAdd);
  339. }
  340. }
  341. return pszDest;
  342. }
  343. LPCSTR CDynamicUpdate::GetDuDownloadPath()
  344. {
  345. return m_szDownloadPath;
  346. }
  347. LPCSTR CDynamicUpdate::GetDuServerUrl()
  348. {
  349. return m_szServerUrl;
  350. }
  351. LPCSTR CDynamicUpdate::GetDuTempPath()
  352. {
  353. return m_szTempPath;
  354. }
  355. // --------------------------------------------------------------------------
  356. //
  357. //
  358. //
  359. //
  360. //
  361. //
  362. // --------------------------------------------------------------------------
  363. DWORD CDynamicUpdate::DoSetupUpdateDetection()
  364. {
  365. if (NULL == m_pV3)
  366. {
  367. m_pV3 = new CV31Server(this);
  368. if (NULL == m_pV3)
  369. {
  370. return ERROR_NOT_ENOUGH_MEMORY;
  371. }
  372. }
  373. if (!m_pV3->ReadIdentInfo())
  374. {
  375. return GetLastError();
  376. }
  377. if (!m_pV3->GetCatalogPUIDs())
  378. {
  379. return GetLastError();
  380. }
  381. if (!m_pV3->GetCatalogs())
  382. {
  383. // there was an error reading the catalogs
  384. return GetLastError();
  385. }
  386. if (!m_pV3->ReadCatalogINI())
  387. {
  388. return GetLastError();
  389. }
  390. if (!m_pV3->UpdateDownloadItemList(m_VersionInfo))
  391. {
  392. // there was an error parsing the catalogs and creating the download list.
  393. return GetLastError();
  394. }
  395. return ERROR_SUCCESS;
  396. }
  397. // --------------------------------------------------------------------------
  398. //
  399. //
  400. //
  401. //
  402. //
  403. //
  404. // --------------------------------------------------------------------------
  405. void CDynamicUpdate::AddDownloadItemToList(DOWNLOADITEM *pDownloadItem)
  406. {
  407. LOG_block("CDynamicUpdate::AddDownloadItemToList");
  408. if (NULL == pDownloadItem)
  409. {
  410. return;
  411. }
  412. if (NULL == m_pDownloadItemList) // no drivers in list yet
  413. {
  414. m_pDownloadItemList = pDownloadItem;
  415. }
  416. else
  417. {
  418. // add to the end of the list
  419. DOWNLOADITEM *pCurrent = m_pDownloadItemList;
  420. while (NULL != pCurrent->pNext)
  421. {
  422. pCurrent = pCurrent->pNext;
  423. }
  424. pCurrent->pNext = pDownloadItem;
  425. pDownloadItem->pPrev = pCurrent;
  426. }
  427. m_dwDownloadItemCount++;
  428. LOG_out("Item added, %d cab(s), first cab ---\"%s\"", pDownloadItem->iNumberOfCabs, pDownloadItem->mszFileList);
  429. }
  430. // --------------------------------------------------------------------------
  431. //
  432. //
  433. //
  434. //
  435. //
  436. //
  437. // --------------------------------------------------------------------------
  438. void CDynamicUpdate::RemoveDownloadItemFromList(DOWNLOADITEM *pDownloadItem)
  439. {
  440. if (NULL == pDownloadItem)
  441. {
  442. return;
  443. }
  444. if (NULL == m_pDownloadItemList)
  445. {
  446. return;
  447. }
  448. DOWNLOADITEM *pCurrent = m_pDownloadItemList;
  449. while (NULL != pCurrent)
  450. {
  451. if (pCurrent == pDownloadItem)
  452. {
  453. break;
  454. }
  455. pCurrent = pCurrent->pNext;
  456. }
  457. if ((NULL == pCurrent) || (pCurrent != pDownloadItem))
  458. {
  459. return; // unexpected
  460. }
  461. if (NULL == pCurrent->pPrev) // first item in list
  462. {
  463. if (NULL == pCurrent->pNext) // only item in list
  464. {
  465. m_pDownloadItemList = NULL;
  466. m_dwDownloadItemCount = 0;
  467. }
  468. else
  469. {
  470. pCurrent->pNext->pPrev = NULL; // next job becomes first
  471. m_pDownloadItemList = pCurrent->pNext;
  472. m_dwDownloadItemCount--;
  473. }
  474. }
  475. else
  476. {
  477. pCurrent->pPrev->pNext = pCurrent->pNext;
  478. if (NULL != pCurrent->pNext)
  479. {
  480. pCurrent->pNext->pPrev = pCurrent->pPrev;
  481. }
  482. }
  483. }
  484. void CDynamicUpdate::SetCallbackHWND(HWND hwnd)
  485. {
  486. m_hwndClientNotify = hwnd;
  487. }
  488. void CDynamicUpdate::SetAbortDownload(BOOL fAbort)
  489. {
  490. EnterCriticalSection(&m_cs);
  491. m_fAbortDownload = fAbort;
  492. LeaveCriticalSection(&m_cs);
  493. }
  494. void CDynamicUpdate::UpdateDownloadItemSize()
  495. {
  496. m_dwTotalDownloadSize = 0;
  497. DOWNLOADITEM *pCurrent = m_pDownloadItemList;
  498. while (pCurrent)
  499. {
  500. m_dwTotalDownloadSize += pCurrent->dwTotalFileSize;
  501. pCurrent = pCurrent->pNext;
  502. }
  503. }
  504. void CDynamicUpdate::ClearDownloadItemList()
  505. {
  506. EnterCriticalSection(&m_csDownload);
  507. DOWNLOADITEM *pCurrent = m_pDownloadItemList;
  508. DOWNLOADITEM *pNext;
  509. while (pCurrent)
  510. {
  511. pNext = pCurrent->pNext;
  512. SafeGlobalFree(pCurrent);
  513. pCurrent = pNext;
  514. }
  515. m_pDownloadItemList = NULL;
  516. m_dwDownloadItemCount = 0;
  517. LeaveCriticalSection(&m_csDownload);
  518. }
  519. void CDynamicUpdate::EnterDownloadListCriticalSection()
  520. {
  521. EnterCriticalSection(&m_csDownload);
  522. }
  523. void CDynamicUpdate::LeaveDownloadListCriticalSection()
  524. {
  525. LeaveCriticalSection(&m_csDownload);
  526. }
  527. void CDynamicUpdate::FixUpV3LocaleID()
  528. {
  529. // Some XP Locale ID's map to a different Locale ID in V3 Terms
  530. // First Example was a new Spanish (Modern) Locale ID (0c0a)
  531. // which in V3 was (040a). For the V3 period we will fix up
  532. // any specific LCID's until IU handles this.
  533. switch (m_lcidLocaleID)
  534. {
  535. case 3082: // 0c0a = Spanish (Modern)
  536. {
  537. m_lcidLocaleID = 1034; // 040a
  538. break;
  539. }
  540. default:
  541. {
  542. // do nothing.
  543. }
  544. }
  545. return;
  546. };
  547. DWORD WaitAndPumpMessages(DWORD nCount, LPHANDLE pHandles, DWORD dwWakeMask)
  548. {
  549. DWORD dwWaitResult;
  550. MSG msg;
  551. while (TRUE)
  552. {
  553. dwWaitResult = MsgWaitForMultipleObjects(nCount, pHandles, FALSE, 1000, dwWakeMask);
  554. if (dwWaitResult <= WAIT_OBJECT_0 + nCount - 1)
  555. {
  556. return dwWaitResult;
  557. }
  558. if (WAIT_OBJECT_0 + nCount == dwWaitResult)
  559. {
  560. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  561. {
  562. TranslateMessage(&msg);
  563. DispatchMessage(&msg);
  564. }
  565. }
  566. }
  567. return dwWaitResult;
  568. }