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.

1420 lines
65 KiB

  1. // **************************************************************************
  2. //
  3. // OEMRun.C
  4. //
  5. // Microsoft Confidential
  6. // Copyright (c) Microsoft Corporation 1999-2001
  7. // All rights reserved
  8. //
  9. // OEM Run wrapper. This application allows the OEM to Run appliations on every audit
  10. // boot. It also allows them to specify applications that should only be run on the
  11. // first audit reboot.
  12. //
  13. // 9/20/1999 Stephen Lodwick
  14. // Project started
  15. //
  16. // 6/22/2000 Stephen Lodwick (stelo)
  17. // Ported to NT
  18. //
  19. // 1/07/2001 Stephen Lodwick (stelo)
  20. // Merged with factory.exe
  21. //
  22. // 4/01/2001 Stephen Lodwick (stelo)
  23. // Added StatusDialog Support
  24. //
  25. // *************************************************************************/
  26. //
  27. #include "factoryp.h"
  28. #include "oemrun.h"
  29. #include "res.h"
  30. //
  31. // Internal Defines
  32. //
  33. #define STR_REG_OEMRUNONCE _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\OemRunOnce") // Registry path for RunOnce apps
  34. #define STR_REG_OEMRUN _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\OemRun") // Registry path for Run apps
  35. #define STR_REG_CURRENTVER _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion") // Registry path for CurrentVersion
  36. #define STR_VAL_OEMRESETSILENT _T("OemReset_Silent") // Registry Value that is set if you don't want OemReset to display Exit dialog
  37. #define STR_VAL_WINBOMRO _T("OemRunOnce")
  38. #define INF_SEC_OEMRUNONCE _T("OemRunOnce")
  39. #define INF_SEC_OEMRUN _T("OemRun")
  40. #define RUN_APPS_ASYNC 0 // This flag is used to run the applications asynchronasly
  41. #define RUN_APPS_SYNC 1 // This flag is used to run the applications sychronasly
  42. #define CHR_UNDERSCORE _T('_')
  43. #define CHR_QUOTE _T('\"')
  44. #define NULLCHR _T('\0')
  45. #define STR_REBOOT _T("REBOOT")
  46. #define STR_INSTALLTECH_MSI _T("MSI")
  47. #define STR_MSI_ATTACH _T(" FASTOEM=1 ALLUSERS=1 DISABLEROLLBACK=1 ")
  48. #define STR_MSI_STAGE _T(" ACTION=ADMIN TARGETDIR=\"%s\" ")
  49. //
  50. // Internal Functions
  51. //
  52. static LPRUNNODE BuildAppList(LPTSTR, BOOL);
  53. static HWND DisplayAppList(HWND, LPRUNNODE);
  54. static void RunAppList(HWND, LPRUNNODE, DWORD);
  55. static void RunAppThread(LPTHREADPARAM);
  56. static void DeleteAppList(LPRUNNODE);
  57. static void OemReboot();
  58. static VOID SetRunOnceState(DWORD);
  59. static DWORD GetRunOnceState(VOID);
  60. //
  61. // Global Defines
  62. //
  63. INSTALLTYPES g_InstallTypes[] =
  64. {
  65. { installtypeStage, INI_VAL_WBOM_STAGE },
  66. { installtypeDetach, INI_VAL_WBOM_DETACH },
  67. { installtypeAttach, INI_VAL_WBOM_ATTACH },
  68. { installtypeStandard, INI_VAL_WBOM_STANDARD },
  69. };
  70. INSTALLTECHS g_InstallTechs[] =
  71. {
  72. { installtechMSI, INI_VAL_WBOM_MSI },
  73. { installtechApp, INI_VAL_WBOM_APP },
  74. { installtechINF, INI_VAL_WBOM_INF },
  75. };
  76. //
  77. // Main external function
  78. //
  79. BOOL ProcessSection(BOOL bOemRunOnce)
  80. {
  81. LPRUNNODE lprnAppList = NULL;
  82. // Build the Application list for the OemRun key
  83. //
  84. lprnAppList = BuildAppList(bOemRunOnce ? STR_REG_OEMRUNONCE : STR_REG_OEMRUN, bOemRunOnce);
  85. // If there are applications in the list, launch the RunOnce dialog or run the applist if in OemRun mode
  86. //
  87. if(lprnAppList)
  88. {
  89. if ( bOemRunOnce )
  90. {
  91. HWND hStatusDialog = NULL;
  92. // Display the application list
  93. //
  94. if ( hStatusDialog = DisplayAppList(NULL, lprnAppList) )
  95. {
  96. RunAppList(hStatusDialog, lprnAppList, RUN_APPS_SYNC);
  97. StatusEndDialog(hStatusDialog);
  98. }
  99. }
  100. else
  101. {
  102. // Launch the Application list asynchronously without the oemrunce UI
  103. //
  104. RunAppList(NULL, lprnAppList, RUN_APPS_ASYNC);
  105. }
  106. }
  107. // Need a better way to determine if this fails or not.
  108. //
  109. return TRUE;
  110. }
  111. static void RunAppThread(LPTHREADPARAM lpThreadParam)
  112. {
  113. RunAppList(lpThreadParam->hWnd, lpThreadParam->lprnList, RUN_APPS_SYNC);
  114. FREE(lpThreadParam);
  115. }
  116. static LPRUNNODE BuildAppList(LPTSTR lpListKey, BOOL bRunOnceKey)
  117. {
  118. HKEY hkPath,
  119. hkSubKey;
  120. TCHAR szField[MAX_PATH] = NULLSTR,
  121. szName[MAX_PATH] = NULLSTR,
  122. szValue[MAX_PATH] = NULLSTR,
  123. szSecType[MAX_PATH] = NULLSTR,
  124. szKeyPath[MAX_PATH] = NULLSTR,
  125. szBuffer[MAX_PATH] = NULLSTR;
  126. DWORD dwRegIndex = 0,
  127. dwRegKeyIndex = 0,
  128. dwNameSize = sizeof(szName)/sizeof(TCHAR), // size of name in TCHARS
  129. dwValueSize = sizeof(szValue), // size of value in bytes
  130. dwItemNumber = 1,
  131. dwTempIndex = 0,
  132. dwCurrentState = bRunOnceKey ? GetRunOnceState() : 0;
  133. LPRUNNODE lprnHead = NULL,
  134. lprnNode = NULL;
  135. LPLPRUNNODE lplprnNext = &lprnHead;
  136. HINF hInf = NULL;
  137. INFCONTEXT InfContext;
  138. BOOL bRet,
  139. bWinbom,
  140. bCleanupNode = FALSE,
  141. bAllocFailed = FALSE,
  142. bReboot;
  143. LPTSTR lpReboot = NULL;
  144. // This section will build the Application list from the winbom.ini
  145. //
  146. if ((hInf = SetupOpenInfFile(g_szWinBOMPath, NULL, INF_STYLE_OLDNT | INF_STYLE_WIN4, NULL)) != INVALID_HANDLE_VALUE)
  147. {
  148. // Determine if we're looking at the Run or RunOnce section and find the first line in the section
  149. //
  150. for ( bRet = SetupFindFirstLine(hInf, bRunOnceKey ? INF_SEC_OEMRUNONCE : INF_SEC_OEMRUN, NULL, &InfContext);
  151. bRet;
  152. bRet = SetupFindNextLine(&InfContext, &InfContext), dwItemNumber++ )
  153. {
  154. // Get the AppName.
  155. //
  156. szName[0] = NULLCHR;
  157. szField[0] = NULLCHR;
  158. SetupGetStringField(&InfContext, 1, szField, STRSIZE(szField), NULL);
  159. ExpandEnvironmentStrings(szField, szName, sizeof(szName)/sizeof(TCHAR));
  160. // Get the AppPath or Section name
  161. //
  162. szValue[0] = NULLCHR;
  163. szField[0] = NULLCHR;
  164. SetupGetStringField(&InfContext, 2, szField, STRSIZE(szField), NULL);
  165. ExpandEnvironmentStrings(szField, szValue, sizeof(szValue)/sizeof(TCHAR));
  166. // Get field to determine what type of section we are getting, if any
  167. //
  168. szSecType[0] = NULLCHR;
  169. SetupGetStringField(&InfContext, 3, szSecType, STRSIZE(szSecType), NULL);
  170. // Special Case the reboot key
  171. //
  172. bReboot = FALSE;
  173. szBuffer[0] = NULLCHR;
  174. SetupGetLineText(&InfContext, NULL, NULL, NULL, szBuffer, STRSIZE(szBuffer), NULL);
  175. StrTrm(szBuffer, CHR_QUOTE);
  176. if ( !LSTRCMPI(szBuffer, STR_REBOOT) )
  177. {
  178. // Reset the values so it looks nice in the dialog
  179. //
  180. lpReboot = AllocateString(NULL, IDS_REBOOT_FRIENDLY);
  181. // Set the default values
  182. //
  183. lstrcpyn(szName, lpReboot, AS ( szName ) );
  184. szValue[0] = NULLCHR;
  185. szSecType[0] = NULLCHR;
  186. bReboot = TRUE;
  187. // Clean up the allocated memory
  188. //
  189. FREE(lpReboot);
  190. }
  191. // Make sure we have a valid app before adding it to the list
  192. //
  193. if ( szName[0] && ( szValue[0] || bReboot ) && (dwItemNumber > dwCurrentState))
  194. {
  195. if( (lprnNode) = (LPRUNNODE)MALLOC(sizeof(RUNNODE)))
  196. {
  197. // Allocate the memory for the data elements in the new node
  198. //
  199. int nDisplayNameLen = ( lstrlen(szName) + 1 ) * sizeof( TCHAR ) ;
  200. int nRunValueLen = ( lstrlen(szValue) + 1 ) * sizeof( TCHAR ) ;
  201. int nKeyPathLen = ( lstrlen(szKeyPath) + 1 ) * sizeof( TCHAR ) ;
  202. if ( ( lprnNode->lpDisplayName = MALLOC( nDisplayNameLen ) ) &&
  203. ( lprnNode->lpValueName = MALLOC( nDisplayNameLen ) ) &&
  204. ( lprnNode->lpRunValue = MALLOC( nRunValueLen ) ) &&
  205. ( lprnNode->lpSubKey = MALLOC( nKeyPathLen ) ) )
  206. {
  207. // Copy in the standard exe information into RUNNODE structure
  208. //
  209. lstrcpyn((LPTSTR)(lprnNode)->lpDisplayName,szName, nDisplayNameLen);
  210. lstrcpyn((LPTSTR)(lprnNode)->lpValueName,szName, nDisplayNameLen);
  211. lstrcpyn((LPTSTR)(lprnNode)->lpRunValue,szValue, nRunValueLen );
  212. lstrcpyn((LPTSTR)(lprnNode)->lpSubKey, szKeyPath, nKeyPathLen);
  213. (lprnNode)->bWinbom = TRUE;
  214. (lprnNode)->bRunOnce = bRunOnceKey;
  215. (lprnNode)->dwItemNumber = dwItemNumber;
  216. (lprnNode)->lpNext = NULL;
  217. (lprnNode)->bReboot = bReboot;
  218. (lprnNode)->InstallTech = installtechUndefined;
  219. (lprnNode)->InstallType = installtypeUndefined;
  220. // If this is a section, copy in additional structure information
  221. //
  222. if ( szSecType[0] )
  223. {
  224. // Log that we have found an application preinstall section
  225. //
  226. FacLogFile(1, IDS_PROC_APPSECTION, szValue, szName);
  227. // Loop through all of the install techs and determine the one that we are installing
  228. //
  229. for (dwTempIndex = 0; dwTempIndex < AS(g_InstallTechs); dwTempIndex++)
  230. {
  231. if ( !lstrcmpi(szSecType, g_InstallTechs[dwTempIndex].lpszDescription) )
  232. (lprnNode)->InstallTech = g_InstallTechs[dwTempIndex].InstallTech;
  233. }
  234. // Determine the InstallType
  235. //
  236. szBuffer[0] = NULLCHR;
  237. GetPrivateProfileString(szValue, INI_KEY_WBOM_INSTALLTYPE, szBuffer, szBuffer, STRSIZE(szBuffer), g_szWinBOMPath);
  238. // If no InstallType is used, assume standard
  239. //
  240. if ( szBuffer[0] == NULLCHR )
  241. (lprnNode)->InstallType = installtypeStandard;
  242. // Loop through all of the install types and determine the one that we are installing
  243. //
  244. for (dwTempIndex = 0; dwTempIndex < AS(g_InstallTypes); dwTempIndex++)
  245. {
  246. if ( !lstrcmpi(szBuffer, g_InstallTypes[dwTempIndex].lpszDescription) )
  247. (lprnNode)->InstallType = g_InstallTypes[dwTempIndex].InstallType;
  248. }
  249. //
  250. // READ IN ALL OTHER SECTION KEYS
  251. //
  252. // SourcePath
  253. //
  254. szField[0] = NULLCHR;
  255. GetPrivateProfileString(szValue, INI_KEY_WBOM_SOURCEPATH, szField, szField, STRSIZE(szField), g_szWinBOMPath);
  256. ExpandEnvironmentStrings(szField, (lprnNode)->szSourcePath, STRSIZE((lprnNode)->szSourcePath));
  257. // TargetPath
  258. //
  259. szField[0] = NULLCHR;
  260. GetPrivateProfileString(szValue, INI_KEY_WBOM_TARGETPATH, szField, szField, STRSIZE(szField), g_szWinBOMPath);
  261. ExpandEnvironmentStrings(szField, (lprnNode)->szTargetPath, STRSIZE((lprnNode)->szTargetPath));
  262. // SetupFile
  263. //
  264. (lprnNode)->szSetupFile[0] = NULLCHR;
  265. GetPrivateProfileString(szValue, INI_KEY_WBOM_SETUPFILE, (lprnNode)->szSetupFile, (lprnNode)->szSetupFile, STRSIZE((lprnNode)->szSetupFile), g_szWinBOMPath);
  266. // Command Line
  267. //
  268. (lprnNode)->szCmdLine[0] = NULLCHR;
  269. GetPrivateProfileString(szValue, INI_KEY_WBOM_CMDLINE, (lprnNode)->szCmdLine, (lprnNode)->szCmdLine, STRSIZE((lprnNode)->szCmdLine), g_szWinBOMPath);
  270. // Section Name for INF file
  271. //
  272. (lprnNode)->szSectionName[0] = NULLCHR;
  273. GetPrivateProfileString(szValue, INI_KEY_WBOM_SECTIONNAME, (lprnNode)->szSectionName, (lprnNode)->szSectionName, STRSIZE((lprnNode)->szSectionName), g_szWinBOMPath);
  274. // Reboot Command
  275. //
  276. szBuffer[0] = NULLCHR;
  277. GetPrivateProfileString(szValue, INI_KEY_WBOM_REBOOT, szBuffer, szBuffer, STRSIZE(szBuffer), g_szWinBOMPath);
  278. if (!LSTRCMPI(szBuffer, _T("YES")))
  279. (lprnNode)->bReboot = TRUE;
  280. // RemoveTargetPath Key
  281. //
  282. szBuffer[0] = NULLCHR;
  283. GetPrivateProfileString(szValue, INI_KEY_WBOM_REMOVETARGET, szBuffer, szBuffer, STRSIZE(szBuffer), g_szWinBOMPath);
  284. // Get the RemoveTargetPath
  285. //
  286. if (!LSTRCMPI(szBuffer, _T("NO")))
  287. (lprnNode)->bRemoveTarget = FALSE;
  288. else
  289. (lprnNode)->bRemoveTarget = TRUE;
  290. // The install tech was invalid, error out
  291. //
  292. if ((lprnNode)->InstallTech == installtechUndefined )
  293. {
  294. FacLogFile(0|LOG_ERR, IDS_ERR_UNDEFTECH, szName);
  295. bCleanupNode = TRUE;
  296. }
  297. // The install type was set to or still is undefine, error out
  298. //
  299. if ( (lprnNode)->InstallType == installtypeUndefined )
  300. {
  301. // The Install type is unknown, let the user know with the log file
  302. //
  303. FacLogFile(0|LOG_ERR, IDS_ERR_UNDEFINSTALL, szName);
  304. bCleanupNode = TRUE;
  305. }
  306. // If we have a valid Install Technology and Install Type, continue on
  307. //
  308. if ( !bCleanupNode )
  309. {
  310. // First determine the install type
  311. //
  312. switch ( (lprnNode)->InstallType )
  313. {
  314. // If we are doing a Staged Install, do the following
  315. //
  316. case installtypeStage:
  317. {
  318. // Check to make sure that the SourcePath exists, as we need it in Staging
  319. //
  320. if ( (lprnNode)->szSourcePath[0] == NULLCHR )
  321. {
  322. FacLogFile(0|LOG_ERR, IDS_ERR_NOSOURCE, szName);
  323. bCleanupNode = TRUE;
  324. }
  325. // Removing the TargetPath is not an option for Staging
  326. //
  327. (lprnNode)->bRemoveTarget = FALSE;
  328. // Determine what install technology we are using
  329. //
  330. switch ( (lprnNode)->InstallTech )
  331. {
  332. // We are performing an Staged/MSI install
  333. //
  334. case installtechMSI:
  335. // Both SetupFile and Stagepath are required for MSI Stage
  336. //
  337. if ( (lprnNode)->szSetupFile[0] == NULLCHR || (lprnNode)->szTargetPath[0] == NULLCHR)
  338. {
  339. FacLogFile(0|LOG_ERR, IDS_ERR_NOSTAGESETUPFILE, szName);
  340. bCleanupNode = TRUE;
  341. }
  342. break;
  343. // We are performing a Staged/Generic install
  344. //
  345. case installtechApp:
  346. case installtechINF:
  347. // Check to make sure that if there is no StagePath we have a SetupFile
  348. //
  349. if ( (lprnNode)->szTargetPath[0] == NULLCHR && (lprnNode)->szSetupFile[0] == NULLCHR)
  350. {
  351. FacLogFile(0|LOG_ERR, IDS_ERR_NOSTAGEPATH, szName);
  352. bCleanupNode = TRUE;
  353. }
  354. // If we are doing an INF install, NULL out the SetupFile
  355. //
  356. if ( (lprnNode)->InstallTech == installtechINF )
  357. (lprnNode)->szSetupFile[0] = NULLCHR;
  358. break;
  359. }
  360. }
  361. break;
  362. // If we are Attaching an application or doing a Standard Install, do the following
  363. //
  364. case installtypeAttach:
  365. case installtypeStandard:
  366. {
  367. // SourcePath is used for Standard install/RemoveStagePath is ignored
  368. //
  369. if ((lprnNode)->InstallType == installtypeStandard )
  370. {
  371. (lprnNode)->szTargetPath[0] = NULLCHR;
  372. // Check to make sure we have SourcePath
  373. //
  374. if ( (lprnNode)->szSourcePath[0] == NULLCHR)
  375. {
  376. FacLogFile(0|LOG_ERR, IDS_ERR_NOSOURCE, szName);
  377. bCleanupNode = TRUE;
  378. }
  379. // We are just going to use the SourcePath as the TargetPath
  380. //
  381. lstrcpyn((lprnNode)->szTargetPath, (lprnNode)->szSourcePath, AS ( (lprnNode)->szTargetPath ) );
  382. // Can't remove the Target for standard install
  383. //
  384. (lprnNode)->bRemoveTarget = FALSE;
  385. }
  386. else
  387. {
  388. // SourcePath is ignored for Attach
  389. //
  390. (lprnNode)->szSourcePath[0] = NULLCHR;
  391. // Make sure we have TargetPath for Attach
  392. //
  393. if ( (lprnNode)->szTargetPath[0] == NULLCHR)
  394. {
  395. FacLogFile(0|LOG_ERR, IDS_ERR_NOTARGETPATH, szName);
  396. bCleanupNode = TRUE;
  397. }
  398. }
  399. // If Attaching an application, the SetupFile is required
  400. //
  401. if ( (lprnNode)->szSetupFile[0] == NULLCHR )
  402. {
  403. FacLogFile(0|LOG_ERR, IDS_ERR_NOSETUPFILE, szName);
  404. bCleanupNode = TRUE;
  405. }
  406. // Determine what install technology we are using
  407. //
  408. switch ( (lprnNode)->InstallTech )
  409. {
  410. // We are performing an Attach/MSI install
  411. //
  412. case installtechMSI:
  413. break;
  414. // We are performing an Attach/Generic install
  415. //
  416. case installtechApp:
  417. break;
  418. // We are performing an Attach/INF install
  419. //
  420. case installtechINF:
  421. // We are required to have a SectionName in this case
  422. //
  423. if ( (lprnNode)->szSectionName[0] == NULLCHR)
  424. {
  425. FacLogFile(0|LOG_ERR, IDS_ERR_NOSECTIONNAME, szName);
  426. bCleanupNode = TRUE;
  427. }
  428. break;
  429. }
  430. }
  431. break;
  432. // If we are Detaching an application, do the following
  433. //
  434. case installtypeDetach:
  435. {
  436. // SourcePath is ignored if Detaching
  437. //
  438. (lprnNode)->szSourcePath[0] = NULLCHR;
  439. // Removing the TargetPath is not an option for Detaching (it's already implied)
  440. //
  441. (lprnNode)->bRemoveTarget = FALSE;
  442. // StagePath is required for Detach
  443. //
  444. if ( (lprnNode)->szTargetPath[0] == NULLCHR )
  445. {
  446. FacLogFile(0|LOG_ERR, IDS_ERR_NOTARGETPATH, szName);
  447. bCleanupNode = TRUE;
  448. }
  449. // Determine what install technology we are using
  450. //
  451. switch ( (lprnNode)->InstallTech )
  452. {
  453. // We are performing an Detach/MSI install
  454. //
  455. case installtechMSI:
  456. break;
  457. // We are performing a Detach/Generic install
  458. //
  459. case installtechApp:
  460. break;
  461. // We are performing a Detach/INF install
  462. //
  463. case installtechINF:
  464. break;
  465. }
  466. }
  467. break;
  468. }
  469. // If we are Installing an application and a Command Line exists while the SetupFile does not, let the user know
  470. //
  471. if ( (lprnNode)->szCmdLine[0] && (lprnNode)->szSetupFile[0] == NULLCHR )
  472. {
  473. // Set the Command Line back to the default
  474. //
  475. (lprnNode)->szCmdLine[0] = NULLCHR;
  476. // This is non-fatal, we will log the error and contine
  477. //
  478. FacLogFile(0|LOG_ERR, IDS_ERR_IGNORECMDLINE, szName);
  479. }
  480. }
  481. }
  482. // If there was no error, move to the next node in the list
  483. //
  484. if ( !bCleanupNode )
  485. {
  486. // Debug information
  487. //
  488. DBGLOG(3, _T("Successfully Added '%s' to Application List.\n"), (lprnNode)->lpDisplayName);
  489. }
  490. // Make sure the new node points to the next node
  491. //
  492. lprnNode->lpNext = (*lplprnNext);
  493. // Make sure the previous node points to the new node
  494. //
  495. *lplprnNext = lprnNode;
  496. // Move to the next node in the list
  497. //
  498. lplprnNext=&((*lplprnNext)->lpNext);
  499. }
  500. else
  501. {
  502. // Memory allocation failed, clean up
  503. //
  504. bAllocFailed = TRUE;
  505. }
  506. // There was an error, clean up the runnode
  507. //
  508. if ( bAllocFailed || bCleanupNode)
  509. {
  510. // Free the memory because we failed the allocation or we have an invalid install type
  511. //
  512. if ( bAllocFailed )
  513. {
  514. // Debug information
  515. //
  516. DBGLOG(3, _T("Failed to Add '%s' to Application List.\n"), (lprnNode)->lpDisplayName);
  517. FREE(lprnNode->lpDisplayName);
  518. FREE(lprnNode->lpValueName);
  519. FREE(lprnNode->lpRunValue);
  520. FREE(lprnNode->lpSubKey);
  521. FREE(lprnNode);
  522. }
  523. else if ( bCleanupNode )
  524. {
  525. // Debug information
  526. //
  527. DBGLOG(3, _T("Invalid entry '%s' will not be processed.\n"), (lprnNode)->lpDisplayName);
  528. // We will display the invalid entry with a failure in runapplist
  529. //
  530. lprnNode->bEntryError = TRUE;
  531. }
  532. // Clear the error flags
  533. //
  534. bCleanupNode = FALSE;
  535. bAllocFailed = FALSE;
  536. }
  537. }
  538. }
  539. }
  540. SetupCloseInfFile(hInf);
  541. }
  542. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, lpListKey, 0, KEY_ALL_ACCESS, &hkPath) == ERROR_SUCCESS)
  543. {
  544. // Enumerate each of the sub keys using a do..while
  545. //
  546. do
  547. {
  548. dwRegIndex = 0;
  549. // Open each of the sub keys
  550. //
  551. if (RegOpenKeyEx(hkPath, szKeyPath, 0, KEY_ALL_ACCESS, &hkSubKey) == ERROR_SUCCESS)
  552. {
  553. // Enumerate each value of the registry
  554. //
  555. while (RegEnumValue(hkSubKey, dwRegIndex, szName, &dwNameSize, NULL, NULL, (LPBYTE)szValue, &dwValueSize ) == ERROR_SUCCESS)
  556. {
  557. // Allocate the memory for the next node
  558. //
  559. if( (lprnNode) = (LPRUNNODE)MALLOC(sizeof(RUNNODE)))
  560. {
  561. int nDisplayNameLen = (lstrlen(szName) + 1) * sizeof(TCHAR );
  562. int nRunValueLen = (lstrlen(szValue) + 1) * sizeof(TCHAR );
  563. int nKeyPathLen = (lstrlen(szKeyPath) + 1) * sizeof(TCHAR);
  564. // Allocate the memory for the data elements in the new node
  565. //
  566. if ( ( lprnNode->lpDisplayName = MALLOC( nDisplayNameLen ) ) &&
  567. ( lprnNode->lpValueName = MALLOC( nDisplayNameLen ) ) &&
  568. ( lprnNode->lpRunValue = MALLOC( nRunValueLen ) ) &&
  569. ( lprnNode->lpSubKey = MALLOC(nKeyPathLen ) ) )
  570. {
  571. // Copy the key name and value into the node buffers
  572. //
  573. lstrcpyn((LPTSTR)(lprnNode)->lpDisplayName, szName, nDisplayNameLen);
  574. lstrcpyn((LPTSTR)(lprnNode)->lpValueName,szName, nDisplayNameLen);
  575. lstrcpyn((LPTSTR)(lprnNode)->lpRunValue,szValue, nRunValueLen);
  576. lstrcpyn((LPTSTR)(lprnNode)->lpSubKey, szKeyPath, nKeyPathLen);
  577. (lprnNode)->bWinbom = FALSE;
  578. (lprnNode)->bRunOnce = bRunOnceKey;
  579. (lprnNode)->lpNext = NULL;
  580. // Run through the linked list to determine where to add the new node
  581. for(lplprnNext=&lprnHead;;(lplprnNext=&((*lplprnNext)->lpNext)))
  582. {
  583. // If we are at the head node or the CompareString functions return true,
  584. // then that's where we want to place the new node
  585. //
  586. if ( (*lplprnNext==NULL) ||
  587. ((CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,(*lplprnNext)->lpSubKey, -1, lprnNode->lpSubKey, -1) == CSTR_GREATER_THAN) && ((*lplprnNext)->bWinbom != TRUE)) ||
  588. ((CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, (*lplprnNext)->lpDisplayName, -1, lprnNode->lpDisplayName, -1) == CSTR_GREATER_THAN ) &&
  589. (CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, lprnNode->lpSubKey, -1, (*lplprnNext)->lpSubKey, -1) != CSTR_GREATER_THAN) &&
  590. ((*lplprnNext)->bWinbom != TRUE) )
  591. )
  592. {
  593. // Make sure the new node points to the next node
  594. //
  595. lprnNode->lpNext = (*lplprnNext);
  596. // Make sure the previous node points to the new node
  597. //
  598. *lplprnNext = lprnNode;
  599. // Break, because we've inserted the node
  600. //
  601. break;
  602. }
  603. }
  604. }
  605. else
  606. {
  607. // Free the memory because we failed the allocation
  608. //
  609. FREE(lprnNode->lpDisplayName);
  610. FREE(lprnNode->lpValueName);
  611. FREE(lprnNode->lpRunValue);
  612. FREE(lprnNode->lpSubKey);
  613. FREE(lplprnNext);
  614. }
  615. }
  616. // Reset the size of the Name and value variables
  617. //
  618. dwNameSize = sizeof(szName)/sizeof(TCHAR);
  619. dwValueSize = sizeof(szValue);
  620. dwRegIndex++;
  621. }
  622. // Close the Subkey
  623. //
  624. RegCloseKey(hkSubKey);
  625. } // End the RegOpenKeyEx - Subkey
  626. if (*szKeyPath)
  627. dwRegKeyIndex++;
  628. } while( RegEnumKey(hkPath, dwRegKeyIndex, szKeyPath, sizeof(szKeyPath)/sizeof(TCHAR)) == ERROR_SUCCESS );
  629. RegCloseKey(hkPath);
  630. } // End the RegOpenKey - Mainkey
  631. return lprnHead;
  632. }
  633. static HWND DisplayAppList(HWND hWnd, LPRUNNODE lprnAppList)
  634. {
  635. STATUSWINDOW swAppList;
  636. LPSTATUSNODE lpsnTemp = NULL;
  637. HWND hAppList = NULL;
  638. LPTSTR lpAppName = NULL;
  639. ZeroMemory(&swAppList, sizeof(swAppList));
  640. swAppList.X = 10;
  641. swAppList.Y = 10;
  642. // Get the title for OEMRUN from the resource
  643. //
  644. if ( (lpAppName = AllocateString(NULL, IDS_APPTITLE_OEMRUN)) && *lpAppName )
  645. {
  646. lstrcpyn(swAppList.szWindowText, lpAppName, AS ( swAppList.szWindowText ) );
  647. FREE(lpAppName);
  648. }
  649. if(lprnAppList)
  650. {
  651. // Walk the list and create our node list
  652. //
  653. while ( lprnAppList )
  654. {
  655. StatusAddNode(lprnAppList->lpDisplayName, &lpsnTemp);
  656. lprnAppList = lprnAppList->lpNext;
  657. }
  658. }
  659. // Create the dialog
  660. //
  661. hAppList = StatusCreateDialog(&swAppList, lpsnTemp);
  662. // Delete the node list as we don't need it anymore
  663. //
  664. StatusDeleteNodes(lpsnTemp);
  665. return ( hAppList );
  666. }
  667. static void RunAppList(HWND hWnd, LPRUNNODE lprnAppList, DWORD dwAction)
  668. {
  669. PROCESS_INFORMATION pi;
  670. STARTUPINFO startup;
  671. LPRUNNODE lprnHead = lprnAppList;
  672. LPLPRUNNODE lplprnNext = &lprnHead;
  673. TCHAR szRegPath[MAX_PATH] = NULLSTR,
  674. szApplication[MAX_PATH] = NULLSTR,
  675. szBuffer[MAX_PATH] = NULLSTR;
  676. HKEY hkPath = NULL;
  677. BOOL bReturn = FALSE;
  678. UINT uRet;
  679. if(lprnHead)
  680. {
  681. // Walk the list and execute each of the programs
  682. //
  683. for(lplprnNext=&lprnHead; *lplprnNext;(lplprnNext=&((*lplprnNext)->lpNext)))
  684. {
  685. // Set up the default startupinfo
  686. //
  687. ZeroMemory(&startup, sizeof(startup));
  688. startup.cb = sizeof(startup);
  689. // Set the default value for the handle to the process
  690. //
  691. pi.hProcess = NULL;
  692. // Default return value for section
  693. //
  694. bReturn = TRUE;
  695. // First check if this node had an invalid entry
  696. //
  697. if ( (*lplprnNext)->bEntryError )
  698. {
  699. bReturn = FALSE;
  700. }
  701. else
  702. {
  703. // Determine if we are a RUNONCE App and whether we are running from the Registry or Winbom
  704. // If we are running from:
  705. // Registry - Delete value
  706. // Winbom - Update current state, current state + 1
  707. if ( (*lplprnNext)->bRunOnce )
  708. {
  709. // If we are running from the Winbom.ini, increment the state index, otherwise, delete the value
  710. //
  711. //
  712. if ( (*lplprnNext)->bWinbom )
  713. SetRunOnceState((*lplprnNext)->dwItemNumber);
  714. else
  715. {
  716. // Create the path in the registry
  717. //
  718. lstrcpyn(szRegPath, STR_REG_OEMRUNONCE, AS ( szRegPath ) );
  719. // There's a subkey, append that to path
  720. //
  721. if ( (*lplprnNext)->lpSubKey[0] )
  722. AddPathN(szRegPath, (*lplprnNext)->lpSubKey, AS ( szRegPath ) );
  723. // Delete value from registry
  724. //
  725. if ( RegOpenKeyEx(HKEY_LOCAL_MACHINE, szRegPath, 0, KEY_ALL_ACCESS, &hkPath) == ERROR_SUCCESS )
  726. {
  727. RegDeleteValue(hkPath, (*lplprnNext)->lpValueName);
  728. }
  729. }
  730. }
  731. // Determine if we are not a section and launch the program
  732. //
  733. if ( (*lplprnNext)->InstallTech == installtechUndefined )
  734. {
  735. if ( (*lplprnNext)->lpRunValue )
  736. {
  737. // Lets attempt to connect to any supplied network resources
  738. //
  739. FactoryNetworkConnect((*lplprnNext)->lpRunValue, g_szWinBOMPath, NULLSTR, TRUE);
  740. bReturn = CreateProcess(NULL, (*lplprnNext)->lpRunValue, NULL, NULL, FALSE, CREATE_NEW_PROCESS_GROUP, NULL, NULL, &startup, &pi);
  741. // Log whether the detach was successful
  742. //
  743. FacLogFile(bReturn ? 1 : 0|LOG_ERR,
  744. bReturn ? IDS_ERR_CREATEPROCESSSUCCESS : IDS_ERR_CREATEPROCESSFAILED, (*lplprnNext)->lpRunValue);
  745. }
  746. }
  747. else
  748. {
  749. // Lets attempt to connect to any supplied network resources
  750. //
  751. FactoryNetworkConnect((*lplprnNext)->szSourcePath, g_szWinBOMPath, (*lplprnNext)->lpRunValue, TRUE);
  752. FactoryNetworkConnect((*lplprnNext)->szCmdLine, g_szWinBOMPath, (*lplprnNext)->lpRunValue, TRUE);
  753. FactoryNetworkConnect((*lplprnNext)->szTargetPath, g_szWinBOMPath, (*lplprnNext)->lpRunValue, TRUE);
  754. // We are a section, first determine the installtype
  755. //
  756. switch ((*lplprnNext)->InstallType)
  757. {
  758. case installtypeStage:
  759. {
  760. INSTALLUILEVEL oldUILevel; // Used for an MSI Attach
  761. // There is a setupfile
  762. //
  763. if ( (*lplprnNext)->szSetupFile[0] )
  764. {
  765. if ( (*lplprnNext)->InstallTech == installtechMSI )
  766. {
  767. // Just some logging, telling the user what we are doing
  768. //
  769. FacLogFile(1, IDS_ERR_INITMSIATTACH, (*lplprnNext)->lpDisplayName);
  770. // Set the old MSIInteralUI Level
  771. //
  772. oldUILevel = MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
  773. // Create the new command line
  774. //
  775. if ( FAILED ( StringCchPrintf ( szBuffer, AS ( szBuffer ), STR_MSI_STAGE,(*lplprnNext)->szTargetPath) ) )
  776. {
  777. FacLogFileStr(3, _T("StringCchPrintf failed %s %s" ), szBuffer, (*lplprnNext)->szTargetPath);
  778. }
  779. if ( FAILED ( StringCchCat ( (*lplprnNext)->szCmdLine, AS ( (*lplprnNext)->szCmdLine ), szBuffer ) ) )
  780. {
  781. FacLogFileStr(3, _T("StringCchCat failed %s %s" ), (*lplprnNext)->szCmdLine, szBuffer );
  782. }
  783. // Create the full path to the Application
  784. //
  785. lstrcpyn( szApplication, (*lplprnNext)->szSourcePath, AS ( szApplication ) );
  786. AddPathN( szApplication, (*lplprnNext)->szSetupFile, AS ( szApplication ) );
  787. // Initiate the installation
  788. //
  789. uRet = MsiInstallProduct(szApplication, (*lplprnNext)->szCmdLine);
  790. // Default return value to true for staged install
  791. //
  792. bReturn = TRUE;
  793. if ( ( uRet == ERROR_SUCCESS_REBOOT_REQUIRED ) ||
  794. ( uRet == ERROR_SUCCESS_REBOOT_INITIATED ) )
  795. {
  796. // We have some code that we need to determine if we do a mini-wipe so we will just fall through
  797. //
  798. (*lplprnNext)->bReboot = TRUE;
  799. }
  800. else if ( uRet != ERROR_SUCCESS )
  801. {
  802. bReturn = FALSE;
  803. FacLogFile(0|LOG_ERR, IDS_MSI_FAILURE, uRet, (*lplprnNext)->lpDisplayName);
  804. }
  805. // Restore internal UI level of MSI installer.
  806. //
  807. MsiSetInternalUI(oldUILevel, NULL);
  808. }
  809. // Determine if there is a sourcepath, and execute the application
  810. //
  811. else if ( (*lplprnNext)->szSourcePath[0] )
  812. {
  813. // Create the path to the application
  814. //
  815. lstrcpyn( szApplication, (*lplprnNext)->szSourcePath, AS(szApplication) );
  816. AddPathN( szApplication, (*lplprnNext)->szSetupFile, AS ( szApplication ) );
  817. StrCatBuff( szApplication, _T(" "), AS(szApplication) );
  818. StrCatBuff( szApplication, (*lplprnNext)->szCmdLine, AS(szApplication) );
  819. // Launch the program
  820. //
  821. bReturn = CreateProcess(NULL, szApplication, NULL, NULL, FALSE, CREATE_NEW_PROCESS_GROUP, NULL, NULL, &startup, &pi);
  822. }
  823. else
  824. bReturn = FALSE;
  825. }
  826. else
  827. {
  828. // There is no setup file, just copy the files from SOURCEPATH -> TARGETPATH
  829. //
  830. if ( (*lplprnNext)->szSourcePath[0] && (*lplprnNext)->szTargetPath[0] )
  831. bReturn = CopyDirectoryProgress(NULL, (*lplprnNext)->szSourcePath, (*lplprnNext)->szTargetPath );
  832. else
  833. FacLogFile(0|LOG_ERR, IDS_ERR_NOSOURCETARGET, (*lplprnNext)->lpDisplayName);
  834. }
  835. // Log to the user whether the stage was successful
  836. //
  837. FacLogFile(bReturn ? 1 : 0|LOG_ERR, bReturn ? IDS_ERR_STAGESUCCESS : IDS_ERR_STAGEFAILED, (*lplprnNext)->lpDisplayName);
  838. break;
  839. }
  840. case installtypeDetach:
  841. {
  842. // If we have a setup file launch it, otherwise, removed the targetPath
  843. //
  844. if ( (*lplprnNext)->szSetupFile[0] )
  845. {
  846. // Create the path to the application
  847. //
  848. lstrcpyn( szApplication, (*lplprnNext)->szSourcePath, AS(szApplication) );
  849. AddPathN( szApplication, (*lplprnNext)->szSetupFile, AS (szApplication ) );
  850. StrCatBuff( szApplication, _T(" "), AS(szApplication) );
  851. StrCatBuff( szApplication, (*lplprnNext)->szCmdLine, AS(szApplication) );
  852. // Launch the program
  853. //
  854. bReturn = CreateProcess(NULL, szApplication, NULL, NULL, FALSE, CREATE_NEW_PROCESS_GROUP, NULL, NULL, &startup, &pi);
  855. }
  856. else
  857. bReturn = DeletePath( (*lplprnNext)->szTargetPath );
  858. // Log whether the detach was successful
  859. //
  860. FacLogFile(bReturn ? 1 : 0|LOG_ERR, bReturn ? IDS_ERR_DETACHSUCCESS : IDS_ERR_DETACHFAILED, (*lplprnNext)->lpDisplayName);
  861. break;
  862. }
  863. case installtypeAttach:
  864. case installtypeStandard:
  865. {
  866. INSTALLUILEVEL oldUILevel; // Used for an MSI Attach
  867. // TargetPath and SetupFile are required to continue attach
  868. //
  869. if ( (*lplprnNext)->szTargetPath[0] && (*lplprnNext)->szSetupFile[0] )
  870. {
  871. switch ( (*lplprnNext)->InstallTech )
  872. {
  873. // We are attaching an MSI application
  874. //
  875. case installtechMSI:
  876. {
  877. // Just some logging, telling the user what we are doing
  878. //
  879. FacLogFile(1, IDS_ERR_INITMSIATTACH, (*lplprnNext)->lpDisplayName);
  880. // Set the old MSIInteralUI Level
  881. //
  882. oldUILevel = MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
  883. // Create the new command line
  884. //
  885. if ( FAILED ( StringCchCat ( (*lplprnNext)->szCmdLine, AS ( (*lplprnNext)->szCmdLine ), STR_MSI_ATTACH ) ) )
  886. {
  887. FacLogFileStr(3, _T("StringCchCat failed %s %s" ), (*lplprnNext)->szCmdLine, STR_MSI_ATTACH );
  888. }
  889. // Create the full path to the Application
  890. //
  891. lstrcpyn( szApplication, (*lplprnNext)->szTargetPath, AS(szApplication) );
  892. AddPathN( szApplication, (*lplprnNext)->szSetupFile, AS ( szApplication ) );
  893. // Initiate the installation
  894. //
  895. uRet = MsiInstallProduct(szApplication, (*lplprnNext)->szCmdLine);
  896. // Set the default return for attaching application
  897. //
  898. bReturn = TRUE;
  899. if ( ( uRet == ERROR_SUCCESS_REBOOT_REQUIRED ) ||
  900. ( uRet == ERROR_SUCCESS_REBOOT_INITIATED ) )
  901. {
  902. // We have some code that we need to determine if we do a mini-wipe so we will just fall through
  903. //
  904. (*lplprnNext)->bReboot = TRUE;
  905. }
  906. else if ( uRet != ERROR_SUCCESS )
  907. {
  908. bReturn = FALSE;
  909. FacLogFile(0|LOG_ERR, IDS_MSI_FAILURE, uRet, (*lplprnNext)->lpDisplayName);
  910. }
  911. // Restore internal UI level of MSI installer.
  912. //
  913. MsiSetInternalUI(oldUILevel, NULL);
  914. }
  915. break;
  916. case installtechApp:
  917. case installtechINF:
  918. // Attaching Generic/INF Application
  919. //
  920. {
  921. // Create the path to the application
  922. //
  923. lstrcpyn( szApplication, (*lplprnNext)->szTargetPath, AS(szApplication) );
  924. AddPathN( szApplication, (*lplprnNext)->szSetupFile, AS ( szApplication ) );
  925. // If Installing Generic Application, add the CmdLine and execute script
  926. //
  927. if ((*lplprnNext)->InstallTech == installtechApp )
  928. {
  929. StrCatBuff( szApplication, _T(" "), AS(szApplication) );
  930. StrCatBuff( szApplication, (*lplprnNext)->szCmdLine, AS(szApplication) );
  931. // Launch the program
  932. //
  933. bReturn = CreateProcess(NULL, szApplication, NULL, NULL, FALSE, CREATE_NEW_PROCESS_GROUP, NULL, NULL, &startup, &pi);
  934. }
  935. else
  936. {
  937. // This is an INF that we are processing, process it
  938. //
  939. bReturn = ProcessInfSection(szApplication, (*lplprnNext)->szSectionName);
  940. }
  941. }
  942. break;
  943. default:
  944. bReturn = FALSE;
  945. }
  946. }
  947. else
  948. bReturn = FALSE;
  949. // Log whether the attach succeeded.
  950. //
  951. FacLogFile(bReturn ? 1 : 0|LOG_ERR, bReturn ? IDS_ERR_ATTACHSUCCESS : IDS_ERR_ATTACHFAILED, (*lplprnNext)->lpDisplayName);
  952. break;
  953. }
  954. default:
  955. FacLogFile(0|LOG_ERR, IDS_ERR_UNDEFINSTALL, (*lplprnNext)->lpDisplayName);
  956. break;
  957. }
  958. }
  959. // If we were successful at creating the process, wait on it and then close any open handles
  960. //
  961. if ( bReturn && pi.hProcess)
  962. {
  963. // If this is synchronous, then wait for the process
  964. //
  965. if (dwAction)
  966. {
  967. DWORD dwExitCode = 0;
  968. WaitForSingleObjectEx(pi.hProcess, INFINITE, TRUE);
  969. // Need to log the exit code.
  970. //
  971. if ( GetExitCodeProcess(pi.hProcess, &dwExitCode) )
  972. {
  973. FacLogFile(0, IDS_LOG_APPEXITCODE, (*lplprnNext)->lpDisplayName, dwExitCode);
  974. }
  975. else
  976. {
  977. FacLogFile(0 | LOG_ERR, IDS_LOG_APPEXITCODENONE, (*lplprnNext)->lpDisplayName);
  978. }
  979. }
  980. // Clean up the handles
  981. //
  982. CloseHandle(pi.hProcess);
  983. CloseHandle(pi.hThread);
  984. }
  985. // We must do some post application stuff after the process is complete
  986. //
  987. if ( (*lplprnNext)->InstallTech != installtechUndefined )
  988. {
  989. // In the attach case we may need to do a mini-wipe, do that here
  990. //
  991. if ( (*lplprnNext)->InstallType == installtypeAttach && (*lplprnNext)->bRemoveTarget)
  992. {
  993. if (!DeletePath( (*lplprnNext)->szTargetPath ))
  994. {
  995. FacLogFile(0 | LOG_ERR, IDS_LOG_APPEXITCODENONE, (*lplprnNext)->lpDisplayName);
  996. }
  997. }
  998. }
  999. // Check to see if we need to reboot
  1000. //
  1001. if ( (*lplprnNext)->bReboot )
  1002. {
  1003. OemReboot();
  1004. return;
  1005. }
  1006. // Disconnect any network connections that were opened by factory
  1007. //
  1008. if ( (*lplprnNext)->InstallTech == installtechUndefined )
  1009. {
  1010. // Disconnect to any resources in the RunValue
  1011. //
  1012. FactoryNetworkConnect((*lplprnNext)->lpRunValue, g_szWinBOMPath, NULLSTR, FALSE);
  1013. }
  1014. else
  1015. {
  1016. // Disconnect from any resources in the SourcePath, CommandLine, or StagePath
  1017. FactoryNetworkConnect((*lplprnNext)->szSourcePath, g_szWinBOMPath, NULLSTR, FALSE);
  1018. FactoryNetworkConnect((*lplprnNext)->szCmdLine, g_szWinBOMPath, NULLSTR, FALSE);
  1019. FactoryNetworkConnect((*lplprnNext)->szTargetPath, g_szWinBOMPath, NULLSTR, FALSE);
  1020. }
  1021. }
  1022. // If the dialog is visible, then progress to the next item in the list
  1023. //
  1024. if ( hWnd )
  1025. StatusIncrement(hWnd, bReturn);
  1026. }
  1027. }
  1028. // Delete the applist from memory
  1029. //
  1030. DeleteAppList(lprnAppList);
  1031. }
  1032. /*++
  1033. ===============================================================================
  1034. Routine Description:
  1035. VOID DeleteAppList
  1036. Deletes all the apps in a given list and frees the memory associated with
  1037. the list
  1038. Arguments:
  1039. lprnCurrent - current head of the list
  1040. Return Value:
  1041. None
  1042. ===============================================================================
  1043. --*/
  1044. static void DeleteAppList(LPRUNNODE lprnCurrent)
  1045. {
  1046. if (lprnCurrent->lpNext!=NULL)
  1047. DeleteAppList(lprnCurrent->lpNext);
  1048. FREE(lprnCurrent);
  1049. }
  1050. /*++
  1051. ===============================================================================
  1052. Routine Description:
  1053. VOID OemReboot
  1054. Sets the OEMRESET key and reboots the machine if necessary during the preinstall
  1055. process. The OEMRESET key is there so the user does not see the OEMRESET Reboot
  1056. dialog.
  1057. Arguments:
  1058. None
  1059. Return Value:
  1060. None
  1061. ===============================================================================
  1062. --*/
  1063. static void OemReboot()
  1064. {
  1065. HKEY hkPath;
  1066. DWORD dwRegValue = 1;
  1067. // Set the reboot flag for OEMReset
  1068. //
  1069. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, STR_REG_CURRENTVER, 0, KEY_ALL_ACCESS, &hkPath) == ERROR_SUCCESS)
  1070. {
  1071. // Setthe reboot value for OEMReset in the registry
  1072. //
  1073. RegSetValueEx(hkPath, STR_VAL_OEMRESETSILENT, 0, REG_DWORD, (LPBYTE)&dwRegValue, sizeof(dwRegValue));
  1074. // Do a little bit of cleaning up
  1075. //
  1076. RegCloseKey(hkPath);
  1077. // Set the necessary system privileges to reboot
  1078. //
  1079. EnablePrivilege(SE_SHUTDOWN_NAME,TRUE);
  1080. // Let's reboot the machine
  1081. //
  1082. ExitWindowsEx(EWX_REBOOT, 0);
  1083. }
  1084. }
  1085. /*++
  1086. ===============================================================================
  1087. Routine Description:
  1088. BOOL SetRunOnceState
  1089. This routine sets the current application we are on for the OemRunOnce section
  1090. of the winbom.ini. This allows us to pick up where we left off if there is a
  1091. reboot during the process
  1092. Arguments:
  1093. dwState - State number to set
  1094. Return Value:
  1095. None
  1096. ===============================================================================
  1097. --*/
  1098. static VOID SetRunOnceState(DWORD dwState)
  1099. {
  1100. HKEY hkPath;
  1101. // Open the currentversion key
  1102. //
  1103. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_FACTORY_STATE, 0, KEY_ALL_ACCESS, &hkPath) == ERROR_SUCCESS)
  1104. {
  1105. // Setthe OemRunOnce flag in the registry so we don't run the winbom.ini RunOnce section again
  1106. //
  1107. RegSetValueEx(hkPath, STR_VAL_WINBOMRO, 0, REG_DWORD, (LPBYTE)&dwState, sizeof(dwState));
  1108. RegCloseKey(hkPath);
  1109. }
  1110. }
  1111. /*++
  1112. ===============================================================================
  1113. Routine Description:
  1114. DWORD GetRunOnceState
  1115. This routine gets current (last run) state that we successfully executed
  1116. Arguments:
  1117. None
  1118. Return Value:
  1119. Last successful state
  1120. ===============================================================================
  1121. --*/
  1122. static DWORD GetRunOnceState(VOID)
  1123. {
  1124. HKEY hkPath;
  1125. DWORD dwState = 0,
  1126. dwStateSize = sizeof(dwState);
  1127. // Open the currentversion key
  1128. //
  1129. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_FACTORY_STATE, 0, KEY_ALL_ACCESS, &hkPath) == ERROR_SUCCESS)
  1130. {
  1131. // Setthe OemRunOnce flag in the registry so we don't run the winbom.ini RunOnce section again
  1132. //
  1133. RegQueryValueEx(hkPath, STR_VAL_WINBOMRO, NULL, NULL, (LPBYTE)&dwState, &dwStateSize);
  1134. RegCloseKey(hkPath);
  1135. }
  1136. return dwState;
  1137. }
  1138. /*++
  1139. ===============================================================================
  1140. Routine Description:
  1141. BOOL OemRun
  1142. This routine is a wrapper for the ProcessSection function and will process the
  1143. OemRun section of the winbom.ini
  1144. Arguments:
  1145. Standard state structure
  1146. Return Value:
  1147. TRUE if no error
  1148. FALSE if error
  1149. ===============================================================================
  1150. --*/
  1151. BOOL OemRun(LPSTATEDATA lpStateData)
  1152. {
  1153. return ProcessSection(FALSE);
  1154. }
  1155. BOOL DisplayOemRun(LPSTATEDATA lpStateData)
  1156. {
  1157. return IniSettingExists(lpStateData->lpszWinBOMPath, INF_SEC_OEMRUN, NULL, NULL);
  1158. }
  1159. /*++
  1160. ===============================================================================
  1161. Routine Description:
  1162. BOOL OemRunOnce
  1163. This routine is a wrapper for the ProcessSection function and will process the
  1164. OemRunOnce section of the winbom.ini
  1165. Arguments:
  1166. Standard state structure
  1167. Return Value:
  1168. TRUE if no error
  1169. FALSE if error
  1170. ===============================================================================
  1171. --*/
  1172. BOOL OemRunOnce(LPSTATEDATA lpStateData)
  1173. {
  1174. return ProcessSection(TRUE);
  1175. }
  1176. BOOL DisplayOemRunOnce(LPSTATEDATA lpStateData)
  1177. {
  1178. return IniSettingExists(lpStateData->lpszWinBOMPath, INF_SEC_OEMRUNONCE, NULL, NULL);
  1179. }