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.

3649 lines
102 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // Copyright (c) 1997-1999 Microsoft Corporation
  4. // All rights reserved.
  5. //
  6. // File Name:
  7. // adddirs.c
  8. //
  9. // Description:
  10. // This file contains the dlgproc and friends of the additional
  11. // dirs page.
  12. //
  13. //----------------------------------------------------------------------------
  14. #include "pch.h"
  15. #include "resource.h"
  16. //
  17. // These are the names of our special roots in the tree-view. They are
  18. // loaded from the resource.
  19. //
  20. static TCHAR *StrOemRootName;
  21. static TCHAR *StrSysDriveName;
  22. static TCHAR *StrSysDirName;
  23. static TCHAR *StrOtherDrivesName;
  24. static TCHAR *StrPnpDriversName;
  25. static TCHAR *StrTempFilesName;
  26. static TCHAR *StrSysprepFilesName;
  27. static TCHAR *StrTextmodeFilesName;
  28. //
  29. // The below types and vars support the extra data that we put on tree-view
  30. // items (the lParam in a TVITEM).
  31. //
  32. // We ONLY put this data on our special keys.
  33. //
  34. // All other tree-view entries must have NULL for the lParam.
  35. //
  36. // This extra data on these special tree-view keys supports a number of
  37. // activities. It helps ComputeFullPathOfItem() figure out the diskpath.
  38. // It helps OnSelectionChange() figure out whether to grey buttons (e.g.
  39. // you can't delete "User Supplied Files", etc...)
  40. //
  41. // The on-disk pathname is computed at run-time (init-time) because we
  42. // don't know where the dist folder is until run-time.
  43. //
  44. enum {
  45. KEY_OEMROOT,
  46. KEY_SYSDRIVE,
  47. KEY_SYSDIR,
  48. KEY_OTHERDRIVES,
  49. KEY_PNPDRIVERS,
  50. KEY_TEMPFILES,
  51. KEY_LANGFILES,
  52. KEY_SYSPREP,
  53. KEY_TEXTMODE
  54. };
  55. typedef struct {
  56. UINT iSpecialKeyId; // which special key?
  57. TCHAR OnDiskPathName[MAX_PATH]; // the disk-path the key maps to
  58. TCHAR *Description; // description to display on the ui
  59. } SPECIAL_KEY_DATA;
  60. SPECIAL_KEY_DATA gOemRootData = { KEY_OEMROOT,
  61. _T(""),
  62. _T("") };
  63. SPECIAL_KEY_DATA gSysDriveData = { KEY_SYSDRIVE,
  64. _T(""),
  65. _T("") };
  66. SPECIAL_KEY_DATA gSysDirData = { KEY_SYSDIR,
  67. _T(""),
  68. _T("") };
  69. SPECIAL_KEY_DATA gOtherDrivesData = { KEY_OTHERDRIVES,
  70. _T(""),
  71. _T("") };
  72. SPECIAL_KEY_DATA gPnpDriversData = { KEY_PNPDRIVERS,
  73. _T(""),
  74. _T("") };
  75. SPECIAL_KEY_DATA gTempFilesData = { KEY_TEMPFILES,
  76. _T(""),
  77. _T("") };
  78. SPECIAL_KEY_DATA gSysprepData = { KEY_SYSPREP,
  79. _T(""),
  80. _T("") };
  81. SPECIAL_KEY_DATA gTextmodeData = { KEY_TEXTMODE,
  82. _T(""),
  83. _T("") };
  84. //
  85. // The below variable is used to keep track of some info about the current
  86. // selection on the tree-view.
  87. //
  88. // Each time the user changes the current selection, we update the below
  89. // variable. Later, when the user pushes the ADD or REMOVE buttons, these
  90. // fields are read. This isolates all of the goo about figuring out disk
  91. // paths to the OnSelectionChange() event.
  92. //
  93. // We set a "Current Item" and a "Current Folder" derived from the current
  94. // tree-view selection. User deletes the current item, and copies go into
  95. // the current folder. CurrentItem == CurrentFolder if user selects a
  96. // directory on the tree-view.
  97. //
  98. typedef struct {
  99. TCHAR lpCurItemPath[MAX_PATH];
  100. TCHAR lpCurFolderPath[MAX_PATH];
  101. HTREEITEM hCurItem;
  102. HTREEITEM hCurFolderItem;
  103. } ADDDIRS_CURSEL_INF;
  104. ADDDIRS_CURSEL_INF gCurSel;
  105. //
  106. // This type and the vars are used to cache info about the shell icons
  107. // associated with files and dirents.
  108. //
  109. // As we walk directory trees, we query the shell to get the icons
  110. // associated with that file or directory. Since we don't know how many
  111. // icons we need before-hand, we cache unique icons onto the linked list
  112. // below. When we're done walking trees, we make the Image_List and
  113. // repaint the tree-view control.
  114. //
  115. typedef struct icon_info_tag {
  116. HIMAGELIST hSysImageList;
  117. int iSysIdx;
  118. int iOurIdx;
  119. HICON hIcon;
  120. struct icon_info_tag *next;
  121. } ICON_INFO;
  122. static ICON_INFO *pHeadOfIconList = NULL;
  123. static int gCurIconIdx = 0;
  124. //
  125. // This array is used by CreateSkeletonOemTree() to build an empty
  126. // $oem$ tree.
  127. //
  128. TCHAR *DefaultOemTree[] = {
  129. _T("$$"),
  130. _T("$$\\system32"),
  131. _T("$1"),
  132. _T("$1\\drivers"),
  133. _T("C"),
  134. _T("D"),
  135. _T("Textmode")
  136. };
  137. //
  138. // Sysprep string constants
  139. //
  140. static TCHAR const SYSPREP_EXE[] = _T("sysprep.exe");
  141. static TCHAR const SETUPCL_EXE[] = _T("setupcl.exe");
  142. static TCHAR SYSPREP_FILE_EXTENSION[] = _T("exe");
  143. static TCHAR* StrExecutableFiles;
  144. static TCHAR* StrAllFiles;
  145. static TCHAR g_szSysprepFileFilter[MAX_PATH + 1];
  146. static TCHAR* StrSelectFileOrFolderToCopy = NULL;
  147. //
  148. // Variables to pass data between the SetupIterateCabinet function and its callback
  149. //
  150. static TCHAR szFileSearchingFor[MAX_PATH + 1];
  151. static TCHAR szDestinationPath[MAX_PATH + 1];
  152. static BOOL bFileCopiedFromCab = FALSE;
  153. #define SIZE_DEFAULT_OEM_TREE ( sizeof(DefaultOemTree) / sizeof(TCHAR*) )
  154. //
  155. // The below type is needed for WalkTreeAndAddItems() which walks the
  156. // distribution folder and populates the tree-view at init time.
  157. //
  158. // In the case of the TempFiles key, it maps to distfold\$oem$. When
  159. // we look at the disk to populate this tree we must not recurse down
  160. // into $$ $1 C D ... We only want the remainder.
  161. //
  162. // In the case of System Drive, we must not recurse down $oem$\$1\drivers
  163. // because those files should appear under the special key PnPDrivers.
  164. //
  165. // The other special keys are safe and use INIT_NORMAL when calling
  166. // WalkTreeAndAddItems().
  167. //
  168. typedef enum {
  169. INIT_NORMAL,
  170. INIT_SYSDRIVE,
  171. INIT_TEMPFILES
  172. } INIT_FLAG;
  173. //
  174. // Keeps track of what product they had chosen when they last got to
  175. // this page. It is initialized to NO_PREVIOUS_PRODUCT_CHOSEN because the
  176. // first time they get to this page they were never here before. This is
  177. // used to determine if we should redraw the entire tree or not. The tree
  178. // view is different for NT work/serv than it is for Sysprep.
  179. //
  180. #define NO_PREVIOUS_PRODUCT_CHOSEN -1
  181. static INT g_iLastProductInstall = NO_PREVIOUS_PRODUCT_CHOSEN;
  182. //---------------------------------------------------------------------------
  183. //
  184. // This section of code is the support for queuing icons.
  185. //
  186. // Notes:
  187. // - Currently, there is only support for queueing icons obtained
  188. // from the shell. Some engineering will be required to add
  189. // fixed IDI_* icons onto the list. Please delete this comment
  190. // if you do this work.
  191. //
  192. // - None of the icon routines report errors to the user. The caller
  193. // should do that if they want to report errors.
  194. //
  195. //---------------------------------------------------------------------------
  196. //---------------------------------------------------------------------------
  197. //
  198. // Function: FindCachedIcon
  199. //
  200. // Purpose: This is a support routine for cacheing icons. Don't call it,
  201. // use LoadShellIcon().
  202. //
  203. // This function searches our global list of shell icon info
  204. // and returns a pointer to that node. If we have not yet
  205. // cached info about this icon, this function creates the node.
  206. //
  207. // Arguments:
  208. // HIMAGELIST hSysImageList - the system image list where icon resides
  209. // int SysIdx - index on the give list of icon
  210. //
  211. // Returns:
  212. // Pointer to ICON_INFO node or NULL if out of memory
  213. //
  214. //---------------------------------------------------------------------------
  215. ICON_INFO *FindCachedIcon(HIMAGELIST hSysImageList,
  216. int SysIdx)
  217. {
  218. ICON_INFO *p = pHeadOfIconList;
  219. //
  220. // See if we've ever seen this icon before. We detect uniqueness
  221. // by the imagelist,idx pair.
  222. //
  223. while ( p ) {
  224. if ( p->hSysImageList == hSysImageList && p->iSysIdx == SysIdx )
  225. break;
  226. p = p->next;
  227. }
  228. //
  229. // If we haven't cached any info about this icon yet, do so now
  230. //
  231. if ( ! p ) {
  232. if ( (p = malloc(sizeof(ICON_INFO))) == NULL )
  233. return NULL;
  234. p->hSysImageList = hSysImageList;
  235. p->iSysIdx = SysIdx;
  236. p->iOurIdx = gCurIconIdx++;
  237. p->hIcon = ImageList_GetIcon(hSysImageList, SysIdx, 0);
  238. p->next = pHeadOfIconList;
  239. pHeadOfIconList = p;
  240. }
  241. return p;
  242. }
  243. //---------------------------------------------------------------------------
  244. //
  245. // Function: LoadShellIcon
  246. //
  247. // Purpose: Given the full pathname of a file or directory, this function
  248. // will query the shell and find out the icon associatted with
  249. // that file or directory.
  250. //
  251. // Arguments:
  252. // LPTSTR lpPath - full path of item
  253. // UINT iWhichIcon - pass either SHGFI_SMALLICON or SHGFI_OPENICON
  254. //
  255. // Notes:
  256. // - Since we only make 1 image list, this routine will only work
  257. // to query small icons (either the normal or the open). It won't
  258. // work for icons that are not 16X16.
  259. //
  260. //---------------------------------------------------------------------------
  261. int LoadShellIcon(LPTSTR lpPath, UINT iWhichIcon)
  262. {
  263. SHFILEINFO FileInfo;
  264. ICON_INFO *pIconInfo;
  265. HIMAGELIST hSysImageList;
  266. hSysImageList =
  267. (HIMAGELIST) SHGetFileInfo(lpPath,
  268. 0,
  269. &FileInfo,
  270. sizeof(FileInfo),
  271. SHGFI_SYSICONINDEX | iWhichIcon);
  272. if ( hSysImageList == NULL )
  273. return -1;
  274. pIconInfo = FindCachedIcon(hSysImageList, FileInfo.iIcon);
  275. if ( pIconInfo == NULL )
  276. return -1;
  277. return pIconInfo->iOurIdx;
  278. }
  279. //---------------------------------------------------------------------------
  280. //
  281. // Function: SetOurImageList
  282. //
  283. // Purpose: Whenever more items have been added to the tree, this function
  284. // is called to update the icon list.
  285. //
  286. // Arguments:
  287. // HWND hTv - Handle to the tree-view control
  288. //
  289. // Returns:
  290. // void
  291. //
  292. //---------------------------------------------------------------------------
  293. void SetOurImageList(HWND hTv)
  294. {
  295. HIMAGELIST hNewImageList, hCurImageList;
  296. ICON_INFO *p = pHeadOfIconList;
  297. int i;
  298. //
  299. // Make the image list now that we know how big it needs to be.
  300. //
  301. hNewImageList = ImageList_Create(GetSystemMetrics(SM_CXSMICON),
  302. GetSystemMetrics(SM_CYSMICON),
  303. ILC_MASK,
  304. gCurIconIdx,
  305. 0);
  306. if ( hNewImageList == NULL )
  307. return;
  308. //
  309. // Add a dummy icon in each spot. This is necessary becase
  310. // ImageList_ReplaceIcon() will only work if an icon has already been
  311. // added to the offset in question.
  312. //
  313. if ( p == NULL )
  314. return;
  315. for ( i=0; i<gCurIconIdx; i++ )
  316. ImageList_AddIcon(hNewImageList, p->hIcon);
  317. //
  318. // Now walk our list of unique icons and put them at the correct
  319. // offset in the image_list.
  320. //
  321. // Note that when we walked the tree, LoadShellIcon() returned the
  322. // index that each tree-view entry should use for it's icons. Thus,
  323. // we must ensure that the correct icon is at the correct offset
  324. // in the tree-view's image_list.
  325. //
  326. for ( p=pHeadOfIconList; p; p=p->next )
  327. ImageList_ReplaceIcon(hNewImageList, p->iOurIdx, p->hIcon);
  328. //
  329. // If there is an old image_list on the tree-view, free it first
  330. //
  331. if ( (hCurImageList = TreeView_GetImageList(hTv, TVSIL_NORMAL)) != NULL )
  332. ImageList_Destroy(hCurImageList);
  333. TreeView_SetImageList(hTv, hNewImageList, TVSIL_NORMAL);
  334. }
  335. //---------------------------------------------------------------------------
  336. //
  337. // This section of code is some miscellaneous low-level support.
  338. //
  339. //---------------------------------------------------------------------------
  340. //---------------------------------------------------------------------------
  341. //
  342. // Function: InsertSingleItem
  343. //
  344. // Purpose: Adds a single item to the tree view. It will be a child
  345. // of the given hParentItem.
  346. //
  347. // This function lives only to support UpdateTreeViewDisplay()
  348. // and should not be called otherwise.
  349. //
  350. // Arguments:
  351. // HWND hwnd - current window
  352. // LPTSTR lpItemName - name to display
  353. // int SmallIconIdx - idx into the image_list
  354. // int OpenIconIdx - idx into the image_list
  355. // SPECIAL_KEY_DATA *lpExtraData - data to keep on the tree-view item
  356. // HTREEITEM hParentItem - parent on the display
  357. //
  358. // Returns:
  359. // HTREEITEM, NULL if it fails
  360. //
  361. // Notes:
  362. // - pass NULL for lpExtraData unless it is one of our pre-defined
  363. // special keys.
  364. //
  365. //---------------------------------------------------------------------------
  366. HTREEITEM InsertSingleItem(HWND hwnd,
  367. LPTSTR lpItemName,
  368. int SmallIconIdx,
  369. int OpenIconIdx,
  370. SPECIAL_KEY_DATA *lpExtraData,
  371. HTREEITEM hParentItem)
  372. {
  373. HTREEITEM hItem;
  374. TVINSERTSTRUCT TvInsert;
  375. UINT ItemMask = TVIF_TEXT | TVIF_PARAM;
  376. if ( SmallIconIdx >= 0 )
  377. {
  378. ItemMask |= TVIF_IMAGE;
  379. }
  380. if ( OpenIconIdx >= 0 )
  381. {
  382. ItemMask |= TVIF_SELECTEDIMAGE;
  383. }
  384. TvInsert.hParent = hParentItem;
  385. TvInsert.hInsertAfter = TVI_LAST;
  386. TvInsert.item.mask = ItemMask;
  387. TvInsert.item.pszText = lpItemName;
  388. TvInsert.item.iImage = SmallIconIdx;
  389. TvInsert.item.iSelectedImage = OpenIconIdx;
  390. TvInsert.item.lParam = (LPARAM) lpExtraData;
  391. hItem = TreeView_InsertItem(GetDlgItem(hwnd, IDC_FILETREE), &TvInsert);
  392. if ( hItem == NULL ) {
  393. ReportErrorId(hwnd, MSGTYPE_ERR, IDS_ERR_ADDING_TVITEM);
  394. }
  395. return hItem;
  396. }
  397. //---------------------------------------------------------------------------
  398. //
  399. // Function: GetItemlParam
  400. //
  401. // Purpose: Gets the lParam off a tree-view item. In this app, it is
  402. // null unless it's one of our special keys.
  403. //
  404. // Arguments:
  405. // HWND hTv
  406. // HTREEITEM hItem
  407. //
  408. // Returns:
  409. // Value of the lParam. In this app, it is SPECIAL_KEY_DATA*. It
  410. // is generally null except for our few special keys.
  411. //
  412. //---------------------------------------------------------------------------
  413. SPECIAL_KEY_DATA *GetItemlParam(HWND hTv, HTREEITEM hItem)
  414. {
  415. TVITEM TvItem;
  416. TvItem.hItem = hItem;
  417. TvItem.mask = TVIF_PARAM;
  418. if ( ! TreeView_GetItem(hTv, &TvItem) )
  419. return NULL;
  420. return (SPECIAL_KEY_DATA*) TvItem.lParam;
  421. }
  422. //---------------------------------------------------------------------------
  423. //
  424. // Function: GetItemName
  425. //
  426. // Purpose: Retrieves the display name of a tree-view item given its handle.
  427. //
  428. // Arguments:
  429. // HWND hTv
  430. // HTREEITEM hItem
  431. // LPTSTR NameBuffer - output
  432. //
  433. // Returns: BOOL - success
  434. //
  435. //---------------------------------------------------------------------------
  436. BOOL GetItemName(HWND hTv, HTREEITEM hItem, LPTSTR NameBuffer)
  437. {
  438. TVITEM TvItem;
  439. TvItem.hItem = hItem;
  440. TvItem.mask = TVIF_TEXT;
  441. TvItem.pszText = NameBuffer;
  442. TvItem.cchTextMax = MAX_PATH;
  443. return TreeView_GetItem(hTv, &TvItem);
  444. }
  445. //---------------------------------------------------------------------------
  446. //
  447. // Function: FindItemByName
  448. //
  449. // Purpose: Searches the children of a given tree-view item and returns
  450. // a handle to the one with the given name.
  451. //
  452. // Arguments:
  453. // HWND hTv
  454. // HTREEITEM hItem
  455. // LPTSTR lpName
  456. //
  457. // Returns:
  458. // HTREEITEM, null if not found
  459. //
  460. //---------------------------------------------------------------------------
  461. HTREEITEM FindItemByName(HWND hTv,
  462. HTREEITEM hItem,
  463. LPTSTR lpName)
  464. {
  465. HTREEITEM hChildItem;
  466. TCHAR NameBuffer[MAX_PATH];
  467. hChildItem = TreeView_GetChild(hTv, hItem);
  468. while ( hChildItem != NULL ) {
  469. if ( ! GetItemName(hTv, hChildItem, NameBuffer) )
  470. return NULL;
  471. if ( lstrcmpi(NameBuffer, lpName) == 0 )
  472. break;
  473. hChildItem = TreeView_GetNextSibling(hTv, hChildItem);
  474. }
  475. return hChildItem;
  476. }
  477. //
  478. // The below functions build the on-disk pathname for each of our special
  479. // root names.
  480. //
  481. // SysDrive maps to $oem$\$1
  482. // SysDir maps to $oem$\$$
  483. // OtherDrives maps to $oem$\%c (where %c is a fixed drive letter)
  484. // PnpDrivers maps to $oem$\$1\drivers
  485. // TempFiles maps to $oem$ (and must skip $$, $1, etc)
  486. //
  487. //----------------------------------------------------------------------------
  488. //
  489. // Function: MakeSysprepSetupFilesPath
  490. //
  491. // Purpose: Computes the path to where sysprep.exe and setupcl.exe are to be
  492. // copied.
  493. //
  494. // Arguments: TCHAR* szSysprepPath - returns the sysprep path, assumed to be
  495. // able to hold MAX_PATH chars
  496. //
  497. // Returns: VOID
  498. //
  499. //----------------------------------------------------------------------------
  500. static VOID
  501. MakeSysprepSetupFilesPath( TCHAR* szSysprepPath )
  502. {
  503. if (0 == ExpandEnvironmentStrings( _T("%SystemDrive%"),
  504. szSysprepPath,
  505. MAX_PATH ))
  506. {
  507. TerminateTheWizard(IDS_ERROR_OUTOFMEMORY);
  508. }
  509. lstrcatn( szSysprepPath, _T("\\sysprep"), MAX_PATH );
  510. }
  511. //----------------------------------------------------------------------------
  512. //
  513. // Function: MakeSysprepPath
  514. //
  515. // Purpose: Computes the path to where the language files for sysprep are to
  516. // be copied.
  517. //
  518. // Arguments: TCHAR* szSysprepPath - returns the sysprep path
  519. //
  520. // Returns: VOID
  521. //
  522. //----------------------------------------------------------------------------
  523. VOID
  524. MakeSysprepPath( TCHAR* szSysprepPath )
  525. {
  526. MakeSysprepSetupFilesPath( szSysprepPath );
  527. lstrcatn( szSysprepPath, _T("\\i386"), MAX_PATH );
  528. }
  529. //----------------------------------------------------------------------------
  530. //
  531. // Function: MakeTempFilesName
  532. //
  533. // Purpose: Computes the path to where the temp files are to be copied.
  534. //
  535. // Arguments: TCHAR* Buffer - returns the temp files path
  536. //
  537. // Returns: VOID
  538. //
  539. //----------------------------------------------------------------------------
  540. VOID
  541. MakeTempFilesName( TCHAR* Buffer )
  542. {
  543. lstrcpyn( Buffer,
  544. WizGlobals.OemFilesPath, AS(Buffer) );
  545. }
  546. //----------------------------------------------------------------------------
  547. //
  548. // Function: MakePnpDriversName
  549. //
  550. // Purpose: Computes the path to where the Plug and Play drivers are to be
  551. // copied.
  552. //
  553. // Arguments: TCHAR* Buffer - returns the path to where the PnP files go
  554. //
  555. // Returns: VOID
  556. //
  557. //----------------------------------------------------------------------------
  558. VOID
  559. MakePnpDriversName( TCHAR* Buffer )
  560. {
  561. HRESULT hrPrintf;
  562. if( WizGlobals.iProductInstall == PRODUCT_SYSPREP )
  563. {
  564. ExpandEnvironmentStrings( _T("%SystemDrive%"),
  565. Buffer,
  566. MAX_PATH );
  567. lstrcatn( Buffer, _T("\\drivers"), MAX_PATH );
  568. }
  569. else
  570. {
  571. hrPrintf=StringCchPrintf( Buffer, AS(Buffer),
  572. _T("%s\\$1\\drivers"),
  573. WizGlobals.OemFilesPath );
  574. }
  575. }
  576. //----------------------------------------------------------------------------
  577. //
  578. // Function: MakeOemRootName
  579. //
  580. // Purpose: Computes the path to where the OEM files are to be copied.
  581. //
  582. // Arguments: TCHAR* Buffer - returns the path to where the OEM files go
  583. //
  584. // Returns: VOID
  585. //
  586. //----------------------------------------------------------------------------
  587. VOID
  588. MakeOemRootName( TCHAR* Buffer )
  589. {
  590. lstrcpyn( Buffer,
  591. WizGlobals.OemFilesPath, AS(Buffer) );
  592. }
  593. //----------------------------------------------------------------------------
  594. //
  595. // Function: MakeSysDriveName
  596. //
  597. // Purpose: Computes the path to the System drive files are to be copied
  598. //
  599. // Arguments: TCHAR* Buffer - returns the path to the where the System drive
  600. // files are to be copied.
  601. //
  602. // Returns: VOID
  603. //
  604. //----------------------------------------------------------------------------
  605. VOID
  606. MakeSysDriveName( TCHAR* Buffer )
  607. {
  608. HRESULT hrPrintf;
  609. hrPrintf=StringCchPrintf( Buffer, AS(Buffer),
  610. _T("%s\\$1"),
  611. WizGlobals.OemFilesPath );
  612. }
  613. //----------------------------------------------------------------------------
  614. //
  615. // Function: MakeSysDirName
  616. //
  617. // Purpose: Computes the path to the System Directory files are to be copied
  618. //
  619. // Arguments: TCHAR* Buffer - returns the path to the where the System
  620. // Directory files are to be copied.
  621. //
  622. // Returns: VOID
  623. //
  624. //----------------------------------------------------------------------------
  625. VOID
  626. MakeSysDirName( TCHAR* Buffer )
  627. {
  628. HRESULT hrPrintf;
  629. hrPrintf=StringCchPrintf( Buffer, AS(Buffer),
  630. _T("%s\\$$"),
  631. WizGlobals.OemFilesPath );
  632. }
  633. //----------------------------------------------------------------------------
  634. //
  635. // Function: MakeOtherDriveName
  636. //
  637. // Purpose: Computes the path to the Other Drive files are to be copied
  638. //
  639. // Arguments: TCHAR* Buffer - returns the path to the where the Other
  640. // Drive files are to be copied.
  641. // TCHAR c - the drive we are making the path for
  642. //
  643. // Returns: VOID
  644. //
  645. //----------------------------------------------------------------------------
  646. VOID
  647. MakeOtherDriveName( TCHAR* Buffer, TCHAR c )
  648. {
  649. HRESULT hrPrintf;
  650. hrPrintf=StringCchPrintf( Buffer, AS(Buffer),
  651. c ? _T("%s\\%c") : _T("%s"),
  652. WizGlobals.OemFilesPath, c );
  653. }
  654. //----------------------------------------------------------------------------
  655. //
  656. // Function: MakeLangFilesName
  657. //
  658. // Purpose: Computes the path to where the language files are to be copied.
  659. //
  660. // Arguments: TCHAR* Buffer - returns the path to where the language files go
  661. //
  662. // Returns: VOID
  663. //
  664. //----------------------------------------------------------------------------
  665. VOID
  666. MakeLangFilesName( TCHAR* Buffer )
  667. {
  668. if( WizGlobals.iProductInstall == PRODUCT_SYSPREP )
  669. {
  670. MakeSysprepPath( Buffer );
  671. }
  672. else
  673. {
  674. lstrcpyn( Buffer,
  675. WizGlobals.OemFilesPath, AS(Buffer) );
  676. }
  677. }
  678. //----------------------------------------------------------------------------
  679. //
  680. // Function: MakeSysprepLangFilesGroupName
  681. //
  682. // Purpose: Computes the path to where the language dirs are to be copied for
  683. // the language groups.
  684. //
  685. // Arguments: TCHAR* Buffer - returns the path to where the language files go
  686. //
  687. // Returns: VOID
  688. //
  689. //----------------------------------------------------------------------------
  690. VOID
  691. MakeSysprepLangFilesGroupName( TCHAR* Buffer )
  692. {
  693. MakeSysprepPath( Buffer );
  694. lstrcatn( Buffer, _T("\\lang"), MAX_PATH );
  695. }
  696. //----------------------------------------------------------------------------
  697. //
  698. // Function: MakeTextmodeFilesName
  699. //
  700. // Purpose: Computes the path to where the OEM boot files are to be copied
  701. //
  702. // Arguments: TCHAR* Buffer - returns the path to the where the textmode
  703. // (HAL and SCSI) files are to be copied.
  704. //
  705. // Returns: VOID
  706. //
  707. //----------------------------------------------------------------------------
  708. VOID
  709. MakeTextmodeFilesName( TCHAR* Buffer )
  710. {
  711. HRESULT hrPrintf;
  712. hrPrintf=StringCchPrintf( Buffer, AS(Buffer),
  713. _T("%s\\Textmode"),
  714. WizGlobals.OemFilesPath );
  715. }
  716. //----------------------------------------------------------------------------
  717. //
  718. // This section of code is for WM_INIT
  719. //
  720. //----------------------------------------------------------------------------
  721. //----------------------------------------------------------------------------
  722. //
  723. // Function: CreateSkeletonOemTree
  724. //
  725. // Purpose: This function creates a skeleton OEM tree. The directories
  726. // created are based on the global array DefaultOemTree[].
  727. //
  728. // If the tree already exists, this function becomes a no-op.
  729. //
  730. // This is called at init-time and is a support routine for
  731. // the OnInit() routine. Don't call it otherwise.
  732. //
  733. // Returns:
  734. // TRUE - no errors, proceed
  735. // FALSE - errors making tree
  736. //
  737. // Notes:
  738. // - Errors are reported to the user.
  739. //
  740. //----------------------------------------------------------------------------
  741. BOOL CreateSkeletonOemTree(HWND hwnd)
  742. {
  743. int i;
  744. TCHAR PathBuffer[MAX_PATH];
  745. //
  746. // Ensure the $oem$ dir exists
  747. //
  748. if ( ! EnsureDirExists(WizGlobals.OemFilesPath) ) {
  749. ReportErrorId(hwnd,
  750. MSGTYPE_ERR | MSGTYPE_WIN32,
  751. IDS_ERR_CREATE_FOLDER,
  752. WizGlobals.OemFilesPath);
  753. return FALSE;
  754. }
  755. //
  756. // Now make all of the default sub-dirs in the $oem$ tree if it is not
  757. // a sysprep
  758. //
  759. if( WizGlobals.iProductInstall != PRODUCT_SYSPREP )
  760. {
  761. for ( i=0; i<SIZE_DEFAULT_OEM_TREE; i++ )
  762. {
  763. lstrcpyn(PathBuffer, WizGlobals.OemFilesPath, AS(PathBuffer));
  764. ConcatenatePaths(PathBuffer, DefaultOemTree[i], NULL);
  765. if ( ! EnsureDirExists(PathBuffer) )
  766. {
  767. ReportErrorId(hwnd,
  768. MSGTYPE_ERR | MSGTYPE_WIN32,
  769. IDS_ERR_CREATE_FOLDER,
  770. PathBuffer);
  771. return FALSE;
  772. }
  773. }
  774. }
  775. return( TRUE );
  776. }
  777. //---------------------------------------------------------------------------
  778. //
  779. // Function: WalkTreeAndAddItems
  780. //
  781. // Purpose: This function walks a tree on the disk and inserts each
  782. // dirent and file found into the tree-view display.
  783. //
  784. // The directory tree will become a child of the given tree-view
  785. // item as hParent.
  786. //
  787. // This function supports OnInitAddDirs() and should not be
  788. // called otherwise.
  789. //
  790. // Arguments:
  791. // HWND hwnd - parent window
  792. // LPTSTR RootBuffer - tree to recurse down
  793. // HTREEITEM hParent - the parent tree view item
  794. // BOOL bTempFiles - special case for "Temp Files"
  795. //
  796. // Returns: VOID
  797. //
  798. // Notes:
  799. //
  800. // - RootBuffer must be MAX_PATH wide.
  801. //
  802. // - Any paths that this routine encounters that are >= MAX_PATH in
  803. // length are silently skipped.
  804. //
  805. // - Always pass bTempFiles=FALSE except when filling in the TempFiles
  806. // root in the tree-view. TempFiles maps to $oem$ on disk, but the
  807. // other special locations are sub-dirs of this. Thus, this findfirst/
  808. // findnext loop must skip those special cases ($1, $$, etc...)
  809. //
  810. //---------------------------------------------------------------------------
  811. VOID WalkTreeAndAddItems(HWND hwnd,
  812. LPTSTR RootBuffer,
  813. HTREEITEM hParent,
  814. INIT_FLAG iInitFlag)
  815. {
  816. LPTSTR RootPathEnd = RootBuffer + lstrlen(RootBuffer);
  817. HANDLE FindHandle;
  818. WIN32_FIND_DATA FindData;
  819. HTREEITEM hItem;
  820. int iSmallIcon;
  821. int iOpenIcon;
  822. TCHAR szOriginalPath[MAX_PATH] = _T("");
  823. //
  824. // Backup the original path so it can be restored later
  825. //
  826. lstrcpyn( szOriginalPath, RootBuffer, AS(szOriginalPath) );
  827. //
  828. // Look for * in this dir
  829. //
  830. if ( ! ConcatenatePaths(RootBuffer, _T("*"), NULL) ) {
  831. //
  832. // Restore the original path before returning
  833. //
  834. lstrcpyn( RootBuffer, szOriginalPath, AS(RootBuffer) );
  835. return;
  836. }
  837. FindHandle = FindFirstFile(RootBuffer, &FindData);
  838. if ( FindHandle == INVALID_HANDLE_VALUE ) {
  839. //
  840. // Restore the original path before returning
  841. //
  842. lstrcpyn( RootBuffer, szOriginalPath, AS(RootBuffer) );
  843. return;
  844. }
  845. do {
  846. *RootPathEnd = _T('\0');
  847. //
  848. // skip over the . and .. entries
  849. //
  850. if (0 == lstrcmp(FindData.cFileName, _T(".")) ||
  851. 0 == lstrcmp(FindData.cFileName, _T("..")))
  852. continue;
  853. //
  854. // TempFiles maps to %distfold%\$oem$, but the others map to a
  855. // sub-directory of $oem$, (e.g. SysDrive maps to $oem$\$1).
  856. //
  857. // By definition, TempFiles is anything under $oem$ that is not
  858. // a special name. So, in the case that we are building the
  859. // Temporary Files tree, be sure we don't recurse down into a
  860. // special $oem$ sub-dir.
  861. //
  862. // Note that we do this check based on fully qualified pathnames
  863. // else comparisons would be ambiguous.
  864. //
  865. if ( iInitFlag == INIT_TEMPFILES ) {
  866. TCHAR Buffer1[MAX_PATH], Buffer2[MAX_PATH], c;
  867. BOOL bContinue;
  868. lstrcpyn(Buffer1, RootBuffer, AS(RootBuffer));
  869. if ( ! ConcatenatePaths(Buffer1, FindData.cFileName, NULL) )
  870. continue;
  871. //
  872. // skip %distfold%\$oem$\$1
  873. //
  874. MakeSysDriveName(Buffer2);
  875. if ( _wcsicmp(Buffer1, Buffer2) == 0 )
  876. continue;
  877. //
  878. // skip %distfold%\$oem$\$$
  879. //
  880. MakeSysDirName(Buffer2);
  881. if ( _wcsicmp(Buffer1, Buffer2) == 0 )
  882. continue;
  883. //
  884. // skip %distfold%\$oem$\textmode
  885. //
  886. MakeTextmodeFilesName(Buffer2);
  887. if ( _wcsicmp(Buffer1, Buffer2) == 0 )
  888. continue;
  889. //
  890. // skip %distfold%\$oem$\%c where %c is any drive letter
  891. //
  892. for ( bContinue=FALSE, c=_T('A'); c<=_T('Z'); c++ ) {
  893. MakeOtherDriveName(Buffer2, c);
  894. if ( _wcsicmp(Buffer1, Buffer2) == 0 ) {
  895. bContinue = TRUE;
  896. break;
  897. }
  898. }
  899. if ( bContinue )
  900. continue;
  901. }
  902. //
  903. // The other special case is SYSDRIVE which maps to $oem$\$1.
  904. //
  905. // Whe must skip $oem$\$1\drivers because that is the root for the
  906. // special key PnPDrivers.
  907. //
  908. else if ( iInitFlag == INIT_SYSDRIVE ) {
  909. TCHAR Buffer1[MAX_PATH], Buffer2[MAX_PATH];
  910. lstrcpyn(Buffer1, RootBuffer, AS(RootBuffer));
  911. if ( ! ConcatenatePaths(Buffer1, FindData.cFileName, NULL) )
  912. continue;
  913. //
  914. // Skip %distfold%\$oem$\$1\drivers
  915. //
  916. MakePnpDriversName(Buffer2);
  917. if ( _wcsicmp(Buffer1, Buffer2) == 0 )
  918. continue;
  919. }
  920. //
  921. // Build the full pathname, if >= MAX_PATH, skip it
  922. //
  923. if ( ! ConcatenatePaths(RootBuffer, FindData.cFileName, NULL) )
  924. continue;
  925. //
  926. // Get the shell icons associated with this file/dir
  927. //
  928. iSmallIcon = LoadShellIcon(RootBuffer, SHGFI_SMALLICON);
  929. iOpenIcon = LoadShellIcon(RootBuffer, SHGFI_OPENICON);
  930. //
  931. // Add this item as a child of the given parent.
  932. //
  933. if ( (hItem = InsertSingleItem(hwnd,
  934. FindData.cFileName,
  935. iSmallIcon,
  936. iOpenIcon,
  937. NULL,
  938. hParent)) == NULL ) {
  939. continue;
  940. }
  941. //
  942. // If this is a dirent, recurse.
  943. //
  944. if ( FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
  945. WalkTreeAndAddItems(hwnd, RootBuffer, hItem, iInitFlag);
  946. } while ( FindNextFile(FindHandle, &FindData) );
  947. *RootPathEnd = _T('\0');
  948. FindClose(FindHandle);
  949. //
  950. // Restore the original path
  951. //
  952. lstrcpyn( RootBuffer, szOriginalPath, AS(RootBuffer) );
  953. }
  954. //---------------------------------------------------------------------------
  955. //
  956. // Function: OnInitAddDirs
  957. //
  958. // Purpose: Called before the dialog first displays. We ensure that
  959. // OemFilesPath and OemPnpDriversPath have good defaults and
  960. // that the skeleton OEM tree exists.
  961. //
  962. //---------------------------------------------------------------------------
  963. VOID OnInitAddDirs(HWND hwnd)
  964. {
  965. HRESULT hrPrintf;
  966. //
  967. // Create the $oem$, $oem$\$1, etc in %distfold%
  968. //
  969. // If there's any errors creating this skeleton distfolder tree, it's
  970. // hopeless. CreateSkeletonOemTree() already reported an error, skip
  971. // this page.
  972. //
  973. //
  974. // ISSUE-2002/02/28-stelo- The fact that the user gets this error before we even
  975. // initialize means there is no good context. Currently,
  976. // the error message is generic.
  977. //
  978. // Go down this path by connecting to a share that you
  979. // only have read access to. This is a good edit scenario.
  980. // OemFilesPath should get computed. User could select
  981. // Oem Branding files directly from a read-only dist folder.
  982. // In that case, I think we no-op the copy.
  983. //
  984. // It must be tested what EnsureDirExists() does in this
  985. // context.
  986. //
  987. if ( ! CreateSkeletonOemTree(hwnd) ) {
  988. return;
  989. }
  990. //
  991. // Load the hard-coded special root names that you see initially
  992. // on the tree-view and their descriptions
  993. //
  994. StrOemRootName = MyLoadString( IDS_OEMROOT_NAME );
  995. StrSysDriveName = MyLoadString( IDS_SYSDRIVE_NAME );
  996. StrSysDirName = MyLoadString( IDS_SYSDIR_NAME );
  997. StrOtherDrivesName = MyLoadString( IDS_OTHERDRIVES_NAME );
  998. StrPnpDriversName = MyLoadString( IDS_PNPDRIVERS_NAME );
  999. StrTempFilesName = MyLoadString( IDS_TEMPFILES_NAME );
  1000. StrSysprepFilesName = MyLoadString( IDS_SYSPREPFILES_NAME );
  1001. StrTextmodeFilesName = MyLoadString( IDS_TEXTMODE_NAME );
  1002. gOemRootData.Description = MyLoadString( IDS_ADD_DESCR_ROOT );
  1003. gSysDriveData.Description = MyLoadString( IDS_ADD_DESCR_SYSDRIVE );
  1004. gSysDirData.Description = MyLoadString( IDS_ADD_DESCR_WINNT );
  1005. gOtherDrivesData.Description = MyLoadString( IDS_ADD_DESCR_OTHER );
  1006. gPnpDriversData.Description = MyLoadString( IDS_ADD_DESCR_PNP );
  1007. gTempFilesData.Description = MyLoadString( IDS_ADD_DESCR_TEMP );
  1008. gSysprepData.Description = MyLoadString( IDS_ADD_DESCR_SYSPREP );
  1009. gTextmodeData.Description = MyLoadString( IDS_ADD_DESCR_TEXTMODE );
  1010. //
  1011. // Compute the on-disk path names for each of our special keys.
  1012. //
  1013. MakeOemRootName( gOemRootData.OnDiskPathName );
  1014. MakeSysDriveName( gSysDriveData.OnDiskPathName );
  1015. MakeSysDirName( gSysDirData.OnDiskPathName );
  1016. MakeOtherDriveName( gOtherDrivesData.OnDiskPathName, _T('\0') );
  1017. //
  1018. // Load and tweak the browse strings
  1019. //
  1020. StrExecutableFiles = MyLoadString( IDS_EXECUTABLE_FILES );
  1021. StrAllFiles = MyLoadString( IDS_ALL_FILES );
  1022. //
  1023. // The question marks (?) are just placehoders for where the NULL char
  1024. // will be inserted.
  1025. //
  1026. hrPrintf=StringCchPrintf( g_szSysprepFileFilter, AS(g_szSysprepFileFilter),
  1027. _T("%s (*.exe)?*.exe?%s (*.*)?*.*?"),
  1028. StrExecutableFiles,
  1029. StrAllFiles );
  1030. ConvertQuestionsToNull( g_szSysprepFileFilter );
  1031. //
  1032. // ISSUE-2002/02/28-stelo- leave this comment in, but move it to a more appropriate place
  1033. //
  1034. // Currently, all of our special keys use the shell folder icon
  1035. // and the shell open_folder icon. So load these icons now and
  1036. // use the same idx for all of the special keys.
  1037. //
  1038. // Note that if we make our own IDI_* for these special keys,
  1039. // you'll have to write a new routine in the icon_queing support
  1040. // to load an IDI_ and you'll need to fiddle with the icon_info
  1041. // type and call the new routine from here. You'll need to fix
  1042. // these comments too, (unless you're too much of a wimp to
  1043. // delete things that should be deleted).
  1044. //
  1045. }
  1046. //---------------------------------------------------------------------------
  1047. //
  1048. // Function: DrawSysprepTreeView
  1049. //
  1050. // Purpose:
  1051. //
  1052. // Arguments: HWND hwnd - handle to the dialog box
  1053. //
  1054. // Returns: VOID
  1055. //
  1056. //
  1057. //---------------------------------------------------------------------------
  1058. VOID
  1059. DrawSysprepTreeView( IN HWND hwnd )
  1060. {
  1061. HWND hTv = GetDlgItem(hwnd, IDC_FILETREE);
  1062. TCHAR c;
  1063. INT iSmallIcon;
  1064. INT iOpenIcon;
  1065. TCHAR szLangFilesPath[MAX_PATH + 1];
  1066. HTREEITEM hRoot,
  1067. hPnpDrivers,
  1068. hSysprepFiles,
  1069. hLangFiles;
  1070. //
  1071. // Delete the old tree so we can build it up fresh
  1072. //
  1073. TreeView_DeleteAllItems( hTv );
  1074. //
  1075. // Compute the on-disk path names for the special keys that change on
  1076. // a sysprep tree view.
  1077. //
  1078. MakePnpDriversName(gPnpDriversData.OnDiskPathName);
  1079. MakeSysprepSetupFilesPath(gSysprepData.OnDiskPathName);
  1080. MakeSysprepLangFilesGroupName(szLangFilesPath);
  1081. //
  1082. // Make sure the language files dir gets created
  1083. //
  1084. EnsureDirExists( szLangFilesPath );
  1085. iSmallIcon = LoadShellIcon(gOemRootData.OnDiskPathName, SHGFI_SMALLICON);
  1086. iOpenIcon = LoadShellIcon(gOemRootData.OnDiskPathName, SHGFI_OPENICON);
  1087. //
  1088. // The drivers dir is outside the rest of the tree so ensure it gets
  1089. // created here.
  1090. //
  1091. EnsureDirExists( gPnpDriversData.OnDiskPathName );
  1092. //
  1093. // Insert each of our special locations into the tree-view.
  1094. //
  1095. hRoot = InsertSingleItem(hwnd,
  1096. StrOemRootName,
  1097. iSmallIcon,
  1098. iOpenIcon,
  1099. &gOemRootData,
  1100. TVI_ROOT);
  1101. hPnpDrivers = InsertSingleItem(hwnd,
  1102. StrPnpDriversName,
  1103. iSmallIcon,
  1104. iOpenIcon,
  1105. &gPnpDriversData,
  1106. hRoot);
  1107. hSysprepFiles = InsertSingleItem(hwnd,
  1108. StrSysprepFilesName,
  1109. iSmallIcon,
  1110. iOpenIcon,
  1111. &gSysprepData,
  1112. hRoot);
  1113. //
  1114. // Now go out and read from the disk and populate each of these
  1115. // special trees.
  1116. //
  1117. // Note that there is nothing but special keys under OEM_ROOT,
  1118. // so there is no tree walking to do for OEM_ROOT, we've already
  1119. // added all of it's children above.
  1120. //
  1121. WalkTreeAndAddItems(hwnd,
  1122. gPnpDriversData.OnDiskPathName,
  1123. hPnpDrivers,
  1124. INIT_NORMAL);
  1125. WalkTreeAndAddItems(hwnd,
  1126. gSysprepData.OnDiskPathName,
  1127. hSysprepFiles,
  1128. INIT_TEMPFILES);
  1129. //
  1130. // Set the imagelist (the icons on the tree-view)
  1131. //
  1132. SetOurImageList(GetDlgItem(hwnd, IDC_FILETREE));
  1133. //
  1134. // All buttons are grey to start with
  1135. //
  1136. EnableWindow(GetDlgItem(hwnd, IDC_REMOVEFILE), FALSE);
  1137. EnableWindow(GetDlgItem(hwnd, IDC_ADDFILE), FALSE);
  1138. //
  1139. // Expand our special keys
  1140. //
  1141. TreeView_Expand(hTv, hRoot, TVE_EXPAND);
  1142. }
  1143. //---------------------------------------------------------------------------
  1144. //
  1145. // Function: DrawStandardTreeView
  1146. //
  1147. // Purpose:
  1148. //
  1149. // Arguments: HWND hwnd - handle to the dialog box
  1150. //
  1151. // Returns: VOID
  1152. //
  1153. //
  1154. //---------------------------------------------------------------------------
  1155. VOID
  1156. DrawStandardTreeView( IN HWND hwnd )
  1157. {
  1158. HWND hTv = GetDlgItem(hwnd, IDC_FILETREE);
  1159. TCHAR c;
  1160. INT iSmallIcon;
  1161. INT iOpenIcon;
  1162. HTREEITEM hRoot,
  1163. hSysDrive,
  1164. hSysDir,
  1165. hOtherDrives,
  1166. hPnpDrivers,
  1167. hTempFiles,
  1168. hTextmodeFiles;
  1169. //
  1170. // Delete the old tree so we can build it up fresh
  1171. //
  1172. TreeView_DeleteAllItems( hTv );
  1173. //
  1174. // Compute the on-disk path names for the special keys that change on
  1175. // a standard tree view.
  1176. //
  1177. MakePnpDriversName(gPnpDriversData.OnDiskPathName);
  1178. MakeTempFilesName(gTempFilesData.OnDiskPathName);
  1179. MakeTextmodeFilesName(gTextmodeData.OnDiskPathName);
  1180. iSmallIcon = LoadShellIcon(gOemRootData.OnDiskPathName, SHGFI_SMALLICON);
  1181. iOpenIcon = LoadShellIcon(gOemRootData.OnDiskPathName, SHGFI_OPENICON);
  1182. //
  1183. // Insert each of our special locations into the tree-view.
  1184. //
  1185. hRoot = InsertSingleItem(hwnd,
  1186. StrOemRootName,
  1187. iSmallIcon,
  1188. iOpenIcon,
  1189. &gOemRootData,
  1190. TVI_ROOT);
  1191. hSysDrive = InsertSingleItem(hwnd,
  1192. StrSysDriveName,
  1193. iSmallIcon,
  1194. iOpenIcon,
  1195. &gSysDriveData,
  1196. hRoot);
  1197. hSysDir = InsertSingleItem(hwnd,
  1198. StrSysDirName,
  1199. iSmallIcon,
  1200. iOpenIcon,
  1201. &gSysDirData,
  1202. hSysDrive);
  1203. hOtherDrives = InsertSingleItem(hwnd,
  1204. StrOtherDrivesName,
  1205. iSmallIcon,
  1206. iOpenIcon,
  1207. &gOtherDrivesData,
  1208. hRoot);
  1209. hPnpDrivers = InsertSingleItem(hwnd,
  1210. StrPnpDriversName,
  1211. iSmallIcon,
  1212. iOpenIcon,
  1213. &gPnpDriversData,
  1214. hSysDrive);
  1215. hTempFiles = InsertSingleItem(hwnd,
  1216. StrTempFilesName,
  1217. iSmallIcon,
  1218. iOpenIcon,
  1219. &gTempFilesData,
  1220. hRoot);
  1221. hTextmodeFiles = InsertSingleItem(hwnd,
  1222. StrTextmodeFilesName,
  1223. iSmallIcon,
  1224. iOpenIcon,
  1225. &gTextmodeData,
  1226. hTempFiles);
  1227. //
  1228. // Now go out and read from the disk and populate each of these
  1229. // special trees.
  1230. //
  1231. // Note that there is nothing but special keys under OEM_ROOT,
  1232. // so there is no tree walking to do for OEM_ROOT, we've already
  1233. // added all of it's children above.
  1234. //
  1235. WalkTreeAndAddItems(hwnd,
  1236. gSysDriveData.OnDiskPathName,
  1237. hSysDrive,
  1238. INIT_SYSDRIVE);
  1239. WalkTreeAndAddItems(hwnd,
  1240. gSysDirData.OnDiskPathName,
  1241. hSysDir,
  1242. INIT_NORMAL);
  1243. for ( c=_T('A'); c<=_T('Z'); c++ ) {
  1244. HTREEITEM hDrive;
  1245. TCHAR DriveLetterBuff[2];
  1246. TCHAR PathBuffer[MAX_PATH];
  1247. HRESULT hrPrintf;
  1248. MakeOtherDriveName(PathBuffer, c);
  1249. if ( DoesFolderExist(PathBuffer) ) {
  1250. hrPrintf=StringCchPrintf(DriveLetterBuff,AS(DriveLetterBuff), _T("%c"), c);
  1251. hDrive = InsertSingleItem(hwnd,
  1252. DriveLetterBuff,
  1253. iSmallIcon,
  1254. iOpenIcon,
  1255. NULL,
  1256. hOtherDrives);
  1257. WalkTreeAndAddItems(hwnd,
  1258. PathBuffer,
  1259. hDrive,
  1260. INIT_NORMAL);
  1261. }
  1262. }
  1263. WalkTreeAndAddItems(hwnd,
  1264. gPnpDriversData.OnDiskPathName,
  1265. hPnpDrivers,
  1266. INIT_NORMAL);
  1267. WalkTreeAndAddItems(hwnd,
  1268. gTempFilesData.OnDiskPathName,
  1269. hTempFiles,
  1270. INIT_TEMPFILES);
  1271. WalkTreeAndAddItems(hwnd,
  1272. gTextmodeData.OnDiskPathName,
  1273. hTextmodeFiles,
  1274. INIT_TEMPFILES);
  1275. //
  1276. // Set the imagelist (the icons on the tree-view)
  1277. //
  1278. SetOurImageList(GetDlgItem(hwnd, IDC_FILETREE));
  1279. //
  1280. // All buttons are grey to start with
  1281. //
  1282. EnableWindow(GetDlgItem(hwnd, IDC_REMOVEFILE), FALSE);
  1283. EnableWindow(GetDlgItem(hwnd, IDC_ADDFILE), FALSE);
  1284. //
  1285. // Expand our special keys
  1286. //
  1287. TreeView_Expand(hTv, hRoot, TVE_EXPAND);
  1288. }
  1289. //---------------------------------------------------------------------------
  1290. //
  1291. // Function: OnSetActiveAddDirs
  1292. //
  1293. // Purpose: Determines if the tree view needs to be redrawn and if it does,
  1294. // redraws it.
  1295. //
  1296. // Arguments: HWND hwnd - handle to the dialog box
  1297. //
  1298. // Returns: VOID
  1299. //
  1300. //---------------------------------------------------------------------------
  1301. VOID
  1302. OnSetActiveAddDirs( IN HWND hwnd )
  1303. {
  1304. if( g_iLastProductInstall == NO_PREVIOUS_PRODUCT_CHOSEN )
  1305. {
  1306. //
  1307. // This is their first time seeing this page, so draw the approprate
  1308. // tree view.
  1309. //
  1310. if( WizGlobals.iProductInstall == PRODUCT_SYSPREP )
  1311. {
  1312. DrawSysprepTreeView( hwnd );
  1313. }
  1314. else
  1315. {
  1316. DrawStandardTreeView( hwnd );
  1317. }
  1318. }
  1319. else if( g_iLastProductInstall == PRODUCT_SYSPREP && WizGlobals.iProductInstall != PRODUCT_SYSPREP )
  1320. {
  1321. DrawStandardTreeView( hwnd );
  1322. }
  1323. else if( g_iLastProductInstall != PRODUCT_SYSPREP && WizGlobals.iProductInstall == PRODUCT_SYSPREP )
  1324. {
  1325. DrawSysprepTreeView( hwnd );
  1326. }
  1327. g_iLastProductInstall = WizGlobals.iProductInstall;
  1328. }
  1329. //----------------------------------------------------------------------------
  1330. //
  1331. // This section of code implements OnTreeViewSelectionChange() which
  1332. // is called whenever the user selects a different tree-view item.
  1333. //
  1334. // On this event, we query the currently selected tree-view item and
  1335. // do some processing to figure out where this tree-view item maps to
  1336. // on disk storage. Once we figure out all we want to know about the
  1337. // current selection, we update all of the fields of gCurSel.
  1338. //
  1339. //----------------------------------------------------------------------------
  1340. //----------------------------------------------------------------------------
  1341. //
  1342. // Function: ComputeFullPathOfItem
  1343. //
  1344. // Purpose: We continually query the parent of the given tree view item
  1345. // until we get to one of our specially defined roots. Then
  1346. // we fill in the buffer with the full path name of where
  1347. // to copy files to.
  1348. //
  1349. // This function supports OnTreeViewSelectionChange() and should
  1350. // not be called otherwise. That is, we only did this processing
  1351. // when the user picks a new destination. We scribble the info
  1352. // we might need later into globals.
  1353. //
  1354. // Arguments:
  1355. // HTREEITEM hItem - handle to tree item
  1356. // LPTSTR PathBuffer - output, caller must pass a MAX_PATH buffer
  1357. // SPECIAL_KEY_DATA **SpecialRoot - output
  1358. //
  1359. // Returns: VOID
  1360. //
  1361. // Notes:
  1362. // - check PathBuffer[0] == _T('\0') for success
  1363. //
  1364. //----------------------------------------------------------------------------
  1365. VOID
  1366. ComputeFullPathOfItem(IN HWND hwnd,
  1367. IN HTREEITEM hItem,
  1368. OUT LPTSTR PathBuffer,
  1369. OUT SPECIAL_KEY_DATA **pSpecialRoot)
  1370. {
  1371. TVITEM TvItemData;
  1372. HTREEITEM hParent;
  1373. TCHAR ItemName[MAX_PATH], TempBuffer[MAX_PATH];
  1374. int NumCharsReplace;
  1375. SPECIAL_KEY_DATA *pSpecialKeyData;
  1376. PathBuffer[0] = _T('\0');
  1377. //
  1378. // The TvItemData is used to query the name of the hItem. We
  1379. // receive the name in ItemName[]. Set the fields that won't
  1380. // change in the loop.
  1381. //
  1382. TvItemData.mask = TVIF_TEXT | TVIF_PARAM;
  1383. TvItemData.pszText = ItemName;
  1384. TvItemData.cchTextMax = MAX_PATH;
  1385. //
  1386. // Now continually query the name of the parent and keep prefixing
  1387. // the parent's name to build the on-disk pathname. Stop when we
  1388. // get to one of our special root keys.
  1389. //
  1390. // We detect hitting a special key because the lParam will be
  1391. // non-null. Once we get there, we know the on-disk prefix.
  1392. //
  1393. do {
  1394. TvItemData.hItem = hItem;
  1395. TreeView_GetItem(GetDlgItem(hwnd, IDC_FILETREE), &TvItemData);
  1396. if ( TvItemData.lParam != (LPARAM) NULL )
  1397. break;
  1398. TempBuffer[0] = _T('\0');
  1399. ConcatenatePaths(TempBuffer, ItemName, PathBuffer, NULL);
  1400. lstrcpyn(PathBuffer, TempBuffer, AS(PathBuffer));
  1401. hParent = TreeView_GetParent(GetDlgItem(hwnd, IDC_FILETREE), hItem);
  1402. if ( hParent == NULL )
  1403. break;
  1404. hItem = hParent;
  1405. } while ( TRUE );
  1406. //
  1407. // The final item queried in the above loop should have a non-null
  1408. // lParam i.e. the loop should only terminate when it encounters
  1409. // a special key.
  1410. //
  1411. pSpecialKeyData = (SPECIAL_KEY_DATA*) TvItemData.lParam;
  1412. Assert(pSpecialKeyData != NULL);
  1413. //
  1414. // Prefix the disk path of our special root key onto the PathBuffer
  1415. // we computed in the loop above.
  1416. //
  1417. TempBuffer[0] = _T('\0');
  1418. ConcatenatePaths(TempBuffer,
  1419. pSpecialKeyData->OnDiskPathName,
  1420. PathBuffer,
  1421. NULL);
  1422. lstrcpyn(PathBuffer, TempBuffer, AS(PathBuffer));
  1423. //
  1424. // Give the caller the address of the special key data. This is how
  1425. // caller knows what description to display on the ui
  1426. //
  1427. (*pSpecialRoot) = pSpecialKeyData;
  1428. }
  1429. //----------------------------------------------------------------------------
  1430. //
  1431. // Function: OnTreeViewSelectionChange
  1432. //
  1433. // Purpose: This function is called when the user changes the file/dir
  1434. // selected on the tree-view.
  1435. //
  1436. // We compute the full path of the tree-view item now selected
  1437. // and update the global gCurSel.
  1438. //
  1439. //----------------------------------------------------------------------------
  1440. VOID OnTreeViewSelectionChange(HWND hwnd)
  1441. {
  1442. HWND hTv = GetDlgItem(hwnd, IDC_FILETREE);
  1443. TCHAR PathBuffer[MAX_PATH], *pEnd;
  1444. HTREEITEM hItem;
  1445. DWORD dwAttribs;
  1446. LPTSTR lpFileNamePart;
  1447. BOOL bEnableCopy;
  1448. SPECIAL_KEY_DATA *pCurItemlParam,
  1449. *pCurFolderlParam;
  1450. SPECIAL_KEY_DATA *RootSpecialData = NULL;
  1451. //
  1452. // Get the currently selected item and figure out the on-disk pathname
  1453. // for it and figure out which of the 6 special roots this item is under
  1454. // (RootSpecialData, that is).
  1455. //
  1456. hItem = TreeView_GetSelection(hTv);
  1457. ComputeFullPathOfItem(hwnd, hItem, PathBuffer, &RootSpecialData);
  1458. //
  1459. // Save this info in the global gCurSel
  1460. //
  1461. gCurSel.hCurItem = hItem;
  1462. lstrcpyn(gCurSel.lpCurItemPath, PathBuffer, AS(gCurSel.lpCurItemPath));
  1463. //
  1464. // If the CurItem is a directory, the CurFolder should be the same.
  1465. // If the CurItem is a file, the CurFolder should be the parent.
  1466. //
  1467. // Copy & NewFolder goes into the CurFolder, deletes use the CurItem.
  1468. //
  1469. lstrcpyn(gCurSel.lpCurFolderPath, gCurSel.lpCurItemPath,AS(gCurSel.lpCurFolderPath));
  1470. gCurSel.hCurFolderItem = gCurSel.hCurItem;
  1471. if ( DoesFileExist(gCurSel.lpCurItemPath) ) {
  1472. lpFileNamePart = MyGetFullPath(gCurSel.lpCurFolderPath);
  1473. if ( lpFileNamePart == NULL || *(lpFileNamePart-1) != _T('\\') )
  1474. {
  1475. AssertMsg(FALSE,
  1476. "Could not parse filename. This should not happen.");
  1477. TerminateTheWizard(IDS_ERROR_OUTOFMEMORY);
  1478. }
  1479. *(lpFileNamePart-1) = _T('\0');
  1480. gCurSel.hCurFolderItem =
  1481. TreeView_GetParent(hTv, gCurSel.hCurFolderItem);
  1482. }
  1483. //
  1484. // Grey/ungrey the buttons.
  1485. //
  1486. // If an lParam is non-null, then it's one of our special keys.
  1487. //
  1488. // User cannot delete any special keys.
  1489. //
  1490. // User can copy, unless the current dest folder is KEY_OEMROOT or
  1491. // KEY_OTHERDRIVES.
  1492. //
  1493. pCurItemlParam = GetItemlParam(hTv, gCurSel.hCurItem);
  1494. pCurFolderlParam = GetItemlParam(hTv, gCurSel.hCurFolderItem);
  1495. EnableWindow(GetDlgItem(hwnd, IDC_REMOVEFILE), pCurItemlParam == NULL);
  1496. bEnableCopy = ( pCurFolderlParam == NULL ||
  1497. ( pCurFolderlParam->iSpecialKeyId != KEY_OEMROOT &&
  1498. pCurFolderlParam->iSpecialKeyId != KEY_OTHERDRIVES) );
  1499. EnableWindow(GetDlgItem(hwnd, IDC_ADDFILE), bEnableCopy);
  1500. //
  1501. // Set the description on the ui.
  1502. //
  1503. Assert(RootSpecialData != NULL);
  1504. SetDlgItemText(hwnd, IDC_ADDDIRS_DESCR, RootSpecialData->Description);
  1505. }
  1506. //---------------------------------------------------------------------------
  1507. //
  1508. // This section of code implements OnAddFileDir() which is called when
  1509. // the user pushes the ADD button. We have to allow the user to Browse
  1510. // for the source file/dir, then do the copy/tree-copy and update the
  1511. // tree-view display.
  1512. //
  1513. //---------------------------------------------------------------------------
  1514. //---------------------------------------------------------------------------
  1515. //
  1516. // Function: BrowseForSourceDir
  1517. //
  1518. // Purpose: This function pulls up the SHBrowseForFolder dialog and allows
  1519. // the user to select a directory to copy NT binaries into.
  1520. //
  1521. // Arguments:
  1522. // HWND hwnd - owning window
  1523. // LPTSTR PathBuffer - MAX_PATH buffer to receive results
  1524. //
  1525. // Returns: BOOL - TRUE if the user entered a path
  1526. // FALSE if the user canceled out of the dialog
  1527. //
  1528. // Notes:
  1529. //
  1530. //---------------------------------------------------------------------------
  1531. BOOL
  1532. BrowseForSourceDir(HWND hwnd, LPTSTR PathBuffer)
  1533. {
  1534. BROWSEINFO BrowseInf;
  1535. UINT ulFlags = BIF_BROWSEINCLUDEFILES |
  1536. BIF_RETURNONLYFSDIRS |
  1537. BIF_EDITBOX;
  1538. LPITEMIDLIST lpIdList;
  1539. if( StrSelectFileOrFolderToCopy == NULL )
  1540. {
  1541. StrSelectFileOrFolderToCopy = MyLoadString( IDS_SELECT_FILE_OR_FOLDER );
  1542. }
  1543. //
  1544. // ISSUE-2002/02/28-stelo-
  1545. // - No initial root, should go back where it was last time
  1546. // - Need a callback to grey out root of drive
  1547. //
  1548. //
  1549. // Go browse
  1550. //
  1551. BrowseInf.hwndOwner = hwnd;
  1552. BrowseInf.pidlRoot = NULL; // root == desktop
  1553. BrowseInf.pszDisplayName = PathBuffer; // output (useless)
  1554. BrowseInf.lpszTitle = StrSelectFileOrFolderToCopy;
  1555. BrowseInf.ulFlags = ulFlags;
  1556. BrowseInf.lpfn = NULL; // no callback
  1557. BrowseInf.lParam = (LPARAM) 0; // no callback
  1558. BrowseInf.iImage = 0; // no image
  1559. lpIdList = SHBrowseForFolder(&BrowseInf);
  1560. //
  1561. // Get the pathname out of this idlist returned and free up the memory
  1562. //
  1563. if ( lpIdList == NULL )
  1564. {
  1565. PathBuffer[0] = _T('\0');
  1566. return( FALSE );
  1567. }
  1568. else
  1569. {
  1570. SHGetPathFromIDList(lpIdList, PathBuffer);
  1571. MyGetFullPath(PathBuffer);
  1572. ILFreePriv(lpIdList);
  1573. return( TRUE );
  1574. }
  1575. }
  1576. //----------------------------------------------------------------------------
  1577. //
  1578. // Function: AdditionalDirsCopyTree
  1579. //
  1580. // Purpose: Copies a directory tree to the given folder. The tree-view
  1581. // display is not updated or anything of the sort. It simply
  1582. // copies the tree.
  1583. //
  1584. // This is a support routine for OnAddFileDir() and should
  1585. // not be called otherwise.
  1586. //
  1587. // Arguements:
  1588. // HWND hwnd - owning window
  1589. // LPTSTR lpSource - MAX_PATH buffer
  1590. // LPTSTR lpDest - MAX_PATH buffer
  1591. // LPTSTR lpFileNamePart - if d:\foo\bar, this should be "bar"
  1592. // HTREEITEM hParentItem - parent item on the display
  1593. //
  1594. // Returns: VOID
  1595. //
  1596. // Notes:
  1597. // - Both lpSource and lpDest must be directories, and each must
  1598. // be a MAX_PATH buffer.
  1599. //
  1600. // - Any paths >= MAX_PATH in length are silently skipped.
  1601. //
  1602. // - lpFileNamePart can point to any buffer anywhere, it does not
  1603. // have to point into lpSource or lpDest buffers. It just has to
  1604. // have the right data.
  1605. //
  1606. //----------------------------------------------------------------------------
  1607. VOID AdditionalDirsCopyTree(HWND hwnd,
  1608. LPTSTR lpSource,
  1609. LPTSTR lpDest,
  1610. LPTSTR lpFileNamePart,
  1611. HTREEITEM hParentItem)
  1612. {
  1613. LPTSTR SrcPathEnd = lpSource + lstrlen(lpSource);
  1614. LPTSTR DestPathEnd = lpDest + lstrlen(lpDest);
  1615. HANDLE FindHandle;
  1616. WIN32_FIND_DATA FindData;
  1617. int iSmallIcon, iOpenIcon;
  1618. HTREEITEM hItem;
  1619. //
  1620. // Create the folder
  1621. //
  1622. if ( ! CreateDirectory(lpDest, NULL) ) {
  1623. ReportErrorId(hwnd,
  1624. MSGTYPE_ERR | MSGTYPE_WIN32,
  1625. IDS_ERR_CREATE_FOLDER,
  1626. lpDest);
  1627. return;
  1628. }
  1629. //
  1630. // Add the tree-view item for this folder
  1631. //
  1632. iSmallIcon = LoadShellIcon(lpSource, SHGFI_SMALLICON);
  1633. iOpenIcon = LoadShellIcon(lpSource, SHGFI_OPENICON);
  1634. if ( (hItem = InsertSingleItem(hwnd,
  1635. lpFileNamePart,
  1636. iSmallIcon,
  1637. iOpenIcon,
  1638. NULL,
  1639. hParentItem)) == NULL ) {
  1640. return;
  1641. }
  1642. //
  1643. // loop over lpSource\*
  1644. //
  1645. if ( ! ConcatenatePaths(lpSource, _T("*"), NULL) )
  1646. return;
  1647. FindHandle = FindFirstFile(lpSource, &FindData);
  1648. if ( FindHandle == INVALID_HANDLE_VALUE )
  1649. return;
  1650. do {
  1651. *SrcPathEnd = _T('\0');
  1652. *DestPathEnd = _T('\0');
  1653. //
  1654. // skip over the . and .. entries
  1655. //
  1656. if (0 == lstrcmp(FindData.cFileName, _T(".")) ||
  1657. 0 == lstrcmp(FindData.cFileName, _T("..")))
  1658. continue;
  1659. //
  1660. // Build the new source and dest names
  1661. //
  1662. if ( ! ConcatenatePaths(lpSource, FindData.cFileName, NULL) ||
  1663. ! ConcatenatePaths(lpDest, FindData.cFileName, NULL) )
  1664. continue;
  1665. //
  1666. // If the source is a file, copy it. If it's a directory, create
  1667. // the directory at the destination and recurse.
  1668. //
  1669. if ( ! (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) {
  1670. if ( ! CopyFile(lpSource, lpDest, TRUE) ) {
  1671. ReportErrorId(hwnd,
  1672. MSGTYPE_ERR | MSGTYPE_WIN32,
  1673. IDS_ERR_COPY_FILE,
  1674. lpSource, lpDest);
  1675. continue;
  1676. }
  1677. SetFileAttributes(lpDest, FILE_ATTRIBUTE_NORMAL);
  1678. //
  1679. // Add the tree-view item for this file
  1680. //
  1681. iSmallIcon = LoadShellIcon(lpSource, SHGFI_SMALLICON);
  1682. iOpenIcon = LoadShellIcon(lpSource, SHGFI_OPENICON);
  1683. if ( InsertSingleItem(hwnd,
  1684. FindData.cFileName,
  1685. iSmallIcon,
  1686. iOpenIcon,
  1687. NULL,
  1688. hItem) == NULL ) {
  1689. continue;
  1690. }
  1691. }
  1692. else {
  1693. AdditionalDirsCopyTree(hwnd,
  1694. lpSource,
  1695. lpDest,
  1696. FindData.cFileName,
  1697. hItem);
  1698. }
  1699. } while ( FindNextFile(FindHandle, &FindData) );
  1700. *SrcPathEnd = _T('\0');
  1701. *DestPathEnd = _T('\0');
  1702. FindClose(FindHandle);
  1703. }
  1704. //----------------------------------------------------------------------------
  1705. //
  1706. // Function: OnAddFileDir
  1707. //
  1708. // Purpose: This function is called when the AddFile button is pushed.
  1709. //
  1710. // Arguments:
  1711. // HWND hwnd - owning window
  1712. //
  1713. // Returns: VOID
  1714. //
  1715. //----------------------------------------------------------------------------
  1716. VOID OnAddFileDir(HWND hwnd)
  1717. {
  1718. TCHAR SrcPathBuffer[MAX_PATH];
  1719. TCHAR DestPathBuffer[MAX_PATH];
  1720. HTREEITEM hItem;
  1721. TCHAR *lpFileNamePart;
  1722. BOOL bSrcIsDir;
  1723. //
  1724. // Browse for the source path. User can cancel on the source, so
  1725. // be sure to check.
  1726. //
  1727. BrowseForSourceDir(hwnd, SrcPathBuffer);
  1728. if ( SrcPathBuffer[0] == _T('\0') )
  1729. return;
  1730. //
  1731. // Get the simple filename out of the src. e.g. d:\foo\bar, we want
  1732. // the "bar".
  1733. //
  1734. // Note:
  1735. //
  1736. // If there's no "bar" there, then the user probably selected the
  1737. // root of a drive (c:\ or d:\ etc.) In that case we'll give a
  1738. // generic stop message "Setup Manager cannot copy path %s". We
  1739. // can't assume in the error text that it was the root the user
  1740. // tried to copy. (although I don't know of another cause, there
  1741. // might be one).
  1742. //
  1743. // ISSUE-2002/02/28-stelo- Turn this into an assert when SHBrowseForFolder call is fixed.
  1744. //
  1745. lpFileNamePart = MyGetFullPath(SrcPathBuffer);
  1746. if ( lpFileNamePart == NULL ) {
  1747. ReportErrorId(hwnd,
  1748. MSGTYPE_ERR,
  1749. IDS_ERR_CANNOT_COPY_PATH,
  1750. SrcPathBuffer);
  1751. return;
  1752. }
  1753. //
  1754. // We will always copy into the current folder, cat the simple name
  1755. // of source onto the destination folder.
  1756. //
  1757. lstrcpyn(DestPathBuffer, gCurSel.lpCurFolderPath, AS(DestPathBuffer));
  1758. if ( ! ConcatenatePaths(DestPathBuffer, lpFileNamePart, NULL) )
  1759. return;
  1760. //
  1761. // Copy it
  1762. //
  1763. if ( DoesFolderExist(SrcPathBuffer) ) {
  1764. AdditionalDirsCopyTree(hwnd,
  1765. SrcPathBuffer,
  1766. DestPathBuffer,
  1767. lpFileNamePart,
  1768. gCurSel.hCurFolderItem);
  1769. }
  1770. else {
  1771. int iSmallIcon = LoadShellIcon(SrcPathBuffer, SHGFI_SMALLICON);
  1772. int iOpenIcon = LoadShellIcon(SrcPathBuffer, SHGFI_OPENICON);
  1773. if ( ! CopyFile(SrcPathBuffer, DestPathBuffer, TRUE) ) {
  1774. ReportErrorId(hwnd,
  1775. MSGTYPE_ERR | MSGTYPE_WIN32,
  1776. IDS_ERR_COPY_FILE,
  1777. SrcPathBuffer, DestPathBuffer);
  1778. return;
  1779. }
  1780. SetFileAttributes(DestPathBuffer, FILE_ATTRIBUTE_NORMAL);
  1781. if ( (hItem = InsertSingleItem(hwnd,
  1782. lpFileNamePart,
  1783. iSmallIcon,
  1784. iOpenIcon,
  1785. NULL,
  1786. gCurSel.hCurFolderItem)) == NULL ) {
  1787. return;
  1788. }
  1789. }
  1790. //
  1791. // We have to update the tree-view's image list because we added
  1792. // files and we may have encountered icons we haven't seen before.
  1793. //
  1794. SetOurImageList(GetDlgItem(hwnd, IDC_FILETREE));
  1795. }
  1796. //----------------------------------------------------------------------------
  1797. //
  1798. // This section of code implements OnRemoveFileDir() which is called
  1799. // when the user pushes the REMOVE button.
  1800. //
  1801. //----------------------------------------------------------------------------
  1802. //----------------------------------------------------------------------------
  1803. //
  1804. // Function: AddDirsDeleteNode
  1805. //
  1806. // Purpose: Function to delete a node from a disk. This function is
  1807. // support for OnRemoveFileDir() and should not be called
  1808. // otherwise.
  1809. //
  1810. // Arguments:
  1811. // HWND hwnd - owning window
  1812. // LPTSTR lpRoot - fully qualified root path
  1813. // LPTSTR lpFileNamePart - if lpRoot==d:\foo\bar, pass "bar"
  1814. // HTREEITEM hItem - item for lpRoot
  1815. //
  1816. // Returns:
  1817. // VOID
  1818. //
  1819. // Notes:
  1820. // - lpRoot must be a buffer MAX_PATH wide
  1821. // - Paths >= MAX_PATH in length are silently skipped
  1822. //
  1823. //----------------------------------------------------------------------------
  1824. VOID AddDirsDeleteNode(HWND hwnd,
  1825. LPTSTR lpRoot,
  1826. LPTSTR lpFileNamePart,
  1827. HTREEITEM hItem)
  1828. {
  1829. LPTSTR lpRootEnd = lpRoot + lstrlen(lpRoot);
  1830. HWND hTv = GetDlgItem(hwnd, IDC_FILETREE);
  1831. HANDLE FindHandle;
  1832. WIN32_FIND_DATA FindData;
  1833. HTREEITEM hCurItem;
  1834. //
  1835. // loop over lpRoot\*
  1836. //
  1837. if ( ! ConcatenatePaths(lpRoot, _T("*"), NULL) )
  1838. return;
  1839. FindHandle = FindFirstFile(lpRoot, &FindData);
  1840. if ( FindHandle == INVALID_HANDLE_VALUE )
  1841. return;
  1842. do {
  1843. *lpRootEnd = _T('\0');
  1844. //
  1845. // skip over the . and .. entries
  1846. //
  1847. if (0 == lstrcmp(FindData.cFileName, _T(".")) ||
  1848. 0 == lstrcmp(FindData.cFileName, _T("..")))
  1849. continue;
  1850. //
  1851. // Build the new path name
  1852. //
  1853. if ( ! ConcatenatePaths(lpRoot, FindData.cFileName, NULL) )
  1854. continue;
  1855. //
  1856. // Find the corresponding tree-view item for this file/dir
  1857. //
  1858. hCurItem = FindItemByName(hTv, hItem, FindData.cFileName);
  1859. //
  1860. // If the source is a file, delete it, else recurse.
  1861. //
  1862. if ( ! (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) {
  1863. if ( ! DeleteFile(lpRoot) ) {
  1864. ReportErrorId(hwnd,
  1865. MSGTYPE_ERR | MSGTYPE_WIN32,
  1866. IDS_ERR_DELETE_FILE,
  1867. lpRoot);
  1868. continue;
  1869. }
  1870. if ( hCurItem != NULL )
  1871. TreeView_DeleteItem(hTv, hCurItem);
  1872. }
  1873. else {
  1874. AddDirsDeleteNode(hwnd, lpRoot, FindData.cFileName, hCurItem);
  1875. }
  1876. } while ( FindNextFile(FindHandle, &FindData) );
  1877. *lpRootEnd = _T('\0');
  1878. FindClose(FindHandle);
  1879. //
  1880. // Remove the root directory
  1881. //
  1882. if ( ! RemoveDirectory(lpRoot) ) {
  1883. ReportErrorId(hwnd,
  1884. MSGTYPE_ERR | MSGTYPE_WIN32,
  1885. IDS_ERR_DELETE_FOLDER,
  1886. lpRoot);
  1887. return;
  1888. }
  1889. //
  1890. // Only delete the tree-view entry if there are no children left.
  1891. //
  1892. // There could be children left in this dir because a DeleteFile()
  1893. // could have failed on a recursive call. e.g. a read-only file.
  1894. //
  1895. if ( TreeView_GetChild(hTv, hItem) == NULL )
  1896. TreeView_DeleteItem(hTv, hItem);
  1897. }
  1898. //----------------------------------------------------------------------------
  1899. //
  1900. // Function: OnRemoveFileDir
  1901. //
  1902. // Purpose: This function is called when the RemoveFile button is pushed.
  1903. //
  1904. //----------------------------------------------------------------------------
  1905. VOID OnRemoveFileDir(HWND hwnd)
  1906. {
  1907. LPTSTR lpPath = gCurSel.lpCurItemPath;
  1908. HTREEITEM hItem = gCurSel.hCurItem;
  1909. HWND hTv = GetDlgItem(hwnd, IDC_FILETREE);
  1910. int iRet;
  1911. //
  1912. // Look at the current selection, and delete the file or delete
  1913. // the node.
  1914. //
  1915. if ( DoesFolderExist(lpPath) ) {
  1916. iRet = ReportErrorId(hwnd,
  1917. MSGTYPE_YESNO,
  1918. IDS_DELETE_FOLDER_CONFIRM,
  1919. lpPath);
  1920. if ( iRet == IDYES ) {
  1921. AddDirsDeleteNode(hwnd,
  1922. lpPath,
  1923. MyGetFullPath(lpPath),
  1924. hItem);
  1925. }
  1926. }
  1927. else {
  1928. iRet = ReportErrorId(hwnd,
  1929. MSGTYPE_YESNO,
  1930. IDS_DELETE_FILE_CONFIRM,
  1931. lpPath);
  1932. if ( iRet == IDYES ) {
  1933. if ( ! DeleteFile(lpPath) ) {
  1934. ReportErrorId(hwnd,
  1935. MSGTYPE_ERR | MSGTYPE_WIN32,
  1936. IDS_ERR_DELETE_FILE,
  1937. lpPath);
  1938. }
  1939. TreeView_DeleteItem(hTv, hItem);
  1940. }
  1941. }
  1942. }
  1943. //----------------------------------------------------------------------------
  1944. //
  1945. // This section of code is for Sysprep functions
  1946. //
  1947. //----------------------------------------------------------------------------
  1948. //----------------------------------------------------------------------------
  1949. //
  1950. // Function: CopySysprepFileLow
  1951. //
  1952. // Purpose: Copies one file to the destination specified. Handles any errors
  1953. // that occur during the copy.
  1954. //
  1955. // Arguments:
  1956. // HWND hwnd - handle to the dialog box
  1957. // TCHAR *szSysprepPathandFileNameSrc - path and file name of source file to copy
  1958. // TCHAR *szSysprepPathandFileNameDest - path and file name of where to copy the file
  1959. // TCHAR *szSysprepPath - the path to the sysprep dir
  1960. // TCHAR *szDirectory - directory to begin the search for the file
  1961. // TCHAR const * const szFileName - the file name to copy
  1962. //
  1963. // Returns: VOID
  1964. //
  1965. //----------------------------------------------------------------------------
  1966. static VOID
  1967. CopySysprepFileLow( IN HWND hwnd,
  1968. IN TCHAR *szSysprepPathandFileNameSrc,
  1969. IN TCHAR *szSysprepPathandFileNameDest,
  1970. IN TCHAR *szSysprepPath,
  1971. IN TCHAR *szDirectory,
  1972. IN TCHAR const * const szFileName )
  1973. {
  1974. BOOL bCopyRetVal = FALSE;
  1975. INT iRetVal;
  1976. //
  1977. // Only do the copy if the file isn't already there
  1978. //
  1979. if( ! DoesFileExist( szSysprepPathandFileNameDest ) )
  1980. {
  1981. //
  1982. // If the file is in the current dir, just copy it,
  1983. // else prompt the user for the location
  1984. //
  1985. if( DoesFileExist( szSysprepPathandFileNameSrc ) )
  1986. {
  1987. bCopyRetVal = CopyFile( szSysprepPathandFileNameSrc,
  1988. szSysprepPathandFileNameDest,
  1989. TRUE );
  1990. }
  1991. else
  1992. {
  1993. BOOL bCopyCompleted = FALSE;
  1994. do
  1995. {
  1996. ReportErrorId( hwnd,
  1997. MSGTYPE_ERR,
  1998. IDS_ERR_SPECIFY_FILE,
  1999. szFileName );
  2000. iRetVal = ShowBrowseFolder( hwnd,
  2001. g_szSysprepFileFilter,
  2002. SYSPREP_FILE_EXTENSION,
  2003. OFN_HIDEREADONLY | OFN_PATHMUSTEXIST,
  2004. szDirectory,
  2005. szSysprepPathandFileNameSrc );
  2006. if( ! iRetVal )
  2007. { // user pressed cancel on the Browse dialog
  2008. ReportErrorId( hwnd,
  2009. MSGTYPE_ERR,
  2010. IDS_ERR_UNABLE_TO_COPY_SYSPREP_FILE,
  2011. szFileName,
  2012. szSysprepPath );
  2013. break;
  2014. }
  2015. if( szSysprepPathandFileNameSrc && ( lstrcmpi( MyGetFullPath( szSysprepPathandFileNameSrc ), szFileName ) == 0 ) )
  2016. {
  2017. bCopyRetVal = CopyFile( szSysprepPathandFileNameSrc,
  2018. szSysprepPathandFileNameDest,
  2019. TRUE );
  2020. bCopyCompleted = TRUE;
  2021. }
  2022. } while( ! bCopyCompleted );
  2023. }
  2024. if( ! bCopyRetVal && iRetVal )
  2025. {
  2026. ReportErrorId( hwnd,
  2027. MSGTYPE_ERR,
  2028. IDS_ERR_UNABLE_TO_COPY_SYSPREP_FILE,
  2029. szFileName,
  2030. szSysprepPath );
  2031. }
  2032. SetFileAttributes( szSysprepPathandFileNameDest,
  2033. FILE_ATTRIBUTE_NORMAL );
  2034. }
  2035. }
  2036. //----------------------------------------------------------------------------
  2037. //
  2038. // Function: CopySysprepFiles
  2039. //
  2040. // Purpose: Copies sysprep.exe and setupcl.exe to the sysprep dir on the
  2041. // system drive. Handles any errors that occur during the copy.
  2042. //
  2043. // Arguments: HWND hwnd - handle to the dialog box
  2044. //
  2045. // Returns: VOID
  2046. //
  2047. //----------------------------------------------------------------------------
  2048. static VOID
  2049. CopySysprepFiles( IN HWND hwnd )
  2050. {
  2051. BOOL bCancel;
  2052. TCHAR szSysprepPath[MAX_PATH] = _T("");
  2053. TCHAR szCurrentDirectory[MAX_PATH+1] = _T("");
  2054. TCHAR szSysprepPathandFileNameSrc[MAX_PATH] = _T("");
  2055. TCHAR szSysprepPathandFileNameDest[MAX_PATH] = _T("");
  2056. MakeSysprepSetupFilesPath( szSysprepPath );
  2057. EnsureDirExists( szSysprepPath );
  2058. // GetModuleFileName may not terminate path if path is truncated in the case
  2059. // of the file spec using the //?/ format and exceeding MAX_PATH. This should
  2060. // never happen in our case, but we will make the check and NULL terminate
  2061. if (GetModuleFileName( NULL, szCurrentDirectory, MAX_PATH) >= MAX_PATH)
  2062. szCurrentDirectory[MAX_PATH]='\0';
  2063. //
  2064. // Copy sysprep.exe to the sysprep dir
  2065. //
  2066. ConcatenatePaths( szSysprepPathandFileNameSrc,
  2067. szCurrentDirectory,
  2068. SYSPREP_EXE,
  2069. NULL );
  2070. ConcatenatePaths( szSysprepPathandFileNameDest,
  2071. szSysprepPath,
  2072. SYSPREP_EXE,
  2073. NULL );
  2074. CopySysprepFileLow( hwnd,
  2075. szSysprepPathandFileNameSrc,
  2076. szSysprepPathandFileNameDest,
  2077. szSysprepPath,
  2078. szCurrentDirectory,
  2079. SYSPREP_EXE );
  2080. //
  2081. // Store the path where the 1st file was found
  2082. //
  2083. GetPathFromPathAndFilename( szSysprepPathandFileNameSrc,
  2084. szCurrentDirectory,
  2085. AS(szCurrentDirectory));
  2086. //
  2087. // Copy setupcl.exe to the sysprep dir
  2088. //
  2089. szSysprepPathandFileNameSrc[0] = _T('\0');
  2090. szSysprepPathandFileNameDest[0] = _T('\0');
  2091. ConcatenatePaths( szSysprepPathandFileNameSrc,
  2092. szCurrentDirectory,
  2093. SETUPCL_EXE,
  2094. NULL );
  2095. ConcatenatePaths( szSysprepPathandFileNameDest,
  2096. szSysprepPath,
  2097. SETUPCL_EXE,
  2098. NULL );
  2099. CopySysprepFileLow( hwnd,
  2100. szSysprepPathandFileNameSrc,
  2101. szSysprepPathandFileNameDest,
  2102. szSysprepPath,
  2103. szCurrentDirectory,
  2104. SETUPCL_EXE );
  2105. }
  2106. //----------------------------------------------------------------------------
  2107. //
  2108. // Function: CopyAllFilesInDir
  2109. //
  2110. // Purpose:
  2111. //
  2112. // Arguments: HWND hwnd - handle to the dialog box
  2113. // TCHAR *szSrcDir - dir of all the files to copy
  2114. // TCHAR *szDestDir - dest where the files are to be copied to
  2115. //
  2116. // Returns: BOOL
  2117. // TRUE - if all the files in the dir were successfully copied
  2118. // FALSE - if there were errors during the copy
  2119. //
  2120. //----------------------------------------------------------------------------
  2121. static BOOL
  2122. CopyAllFilesInDir( IN HWND hwnd, IN TCHAR *szSrcDir, IN TCHAR *szDestDir )
  2123. {
  2124. HANDLE FindHandle;
  2125. WIN32_FIND_DATA FindData;
  2126. TCHAR szSrcRootPath[MAX_PATH];
  2127. TCHAR szDestRootPath[MAX_PATH];
  2128. TCHAR szDirectoryWithTheFiles[MAX_PATH] = _T("");
  2129. lstrcpyn( szDirectoryWithTheFiles, szSrcDir, AS(szDirectoryWithTheFiles) );
  2130. lstrcatn( szDirectoryWithTheFiles, _T("\\*"), MAX_PATH );
  2131. FindHandle = FindFirstFile( szDirectoryWithTheFiles, &FindData );
  2132. // ISSUE-2002/02/28-stelo- on the returns should I signal an error?
  2133. // ISSUE-2002/02/28-stelo- test to make sure this will copy a subdirectory if one exists
  2134. if ( FindHandle == INVALID_HANDLE_VALUE )
  2135. return( FALSE );
  2136. do {
  2137. szSrcRootPath[0] = _T('\0');
  2138. szDestRootPath[0] = _T('\0');
  2139. if( lstrcmp( FindData.cFileName, _T(".") ) == 0 ||
  2140. lstrcmp( FindData.cFileName, _T("..") ) == 0 )
  2141. continue;
  2142. if( ! ( FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) ) {
  2143. BOOL test;
  2144. ConcatenatePaths( szSrcRootPath,
  2145. szSrcDir,
  2146. FindData.cFileName,
  2147. NULL );
  2148. ConcatenatePaths( szDestRootPath,
  2149. szDestDir,
  2150. FindData.cFileName,
  2151. NULL );
  2152. CopyFile( szSrcRootPath, szDestRootPath, FALSE );
  2153. SetFileAttributes( szDestRootPath, FILE_ATTRIBUTE_NORMAL );
  2154. } else {
  2155. //
  2156. // Create the dir and recurse
  2157. //
  2158. if ( ! EnsureDirExists( szDestDir ) ) {
  2159. UINT iRet;
  2160. iRet = ReportErrorId( hwnd,
  2161. MSGTYPE_RETRYCANCEL | MSGTYPE_WIN32,
  2162. IDS_ERR_CREATE_FOLDER,
  2163. szDestDir );
  2164. return( FALSE );
  2165. }
  2166. if ( ! CopyAllFilesInDir( hwnd, szSrcRootPath, szDestDir ) ) {
  2167. return( FALSE );
  2168. }
  2169. }
  2170. } while ( FindNextFile( FindHandle, &FindData ) );
  2171. return( TRUE );
  2172. }
  2173. //----------------------------------------------------------------------------
  2174. //
  2175. // Function: FindFileInWindowsSourceFiles
  2176. //
  2177. // Purpose: To look through the windows source files for a particular file.
  2178. //
  2179. // Arguments: IN HWND hwnd - handle to the dialog box
  2180. // IN TCHAR *pszFile - the file to search for
  2181. // IN TCHAR *pszSourcePath - path to the Windows source files
  2182. // OUT TCHAR *pszFoundPath - path to the found file, if found
  2183. //
  2184. // pszFoundPath is assumed to be able to hold a string of MAX_PATH chars
  2185. //
  2186. // Returns: BOOL - TRUE if the file is found, FALSE if not
  2187. //
  2188. //----------------------------------------------------------------------------
  2189. static BOOL
  2190. FindFileInWindowsSourceFiles( IN HWND hwnd,
  2191. IN TCHAR *pszFile,
  2192. IN TCHAR *pszSourcePath,
  2193. OUT TCHAR *pszFoundPath )
  2194. {
  2195. HANDLE FindHandle;
  2196. WIN32_FIND_DATA FindData;
  2197. TCHAR szOriginalPath[MAX_PATH + 1];
  2198. TCHAR szPossiblePath[MAX_PATH + 1] = _T("");
  2199. TCHAR szPossiblePathAndFileName[MAX_PATH + 1] = _T("");
  2200. ConcatenatePaths( szPossiblePathAndFileName,
  2201. pszSourcePath,
  2202. pszFile,
  2203. NULL );
  2204. if( DoesFileExist( szPossiblePathAndFileName ) )
  2205. {
  2206. lstrcpyn( pszFoundPath, pszSourcePath, MAX_PATH );
  2207. return( TRUE );
  2208. }
  2209. //
  2210. // Look through the sub-directories for it
  2211. //
  2212. //
  2213. // Save the original path so it can be restored later
  2214. //
  2215. lstrcpyn( szOriginalPath, pszSourcePath, AS(szOriginalPath) );
  2216. //
  2217. // Look for * in this dir
  2218. //
  2219. if ( ! ConcatenatePaths( pszSourcePath, _T("*"), NULL ) )
  2220. {
  2221. //
  2222. // Restore the original path before returning
  2223. //
  2224. lstrcpyn( pszSourcePath, szOriginalPath, MAX_PATH );
  2225. return( FALSE );
  2226. }
  2227. FindHandle = FindFirstFile( pszSourcePath, &FindData );
  2228. if( FindHandle == INVALID_HANDLE_VALUE )
  2229. {
  2230. return( FALSE );
  2231. }
  2232. do {
  2233. //
  2234. // skip over the . and .. entries
  2235. //
  2236. if (0 == lstrcmp(FindData.cFileName, _T(".")) ||
  2237. 0 == lstrcmp(FindData.cFileName, _T("..")))
  2238. {
  2239. continue;
  2240. }
  2241. //
  2242. // If this is a dirent, recurse.
  2243. //
  2244. if ( FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
  2245. {
  2246. BOOL bFoundStatus;
  2247. pszSourcePath[0] = _T('\0');
  2248. if ( ! ConcatenatePaths( pszSourcePath, szOriginalPath, FindData.cFileName, NULL ) )
  2249. continue;
  2250. bFoundStatus = FindFileInWindowsSourceFiles( hwnd,
  2251. pszFile,
  2252. pszSourcePath,
  2253. pszFoundPath );
  2254. if( bFoundStatus )
  2255. {
  2256. return( TRUE );
  2257. }
  2258. }
  2259. } while( FindNextFile( FindHandle, &FindData ) );
  2260. FindClose( FindHandle );
  2261. //
  2262. // Restore the original path
  2263. //
  2264. lstrcpyn( pszSourcePath, szOriginalPath, MAX_PATH );
  2265. lstrcpyn( pszFoundPath, _T(""), MAX_PATH );
  2266. return( FALSE );
  2267. }
  2268. //----------------------------------------------------------------------------
  2269. //
  2270. // Function: CabinetCallback
  2271. //
  2272. // Purpose:
  2273. //
  2274. // Arguments:
  2275. //
  2276. // Returns: LRESULT
  2277. //
  2278. //----------------------------------------------------------------------------
  2279. UINT WINAPI
  2280. CabinetCallback( IN PVOID pMyInstallData,
  2281. IN UINT Notification,
  2282. IN UINT_PTR Param1,
  2283. IN UINT_PTR Param2 )
  2284. {
  2285. UINT lRetVal = NO_ERROR;
  2286. FILE_IN_CABINET_INFO *pInfo = NULL;
  2287. switch( Notification )
  2288. {
  2289. case SPFILENOTIFY_FILEINCABINET:
  2290. pInfo = (FILE_IN_CABINET_INFO *) Param1;
  2291. lstrcpyn( pInfo->FullTargetName, szDestinationPath, AS(pInfo->FullTargetName) );
  2292. if( lstrcmpi( szFileSearchingFor, pInfo->NameInCabinet) == 0 )
  2293. {
  2294. lRetVal = FILEOP_DOIT; // Extract the file.
  2295. bFileCopiedFromCab = TRUE;
  2296. }
  2297. else
  2298. {
  2299. lRetVal = FILEOP_SKIP;
  2300. }
  2301. break;
  2302. default:
  2303. lRetVal = NO_ERROR;
  2304. break;
  2305. }
  2306. return( lRetVal );
  2307. }
  2308. //----------------------------------------------------------------------------
  2309. //
  2310. // Function: CopyFromDriverCab
  2311. //
  2312. // Purpose:
  2313. //
  2314. // Arguments:
  2315. //
  2316. // Returns: BOOL
  2317. //
  2318. //----------------------------------------------------------------------------
  2319. static BOOL
  2320. CopyFromDriverCab( TCHAR *pszCabPathAndFileName, TCHAR* pszFileName, TCHAR* pszDest )
  2321. {
  2322. lstrcpyn( szFileSearchingFor, pszFileName, AS(szFileSearchingFor) );
  2323. lstrcpyn( szDestinationPath, pszDest, AS(szDestinationPath) );
  2324. if( ! SetupIterateCabinet( pszCabPathAndFileName, 0, CabinetCallback, 0 ) )
  2325. {
  2326. return( FALSE );
  2327. }
  2328. //
  2329. // See if the file was actually found and copied.
  2330. //
  2331. if( bFileCopiedFromCab )
  2332. {
  2333. bFileCopiedFromCab = FALSE;
  2334. return( TRUE );
  2335. }
  2336. else
  2337. {
  2338. return( FALSE );
  2339. }
  2340. }
  2341. //----------------------------------------------------------------------------
  2342. //
  2343. // Function: AddCompressedFileUnderscore
  2344. //
  2345. // Purpose: Given a filename it converts it to its compressed name.
  2346. //
  2347. // Arguments:
  2348. // IN OUT TCHAR *pszFileName - the file name to change into its
  2349. // compressed file name
  2350. //
  2351. // Returns: VOID
  2352. //
  2353. //----------------------------------------------------------------------------
  2354. static VOID
  2355. AddCompressedFileUnderscore( IN OUT TCHAR *pszFileName )
  2356. {
  2357. TCHAR *pCurrentChar;
  2358. pCurrentChar = pszFileName;
  2359. while( *pCurrentChar != _T('\0') && *pCurrentChar != _T('.') )
  2360. {
  2361. pCurrentChar++;
  2362. }
  2363. if( *pCurrentChar == _T('\0') )
  2364. {
  2365. AssertMsg( FALSE,
  2366. "Filename does not contain a period(.)." );
  2367. }
  2368. else
  2369. {
  2370. pCurrentChar = pCurrentChar + 3;
  2371. *pCurrentChar = _T('_');
  2372. *(pCurrentChar + 1) = _T('\0');
  2373. }
  2374. }
  2375. //----------------------------------------------------------------------------
  2376. //
  2377. // Function: CopyAdditionalLangFiles
  2378. //
  2379. // Purpose: Copies the additional lang files that are specified in the
  2380. // intl.inf for the language groups being installed.
  2381. //
  2382. // Arguments: IN HWND hwnd - handle to the dialog box
  2383. // IN TCHAR *pszSourcePath - source path - must be at least size MAX_PATH
  2384. //
  2385. // Returns: VOID
  2386. //
  2387. //----------------------------------------------------------------------------
  2388. static VOID
  2389. CopyAdditionalLangFiles( IN HWND hwnd, IN TCHAR *pszSourcePath )
  2390. {
  2391. INT i;
  2392. INT j;
  2393. INT nEntries;
  2394. TCHAR *pszLangGroup;
  2395. INT nLangGroup;
  2396. INT nNumFilesToCopy;
  2397. TCHAR szOriginalPath[MAX_PATH + 1];
  2398. TCHAR szLangBaseDir[MAX_PATH + 1] = _T("");
  2399. TCHAR szSrc[MAX_PATH + 1] = _T("");
  2400. TCHAR szDest[MAX_PATH + 1] = _T("");
  2401. TCHAR *pFileName;
  2402. BOOL bFoundFile;
  2403. //
  2404. // Save the original path so it can be restored later
  2405. //
  2406. lstrcpyn( szOriginalPath, pszSourcePath, AS(szOriginalPath) );
  2407. MakeLangFilesName( szLangBaseDir );
  2408. if( ! EnsureDirExists( szLangBaseDir ) )
  2409. {
  2410. // ISSUE-2002/02/28-stelo- report an error
  2411. }
  2412. nEntries = GetNameListSize( &GenSettings.LanguageGroups );
  2413. for( i = 0; i < nEntries; i++ )
  2414. {
  2415. pszLangGroup = GetNameListName( &GenSettings.LanguageGroups, i );
  2416. nLangGroup = _ttoi( pszLangGroup );
  2417. nNumFilesToCopy = GetNameListSize( &FixedGlobals.LangGroupAdditionalFiles[ nLangGroup - 1 ] );
  2418. AssertMsg( nNumFilesToCopy >= 0,
  2419. "Bad value for the number of lang files to copy." );
  2420. for( j = 0; j < nNumFilesToCopy; j++ )
  2421. {
  2422. szSrc[0] = _T('\0');
  2423. szDest[0] = _T('\0');
  2424. //
  2425. // Restore the original path as it might have changed on the last iteration
  2426. //
  2427. lstrcpyn( pszSourcePath, szOriginalPath, MAX_PATH );
  2428. pFileName = GetNameListName( &FixedGlobals.LangGroupAdditionalFiles[ nLangGroup - 1 ], j );
  2429. ConcatenatePaths( szDest,
  2430. szLangBaseDir,
  2431. pFileName,
  2432. NULL );
  2433. bFoundFile = FindFileInWindowsSourceFiles( hwnd,
  2434. pFileName,
  2435. pszSourcePath,
  2436. szSrc );
  2437. ConcatenatePaths( szSrc, pFileName, NULL );
  2438. if( ! bFoundFile )
  2439. {
  2440. TCHAR szFileName[MAX_PATH + 1];
  2441. //
  2442. // If the file doesn't exist, look for the compressed form
  2443. //
  2444. lstrcpyn( szFileName, pFileName, AS(szFileName) );
  2445. AddCompressedFileUnderscore( szFileName );
  2446. bFoundFile = FindFileInWindowsSourceFiles( hwnd,
  2447. szFileName,
  2448. pszSourcePath,
  2449. szSrc );
  2450. if( bFoundFile )
  2451. {
  2452. TCHAR *pszFileName;
  2453. ConcatenatePaths( szSrc, szFileName, NULL );
  2454. pszFileName = MyGetFullPath( szDest );
  2455. AddCompressedFileUnderscore( pszFileName );
  2456. }
  2457. else
  2458. {
  2459. TCHAR szCabPathAndFileName[MAX_PATH + 1] = _T("");
  2460. ConcatenatePaths( szCabPathAndFileName,
  2461. pszSourcePath,
  2462. _T("driver.cab"),
  2463. NULL );
  2464. if( ! CopyFromDriverCab( szCabPathAndFileName, pFileName, szDest ) )
  2465. {
  2466. //
  2467. // If the compressed form isn't found either, print an error
  2468. // message and move on to the next file
  2469. //
  2470. ConcatenatePaths( szSrc,
  2471. pszSourcePath,
  2472. pFileName,
  2473. NULL );
  2474. ReportErrorId( hwnd,
  2475. MSGTYPE_ERR,
  2476. IDS_ERR_CANNOT_FIND_LANG_FILE,
  2477. szSrc );
  2478. }
  2479. continue;
  2480. }
  2481. }
  2482. CopyFile( szSrc, szDest, FALSE );
  2483. SetFileAttributes( szDest, FILE_ATTRIBUTE_NORMAL );
  2484. }
  2485. }
  2486. //
  2487. // Restore the original path
  2488. //
  2489. lstrcpyn( pszSourcePath, szOriginalPath, MAX_PATH );
  2490. }
  2491. //----------------------------------------------------------------------------
  2492. //
  2493. // Function: CopyLanguageFiles
  2494. //
  2495. // Purpose:
  2496. //
  2497. // Arguments: IN HWND hwnd - handle to the dialog box
  2498. //
  2499. // Returns: BOOL - TRUE if a path was specified to the Windows Setup files
  2500. // FALSE if not path was specifed, the user canceled the dialog
  2501. //
  2502. //----------------------------------------------------------------------------
  2503. static BOOL
  2504. CopyLanguageFiles( IN HWND hwnd )
  2505. {
  2506. INT iLangCount;
  2507. INT iNumLangsToInstall;
  2508. INT iCurrentLang = 0;
  2509. BOOL bCopySuccessful;
  2510. TCHAR *pszLangPartialPath;
  2511. TCHAR PathBuffer[MAX_PATH + 1];
  2512. TCHAR WindowsSetupPath[MAX_PATH + 1];
  2513. TCHAR szLangBaseDir[MAX_PATH + 1] = _T("");
  2514. TCHAR szLangPathAndFilesSrc[MAX_PATH + 1] = _T("");
  2515. TCHAR szLangPathAndFilesDest[MAX_PATH + 1] = _T("");
  2516. MakeLangFilesName( szLangBaseDir );
  2517. // ISSUE-2002/02/28-stelo- what if they copied they lang files by hand, then I don't
  2518. // want any pop-ups here
  2519. iNumLangsToInstall = GetNameListSize( &GenSettings.LanguageGroups );
  2520. //
  2521. // See if they are any lang files to copy
  2522. //
  2523. if( iNumLangsToInstall == 0 )
  2524. {
  2525. return( TRUE );
  2526. }
  2527. if( ! EnsureDirExists( szLangBaseDir ) )
  2528. {
  2529. // ISSUE-2002-02-28-stelo- report an error
  2530. }
  2531. do
  2532. {
  2533. BOOL bUserProvidedPath;
  2534. PathBuffer[0] = _T('\0');
  2535. WindowsSetupPath[0] = _T('\0');
  2536. ReportErrorId( hwnd,
  2537. MSGTYPE_ERR,
  2538. IDS_ERR_SPECIFY_LANG_PATH );
  2539. bUserProvidedPath = BrowseForSourceDir( hwnd, PathBuffer );
  2540. if( ! bUserProvidedPath )
  2541. {
  2542. return( FALSE );
  2543. }
  2544. ConcatenatePaths( WindowsSetupPath,
  2545. PathBuffer,
  2546. DOSNET_INF,
  2547. NULL );
  2548. } while( ! DoesFileExist( WindowsSetupPath ) );
  2549. //
  2550. // Copy the language files needed but that are not in each language groups sub-dir
  2551. //
  2552. CopyAdditionalLangFiles( hwnd, PathBuffer );
  2553. iLangCount = GetNameListSize( &GenSettings.LanguageFilePaths );
  2554. //
  2555. // Advance until we find a language that we need to copy files over for or
  2556. // we run out of languages
  2557. //
  2558. for( iCurrentLang = 0;
  2559. iCurrentLang < iLangCount;
  2560. iCurrentLang++ )
  2561. {
  2562. pszLangPartialPath = GetNameListName( &GenSettings.LanguageFilePaths,
  2563. iCurrentLang );
  2564. //
  2565. // If there is actually a lang sub-dir to copy
  2566. //
  2567. if( lstrcmp( pszLangPartialPath, _T("") ) != 0 )
  2568. {
  2569. szLangPathAndFilesSrc[0] = _T('\0');
  2570. szLangPathAndFilesDest[0] = _T('\0');
  2571. ConcatenatePaths( szLangPathAndFilesSrc,
  2572. PathBuffer,
  2573. pszLangPartialPath,
  2574. NULL );
  2575. ConcatenatePaths( szLangPathAndFilesDest,
  2576. szLangBaseDir,
  2577. pszLangPartialPath,
  2578. NULL );
  2579. //
  2580. // Copy the lang files over
  2581. //
  2582. EnsureDirExists( szLangPathAndFilesDest );
  2583. bCopySuccessful = CopyAllFilesInDir( hwnd,
  2584. szLangPathAndFilesSrc,
  2585. szLangPathAndFilesDest );
  2586. if( ! bCopySuccessful )
  2587. {
  2588. ReportErrorId( hwnd,
  2589. MSGTYPE_ERR,
  2590. IDS_ERR_UNABLE_TO_COPY_LANG_DIR,
  2591. szLangPathAndFilesSrc,
  2592. szLangPathAndFilesDest );
  2593. }
  2594. }
  2595. }
  2596. return( TRUE );
  2597. }
  2598. //----------------------------------------------------------------------------
  2599. //
  2600. // This section of code supports the WIZ_NEXT event
  2601. //
  2602. //----------------------------------------------------------------------------
  2603. //----------------------------------------------------------------------------
  2604. //
  2605. // Function: ComputePnpDriverPathR
  2606. //
  2607. // Purpose: This is support to compute OemPnpDriversPath. Every dir in
  2608. // $oem$\$1\drivers that we find a .inf file in, we add it to the
  2609. // OemPnPDriversPath.
  2610. //
  2611. // ComputePnpDriverPath() is the real entry, not this one.
  2612. //
  2613. //----------------------------------------------------------------------------
  2614. VOID ComputePnpDriverPathR(HWND hwnd, LPTSTR lpRoot)
  2615. {
  2616. LPTSTR lpRootEnd = lpRoot + lstrlen(lpRoot);
  2617. HANDLE FindHandle;
  2618. WIN32_FIND_DATA FindData;
  2619. BOOL bAddToSearchPath = FALSE;
  2620. HRESULT hrCat;
  2621. //
  2622. // loop over lpRoot\*
  2623. //
  2624. if ( ! ConcatenatePaths(lpRoot, _T("*"), NULL) )
  2625. return;
  2626. FindHandle = FindFirstFile(lpRoot, &FindData);
  2627. if ( FindHandle == INVALID_HANDLE_VALUE )
  2628. return;
  2629. //
  2630. // If it is a sysprep
  2631. //
  2632. if( WizGlobals.iProductInstall == PRODUCT_SYSPREP ) {
  2633. }
  2634. do {
  2635. *lpRootEnd = _T('\0');
  2636. //
  2637. // skip over the . and .. entries
  2638. //
  2639. if (0 == lstrcmp(FindData.cFileName, _T(".")) ||
  2640. 0 == lstrcmp(FindData.cFileName, _T("..")))
  2641. continue;
  2642. //
  2643. // Build the new path name
  2644. //
  2645. if ( ! ConcatenatePaths(lpRoot, FindData.cFileName, NULL) )
  2646. continue;
  2647. //
  2648. // If we have a .inf file, mark this directory to be included
  2649. // in the search path.
  2650. //
  2651. {
  2652. int len = lstrlen(FindData.cFileName);
  2653. if ( ( len > 4 ) &&
  2654. ( LSTRCMPI( &FindData.cFileName[len - 4], _T(".inf") ) == 0 ) )
  2655. {
  2656. bAddToSearchPath = TRUE;
  2657. }
  2658. }
  2659. //
  2660. // If a dirent, recurse.
  2661. //
  2662. if ( FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
  2663. ComputePnpDriverPathR(hwnd, lpRoot);
  2664. }
  2665. } while ( FindNextFile(FindHandle, &FindData) );
  2666. *lpRootEnd = _T('\0');
  2667. FindClose(FindHandle);
  2668. //
  2669. // If we found a .inf in this dir, add it to the PnpDriver search path
  2670. //
  2671. // Note, we don't want c:\win2000dist\$oem$\$1\drivers\foo. We only want
  2672. // part of it. We want \drivers\foo. So jump past the SysDrive portion.
  2673. //
  2674. // Note that this code assumes that \drivers is a sub-dir of the SysDir.
  2675. //
  2676. if ( bAddToSearchPath ) {
  2677. TCHAR Buffer[MAX_PATH];
  2678. int len;
  2679. if ( WizGlobals.OemPnpDriversPath[0] != _T('\0') )
  2680. hrCat=StringCchCat(WizGlobals.OemPnpDriversPath, AS(WizGlobals.OemPnpDriversPath), _T(";"));
  2681. MakeSysDriveName(Buffer);
  2682. len = lstrlen(Buffer);
  2683. hrCat=StringCchCat(WizGlobals.OemPnpDriversPath,AS(WizGlobals.OemPnpDriversPath), lpRoot + len);
  2684. }
  2685. }
  2686. //----------------------------------------------------------------------------
  2687. //
  2688. // Function: ComputeSysprepPnpPath
  2689. //
  2690. // Purpose: Determines the path to the sysprep PnP drivers.
  2691. //
  2692. // The path will always be %systemdrive%\drivers so all we have to do is
  2693. // check to see if there are any files there. If there are set the path, if
  2694. // not, then do not set the path.
  2695. //
  2696. //----------------------------------------------------------------------------
  2697. VOID
  2698. ComputeSysprepPnpPath( TCHAR* Buffer )
  2699. {
  2700. HANDLE FindHandle;
  2701. WIN32_FIND_DATA FindData;
  2702. INT iFileCount = 0;
  2703. TCHAR szDriverFiles[MAX_PATH] = _T("");
  2704. if ( ! ConcatenatePaths(szDriverFiles, Buffer, _T("*"), NULL) )
  2705. return;
  2706. FindHandle = FindFirstFile(szDriverFiles, &FindData);
  2707. if( FindHandle == INVALID_HANDLE_VALUE )
  2708. {
  2709. return;
  2710. }
  2711. do
  2712. {
  2713. iFileCount++;
  2714. } while( FindNextFile( FindHandle, &FindData ) && iFileCount < 3 );
  2715. //
  2716. // every directory contains 2 files, "." and "..", so we have to check
  2717. // for 3 or more to determine if there are any real files there.
  2718. //
  2719. if( iFileCount >= 3)
  2720. {
  2721. lstrcpyn( WizGlobals.OemPnpDriversPath, Buffer, AS(WizGlobals.OemPnpDriversPath) );
  2722. }
  2723. }
  2724. //----------------------------------------------------------------------------
  2725. //
  2726. // Function: ComputePnpDriverPath
  2727. //
  2728. // Purpose: When user hits the NEXT button, we compute the OemPnpDriversPath
  2729. // based on what we find in $oem$\$1\drivers.
  2730. //
  2731. // Every sub-dir that has a .inf in it, gets put on the path.
  2732. //
  2733. //----------------------------------------------------------------------------
  2734. VOID ComputePnpDriverPath(HWND hwnd)
  2735. {
  2736. TCHAR Buffer[MAX_PATH] = NULLSTR;
  2737. WizGlobals.OemPnpDriversPath[0] = _T('\0');
  2738. MakePnpDriversName(Buffer);
  2739. //
  2740. // If it is a sysprep, then we know the drivers are in %systemdrive%\drivers.
  2741. // Just check to see if there are any files there.
  2742. // If it is not a sysprep, then we need to cat together the paths to the
  2743. // driver directories.
  2744. //
  2745. if( WizGlobals.iProductInstall == PRODUCT_SYSPREP )
  2746. {
  2747. ComputeSysprepPnpPath( Buffer );
  2748. }
  2749. else
  2750. {
  2751. ComputePnpDriverPathR(hwnd, Buffer);
  2752. }
  2753. }
  2754. //----------------------------------------------------------------------------
  2755. //
  2756. // Function: OnWizNextAddDirs
  2757. //
  2758. // Purpose:
  2759. //
  2760. // Arguments: IN HWND hwnd - handle to the dialog box
  2761. //
  2762. // Returns: VOID
  2763. //
  2764. //----------------------------------------------------------------------------
  2765. BOOL
  2766. OnWizNextAddDirs( IN HWND hwnd )
  2767. {
  2768. BOOL bUserCanceled = TRUE;
  2769. ComputePnpDriverPath(hwnd);
  2770. //
  2771. // If it is a sysprep, make sure the sysprep directory exists
  2772. // and the appropriate files are copied
  2773. //
  2774. if( WizGlobals.iProductInstall == PRODUCT_SYSPREP )
  2775. {
  2776. TCHAR szBuffer[MAX_PATH + 1] = _T("");
  2777. //
  2778. // Make the necessary sysprep directories
  2779. //
  2780. MakeLangFilesName( szBuffer );
  2781. if ( szBuffer[0] )
  2782. {
  2783. CreateDirectory( szBuffer, NULL );
  2784. MakePnpDriversName( szBuffer );
  2785. CreateDirectory( szBuffer, NULL );
  2786. CopySysprepFiles( hwnd );
  2787. bUserCanceled = CopyLanguageFiles( hwnd );
  2788. }
  2789. }
  2790. //
  2791. // See if we need to copy the IE Branding file and if we do then copy it.
  2792. //
  2793. if( ( GenSettings.IeCustomizeMethod == IE_USE_BRANDING_FILE ) &&
  2794. ( GenSettings.szInsFile[0] != _T('\0') ) )
  2795. {
  2796. if( DoesFileExist( GenSettings.szInsFile ) )
  2797. {
  2798. TCHAR szDestPathAndFileName[MAX_PATH + 1] = _T("");
  2799. TCHAR *pszFileName = NULL;
  2800. pszFileName = MyGetFullPath( GenSettings.szInsFile );
  2801. ConcatenatePaths( szDestPathAndFileName,
  2802. WizGlobals.OemFilesPath,
  2803. pszFileName,
  2804. NULL );
  2805. CopyFile( GenSettings.szInsFile, szDestPathAndFileName, FALSE );
  2806. }
  2807. else
  2808. {
  2809. ReportErrorId( hwnd,
  2810. MSGTYPE_ERR,
  2811. IDS_ERR_INS_FILE_NO_COPY,
  2812. WizGlobals.OemFilesPath );
  2813. }
  2814. }
  2815. else
  2816. {
  2817. }
  2818. //
  2819. // Route the wizard
  2820. //
  2821. return (!bUserCanceled);
  2822. }
  2823. //----------------------------------------------------------------------------
  2824. //
  2825. // This section of code is the skeleton of a dialog procedure for
  2826. // this page.
  2827. //
  2828. //----------------------------------------------------------------------------
  2829. //----------------------------------------------------------------------------
  2830. //
  2831. // Function: DlgAdditionalDirsPage
  2832. //
  2833. // Purpose: This is the dialog procedure the additional dirs page
  2834. //
  2835. //----------------------------------------------------------------------------
  2836. INT_PTR CALLBACK DlgAdditionalDirsPage(
  2837. IN HWND hwnd,
  2838. IN UINT uMsg,
  2839. IN WPARAM wParam,
  2840. IN LPARAM lParam)
  2841. {
  2842. BOOL bStatus = TRUE;
  2843. switch (uMsg) {
  2844. case WM_INITDIALOG:
  2845. OnInitAddDirs(hwnd);
  2846. break;
  2847. case WM_COMMAND:
  2848. {
  2849. int nButtonId;
  2850. switch ( nButtonId = LOWORD(wParam) ) {
  2851. case IDC_ADDFILE:
  2852. if ( HIWORD(wParam) == BN_CLICKED )
  2853. OnAddFileDir(hwnd);
  2854. break;
  2855. case IDC_REMOVEFILE:
  2856. if ( HIWORD(wParam) == BN_CLICKED )
  2857. OnRemoveFileDir(hwnd);
  2858. break;
  2859. default:
  2860. bStatus = FALSE;
  2861. break;
  2862. }
  2863. }
  2864. break;
  2865. case WM_NOTIFY:
  2866. {
  2867. LPNMHDR pnmh = (LPNMHDR) lParam;
  2868. LPNMTREEVIEW pnmtv = (LPNMTREEVIEW) lParam;
  2869. LPNMTVDISPINFO pnmdisp = (LPNMTVDISPINFO) lParam;
  2870. LPNMTVKEYDOWN pnmkey = (LPNMTVKEYDOWN) lParam;
  2871. if ( pnmh->idFrom == IDC_FILETREE ) {
  2872. switch( pnmh->code ) {
  2873. case TVN_SELCHANGED:
  2874. OnTreeViewSelectionChange(hwnd);
  2875. break;
  2876. default:
  2877. bStatus = FALSE;
  2878. break;
  2879. }
  2880. }
  2881. else {
  2882. switch( pnmh->code ) {
  2883. case PSN_QUERYCANCEL:
  2884. CancelTheWizard(hwnd);
  2885. break;
  2886. case PSN_SETACTIVE:
  2887. OnSetActiveAddDirs( hwnd );
  2888. PropSheet_SetWizButtons(GetParent(hwnd),
  2889. PSWIZB_BACK | PSWIZB_NEXT);
  2890. break;
  2891. case PSN_WIZBACK:
  2892. break;
  2893. case PSN_WIZNEXT:
  2894. if ( !OnWizNextAddDirs( hwnd ) )
  2895. WIZ_FAIL(hwnd);
  2896. break;
  2897. default:
  2898. bStatus = FALSE;
  2899. break;
  2900. }
  2901. }
  2902. }
  2903. break;
  2904. default:
  2905. bStatus = FALSE;
  2906. break;
  2907. }
  2908. return bStatus;
  2909. }