Leaked source code of windows server 2003
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.

1545 lines
39 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. intl.c
  5. Abstract:
  6. Module with code for NLS-related stuff.
  7. This module is designed to be used with intl.inf and font.inf
  8. by control panel applets.
  9. Author:
  10. Ted Miller (tedm) 15-Aug-1995
  11. Revision History:
  12. --*/
  13. #include "setupp.h"
  14. #pragma hdrstop
  15. //
  16. // This structure and the callback function below are used to set the
  17. // hidden attribute bit on certain font files. That bit causes the font folder
  18. // app to not autoinstall these files.
  19. //
  20. typedef struct _FONTQCONTEXT {
  21. PVOID SetupQueueContext;
  22. HINF FontInf;
  23. } FONTQCONTEXT, *PFONTQCONTEXT;
  24. PCWSTR szHiddenFontFiles = L"HiddenFontFiles";
  25. VOID
  26. pSetLocaleSummaryText(
  27. IN HWND hdlg
  28. );
  29. VOID
  30. pSetKeyboardLayoutSummaryText(
  31. IN HWND hdlg
  32. );
  33. void
  34. pSetupRunRegApps()
  35. {
  36. HKEY hkey;
  37. BOOL bOK = TRUE;
  38. DWORD cbData, cbValue, dwType, ctr;
  39. TCHAR szValueName[32], szCmdLine[MAX_PATH];
  40. STARTUPINFO startup;
  41. PROCESS_INFORMATION pi;
  42. if (RegOpenKey( HKEY_LOCAL_MACHINE,
  43. TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\IntlRun"),
  44. &hkey ) == ERROR_SUCCESS)
  45. {
  46. startup.cb = sizeof(STARTUPINFO);
  47. startup.lpReserved = NULL;
  48. startup.lpDesktop = NULL;
  49. startup.lpTitle = NULL;
  50. startup.dwFlags = 0L;
  51. startup.cbReserved2 = 0;
  52. startup.lpReserved2 = NULL;
  53. // startup.wShowWindow = wShowWindow;
  54. for (ctr = 0; ; ctr++)
  55. {
  56. LONG lEnum;
  57. cbValue = sizeof(szValueName) / sizeof(TCHAR);
  58. cbData = sizeof(szCmdLine);
  59. if ((lEnum = RegEnumValue( hkey,
  60. ctr,
  61. szValueName,
  62. &cbValue,
  63. NULL,
  64. &dwType,
  65. (LPBYTE)szCmdLine,
  66. &cbData )) == ERROR_MORE_DATA)
  67. {
  68. //
  69. // ERROR_MORE_DATA means the value name or data was too
  70. // large, so skip to the next item.
  71. //
  72. continue;
  73. }
  74. else if (lEnum != ERROR_SUCCESS)
  75. {
  76. //
  77. // This could be ERROR_NO_MORE_ENTRIES, or some kind of
  78. // failure. We can't recover from any other registry
  79. // problem anyway.
  80. //
  81. break;
  82. }
  83. //
  84. // Found a value.
  85. //
  86. if (dwType == REG_SZ)
  87. {
  88. //
  89. // Adjust for shift in value index.
  90. //
  91. ctr--;
  92. //
  93. // Delete the value.
  94. //
  95. RegDeleteValue(hkey, szValueName);
  96. //
  97. // Only run things marked with a "*" in clean boot.
  98. //
  99. if (CreateProcess( NULL,
  100. szCmdLine,
  101. NULL,
  102. NULL,
  103. FALSE,
  104. CREATE_NEW_PROCESS_GROUP,
  105. NULL,
  106. NULL,
  107. &startup,
  108. &pi ))
  109. {
  110. WaitForSingleObjectEx(pi.hProcess, INFINITE, TRUE);
  111. CloseHandle(pi.hProcess);
  112. CloseHandle(pi.hThread);
  113. }
  114. }
  115. }
  116. RegCloseKey(hkey);
  117. }
  118. }
  119. VOID
  120. InstallServerNLSFiles(
  121. IN HWND Window
  122. )
  123. /*++
  124. Routine Description:
  125. Installs a bunch of code pages for servers. We install sections in intl.inf
  126. named [CODEPAGE_INSTALL_<n>], where the values for <n> are listed in the
  127. section [CodePages].
  128. Arguments:
  129. Window - handle to parent window
  130. Return Value:
  131. None.
  132. --*/
  133. {
  134. HINF hInf;
  135. INFCONTEXT InfContext;
  136. BOOL b;
  137. PCWSTR CodePage;
  138. WCHAR InstallSection[30];
  139. HSPFILEQ FileQueue;
  140. DWORD QueueFlags;
  141. PVOID pQueueContext;
  142. hInf = SetupOpenInfFile(L"INTL.INF",NULL,INF_STYLE_WIN4,NULL);
  143. if(hInf == INVALID_HANDLE_VALUE) {
  144. SetupDebugPrint( L"SETUP: pSetupInstallNLSFiles: Unable to open intl.inf" );
  145. return;
  146. }
  147. if(!SetupOpenAppendInfFile( NULL, hInf, NULL )) {
  148. SetupDebugPrint( L"SETUP: pSetupInstallNLSFiles: Unable to open intl.inf layout" );
  149. return;
  150. }
  151. if(!SetupFindFirstLine(hInf,L"CodePages",NULL,&InfContext)) {
  152. SetupDebugPrint( L"SETUP: pSetupInstallNLSFiles: Unable to find [CodePages] section" );
  153. goto c1;
  154. }
  155. //
  156. // Create a setup file queue and initialize default Setup copy queue
  157. // callback context.
  158. //
  159. QueueFlags = SP_COPY_FORCE_NOOVERWRITE;
  160. FileQueue = SetupOpenFileQueue();
  161. if(!FileQueue || (FileQueue == INVALID_HANDLE_VALUE)) {
  162. SetupDebugPrint( L"SETUP: pSetupInstallNLSFiles: SetupOpenFileQueue failed" );
  163. goto c1;
  164. }
  165. //
  166. // Disable the file-copy progress dialog.
  167. //
  168. pQueueContext = InitSysSetupQueueCallbackEx(
  169. Window,
  170. INVALID_HANDLE_VALUE,
  171. 0,0,NULL);
  172. if(!pQueueContext) {
  173. SetupDebugPrint( L"SETUP: pSetupInstallNLSFiles: InitSysSetupQueueCallbackEx failed" );
  174. goto c2;
  175. }
  176. do {
  177. if(CodePage = pSetupGetField(&InfContext,0)) {
  178. wsprintf( InstallSection, L"CODEPAGE_INSTALL_%s", CodePage );
  179. //
  180. // Enqueue locale-related files for copy.
  181. //
  182. b = SetupInstallFilesFromInfSection(
  183. hInf,
  184. NULL,
  185. FileQueue,
  186. InstallSection,
  187. NULL,
  188. QueueFlags
  189. );
  190. if(!b) {
  191. SetupDebugPrint( L"SETUP: pSetupInstallNLSFiles: SetupInstallFilesFromInfSection failed" );
  192. goto c3;
  193. }
  194. }
  195. } while(SetupFindNextLine(&InfContext,&InfContext));
  196. //
  197. // Copy enqueued files.
  198. //
  199. b = SetupCommitFileQueue(
  200. Window,
  201. FileQueue,
  202. SysSetupQueueCallback,
  203. pQueueContext
  204. );
  205. if(!b) {
  206. SetupDebugPrint( L"SETUP: pSetupInstallNLSFiles: SetupCommitFileQueue failed" );
  207. goto c3;
  208. }
  209. if(!SetupFindFirstLine(hInf,L"CodePages",NULL,&InfContext)) {
  210. SetupDebugPrint( L"SETUP: pSetupInstallNLSFiles: Unable to find [CodePages] section (2nd pass)" );
  211. goto c3;
  212. }
  213. do {
  214. if(CodePage = pSetupGetField(&InfContext,0)) {
  215. wsprintf( InstallSection, L"CODEPAGE_INSTALL_%s", CodePage );
  216. //
  217. // Complete installation of locale stuff.
  218. //
  219. b = SetupInstallFromInfSection(
  220. Window,
  221. hInf,
  222. InstallSection,
  223. SPINST_ALL & ~SPINST_FILES,
  224. NULL,
  225. NULL,
  226. 0,
  227. NULL,
  228. NULL,
  229. NULL,
  230. NULL
  231. );
  232. if(!b) {
  233. SetupDebugPrint( L"SETUP: pSetupInstallNLSFiles: SetupInstallFromInfSection failed" );
  234. goto c3;
  235. }
  236. }
  237. } while(SetupFindNextLine(&InfContext,&InfContext));
  238. c3:
  239. TermSysSetupQueueCallback(pQueueContext);
  240. c2:
  241. SetupCloseFileQueue(FileQueue);
  242. c1:
  243. SetupCloseInfFile(hInf);
  244. return;
  245. }
  246. DWORD
  247. pSetupInitRegionalSettings(
  248. IN HWND Window
  249. )
  250. {
  251. HINF IntlInf;
  252. LONG l;
  253. HKEY hKey;
  254. DWORD d;
  255. BOOL b;
  256. DWORD Type;
  257. INFCONTEXT LineContext;
  258. WCHAR IdFromRegistry[9];
  259. WCHAR KeyName[9];
  260. WCHAR LanguageGroup[9];
  261. WCHAR LanguageInstallSection[25];
  262. LCID SystemLocale;
  263. HSPFILEQ FileQueue;
  264. DWORD QueueFlags;
  265. PVOID pQueueContext;
  266. //
  267. // Open intl.inf. The locale descriptions are in there.
  268. // Lines in the [Locales] section have keys that are 32-bit
  269. // locale ids but the sort part is always 0, so they're more like
  270. // zero-extended language ids.
  271. //
  272. IntlInf = SetupOpenInfFile(L"intl.inf",NULL,INF_STYLE_WIN4,NULL);
  273. if(IntlInf == INVALID_HANDLE_VALUE) {
  274. SetupDebugPrint( L"SETUP: pSetupInitRegionalSettings: Unable to open intl.inf" );
  275. l = GetLastError();
  276. goto c0;
  277. }
  278. if(!SetupOpenAppendInfFile( NULL, IntlInf, NULL )) {
  279. SetupDebugPrint( L"SETUP: pSetupInitRegionalSettings: Unable to open intl.inf layout" );
  280. l = GetLastError();
  281. goto c0;
  282. }
  283. //
  284. // Read the system locale from the registry. and look up in intl.inf.
  285. // The value in the registry is a 16-bit language id, so we need to
  286. // zero-extend it to index intl.inf.
  287. //
  288. l = RegOpenKeyEx(
  289. HKEY_LOCAL_MACHINE,
  290. L"SYSTEM\\CurrentControlSet\\Control\\Nls\\Language",
  291. 0,
  292. KEY_QUERY_VALUE,
  293. &hKey
  294. );
  295. if(l == NO_ERROR) {
  296. d = sizeof(IdFromRegistry);
  297. l = RegQueryValueEx(hKey,L"Default",NULL,&Type,(LPBYTE)IdFromRegistry,&d);
  298. RegCloseKey(hKey);
  299. if((l == NO_ERROR) && ((Type != REG_SZ) || (d != 10))) {
  300. l = ERROR_INVALID_DATA;
  301. }
  302. }
  303. if(l == NO_ERROR) {
  304. l = ERROR_INVALID_DATA;
  305. wsprintf(KeyName,L"0000%s",IdFromRegistry);
  306. if(SetupFindFirstLine(IntlInf,L"Locales",KeyName,&LineContext)
  307. && SetupGetStringField(&LineContext,3,LanguageGroup,
  308. sizeof(LanguageGroup)/sizeof(WCHAR),NULL)) {
  309. l = NO_ERROR;
  310. }
  311. }
  312. if(l == NO_ERROR) {
  313. wsprintf(LanguageInstallSection,L"LG_INSTALL_%s",LanguageGroup);
  314. //
  315. // We copy the files in textmode setup now, so we don't need to do that
  316. // here anymore.
  317. //
  318. #define DO_COPY_FILES
  319. #ifdef DO_COPY_FILES
  320. //
  321. // Create a setup file queue and initialize default Setup copy queue
  322. // callback context.
  323. //
  324. QueueFlags = SP_COPY_FORCE_NOOVERWRITE;
  325. FileQueue = SetupOpenFileQueue();
  326. if(!FileQueue || (FileQueue == INVALID_HANDLE_VALUE)) {
  327. l = ERROR_OUTOFMEMORY;
  328. goto c1;
  329. }
  330. //
  331. // Disable the file-copy progress dialog.
  332. //
  333. pQueueContext = InitSysSetupQueueCallbackEx(
  334. Window,
  335. INVALID_HANDLE_VALUE,
  336. 0,0,NULL);
  337. if(!pQueueContext) {
  338. l = ERROR_OUTOFMEMORY;
  339. goto c2;
  340. }
  341. //
  342. // Enqueue locale-related files for copy. We install locales for the
  343. // system default and the Western language group, which is group 1.
  344. //
  345. b = SetupInstallFilesFromInfSection(
  346. IntlInf,
  347. NULL,
  348. FileQueue,
  349. LanguageInstallSection,
  350. NULL,
  351. QueueFlags
  352. );
  353. if(!b) {
  354. l = GetLastError();
  355. goto c3;
  356. }
  357. if(wcscmp(LanguageGroup,L"1")) {
  358. b = SetupInstallFilesFromInfSection(
  359. IntlInf,
  360. NULL,
  361. FileQueue,
  362. L"LG_INSTALL_1",
  363. NULL,
  364. QueueFlags
  365. );
  366. }
  367. if(!b) {
  368. l = GetLastError();
  369. goto c3;
  370. }
  371. //
  372. // Determine whether the queue actually needs to be committed.
  373. //
  374. b = SetupScanFileQueue(
  375. FileQueue,
  376. SPQ_SCAN_FILE_VALIDITY | SPQ_SCAN_PRUNE_COPY_QUEUE,
  377. Window,
  378. NULL,
  379. NULL,
  380. &d
  381. );
  382. if(!b) {
  383. l = GetLastError();
  384. goto c3;
  385. }
  386. //
  387. // d = 0: User wants new files or some files were missing;
  388. // Must commit queue.
  389. //
  390. // d = 1: User wants to use existing files and queue is empty;
  391. // Can skip committing queue.
  392. //
  393. // d = 2: User wants to use existing files but del/ren queues not empty.
  394. // Must commit queue. The copy queue will have been emptied,
  395. // so only del/ren functions will be performed.
  396. //
  397. if(d == 1) {
  398. b = TRUE;
  399. } else {
  400. //
  401. // Copy enqueued files.
  402. //
  403. b = SetupCommitFileQueue(
  404. Window,
  405. FileQueue,
  406. SysSetupQueueCallback,
  407. pQueueContext
  408. );
  409. }
  410. if(!b) {
  411. l = GetLastError();
  412. goto c3;
  413. }
  414. #endif
  415. //
  416. // Complete installation of locale stuff.
  417. //
  418. b = SetupInstallFromInfSection(
  419. Window,
  420. IntlInf,
  421. LanguageInstallSection,
  422. SPINST_ALL & ~SPINST_FILES,
  423. NULL,
  424. NULL,
  425. 0,
  426. NULL,
  427. NULL,
  428. NULL,
  429. NULL
  430. );
  431. if(!b) {
  432. l = GetLastError();
  433. #ifdef DO_COPY_FILES
  434. goto c3;
  435. #else
  436. goto c1;
  437. #endif
  438. }
  439. if(wcscmp(LanguageGroup,L"1")) {
  440. b = SetupInstallFromInfSection(
  441. Window,
  442. IntlInf,
  443. L"LG_INSTALL_1",
  444. SPINST_ALL & ~SPINST_FILES,
  445. NULL,
  446. NULL,
  447. 0,
  448. NULL,
  449. NULL,
  450. NULL,
  451. NULL
  452. );
  453. }
  454. if(!b) {
  455. l = GetLastError();
  456. #ifdef DO_COPY_FILES
  457. goto c3;
  458. #else
  459. goto c1;
  460. #endif
  461. }
  462. }
  463. pSetupRunRegApps();
  464. SystemLocale = wcstol(IdFromRegistry,NULL,16);
  465. if (l == NO_ERROR) {
  466. l = SetupChangeLocaleEx(
  467. Window,
  468. SystemLocale,
  469. SourcePath,
  470. SP_INSTALL_FILES_QUIETLY,
  471. NULL,0);
  472. #ifdef DO_COPY_FILES
  473. c3:
  474. TermSysSetupQueueCallback(pQueueContext);
  475. c2:
  476. SetupCloseFileQueue(FileQueue);
  477. #endif
  478. }
  479. c1:
  480. SetupCloseInfFile(IntlInf);
  481. c0:
  482. SetupDebugPrint2( L"SETUP: pSetupInitRegionalSettings returned %d (0x%08x)", l, l);
  483. return l;
  484. }
  485. UINT
  486. pSetupFontQueueCallback(
  487. IN PFONTQCONTEXT Context,
  488. IN UINT Notification,
  489. IN UINT_PTR Param1,
  490. IN UINT_PTR Param2
  491. )
  492. {
  493. PFILEPATHS FilePaths;
  494. PWCHAR p;
  495. INFCONTEXT InfContext;
  496. //
  497. // If a file is finished being copied, set its attributes
  498. // to include the hidden attribute if necessary.
  499. //
  500. if((Notification == SPFILENOTIFY_ENDCOPY)
  501. && (FilePaths = (PFILEPATHS)Param1)
  502. && (FilePaths->Win32Error == NO_ERROR)
  503. && (p = wcsrchr(FilePaths->Target,L'\\'))
  504. && SetupFindFirstLine(Context->FontInf,szHiddenFontFiles,p+1,&InfContext)) {
  505. SetFileAttributes(FilePaths->Target,FILE_ATTRIBUTE_HIDDEN);
  506. }
  507. return( IsSetup ?
  508. SysSetupQueueCallback(Context->SetupQueueContext,Notification,Param1,Param2) :
  509. SetupDefaultQueueCallback(Context->SetupQueueContext,Notification,Param1,Param2)
  510. );
  511. }
  512. VOID
  513. pSetupMarkHiddenFonts(
  514. VOID
  515. )
  516. {
  517. HINF hInf;
  518. INFCONTEXT InfContext;
  519. BOOL b;
  520. WCHAR Path[MAX_PATH];
  521. PWCHAR p;
  522. PCWSTR q;
  523. int Space;
  524. hInf = SetupOpenInfFile(L"FONT.INF",NULL,INF_STYLE_WIN4,NULL);
  525. if(hInf != INVALID_HANDLE_VALUE) {
  526. GetWindowsDirectory(Path,MAX_PATH);
  527. lstrcat(Path,L"\\FONTS\\");
  528. p = Path + lstrlen(Path);
  529. Space = MAX_PATH - (int)(p - Path);
  530. if(SetupFindFirstLine(hInf,szHiddenFontFiles,NULL,&InfContext)) {
  531. do {
  532. if(q = pSetupGetField(&InfContext,0)) {
  533. lstrcpyn(p,q,Space);
  534. if(FileExists(Path,NULL)) {
  535. SetFileAttributes(Path,FILE_ATTRIBUTE_HIDDEN);
  536. }
  537. }
  538. } while(SetupFindNextLine(&InfContext,&InfContext));
  539. }
  540. SetupCloseInfFile(hInf);
  541. }
  542. }
  543. DWORD
  544. pSetupNLSInstallFonts(
  545. IN HWND Window,
  546. IN HINF InfHandle,
  547. IN PCWSTR OemCodepage,
  548. IN PCWSTR FontSize,
  549. IN HSPFILEQ FileQueue,
  550. IN PCWSTR SourcePath, OPTIONAL
  551. IN DWORD QueueFlags
  552. )
  553. {
  554. BOOL b;
  555. WCHAR SectionName[64];
  556. //
  557. // Form section name.
  558. //
  559. wsprintf(SectionName,L"Font.CP%s.%s",OemCodepage,FontSize);
  560. if(FileQueue) {
  561. //
  562. // First pass: just enqueue files for copy.
  563. //
  564. b = SetupInstallFilesFromInfSection(
  565. InfHandle,
  566. NULL,
  567. FileQueue,
  568. SectionName,
  569. SourcePath,
  570. QueueFlags
  571. );
  572. } else {
  573. //
  574. // Second pass: do registry munging, etc.
  575. //
  576. b = SetupInstallFromInfSection(
  577. Window,
  578. InfHandle,
  579. SectionName,
  580. SPINST_ALL & ~SPINST_FILES,
  581. NULL,
  582. NULL,
  583. 0,
  584. NULL,
  585. NULL,
  586. NULL,
  587. NULL
  588. );
  589. }
  590. return(b ? NO_ERROR : GetLastError());
  591. }
  592. DWORD
  593. pSetupNLSLoadInfs(
  594. OUT HINF *FontInfHandle,
  595. OUT HINF *IntlInfHandle OPTIONAL
  596. )
  597. {
  598. HINF fontInfHandle;
  599. HINF intlInfHandle;
  600. DWORD d;
  601. fontInfHandle = SetupOpenInfFile(L"font.inf",NULL,INF_STYLE_WIN4,NULL);
  602. if(fontInfHandle == INVALID_HANDLE_VALUE) {
  603. d = GetLastError();
  604. goto c0;
  605. }
  606. if(!SetupOpenAppendInfFile(NULL,fontInfHandle,NULL)) {
  607. d = GetLastError();
  608. goto c1;
  609. }
  610. if(IntlInfHandle) {
  611. intlInfHandle = SetupOpenInfFile(L"intl.inf",NULL,INF_STYLE_WIN4,NULL);
  612. if(intlInfHandle == INVALID_HANDLE_VALUE) {
  613. d = GetLastError();
  614. goto c1;
  615. }
  616. if(!SetupOpenAppendInfFile(NULL,intlInfHandle,NULL)) {
  617. d = GetLastError();
  618. goto c2;
  619. }
  620. *IntlInfHandle = intlInfHandle;
  621. }
  622. *FontInfHandle = fontInfHandle;
  623. return(NO_ERROR);
  624. c2:
  625. SetupCloseInfFile(intlInfHandle);
  626. c1:
  627. SetupCloseInfFile(fontInfHandle);
  628. c0:
  629. return(d);
  630. }
  631. DWORD
  632. SetupChangeLocale(
  633. IN HWND Window,
  634. IN LCID NewLocale
  635. )
  636. {
  637. return(SetupChangeLocaleEx(Window,NewLocale,NULL,0,NULL,0));
  638. }
  639. DWORD
  640. SetupChangeLocaleEx(
  641. IN HWND Window,
  642. IN LCID NewLocale,
  643. IN PCWSTR SourcePath, OPTIONAL
  644. IN DWORD Flags,
  645. IN PVOID Reserved1,
  646. IN DWORD Reserved2
  647. )
  648. {
  649. DWORD d;
  650. BOOL b;
  651. HINF IntlInfHandle;
  652. INFCONTEXT InfContext;
  653. WCHAR Codepage[24];
  654. WCHAR NewLocaleString[24];
  655. FONTQCONTEXT QueueContext;
  656. HSPFILEQ FileQueue;
  657. PCWSTR SizeSpec;
  658. HDC hdc;
  659. PCWSTR p;
  660. DWORD QueueFlags;
  661. HKEY hKey;
  662. DWORD DataType;
  663. DWORD SizeDword;
  664. DWORD DataSize;
  665. SizeSpec = L"96";
  666. #if 0
  667. // This is no longer reliable.
  668. if(hdc = CreateDC(L"DISPLAY",NULL,NULL,NULL)) {
  669. if(GetDeviceCaps(hdc,LOGPIXELSY) > 108) {
  670. SizeSpec = L"120";
  671. }
  672. DeleteDC(hdc);
  673. }
  674. #else
  675. //
  676. // Determine the current font size. Default to 96.
  677. //
  678. d = (DWORD)RegOpenKeyEx(
  679. HKEY_LOCAL_MACHINE,
  680. L"System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
  681. 0,
  682. KEY_QUERY_VALUE,
  683. &hKey
  684. );
  685. if(d == NO_ERROR) {
  686. DataSize = sizeof(DWORD);
  687. d = (DWORD)RegQueryValueEx(
  688. hKey,
  689. L"LogPixels",
  690. NULL,
  691. &DataType,
  692. (LPBYTE)&SizeDword,
  693. &DataSize
  694. );
  695. if( (d == NO_ERROR) && (DataType == REG_DWORD) &&
  696. (DataSize == sizeof(DWORD)) && (SizeDword > 108) ) {
  697. SizeSpec = L"120";
  698. }
  699. RegCloseKey(hKey);
  700. }
  701. #endif
  702. QueueFlags = SP_COPY_NEWER | BaseCopyStyle;
  703. if(Flags & SP_INSTALL_FILES_QUIETLY) {
  704. QueueFlags |= SP_COPY_FORCE_NOOVERWRITE;
  705. }
  706. //
  707. // Load inf files.
  708. //
  709. d = pSetupNLSLoadInfs(&QueueContext.FontInf,&IntlInfHandle);
  710. if(d != NO_ERROR) {
  711. goto c0;
  712. }
  713. //
  714. // Get oem codepage for the locale. This is also a sanity check
  715. // to see that the locale is supported.
  716. //
  717. wsprintf(NewLocaleString,L"%.8x",NewLocale);
  718. if(!SetupFindFirstLine(IntlInfHandle,L"Locales",NewLocaleString,&InfContext)) {
  719. d = ERROR_INVALID_PARAMETER;
  720. goto c1;
  721. }
  722. p = pSetupGetField(&InfContext,2);
  723. if(!p) {
  724. d = ERROR_INVALID_PARAMETER;
  725. goto c1;
  726. }
  727. //
  728. // Copy into local storage since p points into internal structures
  729. // that could move as we call INF APIs
  730. //
  731. lstrcpyn(Codepage,p,sizeof(Codepage)/sizeof(Codepage[0]));
  732. //
  733. // Create a setup file queue and initialize default Setup copy queue
  734. // callback context.
  735. //
  736. FileQueue = SetupOpenFileQueue();
  737. if(!FileQueue || (FileQueue == INVALID_HANDLE_VALUE)) {
  738. d = ERROR_OUTOFMEMORY;
  739. goto c1;
  740. }
  741. QueueContext.SetupQueueContext = IsSetup ?
  742. InitSysSetupQueueCallbackEx(
  743. Window,
  744. INVALID_HANDLE_VALUE,
  745. 0,0,NULL) :
  746. SetupInitDefaultQueueCallbackEx(
  747. Window,
  748. INVALID_HANDLE_VALUE,
  749. 0,0,NULL);
  750. if(!QueueContext.SetupQueueContext) {
  751. d = ERROR_OUTOFMEMORY;
  752. goto c2;
  753. }
  754. //
  755. // Enqueue locale-related files for copy.
  756. //
  757. b = SetupInstallFilesFromInfSection(
  758. IntlInfHandle,
  759. NULL,
  760. FileQueue,
  761. NewLocaleString,
  762. SourcePath,
  763. QueueFlags
  764. );
  765. if(!b) {
  766. d = GetLastError();
  767. goto c3;
  768. }
  769. //
  770. // Enqueue font-related files for copy.
  771. //
  772. d = pSetupNLSInstallFonts(
  773. Window,
  774. QueueContext.FontInf,
  775. Codepage,
  776. SizeSpec,
  777. FileQueue,
  778. SourcePath,
  779. QueueFlags
  780. );
  781. if(d != NO_ERROR) {
  782. goto c3;
  783. }
  784. //
  785. // Determine whether the queue actually needs to be committed.
  786. //
  787. b = SetupScanFileQueue(
  788. FileQueue,
  789. SPQ_SCAN_FILE_VALIDITY | ((Flags & SP_INSTALL_FILES_QUIETLY) ? SPQ_SCAN_PRUNE_COPY_QUEUE : SPQ_SCAN_INFORM_USER),
  790. Window,
  791. NULL,
  792. NULL,
  793. &d
  794. );
  795. if(!b) {
  796. d = GetLastError();
  797. goto c3;
  798. }
  799. //
  800. // d = 0: User wants new files or some files were missing;
  801. // Must commit queue.
  802. //
  803. // d = 1: User wants to use existing files and queue is empty;
  804. // Can skip committing queue.
  805. //
  806. // d = 2: User wants to use existing files but del/ren queues not empty.
  807. // Must commit queue. The copy queue will have been emptied,
  808. // so only del/ren functions will be performed.
  809. //
  810. if(d == 1) {
  811. b = TRUE;
  812. } else {
  813. //
  814. // Copy enqueued files.
  815. //
  816. b = SetupCommitFileQueue(
  817. Window,
  818. FileQueue,
  819. pSetupFontQueueCallback,
  820. &QueueContext
  821. );
  822. }
  823. if(!b) {
  824. d = GetLastError();
  825. goto c3;
  826. }
  827. //
  828. // Complete installation of locale stuff.
  829. //
  830. b = SetupInstallFromInfSection(
  831. Window,
  832. IntlInfHandle,
  833. NewLocaleString,
  834. SPINST_ALL & ~SPINST_FILES,
  835. NULL,
  836. NULL,
  837. 0,
  838. NULL,
  839. NULL,
  840. NULL,
  841. NULL
  842. );
  843. if(!b) {
  844. d = GetLastError();
  845. goto c3;
  846. }
  847. //
  848. // Perform font magic associated with the new locale's codepage(s).
  849. //
  850. d = pSetupNLSInstallFonts(Window,QueueContext.FontInf,Codepage,SizeSpec,NULL,NULL,0);
  851. c3:
  852. if(IsSetup) {
  853. TermSysSetupQueueCallback(QueueContext.SetupQueueContext);
  854. } else {
  855. SetupTermDefaultQueueCallback(QueueContext.SetupQueueContext);
  856. }
  857. c2:
  858. SetupCloseFileQueue(FileQueue);
  859. c1:
  860. SetupCloseInfFile(QueueContext.FontInf);
  861. SetupCloseInfFile(IntlInfHandle);
  862. c0:
  863. if (IsSetup) {
  864. SetupDebugPrint2( L"SETUP: SetupChangeLocaleEx returned %d (0x%08x)", d, d);
  865. }
  866. return(d);
  867. }
  868. DWORD
  869. SetupChangeFontSize(
  870. IN HWND Window,
  871. IN PCWSTR SizeSpec
  872. )
  873. {
  874. DWORD d;
  875. WCHAR cp[24];
  876. FONTQCONTEXT QueueContext;
  877. HSPFILEQ FileQueue;
  878. BOOL b;
  879. //
  880. // Get the current OEM CP
  881. //
  882. wsprintf(cp,L"%u",GetOEMCP());
  883. //
  884. // Load NLS inf.
  885. //
  886. d = pSetupNLSLoadInfs(&QueueContext.FontInf,NULL);
  887. if(d != NO_ERROR) {
  888. goto c0;
  889. }
  890. //
  891. // Create queue and initialize default callback routine.
  892. //
  893. FileQueue = SetupOpenFileQueue();
  894. if(!FileQueue || (FileQueue == INVALID_HANDLE_VALUE)) {
  895. d = ERROR_OUTOFMEMORY;
  896. goto c1;
  897. }
  898. QueueContext.SetupQueueContext = IsSetup ?
  899. InitSysSetupQueueCallbackEx(
  900. Window,
  901. INVALID_HANDLE_VALUE,
  902. 0,0,NULL) :
  903. SetupInitDefaultQueueCallbackEx(
  904. Window,
  905. INVALID_HANDLE_VALUE,
  906. 0,0,NULL);
  907. if(!QueueContext.SetupQueueContext) {
  908. d = ERROR_OUTOFMEMORY;
  909. goto c2;
  910. }
  911. //
  912. // First pass: copy files.
  913. //
  914. d = pSetupNLSInstallFonts(
  915. Window,
  916. QueueContext.FontInf,
  917. cp,
  918. SizeSpec,
  919. FileQueue,
  920. NULL,
  921. SP_COPY_NEWER | BaseCopyStyle
  922. );
  923. if(d != NO_ERROR) {
  924. goto c3;
  925. }
  926. //
  927. // Determine whether the queue actually needs to be committed.
  928. //
  929. b = SetupScanFileQueue(
  930. FileQueue,
  931. SPQ_SCAN_FILE_VALIDITY | SPQ_SCAN_INFORM_USER,
  932. Window,
  933. NULL,
  934. NULL,
  935. &d
  936. );
  937. if(!b) {
  938. d = GetLastError();
  939. goto c3;
  940. }
  941. //
  942. // d = 0: User wants new files or some files were missing;
  943. // Must commit queue.
  944. //
  945. // d = 1: User wants to use existing files and queue is empty;
  946. // Can skip committing queue.
  947. //
  948. // d = 2: User wants to use existing files but del/ren queues not empty.
  949. // Must commit queue. The copy queue will have been emptied,
  950. // so only del/ren functions will be performed.
  951. //
  952. if(d == 1) {
  953. b = TRUE;
  954. } else {
  955. b = SetupCommitFileQueue(
  956. Window,
  957. FileQueue,
  958. pSetupFontQueueCallback,
  959. &QueueContext
  960. );
  961. }
  962. if(!b) {
  963. d = GetLastError();
  964. goto c3;
  965. }
  966. //
  967. // Second pass: perform registry munging, etc.
  968. //
  969. d = pSetupNLSInstallFonts(Window,QueueContext.FontInf,cp,SizeSpec,NULL,NULL,0);
  970. c3:
  971. if(IsSetup) {
  972. TermSysSetupQueueCallback(QueueContext.SetupQueueContext);
  973. } else {
  974. SetupTermDefaultQueueCallback(QueueContext.SetupQueueContext);
  975. }
  976. c2:
  977. SetupCloseFileQueue(FileQueue);
  978. c1:
  979. SetupCloseInfFile(QueueContext.FontInf);
  980. c0:
  981. return(d);
  982. }
  983. ////////////////////////////////////////////////////////////////////
  984. //
  985. // Code below here is for regional settings stuff that occurs during
  986. // gui mode setup
  987. //
  988. ////////////////////////////////////////////////////////////////////
  989. INT_PTR
  990. CALLBACK
  991. RegionalSettingsDlgProc(
  992. IN HWND hdlg,
  993. IN UINT msg,
  994. IN WPARAM wParam,
  995. IN LPARAM lParam
  996. )
  997. {
  998. BOOL b;
  999. NMHDR *NotifyParams;
  1000. WCHAR CmdLine[MAX_PATH];
  1001. b = TRUE;
  1002. switch(msg) {
  1003. case WM_SIMULATENEXT:
  1004. PropSheet_PressButton(GetParent(hdlg),PSBTN_NEXT);
  1005. break;
  1006. case WMX_VALIDATE:
  1007. // Empty page
  1008. return ReturnDlgResult (hdlg, VALIDATE_DATA_OK);
  1009. case WM_NOTIFY:
  1010. NotifyParams = (NMHDR *)lParam;
  1011. switch(NotifyParams->code) {
  1012. case PSN_SETACTIVE:
  1013. TESTHOOK(502);
  1014. BEGIN_SECTION(L"Regional Settings Page");
  1015. SetWizardButtons(hdlg,WizPageRegionalSettings);
  1016. //
  1017. // Set message text.
  1018. //
  1019. pSetLocaleSummaryText(hdlg);
  1020. pSetKeyboardLayoutSummaryText(hdlg);
  1021. //
  1022. // Allow activation.
  1023. //
  1024. //
  1025. // Show unless OEMSkipRegional = 1
  1026. //
  1027. if( Preinstall ) {
  1028. //
  1029. // Always show the page in a Preinstall, unless the user
  1030. // has sent us OEMSkipRegional.
  1031. //
  1032. if (GetPrivateProfileInt(pwGuiUnattended,L"OEMSkipRegional",0,AnswerFile))
  1033. {
  1034. SetWindowLongPtr(hdlg, DWLP_MSGRESULT, -1 );
  1035. }
  1036. else
  1037. {
  1038. // Page becomes active, make page visible.
  1039. SendMessage(GetParent(hdlg), WMX_BBTEXT, (WPARAM)FALSE, 0);
  1040. SetWindowLongPtr(hdlg, DWLP_MSGRESULT,0);
  1041. }
  1042. } else {
  1043. SetWindowLongPtr( hdlg, DWLP_MSGRESULT, 0 );
  1044. if(Unattended) {
  1045. if (!UnattendSetActiveDlg(hdlg,IDD_REGIONAL_SETTINGS))
  1046. {
  1047. break;
  1048. }
  1049. }
  1050. // Page becomes active, make page visible.
  1051. SendMessage(GetParent(hdlg), WMX_BBTEXT, (WPARAM)FALSE, 0);
  1052. }
  1053. break;
  1054. case PSN_WIZNEXT:
  1055. case PSN_WIZFINISH:
  1056. //
  1057. // Allow next page to be activated.
  1058. //
  1059. SetWindowLongPtr(hdlg,DWLP_MSGRESULT,0);
  1060. break;
  1061. case PSN_KILLACTIVE:
  1062. WizardKillHelp(hdlg);
  1063. SetWindowLongPtr(hdlg,DWLP_MSGRESULT,FALSE);
  1064. END_SECTION(L"Regional Settings Page");
  1065. break;
  1066. case PSN_HELP:
  1067. WizardBringUpHelp(hdlg,WizPageRegionalSettings);
  1068. break;
  1069. default:
  1070. b = FALSE;
  1071. break;
  1072. }
  1073. break;
  1074. case WM_COMMAND:
  1075. switch(LOWORD(wParam)) {
  1076. case IDB_LOCALE:
  1077. case IDB_KBDLAYOUT:
  1078. if(HIWORD(wParam) == BN_CLICKED) {
  1079. PropSheet_SetWizButtons(GetParent(hdlg),0);
  1080. EnableWindow(GetParent(hdlg),FALSE);
  1081. wsprintf(
  1082. CmdLine,
  1083. L"/%c /s:\"%s\"",
  1084. (LOWORD(wParam) == IDB_LOCALE) ? L'R' : L'I',
  1085. LegacySourcePath
  1086. );
  1087. InvokeControlPanelApplet(L"intl.cpl",L"",0,CmdLine);
  1088. if(LOWORD(wParam) == IDB_LOCALE) {
  1089. pSetLocaleSummaryText(hdlg);
  1090. }
  1091. pSetKeyboardLayoutSummaryText(hdlg);
  1092. EnableWindow(GetParent(hdlg),TRUE);
  1093. SetWizardButtons(hdlg,WizPageRegionalSettings);
  1094. // Get the focus tot he wizard and set it to the button the user selected.
  1095. SetForegroundWindow(GetParent(hdlg));
  1096. SetFocus(GetDlgItem(hdlg,LOWORD(wParam)));
  1097. } else {
  1098. b = FALSE;
  1099. }
  1100. break;
  1101. default:
  1102. b = FALSE;
  1103. break;
  1104. }
  1105. break;
  1106. default:
  1107. b = FALSE;
  1108. break;
  1109. }
  1110. return(b);
  1111. }
  1112. VOID
  1113. pSetLocaleSummaryText(
  1114. IN HWND hdlg
  1115. )
  1116. {
  1117. HINF IntlInf;
  1118. LONG l;
  1119. HKEY hKey;
  1120. DWORD d;
  1121. DWORD Type;
  1122. INFCONTEXT LineContext;
  1123. WCHAR IdFromRegistry[9];
  1124. WCHAR KeyName[9];
  1125. WCHAR UserLocale[100],GeoLocation[100];
  1126. WCHAR FormatString[300];
  1127. WCHAR MessageText[500];
  1128. LPCWSTR args[2];
  1129. DWORD dwGeoID;
  1130. //
  1131. // Open intl.inf. The locale descriptions are in there.
  1132. // Lines in the [Locales] section have keys that are 32-bit
  1133. // locale ids but the sort part is always 0, so they're more like
  1134. // zero-extended language ids.
  1135. //
  1136. IntlInf = SetupOpenInfFile(L"intl.inf",NULL,INF_STYLE_WIN4,NULL);
  1137. if(IntlInf == INVALID_HANDLE_VALUE) {
  1138. LoadString(MyModuleHandle,IDS_UNKNOWN_PARENS,UserLocale,sizeof(UserLocale)/sizeof(WCHAR));
  1139. lstrcpy(GeoLocation,UserLocale);
  1140. } else {
  1141. //
  1142. // Read the user locale, which is stored as a full 32-bit LCID.
  1143. // We have to chop off the sort id part to index intl.inf.
  1144. //
  1145. l = RegOpenKeyEx(
  1146. HKEY_CURRENT_USER,
  1147. L"Control Panel\\International",
  1148. 0,
  1149. KEY_QUERY_VALUE,
  1150. &hKey
  1151. );
  1152. if(l == NO_ERROR) {
  1153. d = sizeof(IdFromRegistry);
  1154. l = RegQueryValueEx(hKey,L"Locale",NULL,&Type,(LPBYTE)IdFromRegistry,&d);
  1155. RegCloseKey(hKey);
  1156. if((l == NO_ERROR) && ((Type != REG_SZ) || (d != 18))) {
  1157. l = ERROR_INVALID_DATA;
  1158. }
  1159. }
  1160. if(l == NO_ERROR) {
  1161. l = ERROR_INVALID_DATA;
  1162. wsprintf(KeyName,L"0000%s",IdFromRegistry+4);
  1163. if(SetupFindFirstLine(IntlInf,L"Locales",KeyName,&LineContext)
  1164. && SetupGetStringField(&LineContext,1,UserLocale,sizeof(UserLocale)/sizeof(WCHAR),NULL)) {
  1165. l = NO_ERROR;
  1166. }
  1167. }
  1168. if(l != NO_ERROR) {
  1169. LoadString(MyModuleHandle,IDS_UNKNOWN_PARENS,UserLocale,sizeof(UserLocale)/sizeof(WCHAR));
  1170. }
  1171. SetupCloseInfFile(IntlInf);
  1172. //
  1173. // Read the GEO location
  1174. //
  1175. l = RegOpenKeyEx(
  1176. HKEY_CURRENT_USER,
  1177. L"Control Panel\\International\\Geo",
  1178. 0,
  1179. KEY_QUERY_VALUE,
  1180. &hKey
  1181. );
  1182. if(l == NO_ERROR) {
  1183. d = sizeof(IdFromRegistry);
  1184. l = RegQueryValueEx(hKey,L"Nation",NULL,&Type,(LPBYTE)IdFromRegistry,&d);
  1185. RegCloseKey(hKey);
  1186. if((l == NO_ERROR) && (Type != REG_SZ)) {
  1187. l = ERROR_INVALID_DATA;
  1188. }
  1189. }
  1190. if(l == NO_ERROR) {
  1191. l = ERROR_INVALID_DATA;
  1192. dwGeoID = wcstoul ( IdFromRegistry, NULL, 10 );
  1193. if (GetGeoInfo (
  1194. dwGeoID,
  1195. GEO_FRIENDLYNAME,
  1196. GeoLocation,
  1197. sizeof(GeoLocation)/sizeof(WCHAR),
  1198. 0 )
  1199. ) {
  1200. l = NO_ERROR;
  1201. }
  1202. }
  1203. if(l != NO_ERROR) {
  1204. LoadString(MyModuleHandle,IDS_UNKNOWN_PARENS,GeoLocation,sizeof(GeoLocation)/sizeof(WCHAR));
  1205. }
  1206. }
  1207. args[0] = UserLocale;
  1208. args[1] = GeoLocation;
  1209. LoadString(MyModuleHandle,IDS_LOCALE_MSG,FormatString,sizeof(FormatString)/sizeof(WCHAR));
  1210. FormatMessage(
  1211. FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  1212. FormatString,
  1213. 0,0,
  1214. MessageText,
  1215. sizeof(MessageText)/sizeof(WCHAR),
  1216. (va_list *)args
  1217. );
  1218. SetDlgItemText(hdlg,IDT_LOCALE,MessageText);
  1219. }
  1220. VOID
  1221. pSetKeyboardLayoutSummaryText(
  1222. IN HWND hdlg
  1223. )
  1224. {
  1225. LONG l;
  1226. HKEY hKey;
  1227. BOOL MultipleLayouts;
  1228. DWORD d;
  1229. DWORD Type;
  1230. WCHAR IdFromRegistry[9];
  1231. WCHAR Substitute[9];
  1232. WCHAR Name[200];
  1233. WCHAR FormatString[300];
  1234. WCHAR MessageText[500];
  1235. //
  1236. // Open the Preload key in the registry.
  1237. //
  1238. l = RegOpenKeyEx(
  1239. HKEY_CURRENT_USER,
  1240. L"Keyboard Layout\\Preload",
  1241. 0,
  1242. KEY_QUERY_VALUE,
  1243. &hKey
  1244. );
  1245. MultipleLayouts = FALSE;
  1246. if(l == NO_ERROR) {
  1247. //
  1248. // Pull out 2=. If it's there, then we're in a "complex" config
  1249. // situation, which will change our message text a little.
  1250. //
  1251. d = sizeof(IdFromRegistry);
  1252. if(RegQueryValueEx(hKey,L"2",NULL,&Type,(LPBYTE)IdFromRegistry,&d) == NO_ERROR) {
  1253. MultipleLayouts = TRUE;
  1254. }
  1255. //
  1256. // Get 1=, which is the main layout.
  1257. //
  1258. d = sizeof(IdFromRegistry);
  1259. l = RegQueryValueEx(hKey,L"1",NULL,&Type,(LPBYTE)IdFromRegistry,&d);
  1260. if((l == NO_ERROR) && (Type != REG_SZ)) {
  1261. l = ERROR_INVALID_DATA;
  1262. }
  1263. RegCloseKey(hKey);
  1264. //
  1265. // Now we look in the substitutes key to see whether there is a
  1266. // substitute there.
  1267. //
  1268. if(RegOpenKeyEx(HKEY_CURRENT_USER,L"Keyboard Layout\\Substitutes",0,KEY_QUERY_VALUE,&hKey) == NO_ERROR) {
  1269. d = sizeof(Substitute);
  1270. if((RegQueryValueEx(hKey,IdFromRegistry,NULL,&Type,(LPBYTE)Substitute,&d) == NO_ERROR)
  1271. && (Type == REG_SZ)) {
  1272. lstrcpy(IdFromRegistry,Substitute);
  1273. }
  1274. RegCloseKey(hKey);
  1275. }
  1276. //
  1277. // Form the name of the subkey that contains layout data.
  1278. //
  1279. wsprintf(
  1280. Name,
  1281. L"System\\CurrentControlSet\\Control\\Keyboard Layouts\\%s",
  1282. IdFromRegistry
  1283. );
  1284. //
  1285. // Open the key and retrieve the layout name.
  1286. //
  1287. l = RegOpenKeyEx(HKEY_LOCAL_MACHINE,Name,0,KEY_QUERY_VALUE,&hKey);
  1288. if(l == NO_ERROR) {
  1289. d = sizeof(Name);
  1290. l = RegQueryValueEx(hKey,L"Layout Text",NULL,&Type,(LPBYTE)Name,&d);
  1291. if((l == NO_ERROR) && (Type != REG_SZ)) {
  1292. l = ERROR_INVALID_DATA;
  1293. }
  1294. RegCloseKey(hKey);
  1295. }
  1296. }
  1297. if(l != NO_ERROR) {
  1298. LoadString(MyModuleHandle,IDS_UNKNOWN_PARENS,Name,sizeof(Name)/sizeof(WCHAR));
  1299. }
  1300. LoadString(
  1301. MyModuleHandle,
  1302. IDS_KBDLAYOUT_MSG,
  1303. FormatString,
  1304. sizeof(FormatString)/sizeof(WCHAR)
  1305. );
  1306. wsprintf(MessageText,FormatString,Name);
  1307. SetDlgItemText(hdlg,IDT_KBD_LAYOUT,MessageText);
  1308. }