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.

1446 lines
47 KiB

  1. /****************************************************************************\
  2. SYSPREP.C / Mass Storage Device Installer (MSDINST.LIB)
  3. Microsoft Confidential
  4. Copyright (c) Microsoft Corporation 2001
  5. All rights reserved
  6. Source file the MSD Installation library which contains the sysprep
  7. releated code taken from the published sysprep code.
  8. 07/2001 - Jason Cohen (JCOHEN)
  9. Added this new source file for the new MSD Installation project.
  10. \****************************************************************************/
  11. //
  12. // Include File(s):
  13. //
  14. #include "pch.h"
  15. #include <winbom.h>
  16. #include "main.h"
  17. //
  18. // Local Define(s):
  19. //
  20. #define SYSPREP_DEVNODE _T("SYSPREP_TEMPORARY")
  21. #define STR_SERVICE_MAIN _T("Service")
  22. #define STR_SERVICE_UPPER _T("UpperFilter")
  23. #define STR_SERVICE_LOWER _T("LowerFilter")
  24. #define STR_SERVICES_SECTION _T(".Services")
  25. #define NUM_SERVICE_MAIN 0
  26. #define NUM_SERVICE_UPPER 1
  27. #define NUM_SERVICE_LOWER 2
  28. #define DIR_I386 _T("i386")
  29. #define DIR_IA64 _T("ia64")
  30. #define REG_KEY_HIVE_CDD _T("ControlSet001\\Control\\CriticalDeviceDatabase")
  31. #define REG_KEY_HIVE_SETUP_SETUP _T("Microsoft\\Windows\\CurrentVersion\\Setup")
  32. #define REG_KEY_SETUP_SETUP REGSTR_PATH_SETUP REGSTR_KEY_SETUP
  33. #define STR_SYSPREP_INF _T("sysprep\\sysprep.inf")
  34. //
  35. // Local Type Define(s):
  36. //
  37. typedef struct _CLEANUP_NODE
  38. {
  39. LPTSTR lpszService;
  40. DWORD dwType;
  41. struct _CLEANUP_NODE * lpNext;
  42. }
  43. CLEANUP_NODE, *PCLEANUP_NODE, *LPCLEANUP_NODE;
  44. //
  45. // Local Global(s):
  46. //
  47. static LPTSTR s_lpszServiceType[] =
  48. {
  49. STR_SERVICE_MAIN,
  50. STR_SERVICE_UPPER,
  51. STR_SERVICE_LOWER,
  52. };
  53. //
  54. // Local Prototype(s):
  55. //
  56. static BOOL SysprepDevnode(HDEVINFO * phDevInfo, SP_DEVINFO_DATA * pDeviceInfoData, BOOL bCreate);
  57. static BOOL
  58. GetDeviceInstallSection(
  59. IN HDEVINFO hDevInfo,
  60. IN PSP_DEVINFO_DATA pDeviceInfoData,
  61. IN PSP_DRVINFO_DATA pDriverInfoData,
  62. OUT LPTSTR lpszSection,
  63. IN DWORD cbSection
  64. );
  65. static BOOL
  66. GetDeviceServicesSection(
  67. IN HDEVINFO hDevInfo,
  68. IN PSP_DEVINFO_DATA pDeviceInfoData,
  69. IN PSP_DRVINFO_DATA pDriverInfoData,
  70. OUT LPTSTR lpszSection,
  71. IN DWORD cbSection
  72. );
  73. static BOOL
  74. ProcessDeviceProperty(
  75. IN HDEVINFO hDevInfo,
  76. IN PSP_DEVINFO_DATA pDeviceInfoData,
  77. IN LPCLEANUP_NODE * lplpcnList,
  78. IN HKEY hkeyDevice,
  79. IN HKEY hkeySystem,
  80. IN LPTSTR lpszInfPath,
  81. IN LPTSTR lpszServiceSection,
  82. IN DWORD dwProperty
  83. );
  84. static BOOL AddCleanup(LPCLEANUP_NODE * lplpcnHead, LPTSTR lpszService, DWORD dwType);
  85. static LPCLEANUP_NODE OpenCleanup(LPTSTR lpszInfFile);
  86. static BOOL SaveCleanup(LPTSTR lpszInfFile, LPCLEANUP_NODE lpcnHead);
  87. static void CloseCleanup(LPCLEANUP_NODE lpcnHead);
  88. static BOOL AddStrToSect(LPTSTR * lplpmszSect, DWORD * lpcbSect, LPTSTR * lplpmszEnd, DWORD * lpdwSize, LPTSTR lpszStr);
  89. static BOOL
  90. OfflineSourcePath(
  91. HKEY hkeySoftware,
  92. LPTSTR lpszWindows,
  93. LPTSTR lpszSourcePath,
  94. DWORD cbSourcePath
  95. );
  96. //
  97. // Exported Funtion(s):
  98. //
  99. BOOL
  100. SetupCriticalDevices(
  101. LPTSTR lpszInfFile,
  102. HKEY hkeySoftware,
  103. HKEY hkeySystem,
  104. LPTSTR lpszWindows
  105. )
  106. /*++
  107. ===============================================================================
  108. Routine Description:
  109. Parse the [SysprepMassStorage] section in the sysprep.inf file and
  110. populate the critical device database with the specified devices to ensure
  111. that we can boot into the miniwizard when moving the image to a target
  112. system with different boot storage devices.
  113. The installed services/upperfilters/lowerfilters will be recorded, so
  114. that on the next boot into the mini-wizard those without an associated
  115. device will be disabled (the cleanup stage) in order not to unnecessarily
  116. degrade Windows start time.
  117. Arguments:
  118. None.
  119. Return Value:
  120. TRUE if everything is OK, FALSE otherwise.
  121. Assumptions:
  122. 1. No HardwareID exceeds MAX_PATH characters.
  123. 2. No field on a line in the [SysprepMassStorage] section exceeds MAX_PATH
  124. characters.
  125. 3. No service's/upperfilter's/lowerfilter's name exceeds MAX_PATH characters.
  126. 4. DirectoryOnSourceDevice, source DiskDescription, or source DiskTag
  127. (applying to vendor-supplied drivers) cannot exceed MAX_PATH characters.
  128. ===============================================================================
  129. --*/
  130. {
  131. TCHAR szSysprepInfFile[MAX_PATH] = NULLSTR,
  132. szDevice[MAX_PATH],
  133. szSection[MAX_PATH],
  134. szPath[MAX_PATH],
  135. szSourcePath[MAX_PATH];
  136. DWORD dwSize,
  137. dwDis;
  138. LPTSTR lpszCleanupInfFile,
  139. lpszReplace,
  140. lpszSourcePath = NULL;
  141. BOOL bDevnode = TRUE,
  142. bAllOK = TRUE,
  143. bLineExists,
  144. b2ndTry;
  145. HKEY hkeyCDD = NULL,
  146. hkeyDevice = NULL;
  147. LPCLEANUP_NODE lpcnCleanupList;
  148. HINF hInf;
  149. INFCONTEXT InfContext;
  150. HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
  151. SP_DEVINFO_DATA DeviceInfoData;
  152. SP_DEVINSTALL_PARAMS DevInstallParams;
  153. SP_DRVINFO_DATA DriverInfoData;
  154. HSPFILEQ QueueHandle = INVALID_HANDLE_VALUE;
  155. // Do a little parameter validation.
  156. //
  157. if ( ( NULL == hkeySoftware ) ||
  158. ( NULL == hkeySystem ) ||
  159. ( NULL == lpszWindows ) )
  160. {
  161. // If any of these parameters are NULL, then they
  162. // all must be.
  163. //
  164. hkeySoftware = NULL;
  165. hkeySystem = NULL;
  166. lpszWindows = NULL;
  167. }
  168. // Open the inf file with the mass storage list.
  169. //
  170. hInf = SetupOpenInfFile(lpszInfFile, NULL, INF_STYLE_OLDNT | INF_STYLE_WIN4, NULL);
  171. if ( INVALID_HANDLE_VALUE == hInf )
  172. {
  173. OpkLogFile(0 | LOG_ERR, IDS_ERR_OPEN_INF, lpszInfFile);
  174. return FALSE;
  175. }
  176. // If this is offline, we write the cleanup section to the sysprep inf
  177. // that is in the image.
  178. //
  179. if ( lpszWindows )
  180. {
  181. LPTSTR lpFound;
  182. // Strip the windows directory off the offline path so we can build a path to the sysprep.inf.
  183. //
  184. lstrcpy(szSysprepInfFile, lpszWindows);
  185. lpFound = _tcsrchr(szSysprepInfFile, _T('\\'));
  186. // Just in case the lpszWindows folder has a trailing backslash handle that here.
  187. // If this is the case, the character after the backslash is a NULL. Remove the trailing backslash,
  188. // and do the search for the last backslash again. This will be the one we actually want to
  189. // get rid of.
  190. //
  191. if ( !(*(lpFound + 1)) )
  192. {
  193. *lpFound = NULLCHR;
  194. lpFound = _tcsrchr(szSysprepInfFile, _T('\\'));
  195. }
  196. // Cut off the path in front of the windows directory name.
  197. // Add the sysprep.inf path part.
  198. // Set our cleanup file to point to the path we just built.
  199. //
  200. *lpFound = NULLCHR;
  201. AddPathN(szSysprepInfFile, STR_SYSPREP_INF, AS(szSysprepInfFile));
  202. lpszCleanupInfFile = szSysprepInfFile;
  203. }
  204. else
  205. {
  206. lpszCleanupInfFile = lpszInfFile;
  207. }
  208. // If this is an offline install, then we need to get the source path
  209. // to our image.
  210. //
  211. if ( hkeySoftware && lpszWindows &&
  212. OfflineSourcePath(hkeySoftware, lpszWindows, szSourcePath, AS(szSourcePath)) )
  213. {
  214. lpszSourcePath = szSourcePath;
  215. }
  216. // We need a handle to the critical device database registry key if we
  217. // are doing an offline install.
  218. //
  219. if ( ( hkeySystem ) &&
  220. ( ERROR_SUCCESS != RegCreateKeyEx(hkeySystem,
  221. REG_KEY_HIVE_CDD,
  222. 0,
  223. NULL,
  224. REG_OPTION_NON_VOLATILE,
  225. KEY_ALL_ACCESS,
  226. NULL,
  227. &hkeyCDD,
  228. &dwDis) ) )
  229. {
  230. SetupCloseInfFile(hInf);
  231. OpkLogFile(0 | LOG_ERR, IDS_ERR_OPEN_OFFLINECDD);
  232. return FALSE;
  233. }
  234. // Create a dummy devnode.
  235. //
  236. if ( !SysprepDevnode(&hDevInfo, &DeviceInfoData, TRUE) )
  237. {
  238. if ( hkeyCDD )
  239. {
  240. RegCloseKey(hkeyCDD);
  241. }
  242. SetupCloseInfFile(hInf);
  243. OpkLogFile(0 | LOG_ERR, IDS_ERR_CREATE_DEVNODE);
  244. return FALSE;
  245. }
  246. // Init the driver info data structure.
  247. //
  248. ZeroMemory(&DriverInfoData, sizeof(SP_DRVINFO_DATA));
  249. DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
  250. // Read the current cleanup section in the inf file.
  251. //
  252. lpcnCleanupList = OpenCleanup(lpszCleanupInfFile);
  253. // Process each line in our section. Each line should look like:
  254. // <hardware-id>=<inf pathname>
  255. //
  256. // Or in the case of drivers that aren't on the product CD:
  257. // <hardware-id>=<inf pathname>,<directory on recovery floppy>,<description of recovery floppy>,<disk tag of recovery floppy>
  258. //
  259. // If we see an entry like this, we'll know that in the case of system recovery, the
  260. // file should be retrived from a floppy, and not the Windows CD.
  261. //
  262. for ( bLineExists = SetupFindFirstLine(hInf, INI_SEC_WBOM_SYSPREP_MSD, NULL, &InfContext);
  263. bLineExists;
  264. bLineExists = SetupFindNextLine(&InfContext, &InfContext) )
  265. {
  266. // Retrieve the hardwareID from the line.
  267. //
  268. dwSize = AS(szDevice);
  269. if ( !SetupGetStringField(&InfContext, 0, szDevice, dwSize, &dwSize) )
  270. {
  271. bAllOK = FALSE;
  272. continue;
  273. }
  274. // We do this in a loop because we might try twice.
  275. //
  276. b2ndTry = FALSE;
  277. do
  278. {
  279. // And then set it to the devnode.
  280. //
  281. if ( !SetupDiSetDeviceRegistryProperty(hDevInfo,
  282. &DeviceInfoData,
  283. SPDRP_HARDWAREID,
  284. (LPBYTE) szDevice,
  285. (lstrlen(szDevice)+1) * sizeof(TCHAR)) )
  286. {
  287. // If someone removed the devnode, we need to re-create it and repeat this set.
  288. //
  289. if ( ( !b2ndTry ) &&
  290. ( ERROR_NO_SUCH_DEVINST == GetLastError() ) )
  291. {
  292. // Sometimes devices remove the devnode after we install, so we should
  293. // try once to recreate.
  294. //
  295. if ( SysprepDevnode(&hDevInfo, &DeviceInfoData, TRUE) )
  296. {
  297. // If we were able to recreate it, then we should try this again.
  298. //
  299. b2ndTry = TRUE;
  300. }
  301. else
  302. {
  303. // We are really screwed if we have no devnode.
  304. //
  305. bDevnode = FALSE;
  306. }
  307. }
  308. else
  309. {
  310. // Either we tried again already, or there is another error.
  311. //
  312. bAllOK = b2ndTry = FALSE;
  313. }
  314. }
  315. else
  316. {
  317. // It worked, so make sure we don't loop again in case this is the second time
  318. // through.
  319. //
  320. b2ndTry = FALSE;
  321. }
  322. }
  323. while ( b2ndTry );
  324. // If we the devnode was lost and unable to be recreated, then we just have
  325. // to bail out.
  326. //
  327. if ( !bDevnode )
  328. {
  329. OpkLogFile(0 | LOG_ERR, IDS_ERR_CREATE_DEVNODE);
  330. break;
  331. }
  332. // Build the SP_DEVINSTALL_PARAMS for this node.
  333. //
  334. DevInstallParams.cbSize = sizeof(DevInstallParams);
  335. if ( !SetupDiGetDeviceInstallParams(hDevInfo, &DeviceInfoData, &DevInstallParams) )
  336. {
  337. bAllOK = FALSE;
  338. continue;
  339. }
  340. // Set the Flags field: only search the INF file specified in DriverPath field;
  341. // don't create a copy queue, use the provided one in FileQueue; don't call the
  342. // Configuration Manager while populating the CriticalDeviceDatabase.
  343. //
  344. DevInstallParams.Flags |= ( DI_ENUMSINGLEINF |
  345. DI_NOVCP |
  346. DI_DONOTCALLCONFIGMG );
  347. // Set the device's inf pathname
  348. //
  349. dwSize = AS(szPath);
  350. if ( !SetupGetStringField(&InfContext, 1, szPath, dwSize, &dwSize) )
  351. {
  352. OpkLogFile(0 | LOG_ERR, IDS_ERR_GET_INF_NAME);
  353. bAllOK = FALSE;
  354. continue;
  355. }
  356. ExpandEnvironmentStrings(szPath, DevInstallParams.DriverPath, AS(DevInstallParams.DriverPath));
  357. lstrcpyn(szPath, DevInstallParams.DriverPath, AS(szPath));
  358. // Replace the backslashes with pounds in the pnp id so we can use it for the registry key.
  359. //
  360. for ( lpszReplace = szDevice; *lpszReplace; lpszReplace = CharNext(lpszReplace) )
  361. {
  362. if ( _T('\\') == *lpszReplace )
  363. {
  364. *lpszReplace = _T('#');
  365. }
  366. }
  367. // Set the file queue field
  368. //
  369. QueueHandle = SetupOpenFileQueue();
  370. if ( INVALID_HANDLE_VALUE == QueueHandle )
  371. {
  372. OpkLogFile(0 | LOG_ERR, IDS_ERR_OPEN_FILE_QUEUE);
  373. bAllOK = FALSE;
  374. continue;
  375. }
  376. DevInstallParams.FileQueue = QueueHandle;
  377. // 1. Save the parameters we have set.
  378. // 2. Register the newly created device instance with the PnP Manager.
  379. // 3. Perform a compatible driver search.
  380. //
  381. if ( ( SetupDiSetDeviceInstallParams(hDevInfo, &DeviceInfoData, &DevInstallParams) ) &&
  382. ( SetupDiCallClassInstaller(DIF_REGISTERDEVICE, hDevInfo, &DeviceInfoData) ) &&
  383. ( SetupDiBuildDriverInfoList(hDevInfo, &DeviceInfoData, SPDIT_COMPATDRIVER) ) )
  384. {
  385. // Make sure there is at least 1 compat driver for this device.
  386. // If there is not, and then we just process the next one in the list.
  387. //
  388. if ( SetupDiEnumDriverInfo(hDevInfo,
  389. &DeviceInfoData,
  390. SPDIT_COMPATDRIVER,
  391. 0,
  392. &DriverInfoData) )
  393. {
  394. // 1. Select the best compatible driver.
  395. // 2. Install the driver files.
  396. // 3. Make sure we are able to create the drivers key in the CDD if
  397. // we are doing an offline install (otherwise the CDD key will be
  398. // NULL and we don't have to worry about creating the key).
  399. //
  400. if ( ( SetupDiCallClassInstaller(DIF_SELECTBESTCOMPATDRV, hDevInfo, &DeviceInfoData) ) &&
  401. ( SetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES, hDevInfo, &DeviceInfoData) ) &&
  402. ( ( NULL == hkeyCDD ) ||
  403. ( ERROR_SUCCESS == RegCreateKeyEx(hkeyCDD, szDevice, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkeyDevice, &dwDis) ) ) )
  404. {
  405. // Need to commit the file queue here, so the later steps can properly
  406. // be executed in case the device doesn't use the already existing
  407. // coinstaller(s).
  408. //
  409. // ACOSMA code here...
  410. //
  411. if ( !OfflineCommitFileQueue(QueueHandle, szPath, lpszSourcePath, lpszWindows) )
  412. {
  413. OpkLogFile(0 | LOG_ERR, IDS_ERR_COMMIT_OFFLINE_QUEUE);
  414. bAllOK = FALSE;
  415. }
  416. // Install the device (do we really need to do this for the offline case).
  417. //
  418. #if 0
  419. if ( SetupDiCallClassInstaller(DIF_INSTALLDEVICE,
  420. hDevInfo,
  421. &DeviceInfoData) )
  422. #else
  423. SetupDiInstallDevice(hDevInfo,
  424. &DeviceInfoData);
  425. #endif
  426. {
  427. //
  428. // Retrieve class guid (if offline) upper filters, lower filters,
  429. // and controlling service, save them back to the inf file and put
  430. // them in the hive (if offline).
  431. //
  432. // Retrieve the device class GUID (only needed for offline install).
  433. //
  434. if ( ( hkeyDevice ) &&
  435. ( !ProcessDeviceProperty(hDevInfo,
  436. &DeviceInfoData,
  437. &lpcnCleanupList,
  438. hkeyDevice,
  439. hkeySystem,
  440. szPath,
  441. NULL,
  442. SPDRP_CLASSGUID) ) )
  443. {
  444. OpkLogFile(0 | LOG_ERR, IDS_ERR_CLASS_GUID);
  445. bAllOK = FALSE;
  446. }
  447. if ( !GetDeviceServicesSection(hDevInfo, &DeviceInfoData, &DriverInfoData, szSection, AS(szSection)) )
  448. {
  449. szSection[0] = NULLCHR;
  450. bAllOK = FALSE;
  451. }
  452. // Retrieve device upper filters (REG_MULTI_SZ).
  453. //
  454. if ( !ProcessDeviceProperty(hDevInfo,
  455. &DeviceInfoData,
  456. &lpcnCleanupList,
  457. hkeyDevice,
  458. hkeySystem,
  459. szPath,
  460. szSection[0] ? szSection : NULL,
  461. SPDRP_UPPERFILTERS) )
  462. {
  463. OpkLogFile(0 | LOG_ERR, IDS_ERR_UPPER_FILTERS);
  464. bAllOK = FALSE;
  465. }
  466. // Retrieve device lower filters (REG_MULTI_SZ).
  467. //
  468. if ( !ProcessDeviceProperty(hDevInfo,
  469. &DeviceInfoData,
  470. &lpcnCleanupList,
  471. hkeyDevice,
  472. hkeySystem,
  473. szPath,
  474. szSection[0] ? szSection : NULL,
  475. SPDRP_LOWERFILTERS) )
  476. {
  477. OpkLogFile(0 | LOG_ERR, IDS_ERR_LOWER_FILTERS);
  478. bAllOK = FALSE;
  479. }
  480. // Retrieve device its controlling service (REG_SZ).
  481. //
  482. if ( !ProcessDeviceProperty(hDevInfo,
  483. &DeviceInfoData,
  484. &lpcnCleanupList,
  485. hkeyDevice,
  486. hkeySystem,
  487. szPath,
  488. szSection[0] ? szSection : NULL,
  489. SPDRP_SERVICE) )
  490. {
  491. OpkLogFile(0 | LOG_ERR, IDS_ERR_DEVICE_SERVICE);
  492. bAllOK = FALSE;
  493. }
  494. }
  495. // Close the device registry key in the CDD.
  496. //
  497. if ( hkeyDevice )
  498. {
  499. RegCloseKey(hkeyDevice);
  500. hkeyDevice = NULL;
  501. }
  502. }
  503. else
  504. {
  505. OpkLogFile(0 | LOG_ERR, IDS_ERR_SELECT_COMPAT);
  506. bAllOK = FALSE;
  507. }
  508. }
  509. else
  510. {
  511. // Check to see what the error was. Any error other than ERROR_NO_MORE_ITEMS
  512. // will be flaged, by setting the bAllOK return value to FALSE.
  513. //
  514. if ( ERROR_NO_MORE_ITEMS != GetLastError() )
  515. {
  516. OpkLogFile(0 | LOG_ERR, IDS_ERR_ENUM_COMPAT_DRIVER);
  517. bAllOK = FALSE;
  518. }
  519. }
  520. // Make sure that there's no existing compatible list, since we're reusing
  521. // the dummy devnode.
  522. //
  523. if ( !SetupDiDestroyDriverInfoList(hDevInfo, &DeviceInfoData, SPDIT_COMPATDRIVER) )
  524. {
  525. bAllOK = FALSE;
  526. }
  527. }
  528. else
  529. {
  530. OpkLogFile(0 | LOG_ERR, IDS_ERR_BUILD_COMPAT_DRIVER);
  531. bAllOK = FALSE;
  532. }
  533. // Dis-associate file copy queue before we close the queue.
  534. //
  535. DevInstallParams.cbSize = sizeof(DevInstallParams);
  536. if ( SetupDiGetDeviceInstallParams(hDevInfo, &DeviceInfoData, &DevInstallParams) )
  537. {
  538. // Remove the DI_NOVCP flag and NULL out the FileQueue.
  539. //
  540. DevInstallParams.Flags &= ~DI_NOVCP;
  541. DevInstallParams.FileQueue = NULL;
  542. if ( !SetupDiSetDeviceInstallParams(hDevInfo, &DeviceInfoData, &DevInstallParams) )
  543. {
  544. bAllOK = FALSE;
  545. }
  546. }
  547. else
  548. {
  549. bAllOK = FALSE;
  550. }
  551. // Close the file queue.
  552. //
  553. SetupCloseFileQueue(QueueHandle);
  554. }
  555. // See if we still have the devnode.
  556. //
  557. if ( bDevnode )
  558. {
  559. // Remove the SYSPREP_TEMPORARY node under Root.
  560. //
  561. SysprepDevnode(&hDevInfo, &DeviceInfoData, FALSE);
  562. }
  563. else
  564. {
  565. // If the devnode is lost, we need to make sure we return an error.
  566. //
  567. bAllOK = FALSE;
  568. }
  569. // If an offline install, we need to close this key.
  570. //
  571. if ( hkeyCDD )
  572. {
  573. RegCloseKey(hkeyCDD);
  574. }
  575. // Close the handles to our inf files.
  576. //
  577. SetupCloseInfFile(hInf);
  578. //
  579. // Check if the caller wants us to update the offline device path...
  580. //
  581. UpdateOfflineDevicePath( lpszInfFile, hkeySoftware );
  582. // We need to save our cleanup list back to the inf file.
  583. //
  584. SaveCleanup(lpszCleanupInfFile, lpcnCleanupList);
  585. CloseCleanup(lpcnCleanupList);
  586. return bAllOK;
  587. }
  588. //
  589. // Local Function(s):
  590. //
  591. static BOOL SysprepDevnode(HDEVINFO * phDevInfo, SP_DEVINFO_DATA * pDeviceInfoData, BOOL bCreate)
  592. {
  593. BOOL bRet = TRUE;
  594. if ( ( NULL == phDevInfo ) ||
  595. ( NULL == pDeviceInfoData ) )
  596. {
  597. return FALSE;
  598. }
  599. if ( bCreate )
  600. {
  601. // Create a dummy devnode.
  602. //
  603. *phDevInfo = SetupDiCreateDeviceInfoList(NULL, NULL);
  604. if ( INVALID_HANDLE_VALUE == *phDevInfo )
  605. {
  606. return FALSE;
  607. }
  608. // Initialize the DriverInfoData struct.
  609. //
  610. ZeroMemory(pDeviceInfoData, sizeof(SP_DEVINFO_DATA));
  611. pDeviceInfoData->cbSize = sizeof(SP_DEVINFO_DATA);
  612. // Create the devnode.
  613. //
  614. if ( !SetupDiCreateDeviceInfo(*phDevInfo,
  615. SYSPREP_DEVNODE,
  616. (LPGUID) &GUID_NULL,
  617. NULL,
  618. NULL,
  619. DICD_GENERATE_ID,
  620. pDeviceInfoData) )
  621. {
  622. bRet = FALSE;
  623. }
  624. }
  625. else
  626. {
  627. // Remove the dummy devnode.
  628. //
  629. SetupDiCallClassInstaller(DIF_REMOVE, *phDevInfo, pDeviceInfoData);
  630. }
  631. if ( ( !bCreate || !bRet ) &&
  632. ( INVALID_HANDLE_VALUE != *phDevInfo ) )
  633. {
  634. // Free up the dev info list (if we are removing the node or there
  635. // was an error).
  636. //
  637. SetupDiDestroyDeviceInfoList(*phDevInfo);
  638. *phDevInfo = INVALID_HANDLE_VALUE;
  639. }
  640. return bRet;
  641. }
  642. static BOOL
  643. GetDeviceInstallSection(
  644. IN HDEVINFO hDevInfo,
  645. IN PSP_DEVINFO_DATA pDeviceInfoData,
  646. IN PSP_DRVINFO_DATA pDriverInfoData,
  647. OUT LPTSTR lpszSection,
  648. IN DWORD cbSection
  649. )
  650. {
  651. BOOL bRet = FALSE;
  652. PSP_DRVINFO_DETAIL_DATA pDriverInfoDetailData;
  653. DWORD cbBytesNeeded;
  654. // Must have a buffer to return the data or else
  655. // there is no point.
  656. //
  657. if ( ( NULL == lpszSection ) ||
  658. ( 0 == cbSection ) )
  659. {
  660. return FALSE;
  661. }
  662. // Call the api once to get the size. We expect this
  663. // to return a failure.
  664. //
  665. SetLastError(ERROR_SUCCESS);
  666. SetupDiGetDriverInfoDetail(hDevInfo,
  667. pDeviceInfoData,
  668. pDriverInfoData,
  669. NULL,
  670. 0,
  671. &cbBytesNeeded);
  672. // Check for the error, it should be insufficient buffer. Then
  673. // try and allocate the memory needed.
  674. //
  675. if ( ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) &&
  676. ( cbBytesNeeded ) &&
  677. ( pDriverInfoDetailData = (PSP_DRVINFO_DETAIL_DATA) MALLOC(cbBytesNeeded) ) )
  678. {
  679. // Zero out the memory (although the MALLOC guy should be doing that) and
  680. // set the size of the structure.
  681. //
  682. ZeroMemory(pDriverInfoDetailData, cbBytesNeeded);
  683. pDriverInfoDetailData->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
  684. // Now call the function again to get data now that we have our buffer.
  685. //
  686. if ( SetupDiGetDriverInfoDetail(hDevInfo,
  687. pDeviceInfoData,
  688. pDriverInfoData,
  689. pDriverInfoDetailData,
  690. cbBytesNeeded,
  691. NULL) )
  692. {
  693. HINF hDeviceInf;
  694. hDeviceInf = SetupOpenInfFile( pDriverInfoDetailData->InfFileName, NULL, INF_STYLE_OLDNT | INF_STYLE_WIN4, NULL);
  695. if ( INVALID_HANDLE_VALUE != hDeviceInf )
  696. {
  697. DWORD dwInfSectionWithExtLength = 0;
  698. //
  699. // Use SetupDiGetActualSectionToInstall to figure out the decorated driver section...
  700. //
  701. bRet = SetupDiGetActualSectionToInstall( hDeviceInf,
  702. pDriverInfoDetailData->SectionName,
  703. lpszSection,
  704. cbSection,
  705. &dwInfSectionWithExtLength,
  706. NULL );
  707. SetupCloseInfFile( hDeviceInf );
  708. }
  709. }
  710. // Always free the memory now that we have the data we need.
  711. //
  712. FREE(pDriverInfoDetailData);
  713. }
  714. // Only return TRUE if we returned something in their buffer.
  715. //
  716. return bRet;
  717. }
  718. static BOOL
  719. GetDeviceServicesSection(
  720. IN HDEVINFO hDevInfo,
  721. IN PSP_DEVINFO_DATA pDeviceInfoData,
  722. IN PSP_DRVINFO_DATA pDriverInfoData,
  723. OUT LPTSTR lpszSection,
  724. IN DWORD cbSection
  725. )
  726. {
  727. BOOL bRet;
  728. // Call our other function to get the device's install section.
  729. //
  730. bRet = GetDeviceInstallSection(hDevInfo,
  731. pDeviceInfoData,
  732. pDriverInfoData,
  733. lpszSection,
  734. cbSection);
  735. // If it worked, add on the part that makes in the service.
  736. // section.
  737. //
  738. if ( bRet )
  739. {
  740. // Make sure there is enough room to add on our string.
  741. //
  742. if ( AS(STR_SERVICES_SECTION) + lstrlen(lpszSection) <= cbSection )
  743. {
  744. // Woo hoo, add it.
  745. //
  746. lstrcat(lpszSection, STR_SERVICES_SECTION);
  747. }
  748. else
  749. {
  750. // Not enough room, so return an error and null out
  751. // the caller's buffer.
  752. //
  753. *lpszSection = NULLCHR;
  754. bRet = FALSE;
  755. }
  756. }
  757. // Return TRUE only if something valid in the buffer.
  758. //
  759. return bRet;
  760. }
  761. static BOOL
  762. ProcessDeviceProperty(
  763. IN HDEVINFO hDevInfo,
  764. IN PSP_DEVINFO_DATA pDeviceInfoData,
  765. IN LPCLEANUP_NODE * lplpcnList,
  766. IN HKEY hkeyDevice,
  767. IN HKEY hkeySystem,
  768. IN LPTSTR lpszInfPath,
  769. IN LPTSTR lpszServiceSection,
  770. IN DWORD dwProperty
  771. )
  772. {
  773. BOOL bRet = TRUE;
  774. DWORD dwServiceType,
  775. dwRegType,
  776. dwRegSize;
  777. LPTSTR lpszRegKey,
  778. lpszBuffer,
  779. lpszService;
  780. // Figure out the other data we need based on
  781. // the property.
  782. //
  783. switch ( dwProperty )
  784. {
  785. case SPDRP_CLASSGUID:
  786. lpszRegKey = REGSTR_VAL_CLASSGUID;
  787. dwServiceType = 0xFFFFFFFF;
  788. break;
  789. case SPDRP_UPPERFILTERS:
  790. lpszRegKey = REGSTR_VAL_UPPERFILTERS;
  791. dwServiceType = NUM_SERVICE_UPPER;
  792. break;
  793. case SPDRP_LOWERFILTERS:
  794. lpszRegKey = REGSTR_VAL_LOWERFILTERS;
  795. dwServiceType = NUM_SERVICE_LOWER;
  796. break;
  797. case SPDRP_SERVICE:
  798. lpszRegKey = REGSTR_VAL_SERVICE;
  799. dwServiceType = NUM_SERVICE_MAIN;
  800. break;
  801. default:
  802. return FALSE;
  803. }
  804. // Call the registry property api to figure out the size of buffer
  805. // we need.
  806. //
  807. SetLastError(ERROR_SUCCESS);
  808. SetupDiGetDeviceRegistryProperty(hDevInfo,
  809. pDeviceInfoData,
  810. dwProperty,
  811. &dwRegType,
  812. NULL,
  813. 0,
  814. &dwRegSize);
  815. // If we get any other error then the one we are expecting, then just
  816. // return TRUE.
  817. //
  818. if ( ERROR_INSUFFICIENT_BUFFER != GetLastError() )
  819. {
  820. return TRUE;
  821. }
  822. // Make sure reg type is a string.
  823. //
  824. switch ( dwRegType )
  825. {
  826. // We support both REG_SZ and REG_MULTI_SZ.
  827. //
  828. case REG_SZ:
  829. case REG_MULTI_SZ:
  830. // Don't really support this, but if the key happens to be
  831. // this type it should still work fine.
  832. //
  833. case REG_EXPAND_SZ:
  834. break;
  835. // Any other type and there must be some kind of
  836. // error.
  837. //
  838. default:
  839. return FALSE;
  840. }
  841. // Now allocate the buffer we need. This must succeed.
  842. //
  843. lpszBuffer = (LPTSTR) MALLOC(dwRegSize);
  844. if ( NULL == lpszBuffer )
  845. {
  846. return FALSE;
  847. }
  848. // Retrieve device information.
  849. //
  850. if ( SetupDiGetDeviceRegistryProperty(hDevInfo,
  851. pDeviceInfoData,
  852. dwProperty,
  853. &dwRegType,
  854. (LPBYTE) lpszBuffer,
  855. dwRegSize,
  856. &dwRegSize) )
  857. {
  858. // If this is a service, save it to our cleanup list.
  859. //
  860. if ( 0xFFFFFFFF != dwServiceType )
  861. {
  862. // Go through all the services (or just one if not multi sz).
  863. //
  864. for ( lpszService = lpszBuffer; *lpszService; lpszService += (lstrlen(lpszService) + 1) )
  865. {
  866. // Need to make sure this service is installed (only needed for offline install).
  867. //
  868. if ( hkeySystem )
  869. {
  870. // BRIANK code here...
  871. //
  872. AddService(lpszService, lpszServiceSection, lpszInfPath, hkeySystem);
  873. }
  874. // Add to our cleanup list.
  875. //
  876. AddCleanup(lplpcnList, lpszService, dwServiceType);
  877. // If this isn't a multi sz string, break out so we don't
  878. // try to do anymore.
  879. //
  880. if ( REG_MULTI_SZ != dwRegType )
  881. {
  882. break;
  883. }
  884. }
  885. }
  886. // Write it to the CDD (only needed for offline install).
  887. //
  888. if ( ( hkeyDevice ) &&
  889. ( ERROR_SUCCESS != RegSetValueEx(hkeyDevice,
  890. lpszRegKey,
  891. 0,
  892. dwRegType,
  893. (CONST LPBYTE) lpszBuffer,
  894. dwRegSize) ) )
  895. {
  896. // If a set value fails, we need to return an error.
  897. //
  898. bRet = FALSE;
  899. }
  900. }
  901. // Make sure we free the buffer we allocated.
  902. //
  903. FREE(lpszBuffer);
  904. return bRet;
  905. }
  906. static BOOL AddCleanup(LPCLEANUP_NODE * lplpcnHead, LPTSTR lpszService, DWORD dwType)
  907. {
  908. LPCLEANUP_NODE lpcnAdd = *lplpcnHead;
  909. // Loop through our list looking for the a duplicate node.
  910. //
  911. while ( lpcnAdd )
  912. {
  913. // See if the node we want to add is the same as this one.
  914. //
  915. if ( 0 == lstrcmpi(lpcnAdd->lpszService, lpszService) )
  916. {
  917. // Already in the list, just return TRUE.
  918. //
  919. return TRUE;
  920. }
  921. // Advance to the next item in the list.
  922. //
  923. lplpcnHead = &(lpcnAdd->lpNext);
  924. lpcnAdd = lpcnAdd->lpNext;
  925. }
  926. // If we didn't find a duplicate node then we need to add ours.
  927. //
  928. if ( lpcnAdd = (LPCLEANUP_NODE) MALLOC(sizeof(CLEANUP_NODE)) )
  929. {
  930. // Okay, now if all that worked, we just need to alloc the memory for the string
  931. // that contains the name of the service.
  932. //
  933. if ( lpcnAdd->lpszService = (LPTSTR) MALLOC((lstrlen(lpszService) + 1) * sizeof(TCHAR)) )
  934. {
  935. // Already, copy the service string into the buffer we just allocated.
  936. //
  937. lstrcpy(lpcnAdd->lpszService, lpszService);
  938. // Save the type in our node.
  939. //
  940. lpcnAdd->dwType = dwType;
  941. // NULL out the next pointer since this is always the last item in
  942. // the list (shouldn't have to do this because my malloc macro is
  943. // supposed to zero memory, but for some reason it isn't working right.
  944. //
  945. lpcnAdd->lpNext = NULL;
  946. // We should now have a pointer to the address of the next pointer
  947. // in the last node (or the head pointer). Just add our node there.
  948. //
  949. *lplpcnHead = lpcnAdd;
  950. // At this point we are all done.
  951. //
  952. return TRUE;
  953. }
  954. else
  955. {
  956. // Failed, so free our node that we were going to add.
  957. //
  958. FREE(lpcnAdd);
  959. }
  960. }
  961. // Now if we ended up here, some memory allocation must have failed.
  962. //
  963. return FALSE;
  964. }
  965. static LPCLEANUP_NODE OpenCleanup(LPTSTR lpszInfFile)
  966. {
  967. LPCLEANUP_NODE lpcnHead = NULL,
  968. lpcnNew,
  969. *lplpcnAdd = &lpcnHead;
  970. HINF hInf;
  971. BOOL bLoop;
  972. INFCONTEXT InfContext;
  973. TCHAR szService[MAX_PATH];
  974. DWORD dwType;
  975. // First open up the inf. If it failes, there is no need to do anything
  976. // because there is nothing to read. Just return NULL.
  977. //
  978. hInf = SetupOpenInfFile(lpszInfFile, NULL, INF_STYLE_OLDNT | INF_STYLE_WIN4, NULL);
  979. if ( INVALID_HANDLE_VALUE == hInf )
  980. {
  981. return NULL;
  982. }
  983. // Loop through all the lines in the sysprep cleanup section.
  984. //
  985. for ( bLoop = SetupFindFirstLine(hInf, INI_SEC_WBOM_SYSPREP_CLEAN, NULL, &InfContext);
  986. bLoop;
  987. bLoop = SetupFindNextLine(&InfContext, &InfContext) )
  988. {
  989. // First get the service type (which is before the =).
  990. //
  991. if ( SetupGetStringField(&InfContext, 0, szService, AS(szService), NULL) )
  992. {
  993. // Now make sure it is a reconized type (either service, upperfilter,
  994. // or lowerfilter).
  995. //
  996. for ( dwType = 0; ( dwType <= AS(s_lpszServiceType) ); dwType++ )
  997. {
  998. if ( 0 == lstrcmpi(s_lpszServiceType[dwType], szService) )
  999. {
  1000. // If they match, break out and the dwType will be the index
  1001. // to the string.
  1002. //
  1003. break;
  1004. }
  1005. }
  1006. // Make sure we found the string in our array. If we did (dwType isn't too
  1007. // big) then get what is in the first field (after the =). This will be the
  1008. // name of the service. If we get that, then alloc the memory for the struture
  1009. // we are going to add to our cleanup list.
  1010. //
  1011. if ( ( dwType < AS(s_lpszServiceType) ) &&
  1012. ( SetupGetStringField(&InfContext, 1, szService, AS(szService), NULL) ) &&
  1013. ( AddCleanup(lplpcnAdd, szService, dwType) ) &&
  1014. ( lpcnNew = *lplpcnAdd ) )
  1015. {
  1016. // Set the end pointer to the address of the next pointer in the node we
  1017. // just added. This is done so we don't rewalk the list every time we
  1018. // add another node.
  1019. //
  1020. lplpcnAdd = &(lpcnNew->lpNext);
  1021. }
  1022. }
  1023. }
  1024. // Close our inf file now that we are done.
  1025. //
  1026. SetupCloseInfFile(hInf);
  1027. // Return a pointer to the head of the list we just allocated.
  1028. //
  1029. return lpcnHead;
  1030. }
  1031. static BOOL SaveCleanup(LPTSTR lpszInfFile, LPCLEANUP_NODE lpcnHead)
  1032. {
  1033. DWORD cbSection = 8192,
  1034. dwSize = 0;
  1035. LPTSTR lpmszSection,
  1036. lpmszEnd;
  1037. // Need a buffer for the section we are creating.
  1038. //
  1039. lpmszSection = lpmszEnd = (LPTSTR) MALLOC(cbSection * sizeof(TCHAR));
  1040. if ( NULL == lpmszSection )
  1041. {
  1042. return FALSE;
  1043. }
  1044. // Loop through our whole list.
  1045. //
  1046. while ( lpcnHead )
  1047. {
  1048. // Add this line to our section in the form of: ServiceType=ServiceName\0
  1049. //
  1050. if ( !( AddStrToSect(&lpmszSection, &cbSection, &lpmszEnd, &dwSize, s_lpszServiceType[lpcnHead->dwType]) &&
  1051. AddStrToSect(&lpmszSection, &cbSection, &lpmszEnd, &dwSize, _T("=")) &&
  1052. AddStrToSect(&lpmszSection, &cbSection, &lpmszEnd, &dwSize, lpcnHead->lpszService) ) )
  1053. {
  1054. // Memory allocation error, must return.
  1055. //
  1056. return FALSE;
  1057. }
  1058. // Finished with this line, advance the pointer past the NULL.
  1059. //
  1060. lpmszEnd++;
  1061. dwSize++;
  1062. // Go to the next item in the list.
  1063. //
  1064. lpcnHead = lpcnHead->lpNext;
  1065. }
  1066. // Add another NULL after the last item because the section has to be
  1067. // double NULL terminated.
  1068. //
  1069. *lpmszEnd = NULLCHR;
  1070. // If we are going to write anything...
  1071. //
  1072. if ( *lpmszSection )
  1073. {
  1074. // Clear out the section that might already exist. We shouldn't have
  1075. // to do this because when we write out the new section it should replace
  1076. // the old one, but I don't trust these private profile APIs.
  1077. //
  1078. WritePrivateProfileSection(INI_SEC_WBOM_SYSPREP_CLEAN, NULLSTR, lpszInfFile);
  1079. }
  1080. // Now write out our new data.
  1081. //
  1082. WritePrivateProfileSection(INI_SEC_WBOM_SYSPREP_CLEAN, lpmszSection, lpszInfFile);
  1083. // Now we are done with our buffer and we can free it (macro checks for NULL).
  1084. //
  1085. FREE(lpmszSection);
  1086. // If we havent' returned yet, then everything must have worked.
  1087. //
  1088. return TRUE;
  1089. }
  1090. static void CloseCleanup(LPCLEANUP_NODE lpcnHead)
  1091. {
  1092. LPCLEANUP_NODE lpcnFree;
  1093. // Loop through the list until they are all gone.
  1094. //
  1095. while ( lpcnHead )
  1096. {
  1097. // Save a pointer to the node we are going to free
  1098. // (which is the first node in the list).
  1099. //
  1100. lpcnFree = lpcnHead;
  1101. // Now advance the head pointer past the node we are
  1102. // about to free.
  1103. //
  1104. lpcnHead = lpcnHead->lpNext;
  1105. // Now we can free the data in the node.
  1106. //
  1107. FREE(lpcnFree->lpszService);
  1108. // Now we can free the node itself.
  1109. //
  1110. FREE(lpcnFree);
  1111. }
  1112. }
  1113. static BOOL AddStrToSect(LPTSTR * lplpmszSect, DWORD * lpcbSect, LPTSTR * lplpmszEnd, DWORD * lpdwSize, LPTSTR lpszStr)
  1114. {
  1115. DWORD dwStrLen = lstrlen(lpszStr),
  1116. dwSizeNeeded;
  1117. // Make sure our string will fit in the buffer that is
  1118. // currently allocated. We leave room for at least two
  1119. // NULL terminators because we allways double terminate
  1120. // in case this is the last string in the section.
  1121. //
  1122. dwSizeNeeded = *lpdwSize + dwStrLen + 2;
  1123. if ( dwSizeNeeded >= *lpcbSect )
  1124. {
  1125. DWORD cbNewSect = *lpcbSect;
  1126. LPTSTR lpmszNewSect;
  1127. // Double the buffer size until we have enough room.
  1128. //
  1129. do
  1130. {
  1131. cbNewSect *= 2;
  1132. }
  1133. while ( ( cbNewSect <= dwSizeNeeded ) &&
  1134. ( cbNewSect > *lpcbSect ) );
  1135. // Make sure we didn't wrap around with our size
  1136. // buffer (not likely, but doesn't hurt to check) and
  1137. // that our realloc works.
  1138. //
  1139. if ( !( ( cbNewSect > *lpcbSect ) &&
  1140. ( lpmszNewSect = (LPTSTR) REALLOC(*lplpmszSect, cbNewSect * sizeof(TCHAR)) ) ) )
  1141. {
  1142. // This is bad. Free the buffer (the macro will NULL it out
  1143. // so the caller can't use it).
  1144. //
  1145. FREE(*lplpmszSect);
  1146. // Zero and NULL out all these other things so the caller
  1147. // can't rely on them.
  1148. //
  1149. *lpcbSect = 0;
  1150. *lplpmszEnd = NULL;
  1151. *lpdwSize = 0;
  1152. // Return now so we don't try to do anything else.
  1153. //
  1154. return FALSE;
  1155. }
  1156. // Woo hoo, we should be all good now.
  1157. //
  1158. *lplpmszEnd = lpmszNewSect + (*lplpmszEnd - *lplpmszSect);
  1159. *lplpmszSect = lpmszNewSect;
  1160. *lpcbSect = cbNewSect;
  1161. }
  1162. // At this point we must have room for our string, so copy it already.
  1163. //
  1164. lstrcpy(*lplpmszEnd, lpszStr);
  1165. *lpdwSize += dwStrLen;
  1166. *lplpmszEnd += dwStrLen;
  1167. return TRUE;
  1168. }
  1169. static BOOL
  1170. OfflineSourcePath(
  1171. HKEY hkeySoftware,
  1172. LPTSTR lpszWindows,
  1173. LPTSTR lpszSourcePath,
  1174. DWORD cbSourcePath
  1175. )
  1176. {
  1177. BOOL bRet = FALSE;
  1178. LPTSTR lpszOfflineSrc,
  1179. lpszName = NULL;
  1180. TCHAR szWinPEDir[MAX_PATH] = NULLSTR,
  1181. szNewOfflineSrc[MAX_PATH] = NULLSTR;
  1182. UINT uLen;
  1183. // Get the offline source path from the offline hive.
  1184. //
  1185. if ( lpszOfflineSrc = RegGetExpand(hkeySoftware, REG_KEY_HIVE_SETUP_SETUP, REGSTR_VAL_SRCPATH) )
  1186. {
  1187. // In case the offline source path had the %systemroot% or %windir% environment variable in it,
  1188. // we have to make sure the source path we got doesn't point to the WinPE system root.
  1189. //
  1190. // First get the current windows directory.
  1191. //
  1192. if ( ( uLen = GetSystemWindowsDirectory(szWinPEDir, AS(szWinPEDir)) ) &&
  1193. ( szWinPEDir[0] ) )
  1194. {
  1195. // Now check to see if the source path we got starts with the WinPE directory.
  1196. //
  1197. if ( ( uLen <= (UINT) lstrlen(lpszOfflineSrc) ) &&
  1198. ( CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, szWinPEDir, uLen, lpszOfflineSrc, uLen) == CSTR_EQUAL ) )
  1199. {
  1200. // Okay, it does. So we want to construct a new buffer with the offline windows
  1201. // directory passed in, and then with whatever was after the system root (if
  1202. // anything).
  1203. //
  1204. lstrcpyn(szNewOfflineSrc, lpszWindows, AS(szNewOfflineSrc));
  1205. if ( *(lpszOfflineSrc + uLen) )
  1206. {
  1207. AddPathN(szNewOfflineSrc, lpszOfflineSrc + uLen, AS(szNewOfflineSrc));
  1208. }
  1209. }
  1210. }
  1211. // If we didn't make a new path, we should at least make sure
  1212. // the drive leter is correct.
  1213. //
  1214. if ( NULLCHR == szNewOfflineSrc[0] )
  1215. {
  1216. // We need to make the offline source path based on the windows directory passed in and the
  1217. // on in the offline registry.
  1218. //
  1219. if ( GetFullPathName(lpszWindows, AS(szNewOfflineSrc), szNewOfflineSrc, &lpszName) && szNewOfflineSrc[0] && lpszName )
  1220. {
  1221. // This should chop off the windows folder from the offline windows directory.
  1222. //
  1223. *lpszName = NULLCHR;
  1224. // Now we should have the root of the system drive of the image, now add on what
  1225. // was in the registry (passed the drive letter).
  1226. //
  1227. if ( lstrlen(lpszOfflineSrc) > 3 )
  1228. {
  1229. AddPathN(szNewOfflineSrc, lpszOfflineSrc + 3, AS(szNewOfflineSrc));
  1230. }
  1231. }
  1232. else
  1233. {
  1234. // That failed (shouldn't though) so just use the one from the offline registry, but change
  1235. // the drive letter in case the image is on a different drive then it normally would be on.
  1236. //
  1237. lstrcpyn(szNewOfflineSrc, lpszOfflineSrc, AS(szNewOfflineSrc));
  1238. szNewOfflineSrc[0] = *lpszWindows;
  1239. }
  1240. }
  1241. // Now add on the arch folder.
  1242. //
  1243. if ( IsIA64() )
  1244. {
  1245. AddPathN(szNewOfflineSrc, DIR_IA64, AS(szNewOfflineSrc));
  1246. }
  1247. else
  1248. {
  1249. AddPathN(szNewOfflineSrc, DIR_I386, AS(szNewOfflineSrc));
  1250. }
  1251. // Make sure the folder exists.
  1252. //
  1253. if ( DirectoryExists(szNewOfflineSrc) )
  1254. {
  1255. bRet = TRUE;
  1256. lstrcpyn(lpszSourcePath, szNewOfflineSrc, cbSourcePath);
  1257. }
  1258. // Free the buffer allocated.
  1259. //
  1260. FREE(lpszOfflineSrc);
  1261. }
  1262. // Return TRUE only if we reset the buffer.
  1263. //
  1264. return bRet;
  1265. }