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.

5399 lines
145 KiB

  1. ////////////////////////////////////////////////////////////////////////////
  2. //
  3. // MUISetup.c
  4. //
  5. // This file contains the WinMain() and the UI handling of MUISetup.
  6. //
  7. // MUISetup is compiled as an Unicode application.
  8. //
  9. ////////////////////////////////////////////////////////////////////////////
  10. #include <nt.h>
  11. #include <ntrtl.h>
  12. #include <nturtl.h>
  13. #include <userenv.h>
  14. #include <shellapi.h>
  15. #include <regstr.h>
  16. #include <wmistr.h>
  17. #include <wmiumkm.h>
  18. #include <setupapi.h>
  19. #include <shlwapi.h>
  20. #include "sxsapi.h"
  21. #include "muisetup.h"
  22. //
  23. // Context Help IDs
  24. //
  25. //
  26. // Context Help Ids.
  27. //
  28. #define IA64_WOW64FOLDER TEXT("SysWOW64")
  29. STDAPI_(BOOL) IsUserAnAdmin();
  30. static int aMuisetupHelpIds[] =
  31. {
  32. 207, IDH_COMM_GROUPBOX, // Group Box
  33. IDC_LIST1, IDH_MUISETUP_UILANGUAGE_LIST, // UI Language ListView
  34. IDC_DEF_UI_LANG_COMBO, IDH_MUISETUP_UILANGUAGECOMBO, // UI ComboBox selection
  35. IDC_CHECK_LOCALE, IDH_MUISETUP_CHECKLOCALE, // Match system locale with UI language
  36. IDC_CHECK_UIFONT, IDH_MUISETUP_MATCHUIFONT, // Match system locale with UI language
  37. 0, 0
  38. };
  39. //
  40. // Global variables
  41. //
  42. BOOL InstallDialogStarted;
  43. BOOL gbError;
  44. BOOL g_bMatchUIFont;
  45. // Store the special directories listed under [Directories] in mui.inf
  46. TCHAR DirNames[MFL][MAX_PATH],DirNames_ie[MFL][MAX_PATH];
  47. TCHAR szWindowsDir[MAX_PATH];
  48. // The FOLDER where MUISetup.exe is executed.
  49. TCHAR g_szMUISetupFolder[MAX_PATH];
  50. // The FULL PATH for MUISetup.exe.
  51. TCHAR g_szMuisetupPath[MAX_PATH];
  52. // The full path where MUI.inf is located.
  53. TCHAR g_szMUIInfoFilePath[MAX_PATH];
  54. TCHAR g_szVolumeName[MAX_PATH],g_szVolumeRoot[MAX_PATH];
  55. TCHAR g_szMUIHelpFilePath[MAX_PATH],g_szPlatformPath[16],g_szCDLabel[MAX_PATH];
  56. // Windows directory
  57. TCHAR g_szWinDir[MAX_PATH];
  58. TCHAR g_AddLanguages[BUFFER_SIZE];
  59. HANDLE ghMutex = NULL;
  60. HINSTANCE ghInstance;
  61. HWND ghProgDialog; // The progress dialog showed during installation/uninstallation.
  62. HWND ghProgress; // The progress bar in the progress dialog
  63. LANGID gUserUILangId, gSystemUILangId;
  64. BOOL gbIsWorkStation,gbIsServer,gbIsAdvanceServer,gbIsDataCenter,gbIsDomainController;
  65. HINSTANCE g_hUserEnvDll = NULL;
  66. HMODULE g_hAdvPackDll = NULL;
  67. HMODULE g_hSxSDll = NULL;
  68. DWORD g_dwVolumeSerialNo;
  69. BOOL g_InstallCancelled,g_IECopyError,g_bRemoveDefaultUI,g_bRemoveUserUI,g_bCmdMatchLocale,g_bCmdMatchUIFont, g_bReboot;
  70. UILANGUAGEGROUP g_UILanguageGroup;
  71. int g_cdnumber;
  72. // Number of locales supported by the OS
  73. int iLocaleCount;
  74. // Number of MUI languges to insatll
  75. int gNumLanguages,gNumLanguages_Install,gNumLanguages_Uninstall;
  76. // Flag to indicate whether a language group is found for the locale or not.
  77. BOOL gFoundLangGroup;
  78. LGRPID gLangGroup;
  79. LCID gLCID;
  80. // The language groups installed in the system.
  81. LGRPID gLanguageGroups[32] ;
  82. int gNumLanguageGroups;
  83. PFILERENAME_TABLE g_pFileRenameTable;
  84. int g_nFileRename;
  85. PTYPENOTFALLBACK_TABLE g_pNotFallBackTable;
  86. int g_nNotFallBack;
  87. BOOL g_bSilent=FALSE;
  88. //
  89. // Required pfns
  90. //
  91. pfnNtSetDefaultUILanguage gpfnNtSetDefaultUILanguage;
  92. pfnGetUserDefaultUILanguage gpfnGetUserDefaultUILanguage;
  93. pfnGetSystemDefaultUILanguage gpfnGetSystemDefaultUILanguage;
  94. pfnIsValidLanguageGroup gpfnIsValidLanguageGroup;
  95. pfnEnumLanguageGroupLocalesW gpfnEnumLanguageGroupLocalesW;
  96. pfnEnumSystemLanguageGroupsW gpfnEnumSystemLanguageGroupsW;
  97. pfnRtlAdjustPrivilege gpfnRtlAdjustPrivilege;
  98. pfnProcessIdToSessionId gpfnProcessIdToSessionId;
  99. pfnGetDefaultUserProfileDirectoryW gpfnGetDefaultUserProfileDirectoryW = NULL;
  100. pfnLaunchINFSection gpfnLaunchINFSection = NULL;
  101. PSXS_INSTALL_W gpfnSxsInstallW = NULL;
  102. PSXS_UNINSTALL_ASSEMBLYW gpfnSxsUninstallW = NULL;
  103. //
  104. // GetWindowsDirectory stuff
  105. //
  106. UINT WINAPI NT4_GetWindowsDir(LPWSTR pBuf, UINT uSize)
  107. {
  108. return GetWindowsDirectoryW(pBuf, uSize);
  109. }
  110. //
  111. // shlwapi StrToIntEx doesn't work for us
  112. //
  113. DWORD HexStrToInt(LPTSTR lpsz)
  114. {
  115. DWORD dw = 0L;
  116. TCHAR c;
  117. while(*lpsz)
  118. {
  119. c = *lpsz++;
  120. if (c >= TEXT('A') && c <= TEXT('F'))
  121. {
  122. c -= TEXT('A') - 0xa;
  123. }
  124. else if (c >= TEXT('0') && c <= TEXT('9'))
  125. {
  126. c -= TEXT('0');
  127. }
  128. else if (c >= TEXT('a') && c <= TEXT('f'))
  129. {
  130. c -= TEXT('a') - 0xa;
  131. }
  132. else
  133. {
  134. break;
  135. }
  136. dw *= 0x10;
  137. dw += c;
  138. }
  139. return(dw);
  140. }
  141. UINT (WINAPI *pfnGetWindowsDir)(LPWSTR pBuf, UINT uSize) = NT4_GetWindowsDir;
  142. void InitGetWindowsDirectoryPFN(HMODULE hMod)
  143. {
  144. pfnGetWindowsDir = (UINT (WINAPI *) (LPWSTR pBuf, UINT uSize)) GetProcAddress(hMod, "GetSystemWindowsDirectoryW");
  145. if (!pfnGetWindowsDir)
  146. {
  147. pfnGetWindowsDir = NT4_GetWindowsDir;
  148. }
  149. }
  150. ////////////////////////////////////////////////////////////////////////////
  151. //
  152. // GetLanguageDisplayName
  153. //
  154. // Get the display name (in the form of "Language (Region)") for the specified
  155. // language ID.
  156. //
  157. // Parameters:
  158. // [IN] langID Language ID
  159. // [OUT] lpBuffer the buffer to receive the display name.
  160. // [IN] nBufferSize the size of buffer, in TCHAR.
  161. //
  162. // Return Values:
  163. // TRUE if succeed. FALSE if the buffer is not big enough.
  164. //
  165. //
  166. // 01-11-2001 YSLin Created.
  167. //
  168. ////////////////////////////////////////////////////////////////////////////
  169. BOOL GetLanguageDisplayName(LANGID langID, LPTSTR lpBuffer, int nBufferSize)
  170. {
  171. TCHAR lpLangName[BUFFER_SIZE];
  172. TCHAR lpRegionName[BUFFER_SIZE];
  173. int nCharCount = 0;
  174. nCharCount = GetLocaleInfo(langID, LOCALE_SENGLANGUAGE, lpLangName, ARRAYSIZE(lpLangName)-1);
  175. nCharCount += GetLocaleInfo(langID, LOCALE_SENGCOUNTRY , lpRegionName, ARRAYSIZE(lpRegionName)-1);
  176. nCharCount += 3;
  177. if (nCharCount > nBufferSize)
  178. {
  179. if (nBufferSize)
  180. lstrcpy(lpBuffer, TEXT(""));
  181. return (FALSE);
  182. }
  183. wsprintf(lpBuffer, TEXT("%s (%s)"), lpLangName, lpRegionName);
  184. return (TRUE);
  185. }
  186. //
  187. // Our Message Box
  188. //
  189. int DoMessageBox(HWND hwndParent, UINT uIdString, UINT uIdCaption, UINT uType)
  190. {
  191. TCHAR szString[MAX_PATH+MAX_PATH];
  192. TCHAR szCaption[MAX_PATH];
  193. szString[0] = szCaption[0] = TEXT('\0');
  194. if (uIdString)
  195. LoadString(NULL, uIdString, szString, MAX_PATH+MAX_PATH-1);
  196. if (uIdCaption)
  197. LoadString(NULL, uIdCaption, szCaption, MAX_PATH-1);
  198. return MESSAGEBOX(hwndParent, szString, szCaption, uType);
  199. }
  200. ////////////////////////////////////////////////////////////////////////////
  201. //
  202. // DoMessageBoxFromResource
  203. //
  204. // Load a format string from resource, and format the string using the
  205. // specified arguments. Display a message box using the formatted string.
  206. //
  207. // Parameters:
  208. //
  209. // Return Values:
  210. // The return value from MessageBox.
  211. //
  212. // Remarks:
  213. // The length of the formatted string is limited by BUFFER_SIZE.
  214. //
  215. // 08-07-2000 YSLin Created.
  216. //
  217. ////////////////////////////////////////////////////////////////////////////
  218. int DoMessageBoxFromResource(HWND hwndParent, HMODULE hInstance, UINT uIdString, LONG_PTR* lppArgs, UINT uIdCaption, UINT uType)
  219. {
  220. TCHAR szString[BUFFER_SIZE];
  221. TCHAR szCaption[BUFFER_SIZE];
  222. szString[0] = szCaption[0] = TEXT('\0');
  223. if (uIdCaption)
  224. LoadString(hInstance, uIdCaption, szCaption, MAX_PATH-1);
  225. FormatStringFromResource(szString, sizeof(szString)/sizeof(TCHAR), hInstance, uIdString, lppArgs);
  226. return (MESSAGEBOX(hwndParent, szString, szCaption, uType));
  227. }
  228. BOOL IsMatchingPlatform(void)
  229. {
  230. BOOL bx86Image = FALSE;
  231. BOOL bRet = TRUE;
  232. SYSTEM_INFO si;
  233. TCHAR szWOW64Path[MAX_PATH];
  234. #ifdef _X86_
  235. bx86Image = TRUE;
  236. #endif
  237. if (GetWindowsDirectory(szWOW64Path, ARRAYSIZE(szWOW64Path)) &&
  238. PathAppend(szWOW64Path, IA64_WOW64FOLDER) &&
  239. PathFileExists(szWOW64Path) &&
  240. bx86Image)
  241. bRet = FALSE;
  242. return bRet;
  243. }
  244. //
  245. // Program Entry Point
  246. //
  247. INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow)
  248. {
  249. int result = 0;
  250. TCHAR lpCommandLine[BUFFER_SIZE+1];
  251. HMODULE hMod;
  252. int error,nNumArgs=0,i;
  253. LONG_PTR lppArgs[3];
  254. LPWSTR *pszArgv;
  255. if (!IsUserAnAdmin())
  256. {
  257. //
  258. // "You must have administrator right to run muisetup.\n\n"
  259. // "If you want to switch your UI language, please use the regional option from control panel."
  260. //
  261. LogFormattedMessage(ghInstance, IDS_ADMIN_L, NULL);
  262. DoMessageBox(NULL, IDS_ADMIN, IDS_MAIN_TITLE, MB_OK);
  263. return result;
  264. }
  265. //
  266. // Bail out if image doesn't match the running platform
  267. //
  268. if (!IsMatchingPlatform())
  269. {
  270. DoMessageBox(NULL, IDS_WRONG_IMAGE, IDS_MAIN_TITLE, MB_OK | MB_DEFBUTTON1);
  271. return result;
  272. }
  273. ghInstance = hInstance;
  274. //
  275. // Let make sure this NT5, and let's initialize all our pfns
  276. //
  277. if (!InitializePFNs())
  278. {
  279. //
  280. // Not an NT5 system. The following should be ANSI to work on Win9x.
  281. //
  282. CHAR szString[MAX_PATH];
  283. CHAR szCaption[MAX_PATH];
  284. LoadStringA(NULL, IDS_ERROR_NT5_ONLY, szString, MAX_PATH-1);
  285. LoadStringA(NULL, IDS_MAIN_TITLE, szCaption, MAX_PATH-1);
  286. MessageBoxA(NULL, szString, szCaption, MB_OK | MB_ICONINFORMATION);
  287. result = 1;
  288. goto Exit;
  289. }
  290. //
  291. // Check if the program has already been running ?
  292. //
  293. if (CheckMultipleInstances())
  294. {
  295. result = 1;
  296. goto Exit;
  297. }
  298. //
  299. // Initialize any global vars
  300. //
  301. InitGlobals();
  302. //
  303. // Check if I'm launching from previous version of muisetup
  304. //
  305. // I.E. muisetup /$_transfer_$ path_of_MUI_installation_files
  306. //
  307. pszArgv = CommandLineToArgvW((LPCWSTR) GetCommandLineW(), &nNumArgs);
  308. lpCommandLine[0]=TEXT('\0');
  309. if (pszArgv)
  310. {
  311. for (i=1; i<nNumArgs;i++)
  312. {
  313. if (!_tcsicmp(pszArgv[i],MUISETUP_FORWARDCALL_TAG) && ((i+1) < nNumArgs) )
  314. {
  315. i++;
  316. }
  317. else
  318. {
  319. _tcscat(lpCommandLine,pszArgv[i]);
  320. _tcscat(lpCommandLine,TEXT(" "));
  321. }
  322. }
  323. GlobalFree((HGLOBAL) pszArgv);
  324. }
  325. InitCommonControls();
  326. BeginLog();
  327. //
  328. // Block the installation of Data Center and Personal.
  329. //
  330. if (/*gbIsDataCenter || */CheckProductType(MUI_IS_WIN2K_PERSONAL))
  331. {
  332. //
  333. // "Windows XP MultiLanguage Version cannot be installed on this platform."
  334. //
  335. DoMessageBox(NULL, IDS_WRONG_NTAS, IDS_MAIN_TITLE, MB_OK | MB_DEFBUTTON1);
  336. result = 1;
  337. goto Exit;
  338. }
  339. //
  340. // Check to see if a command line has been used
  341. //
  342. if(lpCommandLine && NextCommandTag(lpCommandLine))
  343. {
  344. lppArgs[0] = (LONG_PTR)lpCommandLine;
  345. LogFormattedMessage(NULL, IDS_COMMAND_LOG, lppArgs);
  346. LogMessage(TEXT("")); //Add a carriage return and newline
  347. ParseCommandLine(lpCommandLine);
  348. }
  349. else
  350. {
  351. //
  352. // MUI version needs to match OS version
  353. //
  354. if (!checkversion(TRUE))
  355. {
  356. DoMessageBox(NULL, IDS_WRONG_VERSION, IDS_MAIN_TITLE, MB_OK | MB_DEFBUTTON1);
  357. result = 1;
  358. goto Exit;
  359. }
  360. if (WelcomeDialog(0))
  361. {
  362. DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG_MAIN), 0, DialogFunc);
  363. }
  364. result = 1;
  365. }
  366. Exit:
  367. //
  368. // Cleanup
  369. //
  370. Muisetup_Cleanup();
  371. return result;
  372. }
  373. ////////////////////////////////////////////////////////////////////////////////////
  374. //
  375. // CheckMultipleInstances
  376. //
  377. // Checks if another instance is running, and if so, it switches to it.
  378. //
  379. ////////////////////////////////////////////////////////////////////////////////////
  380. BOOL CheckMultipleInstances(void)
  381. {
  382. ghMutex = CreateMutex(NULL, TRUE, TEXT("Muisetup_Mutex"));
  383. if (ghMutex && (GetLastError() == ERROR_ALREADY_EXISTS))
  384. {
  385. const int idsTitles[] = {IDS_MAIN_TITLE, IDS_INSTALL_TITLE, IDS_PROG_TITLE_2, IDS_PROG_TITLE_3, IDS_UNINSTALL_TITLE};
  386. HWND hWnd;
  387. TCHAR szTitle[MAX_PATH];
  388. int i;
  389. //
  390. // Find the running instance by searching possible Window titles
  391. //
  392. for (i=0; i<ARRAYSIZE(idsTitles); i++)
  393. {
  394. LoadString(NULL, idsTitles[i], szTitle, MAX_PATH-1);
  395. hWnd = FindWindow(NULL,szTitle);
  396. if (hWnd && IsWindow(hWnd))
  397. {
  398. if (IsIconic(hWnd))
  399. ShowWindow(hWnd, SW_RESTORE);
  400. SetForegroundWindow(hWnd);
  401. break;
  402. }
  403. }
  404. //
  405. // Always bail out if there is another running instance
  406. //
  407. return TRUE;
  408. }
  409. return FALSE;
  410. }
  411. ////////////////////////////////////////////////////////////////////////////////////
  412. //
  413. // StartFromTSClient
  414. //
  415. // Check if I'm launched from a TS client
  416. //
  417. ////////////////////////////////////////////////////////////////////////////////////
  418. BOOL StartFromTSClient()
  419. {
  420. BOOL bResult=FALSE;
  421. DWORD_PTR SessionId;
  422. if (gpfnProcessIdToSessionId)
  423. {
  424. if (gpfnProcessIdToSessionId(GetCurrentProcessId(), &SessionId) && SessionId != 0)
  425. {
  426. bResult = TRUE;
  427. }
  428. }
  429. return bResult;
  430. }
  431. ////////////////////////////////////////////////////////////////////////////////////
  432. //
  433. // InitializePFNs
  434. //
  435. // Initialize NT5 specific pfns
  436. //
  437. ////////////////////////////////////////////////////////////////////////////////////
  438. BOOL InitializePFNs()
  439. {
  440. HMODULE hModule;
  441. SYSTEM_INFO SystemInfo;
  442. LONG_PTR lppArgs[2];
  443. //
  444. // Determine platform
  445. //
  446. GetSystemInfo( &SystemInfo );
  447. if (SystemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL ||
  448. SystemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ||
  449. SystemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64)
  450. {
  451. #if defined(_AMD64_)
  452. _tcscpy(g_szPlatformPath, TEXT("amd64\\"));
  453. #elif defined(_IA64_)
  454. _tcscpy(g_szPlatformPath, TEXT("ia64\\"));
  455. #else
  456. _tcscpy(g_szPlatformPath, TEXT("i386\\"));
  457. #endif
  458. }
  459. else
  460. {
  461. // This is NOT supported yet
  462. return FALSE;
  463. }
  464. //
  465. // Let's bring ntdll!NtSetDefaultUILanguage
  466. //
  467. hModule = GetModuleHandle(TEXT("ntdll.dll"));
  468. if (!hModule)
  469. return FALSE;
  470. gpfnNtSetDefaultUILanguage =
  471. (pfnNtSetDefaultUILanguage)GetProcAddress(hModule,
  472. "NtSetDefaultUILanguage");
  473. if (!gpfnNtSetDefaultUILanguage)
  474. return FALSE;
  475. gpfnRtlAdjustPrivilege =
  476. (pfnRtlAdjustPrivilege)GetProcAddress(hModule,
  477. "RtlAdjustPrivilege");
  478. if (!gpfnRtlAdjustPrivilege)
  479. return FALSE;
  480. //
  481. // Let's get out from kernel32.dll :
  482. // - GetUserDefaultUILanguage
  483. // - GetSystemDefaultUILanguage
  484. // - EnumLanguageGroupLocalesW
  485. //
  486. hModule = GetModuleHandle(TEXT("kernel32.dll"));
  487. if (!hModule)
  488. return FALSE;
  489. gpfnGetUserDefaultUILanguage =
  490. (pfnGetUserDefaultUILanguage)GetProcAddress(hModule,
  491. "GetUserDefaultUILanguage");
  492. if (!gpfnGetUserDefaultUILanguage)
  493. return FALSE;
  494. gpfnGetSystemDefaultUILanguage =
  495. (pfnGetSystemDefaultUILanguage)GetProcAddress(hModule,
  496. "GetSystemDefaultUILanguage");
  497. if (!gpfnGetSystemDefaultUILanguage)
  498. return FALSE;
  499. gpfnIsValidLanguageGroup =
  500. (pfnIsValidLanguageGroup)GetProcAddress(hModule,
  501. "IsValidLanguageGroup");
  502. if (!gpfnIsValidLanguageGroup)
  503. return FALSE;
  504. gpfnEnumLanguageGroupLocalesW =
  505. (pfnEnumLanguageGroupLocalesW)GetProcAddress(hModule,
  506. "EnumLanguageGroupLocalesW");
  507. if (!gpfnEnumLanguageGroupLocalesW)
  508. return FALSE;
  509. gpfnEnumSystemLanguageGroupsW =
  510. (pfnEnumSystemLanguageGroupsW)GetProcAddress(hModule,
  511. "EnumSystemLanguageGroupsW");
  512. if (!gpfnEnumSystemLanguageGroupsW)
  513. return FALSE;
  514. gpfnProcessIdToSessionId =
  515. (pfnProcessIdToSessionId) GetProcAddress(hModule,
  516. "ProcessIdToSessionId");
  517. //
  518. // Initialize the pfnGetWindowsDirectory
  519. //
  520. InitGetWindowsDirectoryPFN(hModule);
  521. //
  522. // Try to load userenv.dll
  523. //
  524. g_hUserEnvDll = LoadLibrary(TEXT("userenv.dll"));
  525. if (g_hUserEnvDll)
  526. {
  527. gpfnGetDefaultUserProfileDirectoryW =
  528. (pfnGetDefaultUserProfileDirectoryW)GetProcAddress(g_hUserEnvDll,
  529. "GetDefaultUserProfileDirectoryW");
  530. }
  531. g_hAdvPackDll = LoadLibrary(TEXT("AdvPack.dll"));
  532. if (g_hAdvPackDll == NULL)
  533. {
  534. LogFormattedMessage(ghInstance, IDS_LOAD_ADVPACK_L, NULL);
  535. return (FALSE);
  536. }
  537. gpfnLaunchINFSection = (pfnLaunchINFSection)GetProcAddress(g_hAdvPackDll, "LaunchINFSection");
  538. if (gpfnLaunchINFSection == NULL)
  539. {
  540. lppArgs[0] = (LONG_PTR)TEXT("LaunchINFSection");
  541. LogFormattedMessage(ghInstance, IDS_LOAD_ADVPACK_API_L, lppArgs);
  542. return (FALSE);
  543. }
  544. g_hSxSDll = LoadLibrary(TEXT("SxS.dll"));
  545. if (g_hSxSDll)
  546. {
  547. gpfnSxsInstallW = (PSXS_INSTALL_W)GetProcAddress(g_hSxSDll, SXS_INSTALL_W);
  548. gpfnSxsUninstallW = (PSXS_UNINSTALL_ASSEMBLYW)GetProcAddress(g_hSxSDll, SXS_UNINSTALL_ASSEMBLYW);
  549. }
  550. return TRUE;
  551. }
  552. ////////////////////////////////////////////////////////////////////////////////////
  553. //
  554. // Find the path of execution file and set path for MUI.INF
  555. //
  556. //
  557. ////////////////////////////////////////////////////////////////////////////////////
  558. void SetSourcePath(LPTSTR lpszPreviousMUIPath)
  559. {
  560. UINT_PTR cb;
  561. LPTSTR lpszPath,lpszNext=NULL;
  562. TCHAR szHelpPath[MAX_PATH+1],szHelpFile[MAX_PATH+1];
  563. if (!lpszPreviousMUIPath)
  564. {
  565. g_szMUISetupFolder[0]=TEXT('\0');
  566. cb = GetModuleFileName (ghInstance, g_szMuisetupPath, MAX_PATH);
  567. _tcscpy(g_szMUISetupFolder,g_szMuisetupPath);
  568. //
  569. // Get folder for MUISetup.
  570. //
  571. lpszPath = g_szMUISetupFolder;
  572. while ( (lpszNext=_tcschr(lpszPath,TEXT('\\'))) )
  573. {
  574. lpszPath = lpszNext+1;
  575. }
  576. *lpszPath=TEXT('\0');
  577. }
  578. else
  579. {
  580. _tcscpy(g_szMUISetupFolder,lpszPreviousMUIPath);
  581. }
  582. _tcscpy(g_szMUIInfoFilePath,g_szMUISetupFolder);
  583. _tcscat(g_szMUIInfoFilePath,MUIINFFILENAME);
  584. //
  585. // Check the location of help file
  586. //
  587. _tcscpy(szHelpPath,g_szMUISetupFolder);
  588. LoadString(NULL, IDS_HELPFILE,szHelpFile,MAX_PATH);
  589. _tcscat(szHelpPath,szHelpFile);
  590. if (!FileExists(szHelpPath))
  591. {
  592. pfnGetWindowsDir(szHelpPath, MAX_PATH);
  593. _tcscat(szHelpPath, TEXT("\\"));
  594. _tcscat(szHelpPath,HELPDIR); // HELP\MUI
  595. _tcscat(szHelpPath, TEXT("\\"));
  596. _tcscat(szHelpPath,szHelpFile);
  597. if (FileExists(szHelpPath))
  598. {
  599. _tcscpy(g_szMUIHelpFilePath,szHelpPath);
  600. }
  601. }
  602. else
  603. {
  604. _tcscpy(g_szMUIHelpFilePath,szHelpPath);
  605. }
  606. if(g_szMUIInfoFilePath[1] == TEXT(':'))
  607. {
  608. _tcsncpy(g_szVolumeRoot,g_szMUIInfoFilePath,3);
  609. g_szVolumeRoot[3]=TEXT('\0');
  610. GetVolumeInformation(g_szVolumeRoot, g_szVolumeName, sizeof(g_szVolumeName)/sizeof(TCHAR),
  611. &g_dwVolumeSerialNo, 0, 0, 0, 0);
  612. }
  613. if (!GetPrivateProfileString( MUI_CDLAYOUT_SECTION,
  614. MUI_CDLABEL,
  615. TEXT(""),
  616. g_szCDLabel,
  617. MAX_PATH-1,
  618. g_szMUIInfoFilePath))
  619. {
  620. LoadString(NULL, IDS_CHANGE_CDROM, g_szCDLabel, MAX_PATH-1);
  621. }
  622. }
  623. void Set_SourcePath_FromForward(LPCTSTR lpszPath)
  624. {
  625. TCHAR szMUIPath[MAX_PATH+1];
  626. int nidx=0;
  627. while (*lpszPath)
  628. {
  629. if (*lpszPath == MUI_FILLER_CHAR)
  630. {
  631. szMUIPath[nidx++]=TEXT(' ');
  632. }
  633. else
  634. {
  635. szMUIPath[nidx++]=*lpszPath;
  636. }
  637. lpszPath++;
  638. }
  639. szMUIPath[nidx]=TEXT('\0');
  640. SetSourcePath(szMUIPath);
  641. }
  642. BOOL MUIShouldSwitchToNewVersion(LPTSTR lpszCommandLine)
  643. {
  644. BOOL bResult=FALSE;
  645. TCHAR szTarget[ MAX_PATH+1 ];
  646. ULONG ulHandle,ulBytes;
  647. pfnGetWindowsDir(szTarget, MAX_PATH); //%windir% //
  648. _tcscat(szTarget, TEXT("\\"));
  649. _tcscat(szTarget, MUIDIR); // \MUI //
  650. _tcscat(szTarget, TEXT("\\"));
  651. _tcscat(szTarget,MUISETUP_EXECUTION_FILENAME);
  652. //
  653. // If %windir%\mui\muisetup.exe doesn't exist or current muisetup.exe is launched from %windir%\mui then
  654. // do nothing
  655. //
  656. if (!FileExists(szTarget) || !_tcsicmp(szTarget,g_szMuisetupPath))
  657. {
  658. return bResult;
  659. }
  660. //
  661. // If %windir%mui\muisetup.exe is not a execuatble then do nothing
  662. //
  663. ulBytes = GetFileVersionInfoSize( szTarget, &ulHandle );
  664. if ( ulBytes == 0 )
  665. return bResult;
  666. //
  667. // Compare the version stamp
  668. //
  669. // if version of g_szMuisetupPath (cuurent process) < %windir%\mui\muisetup
  670. // then switch control to it
  671. //
  672. if (CompareMuisetupVersion(g_szMuisetupPath,szTarget))
  673. {
  674. bResult = TRUE;
  675. MUI_TransferControlToNewVersion(szTarget,lpszCommandLine);
  676. }
  677. return bResult;
  678. }
  679. ////////////////////////////////////////////////////////////////////////////////////
  680. //
  681. // CheckVolumeChange
  682. //
  683. // Make sure that MUI CD-ROM is put in the CD drive.
  684. //
  685. ////////////////////////////////////////////////////////////////////////////////////
  686. BOOL CheckVolumeChange()
  687. {
  688. BOOL bResult = FALSE;
  689. TCHAR szVolumeName[MAX_PATH],szCaption[MAX_PATH+1],szMsg[MAX_PATH+1],szMsg00[MAX_PATH+1],szMsg01[MAX_PATH+1];
  690. DWORD dwVolumeSerialNo;
  691. BOOL bInit=TRUE;
  692. LONG_PTR lppArgs[3];
  693. if( *g_szVolumeName &&
  694. GetVolumeInformation(g_szVolumeRoot, szVolumeName, sizeof(szVolumeName)/sizeof(TCHAR),
  695. &dwVolumeSerialNo, 0, 0, 0, 0) )
  696. {
  697. while( lstrcmp(szVolumeName,g_szVolumeName) || (dwVolumeSerialNo != g_dwVolumeSerialNo) )
  698. {
  699. if (bInit)
  700. {
  701. szCaption[0]=szMsg00[0]=szMsg01[0]=TEXT('\0');
  702. LoadString(NULL, IDS_MAIN_TITLE, szCaption, MAX_PATH);
  703. lppArgs[0] = (LONG_PTR)g_szCDLabel;
  704. lppArgs[1] = (LONG_PTR)g_cdnumber;
  705. FormatStringFromResource(szMsg, sizeof(szMsg)/sizeof(TCHAR), ghInstance, IDS_CHANGE_CDROM2, lppArgs);
  706. bInit=FALSE;
  707. }
  708. if (MESSAGEBOX(NULL, szMsg,szCaption, MB_YESNO | MB_ICONQUESTION) == IDNO)
  709. {
  710. return TRUE;
  711. }
  712. GetVolumeInformation(g_szVolumeRoot, szVolumeName, sizeof(szVolumeName)/sizeof(TCHAR),
  713. &dwVolumeSerialNo, 0, 0, 0, 0);
  714. }
  715. }
  716. return bResult;
  717. }
  718. ////////////////////////////////////////////////////////////////////////////////////
  719. //
  720. // InitGlobals
  721. //
  722. // Initialize global variables
  723. //
  724. ////////////////////////////////////////////////////////////////////////////////////
  725. void InitGlobals(void)
  726. {
  727. // User UI Language Id
  728. gUserUILangId = gpfnGetUserDefaultUILanguage();
  729. gSystemUILangId = gpfnGetSystemDefaultUILanguage();
  730. // System Windows directory
  731. szWindowsDir[0] = TEXT('\0');
  732. pfnGetWindowsDir(szWindowsDir, MAX_PATH);
  733. // Does this have admin privliges ?
  734. gbIsWorkStation=CheckProductType(MUI_IS_WIN2K_PRO);
  735. gbIsServer= CheckProductType(MUI_IS_WIN2K_SERVER);
  736. gbIsAdvanceServer= (CheckProductType(MUI_IS_WIN2K_ADV_SERVER_OR_DATACENTER) || CheckProductType(MUI_IS_WIN2K_ENTERPRISE));
  737. gbIsDataCenter=(CheckProductType(MUI_IS_WIN2K_DATACENTER) || CheckProductType(MUI_IS_WIN2K_DC_DATACENTER));
  738. gbIsDomainController=CheckProductType(MUI_IS_WIN2K_DC);
  739. if (gbIsDomainController)
  740. {
  741. if ( (!gbIsWorkStation) && (!gbIsServer) && (!gbIsAdvanceServer))
  742. {
  743. gbIsServer=TRUE;
  744. }
  745. }
  746. // Fill in system supported language groups
  747. gpfnEnumSystemLanguageGroupsW(EnumLanguageGroupsProc, LGRPID_SUPPORTED, 0);
  748. pfnGetWindowsDir(g_szWinDir, sizeof(g_szWinDir));
  749. g_AddLanguages[0]=TEXT('\0');
  750. g_szVolumeName[0]=TEXT('\0');
  751. g_szVolumeRoot[0]=TEXT('\0');
  752. g_szMUIHelpFilePath[0]=TEXT('\0');
  753. g_szCDLabel[0]=TEXT('\0');
  754. g_dwVolumeSerialNo = 0;
  755. gNumLanguages=0;
  756. gNumLanguages_Install=0;
  757. gNumLanguages_Uninstall=0;
  758. g_InstallCancelled = FALSE;
  759. g_bRemoveDefaultUI=FALSE;
  760. g_cdnumber=0;
  761. g_pFileRenameTable=NULL;
  762. g_nFileRename=0;
  763. g_pNotFallBackTable=NULL;
  764. g_nNotFallBack=0;
  765. // Detect source path for installation
  766. SetSourcePath(NULL);
  767. // Initialize the context for diamond FDI
  768. Muisetup_InitDiamond();
  769. // Get all installed UI languages
  770. MUIGetAllInstalledUILanguages();
  771. }
  772. BOOL CALLBACK EnumLanguageGroupsProc(
  773. LGRPID LanguageGroup, // language group identifier
  774. LPTSTR lpLanguageGroupString, // pointer to language group identifier string
  775. LPTSTR lpLanguageGroupNameString, // pointer to language group name string
  776. DWORD dwFlags, // flags
  777. LONG_PTR lParam) // user-supplied parameter
  778. {
  779. gLanguageGroups[gNumLanguageGroups] = LanguageGroup;
  780. gNumLanguageGroups++;
  781. return TRUE;
  782. }
  783. ////////////////////////////////////////////////////////////////////////////////////
  784. //
  785. // Muisetup_Cleanup
  786. //
  787. // Muisetup cleanup code.
  788. //
  789. ////////////////////////////////////////////////////////////////////////////////////
  790. void Muisetup_Cleanup()
  791. {
  792. //
  793. // Free userenv.dll, if needed
  794. //
  795. if (g_hUserEnvDll)
  796. {
  797. FreeLibrary(g_hUserEnvDll);
  798. }
  799. if (g_hAdvPackDll)
  800. {
  801. FreeLibrary(g_hAdvPackDll);
  802. }
  803. if (g_hSxSDll)
  804. {
  805. FreeLibrary(g_hSxSDll);
  806. }
  807. if (ghMutex)
  808. {
  809. CloseHandle(ghMutex);
  810. }
  811. // Free/release diamond DLL
  812. Muisetup_FreeDiamond();
  813. return;
  814. }
  815. ////////////////////////////////////////////////////////////////////////////////////
  816. //
  817. // OpenMuiKey
  818. //
  819. // Opens the Registry Key where installed languages are stored
  820. //
  821. ////////////////////////////////////////////////////////////////////////////////////
  822. HKEY OpenMuiKey(REGSAM samDesired)
  823. {
  824. DWORD dwDisposition;
  825. HKEY hKey;
  826. TCHAR lpSubKey[BUFFER_SIZE];
  827. _tcscpy(lpSubKey, REG_MUI_PATH);
  828. if(RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  829. lpSubKey,
  830. 0,
  831. NULL,
  832. REG_OPTION_NON_VOLATILE,
  833. samDesired,
  834. NULL,
  835. &hKey,
  836. &dwDisposition) != ERROR_SUCCESS)
  837. {
  838. hKey = NULL;
  839. }
  840. return hKey;
  841. }
  842. void DialogCleanUp(HWND hwndDlg)
  843. {
  844. HWND hList = GetDlgItem(hwndDlg, IDC_LIST1);
  845. int iCount = ListView_GetItemCount(hList);
  846. LVITEM lvItem;
  847. PMUILANGINFO pMuiLangInfo;
  848. while (iCount--)
  849. {
  850. lvItem.mask = LVIF_PARAM;
  851. lvItem.iItem = iCount;
  852. lvItem.iSubItem = 0;
  853. lvItem.state = 0;
  854. lvItem.stateMask = 0;
  855. lvItem.pszText = 0;
  856. lvItem.cchTextMax = 0;
  857. lvItem.iImage = 0;
  858. lvItem.lParam = 0;
  859. ListView_GetItem(hList, &lvItem);
  860. pMuiLangInfo = (PMUILANGINFO)lvItem.lParam;
  861. if (pMuiLangInfo)
  862. {
  863. if (pMuiLangInfo->lpszLcid)
  864. LocalFree(pMuiLangInfo->lpszLcid);
  865. LocalFree(pMuiLangInfo);
  866. }
  867. }
  868. }
  869. ////////////////////////////////////////////////////////////////////////////////////
  870. //
  871. // DialogFunc
  872. //
  873. // Callback function for main dialog (102)
  874. //
  875. ////////////////////////////////////////////////////////////////////////////////////
  876. INT_PTR CALLBACK DialogFunc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  877. {
  878. switch(uMsg)
  879. {
  880. case WM_INITDIALOG:
  881. SendMessage(hwndDlg, WM_SETICON , (WPARAM)ICON_BIG, (LPARAM)LoadIcon(ghInstance,MAKEINTRESOURCE(MUI_ICON)));
  882. SendMessage(hwndDlg, WM_SETICON , (WPARAM)ICON_SMALL, (LPARAM)LoadIcon(ghInstance,MAKEINTRESOURCE(MUI_ICON)));
  883. InitializeInstallDialog(hwndDlg, uMsg, wParam, lParam);
  884. return TRUE;
  885. case WM_HELP:
  886. {
  887. WinHelp( (HWND)((LPHELPINFO)lParam)->hItemHandle,
  888. g_szMUIHelpFilePath,
  889. HELP_WM_HELP,
  890. (DWORD_PTR)(LPTSTR)aMuisetupHelpIds );
  891. break;
  892. }
  893. case WM_CONTEXTMENU: // right mouse click
  894. {
  895. WinHelp( (HWND)wParam,
  896. MUISETUP_HELP_FILENAME,
  897. HELP_CONTEXTMENU,
  898. (DWORD_PTR)(LPTSTR)aMuisetupHelpIds );
  899. break;
  900. }
  901. case WM_COMMAND:
  902. switch (LOWORD(wParam))
  903. {
  904. case IDOK:
  905. EnableWindow(hwndDlg, FALSE);
  906. if (StartGUISetup(hwndDlg))
  907. {
  908. EndDialog(hwndDlg, 0);
  909. }
  910. else
  911. {
  912. EnableWindow(hwndDlg, TRUE);
  913. SetFocus(hwndDlg);
  914. }
  915. return TRUE;
  916. case IDCANCEL:
  917. EndDialog(hwndDlg, 0);
  918. return TRUE;
  919. case IDC_DEF_UI_LANG_COMBO:
  920. switch(HIWORD(wParam))
  921. {
  922. case CBN_SELCHANGE:
  923. UpdateCombo(hwndDlg);
  924. return TRUE;
  925. default:
  926. break;
  927. }
  928. break;
  929. case IDC_CHECK_LOCALE:
  930. if (BST_CHECKED == IsDlgButtonChecked( hwndDlg, IDC_CHECK_LOCALE))
  931. {
  932. EnableWindow(GetDlgItem(hwndDlg, IDC_CHECK_UIFONT), TRUE);
  933. }
  934. else
  935. {
  936. CheckDlgButton(hwndDlg, IDC_CHECK_UIFONT, BST_UNCHECKED);
  937. EnableWindow(GetDlgItem(hwndDlg, IDC_CHECK_UIFONT), FALSE);
  938. }
  939. break;
  940. }
  941. //
  942. // End of WM_COMMAND case
  943. //
  944. break;
  945. case WM_NOTIFY:
  946. switch (((NMHDR *)lParam)->code)
  947. {
  948. case(NM_CUSTOMDRAW):
  949. ListViewCustomDraw(hwndDlg, (LPNMLVCUSTOMDRAW)lParam);
  950. return TRUE;
  951. break;
  952. case (LVN_ITEMCHANGING):
  953. return ListViewChanging( hwndDlg,
  954. IDC_LIST1,
  955. (NM_LISTVIEW *)lParam);
  956. break;
  957. case (LVN_ITEMCHANGED) :
  958. ListViewChanged( hwndDlg,
  959. IDC_LIST1,
  960. (NM_LISTVIEW *)lParam );
  961. break;
  962. default:
  963. return FALSE;
  964. }
  965. break;
  966. case WM_CLOSE:
  967. EndDialog(hwndDlg, 0);
  968. return TRUE;
  969. case WM_DESTROY:
  970. DialogCleanUp(hwndDlg);
  971. return TRUE;
  972. default:
  973. return FALSE;
  974. }
  975. return TRUE;
  976. }
  977. ////////////////////////////////////////////////////////////////////////////////////
  978. //
  979. // ListViewChanging
  980. //
  981. // Processing for a LVN_ITEMCHANGING message
  982. //
  983. ////////////////////////////////////////////////////////////////////////////////////
  984. BOOL ListViewChanging(HWND hDlg, int iID, NM_LISTVIEW *pLV)
  985. {
  986. HWND hwndLV = GetDlgItem(hDlg, iID);
  987. PMUILANGINFO pMuiLangInfo;
  988. //
  989. // Make sure it's a state change message
  990. //
  991. if ((!(pLV->uChanged & LVIF_STATE)) || ((pLV->uNewState & 0x3000) == 0))
  992. return FALSE;
  993. //
  994. // Don't let the System Default be unchecked
  995. //
  996. GetMuiLangInfoFromListView(hwndLV, pLV->iItem, &pMuiLangInfo);
  997. if (MAKELCID(gSystemUILangId, SORT_DEFAULT) == pMuiLangInfo->lcid)
  998. return TRUE;
  999. return FALSE;
  1000. }
  1001. ////////////////////////////////////////////////////////////////////////////////////
  1002. //
  1003. // ListViewChanged
  1004. //
  1005. // Processing for a LVN_ITEMCHANGED message
  1006. //
  1007. ////////////////////////////////////////////////////////////////////////////////////
  1008. BOOL ListViewChanged(HWND hDlg, int iID, NM_LISTVIEW *pLV)
  1009. {
  1010. HWND hwndLV = GetDlgItem(hDlg, iID);
  1011. PMUILANGINFO pMuiLangInfo;
  1012. int iCount;
  1013. BOOL bChecked;
  1014. //
  1015. // Make sure it's a state change message.
  1016. //
  1017. if ((!(pLV->uChanged & LVIF_STATE)) ||
  1018. ((pLV->uNewState & 0x3000) == 0))
  1019. {
  1020. return (FALSE);
  1021. }
  1022. //
  1023. // Get the state of the check box for the currently selected item.
  1024. //
  1025. bChecked = ListView_GetCheckState(hwndLV, pLV->iItem) ? TRUE : FALSE;
  1026. //
  1027. // Don't let the System Default or the current user UI language be unchecked
  1028. //
  1029. GetMuiLangInfoFromListView(hwndLV, pLV->iItem, &pMuiLangInfo);
  1030. if (MAKELCID(gSystemUILangId, SORT_DEFAULT) == pMuiLangInfo->lcid)
  1031. {
  1032. //
  1033. // Set Default check state
  1034. //
  1035. if (bChecked == FALSE)
  1036. {
  1037. ListView_SetCheckState( hwndLV,
  1038. pLV->iItem,
  1039. TRUE );
  1040. }
  1041. return FALSE;
  1042. }
  1043. //
  1044. // Deselect all items.
  1045. //
  1046. iCount = ListView_GetItemCount(hwndLV);
  1047. while (iCount > 0)
  1048. {
  1049. iCount--;
  1050. ListView_SetItemState( hwndLV,
  1051. iCount,
  1052. 0,
  1053. LVIS_FOCUSED | LVIS_SELECTED );
  1054. }
  1055. //
  1056. // Make sure this item is selected.
  1057. //
  1058. ListView_SetItemState( hwndLV,
  1059. pLV->iItem,
  1060. LVIS_FOCUSED | LVIS_SELECTED,
  1061. LVIS_FOCUSED | LVIS_SELECTED );
  1062. //
  1063. // Update the combo box
  1064. //
  1065. PostMessage( hDlg,
  1066. WM_COMMAND,
  1067. MAKEWPARAM(IDC_DEF_UI_LANG_COMBO, CBN_SELCHANGE),
  1068. 0L);
  1069. //
  1070. // Return success.
  1071. //
  1072. return (TRUE);
  1073. }
  1074. ////////////////////////////////////////////////////////////////////////////////////
  1075. //
  1076. // ListViewCustomDraw
  1077. //
  1078. // Processing for list view WM_CUSTOMDRAW notification.
  1079. //
  1080. ////////////////////////////////////////////////////////////////////////////////////
  1081. void ListViewCustomDraw(HWND hDlg, LPNMLVCUSTOMDRAW pDraw)
  1082. {
  1083. HWND hwndLV = GetDlgItem(hDlg, IDC_LIST1);
  1084. PMUILANGINFO pMuiLangInfo;
  1085. //
  1086. // Tell the list view to notify me of item draws.
  1087. //
  1088. if (pDraw->nmcd.dwDrawStage == CDDS_PREPAINT)
  1089. {
  1090. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, CDRF_NOTIFYITEMDRAW);
  1091. return;
  1092. }
  1093. //
  1094. // Handle the Item Prepaint.
  1095. //
  1096. if (pDraw->nmcd.dwDrawStage & CDDS_ITEMPREPAINT)
  1097. {
  1098. //
  1099. // Check to see if the item being drawn is the system default or
  1100. // the current active ui language
  1101. //
  1102. GetMuiLangInfoFromListView(hwndLV, (int)pDraw->nmcd.dwItemSpec, &pMuiLangInfo);
  1103. if (MAKELCID(gSystemUILangId, SORT_DEFAULT) == pMuiLangInfo->lcid)
  1104. {
  1105. pDraw->clrText = (GetSysColor(COLOR_GRAYTEXT));
  1106. }
  1107. }
  1108. //
  1109. // Do the default action.
  1110. //
  1111. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, CDRF_DODEFAULT);
  1112. }
  1113. ////////////////////////////////////////////////////////////////////////////////////
  1114. //
  1115. // StartGUISetup
  1116. //
  1117. // Creates dialog with progress bar for installation
  1118. //
  1119. ////////////////////////////////////////////////////////////////////////////////////
  1120. BOOL StartGUISetup(HWND hwndDlg)
  1121. {
  1122. HWND hProgDlg=NULL;
  1123. LONG_PTR lppArgs[3];
  1124. ULONG ulParam[2];
  1125. TCHAR lpMessage[BUFFER_SIZE];
  1126. TCHAR szBuf[BUFFER_SIZE];
  1127. BOOL bLGInstalled,bContinue;
  1128. INT64 ulSizeNeed,ulSizeAvailable;
  1129. BOOL success;
  1130. HWND hList;
  1131. HWND hCombo;
  1132. int iIndex;
  1133. TCHAR lpAddLanguages[BUFFER_SIZE];
  1134. TCHAR lpRemoveLanguages[BUFFER_SIZE];
  1135. TCHAR lpDefaultUILang[BUFFER_SIZE];
  1136. TCHAR szPostParameter[BUFFER_SIZE];
  1137. int installLangCount; // The number of MUI languages to be installed
  1138. int uninstallLangCount; // The number of MUI langauges to be uninstalled.
  1139. LANGID langID;
  1140. INSTALL_LANG_GROUP installLangGroup;
  1141. //
  1142. // (0) Check available disk space
  1143. //
  1144. if(!IsSpaceEnough(hwndDlg,&ulSizeNeed,&ulSizeAvailable))
  1145. {
  1146. ulParam[0] = (ULONG) (ulSizeNeed/1024);
  1147. ulParam[1] = (ULONG) (ulSizeAvailable/1024);
  1148. LoadString(ghInstance, IDS_DISKSPACE_NOTENOUGH, lpMessage, ARRAYSIZE(lpMessage)-1);
  1149. LoadString(ghInstance, IDS_ERROR_DISKSPACE, szBuf, ARRAYSIZE(szBuf)-1);
  1150. FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  1151. lpMessage,
  1152. 0,
  1153. 0,
  1154. lpMessage,
  1155. ARRAYSIZE(lpMessage)-1,
  1156. (va_list *)ulParam);
  1157. LogMessage(lpMessage);
  1158. MESSAGEBOX(NULL, lpMessage, szBuf, MB_OK | MB_DEFBUTTON1 | MB_ICONWARNING);
  1159. //
  1160. // Let User has another chance to reselect
  1161. //
  1162. return FALSE;
  1163. }
  1164. installLangGroup.bFontLinkRegistryTouched = FALSE;
  1165. installLangGroup.NotDeleted = 0;
  1166. //
  1167. // (1) Install Language Group First
  1168. //
  1169. ConvertMUILangToLangGroup(hwndDlg, &installLangGroup);
  1170. hList=GetDlgItem(hwndDlg, IDC_LIST1);
  1171. hCombo=GetDlgItem(hwndDlg, IDC_DEF_UI_LANG_COMBO);
  1172. installLangCount = EnumSelectedLanguages(hList, lpAddLanguages);
  1173. memmove(g_AddLanguages,lpAddLanguages,ARRAYSIZE(lpAddLanguages));
  1174. uninstallLangCount = EnumUnselectedLanguages(hList, lpRemoveLanguages);
  1175. //
  1176. // Let's read the user's UI language selection,
  1177. // and then call the kernel to update the registry.
  1178. //
  1179. hList = GetDlgItem(hwndDlg, IDC_LIST1);
  1180. hCombo = GetDlgItem(hwndDlg, IDC_DEF_UI_LANG_COMBO);
  1181. iIndex = (int)SendMessage(hCombo, CB_GETCURSEL, 0, 0);
  1182. if (iIndex == CB_ERR)
  1183. {
  1184. return FALSE;
  1185. }
  1186. langID = LANGIDFROMLCID((LCID) SendMessage(hCombo, CB_GETITEMDATA, iIndex, 0L));
  1187. wsprintf(lpDefaultUILang, TEXT("%X"), langID);
  1188. success = DoSetup(
  1189. hwndDlg,
  1190. uninstallLangCount, lpRemoveLanguages,
  1191. installLangGroup,
  1192. installLangCount, lpAddLanguages,
  1193. lpDefaultUILang,
  1194. TRUE, TRUE);
  1195. return (success);
  1196. }
  1197. ////////////////////////////////////////////////////////////////////////////////////
  1198. //
  1199. // ProgressDialogFunc
  1200. //
  1201. // Callback function for progresss dialog
  1202. //
  1203. ////////////////////////////////////////////////////////////////////////////////////
  1204. INT_PTR CALLBACK ProgressDialogFunc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1205. {
  1206. switch(uMsg)
  1207. {
  1208. case WM_INITDIALOG:
  1209. return TRUE;
  1210. case WM_COMMAND:
  1211. switch (LOWORD(wParam))
  1212. {
  1213. case IDCANCEL:
  1214. EndDialog(hwndDlg, 0);
  1215. return TRUE;
  1216. }
  1217. break;
  1218. case WM_CLOSE:
  1219. EndDialog(hwndDlg, 0);
  1220. return TRUE;
  1221. case WM_DESTROY:
  1222. EndDialog(hwndDlg, 0);
  1223. return TRUE;
  1224. default:
  1225. return FALSE;
  1226. }
  1227. return TRUE;
  1228. }
  1229. ////////////////////////////////////////////////////////////////////////////////////
  1230. //
  1231. // InitializeInstallDialog
  1232. //
  1233. // Sets contents of list view and combo box in installation dialog
  1234. //
  1235. ////////////////////////////////////////////////////////////////////////////////////
  1236. BOOL InitializeInstallDialog(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1237. {
  1238. BOOL bInsertSystemDefault = FALSE;
  1239. HANDLE hFile;
  1240. HWND hList, hCombo;
  1241. PTSTR lpLanguages;
  1242. TCHAR tchBuffer[BUFFER_SIZE];
  1243. TCHAR lpDefaultSystemLanguage[BUFFER_SIZE],lpUILanguage[BUFFER_SIZE];
  1244. TCHAR lpMessage[BUFFER_SIZE];
  1245. int iIndex;
  1246. int iChkIndex,iCnt,iMUIDirectories=0;
  1247. lpLanguages = tchBuffer;
  1248. SetWindowTitleFromResource(hwndDlg, IDS_MAIN_TITLE);
  1249. hList = GetDlgItem(hwndDlg, IDC_LIST1);
  1250. hCombo=GetDlgItem(hwndDlg, IDC_DEF_UI_LANG_COMBO);
  1251. InitializeListView(hList);
  1252. //
  1253. // Insert the default system language in the list view
  1254. //
  1255. _stprintf(lpDefaultSystemLanguage, TEXT("%04x"), gSystemUILangId);
  1256. iIndex=InsertLanguageInListView(hList, lpDefaultSystemLanguage, TRUE);
  1257. //
  1258. // Insert the languages in MUI.INF in the list view
  1259. //
  1260. if ( ( (iMUIDirectories =EnumLanguages(lpLanguages)) == 0) && (g_UILanguageGroup.iCount == 0 ) )
  1261. {
  1262. //
  1263. // No languages found in MUI.INF
  1264. //
  1265. LoadString(ghInstance, IDS_NO_LANG_L, lpMessage, ARRAYSIZE(lpMessage)-1);
  1266. LogMessage(lpMessage);
  1267. return FALSE;
  1268. }
  1269. while (*lpLanguages != TEXT('\0'))
  1270. {
  1271. if (CheckLanguageIsQualified(lpLanguages))
  1272. {
  1273. InsertLanguageInListView(hList, lpLanguages, FALSE);
  1274. }
  1275. lpLanguages = _tcschr(lpLanguages, '\0');
  1276. lpLanguages++;
  1277. }
  1278. //
  1279. // We should also check all installed UI languages
  1280. //
  1281. for (iCnt=0; iCnt<g_UILanguageGroup.iCount; iCnt++)
  1282. {
  1283. if (!GetLcidItemIndexFromListView(hList, g_UILanguageGroup.lcid[iCnt], &iChkIndex))
  1284. {
  1285. _stprintf(lpUILanguage, TEXT("%04x"), g_UILanguageGroup.lcid[iCnt]);
  1286. if (CheckLanguageIsQualified(lpUILanguage))
  1287. {
  1288. InsertLanguageInListView(hList, lpUILanguage, FALSE);
  1289. }
  1290. }
  1291. }
  1292. //
  1293. // Let's detect which language groups are installed
  1294. //
  1295. DetectLanguageGroups(hwndDlg);
  1296. SelectInstalledLanguages(hList);
  1297. SetDefault(hCombo);
  1298. //
  1299. // Deselect all items.
  1300. //
  1301. iIndex = ListView_GetItemCount(hList);
  1302. while (iIndex > 0)
  1303. {
  1304. iIndex--;
  1305. ListView_SetItemState( hList,
  1306. iIndex,
  1307. 0,
  1308. LVIS_FOCUSED | LVIS_SELECTED );
  1309. }
  1310. //
  1311. // Select the first one in the list.
  1312. //
  1313. ListView_SetItemState( hList,
  1314. 0,
  1315. LVIS_FOCUSED | LVIS_SELECTED,
  1316. LVIS_FOCUSED | LVIS_SELECTED );
  1317. //
  1318. // Match system locale with the default UI language
  1319. //
  1320. if (CheckMUIRegSetting(MUI_MATCH_LOCALE))
  1321. {
  1322. CheckDlgButton(hwndDlg, IDC_CHECK_LOCALE, BST_CHECKED);
  1323. //
  1324. // Match UI font with the default UI language
  1325. //
  1326. if (g_bMatchUIFont = CheckMUIRegSetting(MUI_MATCH_UIFONT))
  1327. {
  1328. CheckDlgButton(hwndDlg, IDC_CHECK_UIFONT, BST_CHECKED);
  1329. }
  1330. }
  1331. else
  1332. {
  1333. SetMUIRegSetting(MUI_MATCH_UIFONT, FALSE);
  1334. EnableWindow(GetDlgItem(hwndDlg, IDC_CHECK_UIFONT), FALSE);
  1335. }
  1336. return TRUE;
  1337. }
  1338. ////////////////////////////////////////////////////////////////////////////////////
  1339. //
  1340. // CheckForUsingCountryName
  1341. //
  1342. // Fetch MUIINF file if the selected UI lang needs to be displayed as a language
  1343. // name or a country name.
  1344. //
  1345. ////////////////////////////////////////////////////////////////////////////////////
  1346. BOOL CheckForUsingCountryName(PMUILANGINFO pMuiLangInfo)
  1347. {
  1348. TCHAR szSource[MAX_PATH];
  1349. szSource[0] = TEXT('\0');
  1350. //
  1351. // Try check if there is a value for it under [UseCountryName]
  1352. //
  1353. GetPrivateProfileString( MUI_COUNTRYNAME_SECTION,
  1354. pMuiLangInfo->lpszLcid,
  1355. TEXT(""),
  1356. szSource,
  1357. MAX_PATH,
  1358. g_szMUIInfoFilePath);
  1359. if (szSource[0] == TEXT('1'))
  1360. {
  1361. return (TRUE);
  1362. }
  1363. return (FALSE);
  1364. }
  1365. ////////////////////////////////////////////////////////////////////////////////////
  1366. //
  1367. // GetDisplayName
  1368. //
  1369. // Fetch MUIINF file if the selected UI lang needs to be displayed using the
  1370. // name specified in [LanguageDisplayName] section of mui.inf.
  1371. // Otherwise, get the display name according to the values in [UseCountryName].
  1372. // If the value for the specified LCID is 1, use the country name. Otherwise,
  1373. // use the locale name.
  1374. //
  1375. ////////////////////////////////////////////////////////////////////////////////////
  1376. BOOL GetDisplayName(PMUILANGINFO pMuiLangInfo)
  1377. {
  1378. //
  1379. // Try check if there is a customized display name for the specified LCID under [LanguageDisplayName].
  1380. //
  1381. pMuiLangInfo->szDisplayName[0] = L'\0';
  1382. if (pMuiLangInfo->lpszLcid)
  1383. {
  1384. GetPrivateProfileString( MUI_DISPLAYNAME_SECTION,
  1385. pMuiLangInfo->lpszLcid,
  1386. TEXT(""),
  1387. pMuiLangInfo->szDisplayName,
  1388. MAX_PATH,
  1389. g_szMUIInfoFilePath);
  1390. }
  1391. if (pMuiLangInfo->szDisplayName[0] == L'\0')
  1392. {
  1393. //
  1394. // There is no entry in [LanguageDisplayName]. Use the country name or locale name.
  1395. //
  1396. Muisetup_GetLocaleLanguageInfo( pMuiLangInfo->lcid,
  1397. pMuiLangInfo->szDisplayName,
  1398. ARRAYSIZE(pMuiLangInfo->szDisplayName)-1,
  1399. CheckForUsingCountryName(pMuiLangInfo));
  1400. }
  1401. return TRUE;
  1402. }
  1403. ////////////////////////////////////////////////////////////////////////////////////
  1404. //
  1405. // GetLanguageGroupDisplayName
  1406. // Get language group display name for MUI install/uninstall dialog
  1407. //
  1408. ////////////////////////////////////////////////////////////////////////////////////
  1409. BOOL GetLanguageGroupDisplayName(LANGID LangId, LPTSTR lpBuffer, int nSize)
  1410. {
  1411. BOOL bRet = FALSE;
  1412. MUILANGINFO MuiLangInfo = {0};
  1413. MuiLangInfo.lcid = MAKELCID(LangId, SORT_DEFAULT);
  1414. MuiLangInfo.lgrpid = GetLanguageGroup(MuiLangInfo.lcid);
  1415. if (GetDisplayName(&MuiLangInfo) &&
  1416. nSize >= lstrlen(MuiLangInfo.szDisplayName))
  1417. {
  1418. lstrcpy(lpBuffer, MuiLangInfo.szDisplayName);
  1419. bRet = TRUE;
  1420. }
  1421. return bRet;
  1422. }
  1423. ////////////////////////////////////////////////////////////////////////////////////
  1424. //
  1425. // Get UI, IE and LPK files size for the lcid
  1426. //
  1427. ////////////////////////////////////////////////////////////////////////////////////
  1428. BOOL GetUIFileSize(PMUILANGINFO pMuiLangInfo)
  1429. {
  1430. TCHAR szSize[MAX_PATH];
  1431. int nCD;
  1432. pMuiLangInfo->ulUISize = 0;
  1433. pMuiLangInfo->ulLPKSize = 0;
  1434. #if defined(_IA64_)
  1435. BOOL bIA64 = TRUE;
  1436. #else
  1437. BOOL bIA64 = FALSE;
  1438. #endif
  1439. szSize[0] = TEXT('\0');
  1440. //
  1441. // Try to get UI files size under [FileSize_UI]
  1442. //
  1443. if (GetPrivateProfileString( bIA64? MUI_UIFILESIZE_SECTION_IA64 : MUI_UIFILESIZE_SECTION,
  1444. pMuiLangInfo->lpszLcid,
  1445. TEXT(""),
  1446. szSize,
  1447. MAX_PATH,
  1448. g_szMUIInfoFilePath))
  1449. {
  1450. pMuiLangInfo->ulUISize =_wtoi64(szSize);
  1451. }
  1452. szSize[0] = TEXT('\0');
  1453. //
  1454. // Try to get LPK files size under [FileSize_LPK]
  1455. //
  1456. if (GetPrivateProfileString( bIA64? MUI_LPKFILESIZE_SECTION_IA64 : MUI_LPKFILESIZE_SECTION,
  1457. pMuiLangInfo->lpszLcid,
  1458. TEXT(""),
  1459. szSize,
  1460. MAX_PATH,
  1461. g_szMUIInfoFilePath))
  1462. {
  1463. pMuiLangInfo->ulLPKSize =_wtoi64(szSize);
  1464. }
  1465. //
  1466. // Try to get CD # under [CD_LAYOUT]
  1467. //
  1468. nCD=GetPrivateProfileInt(bIA64? MUI_CDLAYOUT_SECTION_IA64 : MUI_CDLAYOUT_SECTION,
  1469. pMuiLangInfo->lpszLcid,
  1470. 0,
  1471. g_szMUIInfoFilePath);
  1472. if (nCD)
  1473. {
  1474. pMuiLangInfo->cd_number = nCD;
  1475. if (g_cdnumber == 0)
  1476. {
  1477. g_cdnumber = pMuiLangInfo->cd_number;
  1478. }
  1479. }
  1480. else
  1481. {
  1482. pMuiLangInfo->cd_number = DEFAULT_CD_NUMBER;
  1483. }
  1484. return TRUE;
  1485. }
  1486. BOOL GetUIFileSize_commandline(LPTSTR lpszLcid, INT64 *ulUISize,INT64 *ulLPKSize)
  1487. {
  1488. TCHAR szSize[MAX_PATH];
  1489. int nCD;
  1490. *ulUISize = 0;
  1491. *ulLPKSize = 0;
  1492. #if defined(_IA64_)
  1493. BOOL bIA64 = TRUE;
  1494. #else
  1495. BOOL bIA64 = FALSE;
  1496. #endif
  1497. szSize[0] = TEXT('\0');
  1498. //
  1499. // Try to get UI files size under [FileSize_UI]
  1500. //
  1501. if (GetPrivateProfileString( bIA64? MUI_UIFILESIZE_SECTION_IA64 : MUI_UIFILESIZE_SECTION,
  1502. lpszLcid,
  1503. TEXT(""),
  1504. szSize,
  1505. MAX_PATH,
  1506. g_szMUIInfoFilePath))
  1507. {
  1508. *ulUISize =_wtoi64(szSize);
  1509. }
  1510. szSize[0] = TEXT('\0');
  1511. //
  1512. // Try to get LPK files size under [FileSize_LPK]
  1513. //
  1514. if (GetPrivateProfileString( bIA64? MUI_LPKFILESIZE_SECTION_IA64 : MUI_LPKFILESIZE_SECTION,
  1515. lpszLcid,
  1516. TEXT(""),
  1517. szSize,
  1518. MAX_PATH,
  1519. g_szMUIInfoFilePath))
  1520. {
  1521. *ulLPKSize =_wtoi64(szSize);
  1522. }
  1523. // Try to get CD # under [CD_LAYOUT]
  1524. //
  1525. if (g_cdnumber == 0)
  1526. {
  1527. g_cdnumber=GetPrivateProfileInt( bIA64? MUI_CDLAYOUT_SECTION_IA64 : MUI_CDLAYOUT_SECTION,
  1528. lpszLcid,
  1529. 0,
  1530. g_szMUIInfoFilePath);
  1531. }
  1532. return TRUE;
  1533. }
  1534. ////////////////////////////////////////////////////////////////////////////////////
  1535. //
  1536. // InitializeListView
  1537. //
  1538. // Gets the list view ready for inserting items
  1539. //
  1540. ////////////////////////////////////////////////////////////////////////////////////
  1541. BOOL InitializeListView(HWND hList)
  1542. {
  1543. DWORD dwExStyle;
  1544. LV_COLUMN Column;
  1545. RECT Rect;
  1546. GetClientRect(hList, &Rect);
  1547. Column.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
  1548. Column.fmt = LVCFMT_LEFT;
  1549. Column.cx = Rect.right - GetSystemMetrics(SM_CYHSCROLL);
  1550. Column.pszText = NULL;
  1551. Column.cchTextMax = 0;
  1552. Column.iSubItem = 0;
  1553. ListView_InsertColumn(hList, 0, &Column);
  1554. dwExStyle = ListView_GetExtendedListViewStyle(hList);
  1555. ListView_SetExtendedListViewStyle(hList, dwExStyle | LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT);
  1556. return TRUE;
  1557. }
  1558. ////////////////////////////////////////////////////////////////////////////////////
  1559. //
  1560. //
  1561. // Check if specified language can install on the target machine.
  1562. // I.E. Arabic, Turkish, Greek and Hebrew MUI can only install on NT Workstation;
  1563. // They are not allowed on NT Server
  1564. //
  1565. ////////////////////////////////////////////////////////////////////////////////////
  1566. BOOL CheckLanguageIsQualified(LPTSTR lpLanguage)
  1567. {
  1568. #ifdef XCHECK_LANGUAGE_FOR_PLATFORM
  1569. BOOL bResult = FALSE;
  1570. LANGID LgLang;
  1571. LgLang = (LANGID)_tcstol(lpLanguage, NULL, 16);
  1572. LgLang = PRIMARYLANGID(LgLang);
  1573. if(gbIsAdvanceServer)
  1574. {
  1575. if (LgLang == LANG_GERMAN || LgLang == LANG_FRENCH || LgLang == LANG_SPANISH ||
  1576. LgLang == LANG_JAPANESE || LgLang == LANG_KOREAN || LgLang == LANG_CHINESE)
  1577. {
  1578. bResult = TRUE;
  1579. }
  1580. }
  1581. else if(gbIsServer)
  1582. {
  1583. if (LgLang == LANG_GERMAN || LgLang == LANG_FRENCH || LgLang == LANG_SPANISH ||
  1584. LgLang == LANG_JAPANESE || LgLang == LANG_KOREAN || LgLang == LANG_CHINESE ||
  1585. LgLang == LANG_SWEDISH || LgLang == LANG_ITALIAN || LgLang == LANG_DUTCH ||
  1586. LgLang == LANG_PORTUGUESE || LgLang == LANG_CZECH || LgLang == LANG_HUNGARIAN ||
  1587. LgLang == LANG_POLISH || LgLang == LANG_RUSSIAN || LgLang == LANG_TURKISH)
  1588. {
  1589. bResult = TRUE;
  1590. }
  1591. }
  1592. else if(gbIsWorkStation)
  1593. {
  1594. bResult = TRUE;
  1595. }
  1596. return bResult;
  1597. #else
  1598. return TRUE;
  1599. #endif
  1600. }
  1601. ////////////////////////////////////////////////////////////////////////////////////
  1602. //
  1603. // InsertLanguageInListView
  1604. //
  1605. // Returns the index of the item in the list view after inserting it.
  1606. //
  1607. ////////////////////////////////////////////////////////////////////////////////////
  1608. int InsertLanguageInListView(HWND hList, LPTSTR lpLanguage, BOOL bCheckState)
  1609. {
  1610. LANGID LgLang;
  1611. LV_ITEM lvItem;
  1612. PMUILANGINFO pMuiLangInfo;
  1613. int iIndex;
  1614. lvItem.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE | LVIF_IMAGE;
  1615. lvItem.iItem = 0;
  1616. lvItem.iSubItem = 0;
  1617. lvItem.state = 0;
  1618. lvItem.stateMask = LVIS_STATEIMAGEMASK;
  1619. lvItem.cchTextMax = 0;
  1620. lvItem.iImage = 0;
  1621. //
  1622. // Allocate enough space to hold pszLcid and MUILANGINFO
  1623. //
  1624. pMuiLangInfo = (PMUILANGINFO) LocalAlloc(LPTR, sizeof(MUILANGINFO));
  1625. if (pMuiLangInfo == NULL)
  1626. {
  1627. ExitFromOutOfMemory();
  1628. }
  1629. pMuiLangInfo->lpszLcid = (LPTSTR) LocalAlloc(LMEM_FIXED, (_tcslen(lpLanguage) + 1) * sizeof(TCHAR));
  1630. if (pMuiLangInfo->lpszLcid == NULL)
  1631. {
  1632. ExitFromOutOfMemory();
  1633. }
  1634. //
  1635. // Init pszLcid
  1636. //
  1637. lvItem.lParam = (LPARAM)pMuiLangInfo;
  1638. _tcscpy((LPTSTR)pMuiLangInfo->lpszLcid, lpLanguage);
  1639. //
  1640. // Init lcid
  1641. //
  1642. LgLang = (LANGID)_tcstol(lpLanguage, NULL, 16);
  1643. pMuiLangInfo->lcid = MAKELCID(LgLang, SORT_DEFAULT);
  1644. if (pMuiLangInfo->szDisplayName[0] == L'\0')
  1645. {
  1646. GetDisplayName(pMuiLangInfo);
  1647. }
  1648. lvItem.pszText = pMuiLangInfo->szDisplayName;
  1649. GetUIFileSize(pMuiLangInfo);
  1650. iIndex = ListView_InsertItem(hList, &lvItem);
  1651. if (iIndex >= 0)
  1652. {
  1653. ListView_SetCheckState(hList, iIndex, bCheckState);
  1654. }
  1655. return iIndex;
  1656. }
  1657. ////////////////////////////////////////////////////////////////////////////////////
  1658. //
  1659. // GetMuiLangInfoFromListView
  1660. //
  1661. // Get the MuiLangInfo of the corresponding ListView Item
  1662. //
  1663. ////////////////////////////////////////////////////////////////////////////////////
  1664. BOOL GetMuiLangInfoFromListView(HWND hList, int i, PMUILANGINFO *ppMuiLangInfo)
  1665. {
  1666. LVITEM lvItem;
  1667. //
  1668. // Check if Language Group is installed
  1669. //
  1670. lvItem.mask = LVIF_PARAM;
  1671. lvItem.iItem = i;
  1672. lvItem.iSubItem = 0;
  1673. lvItem.state = 0;
  1674. lvItem.stateMask = 0;
  1675. lvItem.pszText = 0;
  1676. lvItem.cchTextMax = 0;
  1677. lvItem.iImage = 0;
  1678. lvItem.lParam = 0;
  1679. ListView_GetItem(hList, &lvItem);
  1680. *ppMuiLangInfo = (PMUILANGINFO)lvItem.lParam;
  1681. return TRUE;
  1682. }
  1683. ////////////////////////////////////////////////////////////////////////////////////
  1684. //
  1685. // Muisetup_GetLocaleLanguageInfo
  1686. //
  1687. // Read the locale info of the language or country name.
  1688. //
  1689. ////////////////////////////////////////////////////////////////////////////////////
  1690. int Muisetup_GetLocaleLanguageInfo(LCID lcid, PTSTR pBuf, int iLen, BOOL fUseCountryName)
  1691. {
  1692. TCHAR tchBuf[ MAX_PATH ] ;
  1693. int iRet;
  1694. //
  1695. // If this is either 0x0404 or 0x0804, then mark them specially
  1696. //
  1697. if (0x0404 == lcid)
  1698. {
  1699. iRet = LoadString(ghInstance, IDS_MUI_CHT, pBuf, iLen);
  1700. }
  1701. else if (0x0804 == lcid)
  1702. {
  1703. iRet = LoadString(ghInstance, IDS_MUI_CHS, pBuf, iLen);
  1704. }
  1705. else
  1706. {
  1707. iRet = GetLocaleInfo( lcid,
  1708. LOCALE_SENGLANGUAGE,
  1709. pBuf,
  1710. iLen);
  1711. if (fUseCountryName)
  1712. {
  1713. iRet = GetLocaleInfo( lcid,
  1714. LOCALE_SENGCOUNTRY,
  1715. tchBuf,
  1716. (sizeof(tchBuf)/sizeof(TCHAR)));
  1717. if (iRet)
  1718. {
  1719. _tcscat(pBuf, TEXT(" ("));
  1720. _tcscat(pBuf, tchBuf);
  1721. _tcscat(pBuf, TEXT(")"));
  1722. }
  1723. }
  1724. }
  1725. return iRet;
  1726. }
  1727. ////////////////////////////////////////////////////////////////////////////////////
  1728. //
  1729. // GetLcidFromComboBox
  1730. //
  1731. // Retreives the index of the combo box item that corresponds to this UI Language
  1732. //
  1733. ////////////////////////////////////////////////////////////////////////////////////
  1734. BOOL GetLcidFromComboBox(HWND hCombo, LCID lcid, int *piIndex)
  1735. {
  1736. LCID ItemLcid;
  1737. int i;
  1738. int iCount = (int)SendMessage(hCombo, CB_GETCOUNT, 0L, 0L);
  1739. if (CB_ERR != iCount)
  1740. {
  1741. i = 0;
  1742. while (i < iCount)
  1743. {
  1744. ItemLcid = (LCID)SendMessage(hCombo, CB_GETITEMDATA, (WPARAM)i, (LPARAM)0);
  1745. if ((CB_ERR != ItemLcid) && (ItemLcid == lcid))
  1746. {
  1747. *piIndex = i;
  1748. return TRUE;
  1749. }
  1750. i++;
  1751. }
  1752. }
  1753. return FALSE;
  1754. }
  1755. ////////////////////////////////////////////////////////////////////////////////////
  1756. //
  1757. // GetMuiLangInfoFromListView
  1758. //
  1759. // Retreives the index of the listview item that corresponds to this UI Language
  1760. //
  1761. ////////////////////////////////////////////////////////////////////////////////////
  1762. BOOL GetLcidItemIndexFromListView(HWND hList, LCID lcid, int *piIndex)
  1763. {
  1764. int iCount = ListView_GetItemCount(hList);
  1765. int i;
  1766. PMUILANGINFO pMuiLangInfo;
  1767. LVITEM lvItem;
  1768. i = 0;
  1769. while (i < iCount)
  1770. {
  1771. //
  1772. // Check if Language Group is installed
  1773. //
  1774. lvItem.mask = LVIF_PARAM;
  1775. lvItem.iItem = i;
  1776. lvItem.iSubItem = 0;
  1777. lvItem.state = 0;
  1778. lvItem.stateMask = 0;
  1779. lvItem.pszText = 0;
  1780. lvItem.cchTextMax = 0;
  1781. lvItem.iImage = 0;
  1782. lvItem.lParam = 0;
  1783. ListView_GetItem(hList, &lvItem);
  1784. pMuiLangInfo = (PMUILANGINFO)lvItem.lParam;
  1785. if (pMuiLangInfo->lcid == lcid)
  1786. {
  1787. *piIndex = i;
  1788. return TRUE;
  1789. }
  1790. i++;
  1791. }
  1792. return FALSE;
  1793. }
  1794. ////////////////////////////////////////////////////////////////////////////////////
  1795. //
  1796. // SelectInstalledLanguages
  1797. //
  1798. // Sets the list view check state for insalled languages
  1799. //
  1800. ////////////////////////////////////////////////////////////////////////////////////
  1801. BOOL SelectInstalledLanguages(HWND hList)
  1802. {
  1803. DWORD dwData;
  1804. DWORD dwIndex;
  1805. DWORD dwValue;
  1806. HKEY hKey;
  1807. LANGID LgLang;
  1808. LONG rc;
  1809. TCHAR lpItemString[BUFFER_SIZE];
  1810. TCHAR szData[BUFFER_SIZE];
  1811. TCHAR szValue[BUFFER_SIZE];
  1812. int iIndex;
  1813. int nLvIndex;
  1814. if (hKey = OpenMuiKey(KEY_READ))
  1815. {
  1816. dwIndex = 0;
  1817. rc = ERROR_SUCCESS;
  1818. iIndex = ListView_GetItemCount(hList);
  1819. while(rc==ERROR_SUCCESS)
  1820. {
  1821. dwValue=sizeof(szValue)/sizeof(TCHAR);
  1822. szValue[0]=TEXT('\0');
  1823. dwData = sizeof(szData);
  1824. szData[0] = TEXT('\0');
  1825. DWORD dwType;
  1826. rc = RegEnumValue(hKey, dwIndex, szValue, &dwValue, 0, &dwType, (LPBYTE)szData, &dwData);
  1827. if (rc == ERROR_SUCCESS)
  1828. {
  1829. if (dwType != REG_SZ)
  1830. {
  1831. dwIndex++;
  1832. continue;
  1833. }
  1834. LgLang=(WORD)_tcstol(szValue, NULL, 16);
  1835. if (GetLcidItemIndexFromListView(hList, MAKELCID(LgLang, SORT_DEFAULT), &nLvIndex))
  1836. {
  1837. ListView_SetCheckState(hList, nLvIndex, TRUE);
  1838. }
  1839. }
  1840. dwIndex++;
  1841. }
  1842. RegCloseKey(hKey);
  1843. return TRUE;
  1844. }
  1845. return FALSE;
  1846. }
  1847. ////////////////////////////////////////////////////////////////////////////////////
  1848. //
  1849. // UpdateCombo
  1850. //
  1851. // Updates the combo box to correspond to the languages selected in the list view
  1852. //
  1853. ////////////////////////////////////////////////////////////////////////////////////
  1854. BOOL UpdateCombo(HWND hwndDlg)
  1855. {
  1856. BOOL bDefaultSet=FALSE;
  1857. HWND hCombo;
  1858. HWND hList;
  1859. TCHAR lpBuffer[BUFFER_SIZE];
  1860. TCHAR lpSystemDefault[BUFFER_SIZE];
  1861. int i;
  1862. int iIndex;
  1863. int iLbIndex;
  1864. int iListIndex;
  1865. WPARAM iPrevDefault;
  1866. LCID lcidPrev;
  1867. PMUILANGINFO pMuiLangInfo;
  1868. hList = GetDlgItem(hwndDlg, IDC_LIST1);
  1869. hCombo = GetDlgItem(hwndDlg, IDC_DEF_UI_LANG_COMBO);
  1870. //
  1871. // If the Previous Default is still selected, keep it as the default
  1872. //
  1873. iPrevDefault = SendMessage(hCombo, CB_GETCURSEL, 0, 0);
  1874. if (iPrevDefault == CB_ERR)
  1875. return FALSE;
  1876. lcidPrev = (LCID) SendMessage(hCombo, CB_GETITEMDATA, (WPARAM)iPrevDefault, 0);
  1877. //
  1878. // Get the text of the currently selected default
  1879. //
  1880. GetLcidItemIndexFromListView(hList, lcidPrev, &iLbIndex);
  1881. SendMessage(hCombo, CB_RESETCONTENT, 0, 0);
  1882. iIndex = ListView_GetItemCount(hList);
  1883. iListIndex = 0;
  1884. //
  1885. // See if we can preserve the default.
  1886. //
  1887. i = 0;
  1888. while (i < iIndex)
  1889. {
  1890. if (ListView_GetCheckState(hList, i))
  1891. {
  1892. ListView_GetItemText(hList, i, 0, lpBuffer, ARRAYSIZE(lpBuffer)-1);
  1893. iListIndex = (int) SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM)(LPTSTR)lpBuffer);
  1894. if (CB_ERR != iListIndex)
  1895. {
  1896. GetMuiLangInfoFromListView(hList, i, &pMuiLangInfo);
  1897. SendMessage(hCombo, CB_SETITEMDATA, iListIndex, (LPARAM)(LCID)pMuiLangInfo->lcid);
  1898. if (pMuiLangInfo->lcid == lcidPrev)
  1899. {
  1900. SendMessage(hCombo, CB_SETCURSEL, (WPARAM)iListIndex, 0);
  1901. bDefaultSet = TRUE;
  1902. }
  1903. }
  1904. }
  1905. i++;
  1906. }
  1907. //
  1908. // If no default, force the system default.
  1909. //
  1910. if (!bDefaultSet)
  1911. {
  1912. lcidPrev = MAKELCID(gSystemUILangId, SORT_DEFAULT);
  1913. if (!GetLcidFromComboBox(hCombo, lcidPrev, &iIndex))
  1914. {
  1915. GetLocaleInfo(lcidPrev,
  1916. LOCALE_SENGLANGUAGE,
  1917. lpSystemDefault,
  1918. ARRAYSIZE(lpSystemDefault)-1);
  1919. iIndex = (int) SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM)lpSystemDefault);
  1920. SendMessage(hCombo, CB_SETITEMDATA, (WPARAM)iIndex, (LPARAM)(LCID)lcidPrev);
  1921. }
  1922. SendMessage(hCombo, CB_SETCURSEL, (WPARAM)iIndex, 0);
  1923. }
  1924. return TRUE;
  1925. }
  1926. ////////////////////////////////////////////////////////////////////////////////////
  1927. //
  1928. // SetDefault
  1929. //
  1930. // Sets the default user setting in the combo box
  1931. //
  1932. ////////////////////////////////////////////////////////////////////////////////////
  1933. BOOL SetDefault(HWND hCombo)
  1934. {
  1935. int iIndex;
  1936. TCHAR lpBuffer[BUFFER_SIZE];
  1937. LCID lcid = MAKELCID(GetDotDefaultUILanguage(), SORT_DEFAULT);
  1938. GetLocaleInfo(lcid,
  1939. LOCALE_SENGLANGUAGE,
  1940. lpBuffer,
  1941. ARRAYSIZE(lpBuffer)-1);
  1942. iIndex = (int)SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM)lpBuffer);
  1943. if (CB_ERR != iIndex)
  1944. {
  1945. SendMessage(hCombo, CB_SETITEMDATA, (WPARAM)iIndex, (LPARAM)(DWORD) lcid);
  1946. SendMessage(hCombo, CB_SETCURSEL, (WPARAM)iIndex, 0);
  1947. }
  1948. return TRUE;
  1949. }
  1950. ////////////////////////////////////////////////////////////////////////////////////
  1951. //
  1952. // SetUserDefaultLanguage
  1953. //
  1954. // Sets the default language in the registry
  1955. //
  1956. ////////////////////////////////////////////////////////////////////////////////////
  1957. BOOL SetUserDefaultLanguage(LANGID langID, BOOL bApplyCurrentUser, BOOL bApplyAllUsers)
  1958. {
  1959. TCHAR szCommands[BUFFER_SIZE];
  1960. TCHAR szBuf[BUFFER_SIZE];
  1961. BOOL success;
  1962. LONG_PTR lppArgs[2];
  1963. //
  1964. // Set the UI language now
  1965. //
  1966. // status = gpfnNtSetDefaultUILanguage(LANGIDFROMLCID(langID));
  1967. szCommands[0] = TEXT('\0');
  1968. if (bApplyCurrentUser)
  1969. {
  1970. // E.g. MUILanguage = "0411".
  1971. wsprintf(szCommands, TEXT("MUILanguage=\"%x\"\n"), langID);
  1972. }
  1973. if (bApplyAllUsers)
  1974. {
  1975. wsprintf(szBuf, TEXT("MUILanguage_DefaultUser = \"%x\""), langID);
  1976. _tcscat(szCommands, szBuf);
  1977. }
  1978. success = RunRegionalOptionsApplet(szCommands);
  1979. lppArgs[0] = langID;
  1980. if (success)
  1981. {
  1982. if (bApplyCurrentUser)
  1983. {
  1984. LogFormattedMessage(NULL, IDS_SET_UILANG_CURRENT, lppArgs);
  1985. }
  1986. if (bApplyAllUsers)
  1987. {
  1988. LogFormattedMessage(NULL, IDS_SET_UILANG_ALLUSERS, lppArgs);
  1989. }
  1990. } else
  1991. {
  1992. if (bApplyCurrentUser)
  1993. {
  1994. LogFormattedMessage(NULL, IDS_ERROR_SET_UILANG_CURRENT, lppArgs);
  1995. }
  1996. if (bApplyAllUsers)
  1997. {
  1998. LogFormattedMessage(NULL, IDS_ERROR_SET_UILANG_ALLUSERS, lppArgs);
  1999. }
  2000. }
  2001. return (success);
  2002. }
  2003. ////////////////////////////////////////////////////////////////////////////////////
  2004. //
  2005. // GetDotDefaultUILanguage
  2006. //
  2007. // Retrieve the UI language stored in the HKCU\.Default.
  2008. // This is the default UI language for new users.
  2009. //
  2010. ////////////////////////////////////////////////////////////////////////////////////
  2011. LANGID GetDotDefaultUILanguage()
  2012. {
  2013. HKEY hKey;
  2014. DWORD dwKeyType;
  2015. DWORD dwSize;
  2016. BOOL success = FALSE;
  2017. TCHAR szBuffer[BUFFER_SIZE];
  2018. LANGID langID;
  2019. //
  2020. // Get the value in .DEFAULT.
  2021. //
  2022. if (RegOpenKeyEx( HKEY_USERS,
  2023. TEXT(".DEFAULT\\Control Panel\\Desktop"),
  2024. 0L,
  2025. KEY_READ,
  2026. &hKey ) == ERROR_SUCCESS)
  2027. {
  2028. dwSize = sizeof(szBuffer) * sizeof(TCHAR);
  2029. if (RegQueryValueEx( hKey,
  2030. TEXT("MultiUILanguageId"),
  2031. 0L,
  2032. &dwKeyType,
  2033. (LPBYTE)szBuffer,
  2034. &dwSize) == ERROR_SUCCESS)
  2035. {
  2036. if (dwKeyType == REG_SZ)
  2037. {
  2038. langID = (LANGID)_tcstol(szBuffer, NULL, 16);
  2039. success = TRUE;
  2040. }
  2041. }
  2042. RegCloseKey(hKey);
  2043. }
  2044. if (!success)
  2045. {
  2046. langID = GetSystemDefaultUILanguage();
  2047. }
  2048. return (langID);
  2049. }
  2050. ////////////////////////////////////////////////////////////////////////////////////
  2051. //
  2052. // CheckLangGroupCommandLine
  2053. //
  2054. // Command line version of CheckSupport
  2055. //
  2056. ////////////////////////////////////////////////////////////////////////////////////
  2057. BOOL CheckLangGroupCommandLine(PINSTALL_LANG_GROUP pInstallLangGroup, LPTSTR lpArg)
  2058. {
  2059. int i = 0;
  2060. int iArg;
  2061. LGRPID lgrpid;
  2062. iArg = _tcstol(lpArg, NULL, 16);
  2063. //
  2064. // See if the lang group for this MUI lang is installed or not
  2065. //
  2066. lgrpid = GetLanguageGroup(MAKELCID(iArg, SORT_DEFAULT));
  2067. if (AddMUILangGroup(pInstallLangGroup, lgrpid))
  2068. {
  2069. return TRUE;
  2070. }
  2071. return FALSE;
  2072. }
  2073. ////////////////////////////////////////////////////////////////////////////////////
  2074. //
  2075. // SetWindowTitleFromResource
  2076. //
  2077. // Set the window title using the specified resource string ID.
  2078. //
  2079. ////////////////////////////////////////////////////////////////////////////////////
  2080. void SetWindowTitleFromResource(HWND hwnd, int resourceID)
  2081. {
  2082. TCHAR szBuffer[BUFFER_SIZE];
  2083. LoadString(NULL, resourceID, szBuffer, sizeof(szBuffer)/sizeof(TCHAR));
  2084. SetWindowText(hwnd, szBuffer);
  2085. }
  2086. BOOL UpdateFontLinkRegistry(LPTSTR Languages,BOOL *lpbFontLinkRegistryTouched)
  2087. {
  2088. return UpdateRegistry_FontLink(Languages,lpbFontLinkRegistryTouched);
  2089. }
  2090. BOOL RemoveFileReadOnlyAttribute(LPTSTR lpszFileName)
  2091. {
  2092. BOOL bResult = FALSE;
  2093. DWORD dwAttrib;
  2094. dwAttrib = GetFileAttributes (lpszFileName);
  2095. if ( dwAttrib & FILE_ATTRIBUTE_READONLY )
  2096. {
  2097. dwAttrib &= ~FILE_ATTRIBUTE_READONLY;
  2098. SetFileAttributes (lpszFileName, dwAttrib);
  2099. bResult=TRUE;
  2100. }
  2101. return bResult;
  2102. }
  2103. BOOL MUI_DeleteFile(LPTSTR lpszFileName)
  2104. {
  2105. RemoveFileReadOnlyAttribute(lpszFileName);
  2106. return DeleteFile(lpszFileName);
  2107. }
  2108. ////////////////////////////////////////////////////////////////////////////////////
  2109. //
  2110. // MUI_TransferControlToNewVersion
  2111. //
  2112. // Call %windir%\mui\muisetup.exe /$_transfer_$ mui_installation_file_path command_line
  2113. //
  2114. ////////////////////////////////////////////////////////////////////////////////////
  2115. BOOL MUI_TransferControlToNewVersion(LPTSTR lpszExecutable,LPTSTR lpszCommandLine)
  2116. {
  2117. STARTUPINFO si;
  2118. PROCESS_INFORMATION pi;
  2119. TCHAR szAppName[BUFFER_SIZE],szDropPath[MAX_PATH];
  2120. int nIdx,nLen;
  2121. BOOL bResult=FALSE;
  2122. nLen=_tcslen(g_szMUISetupFolder);
  2123. for (nIdx=0; nIdx <nLen ; nIdx++)
  2124. {
  2125. if (g_szMUISetupFolder[nIdx]==TEXT(' '))
  2126. {
  2127. szDropPath[nIdx]=MUI_FILLER_CHAR;
  2128. }
  2129. else
  2130. {
  2131. szDropPath[nIdx]=g_szMUISetupFolder[nIdx];
  2132. }
  2133. }
  2134. szDropPath[nIdx]=TEXT('\0');
  2135. wsprintf(szAppName,TEXT("%s %s %s %s"),lpszExecutable,MUISETUP_FORWARDCALL_TAG,szDropPath,lpszCommandLine);
  2136. //
  2137. // Run the process
  2138. //
  2139. memset( &si, 0x00, sizeof(si));
  2140. si.cb = sizeof(STARTUPINFO);
  2141. if (!CreateProcess(NULL,
  2142. szAppName,
  2143. NULL,
  2144. NULL,
  2145. FALSE,
  2146. 0L,
  2147. NULL, NULL,
  2148. &si,
  2149. &pi) )
  2150. return bResult;
  2151. WaitForSingleObject(pi.hProcess, INFINITE);
  2152. bResult =TRUE;
  2153. return bResult;
  2154. }
  2155. BOOL DeleteSideBySideMUIAssemblyIfExisted(LPTSTR Languages, TCHAR pszLogFile[BUFFER_SIZE])
  2156. {
  2157. lstrcpy(pszLogFile, g_szWinDir); // c:\windows
  2158. lstrcat(pszLogFile, MUISETUP_PATH_SEPARATOR); // c:\windows\
  2159. lstrcat(pszLogFile, MUIDIR); // c:\windows\mui
  2160. lstrcat(pszLogFile, MUISETUP_PATH_SEPARATOR); // c:\windows\mui\
  2161. lstrcat(pszLogFile, MUISETUP_ASSEMBLY_INSTALLATION_LOG_FILENAME); // c:\windows\mui\muisetup.log.
  2162. lstrcat(pszLogFile, Languages); // c:\windows\mui\muisetup.log.1234
  2163. if (GetFileAttributes(pszLogFile) != 0xFFFFFFFF) // existed
  2164. {
  2165. // open it and delete assemblies in the list
  2166. SXS_UNINSTALLW UninstallData = {sizeof(UninstallData)};
  2167. UninstallData.dwFlags = SXS_UNINSTALL_FLAG_USE_INSTALL_LOG;
  2168. UninstallData.lpInstallLogFile = pszLogFile;
  2169. return gpfnSxsUninstallW(&UninstallData,NULL);
  2170. }else
  2171. return TRUE;
  2172. }
  2173. ////////////////////////////////////////////////////////////////////////////////////
  2174. //
  2175. // InstallSelected
  2176. //
  2177. // Install the languages specified
  2178. //
  2179. // Return:
  2180. // TURE if the operation succeeds. Otherwise FALSE.
  2181. //
  2182. ////////////////////////////////////////////////////////////////////////////////////
  2183. BOOL InstallSelected(LPTSTR Languages, BOOL *lpbFontLinkRegistryTouched)
  2184. {
  2185. TCHAR lpMessage[BUFFER_SIZE];
  2186. SYSTEM_INFO SystemInfo;
  2187. int section=0;
  2188. int iLanguages=0;
  2189. //
  2190. // Next step is to create a list of install directories from layout
  2191. // the directories are listed in the [Directories] section of MUI.INF
  2192. //
  2193. if (!EnumDirectories())
  2194. {
  2195. //
  2196. // "LOG: Error reading directory list."
  2197. //
  2198. LoadString(ghInstance, IDS_DIRECTORY_L, lpMessage, ARRAYSIZE(lpMessage)-1);
  2199. LogMessage(lpMessage);
  2200. return (FALSE);
  2201. }
  2202. EnumFileRename();
  2203. EnumTypeNotFallback();
  2204. //
  2205. // Copy the common files
  2206. //
  2207. if (Languages)
  2208. {
  2209. //
  2210. // Copy MUI files for the selected languages.
  2211. //
  2212. SetWindowTitleFromResource(ghProgDialog, IDS_INSTALL_TITLE);
  2213. if (!CopyFiles(ghProgDialog, Languages))
  2214. {
  2215. //
  2216. // "LOG: Error copying files."
  2217. //
  2218. // stop install if copy fails
  2219. //
  2220. LoadString(ghInstance, IDS_COPY_L, lpMessage, ARRAYSIZE(lpMessage)-1);
  2221. LogMessage(lpMessage);
  2222. #ifndef IGNORE_COPY_ERRORS
  2223. gNumLanguages_Install = 0;
  2224. return (FALSE);
  2225. #endif
  2226. }
  2227. CopyRemoveMuiItself(TRUE);
  2228. }
  2229. //
  2230. // register MUI as installed in registry
  2231. //
  2232. if (!UpdateRegistry(Languages,lpbFontLinkRegistryTouched))
  2233. {
  2234. //
  2235. // LOG: Error updating registry
  2236. //
  2237. LoadString(ghInstance, IDS_REGISTRY_L, lpMessage, ARRAYSIZE(lpMessage)-1);
  2238. LogMessage(lpMessage);
  2239. return (FALSE);
  2240. }
  2241. if (!InstallExternalComponents(Languages))
  2242. {
  2243. return (FALSE);
  2244. }
  2245. return (TRUE);
  2246. }
  2247. ////////////////////////////////////////////////////////////////////////////////////
  2248. //
  2249. // UninstallSelected
  2250. //
  2251. // Uninstall the languages specified
  2252. //
  2253. // Return:
  2254. // TRUE if the operation succeeds. Otherwise FALSE.
  2255. //
  2256. ////////////////////////////////////////////////////////////////////////////////////
  2257. BOOL UninstallSelected(LPTSTR Languages,int *lpNotDeleted)
  2258. {
  2259. TCHAR lpMessage[BUFFER_SIZE];
  2260. SYSTEM_INFO SystemInfo;
  2261. int section = 0;
  2262. int iLanguages = 0;
  2263. //
  2264. // Next step is to create a list of install directories
  2265. // the directories are listed in the [Directories] section
  2266. //
  2267. //
  2268. // this enumerates the directories and fills the array DirNames
  2269. //
  2270. if (!EnumDirectories())
  2271. {
  2272. //
  2273. // "LOG: Error reading directory list."
  2274. //
  2275. LoadString(ghInstance, IDS_DIRECTORY_L, lpMessage, ARRAYSIZE(lpMessage)-1);
  2276. LogMessage(lpMessage);
  2277. return (FALSE);
  2278. }
  2279. UninstallExternalComponents(Languages);
  2280. SetWindowTitleFromResource(ghProgDialog, IDS_UNINSTALL_TITLE);
  2281. //
  2282. // Copy the common files
  2283. //
  2284. if (!DeleteFiles(Languages,lpNotDeleted))
  2285. {
  2286. //
  2287. // "LOG: Error deleting files"
  2288. //
  2289. LoadString(ghInstance, IDS_DELETE_L, lpMessage, ARRAYSIZE(lpMessage)-1);
  2290. LogMessage(lpMessage);
  2291. return (FALSE);
  2292. }
  2293. //
  2294. // register MUI as installed in registry
  2295. //
  2296. if (!UninstallUpdateRegistry(Languages))
  2297. {
  2298. //
  2299. // "LOG: Error updating registry."
  2300. //
  2301. LoadString(ghInstance, IDS_REGISTRY_L, lpMessage, ARRAYSIZE(lpMessage)-1);
  2302. LogMessage(lpMessage);
  2303. }
  2304. //
  2305. // Delete sxs Assembly
  2306. //
  2307. if (gpfnSxsUninstallW)
  2308. {
  2309. TCHAR pszLogFile[BUFFER_SIZE];
  2310. if ( ! DeleteSideBySideMUIAssemblyIfExisted(Languages, pszLogFile))
  2311. {
  2312. TCHAR errInfo[BUFFER_SIZE];
  2313. swprintf(errInfo, TEXT("Assembly UnInstallation of %s failed"), pszLogFile);
  2314. OutputDebugString(errInfo);
  2315. }
  2316. }
  2317. return (TRUE);
  2318. }
  2319. ////////////////////////////////////////////////////////////////////////////////////
  2320. //
  2321. // UninstallUpdateRegistry
  2322. //
  2323. // Update the Registry to account for languages that have been uninstalled
  2324. //
  2325. ////////////////////////////////////////////////////////////////////////////////////
  2326. BOOL UninstallUpdateRegistry(LPTSTR Languages)
  2327. {
  2328. LPTSTR Language;
  2329. HKEY hKeyMUI = 0;
  2330. HKEY hKeyFileVersions = 0;
  2331. DWORD dwDisp;
  2332. BOOL bRet = TRUE;
  2333. if ((RegCreateKeyEx( HKEY_LOCAL_MACHINE,
  2334. REG_MUI_PATH,
  2335. 0,
  2336. TEXT("REG_SZ"),
  2337. REG_OPTION_NON_VOLATILE ,
  2338. KEY_ALL_ACCESS,
  2339. NULL,
  2340. &hKeyMUI,
  2341. &dwDisp) == ERROR_SUCCESS) &&
  2342. ((RegCreateKeyEx( HKEY_LOCAL_MACHINE,
  2343. REG_FILEVERSION_PATH,
  2344. 0,
  2345. TEXT("REG_SZ"),
  2346. REG_OPTION_NON_VOLATILE ,
  2347. KEY_ALL_ACCESS,
  2348. NULL,
  2349. &hKeyFileVersions,
  2350. &dwDisp) == ERROR_SUCCESS)))
  2351. {
  2352. Language = Languages;
  2353. while (*Language)
  2354. {
  2355. //
  2356. // Don't remove system UI language for registry
  2357. //
  2358. if (HexStrToInt(Language) != gSystemUILangId)
  2359. {
  2360. //
  2361. // Delete UI Language key, subkeys and values.
  2362. //
  2363. if ((RegDeleteValue(hKeyMUI, Language) != ERROR_SUCCESS) ||
  2364. (DeleteRegTree(hKeyFileVersions, Language) != ERROR_SUCCESS))
  2365. {
  2366. bRet = FALSE;
  2367. }
  2368. }
  2369. while (*Language++) // go to the next language and repeat
  2370. {
  2371. }
  2372. } // of while (*Language)
  2373. }
  2374. //
  2375. // Clean up
  2376. //
  2377. if (hKeyMUI)
  2378. RegCloseKey(hKeyMUI);
  2379. if (hKeyFileVersions)
  2380. RegCloseKey(hKeyFileVersions);
  2381. return bRet;
  2382. }
  2383. ////////////////////////////////////////////////////////////////////////////////////
  2384. //
  2385. // EnumSelectedLanguages
  2386. //
  2387. // Enumerate the languages marked for installation
  2388. //
  2389. // Return:
  2390. // The total number of MUI languages to be added.
  2391. //
  2392. ////////////////////////////////////////////////////////////////////////////////////
  2393. int EnumSelectedLanguages(HWND hList, LPTSTR lpAddLanguages)
  2394. {
  2395. TCHAR lpMessage[BUFFER_SIZE];
  2396. LONG_PTR lppArgs[3];
  2397. TCHAR szBuffer[BUFFER_SIZE];
  2398. TCHAR *p;
  2399. LPTSTR lpszLcid;
  2400. int iIndex;
  2401. int i = 0;
  2402. PMUILANGINFO pMuiLangInfo;
  2403. int installLangCount = 0;
  2404. iIndex = ListView_GetItemCount(hList);
  2405. *lpAddLanguages=TEXT('\0');
  2406. while(i<iIndex)
  2407. {
  2408. if(ListView_GetCheckState(hList, i))
  2409. {
  2410. GetMuiLangInfoFromListView(hList, i, &pMuiLangInfo);
  2411. lpszLcid = pMuiLangInfo->lpszLcid;
  2412. if (!IsInstalled(lpszLcid) && HaveFiles(lpszLcid))
  2413. {
  2414. _tcscat(lpAddLanguages, lpszLcid);
  2415. _tcscat(lpAddLanguages, TEXT("*"));
  2416. //
  2417. // Count how many languages are being installed/uninstalled for the progress bar
  2418. //
  2419. gNumLanguages++;
  2420. gNumLanguages_Install++;
  2421. installLangCount++;
  2422. }
  2423. }
  2424. i++;
  2425. }
  2426. p = lpAddLanguages;
  2427. while (p=_tcschr(p, TEXT('*')))
  2428. {
  2429. *p=TEXT('\0');
  2430. p++;
  2431. }
  2432. return (installLangCount);
  2433. }
  2434. ////////////////////////////////////////////////////////////////////////////////////
  2435. //
  2436. // EnumUnselectedLanguages
  2437. //
  2438. // Enumerate the languages marked for removal
  2439. //
  2440. // Return:
  2441. // The total number of MUI languages to be added.
  2442. //
  2443. ////////////////////////////////////////////////////////////////////////////////////
  2444. int EnumUnselectedLanguages(HWND hList, LPTSTR lpRemoveLanguages)
  2445. {
  2446. LVITEM FindInfo;
  2447. LPTSTR p;
  2448. LONG_PTR lppArgs[1];
  2449. TCHAR lpMessage[BUFFER_SIZE];
  2450. TCHAR szBuffer[BUFFER_SIZE];
  2451. LPTSTR lpszLcid;
  2452. int iIndex;
  2453. int i = 0;
  2454. PMUILANGINFO pMuiLangInfo;
  2455. int uninstallLangCount = 0;
  2456. iIndex = ListView_GetItemCount(hList);
  2457. *lpRemoveLanguages=TEXT('\0');
  2458. g_bRemoveDefaultUI=FALSE;
  2459. while (i < iIndex)
  2460. {
  2461. if (!ListView_GetCheckState(hList, i))
  2462. {
  2463. GetMuiLangInfoFromListView(hList, i, &pMuiLangInfo);
  2464. lpszLcid = pMuiLangInfo->lpszLcid;
  2465. if (IsInstalled(lpszLcid))
  2466. {
  2467. _tcscat(lpRemoveLanguages, lpszLcid);
  2468. _tcscat(lpRemoveLanguages, TEXT("*"));
  2469. if (GetDotDefaultUILanguage() == pMuiLangInfo->lcid)
  2470. {
  2471. g_bRemoveDefaultUI=TRUE;
  2472. }
  2473. else if (GetUserDefaultUILanguage() == pMuiLangInfo->lcid)
  2474. {
  2475. g_bRemoveUserUI = TRUE;
  2476. }
  2477. //
  2478. // Count how many languages are being installed/uninstalled for the progress bar
  2479. //
  2480. gNumLanguages++;
  2481. gNumLanguages_Uninstall++;
  2482. uninstallLangCount++;
  2483. }
  2484. }
  2485. i++;
  2486. }
  2487. p = lpRemoveLanguages;
  2488. while (p=_tcschr(p, TEXT('*')))
  2489. {
  2490. *p = TEXT('\0');
  2491. p++;
  2492. }
  2493. return (uninstallLangCount);
  2494. }
  2495. ////////////////////////////////////////////////////////////////////////////////////
  2496. //
  2497. // SkipBlanks
  2498. //
  2499. // Skips spaces and tabs in string. Returns pointer to next character
  2500. //
  2501. ////////////////////////////////////////////////////////////////////////////////////
  2502. PTCHAR SkipBlanks(PTCHAR pszText)
  2503. {
  2504. while (*pszText==TEXT(' ') || *pszText==TEXT('\t'))
  2505. {
  2506. pszText++;
  2507. }
  2508. return pszText;
  2509. }
  2510. ////////////////////////////////////////////////////////////////////////////////////
  2511. //
  2512. // NextCommandTag
  2513. //
  2514. // pointing to next command tag (TEXT('-') or TEXT('/')
  2515. //
  2516. ////////////////////////////////////////////////////////////////////////////////////
  2517. LPTSTR NextCommandTag(LPTSTR lpcmd)
  2518. {
  2519. LPTSTR p=NULL;
  2520. if(!lpcmd)
  2521. {
  2522. return (p);
  2523. }
  2524. while(*lpcmd)
  2525. {
  2526. if ((*lpcmd == TEXT('-')) || (*lpcmd == TEXT('/')))
  2527. {
  2528. // Skip to the character after the '-','/'.
  2529. p = lpcmd + 1;
  2530. break;
  2531. }
  2532. lpcmd++;
  2533. }
  2534. return (p);
  2535. }
  2536. ////////////////////////////////////////////////////////////////////////////////////
  2537. //
  2538. // IsInInstallList
  2539. //
  2540. // Check if a target is in the string list
  2541. //
  2542. // Structure of string list:
  2543. //
  2544. // <string 1><NULL><string 2><NULL>......<string n><NULL><NULL>
  2545. //
  2546. ////////////////////////////////////////////////////////////////////////////////////
  2547. BOOL IsInInstallList(LPTSTR lpList,LPTSTR lpTarget)
  2548. {
  2549. BOOL bResult=FALSE;
  2550. if (!lpList || !lpTarget)
  2551. return bResult;
  2552. while (*lpList)
  2553. {
  2554. if (!_tcsicmp(lpList,lpTarget))
  2555. {
  2556. bResult=TRUE;
  2557. break;
  2558. }
  2559. while (*lpList++) // move to next
  2560. {
  2561. }
  2562. }
  2563. return bResult;
  2564. }
  2565. ////////////////////////////////////////////////////////////////////////////////////
  2566. //
  2567. // CreateProgressDialog
  2568. //
  2569. // Globals affected:
  2570. // ghProgDialog
  2571. // ghProgress
  2572. //
  2573. ////////////////////////////////////////////////////////////////////////////////////
  2574. void CreateProgressDialog(HWND hwnd)
  2575. {
  2576. ghProgDialog = CreateDialog(ghInstance,
  2577. MAKEINTRESOURCE(IDD_DIALOG_INSTALL_PROGRESS),
  2578. hwnd,
  2579. ProgressDialogFunc);
  2580. ghProgress = GetDlgItem(ghProgDialog, IDC_PROGRESS1);
  2581. }
  2582. ////////////////////////////////////////////////////////////////////////////////////
  2583. //
  2584. // CheckLanguageGroupInstalled
  2585. // Check if the Language groups for specified languages is installed correctly.
  2586. //
  2587. // Parameters:
  2588. // [IN] lpLanguages The double-null-terminated string which contains the hex LCID
  2589. // strings to be checked.
  2590. // Return:
  2591. // TURE if all the required language packs are installed in the system. Otherwise, FALSE is
  2592. // returned.
  2593. //
  2594. // CheckLanguageGroupInstalled
  2595. // Check if the Language groups for specified languages is installed correctly.
  2596. //
  2597. // Parameters:
  2598. // [IN] lpLanguages The double-null-terminated string which contains the hex LCID
  2599. // strings to be checked.
  2600. // Return:
  2601. // TURE if all the required language packs are installed in the system. Otherwise, FALSE is
  2602. // returned.
  2603. //
  2604. // Remarks:
  2605. // 01-18-2001 YSLin Created.
  2606. ////////////////////////////////////////////////////////////////////////////////////
  2607. BOOL CheckLanguageGroupInstalled(LPTSTR lpLanguages)
  2608. {
  2609. LANGID langID;
  2610. LGRPID lgrpID;
  2611. while (*lpLanguages != TEXT('\0'))
  2612. {
  2613. langID = (LANGID)TransNum(lpLanguages);
  2614. lgrpID = GetLanguageGroup(langID);
  2615. if (!gpfnIsValidLanguageGroup(lgrpID, LGRPID_INSTALLED))
  2616. {
  2617. return (FALSE);
  2618. }
  2619. // Go to the null character.
  2620. lpLanguages = _tcschr(lpLanguages, TEXT('\0'));
  2621. // Skip to next char after the null character.
  2622. lpLanguages++;
  2623. }
  2624. return (TRUE);
  2625. }
  2626. ////////////////////////////////////////////////////////////////////////////////////
  2627. //
  2628. // DoSetup
  2629. //
  2630. // Parameters:
  2631. // hwnd The hwnd of the MUISetup main dialog. Pass null if the muisetup is run from command line.
  2632. // UnistallLangCount The number of languages to be uninstalled.
  2633. // lpUninstall The double-null-terminated string which contains the hex LCID strings for the
  2634. // languages to be uninstalled.
  2635. // installLangGroup
  2636. // InstallLangCount The number of languages to be installed.
  2637. // lpInstall The double-null-terminated string which contains the hex LCID strings for the
  2638. // languages to be installed.
  2639. // lpDefaultUILang The language to be set as system default UI language. Pass NULL if the system default
  2640. // UI language is not changed.
  2641. // fAllowReboot The flag to indicate if this function should check if reboot is necessary.
  2642. // bInteractive TRUE if run in interactive mode, or FALSE if run in silent mode.
  2643. //
  2644. //
  2645. // Return:
  2646. // TRUE if installation is successful. Otherwise FALSE.
  2647. //
  2648. // Notes:
  2649. // This functions serves as the entry point of the real installation process, shared by both the GUI setup
  2650. // and the command line mode setup.
  2651. //
  2652. // There are several steps in doing MUI setup.
  2653. // 1. Uninstall the selected MUI languages.
  2654. // 2. Install the necessary language packs according to the selected MUI languges(if any).
  2655. // 3. Install the selected MUI languages.
  2656. // 4. Change the default UI language.
  2657. // 5. Check for rebooting.
  2658. //
  2659. // Please note that to save space, we do the uninstallation first, then do the installation.
  2660. ////////////////////////////////////////////////////////////////////////////////////
  2661. BOOL DoSetup(
  2662. HWND hwnd,
  2663. int UninstallLangCount, LPTSTR lpUninstall,
  2664. INSTALL_LANG_GROUP installLangGroup,
  2665. int InstallLangCount, LPTSTR lpInstall,
  2666. LPTSTR lpDefaultUILang,
  2667. BOOL fAllowReboot, BOOL bInteractive)
  2668. {
  2669. LONG_PTR lppArgs[3];
  2670. TCHAR lpMessage[BUFFER_SIZE];
  2671. TCHAR lpForceUILang[BUFFER_SIZE];
  2672. TCHAR lpTemp[BUFFER_SIZE];
  2673. TCHAR lpTemp2[BUFFER_SIZE];
  2674. LANGID defaultLangID;
  2675. HCURSOR hCurSave;
  2676. int NotDeleted;
  2677. BOOL bDefaultUIChanged = FALSE;
  2678. LANGID lidSys = GetSystemDefaultLangID();
  2679. BOOL isReboot;
  2680. ghProgDialog = NULL;
  2681. ghProgress = NULL;
  2682. hCurSave=SetCursor(LoadCursor(NULL, IDC_WAIT));
  2683. if(UninstallLangCount > 0)
  2684. {
  2685. CreateProgressDialog(hwnd);
  2686. SendMessage(ghProgress, PBM_SETRANGE, (WPARAM)(int)0, (LPARAM)MAKELPARAM(0, UninstallLangCount * INSTALLED_FILES));
  2687. SendMessage(ghProgress, PBM_SETPOS, (WPARAM)0, 0);
  2688. SetWindowTitleFromResource(ghProgDialog, IDS_UNINSTALL_TITLE);
  2689. //
  2690. // Uninstall MUI languages
  2691. //
  2692. if (!UninstallSelected(lpUninstall, &NotDeleted))
  2693. {
  2694. DestroyWindow(ghProgDialog);
  2695. ghProgDialog = NULL;
  2696. SetCursor(hCurSave);
  2697. return (FALSE);
  2698. }
  2699. SendMessage(ghProgress, PBM_SETPOS, (WPARAM)(UninstallLangCount * INSTALLED_FILES), 0);
  2700. }
  2701. if(InstallLangCount > 0)
  2702. {
  2703. //
  2704. // Install Language Group First
  2705. //
  2706. if (!InstallLanguageGroups(&installLangGroup))
  2707. {
  2708. DestroyWindow(ghProgDialog);
  2709. ghProgDialog = NULL;
  2710. SetCursor(hCurSave);
  2711. return (FALSE);
  2712. }
  2713. //
  2714. // Check if language group in installLangGroup is installed correctly
  2715. //
  2716. if (!CheckLanguageGroupInstalled(lpInstall))
  2717. {
  2718. LogFormattedMessage(NULL, IDS_LG_NOT_INSTALL_L, NULL);
  2719. if (bInteractive)
  2720. {
  2721. DoMessageBox(NULL, IDS_LG_NOT_INSTALL, IDS_MAIN_TITLE, MB_OK);
  2722. }
  2723. return (FALSE);
  2724. }
  2725. //
  2726. // Make sure MUI CD-ROM is put in the CD-ROM drive.
  2727. //
  2728. if(CheckVolumeChange())
  2729. {
  2730. DestroyWindow(ghProgDialog);
  2731. ghProgDialog = NULL;
  2732. SetCursor(hCurSave);
  2733. return (FALSE);
  2734. }
  2735. if (ghProgDialog == NULL)
  2736. {
  2737. CreateProgressDialog(hwnd);
  2738. }
  2739. SendMessage(ghProgress, PBM_SETRANGE, (WPARAM)(int)0, (LPARAM)MAKELPARAM(0, InstallLangCount * INSTALLED_FILES));
  2740. SendMessage(ghProgress, PBM_SETPOS, (WPARAM)0, 0);
  2741. SetWindowTitleFromResource(ghProgDialog, IDS_INSTALL_TITLE);
  2742. if (!InstallSelected(lpInstall,&installLangGroup.bFontLinkRegistryTouched))
  2743. {
  2744. DestroyWindow(ghProgDialog);
  2745. ghProgDialog = NULL;
  2746. SetCursor(hCurSave);
  2747. return (FALSE);
  2748. }
  2749. SendMessage(ghProgress, PBM_SETPOS, (WPARAM)((UninstallLangCount+InstallLangCount) * INSTALLED_FILES), 0);
  2750. }
  2751. DestroyWindow(ghProgDialog);
  2752. ghProgDialog = NULL;
  2753. SetCursor(hCurSave);
  2754. if (UninstallLangCount + InstallLangCount > 0)
  2755. {
  2756. //
  2757. // "Installation Complete"
  2758. // "Installation was completed successfully."
  2759. //
  2760. if (bInteractive)
  2761. {
  2762. DoMessageBox(hwnd, InstallLangCount > 0 ? IDS_MUISETUP_SUCCESS : IDS_MUISETUP_UNINSTALL_SUCCESS, IDS_MAIN_TITLE, MB_OK | MB_DEFBUTTON1);
  2763. }
  2764. }
  2765. //
  2766. // In command line mode, if "/D" is specified, we should ask user to confirm making default UI language change.
  2767. // In command line mode, if "/D" is NOT specified, we should NOT try to change the default UI language.
  2768. // In command line mode, if "/D" & "/S" are specified, we will NOT ask user's confirmation.
  2769. // In GUI mode, we always ask user to confirm making default UI language change.
  2770. //
  2771. //
  2772. // Special case:
  2773. // If the current default UI language is going to be removed and user doesn't choose a new UI language,
  2774. // we will force to set the default UI language to be the system UI language.
  2775. //
  2776. if(g_bRemoveDefaultUI)
  2777. {
  2778. if (!lpDefaultUILang || !(IsInstalled(lpDefaultUILang)))
  2779. {
  2780. _stprintf(lpForceUILang, TEXT("%04x"), gSystemUILangId);
  2781. lpDefaultUILang = lpForceUILang;
  2782. }
  2783. }
  2784. if (lpDefaultUILang)
  2785. {
  2786. defaultLangID = (LANGID)_tcstol(lpDefaultUILang, NULL, 16);
  2787. if (IsInstalled(lpDefaultUILang))
  2788. {
  2789. //
  2790. // If the assigned UI language ID (defaultLangID) is already the default user UI language,
  2791. // we don't do anything. Otherwise, change the default user UI langauge.
  2792. //
  2793. if (defaultLangID != GetDotDefaultUILanguage())
  2794. {
  2795. if (SetUserDefaultLanguage(defaultLangID, FALSE, TRUE))
  2796. {
  2797. bDefaultUIChanged = TRUE;
  2798. } else
  2799. {
  2800. if (bInteractive)
  2801. {
  2802. DoMessageBox(hwnd, IDS_DEFAULT_USER_ERROR, IDS_MAIN_TITLE, (MB_OK | MB_ICONEXCLAMATION));
  2803. }
  2804. }
  2805. } else
  2806. {
  2807. // Do nothing here. I leave this here intentionally to highlight that
  2808. // we don't do antying if the specified defaultLangID is already the default UI language.
  2809. }
  2810. //
  2811. // Make sure registry is set correctly
  2812. //
  2813. if(BST_CHECKED == IsDlgButtonChecked( hwnd, IDC_CHECK_LOCALE ))
  2814. {
  2815. SetMUIRegSetting(MUI_MATCH_LOCALE, TRUE);
  2816. SetMUIRegSetting(MUI_MATCH_UIFONT, BST_CHECKED == IsDlgButtonChecked(hwnd, IDC_CHECK_UIFONT));
  2817. }
  2818. else
  2819. {
  2820. SetMUIRegSetting(MUI_MATCH_LOCALE, FALSE);
  2821. SetMUIRegSetting(MUI_MATCH_UIFONT, FALSE);
  2822. }
  2823. //
  2824. // Notify intl.cpl if we have system locale or UI font setting change
  2825. //
  2826. if ((BST_CHECKED == IsDlgButtonChecked( hwnd, IDC_CHECK_LOCALE) || g_bCmdMatchLocale) &&
  2827. defaultLangID != lidSys)
  2828. {
  2829. TCHAR szCommands[BUFFER_SIZE];
  2830. //
  2831. // Invoke intl.cpl to change system locale to match the default UI language
  2832. //
  2833. wsprintf(szCommands, TEXT("SystemLocale = \"%x\""), defaultLangID);
  2834. //
  2835. // Always reboot if system locale is changed
  2836. //
  2837. if (RunRegionalOptionsApplet(szCommands))
  2838. {
  2839. g_bReboot = TRUE;
  2840. }
  2841. }
  2842. else if (g_bMatchUIFont != (BST_CHECKED == IsDlgButtonChecked(hwnd, IDC_CHECK_UIFONT)) ||
  2843. g_bCmdMatchUIFont)
  2844. {
  2845. TCHAR szCommands[BUFFER_SIZE];
  2846. //
  2847. // Invoke intl.cpl to change system locale to match the default UI language
  2848. //
  2849. wsprintf(szCommands, TEXT("SystemLocale = \"%x\""), lidSys);
  2850. if (RunRegionalOptionsApplet(szCommands) && defaultLangID == MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT))
  2851. {
  2852. // Don't prompt for reboot, intl.cpl will cause muisetup to loose focus if we do so.
  2853. // Need to fix this in XP server release
  2854. // g_bReboot = TRUE;
  2855. }
  2856. }
  2857. } else
  2858. {
  2859. //
  2860. // "ERROR: %1 was not set as the default. It is not installed.\r\nNo default UI language change."
  2861. //
  2862. lppArgs[0] = (LONG_PTR)lpDefaultUILang;
  2863. LogFormattedMessage(NULL, IDS_DEFAULT_L, lppArgs);
  2864. return (FALSE);
  2865. }
  2866. }
  2867. //
  2868. // Check for reboot, and if we are allowed to do so.
  2869. //
  2870. if (fAllowReboot)
  2871. {
  2872. //
  2873. // Check if we need to reboot?
  2874. //
  2875. if (!CheckForReboot(hwnd, &installLangGroup))
  2876. {
  2877. //
  2878. // Check if we recommend a reboot?
  2879. //
  2880. if (bInteractive && bDefaultUIChanged)
  2881. {
  2882. GetLanguageDisplayName(defaultLangID, lpTemp, ARRAYSIZE(lpTemp)-1);
  2883. lppArgs[0] = (LONG_PTR)lpTemp;
  2884. if (lidSys == defaultLangID)
  2885. {
  2886. isReboot = (DoMessageBoxFromResource(hwnd, ghInstance, IDS_CHANGE_UI_NEED_RBOOT, lppArgs, IDS_MAIN_TITLE, MB_YESNO) == IDYES);
  2887. } else
  2888. {
  2889. GetLanguageDisplayName(lidSys, lpTemp2, ARRAYSIZE(lpTemp2)-1);
  2890. lppArgs[1] = (LONG_PTR)lpTemp2;
  2891. isReboot = (DoMessageBoxFromResource(hwnd, ghInstance, IDS_CHANGE_UI_NEED_RBOOT_SYSTEM_LCID, lppArgs, IDS_MAIN_TITLE, MB_YESNO) == IDYES);
  2892. }
  2893. if (isReboot)
  2894. {
  2895. Muisetup_RebootTheSystem();
  2896. }
  2897. }
  2898. }
  2899. }
  2900. return (TRUE);
  2901. }
  2902. int ParseUninstallLangs(LPTSTR p, LPTSTR lpUninstall, int cchUninstall, INT64* pulUISize, INT64* pulLPKSize, INT64* pulSpaceNeed, BOOL* pbLogError)
  2903. {
  2904. int iCopied;
  2905. TCHAR lpBuffer[BUFFER_SIZE];
  2906. LONG_PTR lppArgs[2];
  2907. int cLanguagesToUnInstall = 0;
  2908. LANGID LgId;
  2909. LPTSTR pU = lpUninstall;
  2910. p = SkipBlanks(p);
  2911. iCopied = 0;
  2912. while((*p != TEXT('-')) && (*p != TEXT('/')) && (*p != TEXT('\0')))
  2913. {
  2914. iCopied = CopyArgument(lpBuffer, p);
  2915. if(!HaveFiles(lpBuffer, FALSE))
  2916. {
  2917. //
  2918. // "LOG: %1 was not installed. It is not listed in MUI.INF."
  2919. //
  2920. lppArgs[0] = (LONG_PTR)lpBuffer;
  2921. LogFormattedMessage(NULL, IDS_NOT_LISTED_L, lppArgs);
  2922. *pbLogError = TRUE;
  2923. } else if (!IsInstalled(lpBuffer))
  2924. {
  2925. //
  2926. // "LOG: %1 was not uninstalled, because it is not installed. "
  2927. //
  2928. lppArgs[0] = (LONG_PTR)lpBuffer;
  2929. LogFormattedMessage(NULL, IDS_IS_NOT_INSTALLED_L, lppArgs);
  2930. *pbLogError = TRUE;
  2931. } else if (!IsInInstallList(lpUninstall,lpBuffer))
  2932. {
  2933. iCopied = CopyArgument(pU, p);
  2934. //
  2935. // Check if we are going to remove the current UI language
  2936. //
  2937. LgId = (LANGID)_tcstol(pU, NULL, 16);
  2938. if (LgId == GetDotDefaultUILanguage())
  2939. {
  2940. g_bRemoveDefaultUI = TRUE;
  2941. }
  2942. else if (LgId == GetUserDefaultUILanguage())
  2943. {
  2944. g_bRemoveUserUI = TRUE;
  2945. }
  2946. //
  2947. // Calculate the space required
  2948. //
  2949. GetUIFileSize_commandline(lpBuffer, pulUISize,pulLPKSize);
  2950. *pulSpaceNeed-=*pulUISize;
  2951. pU += iCopied;
  2952. pU++; //skip over NULL
  2953. cLanguagesToUnInstall++;
  2954. }
  2955. p += iCopied;
  2956. p = SkipBlanks(p);
  2957. }
  2958. //
  2959. // Uninstall all MUI languages if there is no language argument after /U
  2960. //
  2961. if (iCopied == 0)
  2962. {
  2963. cLanguagesToUnInstall = GetInstalledMUILanguages(lpUninstall, cchUninstall);
  2964. if (cLanguagesToUnInstall == 0)
  2965. {
  2966. LogFormattedMessage(ghInstance, IDS_NO_MUI_LANG, NULL);
  2967. *pbLogError = TRUE;
  2968. }
  2969. else
  2970. {
  2971. if (0x0409 != GetDotDefaultUILanguage())
  2972. {
  2973. g_bRemoveDefaultUI = TRUE;
  2974. }
  2975. if (0x0409 != GetUserDefaultUILanguage())
  2976. {
  2977. g_bRemoveUserUI = TRUE;
  2978. }
  2979. }
  2980. }
  2981. else
  2982. {
  2983. *pU=TEXT('\0');
  2984. }
  2985. return (cLanguagesToUnInstall);
  2986. }
  2987. ////////////////////////////////////////////////////////////////////////////
  2988. //
  2989. // GetCDNameFromLang
  2990. //
  2991. // Given a langange ID (in hex string), return the CD name where the language
  2992. // installation folder exist.
  2993. // This can also be used to check if the language is supported MUI language.
  2994. //
  2995. // Parameters:
  2996. // [IN] lpLangName the language to be installed in hex string.
  2997. // [OUT] lpCDName the number of the CD (e.g. "2" or "3").
  2998. // [IN] nCDNameSize the size of lpCDName, in TCHAR.
  2999. //
  3000. // Return Values:
  3001. // TRUE if lpLangName is a supported MUI language. lpCDName will contain
  3002. // the name of the CD.
  3003. // FALSE if the language ID is not a supported langauge. lpCDNAme will be
  3004. // empty string.
  3005. //
  3006. // Remarks:
  3007. //
  3008. // 01-01-2001 YSLin Created.
  3009. //
  3010. ////////////////////////////////////////////////////////////////////////////
  3011. BOOL GetCDNameFromLang(LPTSTR lpLangName, LPTSTR lpCDName, int nCDNameSize)
  3012. {
  3013. if (!GetPrivateProfileString(
  3014. MUI_CDLAYOUT_SECTION,
  3015. lpLangName,
  3016. TEXT(""),
  3017. lpCDName,
  3018. nCDNameSize,
  3019. g_szMUIInfoFilePath))
  3020. {
  3021. return (FALSE);
  3022. }
  3023. return (TRUE);
  3024. }
  3025. ////////////////////////////////////////////////////////////////////////////////////
  3026. //
  3027. // ParseCommandLine
  3028. //
  3029. // Runs installation functions with command line specifications
  3030. //
  3031. ////////////////////////////////////////////////////////////////////////////////////
  3032. BOOL ParseCommandLine(LPTSTR lpCommandLine)
  3033. {
  3034. BOOL bSetDefaultUI=FALSE; // Specify if the /D switch is used to change the user default UI language.
  3035. BOOL bInstall=FALSE;
  3036. BOOL bLogError=FALSE;
  3037. BOOL bFELangpackAdded=FALSE;
  3038. DWORD dwDisp;
  3039. LANGID LgId;
  3040. TCHAR lpBuffer[BUFFER_SIZE];
  3041. TCHAR lpDefault[BUFFER_SIZE];
  3042. TCHAR lpDefaultText[MAX_PATH];
  3043. TCHAR lpInstall[BUFFER_SIZE];
  3044. TCHAR lpMessage[BUFFER_SIZE];
  3045. TCHAR lpUninstall[BUFFER_SIZE];
  3046. TCHAR lpSystemDefault[BUFFER_SIZE];
  3047. TCHAR lpTemp[BUFFER_SIZE];
  3048. TCHAR szWinDir[MAX_PATH];
  3049. INSTALL_LANG_GROUP installLangGroup;
  3050. LONG_PTR lppArgs[4];
  3051. PTCHAR pI;
  3052. PTCHAR pD;
  3053. PTCHAR p;
  3054. BOOL fAllowReboot = TRUE,bLGInstalled=FALSE;
  3055. int cLanguagesToInstall = 0L;
  3056. int cLanguagesToUnInstall = 0L;
  3057. int iCopied;
  3058. TCHAR chOpt;
  3059. INT64 ulSpaceNeed=0,ulSpaceAvailable=0,ulUISize=0,ulLPKSize=0;
  3060. ULONG ulParam[2];
  3061. ULARGE_INTEGER ulgiFreeBytesAvailableToCaller;
  3062. ULARGE_INTEGER ulgiTotalNumberOfBytes;
  3063. BOOL bHasLangArgs = FALSE;
  3064. BOOL bHelpDisplayed=FALSE;
  3065. TCHAR lpCDName[BUFFER_SIZE];
  3066. //
  3067. // Initialize Lang-Groups to install
  3068. //
  3069. installLangGroup.iCount = 0L;
  3070. installLangGroup.NotDeleted = 0L;
  3071. installLangGroup.bFontLinkRegistryTouched = FALSE;
  3072. lpInstall[0] = TEXT('\0');
  3073. lpUninstall[0] = TEXT('\0');
  3074. lpDefault[0] = TEXT('\0');
  3075. pI = lpInstall;
  3076. pD = lpDefault;
  3077. p = lpCommandLine;
  3078. CharLower(p);
  3079. while(p=NextCommandTag(p))
  3080. {
  3081. chOpt = *p++;
  3082. switch (chOpt)
  3083. {
  3084. case '?':
  3085. case 'h':
  3086. if (!bHelpDisplayed)
  3087. {
  3088. DisplayHelpWindow();
  3089. bHelpDisplayed=TRUE;
  3090. }
  3091. p = SkipBlanks(p);
  3092. break;
  3093. case 'i':
  3094. if (!FileExists(g_szMUIInfoFilePath))
  3095. {
  3096. //
  3097. // "The file MUI.INF cannot be found."
  3098. //
  3099. DoMessageBox(NULL, IDS_NO_MUI_FILE, IDS_MAIN_TITLE, MB_OK | MB_DEFBUTTON1);
  3100. break;
  3101. }
  3102. //
  3103. // MUI version needs to match OS version
  3104. //
  3105. if (!checkversion(TRUE))
  3106. {
  3107. DoMessageBox(NULL, IDS_WRONG_VERSION, IDS_MAIN_TITLE, MB_OK | MB_DEFBUTTON1);
  3108. break;
  3109. }
  3110. p = SkipBlanks(p);
  3111. while ((*p != TEXT('-')) && (*p != TEXT('/')) && (*p != TEXT('\0')))
  3112. {
  3113. bHasLangArgs = TRUE;
  3114. iCopied=CopyArgument(lpBuffer, p);
  3115. if (!IsInstalled(lpBuffer) &&
  3116. CheckLanguageIsQualified(lpBuffer) &&
  3117. HaveFiles(lpBuffer) && (!IsInInstallList(lpInstall,lpBuffer)) )
  3118. {
  3119. //
  3120. // Calculate the space required
  3121. //
  3122. GetUIFileSize_commandline(lpBuffer, &ulUISize,&ulLPKSize);
  3123. ulSpaceNeed+=ulUISize;
  3124. if(CheckLangGroupCommandLine(&installLangGroup, lpBuffer))
  3125. {
  3126. if (IS_FE_LANGPACK(_tcstol(lpBuffer, NULL, 16)))
  3127. {
  3128. if (!bFELangpackAdded)
  3129. {
  3130. ulSpaceNeed+=ulLPKSize;
  3131. bFELangpackAdded = TRUE;
  3132. }
  3133. }else
  3134. {
  3135. ulSpaceNeed+=ulLPKSize;
  3136. }
  3137. }
  3138. AddExtraLangGroupsFromINF(lpBuffer, &installLangGroup);
  3139. iCopied=CopyArgument(pI, p);
  3140. pI += iCopied;
  3141. pI++; //skip over NULL
  3142. bInstall = TRUE;
  3143. cLanguagesToInstall++;
  3144. }
  3145. else
  3146. {
  3147. lppArgs[0]=(LONG_PTR)lpBuffer;
  3148. if(IsInstalled(lpBuffer)|| IsInInstallList(lpInstall,lpBuffer))
  3149. {
  3150. // "LOG: %1 was not installed, because it is already installed. "
  3151. LogFormattedMessage(ghInstance, IDS_IS_INSTALLED_L, lppArgs);
  3152. }
  3153. if(!HaveFiles(lpBuffer))
  3154. {
  3155. if (!GetCDNameFromLang(lpBuffer, lpCDName, ARRAYSIZE(lpCDName)))
  3156. {
  3157. // lpBuffer is not a supported MUI language.
  3158. // "LOG: %1 was not installed, because it is not listed in MUI.INF. Please check if it is a valid UI language ID."
  3159. LogFormattedMessage(ghInstance, IDS_NOT_LISTED_L, lppArgs);
  3160. } else
  3161. {
  3162. // lpBuffer is a supported MUI language, ask user to change CD and
  3163. // rerun setup.
  3164. LoadString(ghInstance, IDS_CHANGE_CDROM, lpTemp, ARRAYSIZE(lpTemp)-1);
  3165. lppArgs[1] = (LONG_PTR)lpTemp;
  3166. lppArgs[2] = (LONG_PTR)lpCDName;
  3167. // "ERROR: %1 was not installed, because it is located in %2 %3. Please insert that CD and rerun MUISetup."
  3168. LogFormattedMessage(ghInstance, IDS_LANG_IN_ANOTHER_CD_L, lppArgs);
  3169. }
  3170. }
  3171. if(!CheckLanguageIsQualified(lpBuffer))
  3172. {
  3173. // "LOG: %1 was not installed, because it cannot be installed on this platform\n"
  3174. LogFormattedMessage(ghInstance, IDS_NOT_QUALIFIED_L, lppArgs);
  3175. }
  3176. bLogError = TRUE;
  3177. }
  3178. p += iCopied;
  3179. p = SkipBlanks(p);
  3180. }
  3181. if (!bHasLangArgs)
  3182. {
  3183. lppArgs[0] = (LONG_PTR)TEXT("/I");
  3184. FormatStringFromResource(lpMessage, sizeof(lpMessage)/sizeof(TCHAR), ghInstance, IDS_ERROR_NO_LANG_ARG, lppArgs);
  3185. LogMessage(lpMessage);
  3186. bLogError = TRUE;
  3187. }
  3188. *pI = TEXT('\0');
  3189. break;
  3190. case 'u':
  3191. if (!checkversion(FALSE))
  3192. {
  3193. DoMessageBox(NULL, IDS_WRONG_VERSION, IDS_MAIN_TITLE, MB_OK | MB_DEFBUTTON1);
  3194. break;
  3195. }
  3196. cLanguagesToUnInstall = ParseUninstallLangs(p, lpUninstall, ARRAYSIZE(lpUninstall), &ulUISize, &ulLPKSize, &ulSpaceNeed, &bLogError);
  3197. break;
  3198. case 'd':
  3199. if (!checkversion(FALSE))
  3200. {
  3201. DoMessageBox(NULL, IDS_WRONG_VERSION, IDS_MAIN_TITLE, MB_OK | MB_DEFBUTTON1);
  3202. break;
  3203. }
  3204. bSetDefaultUI = TRUE;
  3205. p = SkipBlanks(p);
  3206. if (CopyArgument(lpDefault, p) == 0)
  3207. {
  3208. lppArgs[0] = (LONG_PTR)TEXT("/D");
  3209. FormatStringFromResource(lpMessage, sizeof(lpMessage)/sizeof(TCHAR),
  3210. ghInstance, IDS_ERROR_NO_LANG_ARG, lppArgs);
  3211. LogMessage(lpMessage);
  3212. bLogError = TRUE;
  3213. }
  3214. break;
  3215. case 'r':
  3216. fAllowReboot = FALSE;
  3217. break;
  3218. case 's' :
  3219. g_bSilent = TRUE;
  3220. break;
  3221. case 'l':
  3222. g_bCmdMatchLocale = TRUE;
  3223. break;
  3224. case 'f':
  3225. g_bCmdMatchUIFont = TRUE;
  3226. break;
  3227. // Internal, MSI uses this switch to call out external MUI APIs
  3228. case 'e':
  3229. {
  3230. TCHAR szLanguages[32] = {0};
  3231. p = SkipBlanks(p);
  3232. if (CopyArgument(szLanguages, p))
  3233. {
  3234. InstallExternalComponents(szLanguages);
  3235. }
  3236. break;
  3237. }
  3238. // Internal, MSI uses this switch to call out external MUI APIs
  3239. case 'm':
  3240. {
  3241. TCHAR szLanguages[32] = {0};
  3242. p = SkipBlanks(p);
  3243. if (CopyArgument(szLanguages, p))
  3244. {
  3245. UninstallExternalComponents(szLanguages);
  3246. }
  3247. break;
  3248. }
  3249. }
  3250. }
  3251. //
  3252. // UI Font depends on system locale
  3253. //
  3254. if (!g_bCmdMatchLocale && g_bCmdMatchUIFont)
  3255. {
  3256. g_bCmdMatchUIFont = FALSE;
  3257. }
  3258. //
  3259. // Check the disk space
  3260. //
  3261. //
  3262. pfnGetWindowsDir( szWinDir, MAX_PATH);
  3263. szWinDir[3]=TEXT('\0');
  3264. if (GetDiskFreeSpaceEx(szWinDir,
  3265. &ulgiFreeBytesAvailableToCaller,
  3266. &ulgiTotalNumberOfBytes,
  3267. NULL))
  3268. {
  3269. ulSpaceAvailable= ulgiFreeBytesAvailableToCaller.QuadPart;
  3270. if ( ulSpaceAvailable < ulSpaceNeed )
  3271. {
  3272. ulParam[0] = (ULONG) (ulSpaceNeed/1024);
  3273. ulParam[1] = (ULONG) (ulSpaceAvailable/1024);
  3274. LoadString(ghInstance, IDS_DISKSPACE_NOTENOUGH, lpMessage, ARRAYSIZE(lpMessage)-1);
  3275. LoadString(ghInstance, IDS_ERROR_DISKSPACE, lpTemp, ARRAYSIZE(lpTemp)-1);
  3276. FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  3277. lpMessage,
  3278. 0,
  3279. 0,
  3280. lpMessage,
  3281. ARRAYSIZE(lpMessage)-1,
  3282. (va_list *) ulParam);
  3283. LogMessage(lpMessage);
  3284. bLogError = TRUE;
  3285. MESSAGEBOX(NULL, lpMessage, lpTemp, MB_OK | MB_DEFBUTTON1 | MB_ICONWARNING);
  3286. bInstall = FALSE;
  3287. cLanguagesToUnInstall = 0;
  3288. }
  3289. }
  3290. if (!bLogError)
  3291. {
  3292. //
  3293. // Let's set the default UI language
  3294. //
  3295. if (!DoSetup(
  3296. NULL,
  3297. cLanguagesToUnInstall, lpUninstall,
  3298. installLangGroup,
  3299. cLanguagesToInstall, lpInstall,
  3300. (bSetDefaultUI ? lpDefault : NULL),
  3301. fAllowReboot, !g_bSilent))
  3302. {
  3303. bLogError = TRUE;
  3304. }
  3305. }
  3306. if (bLogError && !g_bSilent)
  3307. {
  3308. //
  3309. // "Installation Error"
  3310. // "One or more errors occurred during installation.
  3311. // Please see %1\muisetup.log for more information."
  3312. //
  3313. lppArgs[0] = (LONG_PTR)szWindowsDir;
  3314. DoMessageBoxFromResource(NULL, ghInstance, IDS_ERROR, lppArgs, IDS_ERROR_T, MB_OK | MB_DEFBUTTON1 | MB_ICONWARNING);
  3315. }
  3316. return TRUE;
  3317. }
  3318. ////////////////////////////////////////////////////////////////////////////////////
  3319. //
  3320. // DisplayHelpWindow
  3321. //
  3322. // Displays help window for command line version
  3323. //
  3324. ////////////////////////////////////////////////////////////////////////////////////
  3325. void DisplayHelpWindow()
  3326. {
  3327. STARTUPINFO si;
  3328. PROCESS_INFORMATION pi;
  3329. TCHAR Appname[MAX_PATH+MAX_PATH+1];
  3330. if (FileExists(g_szMUIHelpFilePath))
  3331. {
  3332. wsprintf(Appname,TEXT("winhlp32.exe -n%d %s"),IDH_MUISETUP_COMMANDLINE,g_szMUIHelpFilePath);
  3333. memset( &si, 0x00, sizeof(si));
  3334. si.cb = sizeof(STARTUPINFO);
  3335. if (!CreateProcess(NULL,
  3336. Appname,
  3337. NULL,
  3338. NULL,
  3339. FALSE,
  3340. 0L,
  3341. NULL, NULL,
  3342. &si,
  3343. &pi) )
  3344. return;
  3345. WaitForSingleObject(pi.hProcess, INFINITE);
  3346. }
  3347. else
  3348. {
  3349. //////////////////////////////////////////////
  3350. // MessageBox should be changed to Dialog
  3351. //////////////////////////////////////////////
  3352. DoMessageBox(NULL, IDS_HELP, IDS_HELP_T, MB_OK | MB_DEFBUTTON1);
  3353. }
  3354. }
  3355. ////////////////////////////////////////////////////////////////////////////////////
  3356. //
  3357. // CopyArgument
  3358. //
  3359. // Copies command line argument pointed to by src to dest
  3360. //
  3361. ////////////////////////////////////////////////////////////////////////////////////
  3362. int CopyArgument(LPTSTR dest, LPTSTR src)
  3363. {
  3364. int i=0;
  3365. while(*src!=TEXT(' ') && *src!=TEXT('\0'))
  3366. {
  3367. *dest=*src;
  3368. dest++;
  3369. src++;
  3370. i++;
  3371. }
  3372. *dest = TEXT('\0');
  3373. return i;
  3374. }
  3375. ////////////////////////////////////////////////////////////////////////////////////
  3376. //
  3377. // IsInstalled
  3378. //
  3379. // Checks to see if lpArg is a language installed in the registry
  3380. //
  3381. ////////////////////////////////////////////////////////////////////////////////////
  3382. BOOL IsInstalled(LPTSTR lpArg)
  3383. {
  3384. HKEY hKey;
  3385. DWORD dwData;
  3386. DWORD dwIndex;
  3387. DWORD dwValue;
  3388. TCHAR lpData[BUFFER_SIZE];
  3389. TCHAR lpValue[BUFFER_SIZE];
  3390. int rc;
  3391. int iArg;
  3392. hKey=OpenMuiKey(KEY_READ);
  3393. if (hKey == NULL)
  3394. {
  3395. return (FALSE);
  3396. }
  3397. dwIndex=0;
  3398. rc=ERROR_SUCCESS;
  3399. iArg=_tcstol(lpArg, NULL, 16);
  3400. if (iArg == gSystemUILangId)
  3401. {
  3402. return (TRUE);
  3403. }
  3404. while(rc==ERROR_SUCCESS)
  3405. {
  3406. dwValue=sizeof(lpValue)/sizeof(TCHAR);
  3407. lpValue[0]=TEXT('\0');
  3408. dwData=sizeof(lpData);
  3409. lpData[0]=TEXT('\0');
  3410. DWORD dwType;
  3411. rc=RegEnumValue(hKey, dwIndex, lpValue, &dwValue, 0, &dwType, (LPBYTE)lpData, &dwData);
  3412. if(rc==ERROR_SUCCESS)
  3413. {
  3414. if (dwType != REG_SZ)
  3415. {
  3416. dwIndex++;
  3417. continue;
  3418. }
  3419. if(_tcstol(lpValue, NULL, 16)==iArg)
  3420. {
  3421. RegCloseKey(hKey);
  3422. return TRUE;
  3423. }
  3424. }
  3425. dwIndex++;
  3426. }
  3427. RegCloseKey(hKey);
  3428. return FALSE;
  3429. }
  3430. ////////////////////////////////////////////////////////////////////////////////////
  3431. //
  3432. // GetInstalledMUILanguages
  3433. //
  3434. // Get installed MUI languages, dump it to lpUninstall buffer in a MULTI_SZ format
  3435. //
  3436. ////////////////////////////////////////////////////////////////////////////////////
  3437. DWORD GetInstalledMUILanguages(LPTSTR lpUninstall, int cch)
  3438. {
  3439. HKEY hKey;
  3440. DWORD dwIndex = 0;
  3441. DWORD dwCount = 0;
  3442. DWORD dwValue = cch;
  3443. DWORD dwType;
  3444. if (hKey = OpenMuiKey(KEY_READ))
  3445. {
  3446. while(ERROR_NO_MORE_ITEMS != RegEnumValue(hKey, dwIndex++, lpUninstall, &dwValue, 0, &dwType, NULL, NULL) &&
  3447. cch > 0)
  3448. {
  3449. if (dwType != REG_SZ)
  3450. continue;
  3451. if (_tcstol(lpUninstall, NULL, 16) != gSystemUILangId)
  3452. {
  3453. //
  3454. // Count in NULL
  3455. //
  3456. dwValue++;
  3457. lpUninstall += dwValue;
  3458. cch -= dwValue;
  3459. dwCount++;
  3460. }
  3461. dwValue = cch;
  3462. }
  3463. RegCloseKey(hKey);
  3464. *lpUninstall = TEXT('\0');
  3465. }
  3466. return dwCount;
  3467. }
  3468. ////////////////////////////////////////////////////////////////////////////////////
  3469. //
  3470. // HaveFiles
  3471. //
  3472. // Checks that the language in lpBuffer is in MUI.INF
  3473. //
  3474. ////////////////////////////////////////////////////////////////////////////////////
  3475. BOOL HaveFiles(LPTSTR lpBuffer, BOOL bCheckDir)
  3476. {
  3477. LPTSTR lpLanguages;
  3478. TCHAR lpMessage[BUFFER_SIZE];
  3479. TCHAR tchBuffer[BUFFER_SIZE];
  3480. lpLanguages = tchBuffer;
  3481. if (EnumLanguages(lpLanguages, bCheckDir) == 0)
  3482. {
  3483. //
  3484. // "LOG: No languages found in MUI.INF"
  3485. //
  3486. LoadString(ghInstance, IDS_NO_LANG_L, lpMessage, ARRAYSIZE(lpMessage)-1);
  3487. LogMessage(lpMessage);
  3488. return FALSE;
  3489. }
  3490. while (*lpLanguages != TEXT('\0'))
  3491. {
  3492. if (_tcscmp(lpBuffer, lpLanguages) == 0)
  3493. {
  3494. return TRUE;
  3495. }
  3496. lpLanguages = _tcschr(lpLanguages, '\0');
  3497. lpLanguages++;
  3498. }
  3499. return FALSE;
  3500. }
  3501. ////////////////////////////////////////////////////////////////////////////////////
  3502. //
  3503. // OpenLogFile
  3504. //
  3505. // Opens the setup log for writing
  3506. //
  3507. ////////////////////////////////////////////////////////////////////////////////////
  3508. HANDLE OpenLogFile()
  3509. {
  3510. DWORD dwSize;
  3511. DWORD dwUnicodeHeader;
  3512. HANDLE hFile;
  3513. SECURITY_ATTRIBUTES SecurityAttributes;
  3514. TCHAR lpPath[BUFFER_SIZE];
  3515. int error;
  3516. pfnGetWindowsDir(lpPath, MAX_PATH);
  3517. error=GetLastError();
  3518. _tcscat(lpPath, LOG_FILE);
  3519. SecurityAttributes.nLength=sizeof(SecurityAttributes);
  3520. SecurityAttributes.lpSecurityDescriptor=NULL;
  3521. SecurityAttributes.bInheritHandle=FALSE;
  3522. hFile=CreateFile(
  3523. lpPath,
  3524. GENERIC_WRITE,
  3525. 0,
  3526. &SecurityAttributes,
  3527. OPEN_ALWAYS,
  3528. FILE_ATTRIBUTE_NORMAL,
  3529. NULL);
  3530. #ifdef UNICODE
  3531. //
  3532. // If the file did not already exist, add the unicode header
  3533. //
  3534. if(GetLastError()==0)
  3535. {
  3536. dwUnicodeHeader=0xFEFF;
  3537. WriteFile(hFile, &dwUnicodeHeader, 2, &dwSize, NULL);
  3538. }
  3539. #endif
  3540. error=GetLastError();
  3541. return hFile;
  3542. }
  3543. ////////////////////////////////////////////////////////////////////////////////////
  3544. //
  3545. // LogMessage
  3546. //
  3547. // Writes lpMessage to the setup log
  3548. //
  3549. ////////////////////////////////////////////////////////////////////////////////////
  3550. BOOL LogMessage(LPCTSTR lpMessage)
  3551. {
  3552. DWORD dwBytesWritten;
  3553. HANDLE hFile;
  3554. hFile=OpenLogFile();
  3555. if(hFile==INVALID_HANDLE_VALUE)
  3556. {
  3557. return FALSE;
  3558. }
  3559. SetFilePointer(hFile, 0, NULL, FILE_END);
  3560. WriteFile(
  3561. hFile,
  3562. lpMessage,
  3563. _tcslen(lpMessage) * sizeof(TCHAR),
  3564. &dwBytesWritten,
  3565. NULL);
  3566. SetFilePointer(hFile, 0, NULL, FILE_END);
  3567. WriteFile(
  3568. hFile,
  3569. TEXT("\r\n"),
  3570. _tcslen(TEXT("\r\n")) * sizeof(TCHAR),
  3571. &dwBytesWritten,
  3572. NULL);
  3573. CloseHandle(hFile);
  3574. return TRUE;
  3575. }
  3576. ////////////////////////////////////////////////////////////////////////////////////
  3577. //
  3578. // LogFormattedMessage
  3579. //
  3580. // Writes a formatted lpMessage to the setup log
  3581. //
  3582. ////////////////////////////////////////////////////////////////////////////////////
  3583. BOOL LogFormattedMessage(HINSTANCE hInstance, int messageID, LONG_PTR* lppArgs)
  3584. {
  3585. TCHAR szBuffer[BUFFER_SIZE];
  3586. LoadString(hInstance, messageID, szBuffer, sizeof(szBuffer)/sizeof(TCHAR));
  3587. if (lppArgs == NULL)
  3588. {
  3589. return (LogMessage(szBuffer));
  3590. }
  3591. FormatMessage(
  3592. FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  3593. szBuffer,
  3594. 0,
  3595. 0,
  3596. szBuffer,
  3597. sizeof(szBuffer) / sizeof(TCHAR),
  3598. (va_list *)lppArgs);
  3599. return (LogMessage(szBuffer));
  3600. }
  3601. ////////////////////////////////////////////////////////////////////////////
  3602. //
  3603. // FormatStringFromResource
  3604. //
  3605. // Format a string using the format specified in the resource and the
  3606. // specified arguments.
  3607. //
  3608. // Parameters:
  3609. //
  3610. // Return Values:
  3611. // the formatted string.
  3612. //
  3613. // Remarks:
  3614. //
  3615. // 08-07-2000 YSLin Created.
  3616. //
  3617. ////////////////////////////////////////////////////////////////////////////
  3618. LPTSTR FormatStringFromResource(LPTSTR pszBuffer, UINT bufferSize, HMODULE hInstance, int messageID, LONG_PTR* lppArgs)
  3619. {
  3620. TCHAR szFormatStr[BUFFER_SIZE];
  3621. LoadString(hInstance, messageID, szFormatStr, ARRAYSIZE(szFormatStr)-1);
  3622. FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  3623. szFormatStr,
  3624. 0,
  3625. 0,
  3626. pszBuffer,
  3627. bufferSize ,
  3628. (va_list *)lppArgs);
  3629. return (pszBuffer);
  3630. }
  3631. ////////////////////////////////////////////////////////////////////////////////////
  3632. //
  3633. // BeginLog
  3634. //
  3635. // Writes a header to the setup log
  3636. //
  3637. ////////////////////////////////////////////////////////////////////////////////////
  3638. void BeginLog(void)
  3639. {
  3640. TCHAR lpMessage[BUFFER_SIZE];
  3641. //
  3642. // "**********************************************************
  3643. // Language Module Installation Log
  3644. // **********************************************************" (LOG)
  3645. //
  3646. LoadString(ghInstance, IDS_LOG_HEAD, lpMessage, ARRAYSIZE(lpMessage)-1);
  3647. LogMessage(lpMessage);
  3648. }
  3649. ////////////////////////////////////////////////////////////////////////////////////
  3650. //
  3651. // GetLanguageGroup
  3652. //
  3653. // Retreive the Language Group of this locale.
  3654. //
  3655. ////////////////////////////////////////////////////////////////////////////////////
  3656. LGRPID GetLanguageGroup(LCID lcid)
  3657. {
  3658. int i;
  3659. gLangGroup = LGRPID_WESTERN_EUROPE;
  3660. gFoundLangGroup = FALSE;
  3661. gLCID = lcid;
  3662. for (i=0 ; i<gNumLanguageGroups; i++)
  3663. {
  3664. // The globals gLangGroup and gFoundLangGroup is used in the callback function
  3665. // EnumLanguageGroupLocalesProc.
  3666. gpfnEnumLanguageGroupLocalesW(EnumLanguageGroupLocalesProc, gLanguageGroups[i], 0L, 0L);
  3667. //
  3668. // If we found it, then break now
  3669. //
  3670. if (gFoundLangGroup)
  3671. break;
  3672. }
  3673. return gLangGroup;
  3674. }
  3675. BOOL EnumLanguageGroupLocalesProc(
  3676. LGRPID langGroupId,
  3677. LCID lcid,
  3678. LPTSTR lpszLocale,
  3679. LONG_PTR lParam)
  3680. {
  3681. if (lcid == gLCID)
  3682. {
  3683. gLangGroup = langGroupId;
  3684. gFoundLangGroup = TRUE;
  3685. // stop iterating
  3686. return FALSE;
  3687. }
  3688. // next iteration
  3689. return TRUE;
  3690. }
  3691. ////////////////////////////////////////////////////////////////////////////////////
  3692. //
  3693. // DetectLanguageGroups
  3694. //
  3695. // Detect language groups installed.
  3696. //
  3697. ////////////////////////////////////////////////////////////////////////////////////
  3698. BOOL DetectLanguageGroups(HWND hwndDlg)
  3699. {
  3700. int i, iItems;
  3701. HWND hwndList = GetDlgItem(hwndDlg, IDC_LIST1);
  3702. HWND hwndProgress, hwndStatus,hProgDlg;
  3703. int iCount = ListView_GetItemCount(hwndList);
  3704. LVITEM lvItem;
  3705. PMUILANGINFO pMuiLangInfo;
  3706. TCHAR szBuf[MAX_PATH], szStatus[MAX_PATH];
  3707. PVOID ppArgs[1];
  3708. hProgDlg = CreateDialog(ghInstance,
  3709. MAKEINTRESOURCE(IDD_DIALOG_INSTALL_PROGRESS),
  3710. hwndDlg,
  3711. ProgressDialogFunc);
  3712. hwndProgress = GetDlgItem(hProgDlg, IDC_PROGRESS1);
  3713. hwndStatus = GetDlgItem(hProgDlg, IDC_STATUS);
  3714. //
  3715. // Reflect that we doing something on the UI
  3716. //
  3717. LoadString(ghInstance, IDS_INSTALLLANGGROUP, szBuf, MAX_PATH-1);
  3718. SetWindowText(hProgDlg, szBuf);
  3719. SendMessage(hwndProgress, PBM_SETRANGE, (WPARAM)(int)0, (LPARAM)MAKELPARAM(0, iCount));
  3720. SendMessage(hwndProgress, PBM_SETPOS, (WPARAM)(int)(0), 0);
  3721. SetWindowText(hwndStatus, TEXT(""));
  3722. i = 0;
  3723. while (i < iCount)
  3724. {
  3725. //
  3726. // Check if Language Group is installed
  3727. //
  3728. lvItem.mask = LVIF_PARAM;
  3729. lvItem.iItem = i;
  3730. lvItem.iSubItem = 0;
  3731. lvItem.state = 0;
  3732. lvItem.stateMask = 0;
  3733. lvItem.pszText = 0;
  3734. lvItem.cchTextMax = 0;
  3735. lvItem.iImage = 0;
  3736. lvItem.lParam = 0;
  3737. ListView_GetItem(hwndList, &lvItem);
  3738. pMuiLangInfo = (PMUILANGINFO)lvItem.lParam;
  3739. SendMessage(hwndProgress, PBM_SETPOS, (WPARAM)(int)i+1, 0L);
  3740. LoadString(ghInstance, IDS_CHECK_LANG_GROUP, szStatus, MAX_PATH-1);
  3741. if (pMuiLangInfo->szDisplayName[0] == L'\0')
  3742. {
  3743. GetDisplayName(pMuiLangInfo);
  3744. }
  3745. ppArgs[0] = pMuiLangInfo->szDisplayName;
  3746. FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  3747. szStatus,
  3748. 0,
  3749. 0,
  3750. szStatus,
  3751. MAX_PATH-1,
  3752. (va_list *)ppArgs);
  3753. SetWindowText(hwndStatus, szStatus);
  3754. pMuiLangInfo->lgrpid = GetLanguageGroup(pMuiLangInfo->lcid);
  3755. i++;
  3756. };
  3757. SendMessage(hwndProgress, PBM_SETPOS, (WPARAM)(int)i+1, 0L);
  3758. DestroyWindow(hProgDlg);
  3759. return TRUE;
  3760. }
  3761. ////////////////////////////////////////////////////////////////////////////////////
  3762. //
  3763. // AddExtraLangGroupsFromINF
  3764. //
  3765. // Look at the [LanguagePack] section to see if we need to install extra
  3766. // language packs for the language specified in lpszLcid.
  3767. //
  3768. // This is basically used to support pseudo localized build.
  3769. //
  3770. // Parameter:
  3771. // lpszLcid the LCID of UI language to be installed in string form.
  3772. // pInstallLangGroup points to a strcutre which stores language groups to be installed.
  3773. //
  3774. // Remarks:
  3775. //
  3776. // 10-11-2000 YSLin Created.
  3777. ////////////////////////////////////////////////////////////////////////////////////
  3778. BOOL AddExtraLangGroupsFromINF(LPTSTR lpszLcid, PINSTALL_LANG_GROUP pInstallLangGroup)
  3779. {
  3780. WCHAR szBuffer[BUFFER_SIZE];
  3781. HINF hInf;
  3782. INFCONTEXT InfContext;
  3783. LONG_PTR lppArgs[2];
  3784. int LangGroup;
  3785. int i;
  3786. hInf = SetupOpenInfFile(g_szMUIInfoFilePath, NULL, INF_STYLE_WIN4, NULL);
  3787. if (hInf == INVALID_HANDLE_VALUE)
  3788. {
  3789. _stprintf(szBuffer, TEXT("%d"), GetLastError());
  3790. lppArgs[0] = (LONG_PTR)szBuffer;
  3791. LogFormattedMessage(ghInstance, IDS_NO_READ_L, lppArgs);
  3792. return (FALSE);
  3793. }
  3794. if (SetupFindFirstLine(hInf, MUI_LANGPACK_SECTION, lpszLcid, &InfContext))
  3795. {
  3796. i = 1;
  3797. while (SetupGetIntField(&InfContext, i++, &LangGroup))
  3798. {
  3799. AddMUILangGroup(pInstallLangGroup, LangGroup);
  3800. }
  3801. }
  3802. SetupCloseInfFile(hInf);
  3803. return (TRUE);
  3804. }
  3805. ////////////////////////////////////////////////////////////////////////////////////
  3806. //
  3807. // ConvertMUILangToLangGroup
  3808. //
  3809. // Generate Lang-Group IDs for the selected items in the listview,
  3810. // in preparation to pass them to InstallLanguageGroups(...)
  3811. ////////////////////////////////////////////////////////////////////////////////////
  3812. BOOL ConvertMUILangToLangGroup(HWND hwndDlg, PINSTALL_LANG_GROUP pInstallLangGroup)
  3813. {
  3814. int i;
  3815. LVITEM lvItem;
  3816. HWND hwndList = GetDlgItem(hwndDlg, IDC_LIST1);
  3817. int iCount = ListView_GetItemCount(hwndList);
  3818. PMUILANGINFO pMuiLangInfo;
  3819. BOOL bFirstTime=FALSE;
  3820. //
  3821. // Initialize to "No lang-groups to install"
  3822. //
  3823. pInstallLangGroup->iCount = 0L;
  3824. i = 0;
  3825. while (i < iCount)
  3826. {
  3827. if (ListView_GetCheckState(hwndList, i))
  3828. {
  3829. //
  3830. // Check if Language Group is installed
  3831. //
  3832. lvItem.mask = LVIF_PARAM;
  3833. lvItem.iItem = i;
  3834. lvItem.iSubItem = 0;
  3835. lvItem.state = 0;
  3836. lvItem.stateMask = 0;
  3837. lvItem.pszText = 0;
  3838. lvItem.cchTextMax = 0;
  3839. lvItem.iImage = 0;
  3840. lvItem.lParam = 0;
  3841. ListView_GetItem(hwndList, &lvItem);
  3842. pMuiLangInfo = (PMUILANGINFO)lvItem.lParam;
  3843. //
  3844. // Make sure there are no redundant elements
  3845. //
  3846. AddMUILangGroup(pInstallLangGroup, pMuiLangInfo->lgrpid);
  3847. //
  3848. // Add extra language groups specified in [LangPack] section of mui.inf
  3849. // This is used to support Pesudo Localized Build.
  3850. //
  3851. AddExtraLangGroupsFromINF(pMuiLangInfo->lpszLcid, pInstallLangGroup);
  3852. }
  3853. i++;
  3854. };
  3855. return TRUE;
  3856. }
  3857. ////////////////////////////////////////////////////////////////////////////////////
  3858. //
  3859. // AddMUILangGroup
  3860. //
  3861. // Add a language a group to INSTALL_LANG_GROUP. Takes care of duplicates.
  3862. ////////////////////////////////////////////////////////////////////////////////////
  3863. BOOL AddMUILangGroup(PINSTALL_LANG_GROUP pInstallLangGroup, LGRPID lgrpid)
  3864. {
  3865. int j = 0L;
  3866. BOOL bFound = FALSE;
  3867. //
  3868. // Check if it is installed by default
  3869. //
  3870. if (gpfnIsValidLanguageGroup(lgrpid, LGRPID_INSTALLED))
  3871. {
  3872. return FALSE;
  3873. }
  3874. while (j < pInstallLangGroup->iCount)
  3875. {
  3876. if (pInstallLangGroup->lgrpid[j] == lgrpid)
  3877. {
  3878. bFound = TRUE;
  3879. }
  3880. j++;
  3881. }
  3882. if (!bFound)
  3883. {
  3884. pInstallLangGroup->lgrpid[j] = lgrpid;
  3885. pInstallLangGroup->iCount++;
  3886. return TRUE;
  3887. }
  3888. return FALSE;
  3889. }
  3890. ////////////////////////////////////////////////////////////////////////////////////
  3891. //
  3892. // RunRegionalOptionsApplet
  3893. //
  3894. // Run the Regional Option silent mode installation using the specified pCommands.
  3895. //
  3896. // This function will create the "[RegigionalSettings]" string, so there is no need
  3897. // to supply that in pCommands.
  3898. //
  3899. ////////////////////////////////////////////////////////////////////////////////////
  3900. BOOL RunRegionalOptionsApplet(LPTSTR pCommands)
  3901. {
  3902. HANDLE hFile;
  3903. TCHAR szFilePath[MAX_PATH], szCmdLine[MAX_PATH];
  3904. DWORD dwNumWritten = 0L;
  3905. STARTUPINFO si;
  3906. PROCESS_INFORMATION pi;
  3907. int i;
  3908. LONG_PTR lppArgs[3];
  3909. TCHAR szSection[MAX_PATH] = TEXT("[RegionalSettings]\r\n");
  3910. //
  3911. // prepare the file for un-attended mode setup
  3912. //
  3913. szFilePath[0] = UNICODE_NULL;
  3914. if (!pfnGetWindowsDir(szFilePath, MAX_PATH-1))
  3915. {
  3916. return FALSE;
  3917. }
  3918. i = lstrlen(szFilePath);
  3919. if (szFilePath[i-1] != TEXT('\\'))
  3920. {
  3921. lstrcat(szFilePath, TEXT("\\"));
  3922. }
  3923. lstrcat(szFilePath, MUI_LANG_GROUP_FILE);
  3924. hFile = CreateFile(szFilePath,
  3925. GENERIC_WRITE,
  3926. 0L,
  3927. NULL,
  3928. CREATE_ALWAYS,
  3929. FILE_ATTRIBUTE_NORMAL,
  3930. NULL);
  3931. if (INVALID_HANDLE_VALUE == hFile)
  3932. {
  3933. lppArgs[0] = (LONG_PTR)szFilePath;
  3934. LogFormattedMessage(ghInstance, IDS_ERROR_FILE_CREATE, lppArgs);
  3935. return FALSE;
  3936. }
  3937. WriteFile(hFile,
  3938. szSection,
  3939. (lstrlen(szSection) * sizeof(TCHAR)),
  3940. &dwNumWritten,
  3941. NULL);
  3942. if (dwNumWritten != (lstrlen(szSection) * sizeof(TCHAR)))
  3943. {
  3944. lppArgs[0] = (LONG_PTR)szFilePath;
  3945. LogFormattedMessage(ghInstance, IDS_ERROR_FILE_CREATE, lppArgs);
  3946. CloseHandle(hFile);
  3947. return FALSE;
  3948. }
  3949. WriteFile(hFile,
  3950. pCommands,
  3951. (lstrlen(pCommands) * sizeof(TCHAR)),
  3952. &dwNumWritten,
  3953. NULL);
  3954. if (dwNumWritten != (lstrlen(pCommands) * sizeof(TCHAR)))
  3955. {
  3956. #if SAMER_DBG
  3957. OutputDebugString(TEXT("Unable to write to Language Groups to muilang.txt\n"));
  3958. #endif
  3959. CloseHandle(hFile);
  3960. return (FALSE);
  3961. }
  3962. CloseHandle(hFile);
  3963. //
  3964. // Call the control panel regional-options applet, and wait for it to complete
  3965. //
  3966. lstrcpy(szCmdLine, TEXT("rundll32 shell32,Control_RunDLL intl.cpl,, /f:\""));
  3967. lstrcat(szCmdLine, szFilePath);
  3968. if (g_bCmdMatchUIFont)
  3969. lstrcat(szCmdLine, TEXT("\"/g/t"));
  3970. else
  3971. lstrcat(szCmdLine, TEXT("\"/g"));
  3972. memset( &si, 0x00, sizeof(si));
  3973. si.cb = sizeof(STARTUPINFO);
  3974. if (!CreateProcess(NULL,
  3975. szCmdLine,
  3976. NULL,
  3977. NULL,
  3978. FALSE,
  3979. 0L,
  3980. NULL,
  3981. NULL,
  3982. &si,
  3983. &pi))
  3984. {
  3985. lppArgs[0] = (LONG_PTR)szCmdLine;
  3986. LogFormattedMessage(ghInstance, IDS_ERROR_LAUNCH_INTLCPL, lppArgs);
  3987. return FALSE;
  3988. }
  3989. //
  3990. // Wait forever till intl.cpl terminates.
  3991. //
  3992. WaitForSingleObject(pi.hProcess, INFINITE);
  3993. //
  3994. // Delete the File
  3995. //
  3996. DeleteFile(szFilePath);
  3997. return (TRUE);
  3998. }
  3999. ////////////////////////////////////////////////////////////////////////////////////
  4000. //
  4001. // InstallLanguageGroups
  4002. //
  4003. // Checks whether a language group is needed to be installed or not. If
  4004. // any lang-group needs to be installed, then the routine will invoke
  4005. // the Regional-Options applet in unattended mode setup.
  4006. //
  4007. // Return:
  4008. // TURE if the operation succeeds. Otherwise FALSE.
  4009. //
  4010. ////////////////////////////////////////////////////////////////////////////////////
  4011. BOOL InstallLanguageGroups(PINSTALL_LANG_GROUP pInstallLangGroup)
  4012. {
  4013. TCHAR pCommands[MAX_PATH];
  4014. int i, iCount = pInstallLangGroup->iCount;
  4015. BOOL bFirstTime=FALSE;
  4016. //
  4017. // If nothing to do, then just return
  4018. //
  4019. if (0L == iCount)
  4020. {
  4021. return TRUE;
  4022. }
  4023. i = 0;
  4024. while (i < iCount)
  4025. {
  4026. if (!gpfnIsValidLanguageGroup(pInstallLangGroup->lgrpid[i], LGRPID_INSTALLED))
  4027. {
  4028. if (!bFirstTime)
  4029. {
  4030. bFirstTime = TRUE;
  4031. wsprintf(pCommands, TEXT("LanguageGroup = %d\0"), pInstallLangGroup->lgrpid[i]);
  4032. }
  4033. else
  4034. {
  4035. wsprintf(&pCommands[lstrlen(pCommands)], TEXT(",%d\0"), pInstallLangGroup->lgrpid[i]);
  4036. }
  4037. }
  4038. i++;
  4039. };
  4040. if (!bFirstTime)
  4041. {
  4042. //
  4043. // There is no language group to be added.
  4044. return (FALSE);
  4045. }
  4046. return (RunRegionalOptionsApplet(pCommands));
  4047. }
  4048. ////////////////////////////////////////////////////////////////////////////
  4049. //
  4050. // Muisetup_RebootTheSystem
  4051. //
  4052. // This routine enables all privileges in the token, calls ExitWindowsEx
  4053. // to reboot the system, and then resets all of the privileges to their
  4054. // old state.
  4055. //
  4056. ////////////////////////////////////////////////////////////////////////////
  4057. void Muisetup_RebootTheSystem(void)
  4058. {
  4059. HANDLE Token = NULL;
  4060. ULONG ReturnLength, Index;
  4061. PTOKEN_PRIVILEGES NewState = NULL;
  4062. PTOKEN_PRIVILEGES OldState = NULL;
  4063. BOOL Result;
  4064. Result = OpenProcessToken( GetCurrentProcess(),
  4065. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  4066. &Token );
  4067. if (Result)
  4068. {
  4069. ReturnLength = 4096;
  4070. NewState = (PTOKEN_PRIVILEGES)LocalAlloc(LPTR, ReturnLength);
  4071. OldState = (PTOKEN_PRIVILEGES)LocalAlloc(LPTR, ReturnLength);
  4072. Result = (BOOL)((NewState != NULL) && (OldState != NULL));
  4073. if (Result)
  4074. {
  4075. Result = GetTokenInformation( Token, // TokenHandle
  4076. TokenPrivileges, // TokenInformationClass
  4077. NewState, // TokenInformation
  4078. ReturnLength, // TokenInformationLength
  4079. &ReturnLength ); // ReturnLength
  4080. if (Result)
  4081. {
  4082. //
  4083. // Set the state settings so that all privileges are enabled...
  4084. //
  4085. if (NewState->PrivilegeCount > 0)
  4086. {
  4087. for (Index = 0; Index < NewState->PrivilegeCount; Index++)
  4088. {
  4089. NewState->Privileges[Index].Attributes = SE_PRIVILEGE_ENABLED;
  4090. }
  4091. }
  4092. Result = AdjustTokenPrivileges( Token, // TokenHandle
  4093. FALSE, // DisableAllPrivileges
  4094. NewState, // NewState
  4095. ReturnLength, // BufferLength
  4096. OldState, // PreviousState
  4097. &ReturnLength ); // ReturnLength
  4098. if (Result)
  4099. {
  4100. ExitWindowsEx(EWX_REBOOT, 0);
  4101. AdjustTokenPrivileges( Token,
  4102. FALSE,
  4103. OldState,
  4104. 0,
  4105. NULL,
  4106. NULL );
  4107. }
  4108. }
  4109. }
  4110. }
  4111. if (NewState != NULL)
  4112. {
  4113. LocalFree(NewState);
  4114. }
  4115. if (OldState != NULL)
  4116. {
  4117. LocalFree(OldState);
  4118. }
  4119. if (Token != NULL)
  4120. {
  4121. CloseHandle(Token);
  4122. }
  4123. }
  4124. ////////////////////////////////////////////////////////////////////////////
  4125. //
  4126. // CheckForReboot
  4127. //
  4128. // Check if we need to reboot the system, if a lang group is installed
  4129. //
  4130. // Return:
  4131. // TRUE if we need user to reboot, otherwise FALSE.
  4132. //
  4133. ////////////////////////////////////////////////////////////////////////////
  4134. BOOL CheckForReboot(HWND hwnd, PINSTALL_LANG_GROUP pInstallLangGroup)
  4135. {
  4136. int nIDS,nMask=MB_YESNO | MB_ICONQUESTION;
  4137. if (pInstallLangGroup->iCount || pInstallLangGroup->bFontLinkRegistryTouched || pInstallLangGroup->NotDeleted
  4138. || g_bRemoveDefaultUI || g_bRemoveUserUI || g_bReboot)
  4139. {
  4140. if (g_bRemoveUserUI)
  4141. {
  4142. nIDS=IDS_MUST_REBOOT_STRING1;
  4143. nMask=MB_YESNO | MB_ICONWARNING;
  4144. }
  4145. else if (g_bRemoveDefaultUI)
  4146. {
  4147. nMask=MB_YESNO | MB_ICONWARNING;
  4148. nIDS=IDS_MUST_REBOOT_STRING2;
  4149. }
  4150. else
  4151. {
  4152. nIDS=IDS_REBOOT_STRING;
  4153. }
  4154. if (DoMessageBox(hwnd, nIDS, IDS_MAIN_TITLE, nMask) == IDYES)
  4155. {
  4156. Muisetup_RebootTheSystem();
  4157. }
  4158. return (TRUE);
  4159. }
  4160. return (FALSE);
  4161. }
  4162. ////////////////////////////////////////////////////////////////////////////
  4163. //
  4164. // Following code are stolen from intl.cpl
  4165. //
  4166. // We want to enumulate all installed UI languages
  4167. //
  4168. ////////////////////////////////////////////////////////////////////////////
  4169. DWORD_PTR TransNum(
  4170. LPTSTR lpsz)
  4171. {
  4172. DWORD dw = 0L;
  4173. TCHAR c;
  4174. while (*lpsz)
  4175. {
  4176. c = *lpsz++;
  4177. if (c >= TEXT('A') && c <= TEXT('F'))
  4178. {
  4179. c -= TEXT('A') - 0xa;
  4180. }
  4181. else if (c >= TEXT('0') && c <= TEXT('9'))
  4182. {
  4183. c -= TEXT('0');
  4184. }
  4185. else if (c >= TEXT('a') && c <= TEXT('f'))
  4186. {
  4187. c -= TEXT('a') - 0xa;
  4188. }
  4189. else
  4190. {
  4191. break;
  4192. }
  4193. dw *= 0x10;
  4194. dw += c;
  4195. }
  4196. return (dw);
  4197. }
  4198. BOOL MUIGetAllInstalledUILanguages()
  4199. {
  4200. pfnEnumUILanguages fnEnumUILanguages;
  4201. BOOL result = TRUE;
  4202. HINSTANCE hKernel32;
  4203. //
  4204. // Enumerate the installed UI languages.
  4205. //
  4206. g_UILanguageGroup.iCount = 0L;
  4207. hKernel32 = LoadLibrary(TEXT("kernel32.dll"));
  4208. fnEnumUILanguages = (pfnEnumUILanguages)GetProcAddress(hKernel32, "EnumUILanguagesW");
  4209. if (fnEnumUILanguages == NULL)
  4210. {
  4211. result = FALSE;
  4212. } else
  4213. {
  4214. fnEnumUILanguages(Region_EnumUILanguagesProc, 0, (LONG_PTR)&g_UILanguageGroup);
  4215. }
  4216. FreeLibrary(hKernel32);
  4217. return (result);
  4218. }
  4219. BOOL CALLBACK Region_EnumUILanguagesProc(
  4220. LPWSTR pwszUILanguage,
  4221. LONG_PTR lParam)
  4222. {
  4223. int Ctr = 0;
  4224. LGRPID lgrp;
  4225. PUILANGUAGEGROUP pUILangGroup = (PUILANGUAGEGROUP)lParam;
  4226. LCID UILanguage = (LCID)TransNum( pwszUILanguage );
  4227. if (UILanguage)
  4228. {
  4229. while (Ctr < pUILangGroup->iCount)
  4230. {
  4231. if (pUILangGroup->lcid[Ctr] == UILanguage)
  4232. {
  4233. break;
  4234. }
  4235. Ctr++;
  4236. }
  4237. //
  4238. // Theoritically, we won't go over 64 language groups!
  4239. //
  4240. if ((Ctr == pUILangGroup->iCount) && (Ctr < MAX_UI_LANG_GROUPS))
  4241. {
  4242. pUILangGroup->lcid[Ctr] = UILanguage;
  4243. pUILangGroup->iCount++;
  4244. }
  4245. }
  4246. return (TRUE);
  4247. }
  4248. BOOL IsSpaceEnough(HWND hwndDlg,INT64 *ulSizeNeed,INT64 *ulSizeAvailable)
  4249. {
  4250. HWND hList;
  4251. LGRPID lgrpid[MAX_MUI_LANGUAGES];
  4252. LPTSTR lpszLcid;
  4253. int iIndex;
  4254. int i = 0;
  4255. int iCount=0,iArrayIndex=0;
  4256. PMUILANGINFO pMuiLangInfo;
  4257. BOOL bChked,bResult=TRUE;
  4258. INT64 ulTotalBytesRequired=0,ulSpaceAvailable;
  4259. TCHAR szWinDir[MAX_PATH];
  4260. BOOL bFELangpackAdded = FALSE;
  4261. ULARGE_INTEGER ulgiFreeBytesAvailableToCaller;
  4262. ULARGE_INTEGER ulgiTotalNumberOfBytes;
  4263. *ulSizeNeed=0;
  4264. *ulSizeAvailable=0;
  4265. hList=GetDlgItem(hwndDlg, IDC_LIST1);
  4266. iIndex = ListView_GetItemCount(hList);
  4267. while(i<iIndex)
  4268. {
  4269. bChked=ListView_GetCheckState(hList, i);
  4270. GetMuiLangInfoFromListView(hList, i, &pMuiLangInfo);
  4271. lpszLcid = pMuiLangInfo->lpszLcid;
  4272. //
  4273. // Install required
  4274. //
  4275. if (bChked && !IsInstalled(lpszLcid) && HaveFiles(lpszLcid))
  4276. {
  4277. if (!gpfnIsValidLanguageGroup(pMuiLangInfo->lgrpid, LGRPID_INSTALLED))
  4278. {
  4279. for(iArrayIndex=0;iArrayIndex < iCount;iArrayIndex++)
  4280. {
  4281. if (lgrpid[iArrayIndex]==pMuiLangInfo->lgrpid)
  4282. break;
  4283. }
  4284. if(iArrayIndex == iCount)
  4285. {
  4286. if (IS_FE_LANGPACK(pMuiLangInfo->lcid))
  4287. {
  4288. if (!bFELangpackAdded)
  4289. {
  4290. ulTotalBytesRequired+=pMuiLangInfo->ulLPKSize;
  4291. bFELangpackAdded = TRUE;
  4292. }
  4293. }
  4294. else
  4295. {
  4296. ulTotalBytesRequired+=pMuiLangInfo->ulLPKSize;
  4297. }
  4298. lgrpid[iCount]= pMuiLangInfo->lgrpid;
  4299. iCount++;
  4300. }
  4301. }
  4302. ulTotalBytesRequired+=pMuiLangInfo->ulUISize;
  4303. }
  4304. // Uninstall required
  4305. if (!bChked && IsInstalled(lpszLcid))
  4306. {
  4307. ulTotalBytesRequired-=pMuiLangInfo->ulUISize;
  4308. }
  4309. i++;
  4310. }
  4311. //
  4312. // Let's check available disk space of system drive
  4313. //
  4314. pfnGetWindowsDir( szWinDir, MAX_PATH);
  4315. szWinDir[3]=TEXT('\0');
  4316. if (GetDiskFreeSpaceEx(szWinDir,
  4317. &ulgiFreeBytesAvailableToCaller,
  4318. &ulgiTotalNumberOfBytes,
  4319. NULL))
  4320. {
  4321. ulSpaceAvailable= ulgiFreeBytesAvailableToCaller.QuadPart;
  4322. if ( ulSpaceAvailable < ulTotalBytesRequired )
  4323. {
  4324. *ulSizeNeed =ulTotalBytesRequired;
  4325. *ulSizeAvailable=ulSpaceAvailable;
  4326. bResult=FALSE;
  4327. }
  4328. }
  4329. return bResult;
  4330. }
  4331. void ExitFromOutOfMemory()
  4332. {
  4333. LONG_PTR lppArgs[1];
  4334. lppArgs[0] = (LONG_PTR)GetLastError();
  4335. DoMessageBox(NULL, IDS_OUT_OF_MEMORY, IDS_MAIN_TITLE, MB_ICONEXCLAMATION | MB_OK);
  4336. LogFormattedMessage(ghInstance, IDS_OUT_OF_MEMORY_L, lppArgs);
  4337. ExitProcess(1);
  4338. }
  4339. ////////////////////////////////////////////////////////////////////////////
  4340. //
  4341. // Call the kernel to notify it that a new language is being added or
  4342. // removed
  4343. //
  4344. ////////////////////////////////////////////////////////////////////////////
  4345. void NotifyKernel(
  4346. LPTSTR LangList,
  4347. ULONG Flags
  4348. )
  4349. {
  4350. HANDLE Handle;
  4351. WMILANGUAGECHANGE LanguageChange;
  4352. ULONG ReturnSize;
  4353. BOOL IoctlSuccess;
  4354. ULONG Status;
  4355. if ((LangList != NULL) &&
  4356. (*LangList != 0))
  4357. {
  4358. Handle = CreateFile(WMIDataDeviceName,
  4359. GENERIC_READ | GENERIC_WRITE,
  4360. 0,
  4361. NULL,
  4362. OPEN_EXISTING,
  4363. FILE_ATTRIBUTE_NORMAL,
  4364. NULL);
  4365. if (Handle != INVALID_HANDLE_VALUE)
  4366. {
  4367. while (*LangList != 0)
  4368. {
  4369. memset(&LanguageChange, 0, sizeof(LanguageChange));
  4370. _tcscpy(LanguageChange.Language, LangList);
  4371. LanguageChange.Flags = Flags;
  4372. IoctlSuccess = DeviceIoControl(Handle,
  4373. IOCTL_WMI_NOTIFY_LANGUAGE_CHANGE,
  4374. &LanguageChange,
  4375. sizeof(LanguageChange),
  4376. NULL,
  4377. 0,
  4378. &ReturnSize,
  4379. NULL);
  4380. #if ALANWAR_DBG
  4381. {
  4382. WCHAR Buf[256];
  4383. wsprintf(Buf, L"MUISetup: Notify Lang change -> %d for %ws\n",
  4384. GetLastError(), LangList);
  4385. OutputDebugStringW(Buf);
  4386. }
  4387. #endif
  4388. while (*LangList++ != 0) ;
  4389. }
  4390. CloseHandle(Handle);
  4391. }
  4392. }
  4393. }
  4394. //
  4395. // Query MUI registry setting
  4396. //
  4397. BOOL CheckMUIRegSetting(DWORD dwFlag)
  4398. {
  4399. BOOL bRet = FALSE;
  4400. HKEY hKey;
  4401. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_MUI_SETTING, 0, KEY_READ, &hKey))
  4402. {
  4403. DWORD dwValue;
  4404. DWORD dwSize = sizeof(dwValue);
  4405. DWORD dwType;
  4406. if (ERROR_SUCCESS ==
  4407. RegQueryValueEx(hKey,
  4408. (dwFlag & MUI_MATCH_UIFONT)? REGSTR_VALUE_MATCH_UIFONT : REGSTR_VALUE_MATCH_LOCALE,
  4409. 0, &dwType, (LPBYTE)&dwValue, &dwSize))
  4410. {
  4411. bRet = (BOOL) dwValue;
  4412. }
  4413. RegCloseKey(hKey);
  4414. }
  4415. return bRet;
  4416. }
  4417. //
  4418. // Set MUI registry setting
  4419. //
  4420. BOOL SetMUIRegSetting(DWORD dwFlag, BOOL bEnable)
  4421. {
  4422. BOOL bRet = FALSE;
  4423. HKEY hKey;
  4424. if (ERROR_SUCCESS ==
  4425. RegCreateKeyEx(HKEY_LOCAL_MACHINE, REGSTR_MUI_SETTING, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,NULL, &hKey, NULL))
  4426. {
  4427. DWORD dwValue = (DWORD) bEnable;
  4428. if (ERROR_SUCCESS ==
  4429. RegSetValueEx(hKey,
  4430. (dwFlag & MUI_MATCH_UIFONT)? REGSTR_VALUE_MATCH_UIFONT : REGSTR_VALUE_MATCH_LOCALE,
  4431. 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(DWORD)))
  4432. {
  4433. bRet = TRUE;
  4434. }
  4435. RegCloseKey(hKey);
  4436. }
  4437. return bRet;
  4438. }
  4439. ////////////////////////////////////////////////////////////////////////////
  4440. //
  4441. // DeleteRegTree
  4442. //
  4443. // This deletes all subkeys under a specific key.
  4444. //
  4445. // Note: The code makes no attempt to check or recover from partial
  4446. // deletions.
  4447. //
  4448. // A registry key that is opened by an application can be deleted
  4449. // without error by another application. This is by design.
  4450. //
  4451. ////////////////////////////////////////////////////////////////////////////
  4452. DWORD DeleteRegTree(
  4453. HKEY hStartKey,
  4454. LPTSTR pKeyName)
  4455. {
  4456. DWORD dwRtn, dwSubKeyLength;
  4457. LPTSTR pSubKey = NULL;
  4458. TCHAR szSubKey[REGSTR_MAX_VALUE_LENGTH]; // (256) this should be dynamic.
  4459. HKEY hKey;
  4460. //
  4461. // Do not allow NULL or empty key name.
  4462. //
  4463. if (pKeyName && lstrlen(pKeyName))
  4464. {
  4465. if ((dwRtn = RegOpenKeyEx( hStartKey,
  4466. pKeyName,
  4467. 0,
  4468. KEY_ENUMERATE_SUB_KEYS | DELETE,
  4469. &hKey )) == ERROR_SUCCESS)
  4470. {
  4471. while (dwRtn == ERROR_SUCCESS)
  4472. {
  4473. dwSubKeyLength = REGSTR_MAX_VALUE_LENGTH;
  4474. dwRtn = RegEnumKeyEx( hKey,
  4475. 0, // always index zero
  4476. szSubKey,
  4477. &dwSubKeyLength,
  4478. NULL,
  4479. NULL,
  4480. NULL,
  4481. NULL );
  4482. if (dwRtn == ERROR_NO_MORE_ITEMS)
  4483. {
  4484. dwRtn = RegDeleteKey(hStartKey, pKeyName);
  4485. break;
  4486. }
  4487. else if (dwRtn == ERROR_SUCCESS)
  4488. {
  4489. dwRtn = DeleteRegTree(hKey, szSubKey);
  4490. }
  4491. }
  4492. RegCloseKey(hKey);
  4493. }
  4494. else if (dwRtn == ERROR_FILE_NOT_FOUND)
  4495. {
  4496. dwRtn = ERROR_SUCCESS;
  4497. }
  4498. }
  4499. else
  4500. {
  4501. dwRtn = ERROR_BADKEY;
  4502. }
  4503. return (dwRtn);
  4504. }
  4505. ////////////////////////////////////////////////////////////////////////////////////
  4506. //
  4507. // InstallExternalComponents
  4508. //
  4509. //
  4510. // Return:
  4511. // TURE if the operation succeeds. Otherwise FALSE.
  4512. //
  4513. ////////////////////////////////////////////////////////////////////////////////////
  4514. BOOL InstallExternalComponents(LPTSTR Languages)
  4515. {
  4516. BOOL bRet = TRUE;
  4517. TCHAR lpMessage[BUFFER_SIZE];
  4518. //
  4519. // call WBEM API to mofcompile MUI MFL's for each language
  4520. //
  4521. if (!MofCompileLanguages(Languages))
  4522. {
  4523. //
  4524. // LOG: Error mofcompiling
  4525. //
  4526. LoadString(ghInstance, IDS_MOFCOMPILE_L, lpMessage, ARRAYSIZE(lpMessage)-1);
  4527. LogMessage(lpMessage);
  4528. bRet = FALSE;
  4529. }
  4530. if (bRet)
  4531. {
  4532. //
  4533. // Inform kernel that new languages have been added
  4534. //
  4535. NotifyKernel(Languages,
  4536. WMILANGUAGECHANGE_FLAG_ADDED);
  4537. }
  4538. return bRet;
  4539. }
  4540. ////////////////////////////////////////////////////////////////////////////////////
  4541. //
  4542. // UninstallExternalComponents
  4543. //
  4544. ////////////////////////////////////////////////////////////////////////////////////
  4545. VOID UninstallExternalComponents(LPTSTR Languages)
  4546. {
  4547. //
  4548. // Inform kernel that new languages have been added
  4549. //
  4550. NotifyKernel(Languages,
  4551. WMILANGUAGECHANGE_FLAG_REMOVED);
  4552. }