Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

6027 lines
181 KiB

  1. /*++
  2. Copyright (c) 1991-2000, Microsoft Corporation All rights reserved.
  3. Module Name:
  4. locale.c
  5. Abstract:
  6. This file contains functions that return information about a
  7. language group, a UI language, a locale, or a calendar.
  8. APIs found in this file:
  9. IsValidLanguageGroup
  10. IsValidLocale
  11. IsValidUILanguage
  12. ConvertDefaultLocale
  13. GetThreadLocale
  14. SetThreadLocale
  15. SetThreadUILanguage
  16. GetSystemDefaultUILanguage
  17. GetUserDefaultUILanguage
  18. GetSystemDefaultLangID
  19. GetUserDefaultLangID
  20. GetSystemDefaultLCID
  21. GetUserDefaultLCID
  22. VerLanguageNameW
  23. VerLanguageNameA
  24. GetLocaleInfoW
  25. SetLocaleInfoW
  26. GetCalendarInfoW
  27. SetCalendarInfoW
  28. Revision History:
  29. 05-31-91 JulieB Created.
  30. --*/
  31. //
  32. // Include Files.
  33. //
  34. #include "nls.h"
  35. //
  36. // Allow this file to build without warnings when the DUnicode switch
  37. // is turned off.
  38. //
  39. #undef MAKEINTRESOURCE
  40. #define MAKEINTRESOURCE MAKEINTRESOURCEW
  41. //
  42. // Global Variables.
  43. //
  44. LCID gProcessLocale;
  45. //
  46. // Forward Declarations.
  47. //
  48. BOOL
  49. SetUserInfo(
  50. LCTYPE LCType,
  51. LPWSTR pData,
  52. ULONG DataLength);
  53. BOOL SetCurrentUserRegValue(
  54. LCTYPE LCType,
  55. LPWSTR pData,
  56. ULONG DataLength);
  57. BOOL
  58. SetMultipleUserInfo(
  59. DWORD dwFlags,
  60. int cchData,
  61. LPCWSTR pPicture,
  62. LPCWSTR pSeparator,
  63. LPCWSTR pOrder,
  64. LPCWSTR pTLZero,
  65. LPCWSTR pTimeMarkPosn);
  66. BOOL
  67. SetTwoDigitYearInfo(
  68. CALID Calendar,
  69. LPCWSTR pYearInfo,
  70. int cchData);
  71. void
  72. GetInstallLanguageFromRegistry();
  73. //-------------------------------------------------------------------------//
  74. // PRIVATE API ROUTINES //
  75. //-------------------------------------------------------------------------//
  76. ////////////////////////////////////////////////////////////////////////////
  77. //
  78. // NlsResetProcessLocale
  79. //
  80. ////////////////////////////////////////////////////////////////////////////
  81. void NlsResetProcessLocale(void)
  82. {
  83. //
  84. // If the thread isn't impersonating, then re-read the process locale
  85. // from the current user's registry.
  86. //
  87. if (NtCurrentTeb()->IsImpersonating == 0L)
  88. {
  89. NlsFlushProcessCache(LOCALE_SLOCALE);
  90. NlsGetUserLocale(&gProcessLocale);
  91. }
  92. return;
  93. }
  94. //-------------------------------------------------------------------------//
  95. // API ROUTINES //
  96. //-------------------------------------------------------------------------//
  97. ////////////////////////////////////////////////////////////////////////////
  98. //
  99. // IsValidLanguageGroup
  100. //
  101. // Determines whether or not a language group is installed in the system
  102. // if the LGRPID_INSTALLED flag is set, or whether or not a language group
  103. // is supported in the system if the LGRPID_SUPPORTED flag is set.
  104. //
  105. // 03-10-98 JulieB Created.
  106. ////////////////////////////////////////////////////////////////////////////
  107. BOOL WINAPI IsValidLanguageGroup(
  108. LGRPID LanguageGroup,
  109. DWORD dwFlags)
  110. {
  111. PKEY_VALUE_FULL_INFORMATION pKeyValueFull;
  112. BYTE pStatic[MAX_KEY_VALUE_FULLINFO];
  113. WCHAR pTmpBuf[MAX_PATH]; // temp buffer
  114. UNICODE_STRING ObUnicodeStr; // registry data value string
  115. LPWSTR pData; // ptr to registry data
  116. //
  117. // Invalid Flags Check:
  118. // - flags other than valid ones
  119. // - more than one of either supported or installed
  120. //
  121. if ((dwFlags & IVLG_INVALID_FLAG) ||
  122. (MORE_THAN_ONE(dwFlags, IVLG_SINGLE_FLAG)))
  123. {
  124. return (FALSE);
  125. }
  126. //
  127. // Open the Language Groups registry key.
  128. //
  129. OPEN_LANG_GROUPS_KEY(FALSE);
  130. //
  131. // Convert language group value to Unicode string.
  132. //
  133. if (NlsConvertIntegerToString(LanguageGroup, 16, 1, pTmpBuf, MAX_PATH))
  134. {
  135. return (FALSE);
  136. }
  137. //
  138. // Query the registry for the value.
  139. //
  140. pKeyValueFull = (PKEY_VALUE_FULL_INFORMATION)pStatic;
  141. if ((QueryRegValue( hLangGroupsKey,
  142. pTmpBuf,
  143. &pKeyValueFull,
  144. MAX_KEY_VALUE_FULLINFO,
  145. NULL ) != NO_ERROR))
  146. {
  147. return (FALSE);
  148. }
  149. //
  150. // Language Group is SUPPORTED. If the INSTALLED flag is NOT set, then
  151. // return success.
  152. //
  153. if (!(dwFlags & LGRPID_INSTALLED))
  154. {
  155. return (TRUE);
  156. }
  157. //
  158. // Need to find out if it's installed.
  159. //
  160. if (pKeyValueFull->DataLength > 2)
  161. {
  162. pData = GET_VALUE_DATA_PTR(pKeyValueFull);
  163. if ((pData[0] == L'1') && (pData[1] == 0))
  164. {
  165. return (TRUE);
  166. }
  167. }
  168. //
  169. // Return result.
  170. //
  171. return (FALSE);
  172. }
  173. ////////////////////////////////////////////////////////////////////////////
  174. //
  175. // IsValidLocale
  176. //
  177. // Determines whether or not a locale is installed in the system if the
  178. // LCID_INSTALLED flag is set, or whether or not a locale is supported in
  179. // the system if the LCID_SUPPORTED flag is set.
  180. //
  181. // 07-26-93 JulieB Created.
  182. ////////////////////////////////////////////////////////////////////////////
  183. BOOL WINAPI IsValidLocale(
  184. LCID Locale,
  185. DWORD dwFlags)
  186. {
  187. PKEY_VALUE_FULL_INFORMATION pKeyValueFull;
  188. BYTE pStatic1[MAX_KEY_VALUE_FULLINFO];
  189. BYTE pStatic2[MAX_KEY_VALUE_FULLINFO];
  190. WCHAR pTmpBuf[MAX_PATH]; // temp buffer
  191. UNICODE_STRING ObUnicodeStr; // registry data value string
  192. DWORD Data; // registry data value
  193. LPWSTR pData; // ptr to registry data
  194. BOOL bResult = FALSE; // result value
  195. //
  196. // Invalid Flags Check:
  197. // - flags other than valid ones
  198. // - more than one of either supported or installed
  199. //
  200. if ((dwFlags & IVL_INVALID_FLAG) ||
  201. (MORE_THAN_ONE(dwFlags, IVL_SINGLE_FLAG)))
  202. {
  203. //
  204. // The ME release of NT 4 did a really bad thing and allowed 0x39
  205. // to be passed in as a valid flag value for Arabic and Hebrew.
  206. // As a result, we need to allow this flag combination for
  207. // the Arabic and Hebrew locales.
  208. //
  209. if ((dwFlags == 0x39) &&
  210. ((Locale == MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT), SORT_DEFAULT)) ||
  211. (Locale == MAKELCID(MAKELANGID(LANG_HEBREW, SUBLANG_DEFAULT), SORT_DEFAULT))))
  212. {
  213. dwFlags = LCID_INSTALLED;
  214. }
  215. else
  216. {
  217. return (FALSE);
  218. }
  219. }
  220. //
  221. // Invalid Locale Check.
  222. //
  223. if (IS_INVALID_LOCALE(Locale))
  224. {
  225. return (FALSE);
  226. }
  227. //
  228. // See if the LOCALE information is in the system for the
  229. // given locale.
  230. //
  231. if (GetLocHashNode(Locale) == NULL)
  232. {
  233. //
  234. // Return failure.
  235. //
  236. return (FALSE);
  237. }
  238. //
  239. // Locale is SUPPORTED. If the INSTALLED flag is NOT set, then
  240. // return success.
  241. //
  242. if (!(dwFlags & LCID_INSTALLED))
  243. {
  244. return (TRUE);
  245. }
  246. //
  247. // Open the Locale, the Alternate Sorts, and the Language Groups
  248. // registry keys.
  249. //
  250. OPEN_LOCALE_KEY(FALSE);
  251. OPEN_ALT_SORTS_KEY(FALSE);
  252. OPEN_LANG_GROUPS_KEY(FALSE);
  253. //
  254. // Convert locale value to Unicode string.
  255. //
  256. if (NlsConvertIntegerToString(Locale, 16, 8, pTmpBuf, MAX_PATH))
  257. {
  258. return (FALSE);
  259. }
  260. //
  261. // Query the registry for the value.
  262. //
  263. pKeyValueFull = (PKEY_VALUE_FULL_INFORMATION)pStatic1;
  264. if (((QueryRegValue( hLocaleKey,
  265. pTmpBuf,
  266. &pKeyValueFull,
  267. MAX_KEY_VALUE_FULLINFO,
  268. NULL ) == NO_ERROR) ||
  269. (QueryRegValue( hAltSortsKey,
  270. pTmpBuf,
  271. &pKeyValueFull,
  272. MAX_KEY_VALUE_FULLINFO,
  273. NULL ) == NO_ERROR)) &&
  274. (pKeyValueFull->DataLength > 2))
  275. {
  276. RtlInitUnicodeString(&ObUnicodeStr, GET_VALUE_DATA_PTR(pKeyValueFull));
  277. if ((RtlUnicodeStringToInteger(&ObUnicodeStr, 16, &Data) == NO_ERROR) &&
  278. (Data != 0))
  279. {
  280. pKeyValueFull = (PKEY_VALUE_FULL_INFORMATION)pStatic2;
  281. if ((QueryRegValue( hLangGroupsKey,
  282. ObUnicodeStr.Buffer,
  283. &pKeyValueFull,
  284. MAX_KEY_VALUE_FULLINFO,
  285. NULL ) == NO_ERROR) &&
  286. (pKeyValueFull->DataLength > 2))
  287. {
  288. pData = GET_VALUE_DATA_PTR(pKeyValueFull);
  289. if ((pData[0] == L'1') && (pData[1] == 0))
  290. {
  291. bResult = TRUE;
  292. }
  293. }
  294. }
  295. }
  296. //
  297. // Return result.
  298. //
  299. return (bResult);
  300. }
  301. ////////////////////////////////////////////////////////////////////////////
  302. //
  303. // IsValidUILanguage
  304. //
  305. // Determines whether or not the specified UI language is installed in the system.
  306. //
  307. //
  308. // 12-03-00 YSLin Created.
  309. ////////////////////////////////////////////////////////////////////////////
  310. BOOL WINAPI IsValidUILanguage(LANGID UILangID)
  311. {
  312. NTSTATUS Status;
  313. OBJECT_ATTRIBUTES ObjectAttributes;
  314. UNICODE_STRING KeyPath, KeyValueName;
  315. HANDLE Key;
  316. WCHAR UILangIDStr[5];
  317. WCHAR KeyValueBuffer[ 128 ];
  318. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
  319. ULONG ResultLength;
  320. ULONG Value = 0, Digit, i;
  321. WCHAR c;
  322. BOOL Result = FALSE;
  323. RtlInitUnicodeString(&KeyPath, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Nls\\MUILanguages");
  324. if (!NlsConvertIntegerToHexStringW(UILangID, FALSE, UILangIDStr, sizeof(UILangIDStr)/sizeof(WCHAR)))
  325. {
  326. return (FALSE);
  327. }
  328. RtlInitUnicodeString(&KeyValueName, UILangIDStr);
  329. InitializeObjectAttributes (&ObjectAttributes,
  330. &KeyPath,
  331. OBJ_CASE_INSENSITIVE,
  332. NULL,
  333. NULL);
  334. if (NT_SUCCESS(NtOpenKey (&Key, KEY_READ, &ObjectAttributes)))
  335. {
  336. KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)KeyValueBuffer;
  337. Status = NtQueryValueKey(Key,
  338. &KeyValueName,
  339. KeyValuePartialInformation,
  340. KeyValueInformation,
  341. sizeof( KeyValueBuffer ),
  342. &ResultLength
  343. );
  344. if (NT_SUCCESS(Status))
  345. {
  346. if (KeyValueInformation->Type == REG_SZ && *((PWSTR)(KeyValueInformation->Data)) == L'1')
  347. {
  348. Result = TRUE;
  349. }
  350. }
  351. NtClose(Key);
  352. }
  353. return (Result);
  354. }
  355. ////////////////////////////////////////////////////////////////////////////
  356. //
  357. // ConvertDefaultLocale
  358. //
  359. // Converts any of the special case locale values to an actual locale id.
  360. // If none of the special case locales was given, the given locale id
  361. // is returned.
  362. //
  363. // 09-01-93 JulieB Created.
  364. ////////////////////////////////////////////////////////////////////////////
  365. LCID WINAPI ConvertDefaultLocale(
  366. LCID Locale)
  367. {
  368. //
  369. // Check for the special locale values.
  370. //
  371. CHECK_SPECIAL_LOCALES(Locale, FALSE);
  372. //
  373. // Return the locale id.
  374. //
  375. return (Locale);
  376. }
  377. ////////////////////////////////////////////////////////////////////////////
  378. //
  379. // GetThreadLocale
  380. //
  381. // Returns the locale id for the current thread.
  382. //
  383. // 03-11-93 JulieB Moved from base\client.
  384. ////////////////////////////////////////////////////////////////////////////
  385. LCID WINAPI GetThreadLocale()
  386. {
  387. //
  388. // Return the locale id stored in the TEB.
  389. //
  390. return ((LCID)(NtCurrentTeb()->CurrentLocale));
  391. }
  392. ////////////////////////////////////////////////////////////////////////////
  393. //
  394. // SetThreadLocale
  395. //
  396. // Resets the locale id for the current thread. Any locale-dependent
  397. // functions will reflect the new locale. If the locale passed in is
  398. // not a valid locale id, then FALSE is returned.
  399. //
  400. // 03-11-93 JulieB Moved from base\client; Added Locale Validation.
  401. ////////////////////////////////////////////////////////////////////////////
  402. BOOL WINAPI SetThreadLocale(
  403. LCID Locale)
  404. {
  405. PLOC_HASH pHashN; // ptr to hash node
  406. //
  407. // Validate locale id.
  408. //
  409. VALIDATE_LANGUAGE(Locale, pHashN, 0, FALSE);
  410. if (pHashN == NULL)
  411. {
  412. SetLastError(ERROR_INVALID_PARAMETER);
  413. return (FALSE);
  414. }
  415. //
  416. // Set the locale id in the TEB.
  417. //
  418. NtCurrentTeb()->CurrentLocale = (ULONG)Locale;
  419. //
  420. // Return success.
  421. //
  422. return (TRUE);
  423. }
  424. ////////////////////////////////////////////////////////////////////////////
  425. //
  426. // SetThreadUILanguage
  427. //
  428. // This routine sets the thread UI language based on the console codepage.
  429. //
  430. // 9-29-00 WeiWu Created.
  431. ////////////////////////////////////////////////////////////////////////////
  432. LANGID WINAPI SetThreadUILanguage(
  433. WORD wReserved)
  434. {
  435. //
  436. // Cache system locale and CP info
  437. //
  438. static LCID s_lidSystem = 0;
  439. static UINT s_uiSysCp = 0;
  440. static UINT s_uiSysOEMCp = 0;
  441. UINT uiUserUICp;
  442. UINT uiUserUIOEMCp;
  443. WCHAR szData[16];
  444. LANGID lidUserUI = GetUserDefaultUILanguage();
  445. LCID lcidThreadOld = GetThreadLocale();
  446. //
  447. // Set default thread locale to EN-US
  448. //
  449. // This allow us to fall back to English UI to avoid trashed characters
  450. // when console doesn't meet the criteria of rendering native UI.
  451. //
  452. LCID lcidThread = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
  453. UINT uiConsoleCp = GetConsoleOutputCP();
  454. //
  455. // Make sure nobody uses it yet
  456. //
  457. ASSERT(wReserved == 0);
  458. //
  459. // Get cached system locale and CP info.
  460. //
  461. if (!s_uiSysCp)
  462. {
  463. LCID lcidSystem = GetSystemDefaultLCID();
  464. if (lcidSystem)
  465. {
  466. //
  467. // Get ANSI CP
  468. //
  469. GetLocaleInfoW(lcidSystem, LOCALE_IDEFAULTANSICODEPAGE, szData, sizeof(szData)/sizeof(WCHAR));
  470. NlsConvertStringToIntegerW(szData, 10, -1, &s_uiSysCp);
  471. //
  472. // Get OEM CP
  473. //
  474. GetLocaleInfoW(lcidSystem, LOCALE_IDEFAULTCODEPAGE, szData, sizeof(szData)/sizeof(WCHAR));
  475. NlsConvertStringToIntegerW(szData, 10, -1, &s_uiSysOEMCp);
  476. //
  477. // Cache system primary langauge
  478. //
  479. s_lidSystem = PRIMARYLANGID(LANGIDFROMLCID(lcidSystem));
  480. }
  481. }
  482. //
  483. // Don't cache user UI language and CP info, UI language can be changed without system reboot.
  484. //
  485. if (lidUserUI)
  486. {
  487. GetLocaleInfoW(MAKELCID(lidUserUI,SORT_DEFAULT), LOCALE_IDEFAULTANSICODEPAGE, szData, sizeof(szData)/sizeof(WCHAR));
  488. NlsConvertStringToIntegerW(szData, 10, -1, &uiUserUICp);
  489. GetLocaleInfoW(MAKELCID(lidUserUI,SORT_DEFAULT), LOCALE_IDEFAULTCODEPAGE, szData, sizeof(szData)/sizeof(WCHAR));
  490. NlsConvertStringToIntegerW(szData, 10, -1, &uiUserUIOEMCp);
  491. }
  492. //
  493. // Complex scripts cannot be rendered in the console, so we
  494. // force the English (US) resource.
  495. //
  496. if (uiConsoleCp &&
  497. s_lidSystem != LANG_ARABIC &&
  498. s_lidSystem != LANG_HEBREW &&
  499. s_lidSystem != LANG_VIETNAMESE &&
  500. s_lidSystem != LANG_THAI)
  501. {
  502. //
  503. // Use UI language for console only when console CP, system CP and UI language CP match.
  504. //
  505. if ((uiConsoleCp == s_uiSysCp || uiConsoleCp == s_uiSysOEMCp) &&
  506. (uiConsoleCp == uiUserUICp || uiConsoleCp == uiUserUIOEMCp))
  507. {
  508. lcidThread = MAKELCID(lidUserUI, SORT_DEFAULT);
  509. }
  510. }
  511. //
  512. // Set the thread locale if it's different from the currently set
  513. // thread locale.
  514. //
  515. if ((lcidThread != lcidThreadOld) && (!SetThreadLocale(lcidThread)))
  516. {
  517. lcidThread = lcidThreadOld;
  518. }
  519. //
  520. // Return the thread locale that was set.
  521. //
  522. return (LANGIDFROMLCID(lcidThread));
  523. }
  524. ////////////////////////////////////////////////////////////////////////////
  525. //
  526. // GetSystemDefaultUILanguage
  527. //
  528. // Returns the language of the original install.
  529. //
  530. // 03-10-98 JulieB Created.
  531. ////////////////////////////////////////////////////////////////////////////
  532. LANGID WINAPI GetSystemDefaultUILanguage()
  533. {
  534. //
  535. // Get the original install language and return it.
  536. //
  537. if (gSystemInstallLang == 0)
  538. {
  539. if (NtQueryInstallUILanguage(&gSystemInstallLang) != STATUS_SUCCESS)
  540. {
  541. gSystemInstallLang = 0;
  542. return (NLS_DEFAULT_UILANG);
  543. }
  544. }
  545. return (gSystemInstallLang);
  546. }
  547. ////////////////////////////////////////////////////////////////////////////
  548. //
  549. // GetUserDefaultUILanguage
  550. //
  551. // Returns the current User's UI language selection. If the UI language
  552. // is not available, then the chosen default UI language is used
  553. // (NLS_DEFAULT_UILANG).
  554. //
  555. // 03-10-98 JulieB Created.
  556. ////////////////////////////////////////////////////////////////////////////
  557. LANGID WINAPI GetUserDefaultUILanguage()
  558. {
  559. LANGID DefaultUILang;
  560. LANGID SystemUILang;
  561. //
  562. // Note that the default UI language is coming from HKCU. However,
  563. // in the roaming profile situation, the default UI language for the
  564. // user may be not installed in the roamming machine, therefore we will
  565. // need to check if the DefaultUILang is a valid UI language installed
  566. // in the machine (the check is based in HKLM).
  567. //
  568. if (NtQueryDefaultUILanguage(&DefaultUILang) != STATUS_SUCCESS)
  569. {
  570. if ((SystemUILang = GetSystemDefaultUILanguage()) == 0)
  571. {
  572. return (NLS_DEFAULT_UILANG);
  573. }
  574. return (SystemUILang);
  575. }
  576. return (DefaultUILang);
  577. }
  578. ////////////////////////////////////////////////////////////////////////////
  579. //
  580. // GetSystemDefaultLangID
  581. //
  582. // Returns the default language for the system. If the registry value is
  583. // not readable, then the chosen default language is used
  584. // (NLS_DEFAULT_LANGID).
  585. //
  586. // 05-31-91 JulieB Created.
  587. ////////////////////////////////////////////////////////////////////////////
  588. LANGID WINAPI GetSystemDefaultLangID()
  589. {
  590. //
  591. // Get the language id from the locale id stored in the cache
  592. // and return it.
  593. //
  594. return (LANGIDFROMLCID(gSystemLocale));
  595. }
  596. ////////////////////////////////////////////////////////////////////////////
  597. //
  598. // GetUserDefaultLangID
  599. //
  600. // Returns the default language for the current user. If the current user's
  601. // language is not set, then the system default language id is returned.
  602. //
  603. // 05-31-91 JulieB Created.
  604. ////////////////////////////////////////////////////////////////////////////
  605. LANGID WINAPI GetUserDefaultLangID()
  606. {
  607. //
  608. // Get the language id from the locale id stored in the cache
  609. // and return it.
  610. //
  611. return (LANGIDFROMLCID(GetUserDefaultLCID()));
  612. }
  613. ////////////////////////////////////////////////////////////////////////////
  614. //
  615. // GetSystemDefaultLCID
  616. //
  617. // Returns the default locale for the system.
  618. //
  619. // 05-31-91 JulieB Created.
  620. ////////////////////////////////////////////////////////////////////////////
  621. LCID WINAPI GetSystemDefaultLCID()
  622. {
  623. //
  624. // Return the locale id stored in the cache.
  625. //
  626. return (gSystemLocale);
  627. }
  628. ////////////////////////////////////////////////////////////////////////////
  629. //
  630. // GetUserDefaultLCID
  631. //
  632. // Returns the default locale for the current user. If current user's locale
  633. // is not set, then the system default locale id is returned.
  634. //
  635. // 05-31-91 JulieB Created.
  636. ////////////////////////////////////////////////////////////////////////////
  637. LCID WINAPI GetUserDefaultLCID()
  638. {
  639. LCID Lcid = NtCurrentTeb()->ImpersonationLocale;
  640. switch (Lcid)
  641. {
  642. case ( -1 ) :
  643. {
  644. //
  645. // Thread is being impersonated.
  646. //
  647. if (NT_SUCCESS( NlsGetUserLocale(&Lcid) ))
  648. {
  649. NtCurrentTeb()->ImpersonationLocale = Lcid;
  650. }
  651. else
  652. {
  653. //
  654. // If we can't get it from the registry, then let's use the
  655. // system locale since it won't be resolved by calling
  656. // GetUserDefaultLCID() again.
  657. //
  658. Lcid = NtCurrentTeb()->ImpersonationLocale = gSystemLocale;
  659. }
  660. break;
  661. }
  662. case ( 0 ) :
  663. {
  664. //
  665. // Thread hasn't been impersonated.
  666. // If we are running in the interactive logged on user, then
  667. // use the one cached in CSRSS if the cache is valid. Otherwise,
  668. // use the process cached locale.
  669. //
  670. if (gInteractiveLogonUserProcess == (BOOL) -1)
  671. {
  672. NlsIsInteractiveUserProcess();
  673. }
  674. if ((gInteractiveLogonUserProcess == FALSE) ||
  675. ((Lcid = pNlsUserInfo->UserLocaleId) == 0))
  676. {
  677. if (!gProcessLocale)
  678. {
  679. if (!NT_SUCCESS (NlsGetUserLocale(&gProcessLocale)) )
  680. {
  681. gProcessLocale = gSystemLocale;
  682. }
  683. }
  684. Lcid = gProcessLocale;
  685. }
  686. break;
  687. }
  688. }
  689. return (Lcid);
  690. }
  691. ////////////////////////////////////////////////////////////////////////////
  692. //
  693. // VerLanguageNameW
  694. //
  695. // Returns the language name of the given language id in the language of
  696. // the current user.
  697. //
  698. // 05-31-91 JulieB Moved and Rewrote from Version Library.
  699. ////////////////////////////////////////////////////////////////////////////
  700. DWORD WINAPI VerLanguageNameW(
  701. DWORD wLang,
  702. LPWSTR szLang,
  703. DWORD wSize)
  704. {
  705. DWORD Length = 0; // length of string
  706. WCHAR pTemp[MAX_REG_VAL_SIZE]; // temp buffer
  707. //
  708. // Make sure we have a buffer.
  709. //
  710. if ((wSize == 0) || (szLang == NULL))
  711. {
  712. return (0);
  713. }
  714. //
  715. // Try to get the localized language name for the given ID.
  716. //
  717. pTemp[0] = 0;
  718. if (!(Length = GetStringTableEntry( wLang,
  719. 0,
  720. pTemp,
  721. MAX_REG_VAL_SIZE,
  722. RC_LANGUAGE_NAME )))
  723. {
  724. //
  725. // Can't get the name of the language id passed in, so get
  726. // the "language neutral" name.
  727. //
  728. Length = GetStringTableEntry( LANG_NEUTRAL,
  729. 0,
  730. pTemp,
  731. MAX_REG_VAL_SIZE,
  732. RC_LANGUAGE_NAME );
  733. }
  734. //
  735. // If the length is too big for the buffer, then reset the length
  736. // to the size of the given buffer.
  737. //
  738. if (Length >= wSize)
  739. {
  740. Length = wSize - 1;
  741. }
  742. //
  743. // Copy the string to the buffer and zero terminate it.
  744. //
  745. if (Length > 0)
  746. {
  747. wcsncpy(szLang, pTemp, Length);
  748. szLang[Length] = 0;
  749. }
  750. //
  751. // Return the number of characters in the string, NOT including
  752. // the null termination.
  753. //
  754. return (Length);
  755. }
  756. ////////////////////////////////////////////////////////////////////////////
  757. //
  758. // VerLanguageNameA
  759. //
  760. // Returns the language name of the given language id in the language of
  761. // the current user.
  762. //
  763. // 05-31-91 JulieB Moved from Version Library.
  764. ////////////////////////////////////////////////////////////////////////////
  765. DWORD WINAPI VerLanguageNameA(
  766. DWORD wLang,
  767. LPSTR szLang,
  768. DWORD wSize)
  769. {
  770. UNICODE_STRING Language; // unicode string buffer
  771. ANSI_STRING AnsiString; // ansi string buffer
  772. DWORD Status; // return status
  773. //
  774. // Make sure we have a buffer.
  775. //
  776. if ((wSize == 0) || (szLang == NULL))
  777. {
  778. return (0);
  779. }
  780. //
  781. // Allocate Unicode string structure and set the fields with the
  782. // given parameters.
  783. //
  784. Language.Buffer = RtlAllocateHeap( RtlProcessHeap(),
  785. 0,
  786. sizeof(WCHAR) * wSize );
  787. Language.MaximumLength = (USHORT)(wSize * sizeof(WCHAR));
  788. //
  789. // Make sure the allocation succeeded.
  790. //
  791. if (Language.Buffer == NULL)
  792. {
  793. return (FALSE);
  794. }
  795. //
  796. // Get the language name (in Unicode).
  797. //
  798. Status = VerLanguageNameW( wLang,
  799. Language.Buffer,
  800. wSize );
  801. Language.Length = (USHORT)(Status * sizeof(WCHAR));
  802. //
  803. // Convert unicode string to ansi.
  804. //
  805. AnsiString.Buffer = szLang;
  806. AnsiString.Length = AnsiString.MaximumLength = (USHORT)wSize;
  807. RtlUnicodeStringToAnsiString(&AnsiString, &Language, FALSE);
  808. Status = AnsiString.Length;
  809. RtlFreeUnicodeString(&Language);
  810. //
  811. // Return the value returned from VerLanguageNameW.
  812. //
  813. return (Status);
  814. }
  815. ////////////////////////////////////////////////////////////////////////////
  816. //
  817. // GetLocaleInfoW
  818. //
  819. // Returns one of the various pieces of information about a particular
  820. // locale by querying the configuration registry. This call also indicates
  821. // how much memory is necessary to contain the desired information.
  822. //
  823. // 05-31-91 JulieB Created.
  824. ////////////////////////////////////////////////////////////////////////////
  825. int WINAPI GetLocaleInfoW(
  826. LCID Locale,
  827. LCTYPE LCType,
  828. LPWSTR lpLCData,
  829. int cchData)
  830. {
  831. PLOC_HASH pHashN; // ptr to LOC hash node
  832. int Length = 0; // length of info string
  833. LPWSTR pString; // ptr to the info string
  834. LPWORD pStart; // ptr to starting point
  835. BOOL UserOverride = TRUE; // use user override
  836. BOOL ReturnNum = FALSE; // return number instead of string
  837. LPWSTR pTmp; // tmp ptr to info string
  838. int Repeat; // # repetitions of same letter
  839. WCHAR pTemp[MAX_REG_VAL_SIZE]; // temp buffer
  840. UNICODE_STRING ObUnicodeStr; // value string
  841. int Base = 0; // base for str to int conversion
  842. static LANGID lidSystem = 0; // system default UI language
  843. //
  844. // Invalid Parameter Check:
  845. // - validate LCID
  846. // - count is negative
  847. // - NULL data pointer AND count is not zero
  848. //
  849. // NOTE: invalid type is checked in the switch statement below.
  850. //
  851. VALIDATE_LOCALE(Locale, pHashN, FALSE);
  852. if ( (pHashN == NULL) ||
  853. (cchData < 0) ||
  854. ((lpLCData == NULL) && (cchData != 0)) )
  855. {
  856. SetLastError(ERROR_INVALID_PARAMETER);
  857. return (0);
  858. }
  859. //
  860. // Set the base value to add to in order to get the variable
  861. // length strings.
  862. //
  863. pStart = (LPWORD)(pHashN->pLocaleHdr);
  864. //
  865. // Check for NO USER OVERRIDE flag and remove the USE CP ACP flag.
  866. //
  867. if (LCType & LOCALE_NOUSEROVERRIDE)
  868. {
  869. //
  870. // Flag is set, so set the boolean value and remove the flag
  871. // from the LCType parameter (for switch statement).
  872. //
  873. UserOverride = FALSE;
  874. }
  875. if (LCType & LOCALE_RETURN_NUMBER)
  876. {
  877. //
  878. // Flag is set, so set the boolean value and remove the flag
  879. // from the LCType parameter (for switch statement).
  880. //
  881. ReturnNum = TRUE;
  882. }
  883. LCType = NLS_GET_LCTYPE_VALUE(LCType);
  884. //
  885. // Initialize temp buffer.
  886. //
  887. pTemp[0] = 0;
  888. //
  889. // Return the appropriate information for the given LCTYPE.
  890. // If user information exists for the given LCTYPE, then
  891. // the user default is returned instead of the system default.
  892. //
  893. switch (LCType)
  894. {
  895. case ( LOCALE_ILANGUAGE ) :
  896. {
  897. Base = 16;
  898. pString = pHashN->pLocaleFixed->szILanguage;
  899. break;
  900. }
  901. case ( LOCALE_SLANGUAGE ) :
  902. {
  903. if (!lidSystem)
  904. {
  905. lidSystem = GetSystemDefaultUILanguage();
  906. }
  907. //
  908. // Get the information from the RC file.
  909. //
  910. // Use system installed language resource if we're not under MUI.
  911. // Otherwise, let resource loader load the default language resource.
  912. //
  913. Length = GetStringTableEntry( LANGIDFROMLCID(Locale),
  914. GetUserDefaultUILanguage() == lidSystem? lidSystem : 0,
  915. pTemp,
  916. MAX_REG_VAL_SIZE,
  917. RC_LANGUAGE_NAME );
  918. if (Length == 0)
  919. {
  920. SetLastError(ERROR_INVALID_PARAMETER);
  921. return (0);
  922. }
  923. pString = pTemp;
  924. break;
  925. }
  926. case ( LOCALE_SENGLANGUAGE ) :
  927. {
  928. pString = pStart + pHashN->pLocaleHdr->SEngLanguage;
  929. break;
  930. }
  931. case ( LOCALE_SABBREVLANGNAME ) :
  932. {
  933. if (UserOverride &&
  934. GetUserInfo( Locale,
  935. LCType,
  936. FIELD_OFFSET(NLS_USER_INFO, sAbbrevLangName),
  937. NLS_VALUE_SLANGUAGE,
  938. pTemp,
  939. ARRAYSIZE(pTemp),
  940. TRUE ))
  941. {
  942. pString = pTemp;
  943. }
  944. else
  945. {
  946. pString = pStart + pHashN->pLocaleHdr->SAbbrevLang;
  947. }
  948. break;
  949. }
  950. case ( LOCALE_SISO639LANGNAME ) :
  951. {
  952. pString = pStart + pHashN->pLocaleHdr->SAbbrevLangISO;
  953. break;
  954. }
  955. case ( LOCALE_SNATIVELANGNAME ) :
  956. {
  957. pString = pStart + pHashN->pLocaleHdr->SNativeLang;
  958. break;
  959. }
  960. case ( LOCALE_ICOUNTRY ) :
  961. {
  962. Base = 10;
  963. if (UserOverride &&
  964. GetUserInfo( Locale,
  965. LCType,
  966. FIELD_OFFSET(NLS_USER_INFO, iCountry),
  967. NLS_VALUE_ICOUNTRY,
  968. pTemp,
  969. ARRAYSIZE(pTemp),
  970. TRUE ))
  971. {
  972. pString = pTemp;
  973. }
  974. else
  975. {
  976. pString = pHashN->pLocaleFixed->szICountry;
  977. }
  978. break;
  979. }
  980. case ( LOCALE_SCOUNTRY ) :
  981. {
  982. if (UserOverride &&
  983. GetUserInfo( Locale,
  984. LCType,
  985. FIELD_OFFSET(NLS_USER_INFO, sCountry),
  986. NLS_VALUE_SCOUNTRY,
  987. pTemp,
  988. ARRAYSIZE(pTemp),
  989. TRUE ))
  990. {
  991. pString = pTemp;
  992. }
  993. else
  994. {
  995. //
  996. // Get the information from the RC file.
  997. //
  998. Length = GetStringTableEntry( LANGIDFROMLCID(Locale),
  999. 0,
  1000. pTemp,
  1001. MAX_REG_VAL_SIZE,
  1002. RC_COUNTRY_NAME );
  1003. if (Length == 0)
  1004. {
  1005. SetLastError(ERROR_INVALID_PARAMETER);
  1006. return (0);
  1007. }
  1008. pString = pTemp;
  1009. break;
  1010. }
  1011. break;
  1012. }
  1013. case ( LOCALE_SENGCOUNTRY ) :
  1014. {
  1015. pString = pStart + pHashN->pLocaleHdr->SEngCountry;
  1016. break;
  1017. }
  1018. case ( LOCALE_SABBREVCTRYNAME ) :
  1019. {
  1020. pString = pStart + pHashN->pLocaleHdr->SAbbrevCtry;
  1021. break;
  1022. }
  1023. case ( LOCALE_SISO3166CTRYNAME ) :
  1024. {
  1025. pString = pStart + pHashN->pLocaleHdr->SAbbrevCtryISO;
  1026. break;
  1027. }
  1028. case ( LOCALE_SNATIVECTRYNAME ) :
  1029. {
  1030. pString = pStart + pHashN->pLocaleHdr->SNativeCtry;
  1031. break;
  1032. }
  1033. case ( LOCALE_IGEOID ) :
  1034. {
  1035. Base = 10;
  1036. pString = pHashN->pLocaleFixed->szIGeoID;
  1037. break;
  1038. }
  1039. case ( LOCALE_SSORTNAME ) :
  1040. {
  1041. //
  1042. // Get the information from the RC file.
  1043. //
  1044. Length = GetStringTableEntry( LANGIDFROMLCID(Locale),
  1045. 0,
  1046. pTemp,
  1047. MAX_REG_VAL_SIZE,
  1048. RC_SORT_NAMES + SORTIDFROMLCID(Locale) );
  1049. if (Length == 0)
  1050. {
  1051. //
  1052. // If the sort name doesn't exist for the given locale id,
  1053. // then try to get the Default name. This is stored in the
  1054. // 0x0000 entry.
  1055. //
  1056. Length = GetStringTableEntry( 0x0000,
  1057. 0,
  1058. pTemp,
  1059. MAX_REG_VAL_SIZE,
  1060. RC_SORT_NAMES + SORTIDFROMLCID(Locale) );
  1061. if (Length == 0)
  1062. {
  1063. SetLastError(ERROR_INVALID_PARAMETER);
  1064. return (0);
  1065. }
  1066. }
  1067. pString = pTemp;
  1068. break;
  1069. }
  1070. case ( LOCALE_IDEFAULTLANGUAGE ) :
  1071. {
  1072. Base = 16;
  1073. pString = pHashN->pLocaleFixed->szIDefaultLang;
  1074. break;
  1075. }
  1076. case ( LOCALE_IDEFAULTCOUNTRY ) :
  1077. {
  1078. Base = 10;
  1079. pString = pHashN->pLocaleFixed->szIDefaultCtry;
  1080. break;
  1081. }
  1082. case ( LOCALE_IDEFAULTANSICODEPAGE ) :
  1083. {
  1084. if (ReturnNum)
  1085. {
  1086. if (cchData < 2)
  1087. {
  1088. if (cchData == 0)
  1089. {
  1090. //
  1091. // DWORD is needed for this option (2 WORDS),
  1092. // so return 2.
  1093. //
  1094. return (2);
  1095. }
  1096. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  1097. return (0);
  1098. }
  1099. //
  1100. // Copy the value to lpLCData and return 2
  1101. // (2 WORDS = 1 DWORD).
  1102. //
  1103. *((LPDWORD)lpLCData) = (DWORD)(pHashN->pLocaleFixed->DefaultACP);
  1104. return (2);
  1105. }
  1106. pString = pHashN->pLocaleFixed->szIDefaultACP;
  1107. break;
  1108. }
  1109. case ( LOCALE_IDEFAULTCODEPAGE ) :
  1110. {
  1111. Base = 10;
  1112. pString = pHashN->pLocaleFixed->szIDefaultOCP;
  1113. break;
  1114. }
  1115. case ( LOCALE_IDEFAULTMACCODEPAGE ) :
  1116. {
  1117. Base = 10;
  1118. pString = pHashN->pLocaleFixed->szIDefaultMACCP;
  1119. break;
  1120. }
  1121. case ( LOCALE_IDEFAULTEBCDICCODEPAGE ) :
  1122. {
  1123. Base = 10;
  1124. pString = pHashN->pLocaleFixed->szIDefaultEBCDICCP;
  1125. break;
  1126. }
  1127. case ( LOCALE_SLIST ) :
  1128. {
  1129. if (UserOverride &&
  1130. GetUserInfo( Locale,
  1131. LCType,
  1132. FIELD_OFFSET(NLS_USER_INFO, sList),
  1133. NLS_VALUE_SLIST,
  1134. pTemp,
  1135. ARRAYSIZE(pTemp),
  1136. FALSE ))
  1137. {
  1138. pString = pTemp;
  1139. }
  1140. else
  1141. {
  1142. pString = pStart + pHashN->pLocaleHdr->SList;
  1143. }
  1144. break;
  1145. }
  1146. case ( LOCALE_IMEASURE ) :
  1147. {
  1148. Base = 10;
  1149. if (UserOverride &&
  1150. GetUserInfo( Locale,
  1151. LCType,
  1152. FIELD_OFFSET(NLS_USER_INFO, iMeasure),
  1153. NLS_VALUE_IMEASURE,
  1154. pTemp,
  1155. ARRAYSIZE(pTemp),
  1156. TRUE ))
  1157. {
  1158. pString = pTemp;
  1159. }
  1160. else
  1161. {
  1162. pString = pHashN->pLocaleFixed->szIMeasure;
  1163. }
  1164. break;
  1165. }
  1166. case ( LOCALE_IPAPERSIZE ) :
  1167. {
  1168. Base = 10;
  1169. if (UserOverride &&
  1170. GetUserInfo( Locale,
  1171. LCType,
  1172. FIELD_OFFSET(NLS_USER_INFO, iPaperSize),
  1173. NLS_VALUE_IPAPERSIZE,
  1174. pTemp,
  1175. ARRAYSIZE(pTemp),
  1176. TRUE ))
  1177. {
  1178. pString = pTemp;
  1179. }
  1180. else
  1181. {
  1182. pString = pHashN->pLocaleFixed->szIPaperSize;
  1183. }
  1184. break;
  1185. }
  1186. case ( LOCALE_SDECIMAL ) :
  1187. {
  1188. if (UserOverride &&
  1189. GetUserInfo( Locale,
  1190. LCType,
  1191. FIELD_OFFSET(NLS_USER_INFO, sDecimal),
  1192. NLS_VALUE_SDECIMAL,
  1193. pTemp,
  1194. ARRAYSIZE(pTemp),
  1195. FALSE ))
  1196. {
  1197. pString = pTemp;
  1198. }
  1199. else
  1200. {
  1201. pString = pStart + pHashN->pLocaleHdr->SDecimal;
  1202. }
  1203. break;
  1204. }
  1205. case ( LOCALE_STHOUSAND ) :
  1206. {
  1207. if (UserOverride &&
  1208. GetUserInfo( Locale,
  1209. LCType,
  1210. FIELD_OFFSET(NLS_USER_INFO, sThousand),
  1211. NLS_VALUE_STHOUSAND,
  1212. pTemp,
  1213. ARRAYSIZE(pTemp),
  1214. FALSE ))
  1215. {
  1216. pString = pTemp;
  1217. }
  1218. else
  1219. {
  1220. pString = pStart + pHashN->pLocaleHdr->SThousand;
  1221. }
  1222. break;
  1223. }
  1224. case ( LOCALE_SGROUPING ) :
  1225. {
  1226. if (UserOverride &&
  1227. GetUserInfo( Locale,
  1228. LCType,
  1229. FIELD_OFFSET(NLS_USER_INFO, sGrouping),
  1230. NLS_VALUE_SGROUPING,
  1231. pTemp,
  1232. ARRAYSIZE(pTemp),
  1233. TRUE ))
  1234. {
  1235. pString = pTemp;
  1236. }
  1237. else
  1238. {
  1239. pString = pStart + pHashN->pLocaleHdr->SGrouping;
  1240. }
  1241. break;
  1242. }
  1243. case ( LOCALE_IDIGITS ) :
  1244. {
  1245. Base = 10;
  1246. if (UserOverride &&
  1247. GetUserInfo( Locale,
  1248. LCType,
  1249. FIELD_OFFSET(NLS_USER_INFO, iDigits),
  1250. NLS_VALUE_IDIGITS,
  1251. pTemp,
  1252. ARRAYSIZE(pTemp),
  1253. TRUE ))
  1254. {
  1255. pString = pTemp;
  1256. }
  1257. else
  1258. {
  1259. pString = pHashN->pLocaleFixed->szIDigits;
  1260. }
  1261. break;
  1262. }
  1263. case ( LOCALE_ILZERO ) :
  1264. {
  1265. Base = 10;
  1266. if (UserOverride &&
  1267. GetUserInfo( Locale,
  1268. LCType,
  1269. FIELD_OFFSET(NLS_USER_INFO, iLZero),
  1270. NLS_VALUE_ILZERO,
  1271. pTemp,
  1272. ARRAYSIZE(pTemp),
  1273. TRUE ))
  1274. {
  1275. pString = pTemp;
  1276. }
  1277. else
  1278. {
  1279. pString = pHashN->pLocaleFixed->szILZero;
  1280. }
  1281. break;
  1282. }
  1283. case ( LOCALE_INEGNUMBER ) :
  1284. {
  1285. Base = 10;
  1286. if (UserOverride &&
  1287. GetUserInfo( Locale,
  1288. LCType,
  1289. FIELD_OFFSET(NLS_USER_INFO, iNegNumber),
  1290. NLS_VALUE_INEGNUMBER,
  1291. pTemp,
  1292. ARRAYSIZE(pTemp),
  1293. TRUE ))
  1294. {
  1295. pString = pTemp;
  1296. }
  1297. else
  1298. {
  1299. pString = pHashN->pLocaleFixed->szINegNumber;
  1300. }
  1301. break;
  1302. }
  1303. case ( LOCALE_SNATIVEDIGITS ) :
  1304. {
  1305. if (UserOverride &&
  1306. GetUserInfo( Locale,
  1307. LCType,
  1308. FIELD_OFFSET(NLS_USER_INFO, sNativeDigits),
  1309. NLS_VALUE_SNATIVEDIGITS,
  1310. pTemp,
  1311. ARRAYSIZE(pTemp),
  1312. FALSE ))
  1313. {
  1314. pString = pTemp;
  1315. }
  1316. else
  1317. {
  1318. pString = pStart + pHashN->pLocaleHdr->SNativeDigits;
  1319. }
  1320. break;
  1321. }
  1322. case ( LOCALE_IDIGITSUBSTITUTION ) :
  1323. {
  1324. Base = 10;
  1325. if (UserOverride &&
  1326. GetUserInfo( Locale,
  1327. LCType,
  1328. FIELD_OFFSET(NLS_USER_INFO, iDigitSubstitution),
  1329. NLS_VALUE_IDIGITSUBST,
  1330. pTemp,
  1331. ARRAYSIZE(pTemp),
  1332. TRUE ))
  1333. {
  1334. pString = pTemp;
  1335. }
  1336. else
  1337. {
  1338. pString = pHashN->pLocaleFixed->szIDigitSubstitution;
  1339. }
  1340. break;
  1341. }
  1342. case ( LOCALE_SCURRENCY ) :
  1343. {
  1344. if (UserOverride &&
  1345. GetUserInfo( Locale,
  1346. LCType,
  1347. FIELD_OFFSET(NLS_USER_INFO, sCurrency),
  1348. NLS_VALUE_SCURRENCY,
  1349. pTemp,
  1350. ARRAYSIZE(pTemp),
  1351. FALSE ))
  1352. {
  1353. pString = pTemp;
  1354. }
  1355. else
  1356. {
  1357. pString = pStart + pHashN->pLocaleHdr->SCurrency;
  1358. }
  1359. break;
  1360. }
  1361. case ( LOCALE_SINTLSYMBOL ) :
  1362. {
  1363. pString = pStart + pHashN->pLocaleHdr->SIntlSymbol;
  1364. break;
  1365. }
  1366. case ( LOCALE_SENGCURRNAME ) :
  1367. {
  1368. pString = pStart + pHashN->pLocaleHdr->SEngCurrName;
  1369. break;
  1370. }
  1371. case ( LOCALE_SNATIVECURRNAME ) :
  1372. {
  1373. pString = pStart + pHashN->pLocaleHdr->SNativeCurrName;
  1374. break;
  1375. }
  1376. case ( LOCALE_SMONDECIMALSEP ) :
  1377. {
  1378. if (UserOverride &&
  1379. GetUserInfo( Locale,
  1380. LCType,
  1381. FIELD_OFFSET(NLS_USER_INFO, sMonDecSep),
  1382. NLS_VALUE_SMONDECIMALSEP,
  1383. pTemp,
  1384. ARRAYSIZE(pTemp),
  1385. FALSE ))
  1386. {
  1387. pString = pTemp;
  1388. }
  1389. else
  1390. {
  1391. pString = pStart + pHashN->pLocaleHdr->SMonDecSep;
  1392. }
  1393. break;
  1394. }
  1395. case ( LOCALE_SMONTHOUSANDSEP ) :
  1396. {
  1397. if (UserOverride &&
  1398. GetUserInfo( Locale,
  1399. LCType,
  1400. FIELD_OFFSET(NLS_USER_INFO, sMonThouSep),
  1401. NLS_VALUE_SMONTHOUSANDSEP,
  1402. pTemp,
  1403. ARRAYSIZE(pTemp),
  1404. FALSE ))
  1405. {
  1406. pString = pTemp;
  1407. }
  1408. else
  1409. {
  1410. pString = pStart + pHashN->pLocaleHdr->SMonThousSep;
  1411. }
  1412. break;
  1413. }
  1414. case ( LOCALE_SMONGROUPING ) :
  1415. {
  1416. if (UserOverride &&
  1417. GetUserInfo( Locale,
  1418. LCType,
  1419. FIELD_OFFSET(NLS_USER_INFO, sMonGrouping),
  1420. NLS_VALUE_SMONGROUPING,
  1421. pTemp,
  1422. ARRAYSIZE(pTemp),
  1423. TRUE ))
  1424. {
  1425. pString = pTemp;
  1426. }
  1427. else
  1428. {
  1429. pString = pStart + pHashN->pLocaleHdr->SMonGrouping;
  1430. }
  1431. break;
  1432. }
  1433. case ( LOCALE_ICURRDIGITS ) :
  1434. {
  1435. Base = 10;
  1436. if (UserOverride &&
  1437. GetUserInfo( Locale,
  1438. LCType,
  1439. FIELD_OFFSET(NLS_USER_INFO, iCurrDigits),
  1440. NLS_VALUE_ICURRDIGITS,
  1441. pTemp,
  1442. ARRAYSIZE(pTemp),
  1443. TRUE ))
  1444. {
  1445. pString = pTemp;
  1446. }
  1447. else
  1448. {
  1449. pString = pHashN->pLocaleFixed->szICurrDigits;
  1450. }
  1451. break;
  1452. }
  1453. case ( LOCALE_IINTLCURRDIGITS ) :
  1454. {
  1455. Base = 10;
  1456. pString = pHashN->pLocaleFixed->szIIntlCurrDigits;
  1457. break;
  1458. }
  1459. case ( LOCALE_ICURRENCY ) :
  1460. {
  1461. Base = 10;
  1462. if (UserOverride &&
  1463. GetUserInfo( Locale,
  1464. LCType,
  1465. FIELD_OFFSET(NLS_USER_INFO, iCurrency),
  1466. NLS_VALUE_ICURRENCY,
  1467. pTemp,
  1468. ARRAYSIZE(pTemp),
  1469. TRUE ))
  1470. {
  1471. pString = pTemp;
  1472. }
  1473. else
  1474. {
  1475. pString = pHashN->pLocaleFixed->szICurrency;
  1476. }
  1477. break;
  1478. }
  1479. case ( LOCALE_INEGCURR ) :
  1480. {
  1481. Base = 10;
  1482. if (UserOverride &&
  1483. GetUserInfo( Locale,
  1484. LCType,
  1485. FIELD_OFFSET(NLS_USER_INFO, iNegCurr),
  1486. NLS_VALUE_INEGCURR,
  1487. pTemp,
  1488. ARRAYSIZE(pTemp),
  1489. TRUE ))
  1490. {
  1491. pString = pTemp;
  1492. }
  1493. else
  1494. {
  1495. pString = pHashN->pLocaleFixed->szINegCurr;
  1496. }
  1497. break;
  1498. }
  1499. case ( LOCALE_SPOSITIVESIGN ) :
  1500. {
  1501. if (UserOverride &&
  1502. GetUserInfo( Locale,
  1503. LCType,
  1504. FIELD_OFFSET(NLS_USER_INFO, sPosSign),
  1505. NLS_VALUE_SPOSITIVESIGN,
  1506. pTemp,
  1507. ARRAYSIZE(pTemp),
  1508. FALSE ))
  1509. {
  1510. pString = pTemp;
  1511. }
  1512. else
  1513. {
  1514. pString = pStart + pHashN->pLocaleHdr->SPositiveSign;
  1515. }
  1516. break;
  1517. }
  1518. case ( LOCALE_SNEGATIVESIGN ) :
  1519. {
  1520. if (UserOverride &&
  1521. GetUserInfo( Locale,
  1522. LCType,
  1523. FIELD_OFFSET(NLS_USER_INFO, sNegSign),
  1524. NLS_VALUE_SNEGATIVESIGN,
  1525. pTemp,
  1526. ARRAYSIZE(pTemp),
  1527. FALSE ))
  1528. {
  1529. pString = pTemp;
  1530. }
  1531. else
  1532. {
  1533. pString = pStart + pHashN->pLocaleHdr->SNegativeSign;
  1534. }
  1535. break;
  1536. }
  1537. case ( LOCALE_IPOSSIGNPOSN ) :
  1538. {
  1539. //
  1540. // Since there is no positive sign in any of the ICURRENCY
  1541. // options, use the INEGCURR options instead. All known
  1542. // locales would use the positive sign in the same position
  1543. // as the negative sign.
  1544. //
  1545. // NOTE: For the 2 options that use parenthesis, put the
  1546. // positive sign at the beginning of the string
  1547. // (where the opening parenthesis is).
  1548. //
  1549. // 1 => 4, 5, 8, 15
  1550. // 2 => 3, 11
  1551. // 3 => 0, 1, 6, 9, 13, 14
  1552. // 4 => 2, 7, 10, 12
  1553. //
  1554. Base = 10;
  1555. if (UserOverride &&
  1556. GetUserInfo( Locale,
  1557. LCType,
  1558. FIELD_OFFSET(NLS_USER_INFO, iNegCurr),
  1559. NLS_VALUE_INEGCURR,
  1560. pTemp,
  1561. ARRAYSIZE(pTemp),
  1562. TRUE ))
  1563. {
  1564. pString = pTemp;
  1565. //
  1566. // Set the appropriate value in pString.
  1567. //
  1568. switch (*pString)
  1569. {
  1570. case ( L'4' ) :
  1571. case ( L'5' ) :
  1572. case ( L'8' ) :
  1573. {
  1574. *pString = L'1';
  1575. *(pString + 1) = 0;
  1576. break;
  1577. }
  1578. case ( L'3' ) :
  1579. {
  1580. *pString = L'2';
  1581. *(pString + 1) = 0;
  1582. break;
  1583. }
  1584. case ( L'0' ) :
  1585. case ( L'6' ) :
  1586. case ( L'9' ) :
  1587. {
  1588. *pString = L'3';
  1589. *(pString + 1) = 0;
  1590. break;
  1591. }
  1592. case ( L'2' ) :
  1593. case ( L'7' ) :
  1594. {
  1595. *pString = L'4';
  1596. *(pString + 1) = 0;
  1597. break;
  1598. }
  1599. case ( L'1' ) :
  1600. {
  1601. switch (*(pString + 1))
  1602. {
  1603. case ( 0 ) :
  1604. case ( L'3' ) :
  1605. case ( L'4' ) :
  1606. default :
  1607. {
  1608. *pString = L'3';
  1609. *(pString + 1) = 0;
  1610. break;
  1611. }
  1612. case ( L'0' ) :
  1613. case ( L'2' ) :
  1614. {
  1615. *pString = L'4';
  1616. *(pString + 1) = 0;
  1617. break;
  1618. }
  1619. case ( L'1' ) :
  1620. {
  1621. *pString = L'2';
  1622. *(pString + 1) = 0;
  1623. break;
  1624. }
  1625. case ( L'5' ) :
  1626. {
  1627. *pString = L'1';
  1628. *(pString + 1) = 0;
  1629. break;
  1630. }
  1631. }
  1632. break;
  1633. }
  1634. default :
  1635. {
  1636. pString = pHashN->pLocaleFixed->szIPosSignPosn;
  1637. break;
  1638. }
  1639. }
  1640. }
  1641. else
  1642. {
  1643. pString = pHashN->pLocaleFixed->szIPosSignPosn;
  1644. }
  1645. break;
  1646. }
  1647. case ( LOCALE_INEGSIGNPOSN ) :
  1648. {
  1649. //
  1650. // Use the INEGCURR value from the user portion of the
  1651. // registry, if it exists.
  1652. //
  1653. // 0 => 0, 4, 14, 15
  1654. // 1 => 5, 8
  1655. // 2 => 3, 11
  1656. // 3 => 1, 6, 9, 13
  1657. // 4 => 2, 7, 10, 12
  1658. //
  1659. Base = 10;
  1660. if (UserOverride &&
  1661. GetUserInfo( Locale,
  1662. LCType,
  1663. FIELD_OFFSET(NLS_USER_INFO, iNegCurr),
  1664. NLS_VALUE_INEGCURR,
  1665. pTemp,
  1666. ARRAYSIZE(pTemp),
  1667. TRUE ))
  1668. {
  1669. pString = pTemp;
  1670. //
  1671. // Set the appropriate value in pString.
  1672. //
  1673. switch (*pString)
  1674. {
  1675. case ( L'0' ) :
  1676. case ( L'4' ) :
  1677. {
  1678. *pString = L'0';
  1679. *(pString + 1) = 0;
  1680. break;
  1681. }
  1682. case ( L'5' ) :
  1683. case ( L'8' ) :
  1684. {
  1685. *pString = L'1';
  1686. *(pString + 1) = 0;
  1687. break;
  1688. }
  1689. case ( L'3' ) :
  1690. {
  1691. *pString = L'2';
  1692. *(pString + 1) = 0;
  1693. break;
  1694. }
  1695. case ( L'6' ) :
  1696. case ( L'9' ) :
  1697. {
  1698. *pString = L'3';
  1699. *(pString + 1) = 0;
  1700. break;
  1701. }
  1702. case ( L'2' ) :
  1703. case ( L'7' ) :
  1704. {
  1705. *pString = L'4';
  1706. *(pString + 1) = 0;
  1707. break;
  1708. }
  1709. case ( L'1' ) :
  1710. {
  1711. switch (*(pString + 1))
  1712. {
  1713. case ( 0 ) :
  1714. case ( L'3' ) :
  1715. default :
  1716. {
  1717. *pString = L'3';
  1718. *(pString + 1) = 0;
  1719. break;
  1720. }
  1721. case ( L'0' ) :
  1722. case ( L'2' ) :
  1723. {
  1724. *pString = L'4';
  1725. *(pString + 1) = 0;
  1726. break;
  1727. }
  1728. case ( L'1' ) :
  1729. {
  1730. *pString = L'2';
  1731. *(pString + 1) = 0;
  1732. break;
  1733. }
  1734. case ( L'4' ) :
  1735. case ( L'5' ) :
  1736. {
  1737. *pString = L'0';
  1738. *(pString + 1) = 0;
  1739. break;
  1740. }
  1741. }
  1742. break;
  1743. }
  1744. default :
  1745. {
  1746. pString = pHashN->pLocaleFixed->szINegSignPosn;
  1747. break;
  1748. }
  1749. }
  1750. }
  1751. else
  1752. {
  1753. pString = pHashN->pLocaleFixed->szINegSignPosn;
  1754. }
  1755. break;
  1756. }
  1757. case ( LOCALE_IPOSSYMPRECEDES ) :
  1758. {
  1759. //
  1760. // Use the ICURRENCY value from the user portion of the
  1761. // registry, if it exists.
  1762. //
  1763. // 0 => 1, 3
  1764. // 1 => 0, 2
  1765. //
  1766. Base = 10;
  1767. if (UserOverride &&
  1768. GetUserInfo( Locale,
  1769. LCType,
  1770. FIELD_OFFSET(NLS_USER_INFO, iCurrency),
  1771. NLS_VALUE_ICURRENCY,
  1772. pTemp,
  1773. ARRAYSIZE(pTemp),
  1774. TRUE ))
  1775. {
  1776. pString = pTemp;
  1777. //
  1778. // Set the appropriate value in pString.
  1779. //
  1780. switch (*pString)
  1781. {
  1782. case ( L'1' ) :
  1783. case ( L'3' ) :
  1784. {
  1785. *pString = L'0';
  1786. *(pString + 1) = 0;
  1787. break;
  1788. }
  1789. case ( L'0' ) :
  1790. case ( L'2' ) :
  1791. {
  1792. *pString = L'1';
  1793. *(pString + 1) = 0;
  1794. break;
  1795. }
  1796. default :
  1797. {
  1798. pString = pHashN->pLocaleFixed->szIPosSymPrecedes;
  1799. break;
  1800. }
  1801. }
  1802. }
  1803. else
  1804. {
  1805. pString = pHashN->pLocaleFixed->szIPosSymPrecedes;
  1806. }
  1807. break;
  1808. }
  1809. case ( LOCALE_IPOSSEPBYSPACE ) :
  1810. {
  1811. //
  1812. // Use the ICURRENCY value from the user portion of the
  1813. // registry, if it exists.
  1814. //
  1815. // 0 => 0, 1
  1816. // 1 => 2, 3
  1817. //
  1818. Base = 10;
  1819. if (UserOverride &&
  1820. GetUserInfo( Locale,
  1821. LCType,
  1822. FIELD_OFFSET(NLS_USER_INFO, iCurrency),
  1823. NLS_VALUE_ICURRENCY,
  1824. pTemp,
  1825. ARRAYSIZE(pTemp),
  1826. TRUE ))
  1827. {
  1828. pString = pTemp;
  1829. //
  1830. // Set the appropriate value in pString.
  1831. //
  1832. switch (*pString)
  1833. {
  1834. case ( L'0' ) :
  1835. case ( L'1' ) :
  1836. {
  1837. *pString = L'0';
  1838. *(pString + 1) = 0;
  1839. break;
  1840. }
  1841. case ( L'2' ) :
  1842. case ( L'3' ) :
  1843. {
  1844. *pString = L'1';
  1845. *(pString + 1) = 0;
  1846. break;
  1847. }
  1848. default :
  1849. {
  1850. pString = pHashN->pLocaleFixed->szIPosSepBySpace;
  1851. break;
  1852. }
  1853. }
  1854. }
  1855. else
  1856. {
  1857. pString = pHashN->pLocaleFixed->szIPosSepBySpace;
  1858. }
  1859. break;
  1860. }
  1861. case ( LOCALE_INEGSYMPRECEDES ) :
  1862. {
  1863. //
  1864. // Use the INEGCURR value from the user portion of the
  1865. // registry, if it exists.
  1866. //
  1867. // 0 => 4, 5, 6, 7, 8, 10, 13, 15
  1868. // 1 => 0, 1, 2, 3, 9, 11, 12, 14
  1869. //
  1870. Base = 10;
  1871. if (UserOverride &&
  1872. GetUserInfo( Locale,
  1873. LCType,
  1874. FIELD_OFFSET(NLS_USER_INFO, iNegCurr),
  1875. NLS_VALUE_INEGCURR,
  1876. pTemp,
  1877. ARRAYSIZE(pTemp),
  1878. TRUE ))
  1879. {
  1880. pString = pTemp;
  1881. //
  1882. // Set the appropriate value in pString.
  1883. //
  1884. switch (*pString)
  1885. {
  1886. case ( L'4' ) :
  1887. case ( L'5' ) :
  1888. case ( L'6' ) :
  1889. case ( L'7' ) :
  1890. case ( L'8' ) :
  1891. {
  1892. *pString = L'0';
  1893. *(pString + 1) = 0;
  1894. break;
  1895. }
  1896. case ( L'0' ) :
  1897. case ( L'2' ) :
  1898. case ( L'3' ) :
  1899. case ( L'9' ) :
  1900. {
  1901. *pString = L'1';
  1902. *(pString + 1) = 0;
  1903. break;
  1904. }
  1905. case ( L'1' ) :
  1906. {
  1907. if ((*(pString + 1) == L'0') ||
  1908. (*(pString + 1) == L'3') ||
  1909. (*(pString + 1) == L'5'))
  1910. {
  1911. *pString = L'0';
  1912. *(pString + 1) = 0;
  1913. }
  1914. else
  1915. {
  1916. *pString = L'1';
  1917. *(pString + 1) = 0;
  1918. }
  1919. break;
  1920. }
  1921. default :
  1922. {
  1923. pString = pHashN->pLocaleFixed->szINegSymPrecedes;
  1924. break;
  1925. }
  1926. }
  1927. }
  1928. else
  1929. {
  1930. pString = pHashN->pLocaleFixed->szINegSymPrecedes;
  1931. }
  1932. break;
  1933. }
  1934. case ( LOCALE_INEGSEPBYSPACE ) :
  1935. {
  1936. //
  1937. // Use the INEGCURR value from the user portion of the
  1938. // registry, if it exists.
  1939. //
  1940. // 0 => 0, 1, 2, 3, 4, 5, 6, 7
  1941. // 1 => 8, 9, 10, 11, 12, 13, 14, 15
  1942. //
  1943. Base = 10;
  1944. if (UserOverride &&
  1945. GetUserInfo( Locale,
  1946. LCType,
  1947. FIELD_OFFSET(NLS_USER_INFO, iNegCurr),
  1948. NLS_VALUE_INEGCURR,
  1949. pTemp,
  1950. ARRAYSIZE(pTemp),
  1951. TRUE ))
  1952. {
  1953. pString = pTemp;
  1954. //
  1955. // Set the appropriate value in pString.
  1956. //
  1957. switch (*pString)
  1958. {
  1959. case ( L'0' ) :
  1960. case ( L'2' ) :
  1961. case ( L'3' ) :
  1962. case ( L'4' ) :
  1963. case ( L'5' ) :
  1964. case ( L'6' ) :
  1965. case ( L'7' ) :
  1966. {
  1967. *pString = L'0';
  1968. *(pString + 1) = 0;
  1969. break;
  1970. }
  1971. case ( L'8' ) :
  1972. case ( L'9' ) :
  1973. {
  1974. *pString = L'1';
  1975. *(pString + 1) = 0;
  1976. break;
  1977. }
  1978. case ( L'1' ) :
  1979. {
  1980. if (*(pString + 1) == 0)
  1981. {
  1982. *pString = L'0';
  1983. *(pString + 1) = 0;
  1984. }
  1985. else
  1986. {
  1987. *pString = L'1';
  1988. *(pString + 1) = 0;
  1989. }
  1990. break;
  1991. }
  1992. default :
  1993. {
  1994. pString = pHashN->pLocaleFixed->szINegSepBySpace;
  1995. break;
  1996. }
  1997. }
  1998. }
  1999. else
  2000. {
  2001. pString = pHashN->pLocaleFixed->szINegSepBySpace;
  2002. }
  2003. break;
  2004. }
  2005. case ( LOCALE_STIMEFORMAT ) :
  2006. {
  2007. if (UserOverride &&
  2008. GetUserInfo( Locale,
  2009. LCType,
  2010. FIELD_OFFSET(NLS_USER_INFO, sTimeFormat),
  2011. NLS_VALUE_STIMEFORMAT,
  2012. pTemp,
  2013. ARRAYSIZE(pTemp),
  2014. TRUE ))
  2015. {
  2016. pString = pTemp;
  2017. }
  2018. else
  2019. {
  2020. pString = pStart + pHashN->pLocaleHdr->STimeFormat;
  2021. }
  2022. break;
  2023. }
  2024. case ( LOCALE_STIME ) :
  2025. {
  2026. if (UserOverride &&
  2027. GetUserInfo( Locale,
  2028. LCType,
  2029. FIELD_OFFSET(NLS_USER_INFO, sTime),
  2030. NLS_VALUE_STIME,
  2031. pTemp,
  2032. ARRAYSIZE(pTemp),
  2033. TRUE ))
  2034. {
  2035. pString = pTemp;
  2036. }
  2037. else
  2038. {
  2039. pString = pStart + pHashN->pLocaleHdr->STime;
  2040. }
  2041. break;
  2042. }
  2043. case ( LOCALE_ITIME ) :
  2044. {
  2045. Base = 10;
  2046. if (UserOverride &&
  2047. GetUserInfo( Locale,
  2048. LCType,
  2049. FIELD_OFFSET(NLS_USER_INFO, iTime),
  2050. NLS_VALUE_ITIME,
  2051. pTemp,
  2052. ARRAYSIZE(pTemp),
  2053. TRUE ))
  2054. {
  2055. pString = pTemp;
  2056. }
  2057. else
  2058. {
  2059. pString = pHashN->pLocaleFixed->szITime;
  2060. }
  2061. break;
  2062. }
  2063. case ( LOCALE_ITLZERO ) :
  2064. {
  2065. Base = 10;
  2066. if (UserOverride &&
  2067. GetUserInfo( Locale,
  2068. LCType,
  2069. FIELD_OFFSET(NLS_USER_INFO, iTLZero),
  2070. NLS_VALUE_ITLZERO,
  2071. pTemp,
  2072. ARRAYSIZE(pTemp),
  2073. TRUE ))
  2074. {
  2075. pString = pTemp;
  2076. }
  2077. else
  2078. {
  2079. pString = pHashN->pLocaleFixed->szITLZero;
  2080. }
  2081. break;
  2082. }
  2083. case ( LOCALE_ITIMEMARKPOSN ) :
  2084. {
  2085. Base = 10;
  2086. if (UserOverride &&
  2087. GetUserInfo( Locale,
  2088. LCType,
  2089. FIELD_OFFSET(NLS_USER_INFO, iTimeMarkPosn),
  2090. NLS_VALUE_ITIMEMARKPOSN,
  2091. pTemp,
  2092. ARRAYSIZE(pTemp),
  2093. TRUE ))
  2094. {
  2095. pString = pTemp;
  2096. }
  2097. else
  2098. {
  2099. pString = pHashN->pLocaleFixed->szITimeMarkPosn;
  2100. }
  2101. break;
  2102. }
  2103. case ( LOCALE_S1159 ) :
  2104. {
  2105. if (UserOverride &&
  2106. GetUserInfo( Locale,
  2107. LCType,
  2108. FIELD_OFFSET(NLS_USER_INFO, s1159),
  2109. NLS_VALUE_S1159,
  2110. pTemp,
  2111. ARRAYSIZE(pTemp),
  2112. FALSE ))
  2113. {
  2114. pString = pTemp;
  2115. }
  2116. else
  2117. {
  2118. pString = pStart + pHashN->pLocaleHdr->S1159;
  2119. }
  2120. break;
  2121. }
  2122. case ( LOCALE_S2359 ) :
  2123. {
  2124. if (UserOverride &&
  2125. GetUserInfo( Locale,
  2126. LCType,
  2127. FIELD_OFFSET(NLS_USER_INFO, s2359),
  2128. NLS_VALUE_S2359,
  2129. pTemp,
  2130. ARRAYSIZE(pTemp),
  2131. FALSE ))
  2132. {
  2133. pString = pTemp;
  2134. }
  2135. else
  2136. {
  2137. pString = pStart + pHashN->pLocaleHdr->S2359;
  2138. }
  2139. break;
  2140. }
  2141. case ( LOCALE_SSHORTDATE ) :
  2142. {
  2143. if (UserOverride &&
  2144. GetUserInfo( Locale,
  2145. LCType,
  2146. FIELD_OFFSET(NLS_USER_INFO, sShortDate),
  2147. NLS_VALUE_SSHORTDATE,
  2148. pTemp,
  2149. ARRAYSIZE(pTemp),
  2150. TRUE ))
  2151. {
  2152. pString = pTemp;
  2153. }
  2154. else
  2155. {
  2156. pString = pStart + pHashN->pLocaleHdr->SShortDate;
  2157. }
  2158. break;
  2159. }
  2160. case ( LOCALE_SDATE ) :
  2161. {
  2162. if (UserOverride &&
  2163. GetUserInfo( Locale,
  2164. LCType,
  2165. FIELD_OFFSET(NLS_USER_INFO, sDate),
  2166. NLS_VALUE_SDATE,
  2167. pTemp,
  2168. ARRAYSIZE(pTemp),
  2169. TRUE ))
  2170. {
  2171. pString = pTemp;
  2172. }
  2173. else
  2174. {
  2175. pString = pStart + pHashN->pLocaleHdr->SDate;
  2176. }
  2177. break;
  2178. }
  2179. case ( LOCALE_IDATE ) :
  2180. {
  2181. Base = 10;
  2182. if (UserOverride &&
  2183. GetUserInfo( Locale,
  2184. LCType,
  2185. FIELD_OFFSET(NLS_USER_INFO, iDate),
  2186. NLS_VALUE_IDATE,
  2187. pTemp,
  2188. ARRAYSIZE(pTemp),
  2189. TRUE ))
  2190. {
  2191. pString = pTemp;
  2192. }
  2193. else
  2194. {
  2195. pString = pHashN->pLocaleFixed->szIDate;
  2196. }
  2197. break;
  2198. }
  2199. case ( LOCALE_ICENTURY ) :
  2200. {
  2201. //
  2202. // Use the short date picture to get this information.
  2203. //
  2204. Base = 10;
  2205. if (UserOverride &&
  2206. GetUserInfo( Locale,
  2207. LCType,
  2208. FIELD_OFFSET(NLS_USER_INFO, sShortDate),
  2209. NLS_VALUE_SSHORTDATE,
  2210. pTemp,
  2211. ARRAYSIZE(pTemp),
  2212. TRUE ))
  2213. {
  2214. pString = pTemp;
  2215. //
  2216. // Find out how many y's in string.
  2217. // No need to ignore quotes in short date.
  2218. //
  2219. pTmp = pString;
  2220. while ((*pTmp) &&
  2221. (*pTmp != L'y'))
  2222. {
  2223. pTmp++;
  2224. }
  2225. //
  2226. // Set the appropriate value in pString.
  2227. //
  2228. if (*pTmp == L'y')
  2229. {
  2230. //
  2231. // Get the number of 'y' repetitions in the format string.
  2232. //
  2233. pTmp++;
  2234. for (Repeat = 0; (*pTmp == L'y'); Repeat++, pTmp++)
  2235. ;
  2236. switch (Repeat)
  2237. {
  2238. case ( 0 ) :
  2239. case ( 1 ) :
  2240. {
  2241. //
  2242. // Two-digit century with leading zero.
  2243. //
  2244. *pString = L'0';
  2245. *(pString + 1) = 0;
  2246. break;
  2247. }
  2248. case ( 2 ) :
  2249. case ( 3 ) :
  2250. default :
  2251. {
  2252. //
  2253. // Full century.
  2254. //
  2255. *pString = L'1';
  2256. *(pString + 1) = 0;
  2257. break;
  2258. }
  2259. }
  2260. break;
  2261. }
  2262. }
  2263. //
  2264. // Use the system default value.
  2265. //
  2266. pString = pHashN->pLocaleFixed->szICentury;
  2267. break;
  2268. }
  2269. case ( LOCALE_IDAYLZERO ) :
  2270. {
  2271. //
  2272. // Use the short date picture to get this information.
  2273. //
  2274. Base = 10;
  2275. if (UserOverride &&
  2276. GetUserInfo( Locale,
  2277. LCType,
  2278. FIELD_OFFSET(NLS_USER_INFO, sShortDate),
  2279. NLS_VALUE_SSHORTDATE,
  2280. pTemp,
  2281. ARRAYSIZE(pTemp),
  2282. TRUE ))
  2283. {
  2284. pString = pTemp;
  2285. //
  2286. // Find out how many d's in string.
  2287. // No need to ignore quotes in short date.
  2288. //
  2289. pTmp = pString;
  2290. while ((*pTmp) &&
  2291. (*pTmp != L'd'))
  2292. {
  2293. pTmp++;
  2294. }
  2295. //
  2296. // Set the appropriate value in pString.
  2297. //
  2298. if (*pTmp == L'd')
  2299. {
  2300. //
  2301. // Get the number of 'd' repetitions in the format string.
  2302. //
  2303. pTmp++;
  2304. for (Repeat = 0; (*pTmp == L'd'); Repeat++, pTmp++)
  2305. ;
  2306. switch (Repeat)
  2307. {
  2308. case ( 0 ) :
  2309. {
  2310. //
  2311. // No leading zero.
  2312. //
  2313. *pString = L'0';
  2314. *(pString + 1) = 0;
  2315. break;
  2316. }
  2317. case ( 1 ) :
  2318. default :
  2319. {
  2320. //
  2321. // Use leading zero.
  2322. //
  2323. *pString = L'1';
  2324. *(pString + 1) = 0;
  2325. break;
  2326. }
  2327. }
  2328. break;
  2329. }
  2330. }
  2331. //
  2332. // Use the system default value.
  2333. //
  2334. pString = pHashN->pLocaleFixed->szIDayLZero;
  2335. break;
  2336. }
  2337. case ( LOCALE_IMONLZERO ) :
  2338. {
  2339. //
  2340. // Use the short date picture to get this information.
  2341. //
  2342. Base = 10;
  2343. if (UserOverride &&
  2344. GetUserInfo( Locale,
  2345. LCType,
  2346. FIELD_OFFSET(NLS_USER_INFO, sShortDate),
  2347. NLS_VALUE_SSHORTDATE,
  2348. pTemp,
  2349. ARRAYSIZE(pTemp),
  2350. TRUE ))
  2351. {
  2352. pString = pTemp;
  2353. //
  2354. // Find out how many M's in string.
  2355. // No need to ignore quotes in short date.
  2356. //
  2357. pTmp = pString;
  2358. while ((*pTmp) &&
  2359. (*pTmp != L'M'))
  2360. {
  2361. pTmp++;
  2362. }
  2363. //
  2364. // Set the appropriate value in pString.
  2365. //
  2366. if (*pTmp == L'M')
  2367. {
  2368. //
  2369. // Get the number of 'M' repetitions in the format string.
  2370. //
  2371. pTmp++;
  2372. for (Repeat = 0; (*pTmp == L'M'); Repeat++, pTmp++)
  2373. ;
  2374. switch (Repeat)
  2375. {
  2376. case ( 0 ) :
  2377. {
  2378. //
  2379. // No leading zero.
  2380. //
  2381. *pString = L'0';
  2382. *(pString + 1) = 0;
  2383. break;
  2384. }
  2385. case ( 1 ) :
  2386. default :
  2387. {
  2388. //
  2389. // Use leading zero.
  2390. //
  2391. *pString = L'1';
  2392. *(pString + 1) = 0;
  2393. break;
  2394. }
  2395. }
  2396. break;
  2397. }
  2398. }
  2399. //
  2400. // Use the system default value.
  2401. //
  2402. pString = pHashN->pLocaleFixed->szIMonLZero;
  2403. break;
  2404. }
  2405. case ( LOCALE_SYEARMONTH ) :
  2406. {
  2407. if (UserOverride &&
  2408. GetUserInfo( Locale,
  2409. LCType,
  2410. FIELD_OFFSET(NLS_USER_INFO, sYearMonth),
  2411. NLS_VALUE_SYEARMONTH,
  2412. pTemp,
  2413. ARRAYSIZE(pTemp),
  2414. TRUE ))
  2415. {
  2416. pString = pTemp;
  2417. }
  2418. else
  2419. {
  2420. pString = pStart + pHashN->pLocaleHdr->SYearMonth;
  2421. }
  2422. break;
  2423. }
  2424. case ( LOCALE_SLONGDATE ) :
  2425. {
  2426. if (UserOverride &&
  2427. GetUserInfo( Locale,
  2428. LCType,
  2429. FIELD_OFFSET(NLS_USER_INFO, sLongDate),
  2430. NLS_VALUE_SLONGDATE,
  2431. pTemp,
  2432. ARRAYSIZE(pTemp),
  2433. TRUE ))
  2434. {
  2435. pString = pTemp;
  2436. }
  2437. else
  2438. {
  2439. pString = pStart + pHashN->pLocaleHdr->SLongDate;
  2440. }
  2441. break;
  2442. }
  2443. case ( LOCALE_ILDATE ) :
  2444. {
  2445. //
  2446. // Use the long date picture to get this information.
  2447. //
  2448. Base = 10;
  2449. if (UserOverride &&
  2450. GetUserInfo( Locale,
  2451. LCType,
  2452. FIELD_OFFSET(NLS_USER_INFO, sLongDate),
  2453. NLS_VALUE_SLONGDATE,
  2454. pTemp,
  2455. ARRAYSIZE(pTemp),
  2456. TRUE ))
  2457. {
  2458. pString = pTemp;
  2459. //
  2460. // Find out if d, M, or y is first, but ignore quotes.
  2461. // Also, if "ddd" or "dddd" is found, then skip it. Only
  2462. // want "d" or "dd".
  2463. //
  2464. pTmp = pString;
  2465. while (pTmp = wcspbrk(pTmp, L"dMy'"))
  2466. {
  2467. //
  2468. // Check special cases.
  2469. //
  2470. if (*pTmp == L'd')
  2471. {
  2472. //
  2473. // Check for d's. Ignore more than 2 d's.
  2474. //
  2475. for (Repeat = 0; (*pTmp == L'd'); Repeat++, pTmp++)
  2476. ;
  2477. if (Repeat < 3)
  2478. {
  2479. //
  2480. // Break out of while loop. Found "d" or "dd".
  2481. //
  2482. pTmp--;
  2483. break;
  2484. }
  2485. }
  2486. else if (*pTmp == NLS_CHAR_QUOTE)
  2487. {
  2488. //
  2489. // Ignore quotes.
  2490. //
  2491. pTmp++;
  2492. while ((*pTmp) && (*pTmp != NLS_CHAR_QUOTE))
  2493. {
  2494. pTmp++;
  2495. }
  2496. pTmp++;
  2497. }
  2498. else
  2499. {
  2500. //
  2501. // Found one of the values, so break out of
  2502. // while loop.
  2503. //
  2504. break;
  2505. }
  2506. }
  2507. //
  2508. // Set the appropriate value in pString.
  2509. //
  2510. if (pTmp)
  2511. {
  2512. switch (*pTmp)
  2513. {
  2514. case ( L'd' ) :
  2515. {
  2516. *pString = L'1';
  2517. break;
  2518. }
  2519. case ( L'M' ) :
  2520. {
  2521. *pString = L'0';
  2522. break;
  2523. }
  2524. case ( L'y' ) :
  2525. {
  2526. *pString = L'2';
  2527. break;
  2528. }
  2529. }
  2530. //
  2531. // Null terminate the string.
  2532. //
  2533. *(pString + 1) = 0;
  2534. break;
  2535. }
  2536. }
  2537. //
  2538. // Use the default value.
  2539. //
  2540. pString = pHashN->pLocaleFixed->szILDate;
  2541. break;
  2542. }
  2543. case ( LOCALE_ICALENDARTYPE ) :
  2544. {
  2545. Base = 10;
  2546. if (UserOverride &&
  2547. GetUserInfo( Locale,
  2548. LCType,
  2549. FIELD_OFFSET(NLS_USER_INFO, iCalType),
  2550. NLS_VALUE_ICALENDARTYPE,
  2551. pTemp,
  2552. ARRAYSIZE(pTemp),
  2553. TRUE ))
  2554. {
  2555. pString = pTemp;
  2556. }
  2557. else
  2558. {
  2559. pString = pHashN->pLocaleFixed->szICalendarType;
  2560. }
  2561. break;
  2562. }
  2563. case ( LOCALE_IOPTIONALCALENDAR ) :
  2564. {
  2565. Base = 10;
  2566. pString = pStart + pHashN->pLocaleHdr->IOptionalCal;
  2567. pString = ((POPT_CAL)pString)->pCalStr;
  2568. break;
  2569. }
  2570. case ( LOCALE_IFIRSTDAYOFWEEK ) :
  2571. {
  2572. Base = 10;
  2573. if (UserOverride &&
  2574. GetUserInfo( Locale,
  2575. LCType,
  2576. FIELD_OFFSET(NLS_USER_INFO, iFirstDay),
  2577. NLS_VALUE_IFIRSTDAYOFWEEK,
  2578. pTemp,
  2579. ARRAYSIZE(pTemp),
  2580. TRUE ))
  2581. {
  2582. pString = pTemp;
  2583. }
  2584. else
  2585. {
  2586. pString = pHashN->pLocaleFixed->szIFirstDayOfWk;
  2587. }
  2588. break;
  2589. }
  2590. case ( LOCALE_IFIRSTWEEKOFYEAR ) :
  2591. {
  2592. Base = 10;
  2593. if (UserOverride &&
  2594. GetUserInfo( Locale,
  2595. LCType,
  2596. FIELD_OFFSET(NLS_USER_INFO, iFirstWeek),
  2597. NLS_VALUE_IFIRSTWEEKOFYEAR,
  2598. pTemp,
  2599. ARRAYSIZE(pTemp),
  2600. TRUE ))
  2601. {
  2602. pString = pTemp;
  2603. }
  2604. else
  2605. {
  2606. pString = pHashN->pLocaleFixed->szIFirstWkOfYr;
  2607. }
  2608. break;
  2609. }
  2610. case ( LOCALE_SDAYNAME1 ) :
  2611. {
  2612. pString = pStart + pHashN->pLocaleHdr->SDayName1;
  2613. break;
  2614. }
  2615. case ( LOCALE_SDAYNAME2 ) :
  2616. {
  2617. pString = pStart + pHashN->pLocaleHdr->SDayName2;
  2618. break;
  2619. }
  2620. case ( LOCALE_SDAYNAME3 ) :
  2621. {
  2622. pString = pStart + pHashN->pLocaleHdr->SDayName3;
  2623. break;
  2624. }
  2625. case ( LOCALE_SDAYNAME4 ) :
  2626. {
  2627. pString = pStart + pHashN->pLocaleHdr->SDayName4;
  2628. break;
  2629. }
  2630. case ( LOCALE_SDAYNAME5 ) :
  2631. {
  2632. pString = pStart + pHashN->pLocaleHdr->SDayName5;
  2633. break;
  2634. }
  2635. case ( LOCALE_SDAYNAME6 ) :
  2636. {
  2637. pString = pStart + pHashN->pLocaleHdr->SDayName6;
  2638. break;
  2639. }
  2640. case ( LOCALE_SDAYNAME7 ) :
  2641. {
  2642. pString = pStart + pHashN->pLocaleHdr->SDayName7;
  2643. break;
  2644. }
  2645. case ( LOCALE_SABBREVDAYNAME1 ) :
  2646. {
  2647. pString = pStart + pHashN->pLocaleHdr->SAbbrevDayName1;
  2648. break;
  2649. }
  2650. case ( LOCALE_SABBREVDAYNAME2 ) :
  2651. {
  2652. pString = pStart + pHashN->pLocaleHdr->SAbbrevDayName2;
  2653. break;
  2654. }
  2655. case ( LOCALE_SABBREVDAYNAME3 ) :
  2656. {
  2657. pString = pStart + pHashN->pLocaleHdr->SAbbrevDayName3;
  2658. break;
  2659. }
  2660. case ( LOCALE_SABBREVDAYNAME4 ) :
  2661. {
  2662. pString = pStart + pHashN->pLocaleHdr->SAbbrevDayName4;
  2663. break;
  2664. }
  2665. case ( LOCALE_SABBREVDAYNAME5 ) :
  2666. {
  2667. pString = pStart + pHashN->pLocaleHdr->SAbbrevDayName5;
  2668. break;
  2669. }
  2670. case ( LOCALE_SABBREVDAYNAME6 ) :
  2671. {
  2672. pString = pStart + pHashN->pLocaleHdr->SAbbrevDayName6;
  2673. break;
  2674. }
  2675. case ( LOCALE_SABBREVDAYNAME7 ) :
  2676. {
  2677. pString = pStart + pHashN->pLocaleHdr->SAbbrevDayName7;
  2678. break;
  2679. }
  2680. case ( LOCALE_SMONTHNAME1 ) :
  2681. {
  2682. pString = pStart + pHashN->pLocaleHdr->SMonthName1;
  2683. break;
  2684. }
  2685. case ( LOCALE_SMONTHNAME2 ) :
  2686. {
  2687. pString = pStart + pHashN->pLocaleHdr->SMonthName2;
  2688. break;
  2689. }
  2690. case ( LOCALE_SMONTHNAME3 ) :
  2691. {
  2692. pString = pStart + pHashN->pLocaleHdr->SMonthName3;
  2693. break;
  2694. }
  2695. case ( LOCALE_SMONTHNAME4 ) :
  2696. {
  2697. pString = pStart + pHashN->pLocaleHdr->SMonthName4;
  2698. break;
  2699. }
  2700. case ( LOCALE_SMONTHNAME5 ) :
  2701. {
  2702. pString = pStart + pHashN->pLocaleHdr->SMonthName5;
  2703. break;
  2704. }
  2705. case ( LOCALE_SMONTHNAME6 ) :
  2706. {
  2707. pString = pStart + pHashN->pLocaleHdr->SMonthName6;
  2708. break;
  2709. }
  2710. case ( LOCALE_SMONTHNAME7 ) :
  2711. {
  2712. pString = pStart + pHashN->pLocaleHdr->SMonthName7;
  2713. break;
  2714. }
  2715. case ( LOCALE_SMONTHNAME8 ) :
  2716. {
  2717. pString = pStart + pHashN->pLocaleHdr->SMonthName8;
  2718. break;
  2719. }
  2720. case ( LOCALE_SMONTHNAME9 ) :
  2721. {
  2722. pString = pStart + pHashN->pLocaleHdr->SMonthName9;
  2723. break;
  2724. }
  2725. case ( LOCALE_SMONTHNAME10 ) :
  2726. {
  2727. pString = pStart + pHashN->pLocaleHdr->SMonthName10;
  2728. break;
  2729. }
  2730. case ( LOCALE_SMONTHNAME11 ) :
  2731. {
  2732. pString = pStart + pHashN->pLocaleHdr->SMonthName11;
  2733. break;
  2734. }
  2735. case ( LOCALE_SMONTHNAME12 ) :
  2736. {
  2737. pString = pStart + pHashN->pLocaleHdr->SMonthName12;
  2738. break;
  2739. }
  2740. case ( LOCALE_SMONTHNAME13 ) :
  2741. {
  2742. pString = pStart + pHashN->pLocaleHdr->SMonthName13;
  2743. break;
  2744. }
  2745. case ( LOCALE_SABBREVMONTHNAME1 ) :
  2746. {
  2747. pString = pStart + pHashN->pLocaleHdr->SAbbrevMonthName1;
  2748. break;
  2749. }
  2750. case ( LOCALE_SABBREVMONTHNAME2 ) :
  2751. {
  2752. pString = pStart + pHashN->pLocaleHdr->SAbbrevMonthName2;
  2753. break;
  2754. }
  2755. case ( LOCALE_SABBREVMONTHNAME3 ) :
  2756. {
  2757. pString = pStart + pHashN->pLocaleHdr->SAbbrevMonthName3;
  2758. break;
  2759. }
  2760. case ( LOCALE_SABBREVMONTHNAME4 ) :
  2761. {
  2762. pString = pStart + pHashN->pLocaleHdr->SAbbrevMonthName4;
  2763. break;
  2764. }
  2765. case ( LOCALE_SABBREVMONTHNAME5 ) :
  2766. {
  2767. pString = pStart + pHashN->pLocaleHdr->SAbbrevMonthName5;
  2768. break;
  2769. }
  2770. case ( LOCALE_SABBREVMONTHNAME6 ) :
  2771. {
  2772. pString = pStart + pHashN->pLocaleHdr->SAbbrevMonthName6;
  2773. break;
  2774. }
  2775. case ( LOCALE_SABBREVMONTHNAME7 ) :
  2776. {
  2777. pString = pStart + pHashN->pLocaleHdr->SAbbrevMonthName7;
  2778. break;
  2779. }
  2780. case ( LOCALE_SABBREVMONTHNAME8 ) :
  2781. {
  2782. pString = pStart + pHashN->pLocaleHdr->SAbbrevMonthName8;
  2783. break;
  2784. }
  2785. case ( LOCALE_SABBREVMONTHNAME9 ) :
  2786. {
  2787. pString = pStart + pHashN->pLocaleHdr->SAbbrevMonthName9;
  2788. break;
  2789. }
  2790. case ( LOCALE_SABBREVMONTHNAME10 ) :
  2791. {
  2792. pString = pStart + pHashN->pLocaleHdr->SAbbrevMonthName10;
  2793. break;
  2794. }
  2795. case ( LOCALE_SABBREVMONTHNAME11 ) :
  2796. {
  2797. pString = pStart + pHashN->pLocaleHdr->SAbbrevMonthName11;
  2798. break;
  2799. }
  2800. case ( LOCALE_SABBREVMONTHNAME12 ) :
  2801. {
  2802. pString = pStart + pHashN->pLocaleHdr->SAbbrevMonthName12;
  2803. break;
  2804. }
  2805. case ( LOCALE_SABBREVMONTHNAME13 ) :
  2806. {
  2807. pString = pStart + pHashN->pLocaleHdr->SAbbrevMonthName13;
  2808. break;
  2809. }
  2810. case ( LOCALE_FONTSIGNATURE ) :
  2811. {
  2812. //
  2813. // Check cchData for size of given buffer.
  2814. //
  2815. if (cchData == 0)
  2816. {
  2817. return (MAX_FONTSIGNATURE);
  2818. }
  2819. else if (cchData < MAX_FONTSIGNATURE)
  2820. {
  2821. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  2822. return (0);
  2823. }
  2824. //
  2825. // This string does NOT get zero terminated.
  2826. //
  2827. pString = pHashN->pLocaleFixed->szFontSignature;
  2828. //
  2829. // Copy the string to lpLCData and return the number of
  2830. // characters copied.
  2831. //
  2832. RtlMoveMemory(lpLCData, pString, MAX_FONTSIGNATURE * sizeof(WCHAR));
  2833. return (MAX_FONTSIGNATURE);
  2834. break;
  2835. }
  2836. default :
  2837. {
  2838. SetLastError(ERROR_INVALID_FLAGS);
  2839. return (0);
  2840. }
  2841. }
  2842. //
  2843. // See if the caller wants the value in the form of a number instead
  2844. // of a string.
  2845. //
  2846. if (ReturnNum)
  2847. {
  2848. //
  2849. // Make sure the flags are valid and there is enough buffer
  2850. // space.
  2851. //
  2852. if (Base == 0)
  2853. {
  2854. SetLastError(ERROR_INVALID_FLAGS);
  2855. return (0);
  2856. }
  2857. if (cchData < 2)
  2858. {
  2859. if (cchData == 0)
  2860. {
  2861. //
  2862. // DWORD is needed for this option (2 WORDS), so return 2.
  2863. //
  2864. return (2);
  2865. }
  2866. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  2867. return (0);
  2868. }
  2869. //
  2870. // Convert the string to an int and return 2 (1 DWORD = 2 WORDS).
  2871. //
  2872. RtlInitUnicodeString(&ObUnicodeStr, pString);
  2873. if (RtlUnicodeStringToInteger(&ObUnicodeStr, Base, (LPDWORD)lpLCData))
  2874. {
  2875. SetLastError(ERROR_INVALID_FLAGS);
  2876. return (0);
  2877. }
  2878. return (2);
  2879. }
  2880. //
  2881. // Get the length (in characters) of the string to copy.
  2882. //
  2883. if (Length == 0)
  2884. {
  2885. Length = NlsStrLenW(pString);
  2886. }
  2887. //
  2888. // Add one for the null termination. All strings should be null
  2889. // terminated.
  2890. //
  2891. Length++;
  2892. //
  2893. // Check cchData for size of given buffer.
  2894. //
  2895. if (cchData == 0)
  2896. {
  2897. //
  2898. // If cchData is 0, then we can't use lpLCData. In this
  2899. // case, we simply want to return the length (in characters) of
  2900. // the string to be copied.
  2901. //
  2902. return (Length);
  2903. }
  2904. else if (cchData < Length)
  2905. {
  2906. //
  2907. // The buffer is too small for the string, so return an error
  2908. // and zero bytes written.
  2909. //
  2910. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  2911. return (0);
  2912. }
  2913. //
  2914. // Copy the string to lpLCData and null terminate it.
  2915. // Return the number of characters copied.
  2916. //
  2917. wcsncpy(lpLCData, pString, Length - 1);
  2918. lpLCData[Length - 1] = 0;
  2919. return (Length);
  2920. }
  2921. ////////////////////////////////////////////////////////////////////////////
  2922. //
  2923. // SetLocaleInfoW
  2924. //
  2925. // Sets one of the various pieces of information about a particular
  2926. // locale by making an entry in the user's portion of the configuration
  2927. // registry. This will only affect the user override portion of the locale
  2928. // settings. The system defaults will never be reset.
  2929. //
  2930. // 07-14-93 JulieB Created.
  2931. ////////////////////////////////////////////////////////////////////////////
  2932. BOOL WINAPI SetLocaleInfoW(
  2933. LCID Locale,
  2934. LCTYPE LCType,
  2935. LPCWSTR lpLCData)
  2936. {
  2937. PLOC_HASH pHashN; // ptr to LOC hash node
  2938. int cchData; // length of lpLCData
  2939. LPWSTR pString; // ptr to info string to change
  2940. LPWSTR pPos; // ptr to position in info string
  2941. LPWSTR pPos2; // ptr to position in info string
  2942. LPWSTR pSep; // ptr to separator string
  2943. WCHAR pTemp[MAX_PATH_LEN]; // ptr to temp storage buffer
  2944. WCHAR pOutput[MAX_REG_VAL_SIZE]; // ptr to output for GetInfo call
  2945. WCHAR pOutput2[MAX_REG_VAL_SIZE]; // ptr to output for GetInfo call
  2946. UINT Order; // date or time order value
  2947. UINT TLZero; // time leading zero value
  2948. UINT TimeMarkPosn; // time mark position value
  2949. WCHAR pFind[3]; // ptr to chars to find
  2950. int SepLen; // length of separator string
  2951. UNICODE_STRING ObUnicodeStr; // value string
  2952. int Value; // value
  2953. //
  2954. // Invalid Parameter Check:
  2955. // - validate LCID
  2956. // - NULL data pointer
  2957. //
  2958. // NOTE: invalid type is checked in the switch statement below.
  2959. //
  2960. VALIDATE_LOCALE(Locale, pHashN, FALSE);
  2961. if ((pHashN == NULL) || (lpLCData == NULL))
  2962. {
  2963. SetLastError(ERROR_INVALID_PARAMETER);
  2964. return (FALSE);
  2965. }
  2966. //
  2967. // Get the length of the buffer.
  2968. //
  2969. cchData = NlsStrLenW(lpLCData) + 1;
  2970. //
  2971. // Initialize temp buffer.
  2972. //
  2973. pTemp[0] = 0;
  2974. //
  2975. // Set the appropriate user information for the given LCTYPE.
  2976. //
  2977. LCType &= (~LOCALE_USE_CP_ACP);
  2978. switch (LCType)
  2979. {
  2980. case ( LOCALE_SLIST ) :
  2981. {
  2982. //
  2983. // Validate the new value. It should be no longer than
  2984. // MAX_SLIST wide characters in length.
  2985. //
  2986. if (cchData > MAX_SLIST)
  2987. {
  2988. SetLastError(ERROR_INVALID_PARAMETER);
  2989. return (FALSE);
  2990. }
  2991. //
  2992. // Set the registry with the new SLIST string.
  2993. //
  2994. return (SetUserInfo( LOCALE_SLIST,
  2995. (LPWSTR)lpLCData,
  2996. cchData ));
  2997. break;
  2998. }
  2999. case ( LOCALE_IMEASURE ) :
  3000. {
  3001. //
  3002. // Validate the new value. It should be no longer than
  3003. // MAX_IMEASURE wide characters in length.
  3004. // It should be between 0 and MAX_VALUE_IMEASURE.
  3005. //
  3006. // NOTE: The string may not be NULL, so it must be at least
  3007. // 2 chars long (includes null).
  3008. //
  3009. // Optimized - since MAX_IMEASURE is 2.
  3010. //
  3011. if ((cchData != MAX_IMEASURE) ||
  3012. (*lpLCData < NLS_CHAR_ZERO) ||
  3013. (*lpLCData > MAX_CHAR_IMEASURE))
  3014. {
  3015. SetLastError(ERROR_INVALID_PARAMETER);
  3016. return (FALSE);
  3017. }
  3018. //
  3019. // Set the registry with the new IMEASURE string.
  3020. //
  3021. return (SetUserInfo( LOCALE_IMEASURE,
  3022. (LPWSTR)lpLCData,
  3023. cchData ));
  3024. break;
  3025. }
  3026. case ( LOCALE_IPAPERSIZE ) :
  3027. {
  3028. //
  3029. // Validate the new value.
  3030. // It should be between DMPAPER_LETTER and DMPAPER_LAST.
  3031. //
  3032. // NOTE: The string may not be NULL, so it must be at least
  3033. // 2 chars long (includes null).
  3034. //
  3035. RtlInitUnicodeString(&ObUnicodeStr, lpLCData);
  3036. if ((cchData < 2) ||
  3037. (RtlUnicodeStringToInteger(&ObUnicodeStr, 10, &Value)) ||
  3038. (Value < DMPAPER_LETTER) || (Value > DMPAPER_LAST))
  3039. {
  3040. SetLastError(ERROR_INVALID_PARAMETER);
  3041. return (FALSE);
  3042. }
  3043. //
  3044. // Set the registry with the new IPAPERSIZE string.
  3045. //
  3046. return (SetUserInfo( LOCALE_IPAPERSIZE,
  3047. (LPWSTR)lpLCData,
  3048. cchData ));
  3049. break;
  3050. }
  3051. case ( LOCALE_SDECIMAL ) :
  3052. {
  3053. //
  3054. // Validate the new value. It should be no longer than
  3055. // MAX_SDECIMAL wide characters in length and should not
  3056. // contain any integer values (L'0' thru L'9').
  3057. //
  3058. if (!IsValidSeparatorString( lpLCData,
  3059. MAX_SDECIMAL,
  3060. FALSE ))
  3061. {
  3062. SetLastError(ERROR_INVALID_PARAMETER);
  3063. return (FALSE);
  3064. }
  3065. //
  3066. // Set the registry with the new SDECIMAL string.
  3067. //
  3068. return (SetUserInfo( LOCALE_SDECIMAL,
  3069. (LPWSTR)lpLCData,
  3070. cchData ));
  3071. break;
  3072. }
  3073. case ( LOCALE_STHOUSAND ) :
  3074. {
  3075. //
  3076. // Validate the new value. It should be no longer than
  3077. // MAX_STHOUSAND wide characters in length and should not
  3078. // contain any integer values (L'0' thru L'9').
  3079. //
  3080. if (!IsValidSeparatorString( lpLCData,
  3081. MAX_STHOUSAND,
  3082. FALSE ))
  3083. {
  3084. SetLastError(ERROR_INVALID_PARAMETER);
  3085. return (FALSE);
  3086. }
  3087. //
  3088. // Set the registry with the new STHOUSAND string.
  3089. //
  3090. return (SetUserInfo( LOCALE_STHOUSAND,
  3091. (LPWSTR)lpLCData,
  3092. cchData ));
  3093. break;
  3094. }
  3095. case ( LOCALE_SGROUPING ) :
  3096. {
  3097. //
  3098. // Validate the new value. It should be no longer than
  3099. // MAX_SGROUPING wide characters in length and should
  3100. // contain alternating integer and semicolon values.
  3101. // (eg. 3;2;0 or 3;0 or 0)
  3102. //
  3103. // NOTE: The string may not be NULL, so it must be at least
  3104. // 2 chars long (includes null).
  3105. //
  3106. if (!IsValidGroupingString( lpLCData,
  3107. MAX_SGROUPING,
  3108. TRUE ))
  3109. {
  3110. SetLastError(ERROR_INVALID_PARAMETER);
  3111. return (FALSE);
  3112. }
  3113. //
  3114. // Set the registry with the new SGROUPING string.
  3115. //
  3116. return (SetUserInfo( LOCALE_SGROUPING,
  3117. (LPWSTR)lpLCData,
  3118. cchData ));
  3119. break;
  3120. }
  3121. case ( LOCALE_IDIGITS ) :
  3122. {
  3123. //
  3124. // Validate the new value. It should be no longer than
  3125. // MAX_IDIGITS wide characters in length.
  3126. // The value should be between 0 and MAX_VALUE_IDIGITS.
  3127. //
  3128. // NOTE: The string may not be NULL, so it must be at least
  3129. // 2 chars long (includes null).
  3130. //
  3131. // Optimized - since MAX_IDIGITS is 2.
  3132. //
  3133. if ((cchData != MAX_IDIGITS) ||
  3134. (*lpLCData < NLS_CHAR_ZERO) ||
  3135. (*lpLCData > MAX_CHAR_IDIGITS))
  3136. {
  3137. SetLastError(ERROR_INVALID_PARAMETER);
  3138. return (FALSE);
  3139. }
  3140. //
  3141. // Set the registry with the new IDIGITS string.
  3142. //
  3143. return (SetUserInfo( LOCALE_IDIGITS,
  3144. (LPWSTR)lpLCData,
  3145. cchData ));
  3146. break;
  3147. }
  3148. case ( LOCALE_ILZERO ) :
  3149. {
  3150. //
  3151. // Validate the new value. It should be no longer than
  3152. // MAX_ILZERO wide characters in length.
  3153. // The value should be between 0 and MAX_VALUE_ILZERO.
  3154. //
  3155. // NOTE: The string may not be NULL, so it must be at least
  3156. // 2 chars long (includes null).
  3157. //
  3158. // Optimized - since MAX_ILZERO is 2.
  3159. //
  3160. if ((cchData != MAX_ILZERO) ||
  3161. (*lpLCData < NLS_CHAR_ZERO) ||
  3162. (*lpLCData > MAX_CHAR_ILZERO))
  3163. {
  3164. SetLastError(ERROR_INVALID_PARAMETER);
  3165. return (FALSE);
  3166. }
  3167. //
  3168. // Set the registry with the new ILZERO string.
  3169. //
  3170. return (SetUserInfo( LOCALE_ILZERO,
  3171. (LPWSTR)lpLCData,
  3172. cchData ));
  3173. break;
  3174. }
  3175. case ( LOCALE_INEGNUMBER ) :
  3176. {
  3177. //
  3178. // Validate the new value. It should be no longer than
  3179. // MAX_INEGNUMBER wide characters in length.
  3180. // The value should be between 0 and MAX_VALUE_INEGNUMBER.
  3181. //
  3182. // NOTE: The string may not be NULL, so it must be at least
  3183. // 2 chars long (includes null).
  3184. //
  3185. // Optimized - since MAX_INEGNUMBER is 2.
  3186. //
  3187. if ((cchData != MAX_INEGNUMBER) ||
  3188. (*lpLCData < NLS_CHAR_ZERO) ||
  3189. (*lpLCData > MAX_CHAR_INEGNUMBER))
  3190. {
  3191. SetLastError(ERROR_INVALID_PARAMETER);
  3192. return (FALSE);
  3193. }
  3194. //
  3195. // Set the registry with the new INEGNUMBER string.
  3196. //
  3197. return (SetUserInfo( LOCALE_INEGNUMBER,
  3198. (LPWSTR)lpLCData,
  3199. cchData ));
  3200. break;
  3201. }
  3202. case ( LOCALE_SNATIVEDIGITS ) :
  3203. {
  3204. //
  3205. // Validate the new value. It should be exactly
  3206. // MAX_SNATIVEDIGITS wide characters in length.
  3207. //
  3208. if (cchData != MAX_SNATIVEDIGITS)
  3209. {
  3210. SetLastError(ERROR_INVALID_PARAMETER);
  3211. return (FALSE);
  3212. }
  3213. //
  3214. // Set the registry with the new SNATIVEDIGITS string.
  3215. //
  3216. return (SetUserInfo( LOCALE_SNATIVEDIGITS,
  3217. (LPWSTR)lpLCData,
  3218. cchData ));
  3219. break;
  3220. }
  3221. case ( LOCALE_IDIGITSUBSTITUTION ) :
  3222. {
  3223. //
  3224. // Validate the new value. It should be no longer than
  3225. // MAX_IDIGITSUBST wide characters in length.
  3226. // The value should be between 0 and MAX_VALUE_IDIGITSUBST.
  3227. //
  3228. // NOTE: The string may not be NULL, so it must be at least
  3229. // 2 chars long (includes null).
  3230. //
  3231. // Optimized - since MAX_IDIGITSUBST is 2.
  3232. //
  3233. if ((cchData != MAX_IDIGITSUBST) ||
  3234. (*lpLCData < NLS_CHAR_ZERO) ||
  3235. (*lpLCData > MAX_CHAR_IDIGITSUBST))
  3236. {
  3237. SetLastError(ERROR_INVALID_PARAMETER);
  3238. return (FALSE);
  3239. }
  3240. //
  3241. // Set the registry with the new IDIGITSUBST string.
  3242. //
  3243. return (SetUserInfo( LOCALE_IDIGITSUBSTITUTION,
  3244. (LPWSTR)lpLCData,
  3245. cchData ));
  3246. break;
  3247. }
  3248. case ( LOCALE_SCURRENCY ) :
  3249. {
  3250. //
  3251. // Validate the new value. It should be no longer than
  3252. // MAX_SCURRENCY wide characters in length and should not
  3253. // contain any integer values (L'0' thru L'9').
  3254. //
  3255. if (!IsValidSeparatorString( lpLCData,
  3256. MAX_SCURRENCY,
  3257. FALSE ))
  3258. {
  3259. SetLastError(ERROR_INVALID_PARAMETER);
  3260. return (FALSE);
  3261. }
  3262. //
  3263. // Set the registry with the new SCURRENCY string.
  3264. //
  3265. return (SetUserInfo( LOCALE_SCURRENCY,
  3266. (LPWSTR)lpLCData,
  3267. cchData ));
  3268. break;
  3269. }
  3270. case ( LOCALE_SMONDECIMALSEP ) :
  3271. {
  3272. //
  3273. // Validate the new value. It should be no longer than
  3274. // MAX_SMONDECSEP wide characters in length and should not
  3275. // contain any integer values (L'0' thru L'9').
  3276. //
  3277. if (!IsValidSeparatorString( lpLCData,
  3278. MAX_SMONDECSEP,
  3279. FALSE ))
  3280. {
  3281. SetLastError(ERROR_INVALID_PARAMETER);
  3282. return (FALSE);
  3283. }
  3284. //
  3285. // Set the registry with the new SMONDECIMALSEP string.
  3286. //
  3287. return (SetUserInfo( LOCALE_SMONDECIMALSEP,
  3288. (LPWSTR)lpLCData,
  3289. cchData ));
  3290. break;
  3291. }
  3292. case ( LOCALE_SMONTHOUSANDSEP ) :
  3293. {
  3294. //
  3295. // Validate the new value. It should be no longer than
  3296. // MAX_SMONTHOUSEP wide characters in length and should not
  3297. // contain any integer values (L'0' thru L'9').
  3298. //
  3299. if (!IsValidSeparatorString( lpLCData,
  3300. MAX_SMONTHOUSEP,
  3301. FALSE ))
  3302. {
  3303. SetLastError(ERROR_INVALID_PARAMETER);
  3304. return (FALSE);
  3305. }
  3306. //
  3307. // Set the registry with the new SMONTHOUSANDSEP string.
  3308. //
  3309. return (SetUserInfo( LOCALE_SMONTHOUSANDSEP,
  3310. (LPWSTR)lpLCData,
  3311. cchData ));
  3312. break;
  3313. }
  3314. case ( LOCALE_SMONGROUPING ) :
  3315. {
  3316. //
  3317. // Validate the new value. It should be no longer than
  3318. // MAX_SMONGROUPING wide characters in length and should
  3319. // contain alternating integer and semicolon values.
  3320. // (eg. 3;2;0 or 3;0 or 0)
  3321. //
  3322. // NOTE: The string may not be NULL, so it must be at least
  3323. // 2 chars long (includes null).
  3324. //
  3325. if (!IsValidGroupingString( lpLCData,
  3326. MAX_SMONGROUPING,
  3327. TRUE ))
  3328. {
  3329. SetLastError(ERROR_INVALID_PARAMETER);
  3330. return (FALSE);
  3331. }
  3332. //
  3333. // Set the registry with the new SMONGROUPING string.
  3334. //
  3335. return (SetUserInfo( LOCALE_SMONGROUPING,
  3336. (LPWSTR)lpLCData,
  3337. cchData ));
  3338. break;
  3339. }
  3340. case ( LOCALE_ICURRDIGITS ) :
  3341. {
  3342. //
  3343. // Validate the new value.
  3344. // The value should be between 0 and MAX_VALUE_ICURRDIGITS.
  3345. //
  3346. // NOTE: The string may not be NULL, so it must be at least
  3347. // 2 chars long (includes null).
  3348. //
  3349. RtlInitUnicodeString(&ObUnicodeStr, lpLCData);
  3350. if ((cchData < 2) ||
  3351. (RtlUnicodeStringToInteger(&ObUnicodeStr, 10, &Value)) ||
  3352. (Value < 0) || (Value > MAX_VALUE_ICURRDIGITS) ||
  3353. ((Value == 0) &&
  3354. ((*lpLCData != NLS_CHAR_ZERO) || (cchData != 2))))
  3355. {
  3356. SetLastError(ERROR_INVALID_PARAMETER);
  3357. return (FALSE);
  3358. }
  3359. //
  3360. // Set the registry with the new ICURRDIGITS string.
  3361. //
  3362. return (SetUserInfo( LOCALE_ICURRDIGITS,
  3363. (LPWSTR)lpLCData,
  3364. cchData ));
  3365. break;
  3366. }
  3367. case ( LOCALE_ICURRENCY ) :
  3368. {
  3369. //
  3370. // Validate the new value. It should be no longer than
  3371. // MAX_ICURRENCY wide characters in length.
  3372. // The value should be between 0 and MAX_VALUE_ICURRENCY.
  3373. //
  3374. // NOTE: The string may not be NULL, so it must be at least
  3375. // 2 chars long (includes null).
  3376. //
  3377. // Optimized - since MAX_ICURRENCY is 2.
  3378. //
  3379. if ((cchData != MAX_ICURRENCY) ||
  3380. (*lpLCData < NLS_CHAR_ZERO) ||
  3381. (*lpLCData > MAX_CHAR_ICURRENCY))
  3382. {
  3383. SetLastError(ERROR_INVALID_PARAMETER);
  3384. return (FALSE);
  3385. }
  3386. //
  3387. // Set the registry with the new ICURRENCY string.
  3388. //
  3389. return (SetUserInfo( LOCALE_ICURRENCY,
  3390. (LPWSTR)lpLCData,
  3391. cchData ));
  3392. break;
  3393. }
  3394. case ( LOCALE_INEGCURR ) :
  3395. {
  3396. //
  3397. // Validate the new value.
  3398. // The value should be between 0 and MAX_VALUE_INEGCURR.
  3399. //
  3400. // NOTE: The string may not be NULL, so it must be at least
  3401. // 2 chars long (includes null).
  3402. //
  3403. RtlInitUnicodeString(&ObUnicodeStr, lpLCData);
  3404. if ((cchData < 2) ||
  3405. (RtlUnicodeStringToInteger(&ObUnicodeStr, 10, &Value)) ||
  3406. (Value < 0) || (Value > MAX_VALUE_INEGCURR) ||
  3407. ((Value == 0) &&
  3408. ((*lpLCData != NLS_CHAR_ZERO) || (cchData != 2))))
  3409. {
  3410. SetLastError(ERROR_INVALID_PARAMETER);
  3411. return (FALSE);
  3412. }
  3413. //
  3414. // Set the registry with the new INEGCURR string.
  3415. //
  3416. return (SetUserInfo( LOCALE_INEGCURR,
  3417. (LPWSTR)lpLCData,
  3418. cchData ));
  3419. break;
  3420. }
  3421. case ( LOCALE_SPOSITIVESIGN ) :
  3422. {
  3423. //
  3424. // Validate the new value. It should be no longer than
  3425. // MAX_SPOSSIGN wide characters in length and should not
  3426. // contain any integer values (L'0' thru L'9').
  3427. //
  3428. if (!IsValidSeparatorString( lpLCData,
  3429. MAX_SPOSSIGN,
  3430. FALSE ))
  3431. {
  3432. SetLastError(ERROR_INVALID_PARAMETER);
  3433. return (FALSE);
  3434. }
  3435. //
  3436. // Set the registry with the new SPOSITIVESIGN string.
  3437. //
  3438. return (SetUserInfo( LOCALE_SPOSITIVESIGN,
  3439. (LPWSTR)lpLCData,
  3440. cchData ));
  3441. break;
  3442. }
  3443. case ( LOCALE_SNEGATIVESIGN ) :
  3444. {
  3445. //
  3446. // Validate the new value. It should be no longer than
  3447. // MAX_SNEGSIGN wide characters in length and should not
  3448. // contain any integer values (L'0' thru L'9').
  3449. //
  3450. if (!IsValidSeparatorString( lpLCData,
  3451. MAX_SNEGSIGN,
  3452. FALSE ))
  3453. {
  3454. SetLastError(ERROR_INVALID_PARAMETER);
  3455. return (FALSE);
  3456. }
  3457. //
  3458. // Set the registry with the new SNEGATIVESIGN string.
  3459. //
  3460. return (SetUserInfo( LOCALE_SNEGATIVESIGN,
  3461. (LPWSTR)lpLCData,
  3462. cchData ));
  3463. break;
  3464. }
  3465. case ( LOCALE_STIMEFORMAT ) :
  3466. {
  3467. BOOL bInsideQuotedString = FALSE;
  3468. //
  3469. // Validate the new value. It should be no longer than
  3470. // MAX_STIMEFORMAT wide characters in length.
  3471. //
  3472. // NOTE: The string may not be NULL, so it must be at least
  3473. // 2 chars long (includes null). This is checked below
  3474. // in the check for whether or not there is an hour
  3475. // delimeter.
  3476. //
  3477. if (cchData > MAX_STIMEFORMAT)
  3478. {
  3479. SetLastError(ERROR_INVALID_PARAMETER);
  3480. return (FALSE);
  3481. }
  3482. //
  3483. // NOTE: Must link the STIME, ITIME, ITLZERO, and
  3484. // ITIMEMARKPOSN values in the registry.
  3485. //
  3486. //
  3487. // Search for H or h, so that iTime and iTLZero can be
  3488. // set. If no H or h exists, return an error. Note: the
  3489. // combinations "hH" or "Hh" are invalid.
  3490. //
  3491. pPos = (LPWSTR)lpLCData;
  3492. while ((pPos = wcspbrk(pPos, L"Hh'")))
  3493. {
  3494. if (*pPos == L'\'')
  3495. {
  3496. //
  3497. // Enter or leave a quoted string.
  3498. //
  3499. bInsideQuotedString &= ~TRUE;
  3500. }
  3501. else if (*pPos == L'H')
  3502. {
  3503. //
  3504. // Found an H.
  3505. //
  3506. if (!bInsideQuotedString)
  3507. {
  3508. //
  3509. // Get the appropriate ITIME value.
  3510. //
  3511. Order = 1;
  3512. //
  3513. // Get the appropriate ITLZERO value.
  3514. //
  3515. if (*(pPos + 1) == L'H')
  3516. {
  3517. TLZero = 1;
  3518. break;
  3519. }
  3520. else if (*(pPos + 1) == L'h')
  3521. {
  3522. //
  3523. // Invalid combination.
  3524. //
  3525. pPos = NULL;
  3526. break;
  3527. }
  3528. else
  3529. {
  3530. TLZero = 0;
  3531. break;
  3532. }
  3533. }
  3534. }
  3535. else if (*pPos == L'h')
  3536. {
  3537. //
  3538. // Found an h.
  3539. //
  3540. if (!bInsideQuotedString)
  3541. {
  3542. //
  3543. // Get the appropriate ITIME value.
  3544. //
  3545. Order = 0;
  3546. //
  3547. // Get the appropriate ITLZERO value.
  3548. //
  3549. if (*(pPos + 1) == L'h')
  3550. {
  3551. TLZero = 1;
  3552. break;
  3553. }
  3554. else if (*(pPos + 1) == L'H')
  3555. {
  3556. //
  3557. // Invalid combination.
  3558. //
  3559. pPos = NULL;
  3560. break;
  3561. }
  3562. else
  3563. {
  3564. TLZero = 0;
  3565. break;
  3566. }
  3567. }
  3568. }
  3569. pPos++;
  3570. }
  3571. //
  3572. // If pPos == NULL, then one of two things happened:
  3573. // - reached the end of the string without finding "H" or "h"
  3574. // - found an invalid combination like "hH" or "Hh"
  3575. //
  3576. if (!pPos)
  3577. {
  3578. SetLastError(ERROR_INVALID_PARAMETER);
  3579. return (FALSE);
  3580. }
  3581. //
  3582. // Search for tt, so that ITIMEMARKPOSN can be
  3583. // set. If no tt exists, do not change the value.
  3584. //
  3585. bInsideQuotedString = FALSE;
  3586. pPos = (LPWSTR)lpLCData;
  3587. while ((pPos = wcspbrk(pPos, L"t'")))
  3588. {
  3589. if (*pPos == L'\'')
  3590. {
  3591. //
  3592. // Enter or leave a quoted string.
  3593. //
  3594. bInsideQuotedString &= ~TRUE;
  3595. }
  3596. else if (*(pPos + 1) == L't')
  3597. {
  3598. if (!bInsideQuotedString)
  3599. {
  3600. //
  3601. // The string "tt" is found.
  3602. //
  3603. break;
  3604. }
  3605. }
  3606. pPos++;
  3607. }
  3608. if (pPos)
  3609. {
  3610. //
  3611. // Get the appropriate ITIMEMARKPOSN value.
  3612. //
  3613. bInsideQuotedString = FALSE;
  3614. pPos2 = (LPWSTR)lpLCData;
  3615. while ((pPos2 = wcspbrk(pPos2, L"Hhmst'")))
  3616. {
  3617. if (*pPos == L'\'')
  3618. {
  3619. //
  3620. // Enter or leave a quoted string.
  3621. //
  3622. bInsideQuotedString &= ~TRUE;
  3623. }
  3624. else
  3625. {
  3626. if (!bInsideQuotedString)
  3627. {
  3628. //
  3629. // Get the appropriate ITIMEMARKPOSN value.
  3630. //
  3631. TimeMarkPosn = (pPos == pPos2) ? 1 : 0;
  3632. break;
  3633. }
  3634. }
  3635. pPos2++;
  3636. }
  3637. }
  3638. //
  3639. // Find the time separator so that STIME can be set.
  3640. //
  3641. bInsideQuotedString = FALSE;
  3642. pPos = (LPWSTR)lpLCData;
  3643. while (pPos = wcspbrk(pPos, L"Hhms'"))
  3644. {
  3645. if (*pPos == L'\'')
  3646. {
  3647. //
  3648. // Enter or leave a quoted string.
  3649. //
  3650. bInsideQuotedString &= ~TRUE;
  3651. pPos++;
  3652. }
  3653. else
  3654. {
  3655. if (!bInsideQuotedString)
  3656. {
  3657. //
  3658. // Look for the beginning of the time separator.
  3659. //
  3660. pPos++;
  3661. while ((*pPos) && (wcschr(L"Hhms", *pPos)))
  3662. {
  3663. pPos++;
  3664. }
  3665. //
  3666. // Look for the end of the time separator.
  3667. //
  3668. if (*pPos)
  3669. {
  3670. //
  3671. // Find the end of the separator string.
  3672. //
  3673. pPos2 = wcspbrk(pPos, L"Hhmst");
  3674. if (pPos2)
  3675. {
  3676. if (*pPos2 == L't')
  3677. {
  3678. //
  3679. // Found a time marker, so need to start
  3680. // over in search for separator. There
  3681. // are no separators around the time
  3682. // marker.
  3683. //
  3684. pPos = pPos2 + 1;
  3685. }
  3686. else
  3687. {
  3688. //
  3689. // Found end of separator, so break out of
  3690. // while loop.
  3691. //
  3692. break;
  3693. }
  3694. }
  3695. }
  3696. }
  3697. else
  3698. {
  3699. pPos++;
  3700. }
  3701. }
  3702. }
  3703. //
  3704. // Get the appropriate STIME string.
  3705. //
  3706. if (pPos)
  3707. {
  3708. //
  3709. // Copy to temp buffer so that it's zero terminated.
  3710. //
  3711. pString = pTemp;
  3712. while (pPos != pPos2)
  3713. {
  3714. //
  3715. // If there is a quoted string in the separator, then
  3716. // just put in a white space, since there is no meaning
  3717. // for time field separator anymore.
  3718. //
  3719. if (*pPos == L'\'')
  3720. {
  3721. pString = pTemp;
  3722. *pString++ = L' ';
  3723. break;
  3724. }
  3725. *pString = *pPos;
  3726. pPos++;
  3727. pString++;
  3728. }
  3729. *pString = 0;
  3730. }
  3731. else
  3732. {
  3733. //
  3734. // There is no time separator, so use NULL.
  3735. //
  3736. *pTemp = 0;
  3737. }
  3738. //
  3739. // Validate the new value. It should be no longer than
  3740. // MAX_STIME wide characters in length and should not
  3741. // contain any integer values (L'0' thru L'9').
  3742. //
  3743. // NOTE: The string may not be NULL, so it must be at least
  3744. // 2 chars long (includes null).
  3745. //
  3746. if (!IsValidSeparatorString( pTemp,
  3747. MAX_STIME,
  3748. TRUE ))
  3749. {
  3750. SetLastError(ERROR_INVALID_PARAMETER);
  3751. return (FALSE);
  3752. }
  3753. //
  3754. // Make sure that the time separator does NOT contain any
  3755. // of the special time picture characters - h, H, m, s, t, '.
  3756. //
  3757. if (wcspbrk(pTemp, L"Hhmst'"))
  3758. {
  3759. SetLastError(ERROR_INVALID_PARAMETER);
  3760. return (FALSE);
  3761. }
  3762. //
  3763. // Call the server to set the registry.
  3764. //
  3765. return (SetMultipleUserInfo( LCType,
  3766. cchData,
  3767. lpLCData,
  3768. pTemp,
  3769. (Order == 0) ? L"0" : L"1",
  3770. (TLZero == 0) ? L"0" : L"1",
  3771. (TimeMarkPosn == 0) ? L"0" : L"1" ));
  3772. break;
  3773. }
  3774. case ( LOCALE_STIME ) :
  3775. {
  3776. //
  3777. // NOTE: Must link the STIMEFORMAT value in the registry.
  3778. //
  3779. //
  3780. // Validate the new value. It should be no longer than
  3781. // MAX_STIME wide characters in length and should not
  3782. // contain any integer values (L'0' thru L'9').
  3783. //
  3784. // NOTE: The string may not be NULL, so it must be at least
  3785. // 2 chars long (includes null).
  3786. //
  3787. if (!IsValidSeparatorString( lpLCData,
  3788. MAX_STIME,
  3789. TRUE ))
  3790. {
  3791. SetLastError(ERROR_INVALID_PARAMETER);
  3792. return (FALSE);
  3793. }
  3794. //
  3795. // Make sure that the time separator does NOT contain any
  3796. // of the special time picture characters - h, H, m, s, t, '.
  3797. //
  3798. if (wcspbrk(lpLCData, L"Hhmst'"))
  3799. {
  3800. SetLastError(ERROR_INVALID_PARAMETER);
  3801. return (FALSE);
  3802. }
  3803. //
  3804. // Get the current setting for STIMEFORMAT.
  3805. //
  3806. if (GetUserInfo( Locale,
  3807. LOCALE_STIMEFORMAT,
  3808. FIELD_OFFSET(NLS_USER_INFO, sTimeFormat),
  3809. NLS_VALUE_STIMEFORMAT,
  3810. pOutput,
  3811. ARRAYSIZE(pOutput),
  3812. TRUE ))
  3813. {
  3814. pString = pOutput;
  3815. }
  3816. else
  3817. {
  3818. pString = (LPWORD)(pHashN->pLocaleHdr) +
  3819. pHashN->pLocaleHdr->STimeFormat;
  3820. }
  3821. //
  3822. // Get the current setting for STIME.
  3823. //
  3824. if (GetUserInfo( Locale,
  3825. LCType,
  3826. FIELD_OFFSET(NLS_USER_INFO, sTime),
  3827. NLS_VALUE_STIME,
  3828. pOutput2,
  3829. ARRAYSIZE(pOutput2),
  3830. TRUE ))
  3831. {
  3832. pSep = pOutput2;
  3833. }
  3834. else
  3835. {
  3836. pSep = (LPWORD)(pHashN->pLocaleHdr) +
  3837. pHashN->pLocaleHdr->STime;
  3838. }
  3839. //
  3840. // Get the length of the separator string.
  3841. //
  3842. SepLen = NlsStrLenW(pSep);
  3843. //
  3844. // Setup the string containing the characters to find in
  3845. // the timeformat string.
  3846. //
  3847. pFind[0] = NLS_CHAR_QUOTE;
  3848. pFind[1] = *pSep;
  3849. pFind[2] = 0;
  3850. //
  3851. // Find the time separator in the STIMEFORMAT string and
  3852. // replace it with the new time separator.
  3853. //
  3854. // The new separator may be a different length than
  3855. // the old one, so must use a static buffer for the new
  3856. // time format string.
  3857. //
  3858. pPos = pTemp;
  3859. while (pPos2 = wcspbrk(pString, pFind))
  3860. {
  3861. //
  3862. // Copy format string up to pPos2.
  3863. //
  3864. while (pString < pPos2)
  3865. {
  3866. *pPos = *pString;
  3867. pPos++;
  3868. pString++;
  3869. }
  3870. switch (*pPos2)
  3871. {
  3872. case ( NLS_CHAR_QUOTE ) :
  3873. {
  3874. //
  3875. // Copy the quote.
  3876. //
  3877. *pPos = *pString;
  3878. pPos++;
  3879. pString++;
  3880. //
  3881. // Copy what's inside the quotes.
  3882. //
  3883. while ((*pString) && (*pString != NLS_CHAR_QUOTE))
  3884. {
  3885. *pPos = *pString;
  3886. pPos++;
  3887. pString++;
  3888. }
  3889. //
  3890. // Copy the end quote.
  3891. //
  3892. *pPos = NLS_CHAR_QUOTE;
  3893. pPos++;
  3894. if (*pString)
  3895. {
  3896. pString++;
  3897. }
  3898. break;
  3899. }
  3900. default :
  3901. {
  3902. //
  3903. // Make sure it's the old separator.
  3904. //
  3905. if (NlsStrNEqualW(pString, pSep, SepLen))
  3906. {
  3907. //
  3908. // Adjust pointer to skip over old separator.
  3909. //
  3910. pString += SepLen;
  3911. //
  3912. // Copy the new separator.
  3913. //
  3914. pPos2 = (LPWSTR)lpLCData;
  3915. while (*pPos2)
  3916. {
  3917. *pPos = *pPos2;
  3918. pPos++;
  3919. pPos2++;
  3920. }
  3921. }
  3922. else
  3923. {
  3924. //
  3925. // Copy the code point and continue.
  3926. //
  3927. *pPos = *pString;
  3928. pPos++;
  3929. pString++;
  3930. }
  3931. break;
  3932. }
  3933. }
  3934. }
  3935. //
  3936. // Copy to the end of the string and null terminate it.
  3937. //
  3938. while (*pString)
  3939. {
  3940. *pPos = *pString;
  3941. pPos++;
  3942. pString++;
  3943. }
  3944. *pPos = 0;
  3945. //
  3946. // Call the server to set the registry.
  3947. //
  3948. return (SetMultipleUserInfo( LCType,
  3949. cchData,
  3950. pTemp,
  3951. lpLCData,
  3952. NULL,
  3953. NULL,
  3954. NULL ));
  3955. break;
  3956. }
  3957. case ( LOCALE_ITIME ) :
  3958. {
  3959. //
  3960. // NOTE: Must link the STIMEFORMAT value in the registry.
  3961. //
  3962. //
  3963. // Validate the new value. It should be no longer than
  3964. // MAX_ITIME wide characters in length.
  3965. // The value should be either 0 or MAX_VALUE_ITIME.
  3966. //
  3967. // NOTE: The string may not be NULL, so it must be at least
  3968. // 2 chars long (includes null).
  3969. //
  3970. // Optimized - since MAX_ITIME is 2.
  3971. //
  3972. if ((cchData != MAX_ITIME) ||
  3973. (*lpLCData < NLS_CHAR_ZERO) ||
  3974. (*lpLCData > MAX_CHAR_ITIME))
  3975. {
  3976. SetLastError(ERROR_INVALID_PARAMETER);
  3977. return (FALSE);
  3978. }
  3979. //
  3980. // Get the current setting for STIMEFORMAT.
  3981. //
  3982. if (GetUserInfo( Locale,
  3983. LOCALE_STIMEFORMAT,
  3984. FIELD_OFFSET(NLS_USER_INFO, sTimeFormat),
  3985. NLS_VALUE_STIMEFORMAT,
  3986. pOutput,
  3987. ARRAYSIZE(pOutput),
  3988. TRUE ))
  3989. {
  3990. pString = pOutput;
  3991. }
  3992. else
  3993. {
  3994. //
  3995. // Copy system default to temp buffer.
  3996. //
  3997. NlsStrCpyW( pTemp,
  3998. (LPWORD)(pHashN->pLocaleHdr) +
  3999. pHashN->pLocaleHdr->STimeFormat );
  4000. pString = pTemp;
  4001. }
  4002. //
  4003. // Search down the STIMEFORMAT string.
  4004. // If iTime = 0, then H -> h.
  4005. // If iTime = 1, then h -> H.
  4006. //
  4007. pPos = pString;
  4008. if (*lpLCData == NLS_CHAR_ZERO)
  4009. {
  4010. while (*pPos)
  4011. {
  4012. if (*pPos == L'H')
  4013. {
  4014. *pPos = L'h';
  4015. }
  4016. pPos++;
  4017. }
  4018. }
  4019. else
  4020. {
  4021. while (*pPos)
  4022. {
  4023. if (*pPos == L'h')
  4024. {
  4025. *pPos = L'H';
  4026. }
  4027. pPos++;
  4028. }
  4029. }
  4030. //
  4031. // Call the server to set the registry.
  4032. //
  4033. return (SetMultipleUserInfo( LCType,
  4034. cchData,
  4035. pString,
  4036. NULL,
  4037. lpLCData,
  4038. NULL,
  4039. NULL ));
  4040. break;
  4041. }
  4042. case ( LOCALE_S1159 ) :
  4043. {
  4044. //
  4045. // Validate the new value. It should be no longer than
  4046. // MAX_S1159 wide characters in length.
  4047. //
  4048. if (cchData > MAX_S1159)
  4049. {
  4050. SetLastError(ERROR_INVALID_PARAMETER);
  4051. return (FALSE);
  4052. }
  4053. //
  4054. // Set the registry with the new S1159 string.
  4055. //
  4056. return (SetUserInfo( LOCALE_S1159,
  4057. (LPWSTR)lpLCData,
  4058. cchData ));
  4059. break;
  4060. }
  4061. case ( LOCALE_S2359 ) :
  4062. {
  4063. //
  4064. // Validate the new value. It should be no longer than
  4065. // MAX_S2359 wide characters in length.
  4066. //
  4067. if (cchData > MAX_S2359)
  4068. {
  4069. SetLastError(ERROR_INVALID_PARAMETER);
  4070. return (FALSE);
  4071. }
  4072. //
  4073. // Set the registry with the new S2359 string.
  4074. //
  4075. return (SetUserInfo( LOCALE_S2359,
  4076. (LPWSTR)lpLCData,
  4077. cchData ));
  4078. break;
  4079. }
  4080. case ( LOCALE_SSHORTDATE ) :
  4081. {
  4082. //
  4083. // Validate the new value. It should be no longer than
  4084. // MAX_SSHORTDATE wide characters in length.
  4085. //
  4086. // NOTE: The string may not be NULL, so it must be at least
  4087. // 2 chars long (includes null). This is checked below
  4088. // in the check for whether or not there is a date,
  4089. // month, or year delimeter.
  4090. //
  4091. if (cchData > MAX_SSHORTDATE)
  4092. {
  4093. SetLastError(ERROR_INVALID_PARAMETER);
  4094. return (FALSE);
  4095. }
  4096. //
  4097. // NOTE: Must link the IDATE and SDATE values in the registry.
  4098. //
  4099. //
  4100. // Search for the 'd' or 'M' or 'y' sequence in the date format
  4101. // string to set the new IDATE value.
  4102. //
  4103. // If none of these symbols exist in the date format string,
  4104. // then return an error.
  4105. //
  4106. pPos = wcspbrk(lpLCData, L"dMy");
  4107. if (!pPos)
  4108. {
  4109. SetLastError(ERROR_INVALID_PARAMETER);
  4110. return (FALSE);
  4111. }
  4112. //
  4113. // Set the registry with the appropriate IDATE string.
  4114. //
  4115. switch (*pPos)
  4116. {
  4117. case ( L'M' ) :
  4118. {
  4119. Order = 0;
  4120. break;
  4121. }
  4122. case ( L'd' ) :
  4123. {
  4124. Order = 1;
  4125. break;
  4126. }
  4127. case ( L'y' ) :
  4128. {
  4129. Order = 2;
  4130. break;
  4131. }
  4132. }
  4133. //
  4134. // Set the registry with the appropriate SDATE string.
  4135. //
  4136. // The ptr "pPos" is pointing at either d, M, or y.
  4137. // Go to the next position past sequence of d, M, or y.
  4138. //
  4139. pPos++;
  4140. while ((*pPos) && (wcschr( L"dMy", *pPos )))
  4141. {
  4142. pPos++;
  4143. }
  4144. *pTemp = 0;
  4145. if (*pPos)
  4146. {
  4147. //
  4148. // Find the end of the separator string.
  4149. //
  4150. pPos2 = wcspbrk(pPos, L"dMy");
  4151. if (pPos2)
  4152. {
  4153. //
  4154. // Copy to temp buffer so that it's zero terminated.
  4155. //
  4156. pString = pTemp;
  4157. while (pPos != pPos2)
  4158. {
  4159. //
  4160. // If there is a quoted string in the separator, then
  4161. // just punch in a white space, since there is no meaning
  4162. // for short date field separator anymore.
  4163. //
  4164. if (*pPos == L'\'')
  4165. {
  4166. pString = pTemp;
  4167. *pString++ = L' ';
  4168. break;
  4169. }
  4170. *pString = *pPos;
  4171. pPos++;
  4172. pString++;
  4173. }
  4174. *pString = 0;
  4175. }
  4176. }
  4177. //
  4178. // Since the date separator (LOCALE_SDATE) is being set here, we
  4179. // should do the same validation as LOCALE_SDATE.
  4180. //
  4181. if (!IsValidSeparatorString( pTemp,
  4182. MAX_SDATE,
  4183. TRUE ))
  4184. {
  4185. SetLastError(ERROR_INVALID_PARAMETER);
  4186. return (FALSE);
  4187. }
  4188. //
  4189. // Make sure that the date separator does NOT contain any
  4190. // of the special date picture characters - d, M, y, g, '.
  4191. //
  4192. if (wcspbrk(pTemp, L"dMyg'"))
  4193. {
  4194. SetLastError(ERROR_INVALID_PARAMETER);
  4195. return (FALSE);
  4196. }
  4197. //
  4198. // Call the server to set the registry.
  4199. //
  4200. return (SetMultipleUserInfo( LCType,
  4201. cchData,
  4202. lpLCData,
  4203. pTemp,
  4204. (Order == 0) ? L"0" :
  4205. ((Order == 1) ? L"1" : L"2"),
  4206. NULL,
  4207. NULL ));
  4208. break;
  4209. }
  4210. case ( LOCALE_SDATE ) :
  4211. {
  4212. //
  4213. // NOTE: Must link the SSHORTDATE value in the registry.
  4214. //
  4215. //
  4216. // Validate the new value. It should be no longer than
  4217. // MAX_SDATE wide characters in length and should not
  4218. // contain any integer values (L'0' thru L'9').
  4219. //
  4220. // NOTE: The string may not be NULL, so it must be at least
  4221. // 2 chars long (includes null).
  4222. //
  4223. if (!IsValidSeparatorString( lpLCData,
  4224. MAX_SDATE,
  4225. TRUE ))
  4226. {
  4227. SetLastError(ERROR_INVALID_PARAMETER);
  4228. return (FALSE);
  4229. }
  4230. //
  4231. // Make sure that the date separator does NOT contain any
  4232. // of the special date picture characters - d, M, y, g, '.
  4233. //
  4234. if (wcspbrk(lpLCData, L"dMyg'"))
  4235. {
  4236. SetLastError(ERROR_INVALID_PARAMETER);
  4237. return (FALSE);
  4238. }
  4239. //
  4240. // Get the current setting for SSHORTDATE.
  4241. //
  4242. if (GetUserInfo( Locale,
  4243. LOCALE_SSHORTDATE,
  4244. FIELD_OFFSET(NLS_USER_INFO, sShortDate),
  4245. NLS_VALUE_SSHORTDATE,
  4246. pOutput,
  4247. ARRAYSIZE(pOutput),
  4248. TRUE ))
  4249. {
  4250. pString = pOutput;
  4251. }
  4252. else
  4253. {
  4254. pString = (LPWORD)(pHashN->pLocaleHdr) +
  4255. pHashN->pLocaleHdr->SShortDate;
  4256. }
  4257. //
  4258. // Get the current setting for SDATE.
  4259. //
  4260. if (GetUserInfo( Locale,
  4261. LCType,
  4262. FIELD_OFFSET(NLS_USER_INFO, sDate),
  4263. NLS_VALUE_SDATE,
  4264. pOutput2,
  4265. ARRAYSIZE(pOutput2),
  4266. TRUE ))
  4267. {
  4268. pSep = pOutput2;
  4269. }
  4270. else
  4271. {
  4272. pSep = (LPWORD)(pHashN->pLocaleHdr) +
  4273. pHashN->pLocaleHdr->SDate;
  4274. }
  4275. //
  4276. // Get the length of the separator string.
  4277. //
  4278. SepLen = NlsStrLenW(pSep);
  4279. //
  4280. // Setup the string containing the characters to find in
  4281. // the shortdate string.
  4282. //
  4283. pFind[0] = NLS_CHAR_QUOTE;
  4284. pFind[1] = *pSep;
  4285. pFind[2] = 0;
  4286. //
  4287. // Find the date separator in the SSHORTDATE string and
  4288. // replace it with the new date separator.
  4289. //
  4290. // The new separator may be a different length than
  4291. // the old one, so must use a static buffer for the new
  4292. // short date format string.
  4293. //
  4294. pPos = pTemp;
  4295. while (pPos2 = wcspbrk(pString, pFind))
  4296. {
  4297. //
  4298. // Copy format string up to pPos2.
  4299. //
  4300. while (pString < pPos2)
  4301. {
  4302. *pPos = *pString;
  4303. pPos++;
  4304. pString++;
  4305. }
  4306. switch (*pPos2)
  4307. {
  4308. case ( NLS_CHAR_QUOTE ) :
  4309. {
  4310. //
  4311. // Copy the quote.
  4312. //
  4313. *pPos = *pString;
  4314. pPos++;
  4315. pString++;
  4316. //
  4317. // Copy what's inside the quotes.
  4318. //
  4319. while ((*pString) && (*pString != NLS_CHAR_QUOTE))
  4320. {
  4321. *pPos = *pString;
  4322. pPos++;
  4323. pString++;
  4324. }
  4325. //
  4326. // Copy the end quote.
  4327. //
  4328. *pPos = NLS_CHAR_QUOTE;
  4329. pPos++;
  4330. if (*pString)
  4331. {
  4332. pString++;
  4333. }
  4334. break;
  4335. }
  4336. default :
  4337. {
  4338. //
  4339. // Make sure it's the old separator.
  4340. //
  4341. if (NlsStrNEqualW(pString, pSep, SepLen))
  4342. {
  4343. //
  4344. // Adjust pointer to skip over old separator.
  4345. //
  4346. pString += SepLen;
  4347. //
  4348. // Copy the new separator.
  4349. //
  4350. pPos2 = (LPWSTR)lpLCData;
  4351. while (*pPos2)
  4352. {
  4353. *pPos = *pPos2;
  4354. pPos++;
  4355. pPos2++;
  4356. }
  4357. }
  4358. else
  4359. {
  4360. //
  4361. // Copy the code point and continue.
  4362. //
  4363. *pPos = *pString;
  4364. pPos++;
  4365. pString++;
  4366. }
  4367. break;
  4368. }
  4369. }
  4370. }
  4371. //
  4372. // Copy to the end of the string and null terminate it.
  4373. //
  4374. while (*pString)
  4375. {
  4376. *pPos = *pString;
  4377. pPos++;
  4378. pString++;
  4379. }
  4380. *pPos = 0;
  4381. //
  4382. // Call the server to set the registry.
  4383. //
  4384. return (SetMultipleUserInfo( LCType,
  4385. cchData,
  4386. pTemp,
  4387. lpLCData,
  4388. NULL,
  4389. NULL,
  4390. NULL ));
  4391. break;
  4392. }
  4393. case ( LOCALE_SYEARMONTH ) :
  4394. {
  4395. //
  4396. // Validate the new value. It should be no longer than
  4397. // MAX_SYEARMONTH wide characters in length.
  4398. //
  4399. // NOTE: The string may not be NULL, so it must be at least
  4400. // 2 chars long (includes null). This is checked below
  4401. // in the check for whether or not there is a date,
  4402. // month, or year delimeter.
  4403. //
  4404. if (cchData > MAX_SYEARMONTH)
  4405. {
  4406. SetLastError(ERROR_INVALID_PARAMETER);
  4407. return (FALSE);
  4408. }
  4409. //
  4410. // Make sure one of 'M' or 'y' exists in the date
  4411. // format string. If it does not, then return an error.
  4412. //
  4413. pPos = wcspbrk(lpLCData, L"My");
  4414. if (!pPos)
  4415. {
  4416. SetLastError(ERROR_INVALID_PARAMETER);
  4417. return (FALSE);
  4418. }
  4419. //
  4420. // Set the registry with the new SYEARMONTH string.
  4421. //
  4422. return (SetUserInfo( LOCALE_SYEARMONTH,
  4423. (LPWSTR)lpLCData,
  4424. cchData ));
  4425. break;
  4426. }
  4427. case ( LOCALE_SLONGDATE ) :
  4428. {
  4429. //
  4430. // Validate the new value. It should be no longer than
  4431. // MAX_SLONGDATE wide characters in length.
  4432. //
  4433. // NOTE: The string may not be NULL, so it must be at least
  4434. // 2 chars long (includes null). This is checked below
  4435. // in the check for whether or not there is a date,
  4436. // month, or year delimeter.
  4437. //
  4438. if (cchData > MAX_SLONGDATE)
  4439. {
  4440. SetLastError(ERROR_INVALID_PARAMETER);
  4441. return (FALSE);
  4442. }
  4443. //
  4444. // Make sure one of 'd' or 'M' or 'y' exists in the date
  4445. // format string. If it does not, then return an error.
  4446. //
  4447. pPos = wcspbrk(lpLCData, L"dMy");
  4448. if (!pPos)
  4449. {
  4450. SetLastError(ERROR_INVALID_PARAMETER);
  4451. return (FALSE);
  4452. }
  4453. //
  4454. // Set the registry with the new SLONGDATE string.
  4455. //
  4456. return (SetUserInfo( LOCALE_SLONGDATE,
  4457. (LPWSTR)lpLCData,
  4458. cchData ));
  4459. break;
  4460. }
  4461. case ( LOCALE_ICALENDARTYPE ) :
  4462. {
  4463. //
  4464. // Validate the new value. It should be no longer than
  4465. // MAX_ICALTYPE wide characters in length.
  4466. //
  4467. // NOTE: The string may not be NULL, so it must be at least
  4468. // 2 chars long (includes null).
  4469. //
  4470. if ((cchData < 2) || (cchData > MAX_ICALTYPE) ||
  4471. (!IsValidCalendarTypeStr(pHashN, lpLCData)))
  4472. {
  4473. SetLastError(ERROR_INVALID_PARAMETER);
  4474. return (FALSE);
  4475. }
  4476. //
  4477. // Set the registry with the new ICALENDARTYPE string.
  4478. //
  4479. return (SetUserInfo( LOCALE_ICALENDARTYPE,
  4480. (LPWSTR)lpLCData,
  4481. cchData ));
  4482. break;
  4483. }
  4484. case ( LOCALE_IFIRSTDAYOFWEEK ) :
  4485. {
  4486. //
  4487. // Validate the new value. It should be no longer than
  4488. // MAX_IFIRSTDAY wide characters in length.
  4489. // The value should be between 0 and MAX_VALUE_IFIRSTDAY.
  4490. //
  4491. // NOTE: The string may not be NULL, so it must be at least
  4492. // 2 chars long (includes null).
  4493. //
  4494. // Optimized - since MAX_IFIRSTDAY is 2.
  4495. //
  4496. if ((cchData != MAX_IFIRSTDAY) ||
  4497. (*lpLCData < NLS_CHAR_ZERO) ||
  4498. (*lpLCData > MAX_CHAR_IFIRSTDAY))
  4499. {
  4500. SetLastError(ERROR_INVALID_PARAMETER);
  4501. return (FALSE);
  4502. }
  4503. //
  4504. // Set the registry with the new IFIRSTDAYOFWEEK string.
  4505. //
  4506. return (SetUserInfo( LOCALE_IFIRSTDAYOFWEEK,
  4507. (LPWSTR)lpLCData,
  4508. cchData ));
  4509. break;
  4510. }
  4511. case ( LOCALE_IFIRSTWEEKOFYEAR ) :
  4512. {
  4513. //
  4514. // Validate the new value. It should be no longer than
  4515. // MAX_IFIRSTWEEK wide characters in length.
  4516. // The value should be between 0 and MAX_VALUE_IFIRSTWEEK.
  4517. //
  4518. // NOTE: The string may not be NULL, so it must be at least
  4519. // 2 chars long (includes null).
  4520. //
  4521. // Optimized - since MAX_IFIRSTWEEK is 2.
  4522. //
  4523. if ((cchData != MAX_IFIRSTWEEK) ||
  4524. (*lpLCData < NLS_CHAR_ZERO) ||
  4525. (*lpLCData > MAX_CHAR_IFIRSTWEEK))
  4526. {
  4527. SetLastError(ERROR_INVALID_PARAMETER);
  4528. return (FALSE);
  4529. }
  4530. //
  4531. // Set the registry with the new IFIRSTWEEKOFYEAR string.
  4532. //
  4533. return (SetUserInfo( LOCALE_IFIRSTWEEKOFYEAR,
  4534. (LPWSTR)lpLCData,
  4535. cchData ));
  4536. break;
  4537. }
  4538. default :
  4539. {
  4540. SetLastError(ERROR_INVALID_FLAGS);
  4541. return (FALSE);
  4542. }
  4543. }
  4544. //
  4545. // Return success.
  4546. //
  4547. return (TRUE);
  4548. }
  4549. ////////////////////////////////////////////////////////////////////////////
  4550. //
  4551. // GetCalendarInfoW
  4552. //
  4553. // Returns one of the various pieces of information about a particular
  4554. // calendar by querying the configuration registry. This call also
  4555. // indicates how much memory is necessary to contain the desired
  4556. // information.
  4557. //
  4558. // 12-17-97 JulieB Created.
  4559. ////////////////////////////////////////////////////////////////////////////
  4560. int WINAPI GetCalendarInfoW(
  4561. LCID Locale,
  4562. CALID Calendar,
  4563. CALTYPE CalType,
  4564. LPWSTR lpCalData,
  4565. int cchData,
  4566. LPDWORD lpValue)
  4567. {
  4568. PLOC_HASH pHashN; // ptr to LOC hash node
  4569. int Length = 0; // length of info string
  4570. LPWSTR pString; // ptr to the info string
  4571. BOOL UserOverride = TRUE; // use user override
  4572. BOOL ReturnNum = FALSE; // return number instead of string
  4573. WCHAR pTemp[MAX_REG_VAL_SIZE]; // temp buffer
  4574. UNICODE_STRING ObUnicodeStr; // value string
  4575. int Base = 0; // base for str to int conversion
  4576. LPWSTR pOptCal; // ptr to optional calendar values
  4577. PCAL_INFO pCalInfo; // ptr to calendar info
  4578. //
  4579. // Invalid Parameter Check:
  4580. // - validate LCID
  4581. // - count is negative
  4582. // - NULL data pointer AND count is not zero
  4583. //
  4584. VALIDATE_LOCALE(Locale, pHashN, FALSE);
  4585. if ((pHashN == NULL) ||
  4586. (cchData < 0) ||
  4587. ((lpCalData == NULL) && (cchData != 0)))
  4588. {
  4589. SetLastError(ERROR_INVALID_PARAMETER);
  4590. return (0);
  4591. }
  4592. //
  4593. // Need to check the parameters based on the CAL_RETURN_NUMBER
  4594. // CalType.
  4595. //
  4596. if (CalType & CAL_RETURN_NUMBER)
  4597. {
  4598. if ((lpCalData != NULL) || (cchData != 0) || (lpValue == NULL))
  4599. {
  4600. SetLastError(ERROR_INVALID_PARAMETER);
  4601. return (0);
  4602. }
  4603. }
  4604. else
  4605. {
  4606. if ((lpValue != NULL) ||
  4607. (cchData < 0) ||
  4608. ((lpCalData == NULL) && (cchData != 0)))
  4609. {
  4610. SetLastError(ERROR_INVALID_PARAMETER);
  4611. return (0);
  4612. }
  4613. }
  4614. //
  4615. // Check for NO USER OVERRIDE flag and remove the USE CP ACP flag.
  4616. //
  4617. if (CalType & CAL_NOUSEROVERRIDE)
  4618. {
  4619. //
  4620. // Flag is set, so set the boolean value and remove the flag
  4621. // from the CalType parameter (for switch statement).
  4622. //
  4623. UserOverride = FALSE;
  4624. }
  4625. if (CalType & CAL_RETURN_NUMBER)
  4626. {
  4627. //
  4628. // Flag is set, so set the boolean value and remove the flag
  4629. // from the CalType parameter (for switch statement).
  4630. //
  4631. ReturnNum = TRUE;
  4632. }
  4633. CalType &= (~(CAL_NOUSEROVERRIDE | CAL_USE_CP_ACP | CAL_RETURN_NUMBER));
  4634. //
  4635. // Validate the Calendar parameter.
  4636. //
  4637. if (((CalType != CAL_ITWODIGITYEARMAX) &&
  4638. ((pOptCal = IsValidCalendarType(pHashN, Calendar)) == NULL)) ||
  4639. (GetCalendar(Calendar, &pCalInfo) != NO_ERROR))
  4640. {
  4641. SetLastError(ERROR_INVALID_PARAMETER);
  4642. return (0);
  4643. }
  4644. //
  4645. // Return the appropriate information for the given CALTYPE.
  4646. // If user information exists for the given CALTYPE, then
  4647. // the user default is returned instead of the system default.
  4648. //
  4649. switch (CalType)
  4650. {
  4651. case ( CAL_ICALINTVALUE ) :
  4652. {
  4653. Base = 10;
  4654. //
  4655. // Get the integer value for the given calendar.
  4656. //
  4657. pString = ((POPT_CAL)pOptCal)->pCalStr;
  4658. break;
  4659. }
  4660. case ( CAL_SCALNAME ) :
  4661. {
  4662. //
  4663. // Get the calendar name for the given calendar.
  4664. //
  4665. pString = ((POPT_CAL)pOptCal)->pCalStr +
  4666. NlsStrLenW(((POPT_CAL)pOptCal)->pCalStr) + 1;
  4667. break;
  4668. }
  4669. case ( CAL_ITWODIGITYEARMAX ) :
  4670. {
  4671. Base = 10;
  4672. //
  4673. // Check if a policy is enforced for the current user,
  4674. // and if so, let's use it.
  4675. //
  4676. if (GetTwoDigitYearInfo(Calendar, pTemp, NLS_POLICY_TWO_DIGIT_YEAR_KEY))
  4677. {
  4678. pString = pTemp;
  4679. }
  4680. else
  4681. {
  4682. if (UserOverride &&
  4683. GetTwoDigitYearInfo(Calendar, pTemp, NLS_TWO_DIGIT_YEAR_KEY))
  4684. {
  4685. pString = pTemp;
  4686. }
  4687. else
  4688. {
  4689. //
  4690. // Use the default.
  4691. //
  4692. pString = (LPWORD)pCalInfo +
  4693. (((PCALENDAR_VAR)pCalInfo)->STwoDigitYearMax);
  4694. }
  4695. }
  4696. break;
  4697. }
  4698. case ( CAL_IYEAROFFSETRANGE ) :
  4699. {
  4700. Base = 10;
  4701. //
  4702. // Get the pointer to the appropriate calendar string.
  4703. //
  4704. pString = (LPWORD)pCalInfo +
  4705. (((PCALENDAR_VAR)pCalInfo)->SEraRanges);
  4706. //
  4707. // Make sure the string is NOT empty.
  4708. //
  4709. if (*pString)
  4710. {
  4711. pString = ((PERA_RANGE)pString)->pYearStr;
  4712. }
  4713. else
  4714. {
  4715. pString = L"0";
  4716. }
  4717. break;
  4718. }
  4719. case ( CAL_SERASTRING ) :
  4720. {
  4721. //
  4722. // Get the pointer to the appropriate calendar string.
  4723. //
  4724. pString = (LPWORD)pCalInfo +
  4725. (((PCALENDAR_VAR)pCalInfo)->SEraRanges);
  4726. //
  4727. // Make sure the string is NOT empty. If it is, return the
  4728. // empty string.
  4729. //
  4730. if (*pString)
  4731. {
  4732. pString = ((PERA_RANGE)pString)->pYearStr +
  4733. NlsStrLenW(((PERA_RANGE)pString)->pYearStr) + 1;
  4734. }
  4735. break;
  4736. }
  4737. case ( CAL_SSHORTDATE ) :
  4738. {
  4739. //
  4740. // Get the pointer to the appropriate calendar string.
  4741. //
  4742. pString = (LPWORD)pCalInfo +
  4743. (((PCALENDAR_VAR)pCalInfo)->SShortDate);
  4744. //
  4745. // Make sure the string is NOT empty. If it is, use the
  4746. // locale's short date string.
  4747. //
  4748. if (*pString == 0)
  4749. {
  4750. pString = (LPWORD)(pHashN->pLocaleHdr) +
  4751. pHashN->pLocaleHdr->SShortDate;
  4752. }
  4753. break;
  4754. }
  4755. case ( CAL_SLONGDATE ) :
  4756. {
  4757. //
  4758. // Get the pointer to the appropriate calendar string.
  4759. //
  4760. pString = (LPWORD)pCalInfo +
  4761. (((PCALENDAR_VAR)pCalInfo)->SLongDate);
  4762. //
  4763. // Make sure the string is NOT empty. If it is, use the
  4764. // locale's long date string.
  4765. //
  4766. if (*pString == 0)
  4767. {
  4768. pString = (LPWORD)(pHashN->pLocaleHdr) +
  4769. pHashN->pLocaleHdr->SLongDate;
  4770. }
  4771. break;
  4772. }
  4773. case ( CAL_SYEARMONTH ) :
  4774. {
  4775. //
  4776. // Get the pointer to the appropriate calendar string.
  4777. //
  4778. pString = (LPWORD)pCalInfo +
  4779. (((PCALENDAR_VAR)pCalInfo)->SYearMonth);
  4780. //
  4781. // Make sure the string is NOT empty. If it is, use the
  4782. // locale's year month string.
  4783. //
  4784. if (*pString == 0)
  4785. {
  4786. pString = (LPWORD)(pHashN->pLocaleHdr) +
  4787. pHashN->pLocaleHdr->SYearMonth;
  4788. }
  4789. break;
  4790. }
  4791. case ( CAL_SDAYNAME1 ) :
  4792. case ( CAL_SDAYNAME2 ) :
  4793. case ( CAL_SDAYNAME3 ) :
  4794. case ( CAL_SDAYNAME4 ) :
  4795. case ( CAL_SDAYNAME5 ) :
  4796. case ( CAL_SDAYNAME6 ) :
  4797. case ( CAL_SDAYNAME7 ) :
  4798. case ( CAL_SABBREVDAYNAME1 ) :
  4799. case ( CAL_SABBREVDAYNAME2 ) :
  4800. case ( CAL_SABBREVDAYNAME3 ) :
  4801. case ( CAL_SABBREVDAYNAME4 ) :
  4802. case ( CAL_SABBREVDAYNAME5 ) :
  4803. case ( CAL_SABBREVDAYNAME6 ) :
  4804. case ( CAL_SABBREVDAYNAME7 ) :
  4805. case ( CAL_SMONTHNAME1 ) :
  4806. case ( CAL_SMONTHNAME2 ) :
  4807. case ( CAL_SMONTHNAME3 ) :
  4808. case ( CAL_SMONTHNAME4 ) :
  4809. case ( CAL_SMONTHNAME5 ) :
  4810. case ( CAL_SMONTHNAME6 ) :
  4811. case ( CAL_SMONTHNAME7 ) :
  4812. case ( CAL_SMONTHNAME8 ) :
  4813. case ( CAL_SMONTHNAME9 ) :
  4814. case ( CAL_SMONTHNAME10 ) :
  4815. case ( CAL_SMONTHNAME11 ) :
  4816. case ( CAL_SMONTHNAME12 ) :
  4817. case ( CAL_SMONTHNAME13 ) :
  4818. case ( CAL_SABBREVMONTHNAME1 ) :
  4819. case ( CAL_SABBREVMONTHNAME2 ) :
  4820. case ( CAL_SABBREVMONTHNAME3 ) :
  4821. case ( CAL_SABBREVMONTHNAME4 ) :
  4822. case ( CAL_SABBREVMONTHNAME5 ) :
  4823. case ( CAL_SABBREVMONTHNAME6 ) :
  4824. case ( CAL_SABBREVMONTHNAME7 ) :
  4825. case ( CAL_SABBREVMONTHNAME8 ) :
  4826. case ( CAL_SABBREVMONTHNAME9 ) :
  4827. case ( CAL_SABBREVMONTHNAME10 ) :
  4828. case ( CAL_SABBREVMONTHNAME11 ) :
  4829. case ( CAL_SABBREVMONTHNAME12 ) :
  4830. case ( CAL_SABBREVMONTHNAME13 ) :
  4831. {
  4832. //
  4833. // Get the pointer to the appropriate calendar string if the
  4834. // IfNames flag is set for the calendar.
  4835. //
  4836. pString = NULL;
  4837. if (((PCALENDAR_VAR)pCalInfo)->IfNames)
  4838. {
  4839. pString = (LPWORD)pCalInfo +
  4840. *((LPWORD)((LPBYTE)(pCalInfo) +
  4841. (FIELD_OFFSET(CALENDAR_VAR, SDayName1) +
  4842. ((CalType - CAL_SDAYNAME1) * sizeof(WORD)))));
  4843. }
  4844. //
  4845. // Make sure the string is NOT empty. If it is, use the
  4846. // locale's string.
  4847. //
  4848. if ((pString == NULL) || (*pString == 0))
  4849. {
  4850. pString = (LPWORD)(pHashN->pLocaleHdr) +
  4851. *((LPWORD)((LPBYTE)(pHashN->pLocaleHdr) +
  4852. (FIELD_OFFSET(LOCALE_VAR, SDayName1) +
  4853. ((CalType - CAL_SDAYNAME1) * sizeof(WORD)))));
  4854. }
  4855. break;
  4856. }
  4857. default :
  4858. {
  4859. SetLastError(ERROR_INVALID_FLAGS);
  4860. return (0);
  4861. }
  4862. }
  4863. //
  4864. // See if the caller wants the value in the form of a number instead
  4865. // of a string.
  4866. //
  4867. if (ReturnNum)
  4868. {
  4869. //
  4870. // Make sure the flags are valid and that the DWORD buffer
  4871. // is not NULL.
  4872. //
  4873. if (Base == 0)
  4874. {
  4875. SetLastError(ERROR_INVALID_FLAGS);
  4876. return (0);
  4877. }
  4878. if (lpValue == NULL)
  4879. {
  4880. SetLastError(ERROR_INVALID_PARAMETER);
  4881. return (0);
  4882. }
  4883. //
  4884. // Convert the string to an int and return 2 (1 DWORD = 2 WORDS).
  4885. //
  4886. RtlInitUnicodeString(&ObUnicodeStr, pString);
  4887. if (RtlUnicodeStringToInteger(&ObUnicodeStr, Base, lpValue))
  4888. {
  4889. SetLastError(ERROR_INVALID_FLAGS);
  4890. return (0);
  4891. }
  4892. return (2);
  4893. }
  4894. //
  4895. // Get the length (in characters) of the string to copy.
  4896. //
  4897. if (Length == 0)
  4898. {
  4899. Length = NlsStrLenW(pString);
  4900. }
  4901. //
  4902. // Add one for the null termination. All strings should be null
  4903. // terminated.
  4904. //
  4905. Length++;
  4906. //
  4907. // Check cchData for size of given buffer.
  4908. //
  4909. if (cchData == 0)
  4910. {
  4911. //
  4912. // If cchData is 0, then we can't use lpCalData. In this
  4913. // case, we simply want to return the length (in characters) of
  4914. // the string to be copied.
  4915. //
  4916. return (Length);
  4917. }
  4918. else if (cchData < Length)
  4919. {
  4920. //
  4921. // The buffer is too small for the string, so return an error
  4922. // and zero bytes written.
  4923. //
  4924. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  4925. return (0);
  4926. }
  4927. //
  4928. // Copy the string to lpCalData and null terminate it.
  4929. // Return the number of characters copied.
  4930. //
  4931. wcsncpy(lpCalData, pString, Length - 1);
  4932. lpCalData[Length - 1] = 0;
  4933. return (Length);
  4934. }
  4935. ////////////////////////////////////////////////////////////////////////////
  4936. //
  4937. // SetCalendarInfoW
  4938. //
  4939. // Sets one of the various pieces of information about a particular
  4940. // calendar by making an entry in the user's portion of the configuration
  4941. // registry. This will only affect the user override portion of the
  4942. // calendar settings. The system defaults will never be reset.
  4943. //
  4944. // 12-17-97 JulieB Created.
  4945. ////////////////////////////////////////////////////////////////////////////
  4946. BOOL WINAPI SetCalendarInfoW(
  4947. LCID Locale,
  4948. CALID Calendar,
  4949. CALTYPE CalType,
  4950. LPCWSTR lpCalData)
  4951. {
  4952. PLOC_HASH pHashN; // ptr to LOC hash node
  4953. int cchData; // length of lpLCData
  4954. PCAL_INFO pCalInfo; // ptr to calendar info
  4955. UNICODE_STRING ObUnicodeStr; // value string
  4956. DWORD Value; // value
  4957. //
  4958. // Invalid Parameter Check:
  4959. // - validate LCID
  4960. // - NULL data pointer
  4961. //
  4962. // NOTE: invalid type is checked in the switch statement below.
  4963. //
  4964. VALIDATE_LOCALE(Locale, pHashN, FALSE);
  4965. if ((pHashN == NULL) || (lpCalData == NULL))
  4966. {
  4967. SetLastError(ERROR_INVALID_PARAMETER);
  4968. return (FALSE);
  4969. }
  4970. //
  4971. // Get the length of the buffer.
  4972. //
  4973. cchData = NlsStrLenW(lpCalData) + 1;
  4974. //
  4975. // Validate the Calendar parameter.
  4976. //
  4977. if (GetCalendar(Calendar, &pCalInfo) != NO_ERROR)
  4978. {
  4979. SetLastError(ERROR_INVALID_PARAMETER);
  4980. return (FALSE);
  4981. }
  4982. //
  4983. // Set the appropriate user information for the given CALTYPE.
  4984. //
  4985. CalType &= (~CAL_USE_CP_ACP);
  4986. switch (CalType)
  4987. {
  4988. case ( CAL_ITWODIGITYEARMAX ) :
  4989. {
  4990. //
  4991. // Get the default value to make sure the calendar is
  4992. // allowed to be set. Things like the Japanese Era calendar
  4993. // may not be set.
  4994. //
  4995. RtlInitUnicodeString( &ObUnicodeStr,
  4996. ((LPWORD)pCalInfo +
  4997. (((PCALENDAR_VAR)pCalInfo)->STwoDigitYearMax)) );
  4998. RtlUnicodeStringToInteger(&ObUnicodeStr, 10, &Value);
  4999. if (Value <= 99)
  5000. {
  5001. SetLastError(ERROR_INVALID_PARAMETER);
  5002. return (FALSE);
  5003. }
  5004. //
  5005. // Validate the new value. It should be no longer than
  5006. // MAX_ITWODIGITYEAR wide characters in length.
  5007. // It should be between 99 and 9999.
  5008. //
  5009. if ((cchData > MAX_ITWODIGITYEAR) ||
  5010. (cchData < 3) ||
  5011. ((cchData == 3) &&
  5012. ((*lpCalData != NLS_CHAR_NINE) ||
  5013. (*(lpCalData + 1) != NLS_CHAR_NINE))))
  5014. {
  5015. SetLastError(ERROR_INVALID_PARAMETER);
  5016. return (FALSE);
  5017. }
  5018. //
  5019. // Set the registry with the new TwoDigitYearMax string.
  5020. //
  5021. return (SetTwoDigitYearInfo(Calendar, lpCalData, cchData));
  5022. break;
  5023. }
  5024. default :
  5025. {
  5026. SetLastError(ERROR_INVALID_FLAGS);
  5027. return (FALSE);
  5028. }
  5029. }
  5030. //
  5031. // Return success.
  5032. //
  5033. return (TRUE);
  5034. }
  5035. //-------------------------------------------------------------------------//
  5036. // INTERNAL ROUTINES //
  5037. //-------------------------------------------------------------------------//
  5038. ////////////////////////////////////////////////////////////////////////////
  5039. //
  5040. // SetUserInfo
  5041. //
  5042. // This routine sets the given value in the registry with the given data.
  5043. // All values must be of the type REG_SZ.
  5044. //
  5045. // NOTE: The handle to the registry key must be closed by the CALLER if
  5046. // the return value is NO_ERROR.
  5047. //
  5048. // 07-14-93 JulieB Created.
  5049. ////////////////////////////////////////////////////////////////////////////
  5050. BOOL SetUserInfo(
  5051. LCTYPE LCType,
  5052. LPWSTR pData,
  5053. ULONG DataLength)
  5054. {
  5055. NTSTATUS Status;
  5056. //
  5057. // Get the length of the value string.
  5058. //
  5059. DataLength *= sizeof(WCHAR);
  5060. //
  5061. // If there is no logged on user or the current security context
  5062. // isn't the logged-on interactive user, then set the registry
  5063. // value directly.
  5064. //
  5065. if (! NT_SUCCESS( NlsCheckForInteractiveUser() ))
  5066. {
  5067. return (SetCurrentUserRegValue(LCType, pData, DataLength));
  5068. }
  5069. // Call into server side (csrss.exe) to set the registry and update the cache for the current user.
  5070. Status = CsrBasepNlsSetUserInfo(LCType,
  5071. pData,
  5072. DataLength);
  5073. //
  5074. // Check to see if the "set" operation succeeded.
  5075. //
  5076. if (!NT_SUCCESS(Status))
  5077. {
  5078. //
  5079. // We got a failure. Try using just the registry apis to set the
  5080. // registry. It's possible that the cache is not valid yet if this
  5081. // is called from setup or winlogon.
  5082. //
  5083. return (SetCurrentUserRegValue(LCType, pData, DataLength));
  5084. }
  5085. //
  5086. // Return success.
  5087. //
  5088. return (TRUE);
  5089. }
  5090. ////////////////////////////////////////////////////////////////////////////
  5091. //
  5092. // SetCurrentUserRegValue
  5093. //
  5094. // Set the registry value for the current security context. This routine
  5095. // is called when the current security context is different from the logged
  5096. // on user.
  5097. //
  5098. // 12-26-98 SamerA Created.
  5099. ////////////////////////////////////////////////////////////////////////////
  5100. BOOL SetCurrentUserRegValue(
  5101. LCTYPE LCType,
  5102. LPWSTR pData,
  5103. ULONG DataLength)
  5104. {
  5105. HANDLE hKey = NULL;
  5106. LPWSTR pValue;
  5107. LPWSTR pCache;
  5108. if (0 == ValidateLCType(pNlsUserInfo, LCType, &pValue, &pCache))
  5109. {
  5110. SetLastError(ERROR_INVALID_PARAMETER);
  5111. return FALSE;
  5112. }
  5113. //
  5114. // Open the registry for the current security context
  5115. //
  5116. OPEN_CPANEL_INTL_KEY(hKey, FALSE, KEY_READ | KEY_WRITE);
  5117. if (SetRegValue(hKey, pValue, pData, DataLength) != NO_ERROR)
  5118. {
  5119. CLOSE_REG_KEY(hKey);
  5120. SetLastError(ERROR_INVALID_ACCESS);
  5121. return (FALSE);
  5122. }
  5123. CLOSE_REG_KEY(hKey);
  5124. //
  5125. // Flush the process cache entry, if needed.
  5126. //
  5127. NlsFlushProcessCache(LCType);
  5128. return (TRUE);
  5129. }
  5130. ////////////////////////////////////////////////////////////////////////////
  5131. //
  5132. // SetMultipleUserInfoInRegistry
  5133. //
  5134. // This routine sets the given multiple values in the registry with the
  5135. // given data. All values must be of the type REG_SZ.
  5136. //
  5137. // 06-11-98 JulieB Created.
  5138. ////////////////////////////////////////////////////////////////////////////
  5139. BOOL SetMultipleUserInfoInRegistry(
  5140. DWORD dwFlags,
  5141. int cchData,
  5142. LPCWSTR pPicture,
  5143. LPCWSTR pSeparator,
  5144. LPCWSTR pOrder,
  5145. LPCWSTR pTLZero,
  5146. LPCWSTR pTimeMarkPosn)
  5147. {
  5148. HANDLE hKey = NULL;
  5149. ULONG rc = 0L;
  5150. //
  5151. // Open the Control Panel International registry key.
  5152. //
  5153. OPEN_CPANEL_INTL_KEY(hKey, FALSE, KEY_READ | KEY_WRITE);
  5154. //
  5155. // Save the appropriate values in the registry based on the flags.
  5156. //
  5157. switch (dwFlags)
  5158. {
  5159. case ( LOCALE_STIMEFORMAT ) :
  5160. {
  5161. rc = SetRegValue( hKey,
  5162. NLS_VALUE_STIMEFORMAT,
  5163. pPicture,
  5164. cchData * sizeof(WCHAR) );
  5165. if (NT_SUCCESS(rc))
  5166. {
  5167. NlsFlushProcessCache(LOCALE_STIMEFORMAT);
  5168. rc = SetRegValue( hKey,
  5169. NLS_VALUE_STIME,
  5170. pSeparator,
  5171. (lstrlen(pSeparator) + 1) * sizeof(WCHAR) );
  5172. }
  5173. if (NT_SUCCESS(rc))
  5174. {
  5175. NlsFlushProcessCache(LOCALE_STIME);
  5176. rc = SetRegValue( hKey,
  5177. NLS_VALUE_ITIME,
  5178. pOrder,
  5179. (lstrlen(pOrder) + 1) * sizeof(WCHAR) );
  5180. }
  5181. if (NT_SUCCESS(rc))
  5182. {
  5183. NlsFlushProcessCache(LOCALE_ITIME);
  5184. rc = SetRegValue( hKey,
  5185. NLS_VALUE_ITLZERO,
  5186. pTLZero,
  5187. (lstrlen(pTLZero) + 1) * sizeof(WCHAR) );
  5188. }
  5189. if (NT_SUCCESS(rc))
  5190. {
  5191. NlsFlushProcessCache(LOCALE_ITLZERO);
  5192. rc = SetRegValue( hKey,
  5193. NLS_VALUE_ITIMEMARKPOSN,
  5194. pTimeMarkPosn,
  5195. (lstrlen(pTimeMarkPosn) + 1) * sizeof(WCHAR) );
  5196. if (NT_SUCCESS(rc))
  5197. {
  5198. NlsFlushProcessCache(LOCALE_ITIMEMARKPOSN);
  5199. }
  5200. }
  5201. break;
  5202. }
  5203. case ( LOCALE_STIME ) :
  5204. {
  5205. rc = SetRegValue( hKey,
  5206. NLS_VALUE_STIME,
  5207. pSeparator,
  5208. cchData * sizeof(WCHAR) );
  5209. if (NT_SUCCESS(rc))
  5210. {
  5211. NlsFlushProcessCache(LOCALE_STIME);
  5212. rc = SetRegValue( hKey,
  5213. NLS_VALUE_STIMEFORMAT,
  5214. pPicture,
  5215. (lstrlen(pPicture) + 1) * sizeof(WCHAR) );
  5216. if (NT_SUCCESS(rc))
  5217. {
  5218. NlsFlushProcessCache(LOCALE_STIMEFORMAT);
  5219. }
  5220. }
  5221. break;
  5222. }
  5223. case ( LOCALE_ITIME ) :
  5224. {
  5225. rc = SetRegValue( hKey,
  5226. NLS_VALUE_ITIME,
  5227. pOrder,
  5228. cchData * sizeof(WCHAR) );
  5229. if (NT_SUCCESS(rc))
  5230. {
  5231. NlsFlushProcessCache(LOCALE_ITIME);
  5232. rc = SetRegValue( hKey,
  5233. NLS_VALUE_STIMEFORMAT,
  5234. pPicture,
  5235. (lstrlen(pPicture) + 1) * sizeof(WCHAR) );
  5236. if (NT_SUCCESS(rc))
  5237. {
  5238. NlsFlushProcessCache(LOCALE_STIMEFORMAT);
  5239. }
  5240. }
  5241. break;
  5242. }
  5243. case ( LOCALE_SSHORTDATE ) :
  5244. {
  5245. rc = SetRegValue( hKey,
  5246. NLS_VALUE_SSHORTDATE,
  5247. pPicture,
  5248. cchData * sizeof(WCHAR) );
  5249. if (NT_SUCCESS(rc))
  5250. {
  5251. NlsFlushProcessCache(LOCALE_SSHORTDATE);
  5252. rc = SetRegValue( hKey,
  5253. NLS_VALUE_SDATE,
  5254. pSeparator,
  5255. (lstrlen(pSeparator) + 1) * sizeof(WCHAR) );
  5256. }
  5257. if (NT_SUCCESS(rc))
  5258. {
  5259. NlsFlushProcessCache(LOCALE_SDATE);
  5260. rc = SetRegValue( hKey,
  5261. NLS_VALUE_IDATE,
  5262. pOrder,
  5263. (lstrlen(pOrder) + 1) * sizeof(WCHAR) );
  5264. if (NT_SUCCESS(rc))
  5265. {
  5266. NlsFlushProcessCache(LOCALE_IDATE);
  5267. }
  5268. }
  5269. break;
  5270. }
  5271. case ( LOCALE_SDATE ) :
  5272. {
  5273. rc = SetRegValue( hKey,
  5274. NLS_VALUE_SDATE,
  5275. pSeparator,
  5276. cchData * sizeof(WCHAR) );
  5277. if (NT_SUCCESS(rc))
  5278. {
  5279. NlsFlushProcessCache(LOCALE_SDATE);
  5280. rc = SetRegValue( hKey,
  5281. NLS_VALUE_SSHORTDATE,
  5282. pPicture,
  5283. (lstrlen(pPicture) + 1) * sizeof(WCHAR) );
  5284. if (NT_SUCCESS(rc))
  5285. {
  5286. NlsFlushProcessCache(LOCALE_SSHORTDATE);
  5287. }
  5288. }
  5289. break;
  5290. }
  5291. default :
  5292. {
  5293. CLOSE_REG_KEY(hKey);
  5294. return (FALSE);
  5295. }
  5296. }
  5297. //
  5298. // Close the registry key.
  5299. //
  5300. CLOSE_REG_KEY(hKey);
  5301. //
  5302. // Return the result.
  5303. //
  5304. return (rc == NO_ERROR);
  5305. }
  5306. ////////////////////////////////////////////////////////////////////////////
  5307. //
  5308. // SetMultipleUserInfo
  5309. //
  5310. // This routine calls the server to set multiple registry values. This way,
  5311. // only one client/server transition is necessary.
  5312. //
  5313. // 08-19-94 JulieB Created.
  5314. ////////////////////////////////////////////////////////////////////////////
  5315. BOOL SetMultipleUserInfo(
  5316. DWORD dwFlags,
  5317. int cchData,
  5318. LPCWSTR pPicture,
  5319. LPCWSTR pSeparator,
  5320. LPCWSTR pOrder,
  5321. LPCWSTR pTLZero,
  5322. LPCWSTR pTimeMarkPosn)
  5323. {
  5324. NTSTATUS Status;
  5325. //
  5326. // If there is no logged on user or the current security context
  5327. // isn't the logged-on interactive user, then set the registry
  5328. // value directly.
  5329. //
  5330. if (! NT_SUCCESS( NlsCheckForInteractiveUser() ))
  5331. {
  5332. if (SetMultipleUserInfoInRegistry( dwFlags,
  5333. cchData,
  5334. pPicture,
  5335. pSeparator,
  5336. pOrder,
  5337. pTLZero,
  5338. pTimeMarkPosn ) == FALSE)
  5339. {
  5340. SetLastError(ERROR_INVALID_ACCESS);
  5341. return (FALSE);
  5342. }
  5343. return (TRUE);
  5344. }
  5345. Status = CsrBasepNlsSetMultipleUserInfo(dwFlags,
  5346. cchData,
  5347. pPicture,
  5348. pSeparator,
  5349. pOrder,
  5350. pTLZero,
  5351. pTimeMarkPosn
  5352. );
  5353. //
  5354. // Check to see if the "set" operation succeeded.
  5355. //
  5356. if (!NT_SUCCESS(Status))
  5357. {
  5358. //
  5359. // We got a failure. Try using just the registry apis to set the
  5360. // registry. It's possible that the cache is not valid yet if this
  5361. // is called from setup or winlogon.
  5362. //
  5363. if (SetMultipleUserInfoInRegistry( dwFlags,
  5364. cchData,
  5365. pPicture,
  5366. pSeparator,
  5367. pOrder,
  5368. pTLZero,
  5369. pTimeMarkPosn ) == FALSE)
  5370. {
  5371. SetLastError(ERROR_INVALID_ACCESS);
  5372. return (FALSE);
  5373. }
  5374. }
  5375. //
  5376. // Return success.
  5377. //
  5378. return (TRUE);
  5379. }
  5380. ////////////////////////////////////////////////////////////////////////////
  5381. //
  5382. // GetTwoDigitYearInfo
  5383. //
  5384. // This routine gets the two digit year info from the registry.
  5385. //
  5386. // 12-17-97 JulieB Created.
  5387. ////////////////////////////////////////////////////////////////////////////
  5388. BOOL GetTwoDigitYearInfo(
  5389. CALID Calendar,
  5390. LPWSTR pYearInfo,
  5391. PWSTR pwszKeyPath)
  5392. {
  5393. HANDLE hKey = NULL; // handle to key
  5394. WCHAR pCalStr[MAX_PATH]; // ptr to calendar id string
  5395. PKEY_VALUE_FULL_INFORMATION pKeyValueFull; // ptr to query info
  5396. BYTE pStatic[MAX_KEY_VALUE_FULLINFO]; // ptr to static buffer
  5397. BOOL IfAlloc = FALSE; // if buffer was allocated
  5398. ULONG rc = 0L; // return code
  5399. BOOL bResult = FALSE; // result
  5400. UNICODE_STRING ObUnicodeStr; // year string
  5401. DWORD Year; // year value
  5402. //
  5403. // Open the Control Panel International registry key.
  5404. //
  5405. if (OpenRegKey( &hKey,
  5406. NULL,
  5407. pwszKeyPath,
  5408. KEY_READ ) != NO_ERROR)
  5409. {
  5410. return (FALSE);
  5411. }
  5412. //
  5413. // Convert calendar value to Unicode string.
  5414. //
  5415. if (NlsConvertIntegerToString(Calendar, 10, 0, pCalStr, MAX_PATH))
  5416. {
  5417. NtClose(hKey);
  5418. return (FALSE);
  5419. }
  5420. //
  5421. // Query the registry for the TwoDigitYearMax value.
  5422. //
  5423. pKeyValueFull = (PKEY_VALUE_FULL_INFORMATION)pStatic;
  5424. rc = QueryRegValue( hKey,
  5425. pCalStr,
  5426. &pKeyValueFull,
  5427. MAX_KEY_VALUE_FULLINFO,
  5428. &IfAlloc );
  5429. //
  5430. // Close the registry key.
  5431. //
  5432. NtClose(hKey);
  5433. //
  5434. // See if the TwoDigitYearMax value is present.
  5435. //
  5436. if (rc != NO_ERROR)
  5437. {
  5438. return (FALSE);
  5439. }
  5440. //
  5441. // See if the TwoDigitYearMax data is present.
  5442. //
  5443. if (pKeyValueFull->DataLength > 2)
  5444. {
  5445. //
  5446. // Copy the info.
  5447. //
  5448. NlsStrCpyW(pYearInfo, GET_VALUE_DATA_PTR(pKeyValueFull));
  5449. //
  5450. // Make sure the value is between 99 and 9999.
  5451. //
  5452. RtlInitUnicodeString(&ObUnicodeStr, pYearInfo);
  5453. if ((RtlUnicodeStringToInteger(&ObUnicodeStr, 10, &Year) == NO_ERROR) &&
  5454. (Year >= 99) && (Year <= 9999))
  5455. {
  5456. bResult = TRUE;
  5457. }
  5458. }
  5459. //
  5460. // Free the buffer used for the query.
  5461. //
  5462. if (IfAlloc)
  5463. {
  5464. NLS_FREE_MEM(pKeyValueFull);
  5465. }
  5466. //
  5467. // Return the result.
  5468. //
  5469. return (bResult);
  5470. }
  5471. ////////////////////////////////////////////////////////////////////////////
  5472. //
  5473. // SetTwoDigitYearInfo
  5474. //
  5475. // This routine sets the two digit year info in the registry.
  5476. //
  5477. // 12-17-97 JulieB Created.
  5478. ////////////////////////////////////////////////////////////////////////////
  5479. BOOL SetTwoDigitYearInfo(
  5480. CALID Calendar,
  5481. LPCWSTR pYearInfo,
  5482. int cchData)
  5483. {
  5484. HANDLE hKey = NULL; // handle to key
  5485. WCHAR pCalStr[MAX_PATH]; // ptr to calendar id string
  5486. ULONG rc = 0L; // return code
  5487. //
  5488. // Open the Control Panel International registry key.
  5489. // If it doesn't exist, then we have to create each subkey
  5490. // separately.
  5491. //
  5492. if (OpenRegKey( &hKey,
  5493. NULL,
  5494. NLS_TWO_DIGIT_YEAR_KEY,
  5495. KEY_READ | KEY_WRITE ) != NO_ERROR)
  5496. {
  5497. //
  5498. // Registry key does not exist, so create each subkey
  5499. // separately.
  5500. //
  5501. if (CreateRegKey( &hKey,
  5502. NULL,
  5503. NLS_CALENDARS_KEY,
  5504. KEY_READ | KEY_WRITE ) == NO_ERROR)
  5505. {
  5506. if (CreateRegKey( &hKey,
  5507. NULL,
  5508. NLS_TWO_DIGIT_YEAR_KEY,
  5509. KEY_READ | KEY_WRITE ) != NO_ERROR)
  5510. {
  5511. return (FALSE);
  5512. }
  5513. }
  5514. else
  5515. {
  5516. return (FALSE);
  5517. }
  5518. }
  5519. //
  5520. // Make sure all Gregorian calendars are set to the same value.
  5521. //
  5522. switch (Calendar)
  5523. {
  5524. case ( 1 ) :
  5525. case ( 2 ) :
  5526. case ( 9 ) :
  5527. case ( 10 ) :
  5528. case ( 11 ) :
  5529. case ( 12 ) :
  5530. {
  5531. rc = SetRegValue(hKey, L"1", pYearInfo, (ULONG)cchData * sizeof(WCHAR));
  5532. if (rc == NO_ERROR)
  5533. {
  5534. rc = SetRegValue(hKey, L"2", pYearInfo, (ULONG)cchData * sizeof(WCHAR));
  5535. }
  5536. if (rc == NO_ERROR)
  5537. {
  5538. rc = SetRegValue(hKey, L"9", pYearInfo, (ULONG)cchData * sizeof(WCHAR));
  5539. }
  5540. if (rc == NO_ERROR)
  5541. {
  5542. rc = SetRegValue(hKey, L"10", pYearInfo, (ULONG)cchData * sizeof(WCHAR));
  5543. }
  5544. if (rc == NO_ERROR)
  5545. {
  5546. rc = SetRegValue(hKey, L"11", pYearInfo, (ULONG)cchData * sizeof(WCHAR));
  5547. }
  5548. if (rc == NO_ERROR)
  5549. {
  5550. rc = SetRegValue(hKey, L"12", pYearInfo, (ULONG)cchData * sizeof(WCHAR));
  5551. }
  5552. break;
  5553. }
  5554. default :
  5555. {
  5556. //
  5557. // Convert calendar value to Unicode string.
  5558. //
  5559. if (NlsConvertIntegerToString(Calendar, 10, 0, pCalStr, MAX_PATH))
  5560. {
  5561. NtClose(hKey);
  5562. return (FALSE);
  5563. }
  5564. //
  5565. // Set the TwoDigitYearMax value in the registry.
  5566. //
  5567. rc = SetRegValue(hKey, pCalStr, pYearInfo, (ULONG)cchData * sizeof(WCHAR));
  5568. break;
  5569. }
  5570. }
  5571. //
  5572. // Update the NlsCacheUpdateCount inside csrss
  5573. //
  5574. if (rc == NO_ERROR)
  5575. {
  5576. CsrBasepNlsUpdateCacheCount();
  5577. }
  5578. //
  5579. // Close the registry key.
  5580. //
  5581. NtClose(hKey);
  5582. //
  5583. // Return the result.
  5584. //
  5585. return (rc == NO_ERROR);
  5586. }