Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2526 lines
97 KiB

  1. /*++
  2. Copyright (c) 1991-2000, Microsoft Corporation All rights reserved.
  3. Module Name:
  4. enum.c
  5. Abstract:
  6. This file contains functions that enumerate the user's portion of the
  7. registry for installed and supported locale ids and code page ids.
  8. APIs found in this file:
  9. EnumSystemLanguageGroupsW
  10. EnumLanguageGroupLocalesW
  11. EnumUILanguagesW
  12. EnumSystemLocalesW
  13. EnumSystemCodePagesW
  14. EnumCalendarInfoW
  15. EnumCalendarInfoExW
  16. EnumTimeFormatsW
  17. EnumDateFormatsW
  18. EnumDateFormatsExW
  19. Revision History:
  20. 08-02-93 JulieB Created.
  21. --*/
  22. //
  23. // Include Files.
  24. //
  25. #include "nls.h"
  26. #include "nlssafe.h"
  27. //
  28. // Constant Declarations
  29. //
  30. #define ENUM_BUF_SIZE 9 // buffer size (wchar) for lcid or cpid (incl null)
  31. #define ENUM_MAX_CP_SIZE 5 // max size (wchar) for cp id in registry
  32. #define ENUM_LOCALE_SIZE 8 // buffer size (wchar) for locale id in registry
  33. #define ENUM_MAX_LG_SIZE 2 // max size (wchar) for language group id in registry
  34. #define ENUM_MAX_UILANG_SIZE 4 // max size (wchar) for UI langguage id in registry
  35. //
  36. // Forward Declarations.
  37. //
  38. BOOL
  39. EnumDateTime(
  40. NLS_ENUMPROC lpDateTimeFmtEnumProc,
  41. LCID Locale,
  42. LCTYPE LCType,
  43. DWORD dwFlags,
  44. SIZE_T CacheOffset,
  45. LPWSTR pRegValue,
  46. PLOCALE_VAR pLocaleHdr,
  47. LPWSTR pDateTime,
  48. LPWSTR pEndDateTime,
  49. ULONG CalDateOffset,
  50. ULONG EndCalDateOffset,
  51. BOOL fCalendarInfo,
  52. BOOL fUnicodeVer,
  53. BOOL fExVersion);
  54. //-------------------------------------------------------------------------//
  55. // INTERNAL MACROS //
  56. //-------------------------------------------------------------------------//
  57. ////////////////////////////////////////////////////////////////////////////
  58. //
  59. // NLS_CALL_ENUMPROC_BREAK
  60. //
  61. // Calls the appropriate EnumProc routine. If the fUnicodeVer flag is TRUE,
  62. // then it calls the Unicode version of the callback function. Otherwise,
  63. // it calls the Ansi dispatch routine to translate the string to Ansi and
  64. // then call the Ansi version of the callback function.
  65. //
  66. // This macro will do a break if the enumeration routine returns FALSE.
  67. //
  68. // DEFINED AS A MACRO.
  69. //
  70. // 11-10-93 JulieB Created.
  71. ////////////////////////////////////////////////////////////////////////////
  72. #define NLS_CALL_ENUMPROC_BREAK( Locale, \
  73. lpNlsEnumProc, \
  74. dwFlags, \
  75. pUnicodeBuffer, \
  76. fUnicodeVer ) \
  77. { \
  78. /* \
  79. * Call the appropriate callback function. \
  80. */ \
  81. if (fUnicodeVer) \
  82. { \
  83. /* \
  84. * Call the Unicode callback function. \
  85. */ \
  86. if (((*lpNlsEnumProc)(pUnicodeBuffer)) != TRUE) \
  87. { \
  88. break; \
  89. } \
  90. } \
  91. else \
  92. { \
  93. /* \
  94. * Call the Ansi callback function. \
  95. */ \
  96. if (NlsDispatchAnsiEnumProc( Locale, \
  97. lpNlsEnumProc, \
  98. dwFlags, \
  99. pUnicodeBuffer, \
  100. NULL, \
  101. 0, \
  102. 0, \
  103. 0, \
  104. 0 ) != TRUE) \
  105. { \
  106. break; \
  107. } \
  108. } \
  109. }
  110. ////////////////////////////////////////////////////////////////////////////
  111. //
  112. // NLS_CALL_ENUMPROC_BREAK_2
  113. //
  114. // Calls the appropriate EnumProc routine. If the fUnicodeVer flag is TRUE,
  115. // then it calls the Unicode version of the callback function. Otherwise,
  116. // it calls the Ansi dispatch routine to translate the strings to Ansi and
  117. // then call the Ansi version of the callback function.
  118. //
  119. // This macro will do a break if the enumeration routine returns FALSE.
  120. //
  121. // DEFINED AS A MACRO.
  122. //
  123. // 03-10-98 JulieB Created.
  124. ////////////////////////////////////////////////////////////////////////////
  125. #define NLS_CALL_ENUMPROC_BREAK_2( Locale, \
  126. lpNlsEnumProc, \
  127. dwFlags, \
  128. LanguageGroup, \
  129. EnumLocale, \
  130. pUnicodeBuffer, \
  131. lParam, \
  132. fUnicodeVer ) \
  133. { \
  134. /* \
  135. * Call the appropriate callback function. \
  136. */ \
  137. if (fUnicodeVer) \
  138. { \
  139. /* \
  140. * Call the Unicode callback function. \
  141. */ \
  142. if (((*((NLS_ENUMPROC2)lpNlsEnumProc))( LanguageGroup, \
  143. EnumLocale, \
  144. pUnicodeBuffer, \
  145. lParam )) != TRUE) \
  146. { \
  147. break; \
  148. } \
  149. } \
  150. else \
  151. { \
  152. /* \
  153. * Call the Ansi callback function. \
  154. */ \
  155. if (NlsDispatchAnsiEnumProc( Locale, \
  156. lpNlsEnumProc, \
  157. dwFlags, \
  158. pUnicodeBuffer, \
  159. NULL, \
  160. LanguageGroup, \
  161. EnumLocale, \
  162. lParam, \
  163. 2 ) != TRUE) \
  164. { \
  165. break; \
  166. } \
  167. } \
  168. }
  169. ////////////////////////////////////////////////////////////////////////////
  170. //
  171. // NLS_CALL_ENUMPROC_BREAK_3
  172. //
  173. // Calls the appropriate EnumProc routine. If the fUnicodeVer flag is TRUE,
  174. // then it calls the Unicode version of the callback function. Otherwise,
  175. // it calls the Ansi dispatch routine to translate the strings to Ansi and
  176. // then call the Ansi version of the callback function.
  177. //
  178. // This macro will do a break if the enumeration routine returns FALSE.
  179. //
  180. // DEFINED AS A MACRO.
  181. //
  182. // 03-10-98 JulieB Created.
  183. ////////////////////////////////////////////////////////////////////////////
  184. #define NLS_CALL_ENUMPROC_BREAK_3( Locale, \
  185. lpNlsEnumProc, \
  186. dwFlags, \
  187. LanguageGroup, \
  188. pUnicodeBuffer1, \
  189. pUnicodeBuffer2, \
  190. dwInstall, \
  191. lParam, \
  192. fUnicodeVer ) \
  193. { \
  194. /* \
  195. * Call the appropriate callback function. \
  196. */ \
  197. if (fUnicodeVer) \
  198. { \
  199. /* \
  200. * Call the Unicode callback function. \
  201. */ \
  202. if (((*((NLS_ENUMPROC3)lpNlsEnumProc))( LanguageGroup, \
  203. pUnicodeBuffer1, \
  204. pUnicodeBuffer2, \
  205. (dwInstall), \
  206. lParam )) != TRUE) \
  207. { \
  208. break; \
  209. } \
  210. } \
  211. else \
  212. { \
  213. /* \
  214. * Call the Ansi callback function. \
  215. */ \
  216. if (NlsDispatchAnsiEnumProc( Locale, \
  217. lpNlsEnumProc, \
  218. dwFlags, \
  219. pUnicodeBuffer1, \
  220. pUnicodeBuffer2, \
  221. LanguageGroup, \
  222. (dwInstall), \
  223. lParam, \
  224. 3 ) != TRUE) \
  225. { \
  226. break; \
  227. } \
  228. } \
  229. }
  230. ////////////////////////////////////////////////////////////////////////////
  231. //
  232. // NLS_CALL_ENUMPROC_BREAK_4
  233. //
  234. // Calls the appropriate EnumProc routine. If the fUnicodeVer flag is TRUE,
  235. // then it calls the Unicode version of the callback function. Otherwise,
  236. // it calls the Ansi dispatch routine to translate the string to Ansi and
  237. // then call the Ansi version of the callback function.
  238. //
  239. // This macro will do a break if the enumeration routine returns FALSE.
  240. // Used by EnumUILanguages.
  241. //
  242. // DEFINED AS A MACRO.
  243. //
  244. // 12-03-98 SamerA Created.
  245. ////////////////////////////////////////////////////////////////////////////
  246. #define NLS_CALL_ENUMPROC_BREAK_4( Locale, \
  247. lpNlsEnumProc, \
  248. dwFlags, \
  249. pUnicodeBuffer, \
  250. lParam, \
  251. fUnicodeVer ) \
  252. { \
  253. /* \
  254. * Call the appropriate callback function. \
  255. */ \
  256. if (fUnicodeVer) \
  257. { \
  258. /* \
  259. * Call the Unicode callback function. \
  260. */ \
  261. if (((*((NLS_ENUMPROC4)lpNlsEnumProc))(pUnicodeBuffer, \
  262. lParam)) != TRUE) \
  263. { \
  264. break; \
  265. } \
  266. } \
  267. else \
  268. { \
  269. /* \
  270. * Call the Ansi callback function. \
  271. */ \
  272. if (NlsDispatchAnsiEnumProc( Locale, \
  273. lpNlsEnumProc, \
  274. dwFlags, \
  275. pUnicodeBuffer, \
  276. NULL, \
  277. 0, \
  278. 0, \
  279. lParam, \
  280. 4 ) != TRUE) \
  281. { \
  282. break; \
  283. } \
  284. } \
  285. }
  286. ////////////////////////////////////////////////////////////////////////////
  287. //
  288. // NLS_CALL_ENUMPROC_TRUE_4
  289. //
  290. // Calls the appropriate EnumProc routine. If the fUnicodeVer flag is TRUE,
  291. // then it calls the Unicode version of the callback function. Otherwise,
  292. // it calls the Ansi dispatch routine to translate the string to Ansi and
  293. // then call the Ansi version of the callback function.
  294. //
  295. // This macro will do a break if the enumeration routine returns FALSE.
  296. // Used by EnumUILanguages.
  297. //
  298. // DEFINED AS A MACRO.
  299. //
  300. // 12-03-98 SamerA Created.
  301. ////////////////////////////////////////////////////////////////////////////
  302. #define NLS_CALL_ENUMPROC_TRUE_4( Locale, \
  303. lpNlsEnumProc, \
  304. dwFlags, \
  305. pUnicodeBuffer, \
  306. lParam, \
  307. fUnicodeVer ) \
  308. { \
  309. /* \
  310. * Call the appropriate callback function. \
  311. */ \
  312. if (fUnicodeVer) \
  313. { \
  314. /* \
  315. * Call the Unicode callback function. \
  316. */ \
  317. if (((*((NLS_ENUMPROC4)lpNlsEnumProc))(pUnicodeBuffer, \
  318. lParam)) != TRUE) \
  319. { \
  320. return (TRUE); \
  321. } \
  322. } \
  323. else \
  324. { \
  325. /* \
  326. * Call the Ansi callback function. \
  327. */ \
  328. if (NlsDispatchAnsiEnumProc( Locale, \
  329. lpNlsEnumProc, \
  330. dwFlags, \
  331. pUnicodeBuffer, \
  332. NULL, \
  333. 0, \
  334. 0, \
  335. lParam, \
  336. 4 ) != TRUE) \
  337. { \
  338. return (TRUE); \
  339. } \
  340. } \
  341. }
  342. ////////////////////////////////////////////////////////////////////////////
  343. //
  344. // NLS_CALL_ENUMPROC_TRUE
  345. //
  346. // Calls the appropriate EnumProc routine. If the fUnicodeVer flag is TRUE,
  347. // then it calls the Unicode version of the callback function. Otherwise,
  348. // it calls the Ansi dispatch routine to translate the string to Ansi and
  349. // then call the Ansi version of the callback function.
  350. //
  351. // This macro will return TRUE if the enumeration routine returns FALSE.
  352. //
  353. // DEFINED AS A MACRO.
  354. //
  355. // 11-10-93 JulieB Created.
  356. ////////////////////////////////////////////////////////////////////////////
  357. #define NLS_CALL_ENUMPROC_TRUE( Locale, \
  358. lpNlsEnumProc, \
  359. dwFlags, \
  360. pUnicodeBuffer, \
  361. CalId, \
  362. fUnicodeVer, \
  363. fVer ) \
  364. { \
  365. /* \
  366. * Call the appropriate callback function. \
  367. */ \
  368. if (fUnicodeVer) \
  369. { \
  370. /* \
  371. * Call the Unicode callback function. \
  372. */ \
  373. if (fVer == 1) \
  374. { \
  375. if (((*((NLS_ENUMPROCEX)lpNlsEnumProc))( pUnicodeBuffer, \
  376. CalId )) != TRUE) \
  377. { \
  378. return (TRUE); \
  379. } \
  380. } \
  381. else /* fVer == 0 */ \
  382. { \
  383. if (((*lpNlsEnumProc)(pUnicodeBuffer)) != TRUE) \
  384. { \
  385. return (TRUE); \
  386. } \
  387. } \
  388. } \
  389. else \
  390. { \
  391. /* \
  392. * Call the Ansi callback function. \
  393. */ \
  394. if (NlsDispatchAnsiEnumProc( Locale, \
  395. lpNlsEnumProc, \
  396. dwFlags, \
  397. pUnicodeBuffer, \
  398. NULL, \
  399. CalId, \
  400. 0, \
  401. 0, \
  402. fVer ) != TRUE) \
  403. { \
  404. return (TRUE); \
  405. } \
  406. } \
  407. }
  408. //-------------------------------------------------------------------------//
  409. // API ROUTINES //
  410. //-------------------------------------------------------------------------//
  411. ////////////////////////////////////////////////////////////////////////////
  412. //
  413. // EnumSystemLanguageGroupsW
  414. //
  415. // Enumerates the system language groups that are installed or supported,
  416. // based on the dwFlags parameter. It does so by passing the pointer to
  417. // the string buffer containing the language group id to an
  418. // application-defined callback function. It continues until the last
  419. // language group id is found or the callback function returns FALSE.
  420. //
  421. // 03-10-98 JulieB Created.
  422. ////////////////////////////////////////////////////////////////////////////
  423. BOOL WINAPI EnumSystemLanguageGroupsW(
  424. LANGUAGEGROUP_ENUMPROCW lpLanguageGroupEnumProc,
  425. DWORD dwFlags,
  426. LONG_PTR lParam)
  427. {
  428. return (Internal_EnumSystemLanguageGroups(
  429. (NLS_ENUMPROC)lpLanguageGroupEnumProc,
  430. dwFlags,
  431. lParam,
  432. TRUE ));
  433. }
  434. ////////////////////////////////////////////////////////////////////////////
  435. //
  436. // EnumLanguageGroupLocalesW
  437. //
  438. // Enumerates the locales in a given language group. It does so by
  439. // passing the appropriate information to an application-defined
  440. // callback function. It continues until the last locale in the language
  441. // group is found or the callback function returns FALSE.
  442. //
  443. // 03-10-98 JulieB Created.
  444. ////////////////////////////////////////////////////////////////////////////
  445. BOOL WINAPI EnumLanguageGroupLocalesW(
  446. LANGGROUPLOCALE_ENUMPROCW lpLangGroupLocaleEnumProc,
  447. LGRPID LanguageGroup,
  448. DWORD dwFlags,
  449. LONG_PTR lParam)
  450. {
  451. return (Internal_EnumLanguageGroupLocales(
  452. (NLS_ENUMPROC)lpLangGroupLocaleEnumProc,
  453. LanguageGroup,
  454. dwFlags,
  455. lParam,
  456. TRUE ));
  457. }
  458. ////////////////////////////////////////////////////////////////////////////
  459. //
  460. // EnumUILanguagesW
  461. //
  462. // Enumerates the system UI languages that are installed. It does so by
  463. // passing the pointer to the string buffer containing the UI language id
  464. // to an application-defined callback function. It continues until the
  465. // last UI language id is found or the callback function returns FALSE.
  466. //
  467. // 03-10-98 JulieB Created.
  468. ////////////////////////////////////////////////////////////////////////////
  469. BOOL WINAPI EnumUILanguagesW(
  470. UILANGUAGE_ENUMPROCW lpUILanguageEnumProc,
  471. DWORD dwFlags,
  472. LONG_PTR lParam)
  473. {
  474. return (Internal_EnumUILanguages( (NLS_ENUMPROC)lpUILanguageEnumProc,
  475. dwFlags,
  476. lParam,
  477. TRUE ));
  478. }
  479. ////////////////////////////////////////////////////////////////////////////
  480. //
  481. // EnumSystemLocalesW
  482. //
  483. // Enumerates the system locales that are installed or supported, based on
  484. // the dwFlags parameter. It does so by passing the pointer to the string
  485. // buffer containing the locale id to an application-defined callback
  486. // function. It continues until the last locale id is found or the
  487. // callback function returns FALSE.
  488. //
  489. // 08-02-93 JulieB Created.
  490. ////////////////////////////////////////////////////////////////////////////
  491. BOOL WINAPI EnumSystemLocalesW(
  492. LOCALE_ENUMPROCW lpLocaleEnumProc,
  493. DWORD dwFlags)
  494. {
  495. return (Internal_EnumSystemLocales( (NLS_ENUMPROC)lpLocaleEnumProc,
  496. dwFlags,
  497. TRUE ));
  498. }
  499. ////////////////////////////////////////////////////////////////////////////
  500. //
  501. // EnumSystemCodePagesW
  502. //
  503. // Enumerates the system code pages that are installed or supported, based on
  504. // the dwFlags parameter. It does so by passing the pointer to the string
  505. // buffer containing the code page id to an application-defined callback
  506. // function. It continues until the last code page is found or the
  507. // callback function returns FALSE.
  508. //
  509. // 08-02-93 JulieB Created.
  510. ////////////////////////////////////////////////////////////////////////////
  511. BOOL WINAPI EnumSystemCodePagesW(
  512. CODEPAGE_ENUMPROCW lpCodePageEnumProc,
  513. DWORD dwFlags)
  514. {
  515. return (Internal_EnumSystemCodePages( (NLS_ENUMPROC)lpCodePageEnumProc,
  516. dwFlags,
  517. TRUE ));
  518. }
  519. ////////////////////////////////////////////////////////////////////////////
  520. //
  521. // EnumCalendarInfoW
  522. //
  523. // Enumerates the specified calendar information that is available for the
  524. // specified locale, based on the CalType parameter. It does so by
  525. // passing the pointer to the string buffer containing the calendar info
  526. // to an application-defined callback function. It continues until the
  527. // last calendar info is found or the callback function returns FALSE.
  528. //
  529. // 10-14-93 JulieB Created.
  530. ////////////////////////////////////////////////////////////////////////////
  531. BOOL WINAPI EnumCalendarInfoW(
  532. CALINFO_ENUMPROCW lpCalInfoEnumProc,
  533. LCID Locale,
  534. CALID Calendar,
  535. CALTYPE CalType)
  536. {
  537. return (Internal_EnumCalendarInfo( (NLS_ENUMPROC)lpCalInfoEnumProc,
  538. Locale,
  539. Calendar,
  540. CalType,
  541. TRUE,
  542. FALSE ));
  543. }
  544. ////////////////////////////////////////////////////////////////////////////
  545. //
  546. // EnumCalendarInfoExW
  547. //
  548. // Enumerates the specified calendar information that is available for the
  549. // specified locale, based on the CalType parameter. It does so by
  550. // passing the pointer to the string buffer containing the calendar info
  551. // and the calendar id to an application-defined callback function. It
  552. // continues until the last calendar info is found or the callback function
  553. // returns FALSE.
  554. //
  555. // 10-14-96 JulieB Created.
  556. ////////////////////////////////////////////////////////////////////////////
  557. BOOL WINAPI EnumCalendarInfoExW(
  558. CALINFO_ENUMPROCEXW lpCalInfoEnumProcEx,
  559. LCID Locale,
  560. CALID Calendar,
  561. CALTYPE CalType)
  562. {
  563. return (Internal_EnumCalendarInfo( (NLS_ENUMPROC)lpCalInfoEnumProcEx,
  564. Locale,
  565. Calendar,
  566. CalType,
  567. TRUE,
  568. TRUE ));
  569. }
  570. ////////////////////////////////////////////////////////////////////////////
  571. //
  572. // EnumTimeFormatsW
  573. //
  574. // Enumerates the time formats that are available for the
  575. // specified locale, based on the dwFlags parameter. It does so by
  576. // passing the pointer to the string buffer containing the time format
  577. // to an application-defined callback function. It continues until the
  578. // last time format is found or the callback function returns FALSE.
  579. //
  580. // 10-14-93 JulieB Created.
  581. ////////////////////////////////////////////////////////////////////////////
  582. BOOL WINAPI EnumTimeFormatsW(
  583. TIMEFMT_ENUMPROCW lpTimeFmtEnumProc,
  584. LCID Locale,
  585. DWORD dwFlags)
  586. {
  587. return (Internal_EnumTimeFormats( (NLS_ENUMPROC)lpTimeFmtEnumProc,
  588. Locale,
  589. dwFlags,
  590. TRUE ));
  591. }
  592. ////////////////////////////////////////////////////////////////////////////
  593. //
  594. // EnumDateFormatsW
  595. //
  596. // Enumerates the short date, long date, or year/month formats that are
  597. // available for the specified locale, based on the dwFlags parameter.
  598. // It does so by passing the pointer to the string buffer containing the
  599. // date format to an application-defined callback function. It continues
  600. // until the last date format is found or the callback function returns
  601. // FALSE.
  602. //
  603. // 10-14-93 JulieB Created.
  604. ////////////////////////////////////////////////////////////////////////////
  605. BOOL WINAPI EnumDateFormatsW(
  606. DATEFMT_ENUMPROCW lpDateFmtEnumProc,
  607. LCID Locale,
  608. DWORD dwFlags)
  609. {
  610. return (Internal_EnumDateFormats( (NLS_ENUMPROC)lpDateFmtEnumProc,
  611. Locale,
  612. dwFlags,
  613. TRUE,
  614. FALSE ));
  615. }
  616. ////////////////////////////////////////////////////////////////////////////
  617. //
  618. // EnumDateFormatsExW
  619. //
  620. // Enumerates the short date, long date, or year/month formats that are
  621. // available for the specified locale, based on the dwFlags parameter.
  622. // It does so by passing the pointer to the string buffer containing the
  623. // date format and the calendar id to an application-defined callback
  624. // function. It continues until the last date format is found or the
  625. // callback function returns FALSE.
  626. //
  627. // 10-14-96 JulieB Created.
  628. ////////////////////////////////////////////////////////////////////////////
  629. BOOL WINAPI EnumDateFormatsExW(
  630. DATEFMT_ENUMPROCEXW lpDateFmtEnumProcEx,
  631. LCID Locale,
  632. DWORD dwFlags)
  633. {
  634. return (Internal_EnumDateFormats( (NLS_ENUMPROC)lpDateFmtEnumProcEx,
  635. Locale,
  636. dwFlags,
  637. TRUE,
  638. TRUE ));
  639. }
  640. //-------------------------------------------------------------------------//
  641. // EXTERNAL ROUTINES //
  642. //-------------------------------------------------------------------------//
  643. ////////////////////////////////////////////////////////////////////////////
  644. //
  645. // Internal_EnumSystemLanguageGroups
  646. //
  647. // Enumerates the system language groups that are installed or supported,
  648. // based on the dwFlags parameter. It does so by passing the pointer to
  649. // the string buffer containing the language group id to an
  650. // application-defined callback function. It continues until the last
  651. // language group id is found or the callback function returns FALSE.
  652. //
  653. // 03-10-98 JulieB Created.
  654. ////////////////////////////////////////////////////////////////////////////
  655. BOOL Internal_EnumSystemLanguageGroups(
  656. NLS_ENUMPROC lpLanguageGroupEnumProc,
  657. DWORD dwFlags,
  658. LONG_PTR lParam,
  659. BOOL fUnicodeVer)
  660. {
  661. PKEY_VALUE_FULL_INFORMATION pKeyValueFull = NULL;
  662. BYTE pStatic[MAX_KEY_VALUE_FULLINFO];
  663. BOOL fInstalled; // if installed flag set
  664. ULONG Index; // index for enumeration
  665. ULONG ResultLength; // # bytes written
  666. WCHAR wch; // first char of name
  667. LPWSTR pName; // ptr to name string from registry
  668. WCHAR szLGName[MAX_PATH]; // language group name
  669. UNICODE_STRING ObUnicodeStr; // registry data value string
  670. DWORD Data; // registry data value
  671. ULONG NameLen; // length of name string
  672. LGRPID LangGroup; // language group id
  673. ULONG rc = 0L; // return code
  674. //
  675. // Invalid Parameter Check:
  676. // - function pointer is null
  677. //
  678. if (lpLanguageGroupEnumProc == NULL)
  679. {
  680. SetLastError(ERROR_INVALID_PARAMETER);
  681. return (FALSE);
  682. }
  683. //
  684. // Invalid Flags Check:
  685. // - flags other than valid ones
  686. // - more than one of either supported or installed
  687. //
  688. if ( (dwFlags & ESLG_INVALID_FLAG) ||
  689. (MORE_THAN_ONE(dwFlags, ESLG_SINGLE_FLAG)) )
  690. {
  691. SetLastError(ERROR_INVALID_FLAGS);
  692. return (FALSE);
  693. }
  694. //
  695. // Initialize flag option.
  696. //
  697. fInstalled = dwFlags & LGRPID_INSTALLED;
  698. //
  699. // Initialize key handles.
  700. //
  701. OPEN_LANG_GROUPS_KEY(FALSE);
  702. //
  703. // Loop through the language group ids in the registry, call the
  704. // function pointer for each one that meets the flag criteria.
  705. //
  706. // End loop if either FALSE is returned from the callback function
  707. // or the end of the list is reached.
  708. //
  709. Index = 0;
  710. pKeyValueFull = (PKEY_VALUE_FULL_INFORMATION)pStatic;
  711. RtlZeroMemory(pKeyValueFull, MAX_KEY_VALUE_FULLINFO);
  712. rc = NtEnumerateValueKey( hLangGroupsKey,
  713. Index,
  714. KeyValueFullInformation,
  715. pKeyValueFull,
  716. MAX_KEY_VALUE_FULLINFO,
  717. &ResultLength );
  718. while (rc != STATUS_NO_MORE_ENTRIES)
  719. {
  720. if (!NT_SUCCESS(rc))
  721. {
  722. //
  723. // If we get a different error, then the registry
  724. // is corrupt. Just return FALSE.
  725. //
  726. KdPrint(("NLSAPI: Language Group Enumeration Error - registry corrupt. - %lx.\n",
  727. rc));
  728. SetLastError(ERROR_BADDB);
  729. return (FALSE);
  730. }
  731. //
  732. // Skip over any entry that does not have data associated with it
  733. // if the LGRPID_INSTALLED flag is set.
  734. //
  735. pName = pKeyValueFull->Name;
  736. wch = *pName;
  737. NameLen = pKeyValueFull->NameLength / sizeof(WCHAR);
  738. if ( (NameLen <= ENUM_MAX_LG_SIZE) &&
  739. (((wch >= NLS_CHAR_ZERO) && (wch <= NLS_CHAR_NINE)) ||
  740. (((wch | 0x0020) >= L'a') && ((wch | 0x0020) <= L'f'))) &&
  741. (!((fInstalled) && (pKeyValueFull->DataLength <= 2))) )
  742. {
  743. //
  744. // See if the language group is installed or not.
  745. //
  746. Data = 0;
  747. if (pKeyValueFull->DataLength > 2)
  748. {
  749. RtlInitUnicodeString( &ObUnicodeStr,
  750. GET_VALUE_DATA_PTR(pKeyValueFull) );
  751. if (RtlUnicodeStringToInteger(&ObUnicodeStr, 16, &Data))
  752. {
  753. Data = 0;
  754. }
  755. }
  756. //
  757. // If the installed flag is set, then skip the language group
  758. // if it is not already installed.
  759. //
  760. if ((fInstalled) && (Data != 1))
  761. {
  762. goto EnumNextLanguageGroup;
  763. }
  764. //
  765. // Store the language group id string in the callback buffer.
  766. //
  767. pName[NameLen] = 0;
  768. //
  769. // Get the language group id as a value and the localized
  770. // language group name.
  771. //
  772. RtlInitUnicodeString(&ObUnicodeStr, pName);
  773. if ((RtlUnicodeStringToInteger(&ObUnicodeStr, 16, &LangGroup)) ||
  774. (GetStringTableEntry( LangGroup,
  775. 0,
  776. szLGName,
  777. MAX_PATH,
  778. RC_LANGUAGE_GROUP_NAME ) == 0))
  779. {
  780. goto EnumNextLanguageGroup;
  781. }
  782. //
  783. // Call the appropriate callback function.
  784. //
  785. NLS_CALL_ENUMPROC_BREAK_3( gSystemLocale,
  786. lpLanguageGroupEnumProc,
  787. dwFlags,
  788. LangGroup,
  789. pName,
  790. szLGName,
  791. (Data == 1)
  792. ? LGRPID_INSTALLED
  793. : LGRPID_SUPPORTED,
  794. lParam,
  795. fUnicodeVer );
  796. }
  797. EnumNextLanguageGroup:
  798. //
  799. // Increment enumeration index value and get the next enumeration.
  800. //
  801. Index++;
  802. RtlZeroMemory(pKeyValueFull, MAX_KEY_VALUE_FULLINFO);
  803. rc = NtEnumerateValueKey( hLangGroupsKey,
  804. Index,
  805. KeyValueFullInformation,
  806. pKeyValueFull,
  807. MAX_KEY_VALUE_FULLINFO,
  808. &ResultLength );
  809. }
  810. //
  811. // Return success.
  812. //
  813. return (TRUE);
  814. }
  815. ////////////////////////////////////////////////////////////////////////////
  816. //
  817. // Internal_EnumLanguageGroupLocales
  818. //
  819. // Enumerates the locales in a given language group. It does so by
  820. // passing the appropriate information to an application-defined
  821. // callback function. It continues until the last locale in the language
  822. // group is found or the callback function returns FALSE.
  823. //
  824. // 03-10-98 JulieB Created.
  825. ////////////////////////////////////////////////////////////////////////////
  826. BOOL Internal_EnumLanguageGroupLocales(
  827. NLS_ENUMPROC lpLangGroupLocaleEnumProc,
  828. LGRPID LanguageGroup,
  829. DWORD dwFlags,
  830. LONG_PTR lParam,
  831. BOOL fUnicodeVer)
  832. {
  833. UNICODE_STRING ObUnicodeStr; // locale string
  834. WCHAR szSectionName[MAX_PATH]; // section name in inf file
  835. WCHAR szBuffer[MAX_PATH * 4]; // buffer
  836. WCHAR szInfPath[MAX_PATH_LEN]; // inf file
  837. LPWSTR pStr, pEndStr; // ptr to szBuffer
  838. DWORD LocaleValue; // locale id value
  839. int Length; // length of string in buffer
  840. HRESULT hr;
  841. //
  842. // Invalid Parameter Check:
  843. // - function pointer is null
  844. //
  845. if (lpLangGroupLocaleEnumProc == NULL)
  846. {
  847. SetLastError(ERROR_INVALID_PARAMETER);
  848. return (FALSE);
  849. }
  850. //
  851. // Invalid Flags Check:
  852. // - flags must be 0
  853. //
  854. if (dwFlags != 0)
  855. {
  856. SetLastError(ERROR_INVALID_FLAGS);
  857. return (FALSE);
  858. }
  859. //
  860. // Get INTL.INF section name - LOCALE_LIST_#.
  861. //
  862. if (NlsConvertIntegerToString( LanguageGroup,
  863. 10,
  864. 1,
  865. szBuffer,
  866. ENUM_BUF_SIZE ) != NO_ERROR)
  867. {
  868. SetLastError(ERROR_INVALID_PARAMETER);
  869. return (FALSE);
  870. }
  871. hr = StringCchCopyW(szSectionName, ARRAYSIZE(szSectionName), L"LOCALE_LIST_");
  872. if(FAILED(hr))
  873. {
  874. SetLastError(HRESULT_CODE(hr));
  875. return (FALSE);
  876. }
  877. hr = StringCchCatW(szSectionName, ARRAYSIZE(szSectionName), szBuffer);
  878. if(FAILED(hr))
  879. {
  880. SetLastError(HRESULT_CODE(hr));
  881. return (FALSE);
  882. }
  883. //
  884. // Get the locale list from the intl.inf file.
  885. //
  886. szBuffer[0] = 0;
  887. if(0 == GetSystemWindowsDirectory(szInfPath, MAX_PATH_LEN))
  888. {
  889. SetLastError(ERROR_OUTOFMEMORY);
  890. return (FALSE);
  891. }
  892. hr = StringCchCatW(szInfPath, ARRAYSIZE(szInfPath), L"\\INF\\INTL.INF");
  893. if(FAILED(hr))
  894. {
  895. SetLastError(HRESULT_CODE(hr));
  896. return (FALSE);
  897. }
  898. Length = GetPrivateProfileSection( szSectionName,
  899. szBuffer,
  900. MAX_PATH * 4,
  901. szInfPath );
  902. if (Length == 0)
  903. {
  904. SetLastError(ERROR_INVALID_PARAMETER);
  905. return (FALSE);
  906. }
  907. //
  908. // Parse the buffer and call the callback function for each locale
  909. // in the list. The buffer is double null terminated.
  910. //
  911. pStr = szBuffer;
  912. pEndStr = szBuffer + Length;
  913. while ((pStr < pEndStr) && (*pStr))
  914. {
  915. //
  916. // See if the value starts with 0x or 0X. If so, go past it.
  917. //
  918. if ((*pStr == L'0') &&
  919. ((*(pStr + 1) == L'x') || (*(pStr + 1) == L'X')))
  920. {
  921. pStr += 2;
  922. }
  923. //
  924. // Convert the string to an integer.
  925. //
  926. RtlInitUnicodeString(&ObUnicodeStr, pStr);
  927. if (RtlUnicodeStringToInteger(&ObUnicodeStr, 16, &LocaleValue) != NO_ERROR)
  928. {
  929. KdPrint(("NLSAPI: Language Group Locale Enumeration Error - intl.inf corrupt.\n"));
  930. SetLastError(ERROR_BADDB);
  931. return (FALSE);
  932. }
  933. //
  934. // Call the appropriate callback function.
  935. //
  936. NLS_CALL_ENUMPROC_BREAK_2( gSystemLocale,
  937. lpLangGroupLocaleEnumProc,
  938. dwFlags,
  939. LanguageGroup,
  940. LocaleValue,
  941. pStr,
  942. lParam,
  943. fUnicodeVer );
  944. //
  945. // Increment the pointer to the next string.
  946. //
  947. while (*pStr)
  948. {
  949. pStr++;
  950. }
  951. pStr++;
  952. }
  953. //
  954. // Return success.
  955. //
  956. return (TRUE);
  957. }
  958. ////////////////////////////////////////////////////////////////////////////
  959. //
  960. // Internal_EnumUILanguages
  961. //
  962. // Enumerates the system UI languages that are installed. It does so by
  963. // passing the pointer to the string buffer containing the UI language id
  964. // to an application-defined callback function. It continues until the
  965. // last UI language id is found or the callback function returns FALSE.
  966. //
  967. // 03-10-98 JulieB Created.
  968. ////////////////////////////////////////////////////////////////////////////
  969. BOOL Internal_EnumUILanguages(
  970. NLS_ENUMPROC lpUILanguageEnumProc,
  971. DWORD dwFlags,
  972. LONG_PTR lParam,
  973. BOOL fUnicodeVer)
  974. {
  975. PKEY_VALUE_FULL_INFORMATION pKeyValueFull = NULL;
  976. BYTE pStatic[MAX_KEY_VALUE_FULLINFO];
  977. LANGID LangID; // language id
  978. WCHAR szLang[MAX_PATH]; // language id string
  979. HANDLE hKey = NULL; // handle to muilang key
  980. ULONG Index; // index for enumeration
  981. ULONG ResultLength; // # bytes written
  982. WCHAR wch; // first char of name
  983. LPWSTR pName; // ptr to name string from registry
  984. ULONG NameLen; // length of name string
  985. ULONG rc = 0L; // return code
  986. //
  987. // Invalid Parameter Check:
  988. // - function pointer is null
  989. //
  990. if (lpUILanguageEnumProc == NULL)
  991. {
  992. SetLastError(ERROR_INVALID_PARAMETER);
  993. return (FALSE);
  994. }
  995. //
  996. // Invalid Flags Check:
  997. // - flags must be 0
  998. //
  999. if (dwFlags != 0)
  1000. {
  1001. SetLastError(ERROR_INVALID_FLAGS);
  1002. return (FALSE);
  1003. }
  1004. //
  1005. // Call the appropriate callback function with the user's UI
  1006. // language.
  1007. //
  1008. LangID = GetSystemDefaultUILanguage();
  1009. if (NlsConvertIntegerToString(LangID, 16, 4, szLang, MAX_PATH) == NO_ERROR)
  1010. {
  1011. NLS_CALL_ENUMPROC_TRUE_4( gSystemLocale,
  1012. lpUILanguageEnumProc,
  1013. dwFlags,
  1014. szLang,
  1015. lParam,
  1016. fUnicodeVer);
  1017. }
  1018. else
  1019. {
  1020. szLang[0] = 0;
  1021. }
  1022. //
  1023. // Open the MUILanguages registry key. It is acceptable if the key
  1024. // does not exist, so return TRUE as there are no items to enumerate.
  1025. //
  1026. OPEN_MUILANG_KEY(hKey, TRUE);
  1027. //
  1028. // Loop through the MUILanguage ids in the registry, call the
  1029. // function pointer for each.
  1030. //
  1031. // End loop if either FALSE is returned from the callback function
  1032. // or the end of the list is reached.
  1033. //
  1034. Index = 0;
  1035. pKeyValueFull = (PKEY_VALUE_FULL_INFORMATION)pStatic;
  1036. RtlZeroMemory(pKeyValueFull, MAX_KEY_VALUE_FULLINFO);
  1037. rc = NtEnumerateValueKey( hKey,
  1038. Index,
  1039. KeyValueFullInformation,
  1040. pKeyValueFull,
  1041. MAX_KEY_VALUE_FULLINFO,
  1042. &ResultLength );
  1043. while (rc != STATUS_NO_MORE_ENTRIES)
  1044. {
  1045. if (!NT_SUCCESS(rc))
  1046. {
  1047. //
  1048. // If we get a different error, then the registry
  1049. // is corrupt. Just return FALSE.
  1050. //
  1051. KdPrint(("NLSAPI: MUI Languages Enumeration Error - registry corrupt. - %lx.\n",
  1052. rc));
  1053. SetLastError(ERROR_BADDB);
  1054. return (FALSE);
  1055. }
  1056. //
  1057. // Skip over any entry that does not have data associated with it.
  1058. //
  1059. pName = pKeyValueFull->Name;
  1060. wch = *pName;
  1061. NameLen = pKeyValueFull->NameLength / sizeof(WCHAR);
  1062. if ( (NameLen == ENUM_MAX_UILANG_SIZE) &&
  1063. (((wch >= NLS_CHAR_ZERO) && (wch <= NLS_CHAR_NINE)) ||
  1064. (((wch | 0x0020) >= L'a') && ((wch | 0x0020) <= L'f'))) &&
  1065. (pKeyValueFull->DataLength > 2) )
  1066. {
  1067. //
  1068. // Make sure the UI language is zero terminated.
  1069. //
  1070. pName[NameLen] = 0;
  1071. //
  1072. // Make sure it's not the same as the user UI language
  1073. // that we already enumerated.
  1074. //
  1075. if (lstrcmp(szLang, pName) != 0)
  1076. {
  1077. //
  1078. // Call the appropriate callback function.
  1079. //
  1080. NLS_CALL_ENUMPROC_BREAK_4( gSystemLocale,
  1081. lpUILanguageEnumProc,
  1082. dwFlags,
  1083. pName,
  1084. lParam,
  1085. fUnicodeVer );
  1086. }
  1087. }
  1088. //
  1089. // Increment enumeration index value and get the next enumeration.
  1090. //
  1091. Index++;
  1092. RtlZeroMemory(pKeyValueFull, MAX_KEY_VALUE_FULLINFO);
  1093. rc = NtEnumerateValueKey( hKey,
  1094. Index,
  1095. KeyValueFullInformation,
  1096. pKeyValueFull,
  1097. MAX_KEY_VALUE_FULLINFO,
  1098. &ResultLength );
  1099. }
  1100. //
  1101. // Close the registry key.
  1102. //
  1103. CLOSE_REG_KEY(hKey);
  1104. //
  1105. // Return success.
  1106. //
  1107. return (TRUE);
  1108. }
  1109. ////////////////////////////////////////////////////////////////////////////
  1110. //
  1111. // Internal_EnumSystemLocales
  1112. //
  1113. // Enumerates the system locales that are installed or supported, based on
  1114. // the dwFlags parameter. It does so by passing the pointer to the string
  1115. // buffer containing the locale id to an application-defined callback
  1116. // function. It continues until the last locale id is found or the
  1117. // callback function returns FALSE.
  1118. //
  1119. // 08-02-93 JulieB Created.
  1120. ////////////////////////////////////////////////////////////////////////////
  1121. BOOL Internal_EnumSystemLocales(
  1122. NLS_ENUMPROC lpLocaleEnumProc,
  1123. DWORD dwFlags,
  1124. BOOL fUnicodeVer)
  1125. {
  1126. PKEY_VALUE_FULL_INFORMATION pKeyValueFull1 = NULL;
  1127. PKEY_VALUE_FULL_INFORMATION pKeyValueFull2 = NULL;
  1128. BYTE pStatic1[MAX_KEY_VALUE_FULLINFO];
  1129. BYTE pStatic2[MAX_KEY_VALUE_FULLINFO];
  1130. BOOL fInstalled; // if installed flag set
  1131. ULONG Index; // index for enumeration
  1132. ULONG ResultLength; // # bytes written
  1133. WCHAR wch; // first char of name
  1134. WCHAR pBuffer[ENUM_BUF_SIZE]; // ptr to callback string buffer
  1135. LPWSTR pName; // ptr to name string from registry
  1136. LPWSTR pData; // ptr to data string from registry
  1137. UNICODE_STRING ObUnicodeStr; // registry data value string
  1138. DWORD Data; // registry data value
  1139. HKEY hKey; // handle to registry key
  1140. int Ctr; // loop counter
  1141. ULONG rc = 0L; // return code
  1142. //
  1143. // Invalid Parameter Check:
  1144. // - function pointer is null
  1145. //
  1146. if (lpLocaleEnumProc == NULL)
  1147. {
  1148. SetLastError(ERROR_INVALID_PARAMETER);
  1149. return (FALSE);
  1150. }
  1151. //
  1152. // Invalid Flags Check:
  1153. // - flags other than valid ones
  1154. // - more than one of either supported or installed
  1155. //
  1156. if ( (dwFlags & ESL_INVALID_FLAG) ||
  1157. (MORE_THAN_ONE(dwFlags, ESL_SINGLE_FLAG)) )
  1158. {
  1159. SetLastError(ERROR_INVALID_FLAGS);
  1160. return (FALSE);
  1161. }
  1162. //
  1163. // Initialize flag option.
  1164. //
  1165. fInstalled = dwFlags & LCID_INSTALLED;
  1166. //
  1167. // Initialize key handles.
  1168. //
  1169. OPEN_LOCALE_KEY(FALSE);
  1170. OPEN_ALT_SORTS_KEY(FALSE);
  1171. OPEN_LANG_GROUPS_KEY(FALSE);
  1172. //
  1173. // Initialize the variables for the loop.
  1174. //
  1175. Ctr = 0;
  1176. if (dwFlags & LCID_ALTERNATE_SORTS)
  1177. {
  1178. Ctr++;
  1179. hKey = hAltSortsKey;
  1180. }
  1181. if (dwFlags != LCID_ALTERNATE_SORTS)
  1182. {
  1183. Ctr++;
  1184. hKey = hLocaleKey;
  1185. }
  1186. //
  1187. // Loop through the locale ids and/or the alternate sort ids.
  1188. //
  1189. for (; Ctr > 0; Ctr--)
  1190. {
  1191. //
  1192. // Loop through the locale ids in the registry, call the function
  1193. // pointer for each one that meets the flag criteria.
  1194. //
  1195. // End loop if either FALSE is returned from the callback function
  1196. // or the end of the list is reached.
  1197. //
  1198. // Always need to ignore the DEFAULT entry.
  1199. //
  1200. Index = 0;
  1201. pKeyValueFull1 = (PKEY_VALUE_FULL_INFORMATION)pStatic1;
  1202. pKeyValueFull2 = (PKEY_VALUE_FULL_INFORMATION)pStatic2;
  1203. RtlZeroMemory(pKeyValueFull1, MAX_KEY_VALUE_FULLINFO);
  1204. rc = NtEnumerateValueKey( hKey,
  1205. Index,
  1206. KeyValueFullInformation,
  1207. pKeyValueFull1,
  1208. MAX_KEY_VALUE_FULLINFO,
  1209. &ResultLength );
  1210. while (rc != STATUS_NO_MORE_ENTRIES)
  1211. {
  1212. if (!NT_SUCCESS(rc))
  1213. {
  1214. //
  1215. // If we get a different error, then the registry
  1216. // is corrupt. Just return FALSE.
  1217. //
  1218. KdPrint(("NLSAPI: LCID Enumeration Error - registry corrupt. - %lx.\n",
  1219. rc));
  1220. SetLastError(ERROR_BADDB);
  1221. return (FALSE);
  1222. }
  1223. //
  1224. // Skip over the Default entry in the registry and any
  1225. // entry that does not have data associated with it if the
  1226. // LCID_INSTALLED flag is set.
  1227. //
  1228. pName = pKeyValueFull1->Name;
  1229. wch = *pName;
  1230. if ((pKeyValueFull1->NameLength == (ENUM_LOCALE_SIZE * sizeof(WCHAR))) &&
  1231. (((wch >= NLS_CHAR_ZERO) && (wch <= NLS_CHAR_NINE)) ||
  1232. (((wch | 0x0020) >= L'a') && ((wch | 0x0020) <= L'f'))))
  1233. {
  1234. //
  1235. // If the installed flag is set, then do some extra
  1236. // validation before calling the function proc.
  1237. //
  1238. if (fInstalled)
  1239. {
  1240. if (pKeyValueFull1->DataLength <= 2)
  1241. {
  1242. goto EnumNextLocale;
  1243. }
  1244. RtlInitUnicodeString( &ObUnicodeStr,
  1245. GET_VALUE_DATA_PTR(pKeyValueFull1) );
  1246. if ((RtlUnicodeStringToInteger(&ObUnicodeStr, 16, &Data)) ||
  1247. (Data == 0) ||
  1248. (QueryRegValue( hLangGroupsKey,
  1249. ObUnicodeStr.Buffer,
  1250. &pKeyValueFull2,
  1251. MAX_KEY_VALUE_FULLINFO,
  1252. NULL ) != NO_ERROR) ||
  1253. (pKeyValueFull2->DataLength <= 2))
  1254. {
  1255. goto EnumNextLocale;
  1256. }
  1257. pData = GET_VALUE_DATA_PTR(pKeyValueFull2);
  1258. if ((pData[0] != L'1') || (pData[1] != 0))
  1259. {
  1260. goto EnumNextLocale;
  1261. }
  1262. }
  1263. //
  1264. // Store the locale id in the callback buffer.
  1265. //
  1266. *(pBuffer) = *pName;
  1267. *(pBuffer + 1) = *(pName + 1);
  1268. *(pBuffer + 2) = *(pName + 2);
  1269. *(pBuffer + 3) = *(pName + 3);
  1270. *(pBuffer + 4) = *(pName + 4);
  1271. *(pBuffer + 5) = *(pName + 5);
  1272. *(pBuffer + 6) = *(pName + 6);
  1273. *(pBuffer + 7) = *(pName + 7);
  1274. *(pBuffer + 8) = 0;
  1275. //
  1276. // Call the appropriate callback function.
  1277. //
  1278. NLS_CALL_ENUMPROC_BREAK( gSystemLocale,
  1279. lpLocaleEnumProc,
  1280. dwFlags,
  1281. pBuffer,
  1282. fUnicodeVer );
  1283. }
  1284. EnumNextLocale:
  1285. //
  1286. // Increment enumeration index value and get the next enumeration.
  1287. //
  1288. Index++;
  1289. RtlZeroMemory(pKeyValueFull1, MAX_KEY_VALUE_FULLINFO);
  1290. rc = NtEnumerateValueKey( hKey,
  1291. Index,
  1292. KeyValueFullInformation,
  1293. pKeyValueFull1,
  1294. MAX_KEY_VALUE_FULLINFO,
  1295. &ResultLength );
  1296. }
  1297. //
  1298. // The counter can be either 1 or 2 at this point. If it's 2, then
  1299. // we've just done the Locale key and we need to do the alternate
  1300. // sorts key. If it's 1, then it doesn't matter what this is set to
  1301. // since we're done with the loop.
  1302. //
  1303. hKey = hAltSortsKey;
  1304. }
  1305. //
  1306. // Return success.
  1307. //
  1308. return (TRUE);
  1309. }
  1310. ////////////////////////////////////////////////////////////////////////////
  1311. //
  1312. // Internal_EnumSystemCodePages
  1313. //
  1314. // Enumerates the system code pages that are installed or supported, based
  1315. // on the dwFlags parameter. It does so by passing the pointer to the
  1316. // string buffer containing the code page id to an application-defined
  1317. // callback function. It continues until the last code page is found or
  1318. // the callback function returns FALSE.
  1319. //
  1320. // 08-02-93 JulieB Created.
  1321. ////////////////////////////////////////////////////////////////////////////
  1322. BOOL Internal_EnumSystemCodePages(
  1323. NLS_ENUMPROC lpCodePageEnumProc,
  1324. DWORD dwFlags,
  1325. BOOL fUnicodeVer)
  1326. {
  1327. PKEY_VALUE_FULL_INFORMATION pKeyValueFull = NULL;
  1328. BYTE pStatic[MAX_KEY_VALUE_FULLINFO];
  1329. BOOL fInstalled; // if installed flag set
  1330. ULONG Index = 0; // index for enumeration
  1331. ULONG ResultLength; // # bytes written
  1332. WCHAR wch; // first char of name
  1333. LPWSTR pName; // ptr to name string from registry
  1334. ULONG NameLen; // length of name string
  1335. ULONG rc = 0L; // return code
  1336. //
  1337. // Invalid Parameter Check:
  1338. // - function pointer is null
  1339. //
  1340. if (lpCodePageEnumProc == NULL)
  1341. {
  1342. SetLastError(ERROR_INVALID_PARAMETER);
  1343. return (FALSE);
  1344. }
  1345. //
  1346. // Invalid Flags Check:
  1347. // - flags other than valid ones
  1348. // - more than one of either supported or installed
  1349. //
  1350. if ( (dwFlags & ESCP_INVALID_FLAG) ||
  1351. (MORE_THAN_ONE(dwFlags, ESCP_SINGLE_FLAG)) )
  1352. {
  1353. SetLastError(ERROR_INVALID_FLAGS);
  1354. return (FALSE);
  1355. }
  1356. //
  1357. // Initialize flag option.
  1358. //
  1359. fInstalled = dwFlags & CP_INSTALLED;
  1360. //
  1361. // Loop through the code page ids in the registry, call the function
  1362. // pointer for each one that meets the flag criteria.
  1363. //
  1364. // End loop if either FALSE is returned from the callback function
  1365. // or the end of the list is reached.
  1366. //
  1367. // Always need to ignore the ACP, OEMCP, MACCP, and OEMHAL entries.
  1368. //
  1369. OPEN_CODEPAGE_KEY(FALSE);
  1370. pKeyValueFull = (PKEY_VALUE_FULL_INFORMATION)pStatic;
  1371. RtlZeroMemory(pKeyValueFull, MAX_KEY_VALUE_FULLINFO);
  1372. rc = NtEnumerateValueKey( hCodePageKey,
  1373. Index,
  1374. KeyValueFullInformation,
  1375. pKeyValueFull,
  1376. MAX_KEY_VALUE_FULLINFO,
  1377. &ResultLength );
  1378. while (rc != STATUS_NO_MORE_ENTRIES)
  1379. {
  1380. if (!NT_SUCCESS(rc))
  1381. {
  1382. //
  1383. // If we get a different error, then the registry
  1384. // is corrupt. Just return FALSE.
  1385. //
  1386. KdPrint(("NLSAPI: CP Enumeration Error - registry corrupt. - %lx.\n",
  1387. rc));
  1388. SetLastError(ERROR_BADDB);
  1389. return (FALSE);
  1390. }
  1391. //
  1392. // Skip over the ACP, OEMCP, MACCP, and OEMHAL entries in the
  1393. // registry, and any entry that does not have data associated
  1394. // with it if the CP_INSTALLED flag is set.
  1395. //
  1396. pName = pKeyValueFull->Name;
  1397. wch = *pName;
  1398. NameLen = pKeyValueFull->NameLength / sizeof(WCHAR);
  1399. if ( (NameLen <= ENUM_MAX_CP_SIZE) &&
  1400. (wch >= NLS_CHAR_ZERO) && (wch <= NLS_CHAR_NINE) &&
  1401. (!((fInstalled) && (pKeyValueFull->DataLength <= 2))) )
  1402. {
  1403. //
  1404. // Store the code page id string in the callback buffer.
  1405. //
  1406. pName[NameLen] = 0;
  1407. //
  1408. // Call the appropriate callback function.
  1409. //
  1410. NLS_CALL_ENUMPROC_TRUE( gSystemLocale,
  1411. lpCodePageEnumProc,
  1412. dwFlags,
  1413. pName,
  1414. 0,
  1415. fUnicodeVer,
  1416. 0 );
  1417. }
  1418. //
  1419. // Increment enumeration index value and get the next enumeration.
  1420. //
  1421. Index++;
  1422. RtlZeroMemory(pKeyValueFull, MAX_KEY_VALUE_FULLINFO);
  1423. rc = NtEnumerateValueKey( hCodePageKey,
  1424. Index,
  1425. KeyValueFullInformation,
  1426. pKeyValueFull,
  1427. MAX_KEY_VALUE_FULLINFO,
  1428. &ResultLength );
  1429. }
  1430. //
  1431. // Include UTF-7 and UTF-8 code pages in the enumeration -
  1432. // both installed and supported.
  1433. //
  1434. NLS_CALL_ENUMPROC_TRUE( gSystemLocale,
  1435. lpCodePageEnumProc,
  1436. dwFlags,
  1437. L"65000",
  1438. 0,
  1439. fUnicodeVer,
  1440. 0 );
  1441. NLS_CALL_ENUMPROC_TRUE( gSystemLocale,
  1442. lpCodePageEnumProc,
  1443. dwFlags,
  1444. L"65001",
  1445. 0,
  1446. fUnicodeVer,
  1447. 0 );
  1448. //
  1449. // Return success.
  1450. //
  1451. return (TRUE);
  1452. }
  1453. ////////////////////////////////////////////////////////////////////////////
  1454. //
  1455. // Internal_EnumCalendarInfo
  1456. //
  1457. // Enumerates the specified calendar information that is available for the
  1458. // specified locale, based on the CalType parameter. It does so by
  1459. // passing the pointer to the string buffer containing the calendar info
  1460. // to an application-defined callback function. It continues until the
  1461. // last calendar info is found or the callback function returns FALSE.
  1462. //
  1463. // 10-14-93 JulieB Created.
  1464. ////////////////////////////////////////////////////////////////////////////
  1465. BOOL Internal_EnumCalendarInfo(
  1466. NLS_ENUMPROC lpCalInfoEnumProc,
  1467. LCID Locale,
  1468. CALID Calendar,
  1469. CALTYPE CalType,
  1470. BOOL fUnicodeVer,
  1471. BOOL fExVersion)
  1472. {
  1473. PLOC_HASH pHashN; // ptr to LOC hash node
  1474. ULONG CalFieldOffset; // field offset in calendar structure
  1475. ULONG EndCalFieldOffset; // field offset in calendar structure
  1476. ULONG LocFieldOffset; // field offset in locale structure
  1477. ULONG EndLocFieldOffset; // field offset in locale structure
  1478. LPWSTR pOptCal; // ptr to optional calendar values
  1479. LPWSTR pEndOptCal; // ptr to end of optional calendars
  1480. PCAL_INFO pCalInfo; // ptr to calendar info
  1481. BOOL fIfName = FALSE; // if caltype is a name
  1482. UINT fEra = 0; // if era caltype
  1483. BOOL fLocaleInfo = TRUE; // if locale information
  1484. LPWSTR pString; // ptr to enumeration string
  1485. LPWSTR pEndString; // ptr to end of enumeration string
  1486. CALID CalNum; // calendar number
  1487. DWORD UseCPACP; // original caltype - if use system ACP
  1488. WCHAR pTemp[MAX_REG_VAL_SIZE];// temp buffer to hold two-digit-year-max
  1489. //
  1490. // Invalid Parameter Check:
  1491. // - validate LCID
  1492. // - function pointer is null
  1493. //
  1494. // - CalType will be checked in switch statement below.
  1495. //
  1496. VALIDATE_LOCALE(Locale, pHashN, FALSE);
  1497. if ((pHashN == NULL) || (lpCalInfoEnumProc == NULL))
  1498. {
  1499. SetLastError(ERROR_INVALID_PARAMETER);
  1500. return (FALSE);
  1501. }
  1502. //
  1503. // Initialize the pointers to the optional calendar data.
  1504. //
  1505. if (Calendar == ENUM_ALL_CALENDARS)
  1506. {
  1507. pOptCal = (LPWORD)(pHashN->pLocaleHdr) + pHashN->pLocaleHdr->IOptionalCal;
  1508. pEndOptCal = (LPWORD)(pHashN->pLocaleHdr) + pHashN->pLocaleHdr->SDayName1;
  1509. }
  1510. else
  1511. {
  1512. //
  1513. // Validate the Calendar parameter.
  1514. //
  1515. if ((pOptCal = IsValidCalendarType(pHashN, Calendar)) == NULL)
  1516. {
  1517. SetLastError(ERROR_INVALID_PARAMETER);
  1518. return (FALSE);
  1519. }
  1520. pEndOptCal = pOptCal + ((POPT_CAL)pOptCal)->Offset;
  1521. }
  1522. //
  1523. // Enumerate the information based on CalType.
  1524. //
  1525. UseCPACP = (DWORD)CalType;
  1526. CalType = NLS_GET_CALTYPE_VALUE(CalType);
  1527. switch (CalType)
  1528. {
  1529. case ( CAL_ICALINTVALUE ) :
  1530. {
  1531. //
  1532. // Get the integer value for each of the alternate
  1533. // calendars (as a string).
  1534. //
  1535. while (pOptCal < pEndOptCal)
  1536. {
  1537. if (((POPT_CAL)pOptCal)->CalId != CAL_NO_OPTIONAL)
  1538. {
  1539. //
  1540. // Call the appropriate callback function.
  1541. //
  1542. NLS_CALL_ENUMPROC_TRUE( Locale,
  1543. lpCalInfoEnumProc,
  1544. UseCPACP,
  1545. ((POPT_CAL)pOptCal)->pCalStr,
  1546. ((POPT_CAL)pOptCal)->CalId,
  1547. fUnicodeVer,
  1548. fExVersion );
  1549. }
  1550. //
  1551. // Advance ptr to next optional calendar.
  1552. //
  1553. pOptCal += ((POPT_CAL)pOptCal)->Offset;
  1554. }
  1555. return (TRUE);
  1556. break;
  1557. }
  1558. case ( CAL_SCALNAME ) :
  1559. {
  1560. //
  1561. // Get the calendar name for each of the alternate
  1562. // calendars.
  1563. //
  1564. while (pOptCal < pEndOptCal)
  1565. {
  1566. if (((POPT_CAL)pOptCal)->CalId != CAL_NO_OPTIONAL)
  1567. {
  1568. //
  1569. // Call the appropriate callback function.
  1570. //
  1571. NLS_CALL_ENUMPROC_TRUE(
  1572. Locale,
  1573. lpCalInfoEnumProc,
  1574. UseCPACP,
  1575. ((POPT_CAL)pOptCal)->pCalStr +
  1576. NlsStrLenW(((POPT_CAL)pOptCal)->pCalStr) + 1,
  1577. ((POPT_CAL)pOptCal)->CalId,
  1578. fUnicodeVer,
  1579. fExVersion );
  1580. }
  1581. //
  1582. // Advance ptr to next optional calendar.
  1583. //
  1584. pOptCal += ((POPT_CAL)pOptCal)->Offset;
  1585. }
  1586. return (TRUE);
  1587. break;
  1588. }
  1589. case ( CAL_ITWODIGITYEARMAX ) :
  1590. {
  1591. fLocaleInfo = FALSE;
  1592. CalFieldOffset = FIELD_OFFSET(CALENDAR_VAR, STwoDigitYearMax);
  1593. EndCalFieldOffset = FIELD_OFFSET(CALENDAR_VAR, SEraRanges);
  1594. if (!(UseCPACP & CAL_NOUSEROVERRIDE))
  1595. {
  1596. while (pOptCal < pEndOptCal)
  1597. {
  1598. CalNum = ((POPT_CAL)pOptCal)->CalId;
  1599. if (CalNum != CAL_NO_OPTIONAL)
  1600. {
  1601. //
  1602. // Look into the registry first
  1603. //
  1604. if (GetTwoDigitYearInfo(CalNum, pTemp, ARRAYSIZE(pTemp), NLS_POLICY_TWO_DIGIT_YEAR_KEY) ||
  1605. GetTwoDigitYearInfo(CalNum, pTemp, ARRAYSIZE(pTemp), NLS_TWO_DIGIT_YEAR_KEY))
  1606. {
  1607. NLS_CALL_ENUMPROC_TRUE(
  1608. Locale,
  1609. lpCalInfoEnumProc,
  1610. UseCPACP,
  1611. pTemp,
  1612. CalNum,
  1613. fUnicodeVer,
  1614. fExVersion );
  1615. }
  1616. else
  1617. {
  1618. //
  1619. // Try to find the system default if we couldn't find the
  1620. // user setting in the registry or the user has asked for
  1621. // system default.
  1622. //
  1623. if (GetCalendar(CalNum, &pCalInfo) == NO_ERROR)
  1624. {
  1625. pString = (LPWORD)pCalInfo +
  1626. *((LPWORD)((LPBYTE)(pCalInfo) + CalFieldOffset));
  1627. pEndString = (LPWORD)pCalInfo +
  1628. *((LPWORD)((LPBYTE)(pCalInfo) + EndCalFieldOffset));
  1629. if (*pString)
  1630. {
  1631. while (pString < pEndString)
  1632. {
  1633. //
  1634. // Make sure the string is NOT empty.
  1635. //
  1636. if (*pString)
  1637. {
  1638. //
  1639. // Call the appropriate callback function.
  1640. //
  1641. NLS_CALL_ENUMPROC_TRUE(
  1642. Locale,
  1643. lpCalInfoEnumProc,
  1644. UseCPACP,
  1645. pString,
  1646. CalNum,
  1647. fUnicodeVer,
  1648. fExVersion );
  1649. }
  1650. //
  1651. // Advance pointer to next string.
  1652. //
  1653. pString += NlsStrLenW(pString) + 1;
  1654. }
  1655. }
  1656. }
  1657. }
  1658. }
  1659. //
  1660. // Advance ptr to next optional calendar.
  1661. //
  1662. pOptCal += ((POPT_CAL)pOptCal)->Offset;
  1663. }
  1664. return (TRUE);
  1665. }
  1666. break;
  1667. }
  1668. case ( CAL_IYEAROFFSETRANGE ) :
  1669. case ( CAL_SERASTRING ) :
  1670. {
  1671. fEra = CalType;
  1672. CalFieldOffset = FIELD_OFFSET(CALENDAR_VAR, SEraRanges);
  1673. EndCalFieldOffset = FIELD_OFFSET(CALENDAR_VAR, SShortDate);
  1674. break;
  1675. }
  1676. case ( CAL_SSHORTDATE ) :
  1677. {
  1678. CalFieldOffset = FIELD_OFFSET(CALENDAR_VAR, SShortDate);
  1679. EndCalFieldOffset = FIELD_OFFSET(CALENDAR_VAR, SYearMonth);
  1680. LocFieldOffset = FIELD_OFFSET(LOCALE_VAR, SShortDate);
  1681. EndLocFieldOffset = FIELD_OFFSET(LOCALE_VAR, SDate);
  1682. break;
  1683. }
  1684. case ( CAL_SLONGDATE ) :
  1685. {
  1686. CalFieldOffset = FIELD_OFFSET(CALENDAR_VAR, SLongDate);
  1687. EndCalFieldOffset = FIELD_OFFSET(CALENDAR_VAR, SDayName1);
  1688. LocFieldOffset = FIELD_OFFSET(LOCALE_VAR, SLongDate);
  1689. EndLocFieldOffset = FIELD_OFFSET(LOCALE_VAR, IOptionalCal);
  1690. break;
  1691. }
  1692. case ( CAL_SYEARMONTH ) :
  1693. {
  1694. CalFieldOffset = FIELD_OFFSET(CALENDAR_VAR, SYearMonth);
  1695. EndCalFieldOffset = FIELD_OFFSET(CALENDAR_VAR, SLongDate);
  1696. LocFieldOffset = FIELD_OFFSET(LOCALE_VAR, SYearMonth);
  1697. EndLocFieldOffset = FIELD_OFFSET(LOCALE_VAR, SLongDate);
  1698. break;
  1699. }
  1700. case ( CAL_SDAYNAME1 ) :
  1701. case ( CAL_SDAYNAME2 ) :
  1702. case ( CAL_SDAYNAME3 ) :
  1703. case ( CAL_SDAYNAME4 ) :
  1704. case ( CAL_SDAYNAME5 ) :
  1705. case ( CAL_SDAYNAME6 ) :
  1706. case ( CAL_SDAYNAME7 ) :
  1707. case ( CAL_SABBREVDAYNAME1 ) :
  1708. case ( CAL_SABBREVDAYNAME2 ) :
  1709. case ( CAL_SABBREVDAYNAME3 ) :
  1710. case ( CAL_SABBREVDAYNAME4 ) :
  1711. case ( CAL_SABBREVDAYNAME5 ) :
  1712. case ( CAL_SABBREVDAYNAME6 ) :
  1713. case ( CAL_SABBREVDAYNAME7 ) :
  1714. case ( CAL_SMONTHNAME1 ) :
  1715. case ( CAL_SMONTHNAME2 ) :
  1716. case ( CAL_SMONTHNAME3 ) :
  1717. case ( CAL_SMONTHNAME4 ) :
  1718. case ( CAL_SMONTHNAME5 ) :
  1719. case ( CAL_SMONTHNAME6 ) :
  1720. case ( CAL_SMONTHNAME7 ) :
  1721. case ( CAL_SMONTHNAME8 ) :
  1722. case ( CAL_SMONTHNAME9 ) :
  1723. case ( CAL_SMONTHNAME10 ) :
  1724. case ( CAL_SMONTHNAME11 ) :
  1725. case ( CAL_SMONTHNAME12 ) :
  1726. case ( CAL_SMONTHNAME13 ) :
  1727. case ( CAL_SABBREVMONTHNAME1 ) :
  1728. case ( CAL_SABBREVMONTHNAME2 ) :
  1729. case ( CAL_SABBREVMONTHNAME3 ) :
  1730. case ( CAL_SABBREVMONTHNAME4 ) :
  1731. case ( CAL_SABBREVMONTHNAME5 ) :
  1732. case ( CAL_SABBREVMONTHNAME6 ) :
  1733. case ( CAL_SABBREVMONTHNAME7 ) :
  1734. case ( CAL_SABBREVMONTHNAME8 ) :
  1735. case ( CAL_SABBREVMONTHNAME9 ) :
  1736. case ( CAL_SABBREVMONTHNAME10 ) :
  1737. case ( CAL_SABBREVMONTHNAME11 ) :
  1738. case ( CAL_SABBREVMONTHNAME12 ) :
  1739. case ( CAL_SABBREVMONTHNAME13 ) :
  1740. {
  1741. fIfName = TRUE;
  1742. CalFieldOffset = FIELD_OFFSET(CALENDAR_VAR, SDayName1) +
  1743. ((CalType - CAL_SDAYNAME1) * sizeof(WORD));
  1744. EndCalFieldOffset = FIELD_OFFSET(CALENDAR_VAR, SDayName1) +
  1745. ((CalType - CAL_SDAYNAME1 + 1) * sizeof(WORD));
  1746. LocFieldOffset = FIELD_OFFSET(LOCALE_VAR, SDayName1) +
  1747. ((CalType - CAL_SDAYNAME1) * sizeof(WORD));
  1748. EndLocFieldOffset = FIELD_OFFSET(LOCALE_VAR, SDayName1) +
  1749. ((CalType - CAL_SDAYNAME1 + 1) * sizeof(WORD));
  1750. break;
  1751. }
  1752. default :
  1753. {
  1754. SetLastError(ERROR_INVALID_FLAGS);
  1755. return (FALSE);
  1756. }
  1757. }
  1758. //
  1759. // Get the requested information for each of the alternate calendars.
  1760. //
  1761. // This loop is used for the following CalTypes:
  1762. //
  1763. // iYearOffsetRange (fEra = TRUE)
  1764. // sEraString (fEra = TRUE)
  1765. //
  1766. // sShortDate
  1767. // sLongDate
  1768. // sYearMonth
  1769. //
  1770. // sDayName1-7 (fIfName = TRUE)
  1771. // sAbbrevDayName1-7 (fIfName = TRUE)
  1772. // sMonthName1-7 (fIfName = TRUE)
  1773. // sAbbrevMonthName1-7 (fIfName = TRUE)
  1774. //
  1775. while (pOptCal < pEndOptCal)
  1776. {
  1777. //
  1778. // Get the pointer to the appropriate calendar.
  1779. //
  1780. CalNum = ((POPT_CAL)pOptCal)->CalId;
  1781. if (GetCalendar(CalNum, &pCalInfo) == NO_ERROR)
  1782. {
  1783. //
  1784. // Check era information flag.
  1785. //
  1786. if (fEra)
  1787. {
  1788. //
  1789. // Get the pointer to the appropriate calendar string.
  1790. //
  1791. pString = (LPWORD)pCalInfo +
  1792. *((LPWORD)((LPBYTE)(pCalInfo) + CalFieldOffset));
  1793. pEndString = (LPWORD)pCalInfo +
  1794. *((LPWORD)((LPBYTE)(pCalInfo) + EndCalFieldOffset));
  1795. //
  1796. // Make sure the string is NOT empty.
  1797. //
  1798. if (*pString)
  1799. {
  1800. //
  1801. // See which era information to get.
  1802. //
  1803. if (fEra == CAL_IYEAROFFSETRANGE)
  1804. {
  1805. while (pString < pEndString)
  1806. {
  1807. //
  1808. // Call the appropriate callback function.
  1809. //
  1810. NLS_CALL_ENUMPROC_TRUE(
  1811. Locale,
  1812. lpCalInfoEnumProc,
  1813. UseCPACP,
  1814. ((PERA_RANGE)pString)->pYearStr,
  1815. CalNum,
  1816. fUnicodeVer,
  1817. fExVersion );
  1818. //
  1819. // Advance pointer to next era range.
  1820. //
  1821. pString += ((PERA_RANGE)pString)->Offset;
  1822. }
  1823. }
  1824. else
  1825. {
  1826. while (pString < pEndString)
  1827. {
  1828. //
  1829. // Call the appropriate callback function.
  1830. //
  1831. NLS_CALL_ENUMPROC_TRUE(
  1832. Locale,
  1833. lpCalInfoEnumProc,
  1834. UseCPACP,
  1835. ((PERA_RANGE)pString)->pYearStr +
  1836. NlsStrLenW(((PERA_RANGE)pString)->pYearStr) + 1,
  1837. CalNum,
  1838. fUnicodeVer,
  1839. fExVersion );
  1840. //
  1841. // Advance pointer to next era range.
  1842. //
  1843. pString += ((PERA_RANGE)pString)->Offset;
  1844. }
  1845. }
  1846. }
  1847. }
  1848. else
  1849. {
  1850. //
  1851. // Get the pointer to the appropriate calendar string.
  1852. //
  1853. if ((!fIfName) ||
  1854. (((PCALENDAR_VAR)pCalInfo)->IfNames))
  1855. {
  1856. pString = (LPWORD)pCalInfo +
  1857. *((LPWORD)((LPBYTE)(pCalInfo) + CalFieldOffset));
  1858. pEndString = (LPWORD)pCalInfo +
  1859. *((LPWORD)((LPBYTE)(pCalInfo) + EndCalFieldOffset));
  1860. }
  1861. else
  1862. {
  1863. pString = L"";
  1864. }
  1865. //
  1866. // Make sure we have a string. Otherwise, use the
  1867. // information from the locale section (if appropriate).
  1868. //
  1869. if ((*pString == 0) && (fLocaleInfo) &&
  1870. ((CalNum == CAL_GREGORIAN) ||
  1871. (Calendar != ENUM_ALL_CALENDARS)))
  1872. {
  1873. //
  1874. // Use the default locale string.
  1875. //
  1876. pString = (LPWORD)(pHashN->pLocaleHdr) +
  1877. *((LPWORD)((LPBYTE)(pHashN->pLocaleHdr) +
  1878. LocFieldOffset));
  1879. pEndString = (LPWORD)(pHashN->pLocaleHdr) +
  1880. *((LPWORD)((LPBYTE)(pHashN->pLocaleHdr) +
  1881. EndLocFieldOffset));
  1882. }
  1883. //
  1884. // Go through each of the strings.
  1885. //
  1886. if (*pString)
  1887. {
  1888. while (pString < pEndString)
  1889. {
  1890. //
  1891. // Make sure the string is NOT empty.
  1892. //
  1893. if (*pString)
  1894. {
  1895. //
  1896. // Call the appropriate callback function.
  1897. //
  1898. NLS_CALL_ENUMPROC_TRUE( Locale,
  1899. lpCalInfoEnumProc,
  1900. UseCPACP,
  1901. pString,
  1902. CalNum,
  1903. fUnicodeVer,
  1904. fExVersion );
  1905. }
  1906. //
  1907. // Advance pointer to next string.
  1908. //
  1909. pString += NlsStrLenW(pString) + 1;
  1910. }
  1911. }
  1912. }
  1913. }
  1914. //
  1915. // Advance ptr to next optional calendar.
  1916. //
  1917. pOptCal += ((POPT_CAL)pOptCal)->Offset;
  1918. }
  1919. //
  1920. // Return success.
  1921. //
  1922. return (TRUE);
  1923. }
  1924. ////////////////////////////////////////////////////////////////////////////
  1925. //
  1926. // Internal_EnumTimeFormats
  1927. //
  1928. // Enumerates the time formats that are available for the
  1929. // specified locale, based on the dwFlags parameter. It does so by
  1930. // passing the pointer to the string buffer containing the time format
  1931. // to an application-defined callback function. It continues until the
  1932. // last time format is found or the callback function returns FALSE.
  1933. //
  1934. // 10-14-93 JulieB Created.
  1935. ////////////////////////////////////////////////////////////////////////////
  1936. BOOL Internal_EnumTimeFormats(
  1937. NLS_ENUMPROC lpTimeFmtEnumProc,
  1938. LCID Locale,
  1939. DWORD dwFlags,
  1940. BOOL fUnicodeVer)
  1941. {
  1942. PLOC_HASH pHashN; // ptr to LOC hash node
  1943. //
  1944. // Invalid Parameter Check:
  1945. // - validate LCID
  1946. // - function pointer is null
  1947. //
  1948. VALIDATE_LOCALE(Locale, pHashN, FALSE);
  1949. if ((pHashN == NULL) || (lpTimeFmtEnumProc == NULL))
  1950. {
  1951. SetLastError(ERROR_INVALID_PARAMETER);
  1952. return (FALSE);
  1953. }
  1954. //
  1955. // Invalid Flags Check:
  1956. // - flags other than valid ones
  1957. //
  1958. if (dwFlags & ETF_INVALID_FLAG)
  1959. {
  1960. SetLastError(ERROR_INVALID_FLAGS);
  1961. return (FALSE);
  1962. }
  1963. //
  1964. // Enumerate the time formats.
  1965. //
  1966. return ( EnumDateTime( lpTimeFmtEnumProc,
  1967. Locale,
  1968. LOCALE_STIMEFORMAT,
  1969. dwFlags,
  1970. FIELD_OFFSET(NLS_USER_INFO, sTimeFormat),
  1971. NLS_VALUE_STIMEFORMAT,
  1972. pHashN->pLocaleHdr,
  1973. (LPWORD)(pHashN->pLocaleHdr) +
  1974. pHashN->pLocaleHdr->STimeFormat,
  1975. (LPWORD)(pHashN->pLocaleHdr) +
  1976. pHashN->pLocaleHdr->STime,
  1977. (ULONG)0,
  1978. (ULONG)0,
  1979. FALSE,
  1980. fUnicodeVer,
  1981. FALSE ) );
  1982. }
  1983. ////////////////////////////////////////////////////////////////////////////
  1984. //
  1985. // Internal_EnumDateFormats
  1986. //
  1987. // Enumerates the short date, long date, or year/month formats that are
  1988. // available for the specified locale, based on the dwFlags parameter.
  1989. // It does so by passing the pointer to the string buffer containing the
  1990. // date format (and the calendar id if called from the Ex version) to an
  1991. // application-defined callback function. It continues until the last
  1992. // date format is found or the callback function returns FALSE.
  1993. //
  1994. // 10-14-93 JulieB Created.
  1995. ////////////////////////////////////////////////////////////////////////////
  1996. BOOL Internal_EnumDateFormats(
  1997. NLS_ENUMPROC lpDateFmtEnumProc,
  1998. LCID Locale,
  1999. DWORD dwFlags,
  2000. BOOL fUnicodeVer,
  2001. BOOL fExVersion)
  2002. {
  2003. PLOC_HASH pHashN; // ptr to LOC hash node
  2004. //
  2005. // Invalid Parameter Check:
  2006. // - validate LCID
  2007. // - function pointer is null
  2008. //
  2009. // - flags will be validated in switch statement below
  2010. //
  2011. VALIDATE_LOCALE(Locale, pHashN, FALSE);
  2012. if ((pHashN == NULL) || (lpDateFmtEnumProc == NULL))
  2013. {
  2014. SetLastError(ERROR_INVALID_PARAMETER);
  2015. return (FALSE);
  2016. }
  2017. //
  2018. // Enumerate the date pictures based on the flags.
  2019. //
  2020. switch (dwFlags & (~LOCALE_USE_CP_ACP))
  2021. {
  2022. case ( 0 ) :
  2023. case ( DATE_SHORTDATE ) :
  2024. {
  2025. //
  2026. // Enumerate the short date formats.
  2027. //
  2028. return ( EnumDateTime( lpDateFmtEnumProc,
  2029. Locale,
  2030. LOCALE_SSHORTDATE,
  2031. dwFlags,
  2032. FIELD_OFFSET(NLS_USER_INFO, sShortDate),
  2033. NLS_VALUE_SSHORTDATE,
  2034. pHashN->pLocaleHdr,
  2035. (LPWORD)(pHashN->pLocaleHdr) +
  2036. pHashN->pLocaleHdr->SShortDate,
  2037. (LPWORD)(pHashN->pLocaleHdr) +
  2038. pHashN->pLocaleHdr->SDate,
  2039. (ULONG)FIELD_OFFSET(CALENDAR_VAR, SShortDate),
  2040. (ULONG)FIELD_OFFSET(CALENDAR_VAR, SYearMonth),
  2041. TRUE,
  2042. fUnicodeVer,
  2043. fExVersion ) );
  2044. break;
  2045. }
  2046. case ( DATE_LONGDATE ) :
  2047. {
  2048. //
  2049. // Enumerate the long date formats.
  2050. //
  2051. return ( EnumDateTime( lpDateFmtEnumProc,
  2052. Locale,
  2053. LOCALE_SLONGDATE,
  2054. dwFlags,
  2055. FIELD_OFFSET(NLS_USER_INFO, sLongDate),
  2056. NLS_VALUE_SLONGDATE,
  2057. pHashN->pLocaleHdr,
  2058. (LPWORD)(pHashN->pLocaleHdr) +
  2059. pHashN->pLocaleHdr->SLongDate,
  2060. (LPWORD)(pHashN->pLocaleHdr) +
  2061. pHashN->pLocaleHdr->IOptionalCal,
  2062. (ULONG)FIELD_OFFSET(CALENDAR_VAR, SLongDate),
  2063. (ULONG)FIELD_OFFSET(CALENDAR_VAR, SDayName1),
  2064. TRUE,
  2065. fUnicodeVer,
  2066. fExVersion ) );
  2067. break;
  2068. }
  2069. case ( DATE_YEARMONTH ) :
  2070. {
  2071. //
  2072. // Enumerate the year month formats.
  2073. //
  2074. return ( EnumDateTime( lpDateFmtEnumProc,
  2075. Locale,
  2076. LOCALE_SYEARMONTH,
  2077. dwFlags,
  2078. FIELD_OFFSET(NLS_USER_INFO, sYearMonth),
  2079. NLS_VALUE_SYEARMONTH,
  2080. pHashN->pLocaleHdr,
  2081. (LPWORD)(pHashN->pLocaleHdr) +
  2082. pHashN->pLocaleHdr->SYearMonth,
  2083. (LPWORD)(pHashN->pLocaleHdr) +
  2084. pHashN->pLocaleHdr->SLongDate,
  2085. (ULONG)FIELD_OFFSET(CALENDAR_VAR, SYearMonth),
  2086. (ULONG)FIELD_OFFSET(CALENDAR_VAR, SLongDate),
  2087. TRUE,
  2088. fUnicodeVer,
  2089. fExVersion ) );
  2090. break;
  2091. }
  2092. default :
  2093. {
  2094. SetLastError(ERROR_INVALID_FLAGS);
  2095. return (FALSE);
  2096. }
  2097. }
  2098. }
  2099. //-------------------------------------------------------------------------//
  2100. // INTERNAL ROUTINES //
  2101. //-------------------------------------------------------------------------//
  2102. ////////////////////////////////////////////////////////////////////////////
  2103. //
  2104. // EnumDateTime
  2105. //
  2106. // Enumerates the short date, long date, year/month, or time formats that
  2107. // are available for the specified locale. This is the worker routine for
  2108. // the EnumTimeFormats and EnumDateFormats apis.
  2109. //
  2110. // 10-14-93 JulieB Created.
  2111. ////////////////////////////////////////////////////////////////////////////
  2112. BOOL EnumDateTime(
  2113. NLS_ENUMPROC lpDateTimeFmtEnumProc,
  2114. LCID Locale,
  2115. LCTYPE LCType,
  2116. DWORD dwFlags,
  2117. SIZE_T CacheOffset,
  2118. LPWSTR pRegValue,
  2119. PLOCALE_VAR pLocaleHdr,
  2120. LPWSTR pDateTime,
  2121. LPWSTR pEndDateTime,
  2122. ULONG CalDateOffset,
  2123. ULONG EndCalDateOffset,
  2124. BOOL fCalendarInfo,
  2125. BOOL fUnicodeVer,
  2126. BOOL fExVersion)
  2127. {
  2128. LPWSTR pUser = NULL; // ptr to user date/time string
  2129. LPWSTR pOptCal; // ptr to optional calendar values
  2130. LPWSTR pEndOptCal; // ptr to end of optional calendars
  2131. PCAL_INFO pCalInfo; // ptr to calendar info
  2132. CALID CalNum = 1; // calendar number
  2133. WCHAR pTemp[MAX_REG_VAL_SIZE]; // temp buffer
  2134. UNICODE_STRING ObUnicodeStr; // calendar id string
  2135. //
  2136. // Get the user's Calendar ID.
  2137. //
  2138. if (fExVersion)
  2139. {
  2140. if (GetUserInfo( Locale,
  2141. LOCALE_ICALENDARTYPE,
  2142. FIELD_OFFSET(NLS_USER_INFO, iCalType),
  2143. NLS_VALUE_ICALENDARTYPE,
  2144. pTemp,
  2145. ARRAYSIZE(pTemp),
  2146. TRUE ))
  2147. {
  2148. RtlInitUnicodeString(&ObUnicodeStr, pTemp);
  2149. if ((RtlUnicodeStringToInteger(&ObUnicodeStr, 10, &CalNum)) ||
  2150. (CalNum < 1) || (CalNum > CAL_LAST))
  2151. {
  2152. CalNum = 1;
  2153. }
  2154. }
  2155. }
  2156. //
  2157. // Get the user defined string.
  2158. //
  2159. if (GetUserInfo( Locale,
  2160. LCType,
  2161. CacheOffset,
  2162. pRegValue,
  2163. pTemp,
  2164. ARRAYSIZE(pTemp),
  2165. TRUE ))
  2166. {
  2167. pUser = pTemp;
  2168. //
  2169. // Call the appropriate callback function.
  2170. //
  2171. NLS_CALL_ENUMPROC_TRUE( Locale,
  2172. lpDateTimeFmtEnumProc,
  2173. dwFlags,
  2174. pUser,
  2175. CalNum,
  2176. fUnicodeVer,
  2177. fExVersion );
  2178. }
  2179. //
  2180. // Get the default strings defined for the Gregorian
  2181. // calendar.
  2182. //
  2183. while (pDateTime < pEndDateTime)
  2184. {
  2185. //
  2186. // Call the callback function if the string is not
  2187. // the same as the user string.
  2188. //
  2189. if ((!pUser) || (!NlsStrEqualW(pUser, pDateTime)))
  2190. {
  2191. //
  2192. // Call the appropriate callback function.
  2193. //
  2194. NLS_CALL_ENUMPROC_TRUE( Locale,
  2195. lpDateTimeFmtEnumProc,
  2196. dwFlags,
  2197. pDateTime,
  2198. CAL_GREGORIAN,
  2199. fUnicodeVer,
  2200. fExVersion );
  2201. }
  2202. //
  2203. // Advance pDateTime pointer.
  2204. //
  2205. pDateTime += NlsStrLenW(pDateTime) + 1;
  2206. }
  2207. if (fCalendarInfo)
  2208. {
  2209. //
  2210. // Get any alternate calendar dates.
  2211. //
  2212. pOptCal = (LPWORD)(pLocaleHdr) + pLocaleHdr->IOptionalCal;
  2213. if (((POPT_CAL)pOptCal)->CalId == CAL_NO_OPTIONAL)
  2214. {
  2215. //
  2216. // No optional calendars, so done.
  2217. //
  2218. return (TRUE);
  2219. }
  2220. //
  2221. // Get the requested information for each of the alternate
  2222. // calendars.
  2223. //
  2224. pEndOptCal = (LPWORD)(pLocaleHdr) + pLocaleHdr->SDayName1;
  2225. while (pOptCal < pEndOptCal)
  2226. {
  2227. //
  2228. // Get the pointer to the calendar information.
  2229. //
  2230. CalNum = ((POPT_CAL)pOptCal)->CalId;
  2231. if (GetCalendar(CalNum, &pCalInfo) == NO_ERROR)
  2232. {
  2233. //
  2234. // Get the pointer to the date/time information for the
  2235. // current calendar.
  2236. //
  2237. pDateTime = (LPWORD)pCalInfo +
  2238. *((LPWORD)((LPBYTE)(pCalInfo) + CalDateOffset));
  2239. pEndDateTime = (LPWORD)pCalInfo +
  2240. *((LPWORD)((LPBYTE)(pCalInfo) + EndCalDateOffset));
  2241. //
  2242. // Go through each of the strings.
  2243. //
  2244. while (pDateTime < pEndDateTime)
  2245. {
  2246. //
  2247. // Make sure the string is NOT empty and that it is
  2248. // NOT the same as the user's string.
  2249. //
  2250. if ((*pDateTime) &&
  2251. ((!pUser) || (!NlsStrEqualW(pUser, pDateTime))))
  2252. {
  2253. //
  2254. // Call the appropriate callback function.
  2255. //
  2256. NLS_CALL_ENUMPROC_TRUE( Locale,
  2257. lpDateTimeFmtEnumProc,
  2258. dwFlags,
  2259. pDateTime,
  2260. CalNum,
  2261. fUnicodeVer,
  2262. fExVersion );
  2263. }
  2264. //
  2265. // Advance pointer to next date string.
  2266. //
  2267. pDateTime += NlsStrLenW(pDateTime) + 1;
  2268. }
  2269. }
  2270. //
  2271. // Advance ptr to next optional calendar.
  2272. //
  2273. pOptCal += ((POPT_CAL)pOptCal)->Offset;
  2274. }
  2275. }
  2276. //
  2277. // Return success.
  2278. //
  2279. return (TRUE);
  2280. }