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.

7171 lines
208 KiB

  1. /*++
  2. Copyright (c) 1994-2000, Microsoft Corporation All rights reserved.
  3. Module Name:
  4. util.c
  5. Abstract:
  6. This module implements the utility functions used by the Regional
  7. Options applet.
  8. Revision History:
  9. --*/
  10. //
  11. // Include Files.
  12. //
  13. #include <nt.h>
  14. #include <ntrtl.h>
  15. #include <nturtl.h>
  16. #include <shlwapi.h>
  17. #include "intl.h"
  18. #include <tchar.h>
  19. #include <windowsx.h>
  20. #include <userenv.h>
  21. #include <regstr.h>
  22. #include "intlhlp.h"
  23. #include "maxvals.h"
  24. #include "winnlsp.h"
  25. #include <lmcons.h>
  26. #include "intlmsg.h"
  27. #define STRSAFE_LIB
  28. #include <strsafe.h>
  29. //
  30. // Global Variables.
  31. //
  32. #ifdef UNICODE
  33. #define NUM_CURRENCY_SYMBOLS 2
  34. LPWSTR pCurrencySymbols[] =
  35. {
  36. L"$",
  37. L"\x20ac"
  38. };
  39. #endif
  40. #define NUM_DATE_SEPARATORS 3
  41. LPTSTR pDateSeparators[] =
  42. {
  43. TEXT("/"),
  44. TEXT("-"),
  45. TEXT(".")
  46. };
  47. #define NUM_NEG_NUMBER_FORMATS 5
  48. LPTSTR pNegNumberFormats[] =
  49. {
  50. TEXT("(1.1)"),
  51. TEXT("-1.1"),
  52. TEXT("- 1.1"),
  53. TEXT("1.1-"),
  54. TEXT("1.1 -")
  55. };
  56. #define NUM_POS_CURRENCY_FORMATS 4
  57. LPTSTR pPosCurrencyFormats[] =
  58. {
  59. TEXT("�1.1"),
  60. TEXT("1.1�"),
  61. TEXT("� 1.1"),
  62. TEXT("1.1 �")
  63. };
  64. #define NUM_NEG_CURRENCY_FORMATS 16
  65. LPTSTR pNegCurrencyFormats[] =
  66. {
  67. TEXT("(�1.1)"),
  68. TEXT("-�1.1"),
  69. TEXT("�-1.1"),
  70. TEXT("�1.1-"),
  71. TEXT("(1.1�)"),
  72. TEXT("-1.1�"),
  73. TEXT("1.1-�"),
  74. TEXT("1.1�-"),
  75. TEXT("-1.1 �"),
  76. TEXT("-� 1.1"),
  77. TEXT("1.1 �-"),
  78. TEXT("� 1.1-"),
  79. TEXT("� -1.1"),
  80. TEXT("1.1- �"),
  81. TEXT("(� 1.1)"),
  82. TEXT("(1.1 �)")
  83. };
  84. #define NUM_AM_SYMBOLS 1
  85. LPTSTR pAMSymbols[] =
  86. {
  87. TEXT("AM")
  88. };
  89. #define NUM_PM_SYMBOLS 1
  90. LPTSTR pPMSymbols[] =
  91. {
  92. TEXT("PM")
  93. };
  94. const TCHAR c_szEventSourceName[] = TEXT("Regional and Language Options");
  95. const TCHAR c_szEventRegistryPath[] = TEXT("SYSTEM\\CurrentControlSet\\Services\\EventLog\\System\\Regional and Language Options");
  96. ////////////////////////////////////////////////////////////////////////////
  97. //
  98. // Intl_StrToLong
  99. //
  100. // Returns the long integer value stored in the string. Since these
  101. // values are coming back form the NLS API as ordinal values, do not
  102. // worry about double byte characters.
  103. //
  104. ////////////////////////////////////////////////////////////////////////////
  105. LONG Intl_StrToLong(
  106. LPTSTR szNum)
  107. {
  108. LONG Rtn_Val = 0;
  109. while (*szNum)
  110. {
  111. Rtn_Val = (Rtn_Val * 10) + (*szNum - CHAR_ZERO);
  112. szNum++;
  113. }
  114. return (Rtn_Val);
  115. }
  116. ////////////////////////////////////////////////////////////////////////////
  117. //
  118. // Intl_FileExists
  119. //
  120. // Determines if the file exists and is accessible.
  121. //
  122. ////////////////////////////////////////////////////////////////////////////
  123. BOOL Intl_FileExists(
  124. LPTSTR pFileName)
  125. {
  126. WIN32_FIND_DATA FindData;
  127. HANDLE FindHandle;
  128. BOOL bRet;
  129. UINT OldMode;
  130. OldMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  131. FindHandle = FindFirstFile(pFileName, &FindData);
  132. if (FindHandle == INVALID_HANDLE_VALUE)
  133. {
  134. bRet = FALSE;
  135. }
  136. else
  137. {
  138. FindClose(FindHandle);
  139. bRet = TRUE;
  140. }
  141. SetErrorMode(OldMode);
  142. return (bRet);
  143. }
  144. ////////////////////////////////////////////////////////////////////////////
  145. //
  146. // TransNum
  147. //
  148. // Converts a number string to a dword value (in hex).
  149. //
  150. ////////////////////////////////////////////////////////////////////////////
  151. DWORD TransNum(
  152. LPTSTR lpsz)
  153. {
  154. DWORD dw = 0L;
  155. TCHAR c;
  156. while (*lpsz)
  157. {
  158. c = *lpsz++;
  159. if (c >= TEXT('A') && c <= TEXT('F'))
  160. {
  161. c -= TEXT('A') - 0xa;
  162. }
  163. else if (c >= TEXT('0') && c <= TEXT('9'))
  164. {
  165. c -= TEXT('0');
  166. }
  167. else if (c >= TEXT('a') && c <= TEXT('f'))
  168. {
  169. c -= TEXT('a') - 0xa;
  170. }
  171. else
  172. {
  173. break;
  174. }
  175. dw *= 0x10;
  176. dw += c;
  177. }
  178. return (dw);
  179. }
  180. ////////////////////////////////////////////////////////////////////////////
  181. //
  182. // Item_Has_Digits
  183. //
  184. // Return true if the combo box specified by item in the property sheet
  185. // specified by the dialog handle contains any digits.
  186. //
  187. ////////////////////////////////////////////////////////////////////////////
  188. BOOL Item_Has_Digits(
  189. HWND hDlg,
  190. int nItemId,
  191. BOOL Allow_Empty)
  192. {
  193. TCHAR szBuf[SIZE_128];
  194. LPTSTR lpszBuf = szBuf;
  195. HWND hCtrl = GetDlgItem(hDlg, nItemId);
  196. int dwIndex = ComboBox_GetCurSel(hCtrl);
  197. //
  198. // If there is no selection, get whatever is in the edit box.
  199. //
  200. if (dwIndex == CB_ERR)
  201. {
  202. dwIndex = GetDlgItemText(hDlg, nItemId, szBuf, SIZE_128);
  203. if (dwIndex)
  204. {
  205. //
  206. // Get text succeeded.
  207. //
  208. szBuf[dwIndex] = 0;
  209. }
  210. else
  211. {
  212. //
  213. // Get text failed.
  214. //
  215. dwIndex = CB_ERR;
  216. }
  217. }
  218. else
  219. {
  220. ComboBox_GetLBText(hCtrl, dwIndex, szBuf);
  221. }
  222. if (dwIndex != CB_ERR)
  223. {
  224. while (*lpszBuf)
  225. {
  226. #ifndef UNICODE
  227. if (IsDBCSLeadByte(*lpszBuf))
  228. {
  229. //
  230. // Skip 2 bytes in the array.
  231. //
  232. lpszBuf += 2;
  233. }
  234. else
  235. #endif
  236. {
  237. if ((*lpszBuf >= CHAR_ZERO) && (*lpszBuf <= CHAR_NINE))
  238. {
  239. return (TRUE);
  240. }
  241. lpszBuf++;
  242. }
  243. }
  244. return (FALSE);
  245. }
  246. //
  247. // The data retrieval failed.
  248. // If !Allow_Empty, just return TRUE.
  249. //
  250. return (!Allow_Empty);
  251. }
  252. ////////////////////////////////////////////////////////////////////////////
  253. //
  254. // Item_Has_Digits_Or_Invalid_Chars
  255. //
  256. // Return true if the combo box specified by item in the property sheet
  257. // specified by the dialog handle contains any digits or any of the
  258. // given invalid characters.
  259. //
  260. ////////////////////////////////////////////////////////////////////////////
  261. BOOL Item_Has_Digits_Or_Invalid_Chars(
  262. HWND hDlg,
  263. int nItemId,
  264. BOOL Allow_Empty,
  265. LPTSTR pInvalid)
  266. {
  267. TCHAR szBuf[SIZE_128];
  268. LPTSTR lpszBuf = szBuf;
  269. HWND hCtrl = GetDlgItem(hDlg, nItemId);
  270. int dwIndex = ComboBox_GetCurSel(hCtrl);
  271. //
  272. // If there is no selection, get whatever is in the edit box.
  273. //
  274. if (dwIndex == CB_ERR)
  275. {
  276. dwIndex = GetDlgItemText(hDlg, nItemId, szBuf, SIZE_128);
  277. if (dwIndex)
  278. {
  279. //
  280. // Get text succeeded.
  281. //
  282. szBuf[dwIndex] = 0;
  283. }
  284. else
  285. {
  286. //
  287. // Get text failed.
  288. //
  289. dwIndex = CB_ERR;
  290. }
  291. }
  292. else
  293. {
  294. dwIndex = ComboBox_GetLBText(hCtrl, dwIndex, szBuf);
  295. }
  296. if (dwIndex != CB_ERR)
  297. {
  298. while (*lpszBuf)
  299. {
  300. #ifndef UNICODE
  301. if (IsDBCSLeadByte(*lpszBuf))
  302. {
  303. //
  304. // Skip 2 bytes in the array.
  305. //
  306. lpszBuf += 2;
  307. }
  308. else
  309. #endif
  310. {
  311. if ( ((*lpszBuf >= CHAR_ZERO) && (*lpszBuf <= CHAR_NINE)) ||
  312. (_tcschr(pInvalid, *lpszBuf)) )
  313. {
  314. return (TRUE);
  315. }
  316. lpszBuf++;
  317. }
  318. }
  319. return (FALSE);
  320. }
  321. //
  322. // The data retrieval failed.
  323. // If !Allow_Empty, just return TRUE.
  324. //
  325. return (!Allow_Empty);
  326. }
  327. ////////////////////////////////////////////////////////////////////////////
  328. //
  329. // Item_Check_Invalid_Chars
  330. //
  331. // Return true if the input string contains any characters that are not in
  332. // lpCkChars or in the string contained in the check id control combo box.
  333. // If there is an invalid character and the character is contained in
  334. // lpChgCase, change the invalid character's case so that it will be a
  335. // vaild character.
  336. //
  337. ////////////////////////////////////////////////////////////////////////////
  338. BOOL Item_Check_Invalid_Chars(
  339. HWND hDlg,
  340. LPTSTR lpszBuf,
  341. LPTSTR lpCkChars,
  342. int nCkIdStr,
  343. BOOL Allow_Empty,
  344. LPTSTR lpChgCase,
  345. int nItemId)
  346. {
  347. TCHAR szCkBuf[SIZE_128];
  348. LPTSTR lpCCaseChar;
  349. LPTSTR lpszSaveBuf = lpszBuf;
  350. int nCkBufLen;
  351. BOOL bInQuote = FALSE;
  352. BOOL UpdateEditTest = FALSE;
  353. HWND hCtrl = GetDlgItem(hDlg, nCkIdStr);
  354. DWORD dwIndex = ComboBox_GetCurSel(hCtrl);
  355. BOOL TextFromEditBox = (ComboBox_GetCurSel(GetDlgItem(hDlg, nItemId)) == CB_ERR);
  356. if (!lpszBuf)
  357. {
  358. return (!Allow_Empty);
  359. }
  360. if (dwIndex != CB_ERR)
  361. {
  362. nCkBufLen = ComboBox_GetLBText(hCtrl, dwIndex, szCkBuf);
  363. if (nCkBufLen == CB_ERR)
  364. {
  365. nCkBufLen = 0;
  366. }
  367. }
  368. else
  369. {
  370. //
  371. // No selection, so pull the string from the edit portion.
  372. //
  373. nCkBufLen = GetDlgItemText(hDlg, nCkIdStr, szCkBuf, SIZE_128);
  374. szCkBuf[nCkBufLen] = 0;
  375. }
  376. while (*lpszBuf)
  377. {
  378. #ifndef UNICODE
  379. if (IsDBCSLeadByte(*lpszBuf))
  380. {
  381. //
  382. // If the the text is in the midst of a quote, skip it.
  383. // Otherwise, if there is a string from the check ID to
  384. // compare, determine if the current string is equal to the
  385. // string in the combo box. If it is not equal, return true
  386. // (there are invalid characters). Otherwise, skip the entire
  387. // length of the "check" combo box's string in lpszBuf.
  388. //
  389. if (bInQuote)
  390. {
  391. lpszBuf += 2;
  392. }
  393. else if (nCkBufLen &&
  394. lstrlen(lpszBuf) >= nCkBufLen)
  395. {
  396. if (CompareString( UserLocaleID,
  397. 0,
  398. szCkBuf,
  399. nCkBufLen,
  400. lpszBuf,
  401. nCkBufLen ) != CSTR_EQUAL)
  402. {
  403. //
  404. // Invalid DB character.
  405. //
  406. return (TRUE);
  407. }
  408. lpszBuf += nCkBufLen;
  409. }
  410. }
  411. else
  412. #endif
  413. {
  414. if (bInQuote)
  415. {
  416. bInQuote = (*lpszBuf != CHAR_QUOTE);
  417. lpszBuf++;
  418. }
  419. else if (_tcschr(lpCkChars, *lpszBuf))
  420. {
  421. lpszBuf++;
  422. }
  423. else if (TextFromEditBox &&
  424. (lpCCaseChar = _tcschr(lpChgCase, *lpszBuf), lpCCaseChar))
  425. {
  426. *lpszBuf = lpCkChars[lpCCaseChar - lpChgCase];
  427. UpdateEditTest = TRUE;
  428. lpszBuf++;
  429. }
  430. else if (*lpszBuf == CHAR_QUOTE)
  431. {
  432. lpszBuf++;
  433. bInQuote = TRUE;
  434. }
  435. else if ( (nCkBufLen) &&
  436. (lstrlen(lpszBuf) >= nCkBufLen) &&
  437. (CompareString( UserLocaleID,
  438. 0,
  439. szCkBuf,
  440. nCkBufLen,
  441. lpszBuf,
  442. nCkBufLen ) == CSTR_EQUAL) )
  443. {
  444. lpszBuf += nCkBufLen;
  445. }
  446. else
  447. {
  448. //
  449. // Invalid character.
  450. //
  451. return (TRUE);
  452. }
  453. }
  454. }
  455. //
  456. // Parsing passed.
  457. // If the edit text changed, update edit box only if returning true.
  458. //
  459. if (!bInQuote && UpdateEditTest)
  460. {
  461. return (!SetDlgItemText(hDlg, nItemId, lpszSaveBuf));
  462. }
  463. //
  464. // If there are unmatched quotes return TRUE. Otherwise, return FALSE.
  465. //
  466. if (bInQuote)
  467. {
  468. return (TRUE);
  469. }
  470. return (FALSE);
  471. }
  472. ////////////////////////////////////////////////////////////////////////////
  473. //
  474. // No_Numerals_Error
  475. //
  476. // Display the no numerals allowed in "some control" error.
  477. //
  478. ////////////////////////////////////////////////////////////////////////////
  479. void No_Numerals_Error(
  480. HWND hDlg,
  481. int nItemId,
  482. int iStrId)
  483. {
  484. TCHAR szBuf[SIZE_300];
  485. TCHAR szBuf2[SIZE_128];
  486. TCHAR szErrorMessage[SIZE_300+SIZE_128];
  487. LoadString(hInstance, IDS_LOCALE_NO_NUMS_IN, szBuf, SIZE_300);
  488. LoadString(hInstance, iStrId, szBuf2, SIZE_128);
  489. //wsprintf(szErrorMessage, szBuf, szBuf2);
  490. if(FAILED(StringCchPrintf(szErrorMessage, SIZE_300+SIZE_128, szBuf, szBuf2)))
  491. {
  492. // This should be impossible, but we need to avoid PREfast complaints.
  493. }
  494. MessageBox(hDlg, szErrorMessage, NULL, MB_OK | MB_ICONINFORMATION);
  495. SetFocus(GetDlgItem(hDlg, nItemId));
  496. }
  497. ////////////////////////////////////////////////////////////////////////////
  498. //
  499. // Invalid_Chars_Error
  500. //
  501. // Display the invalid chars in "some style" error.
  502. //
  503. ////////////////////////////////////////////////////////////////////////////
  504. void Invalid_Chars_Error(
  505. HWND hDlg,
  506. int nItemId,
  507. int iStrId)
  508. {
  509. TCHAR szBuf[SIZE_300];
  510. TCHAR szBuf2[SIZE_128];
  511. TCHAR szErrorMessage[SIZE_300+SIZE_128];
  512. LoadString(hInstance, IDS_LOCALE_STYLE_ERR, szBuf, SIZE_300);
  513. LoadString(hInstance, iStrId, szBuf2, SIZE_128);
  514. //wsprintf(szErrorMessage, szBuf, szBuf2);
  515. if(FAILED(StringCchPrintf(szErrorMessage, SIZE_300+SIZE_128, szBuf, szBuf2)))
  516. {
  517. // This should be impossible, but we need to avoid PREfast complaints.
  518. }
  519. MessageBox(hDlg, szErrorMessage, NULL, MB_OK | MB_ICONINFORMATION);
  520. SetFocus(GetDlgItem(hDlg, nItemId));
  521. }
  522. ////////////////////////////////////////////////////////////////////////////
  523. //
  524. // Localize_Combobox_Styles
  525. //
  526. // Transform either all date or time style, as indicated by LCType, in
  527. // the indicated combobox from a value that the NLS will provide to a
  528. // localized value.
  529. //
  530. ////////////////////////////////////////////////////////////////////////////
  531. void Localize_Combobox_Styles(
  532. HWND hDlg,
  533. int nItemId,
  534. LCTYPE LCType)
  535. {
  536. BOOL bInQuote = FALSE;
  537. BOOL Map_Char = TRUE;
  538. TCHAR szBuf1[SIZE_128];
  539. TCHAR szBuf2[SIZE_128];
  540. LPTSTR lpszInBuf = szBuf1;
  541. LPTSTR lpszOutBuf = szBuf2;
  542. HWND hCtrl = GetDlgItem(hDlg, nItemId);
  543. DWORD ItemCnt = ComboBox_GetCount(hCtrl);
  544. DWORD Position = 0;
  545. DWORD dwIndex;
  546. if (!Styles_Localized)
  547. {
  548. return;
  549. }
  550. while (Position < ItemCnt)
  551. {
  552. //
  553. // Could check character count with CB_GETLBTEXTLEN to make sure
  554. // that the item text will fit in 128, but max values for these
  555. // items is 79 chars.
  556. //
  557. dwIndex = ComboBox_GetLBText(hCtrl, Position, szBuf1);
  558. if (dwIndex != CB_ERR)
  559. {
  560. lpszInBuf = szBuf1;
  561. lpszOutBuf = szBuf2;
  562. while (*lpszInBuf)
  563. {
  564. Map_Char = TRUE;
  565. #ifndef UNICODE
  566. if (IsDBCSLeadByte(*lpszInBuf))
  567. {
  568. //
  569. // Copy any double byte character straight through.
  570. //
  571. *lpszOutBuf++ = *lpszInBuf++;
  572. *lpszOutBuf++ = *lpszInBuf++;
  573. }
  574. else
  575. #endif
  576. {
  577. if (*lpszInBuf == CHAR_QUOTE)
  578. {
  579. bInQuote = !bInQuote;
  580. *lpszOutBuf++ = *lpszInBuf++;
  581. }
  582. else
  583. {
  584. if (!bInQuote)
  585. {
  586. if (LCType == LOCALE_STIMEFORMAT ||
  587. LCType == LOCALE_SLONGDATE)
  588. {
  589. Map_Char = FALSE;
  590. if (CompareString( UserLocaleID,
  591. 0,
  592. lpszInBuf,
  593. 1,
  594. TEXT("H"),
  595. 1 ) == CSTR_EQUAL)
  596. {
  597. *lpszOutBuf++ = szStyleH[0];
  598. #ifndef UNICODE
  599. if (IsDBCSLeadByte(*szStyleH))
  600. {
  601. *lpszOutBuf++ = szStyleH[1];
  602. }
  603. #endif
  604. }
  605. else if (CompareString( UserLocaleID,
  606. 0,
  607. lpszInBuf,
  608. 1,
  609. TEXT("h"),
  610. 1 ) == CSTR_EQUAL)
  611. {
  612. *lpszOutBuf++ = szStyleh[0];
  613. #ifndef UNICODE
  614. if (IsDBCSLeadByte(*szStyleh))
  615. {
  616. *lpszOutBuf++ = szStyleh[1];
  617. }
  618. #endif
  619. }
  620. else if (CompareString( UserLocaleID,
  621. 0,
  622. lpszInBuf,
  623. 1,
  624. TEXT("m"),
  625. 1 ) == CSTR_EQUAL)
  626. {
  627. *lpszOutBuf++ = szStylem[0];
  628. #ifndef UNICODE
  629. if (IsDBCSLeadByte(*szStylem))
  630. {
  631. *lpszOutBuf++ = szStylem[1];
  632. }
  633. #endif
  634. }
  635. else if (CompareString( UserLocaleID,
  636. 0,
  637. lpszInBuf,
  638. 1,
  639. TEXT("s"),
  640. 1 ) == CSTR_EQUAL)
  641. {
  642. *lpszOutBuf++ = szStyles[0];
  643. #ifndef UNICODE
  644. if (IsDBCSLeadByte(*szStyles))
  645. {
  646. *lpszOutBuf++ = szStyles[1];
  647. }
  648. #endif
  649. }
  650. else if (CompareString( UserLocaleID,
  651. 0,
  652. lpszInBuf,
  653. 1,
  654. TEXT("t"),
  655. 1 ) == CSTR_EQUAL)
  656. {
  657. *lpszOutBuf++ = szStylet[0];
  658. #ifndef UNICODE
  659. if (IsDBCSLeadByte(*szStylet))
  660. {
  661. *lpszOutBuf++ = szStylet[1];
  662. }
  663. #endif
  664. }
  665. else
  666. {
  667. Map_Char = TRUE;
  668. }
  669. }
  670. if (LCType == LOCALE_SSHORTDATE ||
  671. (LCType == LOCALE_SLONGDATE && Map_Char))
  672. {
  673. Map_Char = FALSE;
  674. if (CompareString( UserLocaleID,
  675. 0,
  676. lpszInBuf,
  677. 1,
  678. TEXT("d"),
  679. 1 ) == CSTR_EQUAL)
  680. {
  681. *lpszOutBuf++ = szStyled[0];
  682. #ifndef UNICODE
  683. if (IsDBCSLeadByte(*szStyled))
  684. {
  685. *lpszOutBuf++ = szStyled[1];
  686. }
  687. #endif
  688. }
  689. else if (CompareString( UserLocaleID,
  690. 0,
  691. lpszInBuf,
  692. 1,
  693. TEXT("M"),
  694. 1 ) == CSTR_EQUAL)
  695. {
  696. *lpszOutBuf++ = szStyleM[0];
  697. #ifndef UNICODE
  698. if (IsDBCSLeadByte(*szStyleM))
  699. {
  700. *lpszOutBuf++ = szStyleM[1];
  701. }
  702. #endif
  703. }
  704. else if (CompareString( UserLocaleID,
  705. 0,
  706. lpszInBuf,
  707. 1,
  708. TEXT("y"),
  709. 1 ) == CSTR_EQUAL)
  710. {
  711. *lpszOutBuf++ = szStyley[0];
  712. #ifndef UNICODE
  713. if (IsDBCSLeadByte(*szStyley))
  714. {
  715. *lpszOutBuf++ = szStyley[1];
  716. }
  717. #endif
  718. }
  719. else
  720. {
  721. Map_Char = TRUE;
  722. }
  723. }
  724. }
  725. if (Map_Char)
  726. {
  727. *lpszOutBuf++ = *lpszInBuf++;
  728. }
  729. else
  730. {
  731. lpszInBuf++;
  732. }
  733. }
  734. }
  735. }
  736. //
  737. // Append null to localized string.
  738. //
  739. *lpszOutBuf = 0;
  740. ComboBox_DeleteString(hCtrl, Position);
  741. ComboBox_InsertString(hCtrl, Position, szBuf2);
  742. }
  743. Position++;
  744. }
  745. }
  746. ////////////////////////////////////////////////////////////////////////////
  747. //
  748. // NLSize_Style
  749. //
  750. // Transform either date or time style, as indicated by LCType, from a
  751. // localized value to one that the NLS API will recognize.
  752. //
  753. ////////////////////////////////////////////////////////////////////////////
  754. BOOL NLSize_Style(
  755. HWND hDlg,
  756. int nItemId,
  757. LPTSTR lpszOutBuf,
  758. LCTYPE LCType)
  759. {
  760. BOOL bInQuote = FALSE;
  761. BOOL Map_Char = TRUE;
  762. TCHAR szBuf[SIZE_128];
  763. LPTSTR lpszInBuf = szBuf;
  764. LPTSTR lpNLSChars1;
  765. LPTSTR lpNLSChars2;
  766. HWND hCtrl = GetDlgItem(hDlg, nItemId);
  767. DWORD dwIndex = ComboBox_GetCurSel(hCtrl);
  768. BOOL TextFromEditBox = dwIndex == CB_ERR;
  769. int Cmp_Size;
  770. #ifndef UNICODE
  771. BOOL Is_Dbl = FALSE;
  772. #endif
  773. //
  774. // If there is no selection, get whatever is in the edit box.
  775. //
  776. if (TextFromEditBox)
  777. {
  778. dwIndex = GetDlgItemText(hDlg, nItemId, szBuf, SIZE_128);
  779. if (dwIndex)
  780. {
  781. //
  782. // Get text succeeded.
  783. //
  784. szBuf[dwIndex] = 0;
  785. }
  786. else
  787. {
  788. //
  789. // Get text failed.
  790. //
  791. dwIndex = (DWORD)CB_ERR;
  792. }
  793. }
  794. else
  795. {
  796. dwIndex = ComboBox_GetLBText(hCtrl, dwIndex, szBuf);
  797. }
  798. if (!Styles_Localized)
  799. {
  800. //lstrcpy(lpszOutBuf, lpszInBuf);
  801. // The string is either the long date, the short date, or
  802. // the long time -- all of them are the same max. length.
  803. if(FAILED(StringCchCopy(lpszOutBuf, MAX_SLONGDATE, lpszInBuf)))
  804. {
  805. // This should be impossible, but we need to avoid PREfast complaints.
  806. }
  807. return (FALSE);
  808. }
  809. switch (LCType)
  810. {
  811. case ( LOCALE_STIMEFORMAT ) :
  812. {
  813. lpNLSChars1 = szTLetters;
  814. lpNLSChars2 = szTCaseSwap;
  815. break;
  816. }
  817. case ( LOCALE_SLONGDATE ) :
  818. {
  819. lpNLSChars1 = szLDLetters;
  820. lpNLSChars2 = szLDCaseSwap;
  821. break;
  822. }
  823. case ( LOCALE_SSHORTDATE ) :
  824. {
  825. lpNLSChars1 = szSDLetters;
  826. lpNLSChars2 = szSDCaseSwap;
  827. break;
  828. }
  829. }
  830. while (*lpszInBuf)
  831. {
  832. Map_Char = TRUE;
  833. #ifdef UNICODE
  834. Cmp_Size = 1;
  835. #else
  836. Is_Dbl = IsDBCSLeadByte(*lpszInBuf);
  837. Cmp_Size = Is_Dbl ? 2 : 1;
  838. #endif
  839. if (*lpszInBuf == CHAR_QUOTE)
  840. {
  841. bInQuote = !bInQuote;
  842. *lpszOutBuf++ = *lpszInBuf++;
  843. }
  844. else
  845. {
  846. if (!bInQuote)
  847. {
  848. if (LCType == LOCALE_STIMEFORMAT || LCType == LOCALE_SLONGDATE)
  849. {
  850. Map_Char = FALSE;
  851. if (CompareString( UserLocaleID,
  852. 0,
  853. lpszInBuf,
  854. Cmp_Size,
  855. szStyleH,
  856. -1 ) == CSTR_EQUAL)
  857. {
  858. *lpszOutBuf++ = CHAR_CAP_H;
  859. }
  860. else if (CompareString( UserLocaleID,
  861. 0,
  862. lpszInBuf,
  863. Cmp_Size,
  864. szStyleh,
  865. -1 ) == CSTR_EQUAL)
  866. {
  867. *lpszOutBuf++ = CHAR_SML_H;
  868. }
  869. else if (CompareString( UserLocaleID,
  870. 0,
  871. lpszInBuf,
  872. Cmp_Size,
  873. szStylem,
  874. -1 ) == CSTR_EQUAL)
  875. {
  876. *lpszOutBuf++ = CHAR_SML_M;
  877. }
  878. else if (CompareString( UserLocaleID,
  879. 0,
  880. lpszInBuf,
  881. Cmp_Size,
  882. szStyles,
  883. -1 ) == CSTR_EQUAL)
  884. {
  885. *lpszOutBuf++ = CHAR_SML_S;
  886. }
  887. else if (CompareString( UserLocaleID,
  888. 0,
  889. lpszInBuf,
  890. Cmp_Size,
  891. szStylet,
  892. -1 ) == CSTR_EQUAL)
  893. {
  894. *lpszOutBuf++ = CHAR_SML_T;
  895. }
  896. else
  897. {
  898. Map_Char = TRUE;
  899. }
  900. }
  901. if (LCType == LOCALE_SSHORTDATE ||
  902. (LCType == LOCALE_SLONGDATE && Map_Char))
  903. {
  904. Map_Char = FALSE;
  905. if (CompareString( UserLocaleID,
  906. 0,
  907. lpszInBuf,
  908. Cmp_Size,
  909. szStyled,
  910. -1 ) == CSTR_EQUAL)
  911. {
  912. *lpszOutBuf++ = CHAR_SML_D;
  913. }
  914. else if (CompareString( UserLocaleID,
  915. 0,
  916. lpszInBuf,
  917. Cmp_Size,
  918. szStyleM,
  919. -1) == CSTR_EQUAL)
  920. {
  921. *lpszOutBuf++ = CHAR_CAP_M;
  922. }
  923. else if (CompareString( UserLocaleID,
  924. 0,
  925. lpszInBuf,
  926. Cmp_Size,
  927. szStyley,
  928. -1 ) == CSTR_EQUAL)
  929. {
  930. *lpszOutBuf++ = CHAR_SML_Y;
  931. }
  932. else if (CompareString( UserLocaleID,
  933. 0,
  934. lpszInBuf,
  935. Cmp_Size,
  936. TEXT("g"),
  937. -1) == CSTR_EQUAL)
  938. {
  939. //
  940. // g is not localized, but it's legal.
  941. //
  942. *lpszOutBuf++ = CHAR_SML_G;
  943. }
  944. else
  945. {
  946. Map_Char = TRUE;
  947. }
  948. }
  949. }
  950. if (Map_Char)
  951. {
  952. //
  953. // Just copy chars in quotes or chars that are not
  954. // recognized. Leave the char checking to the other
  955. // function. However, do check for NLS standard chars
  956. // that were not supposed to be here due to localization.
  957. //
  958. if ( !bInQuote &&
  959. #ifndef UNICODE
  960. !Is_Dbl &&
  961. #endif
  962. (CompareString( UserLocaleID,
  963. 0,
  964. lpszInBuf,
  965. Cmp_Size,
  966. TEXT(" "),
  967. -1 ) != CSTR_EQUAL) &&
  968. ( _tcschr(lpNLSChars1, *lpszInBuf) ||
  969. _tcschr(lpNLSChars2, *lpszInBuf) ) )
  970. {
  971. return (TRUE);
  972. }
  973. *lpszOutBuf++ = *lpszInBuf++;
  974. #ifndef UNICODE
  975. if (Is_Dbl)
  976. {
  977. //
  978. // Copy 2nd byte.
  979. //
  980. *lpszOutBuf++ = *lpszInBuf++;
  981. }
  982. #endif
  983. }
  984. #ifndef UNICODE
  985. else if (Is_Dbl)
  986. {
  987. lpszInBuf += 2;
  988. }
  989. #endif
  990. else
  991. {
  992. lpszInBuf++;
  993. }
  994. }
  995. }
  996. //
  997. // Append null to localized string.
  998. //
  999. *lpszOutBuf = 0;
  1000. return (FALSE);
  1001. }
  1002. #ifndef WINNT
  1003. ////////////////////////////////////////////////////////////////////////////
  1004. //
  1005. // SDate3_1_Compatibility
  1006. //
  1007. // There is a requirement to keep windows 3.1 compatibility in the
  1008. // registry (win.ini). Only allow 1 or 2 'M's, 1 or 2 'd's, and
  1009. // 2 or 4 'y's. The remainder of the date style is compatible.
  1010. //
  1011. ////////////////////////////////////////////////////////////////////////////
  1012. void SDate3_1_Compatibility(
  1013. LPTSTR lpszBuf,
  1014. int Buf_Size)
  1015. {
  1016. BOOL bInQuote = FALSE;
  1017. int Index, Del_Cnt;
  1018. int Len = lstrlen(lpszBuf);
  1019. int MCnt = 0; // running total of Ms
  1020. int dCnt = 0; // running total of ds
  1021. int yCnt = 0; // running total of ys
  1022. while (*lpszBuf)
  1023. {
  1024. #ifndef UNICODE
  1025. if (IsDBCSLeadByte(*lpszBuf))
  1026. {
  1027. lpszBuf += 2;
  1028. }
  1029. else
  1030. #endif
  1031. {
  1032. if (bInQuote)
  1033. {
  1034. bInQuote = (*lpszBuf != CHAR_QUOTE);
  1035. lpszBuf++;
  1036. }
  1037. else if (*lpszBuf == CHAR_CAP_M)
  1038. {
  1039. if (MCnt++ < 2)
  1040. {
  1041. lpszBuf++;
  1042. }
  1043. else
  1044. {
  1045. //
  1046. // At least 1 extra M. Move all of the chars, including
  1047. // null, up by Del_Cnt.
  1048. //
  1049. Del_Cnt = 1;
  1050. Index = 1;
  1051. while (lpszBuf[Index++] == CHAR_CAP_M)
  1052. {
  1053. Del_Cnt++;
  1054. }
  1055. for (Index = 0; Index <= Len - Del_Cnt + 1; Index++)
  1056. {
  1057. lpszBuf[Index] = lpszBuf[Index + Del_Cnt];
  1058. }
  1059. Len -= Del_Cnt;
  1060. }
  1061. }
  1062. else if (*lpszBuf == CHAR_SML_D)
  1063. {
  1064. if (dCnt++ < 2)
  1065. {
  1066. lpszBuf++;
  1067. }
  1068. else
  1069. {
  1070. //
  1071. // At least 1 extra d. Move all of the chars, including
  1072. // null, up by Del_Cnt.
  1073. //
  1074. Del_Cnt = 1;
  1075. Index = 1;
  1076. while (lpszBuf[Index++] == CHAR_SML_D)
  1077. {
  1078. Del_Cnt++;
  1079. }
  1080. for (Index = 0; Index <= Len - Del_Cnt + 1; Index++)
  1081. {
  1082. lpszBuf[Index] = lpszBuf[Index + Del_Cnt];
  1083. }
  1084. Len -= Del_Cnt;
  1085. }
  1086. }
  1087. else if (*lpszBuf == CHAR_SML_Y)
  1088. {
  1089. if (yCnt == 0 || yCnt == 2)
  1090. {
  1091. if (lpszBuf[1] == CHAR_SML_Y)
  1092. {
  1093. lpszBuf += 2;
  1094. yCnt += 2;
  1095. }
  1096. else if (Len < Buf_Size - 1)
  1097. {
  1098. //
  1099. // Odd # of ys & room for one more.
  1100. // Move the remaining text down by 1 (the y will
  1101. // be copied).
  1102. //
  1103. // Use Del_Cnt for unparsed string length.
  1104. //
  1105. Del_Cnt = lstrlen(lpszBuf);
  1106. for (Index = Del_Cnt + 1; Index > 0; Index--)
  1107. {
  1108. lpszBuf[Index] = lpszBuf[Index - 1];
  1109. }
  1110. }
  1111. else
  1112. {
  1113. //
  1114. // No room, move all of the chars, including null,
  1115. // up by 1.
  1116. //
  1117. for (Index = 0; Index <= Len; Index++)
  1118. {
  1119. lpszBuf[Index] = lpszBuf[Index + 1];
  1120. }
  1121. Len--;
  1122. }
  1123. }
  1124. else
  1125. {
  1126. //
  1127. // At least 1 extra y. Move all of the chars, including
  1128. // null, up by Del_Cnt.
  1129. //
  1130. Del_Cnt = 1;
  1131. Index = 1;
  1132. while (lpszBuf[Index++] == CHAR_SML_Y)
  1133. {
  1134. Del_Cnt++;
  1135. }
  1136. for (Index = 0; Index <= Len - Del_Cnt + 1; Index++)
  1137. {
  1138. lpszBuf[Index] = lpszBuf[Index + Del_Cnt];
  1139. }
  1140. Len -= Del_Cnt;
  1141. }
  1142. }
  1143. else if (*lpszBuf == CHAR_QUOTE)
  1144. {
  1145. lpszBuf++;
  1146. bInQuote = TRUE;
  1147. }
  1148. else
  1149. {
  1150. lpszBuf++;
  1151. }
  1152. }
  1153. }
  1154. }
  1155. #endif
  1156. ////////////////////////////////////////////////////////////////////////////
  1157. //
  1158. // Set_Locale_Values
  1159. //
  1160. // Set_Locale_Values is called for each LCType that has either been
  1161. // directly modified via a user change, or indirectly modified by the user
  1162. // changing the regional locale setting. When a dialog handle is available,
  1163. // Set_Locale_Values will pull the new value of the LCType from the
  1164. // appropriate list box (this is a direct change), register it in the
  1165. // locale database, and then update the registry string. If no dialog
  1166. // handle is available, it will simply update the registry string based on
  1167. // the locale registry. If the registration succeeds, return true.
  1168. // Otherwise, return false.
  1169. //
  1170. ////////////////////////////////////////////////////////////////////////////
  1171. BOOL Set_Locale_Values(
  1172. HWND hDlg,
  1173. LCTYPE LCType,
  1174. int nItemId,
  1175. LPTSTR lpIniStr,
  1176. BOOL bValue,
  1177. int Ordinal_Offset,
  1178. LPTSTR Append_Str,
  1179. LPTSTR NLS_Str)
  1180. {
  1181. DWORD dwIndex;
  1182. BOOL bSuccess = TRUE;
  1183. int cchBuf = SIZE_128 + 1;
  1184. TCHAR szBuf[SIZE_128 + 1];
  1185. LPTSTR pBuf = szBuf;
  1186. HWND hCtrl;
  1187. if (NLS_Str)
  1188. {
  1189. //
  1190. // Use a non-localized string.
  1191. //
  1192. //lstrcpy(pBuf, NLS_Str);
  1193. if(FAILED(StringCchCopy(pBuf, cchBuf, NLS_Str)))
  1194. {
  1195. // This should be impossible, but we need to avoid PREfast complaints.
  1196. return(FALSE);
  1197. }
  1198. bSuccess = SetLocaleInfo(UserLocaleID, LCType, pBuf);
  1199. }
  1200. else if (hDlg)
  1201. {
  1202. //
  1203. // Get the new value from the list box.
  1204. //
  1205. hCtrl = GetDlgItem(hDlg, nItemId);
  1206. dwIndex = ComboBox_GetCurSel(hCtrl);
  1207. //
  1208. // If there is no selection, get whatever is in the edit box.
  1209. //
  1210. if (dwIndex == CB_ERR)
  1211. {
  1212. dwIndex = GetDlgItemText(hDlg, nItemId, pBuf, SIZE_128);
  1213. if (dwIndex)
  1214. {
  1215. //
  1216. // Get text succeeded.
  1217. //
  1218. pBuf[dwIndex] = 0;
  1219. }
  1220. else
  1221. {
  1222. //
  1223. // Get text failed.
  1224. // Allow the AM/PM symbols to be set as empty strings.
  1225. // Otherwise, fail.
  1226. //
  1227. if ((LCType == LOCALE_S1159) || (LCType == LOCALE_S2359))
  1228. {
  1229. pBuf[0] = 0;
  1230. }
  1231. else
  1232. {
  1233. bSuccess = FALSE;
  1234. }
  1235. }
  1236. }
  1237. else if (bValue)
  1238. {
  1239. //
  1240. // Need string representation of ordinal locale value.
  1241. //
  1242. if (nItemId == IDC_CALENDAR_TYPE)
  1243. {
  1244. dwIndex = (DWORD)ComboBox_GetItemData(hCtrl, dwIndex);
  1245. }
  1246. else
  1247. {
  1248. //
  1249. // Ordinal_Offset is required since calendar is 1 based,
  1250. // not 0 based.
  1251. //
  1252. dwIndex += Ordinal_Offset;
  1253. }
  1254. //
  1255. // Special case the grouping string.
  1256. //
  1257. if (nItemId == IDC_NUM_DIGITS_GROUP)
  1258. {
  1259. switch (dwIndex)
  1260. {
  1261. case ( 0 ) :
  1262. {
  1263. //lstrcpy(pBuf, TEXT("0"));
  1264. if(FAILED(StringCchCopy(pBuf, cchBuf, TEXT("0"))))
  1265. {
  1266. // This should be impossible, but we need to avoid PREfast complaints.
  1267. }
  1268. break;
  1269. }
  1270. case ( 1 ) :
  1271. {
  1272. //lstrcpy(pBuf, TEXT("3"));
  1273. if(FAILED(StringCchCopy(pBuf, cchBuf, TEXT("3"))))
  1274. {
  1275. // This should be impossible, but we need to avoid PREfast complaints.
  1276. }
  1277. break;
  1278. }
  1279. case ( 2 ) :
  1280. {
  1281. //lstrcpy(pBuf, TEXT("3;2"));
  1282. if(FAILED(StringCchCopy(pBuf, cchBuf, TEXT("3;2"))))
  1283. {
  1284. // This should be impossible, but we need to avoid PREfast complaints.
  1285. }
  1286. break;
  1287. }
  1288. case ( 3 ) :
  1289. {
  1290. //wsprintf( pBuf,
  1291. // TEXT("%d"),
  1292. // ComboBox_GetItemData(hCtrl, dwIndex) );
  1293. if(FAILED(StringCchPrintf( pBuf,
  1294. cchBuf,
  1295. TEXT("%d"),
  1296. ComboBox_GetItemData(hCtrl, dwIndex))))
  1297. {
  1298. // This should be impossible, but we need to avoid PREfast complaints.
  1299. }
  1300. break;
  1301. }
  1302. }
  1303. }
  1304. else if (dwIndex < cInt_Str)
  1305. {
  1306. //lstrcpy(pBuf, aInt_Str[dwIndex]);
  1307. if(FAILED(StringCchCopy(pBuf, cchBuf, aInt_Str[dwIndex])))
  1308. {
  1309. // This should be impossible, but we need to avoid PREfast complaints.
  1310. }
  1311. }
  1312. else
  1313. {
  1314. //wsprintf(pBuf, TEXT("%d"), dwIndex);
  1315. if(FAILED(StringCchPrintf(pBuf, cchBuf, TEXT("%d"), dwIndex)))
  1316. {
  1317. // This should be impossible, but we need to avoid PREfast complaints.
  1318. }
  1319. }
  1320. }
  1321. else
  1322. {
  1323. //
  1324. // Get actual value of locale data.
  1325. //
  1326. bSuccess = (ComboBox_GetLBText(hCtrl, dwIndex, pBuf) != CB_ERR);
  1327. }
  1328. if (bSuccess)
  1329. {
  1330. //
  1331. // If edit text, index value or selection text succeeds...
  1332. //
  1333. if (Append_Str)
  1334. {
  1335. //lstrcat(pBuf, Append_Str);
  1336. if(FAILED(StringCchCat(pBuf, cchBuf, Append_Str)))
  1337. {
  1338. // This should be impossible, but we need to avoid PREfast complaints.
  1339. }
  1340. }
  1341. //
  1342. // If this is sNativeDigits, the LPK is installed, and the
  1343. // first char is 0x206f (nominal digit shapes), then do not
  1344. // store the first char in the registry.
  1345. //
  1346. if ((LCType == LOCALE_SNATIVEDIGITS) &&
  1347. (bLPKInstalled) &&
  1348. (pBuf[0] == TEXT('\x206f')))
  1349. {
  1350. pBuf++;
  1351. }
  1352. bSuccess = SetLocaleInfo( UserLocaleID, LCType, pBuf );
  1353. }
  1354. }
  1355. if (lpIniStr && bSuccess)
  1356. {
  1357. //
  1358. // Set the registry string to the string that is stored in the list
  1359. // box. If there is no dialog handle, get the required string
  1360. // locale value from the NLS function. Write the associated string
  1361. // into the registry.
  1362. //
  1363. if (!hDlg && !NLS_Str)
  1364. {
  1365. GetLocaleInfo( UserLocaleID,
  1366. LCType | LOCALE_NOUSEROVERRIDE,
  1367. pBuf,
  1368. SIZE_128 );
  1369. }
  1370. #ifndef WINNT
  1371. //
  1372. // There is a requirement to keep windows 3.1 compatibility in the
  1373. // win.ini. There are some win32 short date formats that are
  1374. // incompatible with exisiting win 3.1 apps... modify these styles.
  1375. //
  1376. if (LCType == LOCALE_SSHORTDATE)
  1377. {
  1378. SDate3_1_Compatibility(pBuf, SIZE_128);
  1379. }
  1380. #endif
  1381. //
  1382. // Check the value whether it is empty or not.
  1383. //
  1384. switch (LCType)
  1385. {
  1386. case ( LOCALE_STHOUSAND ) :
  1387. case ( LOCALE_SDECIMAL ) :
  1388. case ( LOCALE_SDATE ) :
  1389. case ( LOCALE_STIME ) :
  1390. case ( LOCALE_SLIST ) :
  1391. {
  1392. CheckEmptyString(pBuf);
  1393. break;
  1394. }
  1395. }
  1396. //
  1397. // Set the locale information in the registry.
  1398. //
  1399. // NOTE: We want to use SetLocaleInfo if possible so that the
  1400. // NLS cache is updated right away. Otherwise, we'll
  1401. // simply use WriteProfileString.
  1402. //
  1403. if (!SetLocaleInfo(UserLocaleID, LCType, pBuf))
  1404. {
  1405. WriteProfileString(szIntl, lpIniStr, pBuf);
  1406. }
  1407. }
  1408. else if (!bSuccess)
  1409. {
  1410. LoadString(hInstance, IDS_LOCALE_SET_ERROR, szBuf, SIZE_128);
  1411. MessageBox(hDlg, szBuf, NULL, MB_OK | MB_ICONINFORMATION);
  1412. SetFocus(GetDlgItem(hDlg, nItemId));
  1413. return (FALSE);
  1414. }
  1415. return (TRUE);
  1416. }
  1417. ////////////////////////////////////////////////////////////////////////////
  1418. //
  1419. // Set_List_Values
  1420. //
  1421. // Set_List_Values is called several times for each drop down list which is
  1422. // populated via an enum function. The first call to this function should
  1423. // be with a valid dialog handle, valid dialog item ID, and null string
  1424. // value. If the function is not already in use, it will clear the list box
  1425. // and store the handle and id information for the subsequent calls to this
  1426. // function that will be made by the enumeration function. The calls from
  1427. // the enumeration function will add the specified string values to the
  1428. // list box. When the enumeration function is complete, this function
  1429. // should be called with a null dialog handle, the valid dialog item id,
  1430. // and a null string value. This will clear all of the state information,
  1431. // including the lock flag.
  1432. //
  1433. ////////////////////////////////////////////////////////////////////////////
  1434. BOOL Set_List_Values(
  1435. HWND hDlg,
  1436. int nItemId,
  1437. LPTSTR lpValueString)
  1438. {
  1439. static BOOL bLock, bString;
  1440. static HWND hDialog;
  1441. static int nDItemId, nID;
  1442. if (!lpValueString)
  1443. {
  1444. //
  1445. // Clear the lock if there is no dialog handle and the item IDs
  1446. // match.
  1447. //
  1448. if (bLock && !hDlg && (nItemId == nDItemId))
  1449. {
  1450. if (nItemId != IDC_CALENDAR_TYPE)
  1451. {
  1452. hDialog = 0;
  1453. nDItemId = 0;
  1454. bLock = FALSE;
  1455. }
  1456. else
  1457. {
  1458. if (bString)
  1459. {
  1460. hDialog = 0;
  1461. nDItemId = 0;
  1462. bLock = FALSE;
  1463. bString = FALSE;
  1464. }
  1465. else
  1466. {
  1467. nID = 0;
  1468. bString = TRUE;
  1469. }
  1470. }
  1471. return (TRUE);
  1472. }
  1473. //
  1474. // Return false, for failure, if the function is locked or if the
  1475. // handle or ID parameters are null.
  1476. //
  1477. if (bLock || !hDlg || !nItemId)
  1478. {
  1479. return (FALSE);
  1480. }
  1481. //
  1482. // Prepare for subsequent calls to populate the list box.
  1483. //
  1484. bLock = TRUE;
  1485. hDialog = hDlg;
  1486. nDItemId = nItemId;
  1487. }
  1488. else if (bLock && hDialog && nDItemId)
  1489. {
  1490. //
  1491. // Add the string to the list box.
  1492. //
  1493. if (!bString)
  1494. {
  1495. ComboBox_InsertString( GetDlgItem(hDialog, nDItemId),
  1496. -1,
  1497. lpValueString );
  1498. }
  1499. else
  1500. {
  1501. ComboBox_SetItemData( GetDlgItem(hDialog, nDItemId),
  1502. nID++,
  1503. Intl_StrToLong(lpValueString) );
  1504. }
  1505. }
  1506. else
  1507. {
  1508. return (FALSE);
  1509. }
  1510. return (TRUE);
  1511. }
  1512. ////////////////////////////////////////////////////////////////////////////
  1513. //
  1514. // DropDown_Use_Locale_Values
  1515. //
  1516. // Get the user locale value for the locale type specifier. Add it to
  1517. // the list box and make this value the current selection. If the user
  1518. // locale value for the locale type is different than the system value,
  1519. // add the system value to the list box. If the user default is different
  1520. // than the user override, add the user default.
  1521. //
  1522. ////////////////////////////////////////////////////////////////////////////
  1523. void DropDown_Use_Locale_Values(
  1524. HWND hDlg,
  1525. LCTYPE LCType,
  1526. int nItemId)
  1527. {
  1528. TCHAR szBuf[SIZE_128];
  1529. TCHAR szCmpBuf1[SIZE_128];
  1530. TCHAR szCmpBuf2[SIZE_128];
  1531. HWND hCtrl = GetDlgItem(hDlg, nItemId);
  1532. int ctr;
  1533. if (GetLocaleInfo(UserLocaleID, LCType, szBuf, SIZE_128))
  1534. {
  1535. ComboBox_SetCurSel(hCtrl, ComboBox_InsertString(hCtrl, -1, szBuf));
  1536. //
  1537. // If the system setting is different, add it to the list box.
  1538. //
  1539. if (GetLocaleInfo( SysLocaleID,
  1540. LCType | LOCALE_NOUSEROVERRIDE,
  1541. szCmpBuf1,
  1542. SIZE_128 ))
  1543. {
  1544. if (CompareString( UserLocaleID,
  1545. 0,
  1546. szCmpBuf1,
  1547. -1,
  1548. szBuf,
  1549. -1 ) != CSTR_EQUAL)
  1550. {
  1551. ComboBox_InsertString(hCtrl, -1, szCmpBuf1);
  1552. }
  1553. }
  1554. //
  1555. // If the default user locale setting is different than the user
  1556. // overridden setting and different than the system setting, add
  1557. // it to the list box.
  1558. //
  1559. if (GetLocaleInfo( UserLocaleID,
  1560. LCType | LOCALE_NOUSEROVERRIDE,
  1561. szCmpBuf2,
  1562. SIZE_128 ))
  1563. {
  1564. if (CompareString(UserLocaleID, 0, szCmpBuf2, -1, szBuf, -1) != CSTR_EQUAL &&
  1565. CompareString(UserLocaleID, 0, szCmpBuf2, -1, szCmpBuf1, -1) != CSTR_EQUAL)
  1566. {
  1567. ComboBox_InsertString(hCtrl, -1, szCmpBuf2);
  1568. }
  1569. }
  1570. }
  1571. else
  1572. {
  1573. //
  1574. // Failed to get user value, try for system value. If system value
  1575. // fails, display a message box indicating that there was a locale
  1576. // problem.
  1577. //
  1578. if (GetLocaleInfo( SysLocaleID,
  1579. LCType | LOCALE_NOUSEROVERRIDE,
  1580. szBuf,
  1581. SIZE_128 ))
  1582. {
  1583. ComboBox_SetCurSel(hCtrl, ComboBox_InsertString(hCtrl, -1, szBuf));
  1584. }
  1585. else
  1586. {
  1587. MessageBox(hDlg, szLocaleGetError, NULL, MB_OK | MB_ICONINFORMATION);
  1588. }
  1589. }
  1590. //
  1591. // If it's the date separator, then we want slash, dot, and dash in
  1592. // the list in addition to the user and system settings (if different).
  1593. //
  1594. if (LCType == LOCALE_SDATE)
  1595. {
  1596. for (ctr = 0; ctr < NUM_DATE_SEPARATORS; ctr++)
  1597. {
  1598. if (ComboBox_FindStringExact( hCtrl,
  1599. -1,
  1600. pDateSeparators[ctr] ) == CB_ERR)
  1601. {
  1602. ComboBox_InsertString(hCtrl, -1, pDateSeparators[ctr]);
  1603. }
  1604. }
  1605. }
  1606. //
  1607. // If it's the AM symbol, then we want AM in the list in addition
  1608. // to the user and system settings (if different).
  1609. //
  1610. if (LCType == LOCALE_S1159)
  1611. {
  1612. for (ctr = 0; ctr < NUM_AM_SYMBOLS; ctr++)
  1613. {
  1614. if (ComboBox_FindStringExact( hCtrl,
  1615. -1,
  1616. pAMSymbols[ctr] ) == CB_ERR)
  1617. {
  1618. ComboBox_InsertString(hCtrl, -1, pAMSymbols[ctr]);
  1619. }
  1620. }
  1621. }
  1622. //
  1623. // If it's the PM symbol, then we want PM in the list in addition
  1624. // to the user and system settings (if different).
  1625. //
  1626. if (LCType == LOCALE_S2359)
  1627. {
  1628. for (ctr = 0; ctr < NUM_PM_SYMBOLS; ctr++)
  1629. {
  1630. if (ComboBox_FindStringExact( hCtrl,
  1631. -1,
  1632. pPMSymbols[ctr] ) == CB_ERR)
  1633. {
  1634. ComboBox_InsertString(hCtrl, -1, pPMSymbols[ctr]);
  1635. }
  1636. }
  1637. }
  1638. #ifdef UNICODE
  1639. //
  1640. // If it's the currency symbol, then we want the Euro symbol and dollar
  1641. // sign in the list in addition to the user and system settings (if
  1642. // different).
  1643. //
  1644. if (LCType == LOCALE_SCURRENCY)
  1645. {
  1646. for (ctr = 0; ctr < NUM_CURRENCY_SYMBOLS; ctr++)
  1647. {
  1648. if (ComboBox_FindStringExact( hCtrl,
  1649. -1,
  1650. pCurrencySymbols[ctr] ) == CB_ERR)
  1651. {
  1652. ComboBox_InsertString(hCtrl, -1, pCurrencySymbols[ctr]);
  1653. }
  1654. }
  1655. }
  1656. #endif
  1657. }
  1658. ////////////////////////////////////////////////////////////////////////////
  1659. //
  1660. // EnumProc
  1661. //
  1662. // This call back function calls Set_List_Values assuming that whatever
  1663. // code called the NLS enumeration function (or dummied enumeration
  1664. // function) has properly set up Set_List_Values for the list box
  1665. // population.
  1666. //
  1667. ////////////////////////////////////////////////////////////////////////////
  1668. BOOL CALLBACK EnumProc(
  1669. LPTSTR lpValueString)
  1670. {
  1671. return (Set_List_Values(0, 0, lpValueString));
  1672. }
  1673. ////////////////////////////////////////////////////////////////////////////
  1674. //
  1675. // EnumProcEx
  1676. //
  1677. // This call back function calls Set_List_Values assuming that whatever
  1678. // code called the enumeration function has properly set up
  1679. // Set_List_Values for the list box population.
  1680. // Also, this function fixes the string passed in to contain the correct
  1681. // decimal separator and negative sign, if appropriate.
  1682. //
  1683. ////////////////////////////////////////////////////////////////////////////
  1684. BOOL CALLBACK EnumProcEx(
  1685. LPTSTR lpValueString,
  1686. LPTSTR lpDecimalString,
  1687. LPTSTR lpNegativeString,
  1688. LPTSTR lpSymbolString)
  1689. {
  1690. TCHAR szString[SIZE_128];
  1691. LPTSTR pStr, pValStr, pTemp;
  1692. //
  1693. // Simplify things if we have a NULL string.
  1694. //
  1695. if (lpDecimalString && (*lpDecimalString == CHAR_NULL))
  1696. {
  1697. lpDecimalString = NULL;
  1698. }
  1699. if (lpNegativeString && (*lpNegativeString == CHAR_NULL))
  1700. {
  1701. lpNegativeString = NULL;
  1702. }
  1703. if (lpSymbolString && (*lpSymbolString == CHAR_NULL))
  1704. {
  1705. lpSymbolString = NULL;
  1706. }
  1707. //
  1708. // See if we need to do any substitutions.
  1709. //
  1710. if (lpDecimalString || lpNegativeString || lpSymbolString)
  1711. {
  1712. pValStr = lpValueString;
  1713. pStr = szString;
  1714. while (*pValStr)
  1715. {
  1716. if (lpDecimalString && (*pValStr == CHAR_DECIMAL))
  1717. {
  1718. //
  1719. // Substitute the current user decimal separator.
  1720. //
  1721. pTemp = lpDecimalString;
  1722. while (*pTemp)
  1723. {
  1724. *pStr = *pTemp;
  1725. pStr++;
  1726. pTemp++;
  1727. }
  1728. }
  1729. else if (lpNegativeString && (*pValStr == CHAR_HYPHEN))
  1730. {
  1731. //
  1732. // Substitute the current user negative sign.
  1733. //
  1734. pTemp = lpNegativeString;
  1735. while (*pTemp)
  1736. {
  1737. *pStr = *pTemp;
  1738. pStr++;
  1739. pTemp++;
  1740. }
  1741. }
  1742. else if (lpSymbolString && (*pValStr == CHAR_INTL_CURRENCY))
  1743. {
  1744. //
  1745. // Substitute the current user currency symbol.
  1746. //
  1747. pTemp = lpSymbolString;
  1748. while (*pTemp)
  1749. {
  1750. *pStr = *pTemp;
  1751. pStr++;
  1752. pTemp++;
  1753. }
  1754. }
  1755. else
  1756. {
  1757. //
  1758. // Simply copy the character.
  1759. //
  1760. *pStr = *pValStr;
  1761. pStr++;
  1762. }
  1763. pValStr++;
  1764. }
  1765. *pStr = CHAR_NULL;
  1766. return (Set_List_Values(0, 0, szString));
  1767. }
  1768. else
  1769. {
  1770. return (Set_List_Values(0, 0, lpValueString));
  1771. }
  1772. }
  1773. ////////////////////////////////////////////////////////////////////////////
  1774. //
  1775. // EnumLeadingZeros
  1776. //
  1777. ////////////////////////////////////////////////////////////////////////////
  1778. BOOL EnumLeadingZeros(
  1779. LEADINGZEROS_ENUMPROC lpLeadingZerosEnumProc,
  1780. LCID LCId,
  1781. DWORD dwFlags)
  1782. {
  1783. TCHAR szBuf[SIZE_128];
  1784. TCHAR szDecimal[SIZE_128];
  1785. //
  1786. // If there is no enum proc, return false to indicate a failure.
  1787. //
  1788. if (!lpLeadingZerosEnumProc)
  1789. {
  1790. return (FALSE);
  1791. }
  1792. //
  1793. // Get the Decimal Separator for the current user locale so that
  1794. // it may be displayed correctly.
  1795. //
  1796. if (!GetLocaleInfo(UserLocaleID, LOCALE_SDECIMAL, szDecimal, SIZE_128) ||
  1797. ((szDecimal[0] == CHAR_DECIMAL) && (szDecimal[1] == CHAR_NULL)))
  1798. {
  1799. szDecimal[0] = CHAR_NULL;
  1800. }
  1801. //
  1802. // Call enum proc with the NO string. Check to make sure the
  1803. // enum proc requests continuation.
  1804. //
  1805. LoadString(hInstance, IDS_NO_LZERO, szBuf, SIZE_128);
  1806. if (!lpLeadingZerosEnumProc(szBuf, szDecimal, NULL, NULL))
  1807. {
  1808. return (TRUE);
  1809. }
  1810. //
  1811. // Call enum proc with the YES string.
  1812. //
  1813. LoadString(hInstance, IDS_LZERO, szBuf, SIZE_128);
  1814. lpLeadingZerosEnumProc(szBuf, szDecimal, NULL, NULL);
  1815. return (TRUE);
  1816. }
  1817. ////////////////////////////////////////////////////////////////////////////
  1818. //
  1819. // EnumNegNumFmt
  1820. //
  1821. ////////////////////////////////////////////////////////////////////////////
  1822. BOOL EnumNegNumFmt(
  1823. NEGNUMFMT_ENUMPROC lpNegNumFmtEnumProc,
  1824. LCID LCId,
  1825. DWORD dwFlags)
  1826. {
  1827. TCHAR szDecimal[SIZE_128];
  1828. TCHAR szNeg[SIZE_128];
  1829. int ctr;
  1830. //
  1831. // If there is no enum proc, return false to indicate a failure.
  1832. //
  1833. if (!lpNegNumFmtEnumProc)
  1834. {
  1835. return (FALSE);
  1836. }
  1837. //
  1838. // Get the Decimal Separator for the current user locale so that
  1839. // it may be displayed correctly.
  1840. //
  1841. if (!GetLocaleInfo(UserLocaleID, LOCALE_SDECIMAL, szDecimal, SIZE_128) ||
  1842. ((szDecimal[0] == CHAR_DECIMAL) && (szDecimal[1] == CHAR_NULL)))
  1843. {
  1844. szDecimal[0] = CHAR_NULL;
  1845. }
  1846. //
  1847. // Get the Negative Sign for the current user locale so that
  1848. // it may be displayed correctly.
  1849. //
  1850. if (!GetLocaleInfo(UserLocaleID, LOCALE_SNEGATIVESIGN, szNeg, SIZE_128) ||
  1851. ((szNeg[0] == CHAR_HYPHEN) && (szNeg[1] == CHAR_NULL)))
  1852. {
  1853. szNeg[0] = CHAR_NULL;
  1854. }
  1855. //
  1856. // Call enum proc with each format string. Check to make sure
  1857. // the enum proc requests continuation.
  1858. //
  1859. for (ctr = 0; ctr < NUM_NEG_NUMBER_FORMATS; ctr++)
  1860. {
  1861. if (!lpNegNumFmtEnumProc( pNegNumberFormats[ctr],
  1862. szDecimal,
  1863. szNeg,
  1864. NULL ))
  1865. {
  1866. return (TRUE);
  1867. }
  1868. }
  1869. return (TRUE);
  1870. }
  1871. ////////////////////////////////////////////////////////////////////////////
  1872. //
  1873. // EnumMeasureSystem
  1874. //
  1875. ////////////////////////////////////////////////////////////////////////////
  1876. BOOL EnumMeasureSystem(
  1877. MEASURESYSTEM_ENUMPROC lpMeasureSystemEnumProc,
  1878. LCID LCId,
  1879. DWORD dwFlags)
  1880. {
  1881. TCHAR szBuf[SIZE_128];
  1882. //
  1883. // If there is no enum proc, return false to indicate a failure.
  1884. //
  1885. if (!lpMeasureSystemEnumProc)
  1886. {
  1887. return (FALSE);
  1888. }
  1889. //
  1890. // Call enum proc with the metric string. Check to make sure the
  1891. // enum proc requests continuation.
  1892. //
  1893. LoadString(hInstance, IDS_METRIC, szBuf, SIZE_128);
  1894. if (!lpMeasureSystemEnumProc(szBuf))
  1895. {
  1896. return (TRUE);
  1897. }
  1898. //
  1899. // Call enum proc with the U.S. string.
  1900. //
  1901. LoadString(hInstance, IDS_US, szBuf, SIZE_128);
  1902. lpMeasureSystemEnumProc(szBuf);
  1903. return (TRUE);
  1904. }
  1905. ////////////////////////////////////////////////////////////////////////////
  1906. //
  1907. // EnumPosCurrency
  1908. //
  1909. ////////////////////////////////////////////////////////////////////////////
  1910. BOOL EnumPosCurrency(
  1911. POSCURRENCY_ENUMPROC lpPosCurrencyEnumProc,
  1912. LCID LCId,
  1913. DWORD dwFlags)
  1914. {
  1915. TCHAR szDecimal[SIZE_128];
  1916. TCHAR szSymbol[SIZE_128];
  1917. int ctr;
  1918. //
  1919. // If there is no enum proc, return false to indicate a failure.
  1920. //
  1921. if (!lpPosCurrencyEnumProc)
  1922. {
  1923. return (FALSE);
  1924. }
  1925. //
  1926. // Get the Decimal Separator for the current user locale so that
  1927. // it may be displayed correctly.
  1928. //
  1929. if (!GetLocaleInfo(UserLocaleID, LOCALE_SMONDECIMALSEP, szDecimal, SIZE_128) ||
  1930. ((szDecimal[0] == CHAR_DECIMAL) && (szDecimal[1] == CHAR_NULL)))
  1931. {
  1932. szDecimal[0] = CHAR_NULL;
  1933. }
  1934. //
  1935. // Get the Currency Symbol for the current user locale so that
  1936. // it may be displayed correctly.
  1937. //
  1938. if (!GetLocaleInfo(UserLocaleID, LOCALE_SCURRENCY, szSymbol, SIZE_128) ||
  1939. ((szSymbol[0] == CHAR_INTL_CURRENCY) && (szSymbol[1] == CHAR_NULL)))
  1940. {
  1941. szSymbol[0] = CHAR_NULL;
  1942. }
  1943. //
  1944. // Call enum proc with each format string. Check to make sure the
  1945. // enum proc requests continuation.
  1946. //
  1947. for (ctr = 0; ctr < NUM_POS_CURRENCY_FORMATS; ctr++)
  1948. {
  1949. if (!lpPosCurrencyEnumProc( pPosCurrencyFormats[ctr],
  1950. szDecimal,
  1951. NULL,
  1952. szSymbol ))
  1953. {
  1954. return (TRUE);
  1955. }
  1956. }
  1957. return (TRUE);
  1958. }
  1959. ////////////////////////////////////////////////////////////////////////////
  1960. //
  1961. // EnumNegCurrency
  1962. //
  1963. ////////////////////////////////////////////////////////////////////////////
  1964. BOOL EnumNegCurrency(
  1965. NEGCURRENCY_ENUMPROC lpNegCurrencyEnumProc,
  1966. LCID LCId,
  1967. DWORD dwFlags)
  1968. {
  1969. TCHAR szDecimal[SIZE_128];
  1970. TCHAR szNeg[SIZE_128];
  1971. TCHAR szSymbol[SIZE_128];
  1972. int ctr;
  1973. //
  1974. // If there is no enum proc, return false to indicate a failure.
  1975. //
  1976. if (!lpNegCurrencyEnumProc)
  1977. {
  1978. return (FALSE);
  1979. }
  1980. //
  1981. // Get the Decimal Separator for the current user locale so that
  1982. // it may be displayed correctly.
  1983. //
  1984. if (!GetLocaleInfo(UserLocaleID, LOCALE_SMONDECIMALSEP, szDecimal, SIZE_128) ||
  1985. ((szDecimal[0] == CHAR_DECIMAL) && (szDecimal[1] == CHAR_NULL)))
  1986. {
  1987. szDecimal[0] = CHAR_NULL;
  1988. }
  1989. //
  1990. // Get the Negative Sign for the current user locale so that
  1991. // it may be displayed correctly.
  1992. //
  1993. if (!GetLocaleInfo(UserLocaleID, LOCALE_SNEGATIVESIGN, szNeg, SIZE_128) ||
  1994. ((szNeg[0] == CHAR_HYPHEN) && (szNeg[1] == CHAR_NULL)))
  1995. {
  1996. szNeg[0] = CHAR_NULL;
  1997. }
  1998. //
  1999. // Get the Currency Symbol for the current user locale so that
  2000. // it may be displayed correctly.
  2001. //
  2002. if (!GetLocaleInfo(UserLocaleID, LOCALE_SCURRENCY, szSymbol, SIZE_128) ||
  2003. ((szSymbol[0] == CHAR_INTL_CURRENCY) && (szSymbol[1] == CHAR_NULL)))
  2004. {
  2005. szSymbol[0] = CHAR_NULL;
  2006. }
  2007. //
  2008. // Call enum proc with each format string. Check to make sure the
  2009. // enum proc requests continuation.
  2010. //
  2011. for (ctr = 0; ctr < NUM_NEG_CURRENCY_FORMATS; ctr++)
  2012. {
  2013. if (!lpNegCurrencyEnumProc( pNegCurrencyFormats[ctr],
  2014. szDecimal,
  2015. szNeg,
  2016. szSymbol ))
  2017. {
  2018. return (TRUE);
  2019. }
  2020. }
  2021. return (TRUE);
  2022. }
  2023. ////////////////////////////////////////////////////////////////////////////
  2024. //
  2025. // CheckEmptyString
  2026. //
  2027. // If lpStr is empty, then it fills it with a null ("") string.
  2028. // If lpStr is filled only by space, fills with a blank (" ") string.
  2029. //
  2030. ////////////////////////////////////////////////////////////////////////////
  2031. void CheckEmptyString(
  2032. LPTSTR lpStr)
  2033. {
  2034. LPTSTR lpString;
  2035. WORD wStrCType[64];
  2036. if (!(*lpStr))
  2037. {
  2038. //
  2039. // Put "" string in buffer.
  2040. //
  2041. //lstrcpy(lpStr, TEXT("\"\""));
  2042. if(FAILED(StringCchCopy(lpStr, SIZE_128 + 1, TEXT("\"\""))))
  2043. {
  2044. // This should be impossible, but we need to avoid PREfast complaints.
  2045. }
  2046. }
  2047. else
  2048. {
  2049. for (lpString = lpStr; *lpString; lpString = CharNext(lpString))
  2050. {
  2051. GetStringTypeEx( LOCALE_USER_DEFAULT,
  2052. CT_CTYPE1,
  2053. lpString,
  2054. 1,
  2055. wStrCType);
  2056. if (wStrCType[0] != CHAR_SPACE)
  2057. {
  2058. return;
  2059. }
  2060. }
  2061. //
  2062. // Put " " string in buffer.
  2063. //
  2064. //lstrcpy(lpStr, TEXT("\" \""));
  2065. if(FAILED(StringCchCopy(lpStr, SIZE_128 + 1, TEXT("\" \""))))
  2066. {
  2067. // This should be impossible, but we need to avoid PREfast complaints.
  2068. }
  2069. }
  2070. }
  2071. ////////////////////////////////////////////////////////////////////////////
  2072. //
  2073. // SetDlgItemRTL
  2074. //
  2075. ////////////////////////////////////////////////////////////////////////////
  2076. void SetDlgItemRTL(
  2077. HWND hDlg,
  2078. UINT uItem)
  2079. {
  2080. HWND hItem = GetDlgItem(hDlg, uItem);
  2081. DWORD dwExStyle = GetWindowLong(hItem, GWL_EXSTYLE);
  2082. SetWindowLong(hItem, GWL_EXSTYLE, dwExStyle | WS_EX_RTLREADING);
  2083. }
  2084. ////////////////////////////////////////////////////////////////////////////
  2085. //
  2086. // ShowMsg
  2087. //
  2088. ////////////////////////////////////////////////////////////////////////////
  2089. int ShowMsg(
  2090. HWND hDlg,
  2091. UINT iMsg,
  2092. UINT iTitle,
  2093. UINT iType,
  2094. LPTSTR pString)
  2095. {
  2096. TCHAR szTitle[MAX_PATH];
  2097. TCHAR szMsg[MAX_PATH*2];
  2098. TCHAR szErrMsg[MAX_PATH*2];
  2099. LPTSTR pTitle = NULL;
  2100. if (iTitle)
  2101. {
  2102. if (LoadString(hInstance, iTitle, szTitle, ARRAYSIZE(szTitle)))
  2103. {
  2104. pTitle = szTitle;
  2105. }
  2106. }
  2107. if (pString)
  2108. {
  2109. if (LoadString(hInstance, iMsg, szMsg, ARRAYSIZE(szMsg)))
  2110. {
  2111. //wsprintf(szErrMsg, szMsg, pString);
  2112. if(FAILED(StringCchPrintf(szErrMsg, ARRAYSIZE(szErrMsg), szMsg, pString)))
  2113. {
  2114. // This should be impossible, but we need to avoid PREfast complaints.
  2115. return(FALSE);
  2116. }
  2117. return (MessageBox(hDlg, szErrMsg, pTitle, iType));
  2118. }
  2119. }
  2120. else
  2121. {
  2122. if (LoadString(hInstance, iMsg, szErrMsg, ARRAYSIZE(szErrMsg)))
  2123. {
  2124. return (MessageBox(hDlg, szErrMsg, pTitle, iType));
  2125. }
  2126. }
  2127. return (FALSE);
  2128. }
  2129. ////////////////////////////////////////////////////////////////////////////
  2130. //
  2131. // Intl_EnumLocales
  2132. //
  2133. ////////////////////////////////////////////////////////////////////////////
  2134. void Intl_EnumLocales(
  2135. HWND hDlg,
  2136. HWND hLocale,
  2137. BOOL EnumSystemLocales)
  2138. {
  2139. LPLANGUAGEGROUP pLG;
  2140. DWORD Locale, dwIndex;
  2141. BOOL fSpanish = FALSE;
  2142. UINT ctr;
  2143. TCHAR szBuf[SIZE_300];
  2144. DWORD dwLocaleACP;
  2145. INT iRet = TRUE;
  2146. //
  2147. // Go through the language groups to see which ones are installed.
  2148. // Display only the locales for the groups that are either already
  2149. // installed or the groups the user wants to be installed.
  2150. //
  2151. pLG = pLanguageGroups;
  2152. while (pLG)
  2153. {
  2154. //
  2155. // If the language group is originally installed and not marked for
  2156. // removal OR is marked to be installed, then add the locales for
  2157. // this language group to the System and User combo boxes.
  2158. //
  2159. if (pLG->wStatus & ML_INSTALL)
  2160. {
  2161. for (ctr = 0; ctr < pLG->NumLocales; ctr++)
  2162. {
  2163. //
  2164. // Save the locale id.
  2165. //
  2166. Locale = (pLG->pLocaleList)[ctr];
  2167. //
  2168. // See if we need to special case Spanish.
  2169. //
  2170. if ((LANGIDFROMLCID(Locale) == LANG_SPANISH_TRADITIONAL) ||
  2171. (LANGIDFROMLCID(Locale) == LANG_SPANISH_INTL))
  2172. {
  2173. //
  2174. // If we've already displayed Spanish (Spain), then
  2175. // don't display it again.
  2176. //
  2177. if (!fSpanish)
  2178. {
  2179. //
  2180. // Add the Spanish locale to the list box.
  2181. //
  2182. if (LoadString(hInstance, IDS_SPANISH_NAME, szBuf, SIZE_300))
  2183. {
  2184. dwIndex = ComboBox_AddString(hLocale, szBuf);
  2185. ComboBox_SetItemData( hLocale,
  2186. dwIndex,
  2187. LCID_SPANISH_INTL );
  2188. fSpanish = TRUE;
  2189. }
  2190. }
  2191. }
  2192. else
  2193. {
  2194. //
  2195. // Don't enum system locales that don't have an ACP.
  2196. //
  2197. if (EnumSystemLocales)
  2198. {
  2199. iRet = GetLocaleInfo( Locale,
  2200. LOCALE_IDEFAULTANSICODEPAGE |
  2201. LOCALE_NOUSEROVERRIDE |
  2202. LOCALE_RETURN_NUMBER,
  2203. (PTSTR) &dwLocaleACP,
  2204. sizeof(dwLocaleACP) / sizeof(TCHAR) );
  2205. if (iRet)
  2206. {
  2207. iRet = dwLocaleACP;
  2208. }
  2209. }
  2210. if (iRet)
  2211. {
  2212. //
  2213. // Get the name of the locale.
  2214. //
  2215. GetLocaleInfo(Locale, LOCALE_SLANGUAGE, szBuf, SIZE_300);
  2216. //
  2217. // Add the new locale to the list box.
  2218. //
  2219. dwIndex = ComboBox_AddString(hLocale, szBuf);
  2220. ComboBox_SetItemData(hLocale, dwIndex, Locale);
  2221. }
  2222. }
  2223. }
  2224. }
  2225. pLG = pLG->pNext;
  2226. }
  2227. }
  2228. ////////////////////////////////////////////////////////////////////////////
  2229. //
  2230. // Intl_EnumInstalledCPProc
  2231. //
  2232. ////////////////////////////////////////////////////////////////////////////
  2233. BOOL CALLBACK Intl_EnumInstalledCPProc(
  2234. LPTSTR pString)
  2235. {
  2236. UINT CodePage;
  2237. LPCODEPAGE pCP;
  2238. //
  2239. // Convert the code page string to an integer.
  2240. //
  2241. CodePage = Intl_StrToLong(pString);
  2242. //
  2243. // Find the code page in the linked list and mark it as
  2244. // originally installed.
  2245. //
  2246. pCP = pCodePages;
  2247. while (pCP)
  2248. {
  2249. if (pCP->CodePage == CodePage)
  2250. {
  2251. pCP->wStatus |= ML_ORIG_INSTALLED;
  2252. break;
  2253. }
  2254. pCP = pCP->pNext;
  2255. }
  2256. //
  2257. // Return success.
  2258. //
  2259. return (TRUE);
  2260. }
  2261. ////////////////////////////////////////////////////////////////////////////
  2262. //
  2263. // Intl_InstallKeyboardLayout
  2264. //
  2265. // Install the Keyboard Layout requested. If the Layout parameter is 0,
  2266. // the function will proceed with the installation of the default layout
  2267. // for the Locale specified. No need to validate the Layout because it's
  2268. // done by the Text Services call.
  2269. //
  2270. ////////////////////////////////////////////////////////////////////////////
  2271. BOOL Intl_InstallKeyboardLayout(
  2272. HWND hDlg,
  2273. LCID Locale,
  2274. DWORD Layout,
  2275. BOOL bDefaultLayout,
  2276. BOOL bDefaultUser,
  2277. BOOL bSystemLocale)
  2278. {
  2279. TCHAR szData[MAX_PATH];
  2280. DWORD dwLayout = Layout;
  2281. DWORD dwLocale = (DWORD)Locale;
  2282. TCHAR szLayout[50];
  2283. HKL hklValue = (HKL)NULL;
  2284. BOOL bOverrideDefaultLayout = FALSE;
  2285. //
  2286. // Check if input.dll is loaded.
  2287. //
  2288. if (hInputDLL && pfnInstallInputLayout)
  2289. {
  2290. //
  2291. // See if we need to look for the default layout.
  2292. //
  2293. if (!Layout)
  2294. {
  2295. //
  2296. // Look in the INF file for the default layout.
  2297. //
  2298. if (!Intl_GetDefaultLayoutFromInf(&dwLocale, &dwLayout))
  2299. {
  2300. //
  2301. // Try just the language id.
  2302. //
  2303. if (HIWORD(Locale) != 0)
  2304. {
  2305. dwLocale = LANGIDFROMLCID(Locale);
  2306. if (!Intl_GetDefaultLayoutFromInf(&dwLocale, &dwLayout))
  2307. {
  2308. if (g_bLog)
  2309. {
  2310. //wsprintf(szLayout, TEXT("%08x:%08x"), dwLocale, dwLayout);
  2311. if(SUCCEEDED(StringCchPrintf(szLayout, ARRAYSIZE(szLayout), TEXT("%08x:%08x"), dwLocale, dwLayout)))
  2312. {
  2313. Intl_LogSimpleMessage(IDS_LOG_LOCALE_KBD_FAIL, szLayout);
  2314. }
  2315. }
  2316. return (FALSE);
  2317. }
  2318. }
  2319. else
  2320. {
  2321. if (g_bLog)
  2322. {
  2323. //wsprintf(szLayout,TEXT("%08x:%08x"), dwLocale, dwLayout);
  2324. if(SUCCEEDED(StringCchPrintf(szLayout, ARRAYSIZE(szLayout), TEXT("%08x:%08x"), dwLocale, dwLayout)))
  2325. {
  2326. Intl_LogSimpleMessage(IDS_LOG_LOCALE_KBD_FAIL, szLayout);
  2327. }
  2328. }
  2329. return (FALSE);
  2330. }
  2331. }
  2332. }
  2333. //
  2334. // See if we need to provide the HKL. This case only occurs when
  2335. // we need to set the Layout as the default. Otherwise, the value
  2336. // can be NULL.
  2337. //
  2338. if (bDefaultLayout)
  2339. {
  2340. hklValue = Intl_GetHKL(dwLocale, dwLayout);
  2341. }
  2342. //
  2343. // Check if need to override the default layout.
  2344. //
  2345. if (g_bSetupCase && ((HIWORD(dwLayout) & 0xf000) == 0xe000))
  2346. {
  2347. bOverrideDefaultLayout = TRUE;
  2348. }
  2349. //
  2350. // Install the input Layout.
  2351. //
  2352. if (!(*pfnInstallInputLayout)( dwLocale,
  2353. dwLayout,
  2354. bOverrideDefaultLayout ? FALSE : bDefaultLayout,
  2355. hklValue,
  2356. bDefaultUser,
  2357. g_bSetupCase ? TRUE : bSystemLocale ))
  2358. {
  2359. if (hDlg != NULL)
  2360. {
  2361. GetLocaleInfo(Locale, LOCALE_SLANGUAGE, szData, ARRAYSIZE(szData));
  2362. ShowMsg( hDlg,
  2363. IDS_KBD_LOAD_KBD_FAILED,
  2364. 0,
  2365. MB_OK_OOPS,
  2366. szData );
  2367. }
  2368. else
  2369. {
  2370. if (g_bLog)
  2371. {
  2372. //wsprintf(szLayout, TEXT("%08x:%08x"), dwLocale, dwLayout);
  2373. if(FAILED(StringCchPrintf(szLayout, ARRAYSIZE(szLayout), TEXT("%08x:%08x"), dwLocale, dwLayout)))
  2374. {
  2375. // This should be impossible, but we need to avoid PREfast complaints.
  2376. }
  2377. Intl_LogSimpleMessage(IDS_LOG_LOCALE_KBD_FAIL, szLayout);
  2378. }
  2379. }
  2380. return (FALSE);
  2381. }
  2382. //
  2383. // If the language has a default layout that has a different locale
  2384. // than the language (e.g. Thai), we want the default locale to be
  2385. // English (so that logon can occur with a US keyboard), but the
  2386. // first Thai keyboard layout should be installed when the Thai
  2387. // locale is chosen. This is why we have two locales and layouts
  2388. // passed back to the caller.
  2389. //
  2390. if (PRIMARYLANGID(LANGIDFROMLCID(dwLocale)) !=
  2391. PRIMARYLANGID(LANGIDFROMLCID(Locale)))
  2392. {
  2393. dwLocale = Locale;
  2394. dwLayout = 0;
  2395. if (!Intl_GetSecondValidLayoutFromInf(&dwLocale, &dwLayout))
  2396. {
  2397. //
  2398. // Try just the language id.
  2399. //
  2400. if (HIWORD(Locale) != 0)
  2401. {
  2402. dwLocale = LANGIDFROMLCID(Locale);
  2403. if (!Intl_GetSecondValidLayoutFromInf(&dwLocale, &dwLayout))
  2404. {
  2405. if (g_bLog)
  2406. {
  2407. //wsprintf(szLayout, TEXT("%08x:%08x"), dwLocale, dwLayout);
  2408. if(FAILED(StringCchPrintf(szLayout, ARRAYSIZE(szLayout), TEXT("%08x:%08x"), dwLocale, dwLayout)))
  2409. {
  2410. // This should be impossible, but we need to avoid PREfast complaints.
  2411. }
  2412. Intl_LogSimpleMessage(IDS_LOG_LOCALE_KBD_FAIL, szLayout);
  2413. }
  2414. return (FALSE);
  2415. }
  2416. }
  2417. else
  2418. {
  2419. if (g_bLog)
  2420. {
  2421. //wsprintf(szLayout,TEXT("%08x:%08x"), dwLocale, dwLayout);
  2422. if(FAILED(StringCchPrintf(szLayout, ARRAYSIZE(szLayout), TEXT("%08x:%08x"), dwLocale, dwLayout)))
  2423. {
  2424. // This should be impossible, but we need to avoid PREfast complaints.
  2425. }
  2426. Intl_LogSimpleMessage(IDS_LOG_LOCALE_KBD_FAIL, szLayout);
  2427. }
  2428. return (FALSE);
  2429. }
  2430. }
  2431. }
  2432. //
  2433. // See if we need to provide the HKL. This case only occurs when
  2434. // we need to set the Layout as the default. Otherwise, the value
  2435. // can be NULL.
  2436. //
  2437. if (bDefaultLayout)
  2438. {
  2439. hklValue = Intl_GetHKL(dwLocale, dwLayout);
  2440. }
  2441. //
  2442. // Install the input Layout.
  2443. //
  2444. if (!(*pfnInstallInputLayout)( dwLocale,
  2445. dwLayout,
  2446. FALSE,
  2447. hklValue,
  2448. bDefaultUser,
  2449. g_bSetupCase ? TRUE : bSystemLocale))
  2450. {
  2451. if (hDlg != NULL)
  2452. {
  2453. GetLocaleInfo(Locale, LOCALE_SLANGUAGE, szData, ARRAYSIZE(szData));
  2454. ShowMsg( hDlg,
  2455. IDS_KBD_LOAD_KBD_FAILED,
  2456. 0,
  2457. MB_OK_OOPS,
  2458. szData );
  2459. }
  2460. else
  2461. {
  2462. if (g_bLog)
  2463. {
  2464. //wsprintf(szLayout, TEXT("%08x:%08x"), dwLocale, dwLayout);
  2465. if(FAILED(StringCchPrintf(szLayout, ARRAYSIZE(szLayout), TEXT("%08x:%08x"), dwLocale, dwLayout)))
  2466. {
  2467. // This should be impossible, but we need to avoid PREfast complaints.
  2468. }
  2469. Intl_LogSimpleMessage(IDS_LOG_LOCALE_KBD_FAIL, szLayout);
  2470. }
  2471. }
  2472. return (FALSE);
  2473. }
  2474. }
  2475. else
  2476. {
  2477. if (g_bLog)
  2478. {
  2479. //wsprintf(szLayout, TEXT("%08x:%08x"), dwLocale, dwLayout);
  2480. if(FAILED(StringCchPrintf(szLayout, ARRAYSIZE(szLayout), TEXT("%08x:%08x"), dwLocale, dwLayout)))
  2481. {
  2482. // This should be impossible, but we need to avoid PREfast complaints.
  2483. }
  2484. Intl_LogSimpleMessage(IDS_LOG_LAYOUT_INSTALLED, szLayout);
  2485. }
  2486. }
  2487. //
  2488. // Return success.
  2489. //
  2490. return (TRUE);
  2491. }
  2492. ////////////////////////////////////////////////////////////////////////////
  2493. //
  2494. // Intl_InstallKeyboardLayoutList
  2495. //
  2496. // Install all keyboard requested. Pass through the layout list and ask the
  2497. // Text Services to process with the installation.
  2498. //
  2499. ////////////////////////////////////////////////////////////////////////////
  2500. BOOL Intl_InstallKeyboardLayoutList(
  2501. PINFCONTEXT pContext,
  2502. DWORD dwStartField,
  2503. BOOL bDefaultUserCase)
  2504. {
  2505. DWORD dwNumFields, dwNumList, dwCtr;
  2506. DWORD Locale;
  2507. DWORD Layout;
  2508. BOOL bDefaultLayout = FALSE;
  2509. TCHAR szBuffer[MAX_PATH];
  2510. LPTSTR pPos;
  2511. //
  2512. // Get the number of items in the list.
  2513. //
  2514. dwNumFields = SetupGetFieldCount(pContext);
  2515. if (dwNumFields < dwStartField)
  2516. {
  2517. return (FALSE);
  2518. }
  2519. dwNumList = dwNumFields - dwStartField + 1;
  2520. //
  2521. // Install all Keyboard layouts from the list.
  2522. //
  2523. for (dwCtr = dwStartField; dwCtr <= dwNumFields; dwCtr++)
  2524. {
  2525. if (SetupGetStringField( pContext,
  2526. dwCtr,
  2527. szBuffer,
  2528. ARRAYSIZE(szBuffer),
  2529. NULL ))
  2530. {
  2531. //
  2532. // Find the colon in order to save the input locale
  2533. // and layout values separately.
  2534. //
  2535. pPos = szBuffer;
  2536. while (*pPos)
  2537. {
  2538. if ((*pPos == CHAR_COLON) && (pPos != szBuffer))
  2539. {
  2540. *pPos = 0;
  2541. pPos++;
  2542. //
  2543. // Check if related to the invariant locale.
  2544. //
  2545. Locale = TransNum(szBuffer);
  2546. Layout = TransNum(pPos);
  2547. if (Locale != LOCALE_INVARIANT)
  2548. {
  2549. //
  2550. // Only the first one in list would be installed as
  2551. // the default in the Preload section.
  2552. //
  2553. if (dwCtr == dwStartField)
  2554. {
  2555. bDefaultLayout = TRUE;
  2556. }
  2557. else
  2558. {
  2559. bDefaultLayout = FALSE;
  2560. }
  2561. //
  2562. // Install the keyboard layout requested
  2563. //
  2564. if (Intl_InstallKeyboardLayout( NULL,
  2565. Locale,
  2566. Layout,
  2567. bDefaultLayout,
  2568. bDefaultUserCase,
  2569. FALSE ))
  2570. {
  2571. //
  2572. // Log Layout installation info.
  2573. //
  2574. if (g_bLog)
  2575. {
  2576. Intl_LogSimpleMessage(IDS_LOG_LAYOUT, szBuffer);
  2577. }
  2578. }
  2579. }
  2580. else
  2581. {
  2582. //
  2583. // Log invariant locale blocked.
  2584. //
  2585. if (g_bLog)
  2586. {
  2587. Intl_LogSimpleMessage(IDS_LOG_INV_BLOCK, NULL);
  2588. }
  2589. }
  2590. break;
  2591. }
  2592. pPos++;
  2593. }
  2594. }
  2595. }
  2596. //
  2597. // Return success.
  2598. //
  2599. return (TRUE);
  2600. }
  2601. ////////////////////////////////////////////////////////////////////////////
  2602. //
  2603. // Intl_InstallAllKeyboardLayout
  2604. //
  2605. // Install all keyboard layouts associated with a Language groups.
  2606. //
  2607. ////////////////////////////////////////////////////////////////////////////
  2608. BOOL Intl_InstallAllKeyboardLayout(
  2609. LANGID Language)
  2610. {
  2611. BOOL bRet = TRUE;
  2612. HINF hIntlInf;
  2613. LCID Locale = MAKELCID(Language, SORT_DEFAULT);
  2614. TCHAR szLCID[25];
  2615. INFCONTEXT Context;
  2616. //
  2617. // Open the INF file
  2618. //
  2619. if (Intl_OpenIntlInfFile(&hIntlInf))
  2620. {
  2621. //
  2622. // Get the locale.
  2623. //
  2624. //wsprintf(szLCID, TEXT("%08x"), Locale);
  2625. if(FAILED(StringCchPrintf(szLCID, ARRAYSIZE(szLCID), TEXT("%08x"), Locale)))
  2626. {
  2627. // This should be impossible, but we need to avoid PREfast complaints.
  2628. return(FALSE);
  2629. }
  2630. //
  2631. // Look for the keyboard section.
  2632. //
  2633. if (SetupFindFirstLine( hIntlInf,
  2634. TEXT("Locales"),
  2635. szLCID,
  2636. &Context ))
  2637. {
  2638. bRet = Intl_InstallKeyboardLayoutList(&Context, 5, FALSE);
  2639. }
  2640. Intl_CloseInfFile(&hIntlInf);
  2641. }
  2642. return (bRet);
  2643. }
  2644. ////////////////////////////////////////////////////////////////////////////
  2645. //
  2646. // Intl_UninstallAllKeyboardLayout
  2647. //
  2648. // Remove all keyboard layouts associated with a Language groups.
  2649. //
  2650. ////////////////////////////////////////////////////////////////////////////
  2651. BOOL Intl_UninstallAllKeyboardLayout(
  2652. UINT uiLangGroup,
  2653. BOOL DefaultUserCase)
  2654. {
  2655. LPLANGUAGEGROUP pLG = pLanguageGroups;
  2656. LANGID lidCurrent, lidPrev = 0;
  2657. LCID *pLocale;
  2658. BOOL bRet = TRUE;
  2659. //
  2660. // Bail out if we can't get this API from input.dll.
  2661. //
  2662. if (pfnUninstallInputLayout)
  2663. {
  2664. //
  2665. // Walk through all language groups.
  2666. //
  2667. while (pLG)
  2668. {
  2669. if (pLG->LanguageGroup == uiLangGroup)
  2670. {
  2671. TCHAR szLang[MAX_PATH];
  2672. pLocale = pLG->pLocaleList;
  2673. //
  2674. // Walk through the locale list, remove relevant keyboard
  2675. // layouts by the locale's primary language.
  2676. //
  2677. while (*pLocale)
  2678. {
  2679. lidCurrent = PRIMARYLANGID(*pLocale);
  2680. //
  2681. // Don't uninstall any US keyboard layouts.
  2682. //
  2683. if (lidCurrent == 0x09)
  2684. {
  2685. pLocale++;
  2686. continue;
  2687. }
  2688. //
  2689. // The locale list is sorted, so we can avoid redundant
  2690. // UninstallInputLayout calls.
  2691. //
  2692. if (lidCurrent != lidPrev)
  2693. {
  2694. //
  2695. // Uninstall the input layouts associated with
  2696. // this current locale in the list.
  2697. //
  2698. BOOL bSuccess =
  2699. (*pfnUninstallInputLayout)( (LCID) lidCurrent,
  2700. 0L,
  2701. DefaultUserCase );
  2702. if (g_bLog)
  2703. {
  2704. //wsprintf(szLang, TEXT("%04x"), lidCurrent);
  2705. if(FAILED(StringCchPrintf(szLang, ARRAYSIZE(szLang), TEXT("%04x"), lidCurrent)))
  2706. {
  2707. // This should be impossible, but we need to avoid PREfast complaints.
  2708. }
  2709. Intl_LogSimpleMessage( bSuccess
  2710. ? IDS_LOG_LOCALE_LG_REM
  2711. : IDS_LOG_LOCALE_LG_FAIL,
  2712. szLang );
  2713. }
  2714. if (!bSuccess && bRet)
  2715. {
  2716. bRet = bSuccess;
  2717. }
  2718. lidPrev = lidCurrent;
  2719. }
  2720. pLocale++;
  2721. }
  2722. break;
  2723. }
  2724. pLG = pLG->pNext;
  2725. }
  2726. }
  2727. return bRet;
  2728. }
  2729. ////////////////////////////////////////////////////////////////////////////
  2730. //
  2731. // Intl_GetHKL
  2732. //
  2733. ////////////////////////////////////////////////////////////////////////////
  2734. HKL Intl_GetHKL(
  2735. DWORD dwLocale,
  2736. DWORD dwLayout)
  2737. {
  2738. TCHAR szData[MAX_PATH];
  2739. INFCONTEXT Context;
  2740. HINF hIntlInf;
  2741. TCHAR szLayout[25];
  2742. //
  2743. // Get the HKL based on the input locale value and the layout value.
  2744. //
  2745. if (dwLayout == 0)
  2746. {
  2747. //
  2748. // See if it's the default layout for the input locale or an IME.
  2749. //
  2750. if (HIWORD(dwLocale) == 0)
  2751. {
  2752. return ((HKL)MAKELPARAM(dwLocale, dwLocale));
  2753. }
  2754. else if ((HIWORD(dwLocale) & 0xf000) == 0xe000)
  2755. {
  2756. return ((HKL)IntToPtr(dwLocale));
  2757. }
  2758. }
  2759. else
  2760. {
  2761. //
  2762. // Open the INF file.
  2763. //
  2764. if (Intl_OpenIntlInfFile(&hIntlInf))
  2765. {
  2766. //
  2767. // Create the Layout string.
  2768. //
  2769. //wsprintf(szLayout, TEXT("%08x"), dwLayout);
  2770. if(FAILED(StringCchPrintf(szLayout, ARRAYSIZE(szLayout), TEXT("%08x"), dwLayout)))
  2771. {
  2772. // This should be impossible, but we need to avoid PREfast complaints.
  2773. Intl_CloseInfFile(&hIntlInf);
  2774. return(0);
  2775. }
  2776. //
  2777. // Use the layout to make the hkl.
  2778. //
  2779. if (HIWORD(dwLayout) != 0)
  2780. {
  2781. //
  2782. // We have a special id. Need to find out what the layout id
  2783. // should be.
  2784. //
  2785. if ((SetupFindFirstLine(hIntlInf, szKbdLayoutIds, szLayout, &Context)) &&
  2786. (SetupGetStringField(&Context, 1, szData, ARRAYSIZE(szData), NULL)))
  2787. {
  2788. dwLayout = (DWORD)(LOWORD(TransNum(szData)) | 0xf000);
  2789. }
  2790. }
  2791. //
  2792. // Close the handle
  2793. //
  2794. Intl_CloseInfFile(&hIntlInf);
  2795. //
  2796. // Return the hkl:
  2797. // loword = input locale id
  2798. // hiword = layout id
  2799. //
  2800. return ((HKL)MAKELPARAM(dwLocale, dwLayout));
  2801. }
  2802. }
  2803. //
  2804. // Return failure.
  2805. //
  2806. return (0);
  2807. }
  2808. ////////////////////////////////////////////////////////////////////////////
  2809. //
  2810. // Intl_GetDefaultLayoutFromInf
  2811. //
  2812. ////////////////////////////////////////////////////////////////////////////
  2813. BOOL Intl_GetDefaultLayoutFromInf(
  2814. LPDWORD pdwLocale,
  2815. LPDWORD pdwLayout)
  2816. {
  2817. BOOL bRet = TRUE;
  2818. HINF hIntlInf;
  2819. if (Intl_OpenIntlInfFile(&hIntlInf))
  2820. {
  2821. bRet = Intl_ReadDefaultLayoutFromInf(pdwLocale, pdwLayout, hIntlInf);
  2822. Intl_CloseInfFile(&hIntlInf);
  2823. }
  2824. return (bRet);
  2825. }
  2826. ////////////////////////////////////////////////////////////////////////////
  2827. //
  2828. // Intl_GetSecondValidLayoutFromInf
  2829. //
  2830. ////////////////////////////////////////////////////////////////////////////
  2831. BOOL Intl_GetSecondValidLayoutFromInf(
  2832. LPDWORD pdwLocale,
  2833. LPDWORD pdwLayout)
  2834. {
  2835. BOOL bRet = TRUE;
  2836. HINF hIntlInf;
  2837. if (Intl_OpenIntlInfFile(&hIntlInf))
  2838. {
  2839. bRet = Intl_ReadSecondValidLayoutFromInf(pdwLocale, pdwLayout, hIntlInf);
  2840. Intl_CloseInfFile(&hIntlInf);
  2841. }
  2842. return (bRet);
  2843. }
  2844. ////////////////////////////////////////////////////////////////////////////
  2845. //
  2846. // Intl_InitInf
  2847. //
  2848. ////////////////////////////////////////////////////////////////////////////
  2849. BOOL Intl_InitInf(
  2850. HWND hDlg,
  2851. HINF *phIntlInf,
  2852. LPTSTR pszInf,
  2853. HSPFILEQ *pFileQueue,
  2854. PVOID *pQueueContext)
  2855. {
  2856. BOOL bSpecialCase = TRUE;
  2857. //
  2858. // Open the Inf file.
  2859. //
  2860. *phIntlInf = SetupOpenInfFile(pszInf, NULL, INF_STYLE_WIN4, NULL);
  2861. if (*phIntlInf == INVALID_HANDLE_VALUE)
  2862. {
  2863. if (g_bLog)
  2864. {
  2865. Intl_LogFormatMessage(IDS_LOG_INTL_ERROR);
  2866. }
  2867. return (FALSE);
  2868. }
  2869. if (!SetupOpenAppendInfFile(NULL, *phIntlInf, NULL))
  2870. {
  2871. if (g_bLog)
  2872. {
  2873. Intl_LogFormatMessage(IDS_LOG_SETUP_ERROR);
  2874. }
  2875. SetupCloseInfFile(*phIntlInf);
  2876. return (FALSE);
  2877. }
  2878. //
  2879. // Create a setup file queue and initialize default setup
  2880. // copy queue callback context.
  2881. //
  2882. *pFileQueue = SetupOpenFileQueue();
  2883. if ((!*pFileQueue) || (*pFileQueue == INVALID_HANDLE_VALUE))
  2884. {
  2885. if (g_bLog)
  2886. {
  2887. Intl_LogFormatMessage(IDS_LOG_SETUP_ERROR);
  2888. }
  2889. SetupCloseInfFile(*phIntlInf);
  2890. return (FALSE);
  2891. }
  2892. //
  2893. // Determine if we are dealing with a special case.
  2894. //
  2895. if ((g_bUnttendMode || g_bSetupCase) && !g_bProgressBarDisplay)
  2896. {
  2897. bSpecialCase = FALSE;
  2898. }
  2899. //
  2900. // Don't display FileCopy progress operation during GUI mode setup or Unattend mode.
  2901. //
  2902. *pQueueContext = SetupInitDefaultQueueCallbackEx( GetParent(hDlg),
  2903. (bSpecialCase ? NULL : INVALID_HANDLE_VALUE),
  2904. 0L,
  2905. 0L,
  2906. NULL );
  2907. if (!*pQueueContext)
  2908. {
  2909. if (g_bLog)
  2910. {
  2911. Intl_LogFormatMessage(IDS_LOG_SETUP_ERROR);
  2912. }
  2913. SetupCloseFileQueue(*pFileQueue);
  2914. SetupCloseInfFile(*phIntlInf);
  2915. return (FALSE);
  2916. }
  2917. //
  2918. // Return success.
  2919. //
  2920. return (TRUE);
  2921. }
  2922. ////////////////////////////////////////////////////////////////////////////
  2923. //
  2924. // Intl_OpenIntlInfFile
  2925. //
  2926. ////////////////////////////////////////////////////////////////////////////
  2927. BOOL Intl_OpenIntlInfFile(
  2928. HINF *phInf)
  2929. {
  2930. HINF hIntlInf;
  2931. //
  2932. // Open the intl.inf file.
  2933. //
  2934. hIntlInf = SetupOpenInfFile(szIntlInf, NULL, INF_STYLE_WIN4, NULL);
  2935. if (hIntlInf == INVALID_HANDLE_VALUE)
  2936. {
  2937. return (FALSE);
  2938. }
  2939. if (!SetupOpenAppendInfFile(NULL, hIntlInf, NULL))
  2940. {
  2941. SetupCloseInfFile(hIntlInf);
  2942. return (FALSE);
  2943. }
  2944. *phInf = hIntlInf;
  2945. return (TRUE);
  2946. }
  2947. ////////////////////////////////////////////////////////////////////////////
  2948. //
  2949. // Intl_CloseInf
  2950. //
  2951. ////////////////////////////////////////////////////////////////////////////
  2952. void Intl_CloseInf(
  2953. HINF hIntlInf,
  2954. HSPFILEQ FileQueue,
  2955. PVOID QueueContext)
  2956. {
  2957. //
  2958. // Terminate the Queue.
  2959. //
  2960. SetupTermDefaultQueueCallback(QueueContext);
  2961. //
  2962. // Close the file queue.
  2963. //
  2964. SetupCloseFileQueue(FileQueue);
  2965. //
  2966. // Close the Inf file.
  2967. //
  2968. SetupCloseInfFile(hIntlInf);
  2969. }
  2970. ////////////////////////////////////////////////////////////////////////////
  2971. //
  2972. // Intl_ReadDefaultLayoutFromInf
  2973. //
  2974. ////////////////////////////////////////////////////////////////////////////
  2975. BOOL Intl_ReadDefaultLayoutFromInf(
  2976. LPDWORD pdwLocale,
  2977. LPDWORD pdwLayout,
  2978. HINF hIntlInf)
  2979. {
  2980. INFCONTEXT Context;
  2981. TCHAR szPair[MAX_PATH * 2];
  2982. LPTSTR pPos;
  2983. TCHAR szLCID[25];
  2984. //
  2985. // Get the locale.
  2986. //
  2987. //wsprintf(szLCID, TEXT("%08x"), *pdwLocale);
  2988. if(FAILED(StringCchPrintf(szLCID, ARRAYSIZE(szLCID), TEXT("%08x"), *pdwLocale)))
  2989. {
  2990. // This should be impossible, but we need to avoid PREfast complaints.
  2991. return(FALSE);
  2992. }
  2993. //
  2994. // Get the first (default) LANGID:HKL pair for the given locale.
  2995. // Example String: "0409:00000409"
  2996. //
  2997. szPair[0] = 0;
  2998. if (SetupFindFirstLine( hIntlInf,
  2999. TEXT("Locales"),
  3000. szLCID,
  3001. &Context ))
  3002. {
  3003. SetupGetStringField(&Context, 5, szPair, MAX_PATH, NULL);
  3004. }
  3005. //
  3006. // Make sure we have a string.
  3007. //
  3008. if (szPair[0] == 0)
  3009. {
  3010. return (FALSE);
  3011. }
  3012. //
  3013. // Find the colon in the string and then set the position
  3014. // pointer to the next character.
  3015. //
  3016. pPos = szPair;
  3017. while (*pPos)
  3018. {
  3019. if ((*pPos == CHAR_COLON) && (pPos != szPair))
  3020. {
  3021. *pPos = 0;
  3022. pPos++;
  3023. break;
  3024. }
  3025. pPos++;
  3026. }
  3027. //
  3028. // If there is a layout, then return the input locale and the layout.
  3029. //
  3030. if ((*pPos) &&
  3031. (*pdwLocale = TransNum(szPair)) &&
  3032. (*pdwLayout = TransNum(pPos)))
  3033. {
  3034. return (TRUE);
  3035. }
  3036. //
  3037. // Return failure.
  3038. //
  3039. return (FALSE);
  3040. }
  3041. ////////////////////////////////////////////////////////////////////////////
  3042. //
  3043. // Intl_ReadSecondValidLayoutFromInf
  3044. //
  3045. ////////////////////////////////////////////////////////////////////////////
  3046. BOOL Intl_ReadSecondValidLayoutFromInf(
  3047. LPDWORD pdwLocale,
  3048. LPDWORD pdwLayout,
  3049. HINF hIntlInf)
  3050. {
  3051. INFCONTEXT Context;
  3052. int iField = 6;
  3053. TCHAR szPair[MAX_PATH * 2];
  3054. LPTSTR pPos;
  3055. DWORD dwLoc, dwlay, savedLocale = *pdwLocale;
  3056. TCHAR szLCID[25];
  3057. //
  3058. // Get the locale.
  3059. //
  3060. //wsprintf(szLCID, TEXT("%08x"), *pdwLocale);
  3061. if(FAILED(StringCchPrintf(szLCID, ARRAYSIZE(szLCID), TEXT("%08x"), *pdwLocale)))
  3062. {
  3063. // This should be impossible, but we need to avoid PREfast complaints.
  3064. return(FALSE);
  3065. }
  3066. //
  3067. // Get the first (default) LANGID:HKL pair for the given locale.
  3068. // Example String: "0409:00000409"
  3069. //
  3070. szPair[0] = 0;
  3071. if (SetupFindFirstLine(hIntlInf, TEXT("Locales"), szLCID, &Context))
  3072. {
  3073. while (SetupGetStringField(&Context, iField, szPair, MAX_PATH, NULL))
  3074. {
  3075. //
  3076. // Make sure we have a string.
  3077. //
  3078. if (szPair[0] == 0)
  3079. {
  3080. iField++;
  3081. continue;
  3082. }
  3083. //
  3084. // Find the colon in the string and then set the position
  3085. // pointer to the next character.
  3086. //
  3087. pPos = szPair;
  3088. while (*pPos)
  3089. {
  3090. if ((*pPos == CHAR_COLON) && (pPos != szPair))
  3091. {
  3092. *pPos = 0;
  3093. pPos++;
  3094. break;
  3095. }
  3096. pPos++;
  3097. }
  3098. if (*pPos == 0)
  3099. {
  3100. iField++;
  3101. continue;
  3102. }
  3103. //
  3104. // If there is a layout, then return the input locale and the
  3105. // layout.
  3106. //
  3107. if (((dwLoc = TransNum(szPair)) == 0) ||
  3108. ((dwlay = TransNum(pPos)) == 0))
  3109. {
  3110. iField++;
  3111. continue;
  3112. }
  3113. if (PRIMARYLANGID(LANGIDFROMLCID(dwLoc)) ==
  3114. PRIMARYLANGID(LANGIDFROMLCID(savedLocale)))
  3115. {
  3116. *pdwLayout = dwlay;
  3117. *pdwLocale = dwLoc;
  3118. return (TRUE);
  3119. }
  3120. iField++;
  3121. }
  3122. }
  3123. //
  3124. // Return failure.
  3125. //
  3126. return (FALSE);
  3127. }
  3128. ////////////////////////////////////////////////////////////////////////////
  3129. //
  3130. // Intl_CloseInfFile
  3131. //
  3132. ////////////////////////////////////////////////////////////////////////////
  3133. BOOL Intl_CloseInfFile(
  3134. HINF *phInf)
  3135. {
  3136. SetupCloseInfFile(*phInf);
  3137. *phInf = INVALID_HANDLE_VALUE;
  3138. return (TRUE);
  3139. }
  3140. ////////////////////////////////////////////////////////////////////////////
  3141. //
  3142. // Intl_IsValidLayout
  3143. //
  3144. ////////////////////////////////////////////////////////////////////////////
  3145. BOOL Intl_IsValidLayout(
  3146. DWORD dwLayout)
  3147. {
  3148. HKEY hKey1, hKey2;
  3149. TCHAR szLayout[MAX_PATH];
  3150. //
  3151. // Get the layout id as a string.
  3152. //
  3153. //wsprintf(szLayout, TEXT("%08x"), dwLayout);
  3154. if(FAILED(StringCchPrintf(szLayout, ARRAYSIZE(szLayout), TEXT("%08x"), dwLayout)))
  3155. {
  3156. // This should be impossible, but we need to avoid PREfast complaints.
  3157. return(FALSE);
  3158. }
  3159. //
  3160. // Open the Keyboard Layouts key.
  3161. //
  3162. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szLayoutPath, 0L, KEY_READ, &hKey1) != ERROR_SUCCESS)
  3163. {
  3164. return (FALSE);
  3165. }
  3166. //
  3167. // Try to open the layout id key under the Keyboard Layouts key.
  3168. //
  3169. if (RegOpenKeyEx(hKey1, szLayout, 0L, KEY_READ, &hKey2) != ERROR_SUCCESS)
  3170. {
  3171. RegCloseKey(hKey1);
  3172. return (FALSE);
  3173. }
  3174. //
  3175. // Close the keys.
  3176. //
  3177. RegCloseKey(hKey1);
  3178. RegCloseKey(hKey2);
  3179. //
  3180. // Return success.
  3181. //
  3182. return (TRUE);
  3183. }
  3184. ////////////////////////////////////////////////////////////////////////////
  3185. //
  3186. // Intl_RunRegApps
  3187. //
  3188. ////////////////////////////////////////////////////////////////////////////
  3189. void Intl_RunRegApps(
  3190. LPCTSTR pszRegKey)
  3191. {
  3192. HKEY hkey;
  3193. DWORD cbData, cbValue, dwType, ctr;
  3194. TCHAR szValueName[32], szCmdLine[MAX_PATH];
  3195. STARTUPINFO startup;
  3196. PROCESS_INFORMATION pi;
  3197. if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  3198. pszRegKey,
  3199. 0L,
  3200. KEY_READ | KEY_WRITE,
  3201. &hkey ) == ERROR_SUCCESS)
  3202. {
  3203. startup.cb = sizeof(STARTUPINFO);
  3204. startup.lpReserved = NULL;
  3205. startup.lpDesktop = NULL;
  3206. startup.lpTitle = NULL;
  3207. startup.dwFlags = 0L;
  3208. startup.cbReserved2 = 0;
  3209. startup.lpReserved2 = NULL;
  3210. // startup.wShowWindow = wShowWindow;
  3211. for (ctr = 0; ; ctr++)
  3212. {
  3213. LONG lEnum;
  3214. cbValue = sizeof(szValueName) / sizeof(TCHAR);
  3215. cbData = sizeof(szCmdLine);
  3216. if ((lEnum = RegEnumValue( hkey,
  3217. ctr,
  3218. szValueName,
  3219. &cbValue,
  3220. NULL,
  3221. &dwType,
  3222. (LPBYTE)szCmdLine,
  3223. &cbData )) == ERROR_MORE_DATA)
  3224. {
  3225. //
  3226. // ERROR_MORE_DATA means the value name or data was too
  3227. // large, so skip to the next item.
  3228. //
  3229. continue;
  3230. }
  3231. else if (lEnum != ERROR_SUCCESS)
  3232. {
  3233. //
  3234. // This could be ERROR_NO_MORE_ENTRIES, or some kind of
  3235. // failure. We can't recover from any other registry
  3236. // problem anyway.
  3237. //
  3238. break;
  3239. }
  3240. //
  3241. // Found a value.
  3242. //
  3243. if (dwType == REG_SZ)
  3244. {
  3245. //
  3246. // Adjust for shift in value index.
  3247. //
  3248. ctr--;
  3249. //
  3250. // Delete the value.
  3251. //
  3252. RegDeleteValue(hkey, szValueName);
  3253. //
  3254. // Only run things marked with a "*" in clean boot.
  3255. //
  3256. if (CreateProcess( NULL,
  3257. szCmdLine,
  3258. NULL,
  3259. NULL,
  3260. FALSE,
  3261. CREATE_NEW_PROCESS_GROUP,
  3262. NULL,
  3263. NULL,
  3264. &startup,
  3265. &pi ))
  3266. {
  3267. WaitForSingleObjectEx(pi.hProcess, INFINITE, TRUE);
  3268. CloseHandle(pi.hProcess);
  3269. CloseHandle(pi.hThread);
  3270. }
  3271. }
  3272. }
  3273. RegCloseKey(hkey);
  3274. }
  3275. }
  3276. ////////////////////////////////////////////////////////////////////////////
  3277. //
  3278. // Intl_RebootTheSystem
  3279. //
  3280. // This routine enables all privileges in the token, calls ExitWindowsEx
  3281. // to reboot the system, and then resets all of the privileges to their
  3282. // old state.
  3283. // Input: bRestart TRUE: restart system
  3284. // FALSE: logoff current session
  3285. //
  3286. ////////////////////////////////////////////////////////////////////////////
  3287. VOID Intl_RebootTheSystem(BOOL bRestart)
  3288. {
  3289. HANDLE Token = NULL;
  3290. ULONG ReturnLength, Index;
  3291. PTOKEN_PRIVILEGES NewState = NULL;
  3292. PTOKEN_PRIVILEGES OldState = NULL;
  3293. BOOL Result;
  3294. Result = OpenProcessToken( GetCurrentProcess(),
  3295. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  3296. &Token );
  3297. if (Result)
  3298. {
  3299. ReturnLength = 4096;
  3300. NewState = (PTOKEN_PRIVILEGES)LocalAlloc(LPTR, ReturnLength);
  3301. OldState = (PTOKEN_PRIVILEGES)LocalAlloc(LPTR, ReturnLength);
  3302. Result = (BOOL)((NewState != NULL) && (OldState != NULL));
  3303. if (Result)
  3304. {
  3305. Result = GetTokenInformation( Token, // TokenHandle
  3306. TokenPrivileges, // TokenInformationClass
  3307. NewState, // TokenInformation
  3308. ReturnLength, // TokenInformationLength
  3309. &ReturnLength ); // ReturnLength
  3310. if (Result)
  3311. {
  3312. //
  3313. // Set the state settings so that all privileges are
  3314. // enabled...
  3315. //
  3316. if (NewState->PrivilegeCount > 0)
  3317. {
  3318. for (Index = 0; Index < NewState->PrivilegeCount; Index++)
  3319. {
  3320. NewState->Privileges[Index].Attributes = SE_PRIVILEGE_ENABLED;
  3321. }
  3322. }
  3323. Result = AdjustTokenPrivileges( Token, // TokenHandle
  3324. FALSE, // DisableAllPrivileges
  3325. NewState, // NewState
  3326. ReturnLength, // BufferLength
  3327. OldState, // PreviousState
  3328. &ReturnLength ); // ReturnLength
  3329. if (Result)
  3330. {
  3331. // Restart system
  3332. if (bRestart)
  3333. {
  3334. ExitWindowsEx(EWX_REBOOT, 0);
  3335. }
  3336. // Logoff current session
  3337. else
  3338. {
  3339. ExitWindowsEx(EWX_LOGOFF, 0);
  3340. }
  3341. AdjustTokenPrivileges( Token,
  3342. FALSE,
  3343. OldState,
  3344. 0,
  3345. NULL,
  3346. NULL );
  3347. }
  3348. }
  3349. }
  3350. }
  3351. if (NewState != NULL)
  3352. {
  3353. LocalFree(NewState);
  3354. }
  3355. if (OldState != NULL)
  3356. {
  3357. LocalFree(OldState);
  3358. }
  3359. if (Token != NULL)
  3360. {
  3361. CloseHandle(Token);
  3362. }
  3363. }
  3364. ////////////////////////////////////////////////////////////////////////////
  3365. //
  3366. // Intl_InstallUserLocale
  3367. //
  3368. // When the DefaultUserCase flag is FALSE, this function write information
  3369. // related to the locale for the current user. Otherwise, this function
  3370. // write information for the .DEFAULT user. In the Default user case, the
  3371. // the information are stored in the registry and the NTSUSER.DAT.
  3372. //
  3373. ////////////////////////////////////////////////////////////////////////////
  3374. BOOL Intl_InstallUserLocale(
  3375. LCID Locale,
  3376. BOOL DefaultUserCase,
  3377. BOOL bChangeLocaleInfo )
  3378. {
  3379. HKEY hKey = NULL;
  3380. HKEY hHive = NULL;
  3381. BOOLEAN wasEnabled;
  3382. TCHAR szLCID[25];
  3383. DWORD dwRet;
  3384. //
  3385. // Save the locale id as a string.
  3386. //
  3387. //wsprintf(szLCID, TEXT("%08x"), Locale);
  3388. if(FAILED(StringCchPrintf(szLCID, ARRAYSIZE(szLCID), TEXT("%08x"), Locale)))
  3389. {
  3390. // This should be impossible, but we need to avoid PREfast complaints.
  3391. return(FALSE);
  3392. }
  3393. //
  3394. // Make sure the locale is valid.
  3395. //
  3396. if (!IsValidLocale(Locale, LCID_INSTALLED))
  3397. {
  3398. if (g_bLog)
  3399. {
  3400. Intl_LogSimpleMessage(IDS_LOG_INVALID_LOCALE, szLCID);
  3401. }
  3402. return (FALSE);
  3403. }
  3404. //
  3405. // Log user locale info change.
  3406. //
  3407. if (g_bLog)
  3408. {
  3409. Intl_LogSimpleMessage(IDS_LOG_USER_LOCALE_CHG, szLCID);
  3410. }
  3411. //
  3412. // Open the right registry section.
  3413. //
  3414. if (!DefaultUserCase)
  3415. {
  3416. dwRet = RegOpenKeyEx( HKEY_CURRENT_USER,
  3417. c_szCPanelIntl,
  3418. 0L,
  3419. KEY_READ | KEY_WRITE,
  3420. &hKey );
  3421. }
  3422. else
  3423. {
  3424. dwRet = RegOpenKeyEx( HKEY_USERS,
  3425. c_szCPanelIntl_DefUser,
  3426. 0L,
  3427. KEY_READ | KEY_WRITE,
  3428. &hKey );
  3429. if (dwRet == ERROR_SUCCESS)
  3430. {
  3431. //
  3432. // Load the default hive.
  3433. //
  3434. if ((hHive = Intl_LoadNtUserHive( TEXT("tempKey"),
  3435. c_szCPanelIntl,
  3436. NULL,
  3437. &wasEnabled )) == NULL )
  3438. {
  3439. RegCloseKey(hKey);
  3440. return (FALSE);
  3441. }
  3442. //
  3443. // Save the Locale value in NTUSER.DAT.
  3444. //
  3445. RegSetValueEx( hHive,
  3446. TEXT("Locale"),
  3447. 0L,
  3448. REG_SZ,
  3449. (LPBYTE)szLCID,
  3450. (lstrlen(szLCID) + 1) * sizeof(TCHAR));
  3451. //
  3452. // Clean up.
  3453. //
  3454. RegCloseKey(hHive);
  3455. Intl_UnloadNtUserHive(TEXT("tempKey"), &wasEnabled);
  3456. }
  3457. }
  3458. //
  3459. // Set the locale value in the user's control panel international
  3460. // section of the registry.
  3461. //
  3462. if ((dwRet != ERROR_SUCCESS) ||
  3463. (RegSetValueEx( hKey,
  3464. TEXT("Locale"),
  3465. 0L,
  3466. REG_SZ,
  3467. (LPBYTE)szLCID,
  3468. (lstrlen(szLCID) + 1) * sizeof(TCHAR) ) != ERROR_SUCCESS))
  3469. {
  3470. if (hKey != NULL)
  3471. {
  3472. RegCloseKey(hKey);
  3473. }
  3474. return (FALSE);
  3475. }
  3476. //
  3477. // When the locale changes, update ALL registry information when asked.
  3478. //
  3479. if (bChangeLocaleInfo)
  3480. {
  3481. Intl_SetLocaleInfo(Locale, LOCALE_SABBREVLANGNAME, TEXT("sLanguage"), DefaultUserCase);
  3482. Intl_SetLocaleInfo(Locale, LOCALE_SCOUNTRY, TEXT("sCountry"), DefaultUserCase);
  3483. Intl_SetLocaleInfo(Locale, LOCALE_ICOUNTRY, TEXT("iCountry"), DefaultUserCase);
  3484. Intl_SetLocaleInfo(Locale, LOCALE_S1159, TEXT("s1159"), DefaultUserCase);
  3485. Intl_SetLocaleInfo(Locale, LOCALE_S2359, TEXT("s2359"), DefaultUserCase);
  3486. Intl_SetLocaleInfo(Locale, LOCALE_STIMEFORMAT, TEXT("sTimeFormat"), DefaultUserCase);
  3487. Intl_SetLocaleInfo(Locale, LOCALE_STIME, TEXT("sTime"), DefaultUserCase);
  3488. Intl_SetLocaleInfo(Locale, LOCALE_ITIME, TEXT("iTime"), DefaultUserCase);
  3489. Intl_SetLocaleInfo(Locale, LOCALE_ITLZERO, TEXT("iTLZero"), DefaultUserCase);
  3490. Intl_SetLocaleInfo(Locale, LOCALE_ITIMEMARKPOSN, TEXT("iTimePrefix"), DefaultUserCase);
  3491. Intl_SetLocaleInfo(Locale, LOCALE_SSHORTDATE, TEXT("sShortDate"), DefaultUserCase);
  3492. Intl_SetLocaleInfo(Locale, LOCALE_IDATE, TEXT("iDate"), DefaultUserCase);
  3493. Intl_SetLocaleInfo(Locale, LOCALE_SDATE, TEXT("sDate"), DefaultUserCase);
  3494. Intl_SetLocaleInfo(Locale, LOCALE_SLONGDATE, TEXT("sLongDate"), DefaultUserCase);
  3495. Intl_SetLocaleInfo(Locale, LOCALE_SCURRENCY, TEXT("sCurrency"), DefaultUserCase);
  3496. Intl_SetLocaleInfo(Locale, LOCALE_ICURRENCY, TEXT("iCurrency"), DefaultUserCase);
  3497. Intl_SetLocaleInfo(Locale, LOCALE_INEGCURR, TEXT("iNegCurr"), DefaultUserCase);
  3498. Intl_SetLocaleInfo(Locale, LOCALE_ICURRDIGITS, TEXT("iCurrDigits"), DefaultUserCase);
  3499. Intl_SetLocaleInfo(Locale, LOCALE_SDECIMAL, TEXT("sDecimal"), DefaultUserCase);
  3500. Intl_SetLocaleInfo(Locale, LOCALE_SMONDECIMALSEP, TEXT("sMonDecimalSep"), DefaultUserCase);
  3501. Intl_SetLocaleInfo(Locale, LOCALE_STHOUSAND, TEXT("sThousand"), DefaultUserCase);
  3502. Intl_SetLocaleInfo(Locale, LOCALE_SMONTHOUSANDSEP, TEXT("sMonThousandSep"), DefaultUserCase);
  3503. Intl_SetLocaleInfo(Locale, LOCALE_SLIST, TEXT("sList"), DefaultUserCase);
  3504. Intl_SetLocaleInfo(Locale, LOCALE_IDIGITS, TEXT("iDigits"), DefaultUserCase);
  3505. Intl_SetLocaleInfo(Locale, LOCALE_ILZERO, TEXT("iLzero"), DefaultUserCase);
  3506. Intl_SetLocaleInfo(Locale, LOCALE_INEGNUMBER, TEXT("iNegNumber"), DefaultUserCase);
  3507. Intl_SetLocaleInfo(Locale, LOCALE_SNATIVEDIGITS, TEXT("sNativeDigits"), DefaultUserCase);
  3508. Intl_SetLocaleInfo(Locale, LOCALE_IDIGITSUBSTITUTION, TEXT("NumShape"), DefaultUserCase);
  3509. Intl_SetLocaleInfo(Locale, LOCALE_IMEASURE, TEXT("iMeasure"), DefaultUserCase);
  3510. Intl_SetLocaleInfo(Locale, LOCALE_ICALENDARTYPE, TEXT("iCalendarType"), DefaultUserCase);
  3511. Intl_SetLocaleInfo(Locale, LOCALE_IFIRSTDAYOFWEEK, TEXT("iFirstDayOfWeek"), DefaultUserCase);
  3512. Intl_SetLocaleInfo(Locale, LOCALE_IFIRSTWEEKOFYEAR, TEXT("iFirstWeekOfYear"), DefaultUserCase);
  3513. Intl_SetLocaleInfo(Locale, LOCALE_SGROUPING, TEXT("sGrouping"), DefaultUserCase);
  3514. Intl_SetLocaleInfo(Locale, LOCALE_SMONGROUPING, TEXT("sMonGrouping"), DefaultUserCase);
  3515. Intl_SetLocaleInfo(Locale, LOCALE_SPOSITIVESIGN, TEXT("sPositiveSign"), DefaultUserCase);
  3516. Intl_SetLocaleInfo(Locale, LOCALE_SNEGATIVESIGN, TEXT("sNegativeSign"), DefaultUserCase);
  3517. }
  3518. //
  3519. // Set the user's default locale in the system so that any new
  3520. // process will use the new locale.
  3521. //
  3522. if (!DefaultUserCase)
  3523. {
  3524. NtSetDefaultLocale(TRUE, Locale);
  3525. }
  3526. //
  3527. // Flush the International key.
  3528. //
  3529. if (hKey != NULL)
  3530. {
  3531. RegFlushKey(hKey);
  3532. RegCloseKey(hKey);
  3533. }
  3534. //
  3535. // Return success.
  3536. //
  3537. return (TRUE);
  3538. }
  3539. ////////////////////////////////////////////////////////////////////////////
  3540. //
  3541. // Intl_SetLocaleInfo
  3542. //
  3543. ////////////////////////////////////////////////////////////////////////////
  3544. void Intl_SetLocaleInfo(
  3545. LCID Locale,
  3546. LCTYPE LCType,
  3547. LPTSTR lpIniStr,
  3548. BOOL bDefaultUserCase)
  3549. {
  3550. TCHAR pBuf[SIZE_128];
  3551. //
  3552. // Get the default information for the given locale.
  3553. //
  3554. if (GetLocaleInfo( Locale,
  3555. LCType | LOCALE_NOUSEROVERRIDE,
  3556. pBuf,
  3557. SIZE_128 ))
  3558. {
  3559. if (!bDefaultUserCase)
  3560. {
  3561. //
  3562. // Set the default information in the registry.
  3563. //
  3564. // NOTE: We want to use SetLocaleInfo if possible so that the
  3565. // NLS cache is updated right away. Otherwise, we'll
  3566. // simply use WriteProfileString.
  3567. //
  3568. if (!SetLocaleInfo(Locale, LCType, pBuf))
  3569. {
  3570. //
  3571. // If SetLocaleInfo failed, try WriteProfileString since
  3572. // some of the LCTypes are not supported in SetLocaleInfo.
  3573. //
  3574. WriteProfileString(szIntl, lpIniStr, pBuf);
  3575. }
  3576. }
  3577. else
  3578. {
  3579. //
  3580. // Set the default information in the registry and NTUSER.DAT.
  3581. //
  3582. Intl_SetDefaultUserLocaleInfo(lpIniStr, pBuf);
  3583. }
  3584. }
  3585. }
  3586. ////////////////////////////////////////////////////////////////////////////
  3587. //
  3588. // Intl_AddPage
  3589. //
  3590. ////////////////////////////////////////////////////////////////////////////
  3591. void Intl_AddPage(
  3592. LPPROPSHEETHEADER ppsh,
  3593. UINT id,
  3594. DLGPROC pfn,
  3595. LPARAM lParam,
  3596. UINT iMaxPages)
  3597. {
  3598. if (ppsh->nPages < iMaxPages)
  3599. {
  3600. PROPSHEETPAGE psp;
  3601. psp.dwSize = sizeof(psp);
  3602. psp.dwFlags = PSP_DEFAULT;
  3603. psp.hInstance = hInstance;
  3604. psp.pszTemplate = MAKEINTRESOURCE(id);
  3605. psp.pfnDlgProc = pfn;
  3606. psp.lParam = lParam;
  3607. ppsh->phpage[ppsh->nPages] = CreatePropertySheetPage(&psp);
  3608. if (ppsh->phpage[ppsh->nPages])
  3609. {
  3610. ppsh->nPages++;
  3611. }
  3612. }
  3613. }
  3614. ////////////////////////////////////////////////////////////////////////////
  3615. //
  3616. // Intl_AddExternalPage
  3617. //
  3618. // Adds a property sheet page from the given dll.
  3619. //
  3620. ////////////////////////////////////////////////////////////////////////////
  3621. void Intl_AddExternalPage(
  3622. LPPROPSHEETHEADER ppsh,
  3623. UINT id,
  3624. HINSTANCE hInst,
  3625. LPSTR ProcName,
  3626. UINT iMaxPages)
  3627. {
  3628. DLGPROC pfn;
  3629. if (ppsh->nPages < iMaxPages)
  3630. {
  3631. PROPSHEETPAGE psp;
  3632. if (hInst)
  3633. {
  3634. pfn = (DLGPROC)GetProcAddress(hInst, ProcName);
  3635. if (!pfn)
  3636. {
  3637. return;
  3638. }
  3639. psp.dwSize = sizeof(psp);
  3640. psp.dwFlags = PSP_DEFAULT;
  3641. psp.hInstance = hInst;
  3642. psp.pszTemplate = MAKEINTRESOURCE(id);
  3643. psp.pfnDlgProc = pfn;
  3644. psp.lParam = 0;
  3645. ppsh->phpage[ppsh->nPages] = CreatePropertySheetPage(&psp);
  3646. if (ppsh->phpage[ppsh->nPages])
  3647. {
  3648. ppsh->nPages++;
  3649. }
  3650. }
  3651. }
  3652. }
  3653. ////////////////////////////////////////////////////////////////////////////
  3654. //
  3655. // Intl_SetDefaultUserLocaleInfo
  3656. //
  3657. ////////////////////////////////////////////////////////////////////////////
  3658. BOOL Intl_SetDefaultUserLocaleInfo(
  3659. LPCTSTR lpKeyName,
  3660. LPCTSTR lpString)
  3661. {
  3662. HKEY hKey = NULL;
  3663. LONG rc = 0L;
  3664. TCHAR szProfile[REGSTR_MAX_VALUE_LENGTH];
  3665. BOOLEAN wasEnabled;
  3666. //
  3667. // Open the .DEFAULT control panel international section.
  3668. //
  3669. if ((rc = RegOpenKeyEx( HKEY_USERS,
  3670. c_szCPanelIntl_DefUser,
  3671. 0L,
  3672. KEY_READ | KEY_WRITE,
  3673. &hKey )) == ERROR_SUCCESS)
  3674. {
  3675. //
  3676. // Set the value
  3677. //
  3678. rc = RegSetValueEx( hKey,
  3679. lpKeyName,
  3680. 0L,
  3681. REG_SZ,
  3682. (LPBYTE)lpString,
  3683. (lstrlen(lpString) + 1) * sizeof(TCHAR) );
  3684. //
  3685. // Flush the International key.
  3686. //
  3687. RegFlushKey(hKey);
  3688. RegCloseKey(hKey);
  3689. }
  3690. if (rc == ERROR_SUCCESS)
  3691. {
  3692. //
  3693. // Load the hive.
  3694. //
  3695. if ((hKey = Intl_LoadNtUserHive( TEXT("RegionalSettingsTempKey"),
  3696. c_szCPanelIntl,
  3697. NULL,
  3698. &wasEnabled)) == NULL)
  3699. {
  3700. return (FALSE);
  3701. }
  3702. //
  3703. // Set the value.
  3704. //
  3705. rc = RegSetValueEx( hKey,
  3706. lpKeyName,
  3707. 0L,
  3708. REG_SZ,
  3709. (LPBYTE)lpString,
  3710. (lstrlen(lpString) + 1) * sizeof(TCHAR) );
  3711. //
  3712. // Clean up.
  3713. //
  3714. RegCloseKey(hKey);
  3715. Intl_UnloadNtUserHive(TEXT("RegionalSettingsTempKey"), &wasEnabled);
  3716. }
  3717. else
  3718. {
  3719. return (FALSE);
  3720. }
  3721. return (TRUE);
  3722. }
  3723. ////////////////////////////////////////////////////////////////////////////
  3724. //
  3725. // Intl_DeleteRegKeyValues
  3726. //
  3727. // This deletes all values under a specific key.
  3728. //
  3729. ////////////////////////////////////////////////////////////////////////////
  3730. void Intl_DeleteRegKeyValues(
  3731. HKEY hKey)
  3732. {
  3733. TCHAR szValueName[REGSTR_MAX_VALUE_LENGTH];
  3734. DWORD cbValue = REGSTR_MAX_VALUE_LENGTH;
  3735. //
  3736. // Sanity check.
  3737. //
  3738. if (hKey == NULL)
  3739. {
  3740. return;
  3741. }
  3742. //
  3743. // Enumerate values.
  3744. //
  3745. while (RegEnumValue( hKey,
  3746. 0,
  3747. szValueName,
  3748. &cbValue,
  3749. NULL,
  3750. NULL,
  3751. NULL,
  3752. NULL ) == ERROR_SUCCESS)
  3753. {
  3754. //
  3755. // Delete the value.
  3756. //
  3757. RegDeleteValue(hKey, szValueName);
  3758. cbValue = REGSTR_MAX_VALUE_LENGTH;
  3759. }
  3760. }
  3761. ////////////////////////////////////////////////////////////////////////////
  3762. //
  3763. // Intl_DeleteRegTree
  3764. //
  3765. // This deletes all subkeys under a specific key.
  3766. //
  3767. // Note: The code makes no attempt to check or recover from partial
  3768. // deletions.
  3769. //
  3770. // A registry key that is opened by an application can be deleted
  3771. // without error by another application. This is by design.
  3772. //
  3773. ////////////////////////////////////////////////////////////////////////////
  3774. DWORD Intl_DeleteRegTree(
  3775. HKEY hStartKey,
  3776. LPTSTR pKeyName)
  3777. {
  3778. DWORD dwRtn, dwSubKeyLength;
  3779. LPTSTR pSubKey = NULL;
  3780. TCHAR szSubKey[REGSTR_MAX_VALUE_LENGTH]; // (256) this should be dynamic.
  3781. HKEY hKey;
  3782. //
  3783. // Do not allow NULL or empty key name.
  3784. //
  3785. if (pKeyName && lstrlen(pKeyName))
  3786. {
  3787. if ((dwRtn = RegOpenKeyEx( hStartKey,
  3788. pKeyName,
  3789. 0,
  3790. KEY_ENUMERATE_SUB_KEYS | DELETE,
  3791. &hKey )) == ERROR_SUCCESS)
  3792. {
  3793. while (dwRtn == ERROR_SUCCESS)
  3794. {
  3795. dwSubKeyLength = REGSTR_MAX_VALUE_LENGTH;
  3796. dwRtn = RegEnumKeyEx( hKey,
  3797. 0, // always index zero
  3798. szSubKey,
  3799. &dwSubKeyLength,
  3800. NULL,
  3801. NULL,
  3802. NULL,
  3803. NULL );
  3804. if (dwRtn == ERROR_NO_MORE_ITEMS)
  3805. {
  3806. dwRtn = RegDeleteKey(hStartKey, pKeyName);
  3807. break;
  3808. }
  3809. else if (dwRtn == ERROR_SUCCESS)
  3810. {
  3811. dwRtn = Intl_DeleteRegTree(hKey, szSubKey);
  3812. }
  3813. }
  3814. RegCloseKey(hKey);
  3815. //
  3816. // Do not save return code because error has already occurred.
  3817. //
  3818. }
  3819. }
  3820. else
  3821. {
  3822. dwRtn = ERROR_BADKEY;
  3823. }
  3824. return (dwRtn);
  3825. }
  3826. ////////////////////////////////////////////////////////////////////////////
  3827. //
  3828. // Intl_DeleteRegSubKeys
  3829. //
  3830. // This deletes all subkeys under a specific key.
  3831. //
  3832. ////////////////////////////////////////////////////////////////////////////
  3833. void Intl_DeleteRegSubKeys(
  3834. HKEY hKey)
  3835. {
  3836. TCHAR szKeyName[REGSTR_MAX_VALUE_LENGTH];
  3837. DWORD cbKey = REGSTR_MAX_VALUE_LENGTH;
  3838. //
  3839. // Sanity check.
  3840. //
  3841. if (hKey == NULL)
  3842. {
  3843. return;
  3844. }
  3845. //
  3846. // Enumerate values.
  3847. //
  3848. while (RegEnumKeyEx( hKey,
  3849. 0,
  3850. szKeyName,
  3851. &cbKey,
  3852. NULL,
  3853. NULL,
  3854. NULL,
  3855. NULL ) == ERROR_SUCCESS)
  3856. {
  3857. //
  3858. // Delete the value.
  3859. //
  3860. Intl_DeleteRegTree(hKey, szKeyName);
  3861. cbKey = REGSTR_MAX_VALUE_LENGTH;
  3862. }
  3863. }
  3864. ////////////////////////////////////////////////////////////////////////////
  3865. //
  3866. // Intl_CopyRegKeyValues
  3867. //
  3868. // This copies all values under the source key to the destination key.
  3869. //
  3870. ////////////////////////////////////////////////////////////////////////////
  3871. DWORD Intl_CopyRegKeyValues(
  3872. HKEY hSrc,
  3873. HKEY hDest)
  3874. {
  3875. DWORD cbValue, dwSubKeyIndex=0, dwType, cdwBuf;
  3876. DWORD dwValues, cbMaxValueData, i;
  3877. TCHAR szValue[REGSTR_MAX_VALUE_LENGTH]; // this should be dynamic.
  3878. DWORD lRet = ERROR_SUCCESS;
  3879. LPBYTE pBuf;
  3880. if ((lRet = RegQueryInfoKey( hSrc,
  3881. NULL,
  3882. NULL,
  3883. NULL,
  3884. NULL,
  3885. NULL,
  3886. NULL,
  3887. &dwValues,
  3888. NULL,
  3889. &cbMaxValueData,
  3890. NULL,
  3891. NULL )) == ERROR_SUCCESS)
  3892. {
  3893. if (dwValues)
  3894. {
  3895. if ((pBuf = HeapAlloc( GetProcessHeap(),
  3896. HEAP_ZERO_MEMORY,
  3897. cbMaxValueData )))
  3898. {
  3899. for (i = 0; i < dwValues; i++)
  3900. {
  3901. //
  3902. // Get values to create.
  3903. //
  3904. cbValue = REGSTR_MAX_VALUE_LENGTH;
  3905. cdwBuf = cbMaxValueData;
  3906. lRet = RegEnumValue( hSrc, // handle of key to query
  3907. i, // index of value to query
  3908. szValue, // buffer for value string
  3909. &cbValue, // address for size of buffer
  3910. NULL, // reserved
  3911. &dwType, // buffer address for type code
  3912. pBuf, // address of buffer for value data
  3913. &cdwBuf ); // address for size of buffer
  3914. if (lRet == ERROR_SUCCESS)
  3915. {
  3916. if ((lRet = RegSetValueEx( hDest,
  3917. szValue,
  3918. 0,
  3919. dwType,
  3920. (CONST BYTE *)pBuf,
  3921. cdwBuf )) != ERROR_SUCCESS)
  3922. {
  3923. break;
  3924. }
  3925. }
  3926. else
  3927. {
  3928. break;
  3929. }
  3930. }
  3931. HeapFree(GetProcessHeap(), 0, pBuf);
  3932. }
  3933. }
  3934. }
  3935. return (lRet);
  3936. }
  3937. ////////////////////////////////////////////////////////////////////////////
  3938. //
  3939. // Intl_CreateRegTree
  3940. //
  3941. // This copies all values and subkeys under the source key to the
  3942. // destination key.
  3943. //
  3944. ////////////////////////////////////////////////////////////////////////////
  3945. DWORD Intl_CreateRegTree(
  3946. HKEY hSrc,
  3947. HKEY hDest)
  3948. {
  3949. DWORD cdwClass, dwSubKeyLength, dwDisposition, dwKeyIndex = 0;
  3950. LPTSTR pSubKey = NULL;
  3951. TCHAR szSubKey[REGSTR_MAX_VALUE_LENGTH]; // this should be dynamic.
  3952. TCHAR szClass[REGSTR_MAX_VALUE_LENGTH]; // this should be dynamic.
  3953. HKEY hNewKey, hKey;
  3954. DWORD lRet;
  3955. //
  3956. // Copy values
  3957. //
  3958. if ((lRet = Intl_CopyRegKeyValues( hSrc,
  3959. hDest )) != ERROR_SUCCESS)
  3960. {
  3961. return (lRet);
  3962. }
  3963. //
  3964. // Copy the subkeys and the subkey values.
  3965. //
  3966. for (;;)
  3967. {
  3968. dwSubKeyLength = REGSTR_MAX_VALUE_LENGTH;
  3969. cdwClass = REGSTR_MAX_VALUE_LENGTH;
  3970. lRet = RegEnumKeyEx( hSrc,
  3971. dwKeyIndex,
  3972. szSubKey,
  3973. &dwSubKeyLength,
  3974. NULL,
  3975. szClass,
  3976. &cdwClass,
  3977. NULL );
  3978. if (lRet == ERROR_NO_MORE_ITEMS)
  3979. {
  3980. lRet = ERROR_SUCCESS;
  3981. break;
  3982. }
  3983. else if (lRet == ERROR_SUCCESS)
  3984. {
  3985. if ((lRet = RegCreateKeyEx( hDest,
  3986. szSubKey,
  3987. 0,
  3988. szClass,
  3989. REG_OPTION_NON_VOLATILE,
  3990. KEY_ALL_ACCESS,
  3991. NULL,
  3992. &hNewKey,
  3993. &dwDisposition )) == ERROR_SUCCESS)
  3994. {
  3995. //
  3996. // Copy all subkeys.
  3997. //
  3998. if ((lRet = RegOpenKeyEx( hSrc,
  3999. szSubKey,
  4000. 0,
  4001. KEY_ALL_ACCESS,
  4002. &hKey )) == ERROR_SUCCESS)
  4003. {
  4004. //
  4005. // Recursively copy the remainder of the tree.
  4006. //
  4007. lRet = Intl_CreateRegTree(hKey, hNewKey);
  4008. CloseHandle(hKey);
  4009. CloseHandle(hNewKey);
  4010. if (lRet != ERROR_SUCCESS)
  4011. {
  4012. break;
  4013. }
  4014. }
  4015. else
  4016. {
  4017. CloseHandle(hNewKey);
  4018. break;
  4019. }
  4020. }
  4021. }
  4022. else
  4023. {
  4024. break;
  4025. }
  4026. ++dwKeyIndex;
  4027. }
  4028. return (lRet);
  4029. }
  4030. ////////////////////////////////////////////////////////////////////////////
  4031. //
  4032. // Intl_LoadNtUserHive
  4033. //
  4034. // The caller of this function needs to call Intl_UnloadNtUserHive() when
  4035. // the function succeeds in order to properly release the handle on the
  4036. // NTUSER.DAT file.
  4037. //
  4038. ////////////////////////////////////////////////////////////////////////////
  4039. HKEY Intl_LoadNtUserHive(
  4040. LPCTSTR lpRoot,
  4041. LPCTSTR lpKeyName,
  4042. LPCTSTR lpAccountName,
  4043. BOOLEAN *lpWasEnabled)
  4044. {
  4045. HKEY hKey = NULL;
  4046. LONG rc = 0L;
  4047. BOOL bRet = TRUE;
  4048. TCHAR szProfile[REGSTR_MAX_VALUE_LENGTH] = {0};
  4049. TCHAR szKeyName[REGSTR_MAX_VALUE_LENGTH] = {0};
  4050. DWORD cchSize;
  4051. cchSize = MAX_PATH;
  4052. if(NULL == lpAccountName)
  4053. {
  4054. //
  4055. // Get the file name for the Default User profile.
  4056. //
  4057. if (!GetDefaultUserProfileDirectory(szProfile, &cchSize))
  4058. {
  4059. return (NULL);
  4060. }
  4061. }
  4062. else
  4063. {
  4064. //
  4065. // Get the file name for the specified account's User profile.
  4066. //
  4067. if (!GetProfilesDirectory(szProfile, &cchSize))
  4068. {
  4069. return (NULL);
  4070. }
  4071. // lstrcat(szProfile, lpAccountName);
  4072. if(FAILED(StringCchCat(szProfile, ARRAYSIZE(szProfile), lpAccountName)))
  4073. {
  4074. // This should be impossible, but we need to avoid PREfast complaints.
  4075. return(NULL);
  4076. }
  4077. }
  4078. // lstrcat(szProfile, TEXT("\\NTUSER.DAT"));
  4079. if(FAILED(StringCchCat(szProfile, ARRAYSIZE(szProfile), TEXT("\\NTUSER.DAT"))))
  4080. {
  4081. // This should be impossible, but we need to avoid PREfast complaints.
  4082. return(NULL);
  4083. }
  4084. //
  4085. // Set the value in the Default User hive.
  4086. //
  4087. rc = Intl_SetPrivilegeAccessToken(SE_RESTORE_NAME, TRUE,lpWasEnabled);
  4088. if (NT_SUCCESS(rc))
  4089. {
  4090. //
  4091. // Load the hive and restore the privilege to its previous state.
  4092. //
  4093. rc = RegLoadKey(HKEY_USERS, lpRoot, szProfile);
  4094. Intl_SetPrivilegeAccessToken(SE_RESTORE_NAME, *lpWasEnabled,lpWasEnabled);
  4095. //
  4096. // If the hive loaded properly, set the value.
  4097. //
  4098. if (rc == ERROR_SUCCESS)
  4099. {
  4100. //
  4101. // Get the temporary key name.
  4102. //
  4103. //swprintf(szKeyName, TEXT("%s\\%s"), lpRoot, lpKeyName);
  4104. if(SUCCEEDED(StringCchPrintfW(szKeyName, REGSTR_MAX_VALUE_LENGTH, TEXT("%s\\%s"), lpRoot, lpKeyName)))
  4105. {
  4106. if ((rc = RegOpenKeyEx( HKEY_USERS,
  4107. szKeyName,
  4108. 0L,
  4109. KEY_READ | KEY_WRITE,
  4110. &hKey )) == ERROR_SUCCESS)
  4111. {
  4112. return (hKey);
  4113. }
  4114. }
  4115. Intl_UnloadNtUserHive(lpRoot, lpWasEnabled);
  4116. return (NULL);
  4117. }
  4118. }
  4119. return (NULL);
  4120. }
  4121. ////////////////////////////////////////////////////////////////////////////
  4122. //
  4123. // Intl_UnloadNtUserHive
  4124. //
  4125. ////////////////////////////////////////////////////////////////////////////
  4126. void Intl_UnloadNtUserHive(
  4127. LPCTSTR lpRoot,
  4128. BOOLEAN *lpWasEnabled)
  4129. {
  4130. if (NT_SUCCESS(Intl_SetPrivilegeAccessToken( SE_RESTORE_NAME,
  4131. TRUE,
  4132. lpWasEnabled )))
  4133. {
  4134. RegUnLoadKey(HKEY_USERS, lpRoot);
  4135. Intl_SetPrivilegeAccessToken( SE_RESTORE_NAME,
  4136. *lpWasEnabled,
  4137. lpWasEnabled );
  4138. }
  4139. }
  4140. ////////////////////////////////////////////////////////////////////////////
  4141. //
  4142. // Intl_ChangeUILangForAllUsers
  4143. //
  4144. // LATER: Clean up this function to put all six registry update cases into
  4145. // one loop, with a struct that contains info on the reg key to
  4146. // update/hive to load and the cases in which they are to run.
  4147. //
  4148. ////////////////////////////////////////////////////////////////////////////
  4149. BOOL Intl_ChangeUILangForAllUsers(
  4150. LANGID UILanguageId)
  4151. {
  4152. HKEY hKey;
  4153. HKEY hHive;
  4154. TCHAR szData[MAX_PATH];
  4155. TCHAR* arStrings[1];
  4156. LONG rc = 0L;
  4157. BOOLEAN wasEnabled;
  4158. int i;
  4159. //
  4160. // Array of user accounts that we care about
  4161. //
  4162. LPTSTR ppDefaultUser[] = { TEXT(".DEFAULT"), TEXT("S-1-5-19"), TEXT("S-1-5-20")};
  4163. TCHAR szRegPath[MAX_PATH];
  4164. //
  4165. // Save the UILanguageId as a string.
  4166. //
  4167. //wsprintf(szData, TEXT("%08x"), UILanguageId);
  4168. if(FAILED(StringCchPrintf(szData, ARRAYSIZE(szData), TEXT("%08x"), UILanguageId)))
  4169. {
  4170. // This should be impossible, but we need to avoid PREfast complaints.
  4171. return(FALSE);
  4172. }
  4173. //
  4174. // We need to log the event to the MUI event log so admins have warning of tampering (bug 553706)
  4175. //
  4176. // We only have 1 string to log
  4177. arStrings[0]=szData;
  4178. Intl_LogEvent(MSG_REGIONALOPTIONSCHANGE_DEFUILANG, c_szEventSourceName, ARRAYSIZE(arStrings), arStrings);
  4179. //
  4180. // Now save value for all the users -- in minisetup
  4181. // only the first entry will succeed (see below)
  4182. //
  4183. for (i=0; i< ARRAYSIZE(ppDefaultUser); i++)
  4184. {
  4185. if (!PathCombine(szRegPath, ppDefaultUser[i], TEXT("Control Panel\\Desktop")))
  4186. {
  4187. return (FALSE);
  4188. }
  4189. //
  4190. // Set the value in .DEFAULT registry.
  4191. //
  4192. if ((rc = RegOpenKeyEx( HKEY_USERS,
  4193. szRegPath,
  4194. 0L,
  4195. KEY_READ | KEY_WRITE,
  4196. &hKey )) == ERROR_SUCCESS)
  4197. {
  4198. rc = RegSetValueEx( hKey,
  4199. c_szMUIValue,
  4200. 0L,
  4201. REG_SZ,
  4202. (LPBYTE)szData,
  4203. (lstrlen(szData) + 1) * sizeof(TCHAR) );
  4204. //
  4205. // Sync up UI language pending key
  4206. //
  4207. if (rc == ERROR_SUCCESS)
  4208. {
  4209. rc = RegSetValueEx( hKey,
  4210. szMUILangPending,
  4211. 0L,
  4212. REG_SZ,
  4213. (LPBYTE)szData,
  4214. (lstrlen(szData) + 1) * sizeof(TCHAR) );
  4215. }
  4216. RegCloseKey(hKey);
  4217. }
  4218. }
  4219. //
  4220. // Save the value into the .DEFAULT user hive
  4221. //
  4222. //
  4223. // Load the default hive
  4224. //
  4225. if ((hHive = Intl_LoadNtUserHive( TEXT("tempKey"),
  4226. c_szCPanelDesktop,
  4227. NULL,
  4228. &wasEnabled )) == NULL )
  4229. {
  4230. return (FALSE);
  4231. }
  4232. //
  4233. // Save the MUI language value in the default user NTUSER.dat
  4234. //
  4235. rc = RegSetValueEx( hHive,
  4236. c_szMUIValue,
  4237. 0L,
  4238. REG_SZ,
  4239. (LPBYTE)szData,
  4240. (lstrlen(szData) + 1) * sizeof(TCHAR));
  4241. //
  4242. // Sync up UI language pending key
  4243. //
  4244. if (rc == ERROR_SUCCESS)
  4245. {
  4246. rc = RegSetValueEx( hHive,
  4247. szMUILangPending,
  4248. 0L,
  4249. REG_SZ,
  4250. (LPBYTE)szData,
  4251. (lstrlen(szData) + 1) * sizeof(TCHAR) );
  4252. }
  4253. //
  4254. // Clean up
  4255. //
  4256. RegCloseKey(hHive);
  4257. Intl_UnloadNtUserHive(TEXT("tempKey"), &wasEnabled);
  4258. //
  4259. // For the minisetup case, S-1-5-19 and S-1-5-20 are not yet loaded,
  4260. // so the above code will have failed. Load the hives directly.
  4261. //
  4262. if(2 == g_bSetupCase)
  4263. {
  4264. //
  4265. // Array of user account locations that we care about
  4266. //
  4267. LPTSTR ppMiniSetupUsers[] = { TEXT("\\LocalService"), TEXT("\\NetworkService") };
  4268. for (i=0; i< ARRAYSIZE(ppMiniSetupUsers); i++)
  4269. {
  4270. //
  4271. // Load the appropriate hive
  4272. //
  4273. if ((hHive = Intl_LoadNtUserHive( TEXT("tempKey"),
  4274. c_szCPanelDesktop,
  4275. ppMiniSetupUsers[i],
  4276. &wasEnabled )) == NULL )
  4277. {
  4278. return (FALSE);
  4279. }
  4280. //
  4281. // Save the MUI language value in the appropriate NTUSER.dat
  4282. //
  4283. rc = RegSetValueEx( hHive,
  4284. c_szMUIValue,
  4285. 0L,
  4286. REG_SZ,
  4287. (LPBYTE)szData,
  4288. (lstrlen(szData) + 1) * sizeof(TCHAR));
  4289. //
  4290. // Sync up UI language pending key
  4291. //
  4292. if (rc == ERROR_SUCCESS)
  4293. {
  4294. rc = RegSetValueEx( hHive,
  4295. szMUILangPending,
  4296. 0L,
  4297. REG_SZ,
  4298. (LPBYTE)szData,
  4299. (lstrlen(szData) + 1) * sizeof(TCHAR) );
  4300. }
  4301. //
  4302. // Clean up
  4303. //
  4304. RegCloseKey(hHive);
  4305. Intl_UnloadNtUserHive(TEXT("tempKey"), &wasEnabled);
  4306. }
  4307. }
  4308. //
  4309. // Install Language Input locales.
  4310. //
  4311. return Intl_InstallKeyboardLayout(NULL,
  4312. MAKELCID(UILanguageId, SORT_DEFAULT),
  4313. 0,
  4314. FALSE,
  4315. TRUE,
  4316. FALSE);
  4317. }
  4318. ////////////////////////////////////////////////////////////////////////////
  4319. //
  4320. // Intl_CreateEventLog()
  4321. //
  4322. ////////////////////////////////////////////////////////////////////////////
  4323. BOOL Intl_CreateEventLog()
  4324. {
  4325. HKEY hk;
  4326. DWORD dwData;
  4327. TCHAR szPath[MAX_PATH+1] = {0};
  4328. HRESULT hr = S_OK;
  4329. size_t cch = 0;
  4330. size_t cb = 0;
  4331. // Find the windows directory
  4332. if (!GetSystemWindowsDirectory(szPath, MAX_PATH+1))
  4333. {
  4334. return FALSE;
  4335. }
  4336. // check retrieved winpath, it needs to have space to append "system32\intl.cpl" at the end
  4337. hr = StringCchLength(szPath, ARRAYSIZE(szPath), &cch);
  4338. if (FAILED(hr) || ((cch + 17) >= MAX_PATH+1))
  4339. {
  4340. // If this really happened, windows wouldn't boot! (kernel32.dll would be too long a path!)
  4341. return FALSE;
  4342. }
  4343. // append system32\\intl.cpl
  4344. // Add a \ if the winpath didn't have it already
  4345. if (szPath[cch-1] != TEXT('\\'))
  4346. {
  4347. szPath[cch++] = '\\';
  4348. szPath[cch] = '\0';
  4349. }
  4350. // Add our string
  4351. hr = StringCchCat(szPath, MAX_PATH+1, TEXT("system32\\intl.cpl"));
  4352. if (FAILED(hr))
  4353. {
  4354. // Somehow we couln't fix our strings (may not have had enough space)
  4355. return FALSE;
  4356. }
  4357. // get the byte count for RegSetValueEx
  4358. hr = StringCbLength(szPath, (MAX_PATH+1) * sizeof(TCHAR), &cb);
  4359. if (FAILED(hr))
  4360. {
  4361. // Our string didn't work.
  4362. return FALSE;
  4363. }
  4364. // Add our event log source name as a subkey under the System
  4365. // key in the EventLog registry key.
  4366. if (ERROR_SUCCESS != RegCreateKey(HKEY_LOCAL_MACHINE, c_szEventRegistryPath, &hk))
  4367. {
  4368. // Couldn't open/create the registry key
  4369. return FALSE;
  4370. }
  4371. // Add our file name to the EventMessageFile subkey. (Source for event log strings)
  4372. if (RegSetValueEx(hk, TEXT("EventMessageFile"), 0, REG_EXPAND_SZ, (LPBYTE) szPath, cb))
  4373. {
  4374. // That didn't work.
  4375. RegCloseKey(hk);
  4376. return FALSE;
  4377. }
  4378. // Set the supported event types in the TypesSupported subkey.
  4379. dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;
  4380. if (RegSetValueEx(hk, TEXT("TypesSupported"), 0, REG_DWORD, (LPBYTE) &dwData, sizeof(DWORD)))
  4381. {
  4382. // Didn't work.
  4383. RegCloseKey(hk);
  4384. return FALSE;
  4385. }
  4386. if (ERROR_SUCCESS != RegCloseKey(hk))
  4387. {
  4388. // Couldn't close key (at least it got here though!)
  4389. return FALSE;
  4390. }
  4391. return TRUE;
  4392. }
  4393. ////////////////////////////////////////////////////////////////////////////
  4394. //
  4395. // Intl_LogEvent()
  4396. //
  4397. ////////////////////////////////////////////////////////////////////////////
  4398. BOOL Intl_LogEvent(
  4399. DWORD dwEventId, LPCTSTR szEventSource, WORD wNumStrings, LPCWSTR *lpStrings)
  4400. {
  4401. TCHAR szUserName[UNLEN+1];
  4402. PSID psidUser = NULL;
  4403. TCHAR *pszDomain = NULL;
  4404. DWORD cbSid = 0;
  4405. DWORD cbDomain = 0;
  4406. DWORD cbUser = ARRAYSIZE(szUserName);
  4407. SID_NAME_USE snu;
  4408. HANDLE hLog;
  4409. BOOL bResult = FALSE;
  4410. // Make sure our event source is registered correctly first
  4411. // (We actually don't need to do this if szEventSource isn't us, but right
  4412. // now only us is calling this, so we'll assume we're us.)
  4413. // This is redundant, we don't have to do this every time, however it doesn't
  4414. // hurt much since these events will be very rare and its a lot easier this
  4415. // way, and it has the advantage of repairing us if our registry entries were broken
  4416. //
  4417. // We ignore the error condition, because Application log is better than none!
  4418. Intl_CreateEventLog();
  4419. // register the event source, first try not having written to the registry
  4420. hLog = RegisterEventSource(NULL, szEventSource);
  4421. if (hLog == NULL)
  4422. {
  4423. // Failed
  4424. goto Exit;
  4425. }
  4426. // get the sid from the current thread token, this should be the current user who's
  4427. // running the installation
  4428. if (!GetUserName(szUserName, &cbUser))
  4429. {
  4430. // Failed
  4431. goto Exit;
  4432. }
  4433. // convert user name to its security identifier, first time to get buffer size, second time
  4434. // to actually get the Sid
  4435. if (!LookupAccountName(NULL, szUserName, NULL, &cbSid, NULL, &cbDomain, &snu))
  4436. {
  4437. // allocate the buffers
  4438. psidUser = (PSID) LocalAlloc(LPTR, cbSid);
  4439. if (NULL == psidUser)
  4440. {
  4441. goto Exit;
  4442. }
  4443. // NOTENOTE: cbDomain is in TCHAR.
  4444. pszDomain = (TCHAR*) LocalAlloc(LPTR, cbDomain * sizeof(TCHAR));
  4445. if (NULL == pszDomain)
  4446. {
  4447. goto Exit;
  4448. }
  4449. if (!LookupAccountName(NULL, szUserName, psidUser, &cbSid, pszDomain, &cbDomain, &snu))
  4450. {
  4451. goto Exit;
  4452. }
  4453. }
  4454. if (!ReportEvent(hLog,
  4455. EVENTLOG_INFORMATION_TYPE,
  4456. 0,
  4457. dwEventId,
  4458. psidUser,
  4459. wNumStrings,
  4460. 0,
  4461. lpStrings,
  4462. NULL))
  4463. {
  4464. goto Exit;
  4465. }
  4466. // If we got this far without going to, then we're true.
  4467. bResult = TRUE;
  4468. Exit:
  4469. if (NULL != hLog)
  4470. {
  4471. if (!DeregisterEventSource(hLog))
  4472. {
  4473. bResult = FALSE;
  4474. }
  4475. }
  4476. if (psidUser)
  4477. {
  4478. if (LocalFree(psidUser))
  4479. {
  4480. bResult = FALSE;
  4481. }
  4482. }
  4483. if (pszDomain)
  4484. {
  4485. if (LocalFree(pszDomain))
  4486. {
  4487. bResult = FALSE;
  4488. }
  4489. }
  4490. return bResult;
  4491. }
  4492. ////////////////////////////////////////////////////////////////////////////
  4493. //
  4494. // Intl_LoadLanguageGroups
  4495. //
  4496. ////////////////////////////////////////////////////////////////////////////
  4497. BOOL Intl_LoadLanguageGroups(
  4498. HWND hDlg)
  4499. {
  4500. LPLANGUAGEGROUP pLG;
  4501. DWORD dwExStyle;
  4502. RECT Rect;
  4503. LV_COLUMN Column;
  4504. LV_ITEM Item;
  4505. int iIndex;
  4506. //
  4507. // Open the Inf file.
  4508. //
  4509. g_hIntlInf = SetupOpenInfFile(szIntlInf, NULL, INF_STYLE_WIN4, NULL);
  4510. if (g_hIntlInf == INVALID_HANDLE_VALUE)
  4511. {
  4512. return (FALSE);
  4513. }
  4514. if (!SetupOpenAppendInfFile(NULL, g_hIntlInf, NULL))
  4515. {
  4516. SetupCloseInfFile(g_hIntlInf);
  4517. g_hIntlInf = NULL;
  4518. return (FALSE);
  4519. }
  4520. //
  4521. // Get all supported language groups from the inf file.
  4522. //
  4523. if (Intl_GetSupportedLanguageGroups() == FALSE)
  4524. {
  4525. return (FALSE);
  4526. }
  4527. //
  4528. // Close the inf file.
  4529. //
  4530. SetupCloseInfFile(g_hIntlInf);
  4531. g_hIntlInf = NULL;
  4532. //
  4533. // Enumerate all installed language groups.
  4534. //
  4535. if (Intl_EnumInstalledLanguageGroups() == FALSE)
  4536. {
  4537. return (FALSE);
  4538. }
  4539. //
  4540. // Return success.
  4541. //
  4542. return (TRUE);
  4543. }
  4544. ////////////////////////////////////////////////////////////////////////////
  4545. //
  4546. // Intl_GetSupportedLanguageGroups
  4547. //
  4548. ////////////////////////////////////////////////////////////////////////////
  4549. BOOL Intl_GetSupportedLanguageGroups()
  4550. {
  4551. UINT LanguageGroup;
  4552. HANDLE hLanguageGroup;
  4553. LPLANGUAGEGROUP pLG;
  4554. INFCONTEXT Context;
  4555. TCHAR szSection[MAX_PATH];
  4556. TCHAR szTemp[MAX_PATH];
  4557. int LineCount, LineNum;
  4558. DWORD ItemCount;
  4559. WORD wItemStatus;
  4560. //
  4561. // Get the number of supported language groups from the inf file.
  4562. //
  4563. LineCount = (UINT)SetupGetLineCount(g_hIntlInf, TEXT("LanguageGroups"));
  4564. if (LineCount <= 0)
  4565. {
  4566. return (FALSE);
  4567. }
  4568. //
  4569. // Go through all supported language groups in the inf file.
  4570. //
  4571. for (LineNum = 0; LineNum < LineCount; LineNum++)
  4572. {
  4573. if (SetupGetLineByIndex(g_hIntlInf, TEXT("LanguageGroups"), LineNum, &Context) &&
  4574. SetupGetIntField(&Context, 0, &LanguageGroup))
  4575. {
  4576. //
  4577. // Create the new node.
  4578. //
  4579. if (!(hLanguageGroup = GlobalAlloc(GHND, sizeof(LANGUAGEGROUP))))
  4580. {
  4581. return (FALSE);
  4582. }
  4583. pLG = GlobalLock(hLanguageGroup);
  4584. //
  4585. // Fill in the new node with the appropriate info.
  4586. //
  4587. pLG->wStatus = 0;
  4588. pLG->LanguageGroup = LanguageGroup;
  4589. pLG->hLanguageGroup = hLanguageGroup;
  4590. (pLG->pszName)[0] = 0;
  4591. pLG->NumLocales = 0;
  4592. pLG->NumAltSorts = 0;
  4593. //
  4594. // Set the collection
  4595. //
  4596. if ((pLG->LanguageGroup == LGRPID_JAPANESE) ||
  4597. (pLG->LanguageGroup == LGRPID_KOREAN) ||
  4598. (pLG->LanguageGroup == LGRPID_TRADITIONAL_CHINESE) ||
  4599. (pLG->LanguageGroup == LGRPID_SIMPLIFIED_CHINESE) )
  4600. {
  4601. pLG->LanguageCollection = CJK_COLLECTION;
  4602. }
  4603. else if ((pLG->LanguageGroup == LGRPID_ARABIC) ||
  4604. (pLG->LanguageGroup == LGRPID_ARMENIAN) ||
  4605. (pLG->LanguageGroup == LGRPID_GEORGIAN) ||
  4606. (pLG->LanguageGroup == LGRPID_HEBREW) ||
  4607. (pLG->LanguageGroup == LGRPID_INDIC) ||
  4608. (pLG->LanguageGroup == LGRPID_VIETNAMESE) ||
  4609. (pLG->LanguageGroup == LGRPID_THAI))
  4610. {
  4611. pLG->LanguageCollection = COMPLEX_COLLECTION;
  4612. }
  4613. else
  4614. {
  4615. pLG->LanguageCollection = BASIC_COLLECTION;
  4616. }
  4617. //
  4618. // Get the appropriate display string.
  4619. //
  4620. if (!SetupGetStringField(&Context, 1, pLG->pszName, MAX_PATH, NULL))
  4621. {
  4622. GlobalUnlock(hLanguageGroup);
  4623. GlobalFree(hLanguageGroup);
  4624. continue;
  4625. }
  4626. //
  4627. // Get the list of locales for this language group.
  4628. //
  4629. if (Intl_GetLocaleList(pLG) == FALSE)
  4630. {
  4631. return (FALSE);
  4632. }
  4633. //
  4634. // Add the language group to the front of the linked list.
  4635. //
  4636. pLG->pNext = pLanguageGroups;
  4637. pLanguageGroups = pLG;
  4638. }
  4639. }
  4640. //
  4641. // Return success.
  4642. //
  4643. return (TRUE);
  4644. }
  4645. ////////////////////////////////////////////////////////////////////////////
  4646. //
  4647. // Intl_EnumInstalledLanguageGroups
  4648. //
  4649. ////////////////////////////////////////////////////////////////////////////
  4650. BOOL Intl_EnumInstalledLanguageGroups()
  4651. {
  4652. HKEY hKey;
  4653. TCHAR szValue[MAX_PATH];
  4654. TCHAR szData[MAX_PATH];
  4655. TCHAR szDefault[SIZE_64];
  4656. DWORD dwIndex, cchValue, cbData;
  4657. LONG rc;
  4658. UINT LanguageGroup, OriginalGroup, DefaultGroup, UILanguageGroup;
  4659. LPLANGUAGEGROUP pLG;
  4660. LCID Locale;
  4661. LANGID Language;
  4662. int Ctr;
  4663. //
  4664. // Get the original install language so that we can mark that
  4665. // language group as permanent.
  4666. //
  4667. Language = GetSystemDefaultUILanguage();
  4668. if (SUBLANGID(Language) == SUBLANG_NEUTRAL)
  4669. {
  4670. Language = MAKELANGID(PRIMARYLANGID(Language), SUBLANG_DEFAULT);
  4671. }
  4672. if ((OriginalGroup = Intl_GetLanguageGroup(Language)) == 0)
  4673. {
  4674. OriginalGroup = 1;
  4675. }
  4676. //
  4677. // Get the default system locale so that we can mark that language
  4678. // group as permanent. During gui mode setup, read the system locale from
  4679. // the registry to make the info on the setup page consistent with intl.cpl.
  4680. // SysLocaleID will be the registry value in case of setup.
  4681. //
  4682. Locale = SysLocaleID;
  4683. if (Locale == (LCID)Language)
  4684. {
  4685. DefaultGroup = OriginalGroup;
  4686. }
  4687. else
  4688. {
  4689. if ((DefaultGroup = Intl_GetLanguageGroup(Locale)) == 0)
  4690. {
  4691. DefaultGroup = 1;
  4692. }
  4693. }
  4694. //
  4695. // Get the UI language's language groups to disable the user from
  4696. // un-installing them. MUISETUP makes sure that each installed UI
  4697. // language has its language group installed.
  4698. //
  4699. Intl_GetUILanguageGroups(&UILangGroup);
  4700. //
  4701. // Open the HKLM\SYSTEM\CurrentControlSet\Control\Nls\Language Groups
  4702. // key.
  4703. //
  4704. if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  4705. c_szLanguageGroups,
  4706. 0,
  4707. KEY_READ,
  4708. &hKey ) != ERROR_SUCCESS)
  4709. {
  4710. return (FALSE);
  4711. }
  4712. //
  4713. // Enumerate the values in the Language Groups key.
  4714. //
  4715. dwIndex = 0;
  4716. cchValue = sizeof(szValue) / sizeof(TCHAR);
  4717. szValue[0] = TEXT('\0');
  4718. cbData = sizeof(szData);
  4719. szData[0] = TEXT('\0');
  4720. rc = RegEnumValue( hKey,
  4721. dwIndex,
  4722. szValue,
  4723. &cchValue,
  4724. NULL,
  4725. NULL,
  4726. (LPBYTE)szData,
  4727. &cbData );
  4728. while (rc == ERROR_SUCCESS)
  4729. {
  4730. //
  4731. // If the language group contains data, then it is installed.
  4732. //
  4733. if ((szData[0] != 0) &&
  4734. (LanguageGroup = TransNum(szValue)))
  4735. {
  4736. //
  4737. // Find the language group in the linked list and mark it as
  4738. // originally installed.
  4739. //
  4740. pLG = pLanguageGroups;
  4741. while (pLG)
  4742. {
  4743. if (pLG->LanguageGroup == LanguageGroup)
  4744. {
  4745. pLG->wStatus |= ML_INSTALL;
  4746. //
  4747. // If this is a language group for a UI language that's
  4748. // installed, then disable the un-installation of this
  4749. // language group.
  4750. //
  4751. Ctr = 0;
  4752. while (Ctr < UILangGroup.iCount)
  4753. {
  4754. if (UILangGroup.lgrp[Ctr] == LanguageGroup)
  4755. {
  4756. pLG->wStatus |= ML_PERMANENT;
  4757. break;
  4758. }
  4759. Ctr++;
  4760. }
  4761. if (pLG->LanguageGroup == OriginalGroup)
  4762. {
  4763. pLG->wStatus |= ML_PERMANENT;
  4764. }
  4765. if (pLG->LanguageGroup == DefaultGroup)
  4766. {
  4767. pLG->wStatus |= (ML_PERMANENT | ML_DEFAULT);
  4768. if (LoadString(hInstance, IDS_DEFAULT, szDefault, SIZE_64))
  4769. {
  4770. //lstrcat(pLG->pszName, szDefault);
  4771. if(FAILED(StringCchCat(pLG->pszName, MAX_PATH, szDefault)))
  4772. {
  4773. // This should be impossible, but we need to avoid PREfast complaints.
  4774. RegCloseKey(hKey);
  4775. return(FALSE);
  4776. }
  4777. }
  4778. }
  4779. break;
  4780. }
  4781. pLG = pLG->pNext;
  4782. }
  4783. }
  4784. //
  4785. // Get the next enum value.
  4786. //
  4787. dwIndex++;
  4788. cchValue = sizeof(szValue) / sizeof(TCHAR);
  4789. szValue[0] = TEXT('\0');
  4790. cbData = sizeof(szData);
  4791. szData[0] = TEXT('\0');
  4792. rc = RegEnumValue( hKey,
  4793. dwIndex,
  4794. szValue,
  4795. &cchValue,
  4796. NULL,
  4797. NULL,
  4798. (LPBYTE)szData,
  4799. &cbData );
  4800. }
  4801. //
  4802. // Close the registry key handle.
  4803. //
  4804. RegCloseKey(hKey);
  4805. //
  4806. // Return success.
  4807. //
  4808. return (TRUE);
  4809. }
  4810. ////////////////////////////////////////////////////////////////////////////
  4811. //
  4812. // Intl_LanguageGroupDirExist
  4813. //
  4814. ////////////////////////////////////////////////////////////////////////////
  4815. BOOL Intl_LanguageGroupDirExist(
  4816. PTSTR pszLangDir)
  4817. {
  4818. TCHAR szLanguageGroupDir[MAX_PATH];
  4819. WIN32_FIND_DATA FindData;
  4820. HANDLE FindHandle;
  4821. TCHAR SavedChar;
  4822. //
  4823. // If it doesn't start with lang, then this is a core language.
  4824. //
  4825. SavedChar = pszLangDir[4];
  4826. pszLangDir[4] = TEXT('\0');
  4827. if (lstrcmp(pszLangDir, TEXT("lang")))
  4828. {
  4829. return (TRUE);
  4830. }
  4831. pszLangDir[4] = SavedChar;
  4832. //
  4833. // Format the path to the language group directory.
  4834. //
  4835. //lstrcpy(szLanguageGroupDir, pSetupSourcePathWithArchitecture);
  4836. //lstrcat(szLanguageGroupDir, TEXT("\\"));
  4837. //lstrcat(szLanguageGroupDir, pszLangDir);
  4838. if(FAILED(StringCchCopy(szLanguageGroupDir, MAX_PATH, pSetupSourcePathWithArchitecture)) ||
  4839. FAILED(StringCchCat(szLanguageGroupDir, MAX_PATH, TEXT("\\"))) ||
  4840. FAILED(StringCchCat(szLanguageGroupDir, MAX_PATH, pszLangDir)))
  4841. {
  4842. // This should be impossible, but we need to avoid PREfast complaints.
  4843. return(FALSE);
  4844. }
  4845. //
  4846. // See if the language group directory exists.
  4847. //
  4848. FindHandle = FindFirstFile(szLanguageGroupDir, &FindData);
  4849. if (FindHandle != INVALID_HANDLE_VALUE)
  4850. {
  4851. FindClose(FindHandle);
  4852. if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  4853. {
  4854. //
  4855. // Return success.
  4856. //
  4857. return (TRUE);
  4858. }
  4859. }
  4860. //
  4861. // Return failure.
  4862. //
  4863. return (FALSE);
  4864. }
  4865. ////////////////////////////////////////////////////////////////////////////
  4866. //
  4867. // Intl_LanguageGroupFilesExist
  4868. //
  4869. ////////////////////////////////////////////////////////////////////////////
  4870. BOOL Intl_LanguageGroupFilesExist()
  4871. {
  4872. TCHAR szLanguageGroupDir[MAX_PATH];
  4873. WIN32_FIND_DATA FindData;
  4874. HANDLE FindHandle;
  4875. //
  4876. // Format the path to the language group directory. Add the wildcard
  4877. // to search for any files located in the lang directory.
  4878. //
  4879. //lstrcpy(szLanguageGroupDir, pSetupSourcePathWithArchitecture);
  4880. //lstrcat(szLanguageGroupDir, TEXT("\\Lang\\*"));
  4881. if(FAILED(StringCchCopy(szLanguageGroupDir, MAX_PATH, pSetupSourcePathWithArchitecture)) ||
  4882. FAILED(StringCchCat(szLanguageGroupDir, MAX_PATH, TEXT("\\Lang\\*"))))
  4883. {
  4884. // This should be impossible, but we need to avoid PREfast complaints.
  4885. return(FALSE);
  4886. }
  4887. //
  4888. // See if at least one file exists.
  4889. //
  4890. FindHandle = FindFirstFile(szLanguageGroupDir, &FindData);
  4891. if (FindHandle != INVALID_HANDLE_VALUE)
  4892. {
  4893. FindClose(FindHandle);
  4894. //
  4895. // Return success.
  4896. //
  4897. return (TRUE);
  4898. }
  4899. //
  4900. // Return failure.
  4901. //
  4902. return (FALSE);
  4903. }
  4904. ////////////////////////////////////////////////////////////////////////////
  4905. //
  4906. // Intl_GetLocaleList
  4907. //
  4908. ////////////////////////////////////////////////////////////////////////////
  4909. BOOL Intl_GetLocaleList(
  4910. LPLANGUAGEGROUP pLG)
  4911. {
  4912. TCHAR szSection[MAX_PATH];
  4913. INFCONTEXT Context;
  4914. int LineCount, LineNum;
  4915. LCID Locale;
  4916. //
  4917. // Get the inf section name.
  4918. //
  4919. //wsprintf(szSection, TEXT("%ws%d"), szLocaleListPrefix, pLG->LanguageGroup);
  4920. if(FAILED(StringCchPrintf(szSection, ARRAYSIZE(szSection), TEXT("%ws%d"), szLocaleListPrefix, pLG->LanguageGroup)))
  4921. {
  4922. // This should be impossible, but we need to avoid PREfast complaints.
  4923. return(FALSE);
  4924. }
  4925. //
  4926. // Get the number of locales for the language group.
  4927. //
  4928. LineCount = (UINT)SetupGetLineCount(g_hIntlInf, szSection);
  4929. if (LineCount <= 0)
  4930. {
  4931. return (FALSE);
  4932. }
  4933. //
  4934. // Add each locale in the list to the language group node.
  4935. //
  4936. for (LineNum = 0; LineNum < LineCount; LineNum++)
  4937. {
  4938. if (SetupGetLineByIndex(g_hIntlInf, szSection, LineNum, &Context) &&
  4939. SetupGetIntField(&Context, 0, &Locale))
  4940. {
  4941. if (SORTIDFROMLCID(Locale))
  4942. {
  4943. //
  4944. // Add the locale to the alternate sort list for this
  4945. // language group.
  4946. //
  4947. if (pLG->NumAltSorts >= MAX_PATH)
  4948. {
  4949. return (FALSE);
  4950. }
  4951. pLG->pAltSortList[pLG->NumAltSorts] = Locale;
  4952. (pLG->NumAltSorts)++;
  4953. }
  4954. else
  4955. {
  4956. //
  4957. // Add the locale to the locale list for this
  4958. // language group.
  4959. //
  4960. if (pLG->NumLocales >= MAX_PATH)
  4961. {
  4962. return (FALSE);
  4963. }
  4964. pLG->pLocaleList[pLG->NumLocales] = Locale;
  4965. (pLG->NumLocales)++;
  4966. }
  4967. }
  4968. }
  4969. //
  4970. // Return success.
  4971. //
  4972. return (TRUE);
  4973. }
  4974. ////////////////////////////////////////////////////////////////////////////
  4975. //
  4976. // Region_GetLocaleLanguageGroup
  4977. //
  4978. // Reads the Language Group Id of the given language.
  4979. //
  4980. ////////////////////////////////////////////////////////////////////////////
  4981. DWORD Intl_GetLanguageGroup(
  4982. LCID lcid)
  4983. {
  4984. TCHAR szValue[MAX_PATH];
  4985. TCHAR szData[MAX_PATH];
  4986. HKEY hKey;
  4987. DWORD cbData;
  4988. //wsprintf(szValue, TEXT("%8.8x"), lcid);
  4989. if(FAILED(StringCchPrintf(szValue, ARRAYSIZE(szValue), TEXT("%8.8x"), lcid)))
  4990. {
  4991. // This should be impossible, but we need to avoid PREfast complaints.
  4992. }
  4993. szData[0] = 0;
  4994. if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  4995. c_szInstalledLocales,
  4996. 0,
  4997. KEY_READ,
  4998. &hKey ) == ERROR_SUCCESS)
  4999. {
  5000. cbData = sizeof(szData);
  5001. RegQueryValueEx(hKey, szValue, NULL, NULL, (LPBYTE)szData, &cbData);
  5002. RegCloseKey(hKey);
  5003. }
  5004. return (TransNum(szData));
  5005. }
  5006. ////////////////////////////////////////////////////////////////////////////
  5007. //
  5008. // Intl_GetUILanguageGroups
  5009. //
  5010. // Reads the language groups of all the UI languages installed on this
  5011. // machine.
  5012. //
  5013. ////////////////////////////////////////////////////////////////////////////
  5014. BOOL Intl_GetUILanguageGroups(
  5015. PUILANGUAGEGROUP pUILanguageGroup)
  5016. {
  5017. //
  5018. // Enumerate the installed UI languages.
  5019. //
  5020. pUILanguageGroup->iCount = 0L;
  5021. EnumUILanguages(Intl_EnumUILanguagesProc, 0, (LONG_PTR)pUILanguageGroup);
  5022. //
  5023. // Return success.
  5024. //
  5025. return (TRUE);
  5026. }
  5027. ////////////////////////////////////////////////////////////////////////////
  5028. //
  5029. // Intl_EnumUILanguagesProc
  5030. //
  5031. ////////////////////////////////////////////////////////////////////////////
  5032. BOOL CALLBACK Intl_EnumUILanguagesProc(
  5033. LPWSTR pwszUILanguage,
  5034. LONG_PTR lParam)
  5035. {
  5036. int Ctr = 0;
  5037. LGRPID lgrp;
  5038. PUILANGUAGEGROUP pUILangGroup = (PUILANGUAGEGROUP)lParam;
  5039. LCID UILanguage = TransNum(pwszUILanguage);
  5040. if (UILanguage)
  5041. {
  5042. if ((lgrp = Intl_GetLanguageGroup(UILanguage)) == 0)
  5043. {
  5044. lgrp = 1; // default;
  5045. }
  5046. while (Ctr < pUILangGroup->iCount)
  5047. {
  5048. if (pUILangGroup->lgrp[Ctr] == lgrp)
  5049. {
  5050. break;
  5051. }
  5052. Ctr++;
  5053. }
  5054. //
  5055. // Theoritically, we won't go over 64 language groups!
  5056. //
  5057. if ((Ctr == pUILangGroup->iCount) && (Ctr < MAX_UI_LANG_GROUPS))
  5058. {
  5059. pUILangGroup->lgrp[Ctr] = lgrp;
  5060. pUILangGroup->iCount++;
  5061. }
  5062. }
  5063. return (TRUE);
  5064. }
  5065. ////////////////////////////////////////////////////////////////////////////
  5066. //
  5067. // Intl_SaveValuesToDefault
  5068. //
  5069. // This function copies the current user settings under the srcKey to
  5070. // the Default user under the destKey.
  5071. //
  5072. ////////////////////////////////////////////////////////////////////////////
  5073. void Intl_SaveValuesToDefault(
  5074. LPCTSTR srcKey,
  5075. LPCTSTR destKey)
  5076. {
  5077. HKEY hkeyLayouts;
  5078. HKEY hkeyLayouts_DefUser;
  5079. //
  5080. // 1. Open the Current user key.
  5081. //
  5082. if (RegOpenKeyEx( HKEY_CURRENT_USER,
  5083. srcKey,
  5084. 0,
  5085. KEY_ALL_ACCESS,
  5086. &hkeyLayouts ) != ERROR_SUCCESS)
  5087. {
  5088. return;
  5089. }
  5090. //
  5091. // 2. Open the .Default hive key.
  5092. //
  5093. if (RegOpenKeyEx( HKEY_USERS,
  5094. destKey,
  5095. 0,
  5096. KEY_ALL_ACCESS,
  5097. &hkeyLayouts_DefUser ) != ERROR_SUCCESS)
  5098. {
  5099. RegCloseKey(hkeyLayouts);
  5100. return;
  5101. }
  5102. //
  5103. // 3. Delete .Default key values.
  5104. //
  5105. Intl_DeleteRegKeyValues(hkeyLayouts_DefUser);
  5106. //
  5107. // 4. Delete .Default subkeys.
  5108. //
  5109. Intl_DeleteRegSubKeys(hkeyLayouts_DefUser);
  5110. //
  5111. // 5. Copy tree.
  5112. //
  5113. Intl_CreateRegTree(hkeyLayouts, hkeyLayouts_DefUser);
  5114. //
  5115. // 6. Clean up
  5116. //
  5117. RegCloseKey(hkeyLayouts_DefUser);
  5118. RegCloseKey(hkeyLayouts);
  5119. }
  5120. ////////////////////////////////////////////////////////////////////////////
  5121. //
  5122. // Intl_SaveValuesToNtUserFile
  5123. //
  5124. // This function copy current user setting under the srcKey to the Default
  5125. // user hive under the destKey.
  5126. //
  5127. ////////////////////////////////////////////////////////////////////////////
  5128. void Intl_SaveValuesToNtUserFile(
  5129. HKEY hSourceRegKey,
  5130. LPCTSTR srcKey,
  5131. LPCTSTR destKey)
  5132. {
  5133. HKEY hRegKey;
  5134. HKEY hHive;
  5135. BOOLEAN wasEnabled;
  5136. //
  5137. // 1. Open the Current user key.
  5138. //
  5139. if (RegOpenKeyEx( hSourceRegKey,
  5140. srcKey,
  5141. 0,
  5142. KEY_READ,
  5143. &hRegKey ) != ERROR_SUCCESS)
  5144. {
  5145. return;
  5146. }
  5147. //
  5148. // 2. Load the hive to a temporary key location.
  5149. //
  5150. if ((hHive = Intl_LoadNtUserHive( TEXT("TempKey"),
  5151. destKey,
  5152. NULL,
  5153. &wasEnabled )) == NULL)
  5154. {
  5155. RegCloseKey(hRegKey);
  5156. return;
  5157. }
  5158. //
  5159. // 3. Delete .Default key values.
  5160. //
  5161. Intl_DeleteRegKeyValues(hHive);
  5162. //
  5163. // 4. Delete .Default subkeys.
  5164. //
  5165. Intl_DeleteRegSubKeys(hHive);
  5166. //
  5167. // 5. Copy tree.
  5168. //
  5169. Intl_CreateRegTree(hRegKey, hHive);
  5170. //
  5171. // 6. Clean up.
  5172. //
  5173. RegCloseKey(hHive);
  5174. Intl_UnloadNtUserHive(TEXT("TempKey"), &wasEnabled);
  5175. RegCloseKey(hRegKey);
  5176. }
  5177. ////////////////////////////////////////////////////////////////////////////
  5178. //
  5179. // Intl_IsSetupMode
  5180. //
  5181. // Look into the registry if we are currently in setup mode.
  5182. //
  5183. // Return Values:
  5184. //
  5185. // 0 == not in setup
  5186. // 1 == setup
  5187. // 2 == minisetup
  5188. //
  5189. ////////////////////////////////////////////////////////////////////////////
  5190. int Intl_IsSetupMode()
  5191. {
  5192. HKEY hKey;
  5193. DWORD fSystemSetupInProgress = 0;
  5194. DWORD cbData = 0;
  5195. //
  5196. // Open the registry key used by setup
  5197. //
  5198. if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  5199. c_szSetupKey,
  5200. 0,
  5201. KEY_READ,
  5202. &hKey ) == ERROR_SUCCESS)
  5203. {
  5204. //
  5205. // Query for the value indicating that we are in setup.
  5206. //
  5207. // SystemSetupInProgress == 1 means we are in system setup
  5208. // or minisetup.
  5209. //
  5210. cbData = sizeof(fSystemSetupInProgress);
  5211. RegQueryValueEx( hKey,
  5212. szSetupInProgress,
  5213. NULL,
  5214. NULL,
  5215. (LPBYTE)&fSystemSetupInProgress,
  5216. &cbData );
  5217. if(1 == fSystemSetupInProgress)
  5218. {
  5219. //
  5220. // We are in setup or in minisetup. Lets find out which one.
  5221. // Query for the value indicating that we are in mini setup.
  5222. //
  5223. // MiniSetupInProgress == 1 means we are in mini setup
  5224. //
  5225. fSystemSetupInProgress = 0;
  5226. cbData = sizeof(fSystemSetupInProgress);
  5227. RegQueryValueEx( hKey,
  5228. szMiniSetupInProgress,
  5229. NULL,
  5230. NULL,
  5231. (LPBYTE)&fSystemSetupInProgress,
  5232. &cbData );
  5233. if(1 == fSystemSetupInProgress)
  5234. {
  5235. //
  5236. // In minisetup, so set the return value to 2
  5237. //
  5238. fSystemSetupInProgress = 2;
  5239. }
  5240. else
  5241. {
  5242. //
  5243. // We are just in regular setup
  5244. //
  5245. fSystemSetupInProgress = 1;
  5246. }
  5247. }
  5248. //
  5249. // Clean up
  5250. //
  5251. RegCloseKey(hKey);
  5252. //
  5253. // Check the value
  5254. //
  5255. if (0 != fSystemSetupInProgress)
  5256. {
  5257. //
  5258. // In setup mode...
  5259. //
  5260. if (g_bLog)
  5261. {
  5262. Intl_LogSimpleMessage(IDS_LOG_SETUP_MODE, NULL);
  5263. }
  5264. }
  5265. }
  5266. return ((int)fSystemSetupInProgress);
  5267. }
  5268. ////////////////////////////////////////////////////////////////////////////
  5269. //
  5270. // Intl_IsWinntUpgrade
  5271. //
  5272. // Look into the registry if we are currently in winnt upgrade.
  5273. //
  5274. ////////////////////////////////////////////////////////////////////////////
  5275. BOOL Intl_IsWinntUpgrade()
  5276. {
  5277. HKEY hKey;
  5278. DWORD fUpgradeInProgress = 0;
  5279. DWORD cbData = 0;
  5280. //
  5281. // Verify that we're in setup first.
  5282. //
  5283. if (!g_bSetupCase)
  5284. {
  5285. return (FALSE);
  5286. }
  5287. //
  5288. // Open the registry key used by setup.
  5289. //
  5290. if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  5291. c_szSetupKey,
  5292. 0,
  5293. KEY_READ,
  5294. &hKey ) != ERROR_SUCCESS)
  5295. {
  5296. return (FALSE);
  5297. }
  5298. //
  5299. // Query for the value indicating that we are in setup.
  5300. //
  5301. cbData = sizeof(fUpgradeInProgress);
  5302. if (RegQueryValueEx( hKey,
  5303. szSetupUpgrade,
  5304. NULL,
  5305. NULL,
  5306. (LPBYTE)&fUpgradeInProgress,
  5307. &cbData ) != ERROR_SUCCESS)
  5308. {
  5309. RegCloseKey(hKey);
  5310. return (FALSE);
  5311. }
  5312. //
  5313. // Clean up.
  5314. //
  5315. RegCloseKey(hKey);
  5316. //
  5317. // Check the value.
  5318. //
  5319. if (fUpgradeInProgress)
  5320. {
  5321. //
  5322. // Upgrade scenario.
  5323. //
  5324. if (g_bLog)
  5325. {
  5326. Intl_LogSimpleMessage(IDS_LOG_UPGRADE_SCENARIO, NULL);
  5327. }
  5328. return (TRUE);
  5329. }
  5330. return (FALSE);
  5331. }
  5332. ////////////////////////////////////////////////////////////////////////////
  5333. //
  5334. // Intl_IsUIFontSubstitute
  5335. //
  5336. // Look into the registry if we need to substitute the font.
  5337. //
  5338. ////////////////////////////////////////////////////////////////////////////
  5339. BOOL Intl_IsUIFontSubstitute()
  5340. {
  5341. HKEY hKey;
  5342. DWORD fUIFontSubstitute = 0;
  5343. DWORD cbData = 0;
  5344. //
  5345. // Command line call, no need to check registry
  5346. //
  5347. if (g_bMatchUIFont)
  5348. {
  5349. return (TRUE);
  5350. }
  5351. //
  5352. // Open the registry key used MUI font substitution.
  5353. //
  5354. if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  5355. c_szMUILanguages,
  5356. 0,
  5357. KEY_READ,
  5358. &hKey ) != ERROR_SUCCESS)
  5359. {
  5360. return (FALSE);
  5361. }
  5362. //
  5363. // Query for the value indicating that we need to apply font
  5364. // substitution.
  5365. //
  5366. cbData = sizeof(fUIFontSubstitute);
  5367. if (RegQueryValueEx( hKey,
  5368. szUIFontSubstitute,
  5369. NULL,
  5370. NULL,
  5371. (LPBYTE)&fUIFontSubstitute,
  5372. &cbData ) != ERROR_SUCCESS)
  5373. {
  5374. RegCloseKey(hKey);
  5375. return (FALSE);
  5376. }
  5377. //
  5378. // Clean up.
  5379. //
  5380. RegCloseKey(hKey);
  5381. //
  5382. // Check the value.
  5383. //
  5384. if (fUIFontSubstitute)
  5385. {
  5386. //
  5387. // Upgrade scenario.
  5388. //
  5389. if (g_bLog)
  5390. {
  5391. Intl_LogSimpleMessage(IDS_LOG_FONT_SUBSTITUTE, NULL);
  5392. }
  5393. return (TRUE);
  5394. }
  5395. return (FALSE);
  5396. }
  5397. ////////////////////////////////////////////////////////////////////////////
  5398. //
  5399. // Intl_ApplyFontSubstitute
  5400. //
  5401. // Search into the intl.inf file to see of the SystemLocale need font
  5402. // substitution.
  5403. //
  5404. // Some MUI languages require shell font to match localized fonts,
  5405. // so we have to update following corresponding registry values
  5406. // HKLM\Software\Microsoft\Windows NT\CurrentVersion\FontSubstitutes
  5407. // HKLM\Software\Microsoft\Windows NT\CurrentVersion\GRE_Initialize
  5408. // Values are read from intl.inf [FontSubstitute] section
  5409. //
  5410. // When locales are switch out of those specific languages or font match is disabled,
  5411. // font.inf and us intl.inf will restore previous values
  5412. //
  5413. ////////////////////////////////////////////////////////////////////////////
  5414. VOID Intl_ApplyFontSubstitute(LCID SystemLocale)
  5415. {
  5416. HINF hIntlInf;
  5417. TCHAR szLCID[25];
  5418. INFCONTEXT Context;
  5419. TCHAR szFont[MAX_PATH] = {0};
  5420. TCHAR szFontSubst[MAX_PATH] = {0};
  5421. TCHAR szGreFontHeight[MAX_PATH] = {0};
  5422. TCHAR szGreFontHeightValue[MAX_PATH] = {0};
  5423. DWORD dwFontHeight;
  5424. HKEY hKey;
  5425. //
  5426. // Open the Intl.inf file.
  5427. //
  5428. if (Intl_OpenIntlInfFile(&hIntlInf))
  5429. {
  5430. //
  5431. // Get the locale.
  5432. //
  5433. //wsprintf(szLCID, TEXT("%08x"), SystemLocale);
  5434. if(FAILED(StringCchPrintf(szLCID, ARRAYSIZE(szLCID), TEXT("%08x"), SystemLocale)))
  5435. {
  5436. // This should be impossible, but we need to avoid PREfast complaints.
  5437. }
  5438. //
  5439. // Look for the Font Substitute section.
  5440. //
  5441. if (SetupFindFirstLine( hIntlInf,
  5442. szFontSubstitute,
  5443. szLCID,
  5444. &Context ))
  5445. {
  5446. //
  5447. // Look for the font substitute and height infomation
  5448. //
  5449. if (!SetupGetStringField( &Context,
  5450. 1,
  5451. szFont,
  5452. MAX_PATH,
  5453. NULL ) ||
  5454. !SetupGetStringField( &Context,
  5455. 2,
  5456. szFontSubst,
  5457. MAX_PATH,
  5458. NULL ) ||
  5459. !SetupGetStringField( &Context,
  5460. 3,
  5461. szGreFontHeight,
  5462. MAX_PATH,
  5463. NULL ) ||
  5464. !SetupGetStringField( &Context,
  5465. 4,
  5466. szGreFontHeightValue,
  5467. MAX_PATH,
  5468. NULL ))
  5469. {
  5470. //
  5471. // Clean up.
  5472. //
  5473. Intl_CloseInfFile(hIntlInf);
  5474. return;
  5475. }
  5476. dwFontHeight = StrToInt(szGreFontHeightValue);
  5477. }
  5478. else
  5479. {
  5480. //
  5481. // Nothing to do for this specific locale. Clean up.
  5482. //
  5483. Intl_CloseInfFile(hIntlInf);
  5484. return;
  5485. }
  5486. }
  5487. else
  5488. {
  5489. return;
  5490. }
  5491. //
  5492. // Close the Intl.inf file
  5493. //
  5494. Intl_CloseInfFile(hIntlInf);
  5495. //
  5496. // Proceed with the font replacement.
  5497. //
  5498. if (szFont[0] && szFontSubst[0])
  5499. {
  5500. //
  5501. // Open the Font Substitute registry key.
  5502. //
  5503. if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  5504. c_szFontSubstitute,
  5505. 0L,
  5506. KEY_READ | KEY_WRITE,
  5507. &hKey ) == ERROR_SUCCESS)
  5508. {
  5509. //
  5510. // Set the Font value with the Font Substitute.
  5511. //
  5512. RegSetValueEx( hKey,
  5513. szFont,
  5514. 0L,
  5515. REG_SZ,
  5516. (LPBYTE)szFontSubst,
  5517. (lstrlen(szFontSubst) + 1) * sizeof(TCHAR) );
  5518. RegCloseKey(hKey);
  5519. }
  5520. if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  5521. c_szGreFontInitialize,
  5522. 0L,
  5523. KEY_READ | KEY_WRITE,
  5524. &hKey ) == ERROR_SUCCESS)
  5525. {
  5526. //
  5527. // Set the GRE_Initialize font height value.
  5528. //
  5529. RegSetValueEx( hKey,
  5530. szGreFontHeight,
  5531. 0L,
  5532. REG_DWORD,
  5533. (LPBYTE)&dwFontHeight,
  5534. sizeof(dwFontHeight));
  5535. RegCloseKey(hKey);
  5536. }
  5537. }
  5538. }
  5539. ////////////////////////////////////////////////////////////////////////////
  5540. //
  5541. // Intl_OpenLogFile
  5542. //
  5543. // Opens the Region and Languages Options log for writing.
  5544. //
  5545. ////////////////////////////////////////////////////////////////////////////
  5546. HANDLE Intl_OpenLogFile()
  5547. {
  5548. DWORD dwSize;
  5549. DWORD dwUnicodeHeader;
  5550. HANDLE hFile;
  5551. SECURITY_ATTRIBUTES SecurityAttributes;
  5552. TCHAR lpPath[MAX_PATH];
  5553. if(0 == GetWindowsDirectory(lpPath, MAX_PATH))
  5554. {
  5555. // SECURITY: Make sure we null out lpPath
  5556. lpPath[0] = TEXT('\0');
  5557. }
  5558. PathAppend(lpPath, TEXT("\\regopt.log"));
  5559. SecurityAttributes.nLength = sizeof(SecurityAttributes);
  5560. SecurityAttributes.lpSecurityDescriptor = NULL;
  5561. SecurityAttributes.bInheritHandle = FALSE;
  5562. hFile = CreateFile( lpPath,
  5563. GENERIC_WRITE,
  5564. 0,
  5565. &SecurityAttributes,
  5566. OPEN_ALWAYS,
  5567. FILE_ATTRIBUTE_NORMAL,
  5568. NULL );
  5569. #ifdef UNICODE
  5570. //
  5571. // If the file did not already exist, add the unicode header.
  5572. //
  5573. if (GetLastError() == 0)
  5574. {
  5575. dwUnicodeHeader = 0xFEFF;
  5576. WriteFile(hFile, &dwUnicodeHeader, 2, &dwSize, NULL);
  5577. }
  5578. #endif
  5579. return (hFile);
  5580. }
  5581. ////////////////////////////////////////////////////////////////////////////
  5582. //
  5583. // Intl_LogMessage
  5584. //
  5585. // Writes lpMessage to the Region and Languages Options log.
  5586. //
  5587. ////////////////////////////////////////////////////////////////////////////
  5588. BOOL Intl_LogMessage(
  5589. LPCTSTR lpMessage)
  5590. {
  5591. DWORD dwBytesWritten;
  5592. HANDLE hFile;
  5593. if (!g_bLog)
  5594. {
  5595. return (FALSE);
  5596. }
  5597. if (lpMessage == NULL)
  5598. {
  5599. return (TRUE);
  5600. }
  5601. hFile = Intl_OpenLogFile();
  5602. if (hFile == INVALID_HANDLE_VALUE)
  5603. {
  5604. return (FALSE);
  5605. }
  5606. SetFilePointer(hFile, 0, NULL, FILE_END);
  5607. WriteFile( hFile,
  5608. lpMessage,
  5609. _tcslen(lpMessage) * sizeof(TCHAR),
  5610. &dwBytesWritten,
  5611. NULL );
  5612. SetFilePointer(hFile, 0, NULL, FILE_END);
  5613. WriteFile( hFile,
  5614. TEXT("\r\n"),
  5615. _tcslen(TEXT("\r\n")) * sizeof(TCHAR),
  5616. &dwBytesWritten,
  5617. NULL );
  5618. CloseHandle(hFile);
  5619. return (TRUE);
  5620. }
  5621. ////////////////////////////////////////////////////////////////////////////
  5622. //
  5623. // Intl_LogUnattendFile
  5624. //
  5625. // Writes the unattended mode file to the setup log.
  5626. //
  5627. ////////////////////////////////////////////////////////////////////////////
  5628. void Intl_LogUnattendFile(
  5629. LPCTSTR pFileName)
  5630. {
  5631. DWORD dwSize;
  5632. HANDLE hFile;
  5633. OFSTRUCT fileInfo;
  5634. BOOL bResult;
  5635. CHAR inBuffer[MAX_PATH] = {0};
  5636. DWORD nBytesRead;
  5637. WCHAR outBufferW[MAX_PATH] = {0};
  5638. int nWCharRead;
  5639. DWORD status;
  5640. //
  5641. // Open the unattended mode file.
  5642. //
  5643. if ((hFile = CreateFile( pFileName,
  5644. GENERIC_READ,
  5645. 0,
  5646. NULL,
  5647. OPEN_EXISTING,
  5648. FILE_ATTRIBUTE_NORMAL,
  5649. NULL )) == INVALID_HANDLE_VALUE)
  5650. {
  5651. return;
  5652. }
  5653. //
  5654. // Write the header.
  5655. //
  5656. Intl_LogSimpleMessage(IDS_LOG_UNAT_HEADER, NULL);
  5657. //
  5658. // Read the unattended mode file in 259 byte chunks.
  5659. //
  5660. while (bResult = ReadFile( hFile,
  5661. (LPVOID)inBuffer,
  5662. MAX_PATH - 1,
  5663. &nBytesRead,
  5664. NULL ) && (nBytesRead > 0))
  5665. {
  5666. //
  5667. // Null terminated string.
  5668. //
  5669. inBuffer[nBytesRead] = '\0';
  5670. //
  5671. // Convert the ansi data to unicode.
  5672. //
  5673. nWCharRead = MultiByteToWideChar( CP_ACP,
  5674. MB_PRECOMPOSED,
  5675. inBuffer,
  5676. nBytesRead,
  5677. outBufferW,
  5678. MAX_PATH );
  5679. //
  5680. // Write to the log file.
  5681. //
  5682. if (nWCharRead)
  5683. {
  5684. Intl_LogMessage((LPCTSTR)outBufferW);
  5685. }
  5686. }
  5687. //
  5688. // Write the footer.
  5689. //
  5690. Intl_LogSimpleMessage(IDS_LOG_UNAT_FOOTER, NULL);
  5691. //
  5692. // Cleanup.
  5693. //
  5694. CloseHandle(hFile);
  5695. }
  5696. ////////////////////////////////////////////////////////////////////////////
  5697. //
  5698. // Intl_LogSimpleMessage
  5699. //
  5700. // Writes a simple message to the log file.
  5701. //
  5702. ////////////////////////////////////////////////////////////////////////////
  5703. void Intl_LogSimpleMessage(
  5704. UINT LogId,
  5705. LPCTSTR pAppend)
  5706. {
  5707. TCHAR szLogBuffer[4 * MAX_PATH];
  5708. int cchLogBuffer = ARRAYSIZE(szLogBuffer);
  5709. LoadString(hInstance, LogId, szLogBuffer, cchLogBuffer - 1);
  5710. if (pAppend)
  5711. {
  5712. // _tcscat(szLogBuffer, pAppend);
  5713. if(FAILED(StringCchCatW(szLogBuffer, cchLogBuffer, pAppend)))
  5714. {
  5715. // This should be impossible, but we need to avoid PREfast complaints.
  5716. }
  5717. }
  5718. Intl_LogMessage(szLogBuffer);
  5719. }
  5720. ////////////////////////////////////////////////////////////////////////////
  5721. //
  5722. // Intl_LogFormatMessage
  5723. //
  5724. // Writes an error message using FormatMessage to the log file.
  5725. //
  5726. ////////////////////////////////////////////////////////////////////////////
  5727. void Intl_LogFormatMessage(
  5728. UINT LogId)
  5729. {
  5730. LPVOID lpMsgBuf = NULL;
  5731. TCHAR szLogBuffer[4 * MAX_PATH];
  5732. int cchLogBuffer = ARRAYSIZE(szLogBuffer);
  5733. //
  5734. // Load the log message.
  5735. //
  5736. LoadString( hInstance,
  5737. LogId,
  5738. szLogBuffer,
  5739. cchLogBuffer - 1 );
  5740. //
  5741. // Get the message for the last error.
  5742. //
  5743. if(0 < FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER |
  5744. FORMAT_MESSAGE_FROM_SYSTEM |
  5745. FORMAT_MESSAGE_IGNORE_INSERTS,
  5746. NULL,
  5747. GetLastError(),
  5748. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  5749. (LPTSTR) &lpMsgBuf,
  5750. 0,
  5751. NULL ))
  5752. {
  5753. //
  5754. // Concatenate the log message and the last error.
  5755. //
  5756. // _tcscat(szLogBuffer, lpMsgBuf);
  5757. if(FAILED(StringCchCatW(szLogBuffer, ARRAYSIZE(szLogBuffer), lpMsgBuf)))
  5758. {
  5759. // This should be impossible, but we need to avoid PREfast complaints.
  5760. }
  5761. //
  5762. // Free the buffer created by FormatMessage.
  5763. //
  5764. LocalFree(lpMsgBuf);
  5765. }
  5766. else
  5767. {
  5768. // CONSIDER: FormatMessage failed (probably a LocalAlloc failure).
  5769. // Maybe we should append the error code, at least?
  5770. }
  5771. //
  5772. // Log the message to the log file.
  5773. //
  5774. Intl_LogMessage(szLogBuffer);
  5775. }
  5776. ////////////////////////////////////////////////////////////////////////////
  5777. //
  5778. // Intl_SaveDefaultUserSettings
  5779. //
  5780. // This function will get information from the the current user and write it in
  5781. // the .DEFAULT and NTUSER.DAT file.
  5782. //
  5783. ////////////////////////////////////////////////////////////////////////////
  5784. void Intl_SaveDefaultUserSettings()
  5785. {
  5786. //
  5787. // Check if the Default user settings have been saved already.
  5788. //
  5789. if (g_bSettingsChanged)
  5790. {
  5791. DWORD dwDisposition;
  5792. HKEY hDesKey, hSrcKey;
  5793. //
  5794. // Set the UI Language for ALL new users of this machine.
  5795. //
  5796. Intl_ChangeUILangForAllUsers(Intl_GetPendingUILanguage());
  5797. //
  5798. // Copy the International keys and subkeys.
  5799. //
  5800. Intl_SaveValuesToDefault(c_szCPanelIntl, c_szCPanelIntl_DefUser);
  5801. Intl_SaveValuesToNtUserFile(HKEY_CURRENT_USER, c_szCPanelIntl, c_szCPanelIntl);
  5802. //
  5803. // Copy only the CTFMON information.
  5804. //
  5805. if(RegOpenKeyEx( HKEY_CURRENT_USER,
  5806. c_szCtfmon,
  5807. 0,
  5808. KEY_ALL_ACCESS,
  5809. &hSrcKey) == ERROR_SUCCESS)
  5810. {
  5811. if(RegOpenKeyEx( HKEY_USERS,
  5812. c_szCtfmon_DefUser,
  5813. 0,
  5814. KEY_ALL_ACCESS,
  5815. &hDesKey) == ERROR_SUCCESS)
  5816. {
  5817. DWORD dwValueLength, dwType;
  5818. TCHAR szValue[REGSTR_MAX_VALUE_LENGTH];
  5819. //
  5820. // Get the source value if exist.
  5821. //
  5822. szValue[0] = 0;
  5823. dwValueLength = sizeof(szValue);
  5824. if(RegQueryValueEx( hSrcKey,
  5825. szCtfmonValue,
  5826. NULL,
  5827. &dwType,
  5828. (LPBYTE)szValue,
  5829. &dwValueLength) == ERROR_SUCCESS)
  5830. {
  5831. //
  5832. // Set the destination value.
  5833. //
  5834. RegSetValueEx( hDesKey,
  5835. szCtfmonValue,
  5836. 0L,
  5837. dwType,
  5838. (CONST BYTE *)szValue,
  5839. dwValueLength);
  5840. }
  5841. CloseHandle(hDesKey);
  5842. }
  5843. CloseHandle(hSrcKey);
  5844. }
  5845. Intl_SaveValuesToNtUserFile(HKEY_CURRENT_USER, c_szCtfmon, c_szCtfmon);
  5846. //
  5847. // Copy the Keyboard Layouts keys and subkeys.
  5848. //
  5849. Intl_SaveValuesToDefault(c_szKbdLayouts, c_szKbdLayouts_DefUser);
  5850. Intl_SaveValuesToNtUserFile(HKEY_CURRENT_USER, c_szKbdLayouts, c_szKbdLayouts);
  5851. //
  5852. // Copy the Input Method keys and subkeys.
  5853. //
  5854. Intl_SaveValuesToDefault(c_szInputMethod, c_szInputMethod_DefUser);
  5855. Intl_SaveValuesToNtUserFile(HKEY_CURRENT_USER, c_szInputMethod, c_szInputMethod);
  5856. //
  5857. // Copy the Tips keys and subkeys. Make sure that the CTF
  5858. // destination key exist.
  5859. //
  5860. if (RegCreateKeyEx( HKEY_USERS,
  5861. c_szInputTips_DefUser,
  5862. 0,
  5863. NULL,
  5864. REG_OPTION_NON_VOLATILE,
  5865. KEY_ALL_ACCESS,
  5866. NULL,
  5867. &hDesKey,
  5868. &dwDisposition ) == ERROR_SUCCESS)
  5869. {
  5870. CloseHandle(hDesKey);
  5871. Intl_SaveValuesToDefault(c_szInputTips, c_szInputTips_DefUser);
  5872. Intl_SaveValuesToNtUserFile(HKEY_CURRENT_USER, c_szInputTips, c_szInputTips);
  5873. }
  5874. //
  5875. // Settings saved.
  5876. //
  5877. g_bSettingsChanged = FALSE;
  5878. }
  5879. }
  5880. ////////////////////////////////////////////////////////////////////////////
  5881. //
  5882. // Intl_SaveDefaultUserInputSettings
  5883. //
  5884. // This function copy .Default user input-related setting to ntuser.dat.
  5885. // There are four things to copy to make keyboard layout work for
  5886. // new users:
  5887. // * "Software\\Microsoft\\Windows\\CurrentVersion\\Run\\ctfmon.exe" (if any)
  5888. // * "Keyboard Layout"
  5889. // * "Control Panel\\Input Method"
  5890. // * "Software\\Microsoft\\CTF" (if any)
  5891. //
  5892. ////////////////////////////////////////////////////////////////////////////
  5893. BOOL Intl_SaveDefaultUserInputSettings()
  5894. {
  5895. HKEY hDesKey;
  5896. DWORD dwDisposition;
  5897. //
  5898. // The following call will copy everything under Windows\CurrentVersion\Run
  5899. // to ntuser.dat.
  5900. //
  5901. Intl_SaveValuesToNtUserFile(HKEY_USERS, c_szCtfmon_DefUser, c_szCtfmon);
  5902. //
  5903. // Copy the Keyboard Layouts keys and subkeys.
  5904. //
  5905. Intl_SaveValuesToNtUserFile(HKEY_USERS, c_szKbdLayouts_DefUser, c_szKbdLayouts);
  5906. //
  5907. // Copy the Input Method keys and subkeys.
  5908. //
  5909. Intl_SaveValuesToNtUserFile(HKEY_USERS, c_szInputMethod_DefUser, c_szInputMethod);
  5910. //
  5911. // Copy the Tips keys and subkeys. Make sure that the CTF
  5912. // destination key exist.
  5913. //
  5914. if (RegCreateKeyEx( HKEY_USERS,
  5915. c_szInputTips_DefUser,
  5916. 0,
  5917. NULL,
  5918. REG_OPTION_NON_VOLATILE,
  5919. KEY_READ,
  5920. NULL,
  5921. &hDesKey,
  5922. &dwDisposition ) == ERROR_SUCCESS)
  5923. {
  5924. CloseHandle(hDesKey);
  5925. Intl_SaveValuesToNtUserFile(HKEY_USERS, c_szInputTips_DefUser, c_szInputTips);
  5926. }
  5927. return (TRUE);
  5928. }
  5929. ////////////////////////////////////////////////////////////////////////////
  5930. //
  5931. // Intl_IsMUIFileVersionSameAsOS
  5932. //
  5933. ////////////////////////////////////////////////////////////////////////////
  5934. #define MUISETUP_EXE_RELATIVE_PATH TEXT("mui\\muisetup.exe")
  5935. #define MUISETUP_INF_RELATIVE_PATH TEXT("mui\\mui.inf")
  5936. BOOL Intl_IsMUISetupVersionSameAsOS()
  5937. {
  5938. BOOL bSpUpgrade = FALSE;
  5939. DWORD dwDummy = 0;
  5940. DWORD dwBufSize = 0;
  5941. UINT uiLen = 0;
  5942. BYTE *pbBuffer = NULL;
  5943. VS_FIXEDFILEINFO *pvsFileInfo;
  5944. BOOL bResult = TRUE;
  5945. TCHAR tempmsg[MAX_PATH];
  5946. TCHAR build[MAX_PATH];
  5947. TCHAR szAppPath[MAX_PATH];
  5948. TCHAR szInfPath[MAX_PATH];
  5949. HRESULT hr = S_OK;
  5950. GetSystemWindowsDirectory(szAppPath, ARRAYSIZE(szAppPath));
  5951. GetSystemWindowsDirectory(szInfPath, ARRAYSIZE(szInfPath));
  5952. //
  5953. // Invoke muisetup to uninstall MUI languages.
  5954. //
  5955. if ((PathAppend(szAppPath, MUISETUP_EXE_RELATIVE_PATH) && Intl_FileExists(szAppPath)) &&
  5956. (PathAppend(szInfPath, MUISETUP_INF_RELATIVE_PATH) && Intl_FileExists(szInfPath)))
  5957. {
  5958. dwBufSize = GetFileVersionInfoSize(szAppPath, &dwDummy);
  5959. if (dwBufSize > 0)
  5960. {
  5961. // allocate enough buffer to store the file version info
  5962. pbBuffer = (BYTE*) LocalAlloc(LPTR, dwBufSize+1);
  5963. if (NULL == pbBuffer)
  5964. {
  5965. goto Exit;
  5966. }
  5967. else
  5968. {
  5969. // Get the file version info
  5970. if (!GetFileVersionInfo(szAppPath, dwDummy, dwBufSize, pbBuffer))
  5971. {
  5972. goto Exit;
  5973. }
  5974. else
  5975. {
  5976. // get the version from the file version info using VerQueryValue
  5977. if (!VerQueryValue(pbBuffer, TEXT("\\"), (LPVOID *) &pvsFileInfo, &uiLen))
  5978. {
  5979. goto Exit;
  5980. }
  5981. }
  5982. }
  5983. }
  5984. else
  5985. {
  5986. goto Exit;
  5987. }
  5988. // read the mui.inf version from mui.inf
  5989. GetPrivateProfileString( TEXT("Buildnumber"),
  5990. NULL,
  5991. TEXT("0"),
  5992. tempmsg,
  5993. ARRAYSIZE(tempmsg),
  5994. szInfPath);
  5995. //wsprintf(build, TEXT("%d"), HIWORD(pvsFileInfo->dwFileVersionLS));
  5996. hr = StringCchPrintf(build, ARRAYSIZE(build), TEXT("%d"), HIWORD(pvsFileInfo->dwFileVersionLS));
  5997. if (_tcscmp(tempmsg, build))
  5998. {
  5999. bSpUpgrade = FALSE;
  6000. }
  6001. else
  6002. {
  6003. bSpUpgrade = TRUE;
  6004. }
  6005. }
  6006. Exit:
  6007. if (pbBuffer)
  6008. {
  6009. LocalFree(pbBuffer);
  6010. }
  6011. return bSpUpgrade;
  6012. }
  6013. ////////////////////////////////////////////////////////////////////////////
  6014. //
  6015. // Intl_IsLIP
  6016. //
  6017. ////////////////////////////////////////////////////////////////////////////
  6018. BOOL Intl_IsLIP()
  6019. {
  6020. BOOL bResult = TRUE;
  6021. UINT iLangCount = 0;
  6022. HKEY hKey;
  6023. TCHAR szValue[MAX_PATH];
  6024. TCHAR szData[MAX_PATH];
  6025. DWORD dwIndex, cchValue, cbData;
  6026. DWORD UILang;
  6027. DWORD dwType;
  6028. LONG rc;
  6029. //
  6030. // First check for the LIP System Key, if it is there, then we are done
  6031. //
  6032. if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  6033. c_szLIPInstalled,
  6034. 0,
  6035. KEY_READ,
  6036. &hKey ) == ERROR_SUCCESS)
  6037. {
  6038. RegCloseKey(hKey);
  6039. return (TRUE);
  6040. }
  6041. //
  6042. // if not found, then open the registry key used MUI to doublecheck
  6043. // for LIP enabled system
  6044. //
  6045. if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  6046. c_szMUILanguages,
  6047. 0,
  6048. KEY_READ,
  6049. &hKey ) != ERROR_SUCCESS)
  6050. {
  6051. return (FALSE);
  6052. }
  6053. //
  6054. // Enumerate the values in the MUILanguages key.
  6055. //
  6056. dwIndex = 0;
  6057. cchValue = sizeof(szValue) / sizeof(TCHAR);
  6058. szValue[0] = TEXT('\0');
  6059. cbData = sizeof(szData);
  6060. szData[0] = TEXT('\0');
  6061. rc = RegEnumValue( hKey,
  6062. dwIndex,
  6063. szValue,
  6064. &cchValue,
  6065. NULL,
  6066. &dwType,
  6067. (LPBYTE)szData,
  6068. &cbData );
  6069. while (rc == ERROR_SUCCESS)
  6070. {
  6071. //
  6072. // If the UI language contains data, then it is installed.
  6073. //
  6074. if ((szData[0] != 0) &&
  6075. (dwType == REG_SZ) &&
  6076. (UILang = TransNum(szValue)) &&
  6077. (GetLocaleInfo(UILang, LOCALE_SNATIVELANGNAME, szData, MAX_PATH)) &&
  6078. (IsValidUILanguage((LANGID)UILang)))
  6079. {
  6080. //
  6081. // if English 0409 key is found, we have a MUI system and not LIP
  6082. //
  6083. if (UILang == 0x0409)
  6084. {
  6085. bResult = FALSE;
  6086. break;
  6087. }
  6088. //
  6089. // If there are more than one language installed, or then it is
  6090. // also not a LIP system - this can be 0409 + any other language also.
  6091. //
  6092. iLangCount= iLangCount + 1;
  6093. if (iLangCount > 1)
  6094. {
  6095. bResult = FALSE;
  6096. break;
  6097. }
  6098. }
  6099. //
  6100. // Get the next enum value.
  6101. //
  6102. dwIndex++;
  6103. cchValue = sizeof(szValue) / sizeof(TCHAR);
  6104. szValue[0] = TEXT('\0');
  6105. cbData = sizeof(szData);
  6106. szData[0] = TEXT('\0');
  6107. rc = RegEnumValue( hKey,
  6108. dwIndex,
  6109. szValue,
  6110. &cchValue,
  6111. NULL,
  6112. &dwType,
  6113. (LPBYTE)szData,
  6114. &cbData );
  6115. }
  6116. //
  6117. // Clean up.
  6118. //
  6119. RegCloseKey(hKey);
  6120. return bResult;
  6121. }
  6122. ////////////////////////////////////////////////////////////////////////////
  6123. //
  6124. // Intl_RemoveMUIFile
  6125. //
  6126. ////////////////////////////////////////////////////////////////////////////
  6127. void Intl_RemoveMUIFile()
  6128. {
  6129. TCHAR szAppPath[MAX_PATH];
  6130. if(0 == GetSystemWindowsDirectory(szAppPath, ARRAYSIZE(szAppPath)))
  6131. {
  6132. // SECURITY: Make sure we null out szAppPath
  6133. szAppPath[0] = TEXT('\0');
  6134. }
  6135. //
  6136. // Invoke muisetup to uninstall MUI languages.
  6137. //
  6138. if (PathAppend(szAppPath, MUISETUP_EXE_RELATIVE_PATH) &&
  6139. Intl_FileExists(szAppPath))
  6140. {
  6141. //
  6142. // Only remove MUI if we are not in an SP OS upgrade scenario and if the system is not LIP
  6143. //
  6144. if (!Intl_IsMUISetupVersionSameAsOS() && !Intl_IsLIP())
  6145. {
  6146. SHELLEXECUTEINFO ExecInfo = {0};
  6147. SHFILEOPSTRUCT shFile =
  6148. {
  6149. NULL, FO_DELETE, szAppPath, NULL, FOF_NOCONFIRMATION|FOF_SILENT|FOF_NOERRORUI, 0, 0, 0
  6150. };
  6151. ExecInfo.lpParameters = TEXT("/u /r /s /o /t");
  6152. ExecInfo.fMask = SEE_MASK_FLAG_NO_UI;
  6153. ExecInfo.lpFile = szAppPath;
  6154. ExecInfo.nShow = SW_SHOWNORMAL;
  6155. ExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
  6156. ShellExecuteEx(&ExecInfo);
  6157. //
  6158. // An additional NULL character must be appended for this
  6159. // multi-string buffer.
  6160. //
  6161. szAppPath[lstrlen(szAppPath) + 1] = 0x00;
  6162. SHFileOperation(&shFile);
  6163. }
  6164. }
  6165. }
  6166. ////////////////////////////////////////////////////////////////////////////
  6167. //
  6168. // Intl_CallTextServices
  6169. //
  6170. ////////////////////////////////////////////////////////////////////////////
  6171. void Intl_CallTextServices()
  6172. {
  6173. TCHAR szAppPath[MAX_PATH];
  6174. if(0 == GetSystemDirectory(szAppPath, ARRAYSIZE(szAppPath)))
  6175. {
  6176. // SECURITY: Make sure we null out szAppPath
  6177. szAppPath[0] = TEXT('\0');
  6178. }
  6179. //
  6180. // Invoke the Input applet.
  6181. //
  6182. if (PathAppend(szAppPath, TEXT("rundll32.exe")) &&
  6183. Intl_FileExists(szAppPath))
  6184. {
  6185. SHELLEXECUTEINFO ExecInfo = {0};
  6186. ExecInfo.lpParameters = TEXT("shell32.dll,Control_RunDLL input.dll");
  6187. ExecInfo.lpFile = szAppPath;
  6188. ExecInfo.nShow = SW_SHOWNORMAL;
  6189. ExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
  6190. ShellExecuteEx(&ExecInfo);
  6191. }
  6192. }
  6193. ////////////////////////////////////////////////////////////////////////////
  6194. //
  6195. // Intl_GetPendingUILanguage
  6196. //
  6197. // Look into the registry for the pending UI Language. This function is
  6198. // used for the default user case.
  6199. //
  6200. ////////////////////////////////////////////////////////////////////////////
  6201. LANGID Intl_GetPendingUILanguage()
  6202. {
  6203. HKEY hKey;
  6204. LANGID dwDefaultUILanguage = 0;
  6205. DWORD cbData = 0;
  6206. TCHAR szBuffer[MAX_PATH];
  6207. //
  6208. // Open the registry key used by setup.
  6209. //
  6210. if (RegOpenKeyEx( HKEY_CURRENT_USER,
  6211. c_szCPanelDesktop,
  6212. 0,
  6213. KEY_READ,
  6214. &hKey ) != ERROR_SUCCESS)
  6215. {
  6216. return (GetUserDefaultUILanguage());
  6217. }
  6218. //
  6219. // Query the pending MUI Language.
  6220. //
  6221. cbData = ARRAYSIZE(szBuffer);
  6222. if (RegQueryValueEx( hKey,
  6223. szMUILangPending,
  6224. NULL,
  6225. NULL,
  6226. (LPBYTE)szBuffer,
  6227. &cbData ) != ERROR_SUCCESS)
  6228. {
  6229. RegCloseKey(hKey);
  6230. return (GetUserDefaultUILanguage());
  6231. }
  6232. else
  6233. {
  6234. if ((dwDefaultUILanguage = (LANGID)TransNum(szBuffer)) == 0)
  6235. {
  6236. RegCloseKey(hKey);
  6237. return (GetUserDefaultUILanguage());
  6238. }
  6239. else
  6240. {
  6241. RegCloseKey(hKey);
  6242. return ((LANGID)dwDefaultUILanguage);
  6243. }
  6244. }
  6245. }
  6246. ////////////////////////////////////////////////////////////////////////////////////
  6247. //
  6248. // Intl_GetDotDefaultUILanguage
  6249. //
  6250. // Retrieve the UI language stored in the HKCU\.Default.
  6251. // This is the default UI language for new users.
  6252. //
  6253. ////////////////////////////////////////////////////////////////////////////////////
  6254. LANGID Intl_GetDotDefaultUILanguage()
  6255. {
  6256. HKEY hKey;
  6257. DWORD dwKeyType;
  6258. DWORD dwSize;
  6259. BOOL success = FALSE;
  6260. TCHAR szBuffer[MAX_PATH];
  6261. LANGID langID;
  6262. //
  6263. // Get the value in .DEFAULT.
  6264. //
  6265. if (RegOpenKeyEx( HKEY_USERS,
  6266. c_szCPanelDesktop_DefUser,
  6267. 0L,
  6268. KEY_READ,
  6269. &hKey ) == ERROR_SUCCESS)
  6270. {
  6271. dwSize = sizeof(szBuffer);
  6272. if (RegQueryValueEx( hKey,
  6273. c_szMUIValue,
  6274. 0L,
  6275. &dwKeyType,
  6276. (LPBYTE)szBuffer,
  6277. &dwSize) == ERROR_SUCCESS)
  6278. {
  6279. if (dwKeyType == REG_SZ)
  6280. {
  6281. langID = (LANGID)_tcstol(szBuffer, NULL, 16);
  6282. success = TRUE;
  6283. }
  6284. }
  6285. RegCloseKey(hKey);
  6286. }
  6287. //
  6288. // key exists, we need to check if the key is valid or not
  6289. //
  6290. if (success)
  6291. {
  6292. success = IsValidUILanguage(langID);
  6293. }
  6294. if (!success)
  6295. {
  6296. return (GetSystemDefaultUILanguage());
  6297. }
  6298. return (langID);
  6299. }
  6300. ////////////////////////////////////////////////////////////////////////////
  6301. //
  6302. // SetControlReadingOrder
  6303. //
  6304. // Set the specified control to be left-to-right or right-to-left reading order.
  6305. //
  6306. // bUseRightToLeft==FALSE: Use left-to-right reading order
  6307. // bUseRightToLeft==TRUE: Use right-to-left reading order
  6308. //
  6309. ////////////////////////////////////////////////////////////////////////////
  6310. void SetControlReadingOrder(BOOL bUseRightToLeft, HWND hwnd)
  6311. {
  6312. BOOL bCurrentRTL;
  6313. if (IsRtLLocale(GetUserDefaultUILanguage()))
  6314. {
  6315. // If the current UI langauge is RTL, the dailog is already localized as RTL.
  6316. // In this case, don't change the direction of the control.
  6317. return;
  6318. }
  6319. bCurrentRTL = (GetWindowLongPtr(hwnd, GWL_EXSTYLE) & (WS_EX_RTLREADING)) != 0;
  6320. if (bCurrentRTL != bUseRightToLeft)
  6321. {
  6322. // Reverse the WS_EX_RTLREADING and WS_EX_RIGHT bit.
  6323. SetWindowLongPtr(hwnd, GWL_EXSTYLE, GetWindowLongPtr(hwnd, GWL_EXSTYLE) ^ (WS_EX_RTLREADING | WS_EX_RIGHT));
  6324. InvalidateRect(hwnd, NULL, FALSE);
  6325. }
  6326. }
  6327. ////////////////////////////////////////////////////////////////////////////
  6328. //
  6329. // Intl_MyQueueCallback
  6330. //
  6331. // During unattended mode, we don't necessarly want the Files Location
  6332. // dialog from setup to be displayed. If the flag D is passed as parameter
  6333. // then we don't show the dialog and abort the installation.
  6334. //
  6335. ////////////////////////////////////////////////////////////////////////////
  6336. UINT WINAPI Intl_MyQueueCallback(PVOID pQueueContext,
  6337. UINT Notification,
  6338. UINT_PTR Param1,
  6339. UINT_PTR Param2)
  6340. {
  6341. if ((g_bDisableSetupDialog) &&
  6342. (g_bUnttendMode) &&
  6343. (SPFILENOTIFY_NEEDMEDIA == Notification))
  6344. {
  6345. // Abort if the installation is about to show a dialog to
  6346. // locate the source file location.
  6347. return FILEOP_ABORT;
  6348. }
  6349. else
  6350. {
  6351. // Pass all other notifications through without modification
  6352. return SetupDefaultQueueCallback(pQueueContext,
  6353. Notification,
  6354. Param1,
  6355. Param2);
  6356. }
  6357. }
  6358. ////////////////////////////////////////////////////////////////////////////
  6359. //
  6360. // Enable/restore to previous state
  6361. // a named priviledge of token of current process
  6362. //
  6363. // Input: pszPrivilegeName = Named Privilege
  6364. // bEnabled = enable/disable the Named Privilege
  6365. // Output *lpWasEnabled = last state of the Named Privilege (enabled/disabled)
  6366. ////////////////////////////////////////////////////////////////////////////
  6367. DWORD Intl_SetPrivilegeAccessToken(WCHAR * pszPrivilegeName, BOOLEAN bEnabled, BOOLEAN *lpWasEnabled)
  6368. {
  6369. HANDLE hProcess;
  6370. HANDLE hAccessToken=NULL;
  6371. LUID luidPrivilegeLUID;
  6372. TOKEN_PRIVILEGES tpTokenPrivilege,tpTokenPrivilegeOld;
  6373. DWORD dwOld, dwErr, dwReturn=ERROR_INTERNAL_ERROR;
  6374. //
  6375. // Get handle of Current Prcoess
  6376. //
  6377. hProcess = GetCurrentProcess();
  6378. if (!hProcess)
  6379. {
  6380. goto done;
  6381. }
  6382. //
  6383. // Get handle of process token
  6384. //
  6385. if (!OpenProcessToken(hProcess,TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,&hAccessToken))
  6386. {
  6387. goto done;
  6388. }
  6389. //
  6390. // Get ID of named Privilege
  6391. //
  6392. if (!LookupPrivilegeValue(NULL,pszPrivilegeName,&luidPrivilegeLUID))
  6393. {
  6394. goto done;
  6395. }
  6396. tpTokenPrivilege.PrivilegeCount = 1;
  6397. tpTokenPrivilege.Privileges[0].Luid = luidPrivilegeLUID;
  6398. if (bEnabled)
  6399. {
  6400. tpTokenPrivilege.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  6401. }
  6402. else
  6403. {
  6404. tpTokenPrivilege.Privileges[0].Attributes = 0;
  6405. }
  6406. //
  6407. // Enable the named Privilege
  6408. //
  6409. if (!AdjustTokenPrivileges(hAccessToken,
  6410. FALSE,
  6411. &tpTokenPrivilege,
  6412. sizeof(TOKEN_PRIVILEGES),
  6413. &tpTokenPrivilegeOld,
  6414. &dwOld))
  6415. {
  6416. goto done;
  6417. }
  6418. dwReturn = ERROR_SUCCESS;
  6419. //
  6420. // Get previous state (enabled/disabled)
  6421. //
  6422. if (lpWasEnabled)
  6423. {
  6424. if (tpTokenPrivilegeOld.Privileges[0].Attributes == SE_PRIVILEGE_ENABLED)
  6425. {
  6426. *lpWasEnabled = TRUE;
  6427. }
  6428. else
  6429. {
  6430. *lpWasEnabled = FALSE;
  6431. }
  6432. }
  6433. done:
  6434. if (dwReturn != ERROR_SUCCESS)
  6435. {
  6436. if ( (dwReturn=GetLastError()) == ERROR_SUCCESS)
  6437. {
  6438. dwReturn = ERROR_INTERNAL_ERROR;
  6439. }
  6440. }
  6441. if (hAccessToken)
  6442. {
  6443. CloseHandle(hAccessToken);
  6444. }
  6445. return dwReturn;
  6446. }