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.

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