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.

1136 lines
39 KiB

  1. /****************************************************************************\
  2. SKU.C / OPK Wizard (OPKWIZ.EXE)
  3. Microsoft Confidential
  4. Copyright (c) Microsoft Corporation 1998
  5. All rights reserved
  6. Source file for the OPK Wizard that contains the external and internal
  7. functions used by the "Target SKU" wizard page.
  8. 10/00 - Jason Cohen (JCOHEN)
  9. Added this new source file for the OPK Wizard. It includes the new
  10. ability to deploy mulitple product skus (per, pro, srv, ...) from one
  11. wizard.
  12. \****************************************************************************/
  13. //
  14. // Include File(s):
  15. //
  16. #include "pch.h"
  17. #include "sku.h"
  18. #include "wizard.h"
  19. #include "resource.h"
  20. //
  21. // Internal Global(s):
  22. //
  23. static STRRES s_srSkuDirs[] =
  24. {
  25. { DIR_SKU_PRO, IDS_SKU_PRO },
  26. { DIR_SKU_SRV, IDS_SKU_SRV },
  27. { DIR_SKU_ADV, IDS_SKU_ADV },
  28. { DIR_SKU_DTC, IDS_SKU_DTC },
  29. { DIR_SKU_PER, IDS_SKU_PER },
  30. { DIR_SKU_BLA, IDS_SKU_BLA },
  31. { DIR_SKU_SBS, IDS_SKU_SBS },
  32. };
  33. static STRRES s_srArchDirs[] =
  34. {
  35. { DIR_ARCH_X86, IDS_ARCH_X86 },
  36. { DIR_ARCH_IA64, IDS_ARCH_IA64 },
  37. };
  38. // This is used to map the product type in the inf to
  39. // the directory name we use. These MUST be in the
  40. // correct order.
  41. //
  42. static LPTSTR s_lpProductType[] =
  43. {
  44. DIR_SKU_PRO, // ProductType = 0
  45. DIR_SKU_SRV, // ProductType = 1
  46. DIR_SKU_ADV, // ProductType = 2
  47. DIR_SKU_DTC, // ProductType = 3
  48. DIR_SKU_PER, // ProductType = 4
  49. DIR_SKU_BLA, // ProductType = 5
  50. DIR_SKU_SBS, // ProductType = 6
  51. };
  52. static LPTSTR s_lpSourceDirs[] =
  53. {
  54. DIR_CD_IA64, // Must be before x86 because ia64 has both dirs.
  55. DIR_CD_X86, // Should always be last in the list.
  56. };
  57. static LPTSTR s_lpPlatformArchDir[] =
  58. {
  59. STR_PLATFORM_X86, DIR_ARCH_X86,
  60. STR_PLATFORM_IA64, DIR_ARCH_IA64,
  61. };
  62. static LPTSTR s_lpLocalIDs[] =
  63. {
  64. _T("00000401"), _T("ARA"),
  65. _T("00000404"), _T("CHT"),
  66. _T("00000804"), _T("CHS"),
  67. _T("00000409"), _T("ENG"),
  68. _T("00000407"), _T("GER"),
  69. _T("0000040D"), _T("HEB"),
  70. _T("00000411"), _T("JPN"),
  71. _T("00000412"), _T("KOR"),
  72. _T("00000416"), _T("BRZ"),
  73. _T("00000403"), _T("CAT"),
  74. _T("00000405"), _T("CZE"),
  75. _T("00000406"), _T("DAN"),
  76. _T("00000413"), _T("DUT"),
  77. _T("0000040B"), _T("FIN"),
  78. _T("0000040C"), _T("FRN"),
  79. _T("00000408"), _T("GRK"),
  80. _T("0000040E"), _T("HUN"),
  81. _T("00000410"), _T("ITN"),
  82. _T("00000414"), _T("NOR"),
  83. _T("00000415"), _T("POL"),
  84. _T("00000816"), _T("POR"),
  85. _T("00000419"), _T("RUS"),
  86. _T("00000C0A"), _T("SPA"),
  87. _T("0000041D"), _T("SWE"),
  88. _T("0000041F"), _T("TRK"),
  89. };
  90. //
  91. // Local Define(s):
  92. //
  93. #define FILE_INTL_INF _T("INTL.INF")
  94. #define INF_SEC_DEFAULT _T("DefaultValues")
  95. #define INF_VAL_LOCALE _T("Locale")
  96. //
  97. // Internal Function Prototype(s):
  98. //
  99. static BOOL OnInit(HWND hwnd, HWND hwndFocus, LPARAM lParam);
  100. static void OnCommand(HWND hwnd, INT id, HWND hwndCtl, UINT codeNotify);
  101. static BOOL OnNext(HWND hwnd);
  102. static void OnDestroy(HWND hwnd);
  103. static BOOL OnSetActive(HWND hwnd);
  104. static void EnumDirs(HWND hwndLB, LPTSTR lpSkuDir);
  105. static LPTSTR AllocateSPStrRes(HINSTANCE hInstance, LPSTRRES lpsrTable, DWORD cbTable, LPTSTR lpString, LPTSTR * lplpReturn, DWORD *lpdwSP);
  106. static INT AddSkuToList(HWND hwndLB, LPTSTR lpSkuDir, LPTSTR lpArchDir, LPTSTR lpReturn, DWORD cbReturn, DWORD dwSP);
  107. static BOOL StartCopy(HWND hwnd, HANDLE hEvent, LPCOPYDIRDATA lpcdd);
  108. DWORD WINAPI CopyDirectoryThread(LPVOID lpVoid);
  109. LRESULT CALLBACK SkuNameDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  110. //
  111. // External Function(s):
  112. //
  113. LRESULT CALLBACK SkuDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  114. {
  115. switch (uMsg)
  116. {
  117. HANDLE_MSG(hwnd, WM_INITDIALOG, OnInit);
  118. HANDLE_MSG(hwnd, WM_COMMAND, OnCommand);
  119. case WM_NOTIFY:
  120. switch ( ((NMHDR FAR *) lParam)->code )
  121. {
  122. case PSN_KILLACTIVE:
  123. case PSN_RESET:
  124. case PSN_WIZBACK:
  125. case PSN_WIZFINISH:
  126. break;
  127. case PSN_WIZNEXT:
  128. if ( !OnNext(hwnd) )
  129. WIZ_FAIL(hwnd);
  130. break;
  131. case PSN_QUERYCANCEL:
  132. WIZ_CANCEL(hwnd);
  133. break;
  134. case PSN_HELP:
  135. WIZ_HELP();
  136. break;
  137. case PSN_SETACTIVE:
  138. OnSetActive(hwnd);
  139. break;
  140. default:
  141. return FALSE;
  142. }
  143. break;
  144. case WM_DESTROY:
  145. OnDestroy(hwnd);
  146. return 0;
  147. default:
  148. return FALSE;
  149. }
  150. return TRUE;
  151. }
  152. void SetupSkuListBox(HWND hwndLB, LPTSTR lpLangDir)
  153. {
  154. TCHAR szPath[MAX_PATH];
  155. // Setup the path buffer to the config dir for the
  156. // tag files we might need to look for.
  157. //
  158. lstrcpyn(szPath, g_App.szLangDir,AS(szPath));
  159. AddPathN(szPath, lpLangDir,AS(szPath));
  160. AddPathN(szPath, DIR_SKU,AS(szPath));
  161. if ( SetCurrentDirectory(szPath) )
  162. EnumDirs(hwndLB, NULL);
  163. // If there are items in the list, make sure there is one selected.
  164. //
  165. if ( ( (INT) SendMessage(hwndLB, LB_GETCOUNT, 0, 0L) > 0 ) &&
  166. ( SendMessage(hwndLB, LB_GETCURSEL, 0, 0L) == LB_ERR ) )
  167. {
  168. SendMessage(hwndLB, LB_SETCURSEL, 0, 0L);
  169. }
  170. }
  171. void AddSku(HWND hwnd, HWND hwndLB, LPTSTR lpLangName)
  172. {
  173. BOOL bGoodSource = FALSE,
  174. bErrorDisplayed = FALSE;
  175. DWORD dwSearch;
  176. DWORD dwSP=0;
  177. // First find out where the sku is that they want to add.
  178. //
  179. while ( !bGoodSource && BrowseForFolder(hwnd, IDS_BROWSEFOLDER, g_App.szBrowseFolder, BIF_RETURNONLYFSDIRS | BIF_EDITBOX | BIF_VALIDATE) )
  180. {
  181. TCHAR szPath[MAX_PATH] = NULLSTR;
  182. LPTSTR lpEnd,
  183. lpEnd2;
  184. // Set to default value
  185. //
  186. bErrorDisplayed = FALSE;
  187. // Make our own copy of the path we got back.
  188. //
  189. lstrcpyn(szPath, g_App.szBrowseFolder, AS(szPath));
  190. // First check and see if we have the inf we need right here.
  191. //
  192. lpEnd = szPath + lstrlen(szPath);
  193. AddPathN(szPath, FILE_DOSNET_INF,AS(szPath));
  194. if ( !(bGoodSource = FileExists(szPath)) )
  195. {
  196. // Search for all the possible source directories that could be on the CD.
  197. //
  198. for ( dwSearch = 0; !bGoodSource && ( dwSearch < AS(s_lpSourceDirs) ); dwSearch++ )
  199. {
  200. // First test for the directory.
  201. //
  202. *lpEnd = NULLCHR;
  203. AddPathN(szPath, s_lpSourceDirs[dwSearch],AS(szPath));
  204. if ( DirectoryExists(szPath) )
  205. {
  206. // Also make sure that the inf file we need is there.
  207. //
  208. lpEnd2 = szPath + lstrlen(szPath);
  209. AddPathN(szPath, FILE_DOSNET_INF,AS(szPath));
  210. if ( bGoodSource = FileExists(szPath) )
  211. lpEnd = lpEnd2;
  212. }
  213. }
  214. }
  215. // Check to see if we have a matching language
  216. //
  217. if ( bGoodSource )
  218. {
  219. TCHAR szLangFile[MAX_PATH]= NULLSTR,
  220. szLang[MAX_PATH] = NULLSTR;
  221. // Check for the lang dir
  222. //
  223. lstrcpyn(szLangFile, szPath, (lstrlen(szPath) - lstrlen(lpEnd) + 1));
  224. AddPathN(szLangFile, FILE_INTL_INF,AS(szLangFile));
  225. // Check to see that the lang file contains a valid locale and that we recognize the locale
  226. //
  227. if ( GetPrivateProfileString(INF_SEC_DEFAULT, INF_VAL_LOCALE, NULLSTR, szLang, STRSIZE(szLang), szLangFile) && szLang[0] )
  228. {
  229. // Find the locale in our list
  230. //
  231. for ( dwSearch = 1; ( dwSearch < AS(s_lpLocalIDs) ) && ( lstrcmpi(s_lpLocalIDs[dwSearch - 1], szLang) != 0 ); dwSearch += 2 );
  232. // See if we found the item in our list and they match
  233. //
  234. if ( !(dwSearch < AS(s_lpLocalIDs)) ||
  235. (lstrcmpi(s_lpLocalIDs[dwSearch], lpLangName) != 0) )
  236. {
  237. // We are not in the list, let the user know that we can't add the language
  238. //
  239. MsgBox(GetParent(hwnd), IDS_ERR_BADSOURCELANG, IDS_APPNAME, MB_ERRORBOX);
  240. bGoodSource = FALSE;
  241. bErrorDisplayed = TRUE;
  242. }
  243. }
  244. else
  245. {
  246. // We were not able to get the locale string from the source files, this is not a valid source
  247. //
  248. bGoodSource = FALSE;
  249. }
  250. }
  251. // Only if we found the inf is this going to be a vaild location.
  252. //
  253. if ( bGoodSource )
  254. {
  255. TCHAR szInfFile[MAX_PATH],
  256. szSrcPath[MAX_PATH] = NULLSTR,
  257. szPlatform[256] = NULLSTR;
  258. DWORD dwProdType;
  259. TCHAR szSP[MAX_INFOLEN];
  260. // Reset this to false... we will set it to true if most everything works as planned.
  261. //
  262. bGoodSource = FALSE;
  263. // Copy our inf file into its own buffer.
  264. //
  265. lstrcpyn(szInfFile, szPath, AS(szInfFile));
  266. // Now we need to get the path to the root of our source (up one
  267. // from where we are now).
  268. //
  269. *lpEnd = NULLCHR;
  270. AddPathN(szPath, _T(".."),AS(szPath));
  271. // Make sure we have the full path and all the data out of the inf
  272. // we need.
  273. //
  274. if ( ( GetFullPathName(szPath, AS(szSrcPath), szSrcPath, &lpEnd) && szSrcPath[0] ) &&
  275. ( (dwProdType = GetPrivateProfileInt(INI_SEC_MISC, INI_KEY_PRODTYPE, 0xFFFFFFFF, szInfFile)) != 0xFFFFFFFF ) &&
  276. ( GetPrivateProfileString(INI_SEC_MISC, INI_KEY_PLATFORM, NULLSTR, szPlatform, STRSIZE(szPlatform), szInfFile) && szPlatform[0] ) )
  277. {
  278. // At this point we have done most of the checks to know for sure that
  279. // this is a good source location for a sku. By setting this we won't error
  280. // out on our exit.
  281. //
  282. bGoodSource = TRUE;
  283. // Convert the platform name we found in the inf to the arch name we use for
  284. // the directory.
  285. //
  286. for ( dwSearch = 1; ( dwSearch < AS(s_lpPlatformArchDir) ) && ( lstrcmpi(s_lpPlatformArchDir[dwSearch - 1], szPlatform) != 0 ); dwSearch += 2 );
  287. // Make sure we found it in our list. We must recognize the platform in order
  288. // to preinstall it.
  289. //
  290. if ( dwSearch < AS(s_lpPlatformArchDir) )
  291. {
  292. TCHAR szSkuName[64];
  293. LPTSTR lpSkuDir;
  294. // Make sure this is a known product type.
  295. //
  296. if ( dwProdType < AS(s_lpProductType) ) {
  297. // get the ServicePack number
  298. szSP[0]= NULLCHR;
  299. if ( GetPrivateProfileString(INI_SEC_MISC, INI_KEY_SERVICEPACK, NULLSTR, szSP, STRSIZE(szSP), szInfFile) && szSP[0] )
  300. dwSP= _wtol(szSP);
  301. lpSkuDir = s_lpProductType[dwProdType];
  302. }
  303. else
  304. {
  305. // Don't know the product type, we should ask them what to use
  306. // for the directory name.
  307. //
  308. *((LPDWORD) szSkuName) = AS(szSkuName);
  309. if ( DialogBoxParam(g_App.hInstance, MAKEINTRESOURCE(IDD_SKUNAME), hwnd, SkuNameDlgProc, (LPARAM) szSkuName) && szSkuName[0] )
  310. lpSkuDir = szSkuName;
  311. else
  312. lpSkuDir = NULL;
  313. }
  314. // Make sure we have the sku dir.
  315. //
  316. if ( lpSkuDir )
  317. {
  318. DWORD dwEndSkuLen,
  319. dwFileCount;
  320. TCHAR szDstPath[MAX_PATH],
  321. szDirKey[32];
  322. LPTSTR lpArchDir;
  323. HRESULT hrPrintf;
  324. TCHAR szSkuDir[32];
  325. // Create the path of the root destination directory we need.
  326. //
  327. lstrcpyn(szDstPath, g_App.szLangDir,AS(szDstPath));
  328. AddPathN(szDstPath, lpLangName,AS(szDstPath));
  329. AddPathN(szDstPath, DIR_SKU,AS(szDstPath));
  330. AddPathN(szDstPath, lpSkuDir,AS(szDstPath));
  331. dwEndSkuLen = (DWORD) lstrlen(szDstPath);
  332. // if this is a service pack, cat .spx to product name where x is the SP number
  333. // and make szSkuDir be the sku.xpx name
  334. lstrcpyn(szSkuDir, lpSkuDir,AS(szSkuDir));
  335. if (dwSP) {
  336. hrPrintf=StringCchPrintf(szDstPath+(DWORD)lstrlen(szDstPath), AS(szDstPath)-(DWORD)lstrlen(szDstPath), _T(".sp%d"), dwSP);
  337. hrPrintf=StringCchPrintf(szSkuDir+(DWORD)lstrlen(szSkuDir), AS(szSkuDir)-(DWORD)lstrlen(szSkuDir), _T(".sp%d"), dwSP);
  338. }
  339. // Finally add our arch name to the end.
  340. //
  341. lpArchDir = s_lpPlatformArchDir[dwSearch];
  342. AddPathN(szDstPath, lpArchDir,AS(szDstPath));
  343. // Make sure there is at least one source directory and file.
  344. //
  345. hrPrintf=StringCchPrintf(szDirKey, AS(szDirKey), INI_KEY_DIR, NUM_FIRST_SOURCE_DX);
  346. szPath[0] = NULLCHR;
  347. if ( ( GetPrivateProfileString(INI_SEC_DIRS, szDirKey, NULLSTR, szPath, STRSIZE(szPath), szInfFile) && szPath[0] ) &&
  348. ( dwFileCount = CopySkuFiles(NULL, NULL, szSrcPath, szDstPath, szInfFile) ) )
  349. {
  350. BOOL bExists;
  351. TCHAR szDisplayName[256];
  352. // Make sure we don't already have this SKU here.
  353. //
  354. if ( bExists = DirectoryExists(szDstPath) )
  355. AddSkuToList(NULL, szSkuDir, lpArchDir, szDisplayName, AS(szDisplayName), dwSP);
  356. if ( ( !bExists ) ||
  357. ( MsgBox(GetParent(hwnd), IDS_OVERWRITESKU, IDS_APPNAME, MB_YESNO | MB_DEFBUTTON2 | MB_ICONQUESTION, szDisplayName) == IDYES ) )
  358. {
  359. // Now we are ready to actually create our root destination directory.
  360. //
  361. COPYDIRDATA cdd;
  362. INT nItem;
  363. // May need to remove the sku files first if we are overwriting a SKU.
  364. //
  365. if ( bExists )
  366. DeletePath(szDstPath);
  367. // Put all our data in the structure so we can pass it on to the progress dialog.
  368. //
  369. lstrcpyn(cdd.szSrc, szSrcPath,AS(cdd.szSrc));
  370. lstrcpyn(cdd.szDst, szDstPath,AS(cdd.szDst));
  371. lstrcpyn(cdd.szInfFile, szInfFile,AS(cdd.szInfFile));
  372. cdd.lpszEndSku = cdd.szDst + dwEndSkuLen;
  373. cdd.dwFileCount = dwFileCount;
  374. // Create the progress dialog.
  375. //
  376. switch ( DialogBoxParam(g_App.hInstance, MAKEINTRESOURCE(IDD_PROGRESS), hwnd, ProgressDlgProc, (LPARAM) &cdd) )
  377. {
  378. case PROGRESS_ERR_SUCCESS:
  379. if ( ( !bExists ) &&
  380. ( (nItem = AddSkuToList(hwndLB, szSkuDir, lpArchDir, NULL, 0, dwSP)) >= 0 ) &&
  381. ( (INT) SendMessage(hwndLB, LB_GETCOUNT, 0, 0L) > 0 ) &&
  382. ( (INT) SendMessage(hwndLB, LB_GETCURSEL, 0, 0L) == LB_ERR ) )
  383. {
  384. SendMessage(hwndLB, LB_SETCURSEL, nItem, 0L);
  385. }
  386. break;
  387. case PROGRESS_ERR_CANCEL:
  388. break;
  389. case PROGRESS_ERR_COPYERR:
  390. MsgBox(GetParent(hwnd), IDS_ERR_COPYFAIL, IDS_APPNAME, MB_ERRORBOX, UPPER(cdd.szDst[0]));
  391. break;
  392. case PROGRESS_ERR_THREAD:
  393. MsgBox(GetParent(hwnd), IDS_OUTOFMEM, IDS_APPNAME, MB_ERRORBOX);
  394. break;
  395. }
  396. }
  397. }
  398. else
  399. {
  400. // Actually turns out the source is not vallid. Reset this to false
  401. // so we show the bad source error.
  402. //
  403. bGoodSource = FALSE;
  404. }
  405. }
  406. }
  407. else
  408. {
  409. // Display an error saying we don't recognize the arch.
  410. //
  411. MsgBox(GetParent(hwnd), IDS_ERR_BADARCH, IDS_APPNAME, MB_ERRORBOX);
  412. bGoodSource = FALSE;
  413. bErrorDisplayed = TRUE;
  414. }
  415. }
  416. }
  417. // This is only not true if the source the user selected is not valid and we need to tell them.
  418. // Any other failure and this will still be true and the user will have already been informed.
  419. //
  420. if ( !bGoodSource && !bErrorDisplayed)
  421. MsgBox(GetParent(hwnd), IDS_ERR_BADSOURCE, IDS_APPNAME, MB_ERRORBOX);
  422. }
  423. }
  424. void DelSku(HWND hwnd, HWND hwndLB, LPTSTR lpLangName)
  425. {
  426. INT nItem;
  427. // Get the selected item.
  428. //
  429. if ( (nItem = (INT) SendMessage(hwndLB, LB_GETCURSEL, 0, 0L)) >= 0 )
  430. {
  431. TCHAR szSkuPath[MAX_PATH],
  432. szSkuName[256] = NULLSTR;
  433. LPTSTR lpEnd,
  434. lpDirs = (LPTSTR) SendMessage(hwndLB, LB_GETITEMDATA, nItem, 0L);
  435. SendMessage(hwndLB, LB_GETTEXT, nItem, (LPARAM) szSkuName);
  436. if ( ( lpDirs != (LPTSTR) LB_ERR ) &&
  437. ( szSkuName[0] ) &&
  438. ( MsgBox(hwnd, IDS_DELETESKU, IDS_APPNAME, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2, szSkuName) == IDYES ) &&
  439. ( SendMessage(hwndLB, LB_DELETESTRING, nItem, 0L) != LB_ERR ) )
  440. {
  441. LPTSTR lpDirsDup = lpDirs;
  442. // Create a path to the folder for this SKU\Arch.
  443. //
  444. lstrcpyn(szSkuPath, g_App.szLangDir,AS(szSkuPath));
  445. AddPathN(szSkuPath, lpLangName,AS(szSkuPath));
  446. AddPathN(szSkuPath, DIR_SKU,AS(szSkuPath));
  447. AddPathN(szSkuPath, lpDirs,AS(szSkuPath));
  448. lpEnd = szSkuPath + lstrlen(szSkuPath);
  449. lpDirs += lstrlen(lpDirs) + 1;
  450. AddPathN(szSkuPath, lpDirs,AS(szSkuPath));
  451. // This removes just the Arch folder... the folder for this sku might have some others
  452. // in it.
  453. //
  454. DeletePath(szSkuPath);
  455. // You have to reset the current directory before we try removing the folder for
  456. // this SKU because DeletePath leaves its current dir as the parent of the one
  457. // it removed.
  458. //
  459. SetCurrentDirectory(g_App.szOpkDir);
  460. // Now try to remve the folder for this SKU if it is empty (otherwise the RemoveDir
  461. // call just fails and we don't care.
  462. //
  463. *lpEnd = NULLCHR;
  464. RemoveDirectory(szSkuPath);
  465. // Now reselect another item in the list.
  466. //
  467. if ( (INT) SendMessage(hwndLB, LB_GETCOUNT, 0, 0L) <= nItem )
  468. nItem--;
  469. if ( nItem >= 0 )
  470. SendMessage(hwndLB, LB_SETCURSEL, nItem, 0L);
  471. FREE(lpDirsDup);
  472. }
  473. }
  474. }
  475. //
  476. // Internal Function(s):
  477. //
  478. static BOOL OnInit(HWND hwnd, HWND hwndFocus, LPARAM lParam)
  479. {
  480. // Always return false to WM_INITDIALOG.
  481. //
  482. return FALSE;
  483. }
  484. static void OnCommand(HWND hwnd, INT id, HWND hwndCtl, UINT codeNotify)
  485. {
  486. BOOL bReset = FALSE;
  487. switch ( id )
  488. {
  489. case IDC_ADD:
  490. // User clicked Add.
  491. //
  492. AddSku(GetParent(hwnd), GetDlgItem(hwnd, IDC_SKU_LIST), g_App.szLangName);
  493. bReset = TRUE;
  494. break;
  495. case IDC_DELETE:
  496. // User clicked Delete (not implimented on the page yet).
  497. //
  498. DelSku(GetParent(hwnd), GetDlgItem(hwnd, IDC_SKU_LIST), g_App.szLangName);
  499. bReset = TRUE;
  500. break;
  501. case IDC_SKU_LIST:
  502. if ( codeNotify == LBN_SELCHANGE )
  503. bReset = TRUE;
  504. break;
  505. }
  506. if ( bReset )
  507. {
  508. if ( (INT) SendDlgItemMessage(hwnd, IDC_SKU_LIST, LB_GETCURSEL, 0, 0L) >= 0 )
  509. WIZ_BUTTONS(hwnd, PSWIZB_BACK | PSWIZB_NEXT);
  510. else
  511. WIZ_BUTTONS(hwnd, PSWIZB_BACK);
  512. }
  513. }
  514. static BOOL OnNext(HWND hwnd)
  515. {
  516. BOOL bOk = FALSE;
  517. if ( (INT) SendDlgItemMessage(hwnd, IDC_SKU_LIST, LB_GETCOUNT, 0, 0L) > 0 )
  518. {
  519. INT nItem = (INT) SendDlgItemMessage(hwnd, IDC_SKU_LIST, LB_GETCURSEL, 0, 0L);
  520. if ( nItem >= 0 )
  521. {
  522. LPTSTR lpDirs = (LPTSTR) SendDlgItemMessage(hwnd, IDC_SKU_LIST, LB_GETITEMDATA, nItem, 0L);
  523. if ( lpDirs != (LPTSTR) LB_ERR )
  524. {
  525. lstrcpyn(g_App.szSkuName, lpDirs, AS(g_App.szSkuName));
  526. WritePrivateProfileString(INI_SEC_WINPE, INI_KEY_WINPE_LANG, g_App.szLangName, g_App.szWinBomIniFile);
  527. WritePrivateProfileString(INI_SEC_WINPE, INI_KEY_WINPE_LANG, g_App.szLangName, g_App.szOpkWizIniFile);
  528. WritePrivateProfileString(INI_SEC_WINPE, INI_KEY_WBOM_WINPE_SKU, g_App.szSkuName, g_App.szWinBomIniFile);
  529. WritePrivateProfileString(INI_SEC_WINPE, INI_KEY_WBOM_WINPE_SKU, g_App.szSkuName, g_App.szOpkWizIniFile);
  530. WritePrivateProfileString(INI_SEC_WINPE, INI_KEY_ARCH, lpDirs + lstrlen(lpDirs) + 1, g_App.szOpkWizIniFile);
  531. bOk = TRUE;
  532. }
  533. else
  534. MsgBox(GetParent(hwnd), IDS_ERR_SKUDIR, IDS_APPNAME, MB_ERRORBOX);
  535. }
  536. else
  537. MsgBox(GetParent(hwnd), IDS_ERR_NOSKU, IDS_APPNAME, MB_ERRORBOX);
  538. }
  539. else
  540. MsgBox(GetParent(hwnd), IDS_ERR_NOSKU, IDS_APPNAME, MB_ERRORBOX);
  541. return bOk;
  542. }
  543. //
  544. // This function gets called when the dialog is destroyed as well as when
  545. // a PSN_SETACTIVE message is sent to the IDD_SKU dialog.
  546. //
  547. static void OnDestroy(HWND hwnd)
  548. {
  549. LPTSTR lpString;
  550. INT nItem = (INT) SendDlgItemMessage(hwnd, IDC_SKU_LIST, LB_GETCOUNT, 0, 0L);
  551. // Free the string I allocated for each list item's data.
  552. //
  553. while ( --nItem >= 0 )
  554. {
  555. if ( (lpString = (LPTSTR) SendDlgItemMessage(hwnd, IDC_SKU_LIST, LB_GETITEMDATA, nItem, 0L)) != (LPTSTR) LB_ERR )
  556. {
  557. FREE(lpString);
  558. SendDlgItemMessage(hwnd, IDC_SKU_LIST, LB_SETITEMDATA, nItem, 0L);
  559. }
  560. }
  561. SendDlgItemMessage(hwnd, IDC_SKU_LIST, LB_RESETCONTENT, 0, 0L);
  562. }
  563. static void EnumDirs(HWND hwndLB, LPTSTR lpSkuDir)
  564. {
  565. WIN32_FIND_DATA FileFound;
  566. HANDLE hFile;
  567. if ( (hFile = FindFirstFile(_T("*"), &FileFound)) != INVALID_HANDLE_VALUE )
  568. {
  569. do
  570. {
  571. // Look for all the directories that are not "." or "..".
  572. //
  573. if ( ( FileFound.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) &&
  574. ( lstrcmp(FileFound.cFileName, _T(".")) ) &&
  575. ( lstrcmp(FileFound.cFileName, _T("..")) ) )
  576. {
  577. // If we have a sku name already, then we just got the arch and we can
  578. // add the string to the list box now. Otherwise we just got the sku
  579. // name and we have to call this function to get the arch.
  580. //
  581. if ( lpSkuDir )
  582. {
  583. AddSkuToList(hwndLB, lpSkuDir, FileFound.cFileName, NULL, 0, 0);
  584. }
  585. else if ( SetCurrentDirectory(FileFound.cFileName) )
  586. {
  587. EnumDirs(hwndLB, FileFound.cFileName);
  588. SetCurrentDirectory(_T(".."));
  589. }
  590. }
  591. }
  592. while ( FindNextFile(hFile, &FileFound) );
  593. FindClose(hFile);
  594. }
  595. }
  596. // AllocateSPStrRes - allocate string resource for product name checking for .spx extension where x is SP number
  597. //
  598. // OUT: lpdwSP - Service pack number
  599. //
  600. // RETURNS: NULL if string not found, else pointer to product string
  601. static LPTSTR AllocateSPStrRes(HINSTANCE hInstance, LPSTRRES lpsrTable, DWORD cbTable, LPTSTR lpString, LPTSTR * lplpReturn, DWORD *lpdwSP)
  602. {
  603. LPSTRRES lpsrSearch = lpsrTable;
  604. LPTSTR lpReturn = NULL;
  605. BOOL bFound;
  606. // Init this return value.
  607. //
  608. if ( lplpReturn )
  609. *lplpReturn = NULL;
  610. // Try to find the friendly name for this string in our table.
  611. //
  612. while ( ( bFound = ((DWORD) (lpsrSearch - lpsrTable) < cbTable) ) &&
  613. ( CompareString( MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT), NORM_IGNORECASE, lpString, 3, lpsrSearch->lpStr, 3 ) != CSTR_EQUAL ) )
  614. {
  615. lpsrSearch++;
  616. }
  617. // If it was found, allocate the friendly name from the resource.
  618. //
  619. if ( bFound )
  620. {
  621. // if this is a service pack, the last character of the dir name will be a digit
  622. // _wtol returns 0 if there is not a digit at the end which is what we want
  623. *lpdwSP= _wtol(lpString+lstrlen(lpString)-1);
  624. lpReturn = AllocateString(hInstance, lpsrSearch->uId);
  625. if ( lplpReturn )
  626. *lplpReturn = lpsrSearch->lpStr;
  627. }
  628. return lpReturn;
  629. }
  630. static INT AddSkuToList(HWND hwndLB, LPTSTR lpSkuDir, LPTSTR lpArchDir, LPTSTR lpReturn, DWORD cbReturn, DWORD dwSP)
  631. {
  632. LPTSTR lpSkuName = AllocateStrRes(NULL, s_srSkuDirs, AS(s_srSkuDirs), lpSkuDir, NULL),
  633. lpArchName = AllocateStrRes(NULL, s_srArchDirs, AS(s_srArchDirs), lpArchDir, NULL),
  634. lpString,
  635. lpszItemData,
  636. lpszSkuSP;
  637. INT nItem = LB_ERR;
  638. BOOL bAllocatedName = TRUE;
  639. int iStringLen;
  640. HRESULT hrPrintf;
  641. // We have an un-recognized product that we should add to the list
  642. //
  643. if ( lpSkuDir && !lpSkuName )
  644. {
  645. // check to see if this is a service pack
  646. if (!(lpSkuName = AllocateSPStrRes(NULL, s_srSkuDirs, AS(s_srSkuDirs), lpSkuDir, NULL, &dwSP))) {
  647. // We don't want to try and free this at the end of the function
  648. //
  649. bAllocatedName = FALSE;
  650. // The friendly name is the sku dir that was entered
  651. //
  652. lpSkuName = lpSkuDir;
  653. }
  654. }
  655. lpszSkuSP = AllocateString(NULL, IDS_SKU_SP);
  656. if ( ( lpSkuName && lpArchName ) &&
  657. ( lpString = MALLOC((lstrlen(lpSkuName) + lstrlen(lpArchName) + AS(STR_SKUARCH) + lstrlen(lpszSkuSP) + 1) * sizeof(TCHAR)) ) )
  658. {
  659. // Create the display name for the list box.
  660. //
  661. iStringLen=(lstrlen(lpSkuName) + lstrlen(lpArchName) + AS(STR_SKUARCH) + lstrlen(lpszSkuSP) + 1);
  662. hrPrintf=StringCchPrintf(lpString, iStringLen, STR_SKUARCH, lpSkuName ? lpSkuName : lpSkuDir, lpArchName ? lpArchName : lpArchDir);
  663. if (dwSP)
  664. hrPrintf=StringCchPrintf(lpString+lstrlen(lpString), iStringLen-lstrlen(lpString), lpszSkuSP, dwSP);
  665. // Check to see if we want to return the display string.
  666. //
  667. if ( lpReturn && cbReturn )
  668. lstrcpyn(lpReturn, lpString, cbReturn);
  669. // Add the string to the list box if we were passed in a list box handle.
  670. //
  671. if ( ( hwndLB ) &&
  672. ( (nItem = (INT) SendMessage(hwndLB, LB_ADDSTRING, 0, (LPARAM) lpString)) >= 0 ) )
  673. {
  674. // Make sure we are able to save the sku and arch dir names as the item data, otherwise it is no good
  675. // and we have to delete the string from the list.
  676. //
  677. if ( ( (lpszItemData = MALLOC((lstrlen(lpSkuDir) + lstrlen(lpArchDir) + 2) * sizeof(TCHAR))) == NULL ) ||
  678. ( SendMessage(hwndLB, LB_SETITEMDATA, nItem, (LPARAM) lpszItemData) == LB_ERR ) )
  679. {
  680. // Do'h... we have to remove it.
  681. //
  682. SendMessage(hwndLB, LB_DELETESTRING, nItem, 0L);
  683. nItem = LB_ERR;
  684. FREE(lpszItemData); // Macro checks for NULL.
  685. }
  686. else
  687. {
  688. // Store the two directory names in the same string, separated by a null character.
  689. //
  690. iStringLen=(lstrlen(lpSkuDir) + lstrlen(lpArchDir) + 2);
  691. lstrcpyn(lpszItemData, lpSkuDir,iStringLen);
  692. lstrcpyn(lpszItemData + lstrlen(lpszItemData) + 1, lpArchDir,(iStringLen -lstrlen(lpszItemData)-1));
  693. }
  694. }
  695. FREE(lpString);
  696. }
  697. // Only free lpSkuName if we allocated in the function
  698. //
  699. if ( bAllocatedName )
  700. {
  701. FREE(lpSkuName); // Macro checks for NULL.
  702. }
  703. FREE(lpArchName); // Macro checks for NULL.
  704. FREE(lpszSkuSP); // Macro checks for NULL.
  705. return nItem;
  706. }
  707. // Note: lpszSrc and lpszDst must be at least size MAX_PATH
  708. DWORD CopySkuFiles(HWND hwndProgress, HANDLE hEvent, LPTSTR lpszSrc, LPTSTR lpszDst, LPTSTR lpszInfFile)
  709. {
  710. LPTSTR lpszEndSrc = lpszSrc + lstrlen(lpszSrc),
  711. lpszEndDst = lpszDst + lstrlen(lpszDst);
  712. DWORD dwRet = 1,
  713. dwCount = 0,
  714. dwLoop = NUM_FIRST_SOURCE_DX;
  715. BOOL bFound,
  716. bCopyOK;
  717. TCHAR szDirKey[32],
  718. szDir[MAX_PATH];
  719. HRESULT hrPrintf;
  720. do
  721. {
  722. // Create the key we want to look for in the inf file.
  723. //
  724. hrPrintf=StringCchPrintf(szDirKey, AS(szDirKey), INI_KEY_DIR, dwLoop++);
  725. // Now see if that key exists.
  726. //
  727. szDir[0] = NULLCHR;
  728. if ( bFound = ( GetPrivateProfileString(INI_SEC_DIRS, szDirKey, NULLSTR, szDir, STRSIZE(szDir), lpszInfFile) && szDir[0] ) )
  729. {
  730. // Now setup the destination and source paths.
  731. //
  732. AddPathN(lpszSrc, szDir, MAX_PATH);
  733. AddPathN(lpszDst, szDir, MAX_PATH);
  734. // Copy the directory, if it fails we should error and bail.
  735. // Note that if the progress is NULL, then we are just doing
  736. // a count and we don't need to actually copy.
  737. //
  738. if ( hwndProgress == NULL )
  739. dwCount = dwCount + FileCount(lpszSrc);
  740. else
  741. {
  742. CopyDirectoryProgressCancel(hwndProgress, hEvent, lpszSrc, lpszDst);
  743. }
  744. // If we keep going we need to reset our root destination and source paths.
  745. //
  746. *lpszEndSrc = NULLCHR;
  747. *lpszEndDst = NULLCHR;
  748. }
  749. // on professional 32-bit skus, only copy the first Directory
  750. if (wcsstr(lpszDst,DIR_SKU_PRO) && wcsstr(lpszDst,DIR_ARCH_X86))
  751. break;
  752. }
  753. while ( dwRet && bFound );
  754. // Now return, either 0 for an error, or 1 for a successful copy,
  755. // or the count of files if hwndProgress is NULL.
  756. //
  757. return hwndProgress ? dwRet : dwCount;
  758. }
  759. static BOOL StartCopy(HWND hwnd, HANDLE hEvent, LPCOPYDIRDATA lpcdd)
  760. {
  761. BOOL bRet = TRUE;
  762. HANDLE hThread;
  763. DWORD dwThreadId;
  764. // Replace the old parent with the new progress dialog parent.
  765. //
  766. lpcdd->hwndParent = hwnd;
  767. // Need to pass in the cancel event as well.
  768. //
  769. lpcdd->hEvent = hEvent;
  770. // Now create the thread that will copy the actual files.
  771. //
  772. if ( hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) CopyDirectoryThread, (LPVOID) lpcdd, 0, &dwThreadId) )
  773. CloseHandle(hThread);
  774. else
  775. bRet = FALSE;
  776. return bRet;
  777. }
  778. DWORD WINAPI CopyDirectoryThread(LPVOID lpVoid)
  779. {
  780. LPCOPYDIRDATA lpcdd = (LPCOPYDIRDATA) lpVoid;
  781. BOOL bRet = FALSE;
  782. INT_PTR iRet = PROGRESS_ERR_SUCCESS;
  783. HWND hwnd = lpcdd->hwndParent,
  784. hwndProgress = GetDlgItem(hwnd, IDC_PROGRESS);
  785. // First we need to create the path.
  786. //
  787. if ( CreatePath(lpcdd->szDst) )
  788. {
  789. // Setup the progress bar.
  790. //
  791. SendMessage(hwndProgress, PBM_SETSTEP, 1, 0L);
  792. SendMessage(hwndProgress, PBM_SETRANGE32, 0, (LPARAM) lpcdd->dwFileCount);
  793. // Now try and copy the files.
  794. //
  795. if ( !CopySkuFiles(hwndProgress, lpcdd->hEvent, lpcdd->szSrc, lpcdd->szDst, lpcdd->szInfFile) )
  796. {
  797. // Delete our destination directory if there is an error. This removes just the Arch
  798. // folder... the folder for this sku might have some others in it.
  799. //
  800. DeletePath(lpcdd->szDst);
  801. // You have to reset the current directory before we try removing the folder for
  802. // this SKU because DeletePath leaves its current dir as the parent of the one
  803. // it removed.
  804. //
  805. SetCurrentDirectory(g_App.szOpkDir);
  806. // Now try to remove the folder for this SKU if it is empty (otherwise the RemoveDir
  807. // call just fails and we don't care).
  808. //
  809. *lpcdd->lpszEndSku = NULLCHR;
  810. RemoveDirectory(lpcdd->szDst);
  811. }
  812. else
  813. bRet = TRUE;
  814. }
  815. // Figure out our error code.
  816. //
  817. if ( !bRet )
  818. {
  819. if ( ( lpcdd->hEvent ) &&
  820. ( WaitForSingleObject(lpcdd->hEvent, 0) != WAIT_TIMEOUT ) )
  821. {
  822. iRet = PROGRESS_ERR_CANCEL;
  823. }
  824. else
  825. iRet = PROGRESS_ERR_COPYERR;
  826. }
  827. // Now end the dialog with our error code.
  828. //
  829. EndDialog(hwnd, iRet);
  830. return bRet;
  831. }
  832. LRESULT CALLBACK ProgressDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  833. {
  834. static HANDLE hEvent;
  835. switch (uMsg)
  836. {
  837. case WM_INITDIALOG:
  838. hEvent = CreateEvent(NULL, TRUE, FALSE, STR_EVENT_CANCEL);
  839. PostMessage(hwnd, WM_APP_STARTCOPY, 0, lParam);
  840. return FALSE;
  841. case WM_COMMAND:
  842. case WM_CLOSE:
  843. if ( hEvent )
  844. SetEvent(hEvent);
  845. else
  846. EndDialog(hwnd, PROGRESS_ERR_CANCEL);
  847. return FALSE;
  848. case WM_APP_STARTCOPY:
  849. if ( !StartCopy(hwnd, hEvent, (LPCOPYDIRDATA) lParam) )
  850. EndDialog(hwnd, PROGRESS_ERR_THREAD);
  851. break;
  852. case WM_DESTROY:
  853. if ( hEvent )
  854. {
  855. CloseHandle(hEvent);
  856. hEvent = NULL;
  857. }
  858. return FALSE;
  859. default:
  860. return FALSE;
  861. }
  862. return TRUE;
  863. }
  864. LRESULT CALLBACK SkuNameDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  865. {
  866. static LPTSTR lpszRet = NULL;
  867. static DWORD dwSize = 0;
  868. switch (uMsg)
  869. {
  870. case WM_INITDIALOG:
  871. if ( lParam )
  872. {
  873. // We need to save the pointer to our return string buffer.
  874. //
  875. lpszRet = (LPTSTR) lParam;
  876. // The size of our string buffer is stored in the first 4 bytes of the string.
  877. //
  878. dwSize = *((LPDWORD) lParam);
  879. // Init our string buffer to a empty string.
  880. //
  881. *lpszRet = NULLCHR;
  882. // Limit the size of the string that can be entered.
  883. //
  884. SendDlgItemMessage(hwnd, IDC_SKU_NAME, EM_LIMITTEXT, dwSize ? dwSize - 1 : 0, 0L);
  885. }
  886. return FALSE;
  887. case WM_COMMAND:
  888. switch ( LOWORD(wParam) )
  889. {
  890. case IDOK:
  891. if ( lpszRet && dwSize )
  892. GetDlgItemText(hwnd, IDC_SKU_NAME, lpszRet, dwSize);
  893. EndDialog(hwnd, 1);
  894. break;
  895. case IDCANCEL:
  896. EndDialog(hwnd, 0);
  897. break;
  898. }
  899. return FALSE;
  900. default:
  901. return FALSE;
  902. }
  903. return TRUE;
  904. }
  905. BOOL OnSetActive(HWND hwnd)
  906. {
  907. TCHAR szSku[256] = NULLSTR,
  908. szArch[256] = NULLSTR;
  909. INT nItem;
  910. LPTSTR lpDirs;
  911. g_App.dwCurrentHelp = IDH_TARGET;
  912. if ( (nItem = (INT) SendDlgItemMessage(hwnd, IDC_SKU_LIST, LB_GETCURSEL, 0, 0L)) == LB_ERR )
  913. {
  914. // Retrieve the settings from the winbom.
  915. //
  916. GetPrivateProfileString(INI_SEC_WINPE, INI_KEY_WBOM_WINPE_SKU, NULLSTR, szSku, STRSIZE(szSku), GET_FLAG(OPK_BATCHMODE) ? g_App.szOpkWizIniFile : g_App.szWinBomIniFile);
  917. GetPrivateProfileString(INI_SEC_WINPE, INI_KEY_ARCH, NULLSTR, szArch, STRSIZE(szArch), g_App.szOpkWizIniFile);
  918. }
  919. else
  920. {
  921. // Remember the selection from the item if an item was selected
  922. lpDirs = (LPTSTR) SendDlgItemMessage(hwnd, IDC_SKU_LIST, LB_GETITEMDATA, nItem, 0L);
  923. lstrcpyn(szSku, lpDirs,AS(szSku));
  924. lstrcpyn(szArch, lpDirs + lstrlen(lpDirs) + 1,AS(szArch));
  925. }
  926. // We must have a lang at this point.
  927. //
  928. if ( g_App.szLangName[0] == NULLCHR )
  929. {
  930. MsgBox(GetParent(hwnd), IDS_ERR_INVALIDCONFIG, IDS_APPNAME, MB_ERRORBOX);
  931. WIZ_EXIT(hwnd);
  932. }
  933. // Remove all items from the list
  934. //
  935. OnDestroy(hwnd);
  936. // Setup the path buffer to the config dir for the
  937. // tag files we might need to look for.
  938. //
  939. SetupSkuListBox(GetDlgItem(hwnd, IDC_SKU_LIST), g_App.szLangName);
  940. // Look through the items in the list and select the one
  941. // that was in the winbom, if we find one.
  942. //
  943. nItem = (INT) SendDlgItemMessage(hwnd, IDC_SKU_LIST, LB_GETCOUNT, 0, 0L);
  944. while ( --nItem >= 0)
  945. {
  946. lpDirs = (LPTSTR) SendDlgItemMessage(hwnd, IDC_SKU_LIST, LB_GETITEMDATA, nItem, 0L);
  947. if ( lpDirs != (LPTSTR) LB_ERR )
  948. {
  949. if ( ( lstrcmpi(szSku, lpDirs) == 0 ) &&
  950. ( lstrcmpi(szArch, lpDirs + lstrlen(lpDirs) + 1) == 0 ) )
  951. {
  952. SendDlgItemMessage(hwnd, IDC_SKU_LIST, LB_SETCURSEL, nItem, 0L);
  953. }
  954. }
  955. }
  956. if ( (INT) SendDlgItemMessage(hwnd, IDC_SKU_LIST, LB_GETCURSEL, 0, 0L) >= 0 )
  957. {
  958. WIZ_BUTTONS(hwnd, PSWIZB_BACK | PSWIZB_NEXT);
  959. if ( GET_FLAG(OPK_BATCHMODE) &&
  960. OnNext(hwnd) )
  961. {
  962. WIZ_SKIP(hwnd);
  963. }
  964. }
  965. else
  966. WIZ_BUTTONS(hwnd, PSWIZB_BACK);
  967. return TRUE;
  968. }