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.

590 lines
22 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. winbom.c
  5. Abstract:
  6. Process the WinBOM (Windows Bill-of-Materials) file during OEM/SB pre-installation.
  7. Task performed will be:
  8. Download updated device drivers from NET
  9. Process OOBE info
  10. Process User/Customer specific settings
  11. Process OEM user specific customization
  12. Process Application pre-installations
  13. Author:
  14. Donald McNamara (donaldm) 2/8/2000
  15. Revision History:
  16. - Added preinstall support to ProcessWinBOM: Jason Lawrence (t-jasonl) 6/7/2000
  17. --*/
  18. #include "factoryp.h"
  19. //
  20. // Defined Value(s):
  21. //
  22. // Time out in milliseconds to wait for the dialog thread to finish.
  23. //
  24. #define DIALOG_WAIT_TIMEOUT 2000
  25. //
  26. // Internal Function Prototype(s):
  27. //
  28. static BOOL SetRunKey(BOOL bSet, LPDWORD lpdwTickCount);
  29. /*++
  30. ===============================================================================
  31. Routine Description:
  32. BOOL ProcessWinBOM
  33. This routine will process all sections of the WinBOM
  34. Arguments:
  35. lpszWinBOMPath - Buffer containing the fully qualified path to the WINBOM
  36. file
  37. lpStates - Array of states that will be processed.
  38. cbStates - Number of states in the states array.
  39. Return Value:
  40. TRUE if no errors were encountered
  41. FALSE if there was an error
  42. ===============================================================================
  43. --*/
  44. BOOL ProcessWinBOM(LPTSTR lpszWinBOMPath, LPSTATES lpStates, DWORD cbStates)
  45. {
  46. STATE stateCurrent,
  47. stateStart = stateUnknown;
  48. LPSTATES lpState;
  49. STATEDATA stateData;
  50. BOOL bQuit,
  51. bErr = FALSE,
  52. bLoggedOn = GET_FLAG(g_dwFactoryFlags, FLAG_LOGGEDON),
  53. bServer = IsServer(),
  54. bPerf = GET_FLAG(g_dwFactoryFlags, FLAG_LOG_PERF),
  55. bStatus = !GET_FLAG(g_dwFactoryFlags, FLAG_NOUI),
  56. bInit;
  57. HKEY hKey;
  58. HWND hwndStatus = NULL;
  59. DWORD dwForReal,
  60. dwStates,
  61. dwStatus = 0;
  62. LPSTATUSNODE lpsnTemp = NULL;
  63. // Get the current state from the registry.
  64. //
  65. if ( RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_FACTORY_STATE, 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS )
  66. {
  67. DWORD dwType = REG_DWORD,
  68. dwValue = 0,
  69. cbValue = sizeof(DWORD);
  70. if ( RegQueryValueEx(hKey, _T("CurrentState"), NULL, &dwType, (LPBYTE) &dwValue, &cbValue) == ERROR_SUCCESS )
  71. {
  72. stateStart = (STATE) dwValue;
  73. }
  74. RegCloseKey(hKey);
  75. }
  76. // Set the static state data.
  77. //
  78. stateData.lpszWinBOMPath = lpszWinBOMPath;
  79. // We loop through the states twice. The first time is just
  80. // a quick run through to see what states to add to the status
  81. // dialog. The second time is the "real" time when we actually
  82. // run each state.
  83. //
  84. for ( dwForReal = 0; dwForReal < 2; dwForReal++ )
  85. {
  86. // Reset these guys every time.
  87. //
  88. bInit = TRUE;
  89. bQuit = FALSE,
  90. dwStates = cbStates;
  91. lpState = lpStates;
  92. stateCurrent = stateStart;
  93. // If this is the real thing we need to handle the status dialog stuff.
  94. //
  95. if ( dwForReal )
  96. {
  97. // Create the dialog if we want to display the UI.
  98. //
  99. if ( bStatus && dwStatus )
  100. {
  101. STATUSWINDOW swAppList;
  102. // Start by zeroing out the structure.
  103. //
  104. ZeroMemory(&swAppList, sizeof(swAppList));
  105. // Now copy the title into the structure.
  106. //
  107. if ( swAppList.lpszDescription = AllocateString(NULL, IDS_APPTITLE) )
  108. {
  109. lstrcpyn(swAppList.szWindowText, swAppList.lpszDescription, AS(swAppList.szWindowText));
  110. FREE(swAppList.lpszDescription);
  111. }
  112. // Get the description string.
  113. //
  114. swAppList.lpszDescription = AllocateString(NULL, IDS_STATUS_DESC);
  115. // Load the main icon for the status window.
  116. //
  117. swAppList.hMainIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_FACTORYPRE));
  118. // Set the screen cordinates for the status window.
  119. //
  120. swAppList.X = -10;
  121. swAppList.Y = 10;
  122. // Now actually create the status window.
  123. //
  124. hwndStatus = StatusCreateDialog(&swAppList, lpsnTemp);
  125. // Clean up any allocated memory.
  126. //
  127. FREE(swAppList.lpszDescription);
  128. }
  129. // Delete the node list as we don't need it anymore
  130. // because the status window is already displayed.
  131. //
  132. if ( lpsnTemp )
  133. {
  134. StatusDeleteNodes(lpsnTemp);
  135. }
  136. }
  137. // Process WINBOM states, until we reach the finished state.
  138. //
  139. do
  140. {
  141. // Set or advance to the next state.
  142. //
  143. if ( bInit )
  144. {
  145. // Now if we are logged on, we need to advance to that state.
  146. //
  147. if ( bLoggedOn )
  148. {
  149. while ( dwStates && ( lpState->state != stateLogon ) )
  150. {
  151. lpState++;
  152. dwStates--;
  153. }
  154. }
  155. // If we don't know the current state, set it to the first one.
  156. //
  157. if ( stateCurrent == stateUnknown )
  158. {
  159. stateCurrent = lpState->state;
  160. }
  161. // Make sure we don't do the init code again.
  162. //
  163. bInit = FALSE;
  164. }
  165. else
  166. {
  167. if ( stateCurrent == lpState->state )
  168. {
  169. // Advance and save the current state.
  170. //
  171. stateCurrent = (++lpState)->state;
  172. // Set the current state in the registry (only if doing this for real).
  173. //
  174. if ( dwForReal && ( RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_FACTORY_STATE, 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS ) )
  175. {
  176. RegSetValueEx(hKey, _T("CurrentState"), 0, REG_DWORD, (LPBYTE) &stateCurrent, sizeof(DWORD));
  177. RegCloseKey(hKey);
  178. }
  179. }
  180. else
  181. {
  182. // Just advanced to the next state.
  183. //
  184. lpState++;
  185. }
  186. }
  187. // Decrement our size counter to make sure we don't go past
  188. // the end of our array.
  189. //
  190. dwStates--;
  191. // Only execute this state if it isn't a one time only state or
  192. // our current state is the same one we are about to execute.
  193. //
  194. // Also don't execute this state if we are running on server and
  195. // it should not be.
  196. //
  197. if ( ( !GET_FLAG(lpState->dwFlags, FLAG_STATE_ONETIME) || ( stateCurrent == lpState->state ) ) &&
  198. ( !GET_FLAG(lpState->dwFlags, FLAG_STATE_NOTONSERVER) || ( !bServer ) ) )
  199. {
  200. // First reset any state data in the structure
  201. // that might be left over from a previous state call.
  202. //
  203. stateData.state = lpState->state;
  204. stateData.bQuit = FALSE;
  205. // If this is for real, then do the state stuff.
  206. //
  207. if ( dwForReal )
  208. {
  209. LPTSTR lpStateText;
  210. BOOL bStateErr = FALSE,
  211. bSwitchCode = TRUE;
  212. DWORD dwTickStart = 0,
  213. dwTickFinish = 0;
  214. // Get the friendly name for the state if there is one.
  215. //
  216. lpStateText = lpState->nFriendlyName ? AllocateString(NULL, lpState->nFriendlyName) : NULL;
  217. // Log that we are starting this state (special case the log on case becase
  218. // we don't want to log that we are starting it twice.
  219. //
  220. if ( ( lpStateText ) &&
  221. ( !bLoggedOn || ( stateLogon != lpState->state ) ) )
  222. {
  223. FacLogFile(2, IDS_LOG_STARTINGSTATE, lpStateText);
  224. }
  225. // Get the starting tick count.
  226. //
  227. dwTickStart = GetTickCount();
  228. // See if the state has a function.
  229. //
  230. if ( lpState->statefunc )
  231. {
  232. // Run the state function.
  233. //
  234. bStateErr = !lpState->statefunc(&stateData);
  235. // Get the finish tick count.
  236. //
  237. dwTickFinish = GetTickCount();
  238. }
  239. // Jump to the code for this state if there is one. We should avoid
  240. // putting code here. For now just the logon and finish states are
  241. // in the switch statement because they are very simple and crucial
  242. // to how the state loop works. All the other states just do some
  243. // work that we don't care about or need to have any knowledge of.
  244. //
  245. switch ( lpState->state )
  246. {
  247. case stateLogon:
  248. // If we haven't logged on yet, we need to quit when we get to this state.
  249. //
  250. if ( !bLoggedOn )
  251. {
  252. // Set the run key so we get kicked off again after we log on.
  253. //
  254. bStateErr = !SetRunKey(TRUE, &dwTickStart);
  255. bQuit = TRUE;
  256. // Don't want to log the perf yet, so set these to FALSE and zero.
  257. //
  258. bSwitchCode = FALSE;
  259. dwTickFinish = 0;
  260. }
  261. else
  262. {
  263. // Clear the run keys and get the original tick count.
  264. //
  265. if ( ( bStateErr = !SetRunKey(FALSE, &dwTickStart) ) &&
  266. ( 0 == dwTickStart ) )
  267. {
  268. // If for some reason we were not able to get the tick count
  269. // from the registry, just set these to FALSE and zero so
  270. // we don't try to log the perf.
  271. //
  272. bSwitchCode = FALSE;
  273. dwTickFinish = 0;
  274. }
  275. }
  276. break;
  277. case stateFinish:
  278. // Nothing should ever really go in the finished state. We just
  279. // set bQuit to true so we exit out.
  280. //
  281. bQuit = TRUE;
  282. break;
  283. default:
  284. bSwitchCode = FALSE;
  285. }
  286. // Check if code in the switch statement was run.
  287. //
  288. if ( bSwitchCode )
  289. {
  290. // Get the finish tick count again.
  291. //
  292. dwTickFinish = GetTickCount();
  293. }
  294. // Log that we are finished with this state.
  295. //
  296. if ( lpStateText )
  297. {
  298. // Write out that we have finished this state (unless this is the
  299. // first time for the logon state, we don't want to log that it finished
  300. // twice unless there is an error the first time).
  301. //
  302. if ( bStateErr )
  303. {
  304. FacLogFile(0 | LOG_ERR, IDS_ERR_FINISHINGSTATE, lpStateText);
  305. }
  306. else if ( bLoggedOn || ( stateLogon != lpState->state ) )
  307. {
  308. FacLogFile(2, IDS_LOG_FINISHINGSTATE, lpStateText);
  309. }
  310. // See if we actually ran any code.
  311. //
  312. if ( dwTickFinish && bPerf )
  313. {
  314. // Calculate the difference in milleseconds.
  315. //
  316. if ( dwTickFinish >= dwTickStart )
  317. {
  318. dwTickFinish -= dwTickStart;
  319. }
  320. else
  321. {
  322. dwTickFinish += ( 0xFFFFFFFF - dwTickStart );
  323. }
  324. // Write out to the log the time this state took.
  325. //
  326. FacLogFile(0, IDS_LOG_STATEPERF, lpStateText, dwTickFinish / 1000, dwTickFinish - ((dwTickFinish / 1000) * 1000));
  327. }
  328. // Free the friendly name.
  329. //
  330. FREE(lpStateText);
  331. }
  332. // If there is status text, we should increment past it.
  333. //
  334. if ( hwndStatus && GET_FLAG(lpState->dwFlags, FLAG_STATE_DISPLAYED) )
  335. {
  336. StatusIncrement(hwndStatus, !bStateErr);
  337. }
  338. // Check to see if the state failed.
  339. //
  340. if ( bStateErr )
  341. {
  342. // State function failed, set the error var and see if we need
  343. // to quit proccessing states.
  344. //
  345. bErr = TRUE;
  346. if ( GET_FLAG(lpState->dwFlags, FLAG_STATE_QUITONERR) ||
  347. GET_FLAG(g_dwFactoryFlags, FLAG_STOP_ON_ERROR) )
  348. {
  349. bQuit = TRUE;
  350. }
  351. }
  352. }
  353. else
  354. {
  355. // Always reset the displayed flag first.
  356. //
  357. RESET_FLAG(lpState->dwFlags, FLAG_STATE_DISPLAYED);
  358. // Only need to do more if we want to display the UI.
  359. //
  360. if ( bStatus )
  361. {
  362. LPTSTR lpszDisplay;
  363. // Only if there is a friendly name can we display it.
  364. //
  365. if ( lpState->nFriendlyName && ( lpszDisplay = AllocateString(NULL, lpState->nFriendlyName) ) )
  366. {
  367. BOOL bDisplay;
  368. // First use the state display function (if there is one) to figure out
  369. // if this item is to be displayed or not.
  370. //
  371. // The function can set bQuit in the state structure just like when it actually
  372. // runs. We will catch this below and make this the last item in the list.
  373. //
  374. bDisplay = lpState->displayfunc ? lpState->displayfunc(&stateData) : FALSE;
  375. // Jump to the display code for this state to see if it is really displayed
  376. // or should be the last item in the list. We should avoid putting code
  377. // here. For now just the logon and finish states are in the switch
  378. // statement because they are very simple and crucial to how the state
  379. // loop works for the display dialog. All the other states make their own
  380. // determination if they should be displayed or not.
  381. //
  382. switch ( lpState->state )
  383. {
  384. case stateLogon:
  385. // If we haven't logged on yet, we need to quit when we get to this state.
  386. //
  387. if ( !bLoggedOn )
  388. {
  389. // Set the quit so this is the last item listed before logon.
  390. //
  391. bQuit = TRUE;
  392. }
  393. else
  394. {
  395. // Not going to show this state after logon, only before. We can change
  396. // this if we think we should show it as the first item after logon, but
  397. // it doesn't really matter.
  398. //
  399. bDisplay = FALSE;
  400. }
  401. break;
  402. case stateFinish:
  403. // We just set the quit so we make sure and exit out.
  404. //
  405. bQuit = TRUE;
  406. break;
  407. }
  408. // Now check to see if we really want to display this state.
  409. //
  410. if ( bDisplay )
  411. {
  412. StatusAddNode(lpszDisplay, &lpsnTemp);
  413. SET_FLAG(lpState->dwFlags, FLAG_STATE_DISPLAYED);
  414. dwStatus++;
  415. }
  416. // Free the friendly name.
  417. //
  418. FREE(lpszDisplay);
  419. }
  420. }
  421. }
  422. // If they want to quit, set bQuit.
  423. //
  424. if ( stateData.bQuit )
  425. {
  426. bQuit = TRUE;
  427. }
  428. }
  429. }
  430. while ( !bQuit && dwStates );
  431. }
  432. // If we created the status window, end it now.
  433. //
  434. if ( hwndStatus )
  435. {
  436. StatusEndDialog(hwndStatus);
  437. }
  438. return !bErr;
  439. }
  440. BOOL DisplayAlways(LPSTATEDATA lpStateData)
  441. {
  442. return TRUE;
  443. }
  444. static BOOL SetRunKey(BOOL bSet, LPDWORD lpdwTickCount)
  445. {
  446. HKEY hKey;
  447. BOOL bRet = FALSE;
  448. DWORD dwDis;
  449. // First need to open the key either way.
  450. //
  451. if ( RegCreateKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_RUN, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwDis) == ERROR_SUCCESS )
  452. {
  453. if ( bSet )
  454. {
  455. TCHAR szCmd[MAX_PATH + 32];
  456. // Set us to run after we get logged on.
  457. //
  458. lstrcpyn(szCmd, g_szFactoryPath, AS ( szCmd ) );
  459. if ( FAILED ( StringCchCat ( szCmd, AS ( szCmd ), _T(" -logon") ) ) )
  460. {
  461. FacLogFileStr(3, _T("StringCchCat failed %s %s\n"), szCmd, _T(" -logon") );
  462. }
  463. if ( RegSetValueEx(hKey, _T("AuditMode"), 0, REG_SZ, (CONST LPBYTE) szCmd, ( lstrlen(szCmd) + 1 ) * sizeof(TCHAR)) == ERROR_SUCCESS )
  464. bRet = TRUE;
  465. }
  466. else
  467. {
  468. // Delete the run key so we aren't left there.
  469. //
  470. if ( RegDeleteValue(hKey, _T("AuditMode")) == ERROR_SUCCESS )
  471. bRet = TRUE;
  472. }
  473. RegCloseKey(hKey);
  474. }
  475. // Open the key where we save some state info.
  476. //
  477. if ( RegCreateKeyEx(HKEY_LOCAL_MACHINE, REG_FACTORY_STATE, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwDis) == ERROR_SUCCESS )
  478. {
  479. if ( bSet )
  480. {
  481. // Set the tick count so we know how long the logon takes.
  482. //
  483. if ( RegSetValueEx(hKey, _T("TickCount"), 0, REG_DWORD, (CONST LPBYTE) lpdwTickCount, sizeof(DWORD)) != ERROR_SUCCESS )
  484. bRet = FALSE;
  485. }
  486. else
  487. {
  488. DWORD dwType,
  489. cbValue = sizeof(DWORD);
  490. // Read and delete the run key so it isn't left there.
  491. //
  492. if ( ( RegQueryValueEx(hKey, _T("TickCount"), NULL, &dwType, (LPBYTE) lpdwTickCount, &cbValue) != ERROR_SUCCESS ) ||
  493. ( REG_DWORD != dwType ) )
  494. {
  495. *lpdwTickCount = 0;
  496. bRet = FALSE;
  497. }
  498. else
  499. RegDeleteValue(hKey, _T("TickCount"));
  500. }
  501. RegCloseKey(hKey);
  502. }
  503. return bRet;
  504. }