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
2526 lines
97 KiB
/*++
|
|
|
|
Copyright (c) 1991-2000, Microsoft Corporation All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
enum.c
|
|
|
|
Abstract:
|
|
|
|
This file contains functions that enumerate the user's portion of the
|
|
registry for installed and supported locale ids and code page ids.
|
|
|
|
APIs found in this file:
|
|
EnumSystemLanguageGroupsW
|
|
EnumLanguageGroupLocalesW
|
|
EnumUILanguagesW
|
|
EnumSystemLocalesW
|
|
EnumSystemCodePagesW
|
|
EnumCalendarInfoW
|
|
EnumCalendarInfoExW
|
|
EnumTimeFormatsW
|
|
EnumDateFormatsW
|
|
EnumDateFormatsExW
|
|
|
|
Revision History:
|
|
|
|
08-02-93 JulieB Created.
|
|
|
|
--*/
|
|
|
|
|
|
|
|
//
|
|
// Include Files.
|
|
//
|
|
|
|
#include "nls.h"
|
|
#include "nlssafe.h"
|
|
|
|
|
|
|
|
//
|
|
// Constant Declarations
|
|
//
|
|
|
|
#define ENUM_BUF_SIZE 9 // buffer size (wchar) for lcid or cpid (incl null)
|
|
#define ENUM_MAX_CP_SIZE 5 // max size (wchar) for cp id in registry
|
|
#define ENUM_LOCALE_SIZE 8 // buffer size (wchar) for locale id in registry
|
|
#define ENUM_MAX_LG_SIZE 2 // max size (wchar) for language group id in registry
|
|
#define ENUM_MAX_UILANG_SIZE 4 // max size (wchar) for UI langguage id in registry
|
|
|
|
|
|
|
|
|
|
//
|
|
// Forward Declarations.
|
|
//
|
|
|
|
BOOL
|
|
EnumDateTime(
|
|
NLS_ENUMPROC lpDateTimeFmtEnumProc,
|
|
LCID Locale,
|
|
LCTYPE LCType,
|
|
DWORD dwFlags,
|
|
SIZE_T CacheOffset,
|
|
LPWSTR pRegValue,
|
|
PLOCALE_VAR pLocaleHdr,
|
|
LPWSTR pDateTime,
|
|
LPWSTR pEndDateTime,
|
|
ULONG CalDateOffset,
|
|
ULONG EndCalDateOffset,
|
|
BOOL fCalendarInfo,
|
|
BOOL fUnicodeVer,
|
|
BOOL fExVersion);
|
|
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------//
|
|
// INTERNAL MACROS //
|
|
//-------------------------------------------------------------------------//
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// NLS_CALL_ENUMPROC_BREAK
|
|
//
|
|
// Calls the appropriate EnumProc routine. If the fUnicodeVer flag is TRUE,
|
|
// then it calls the Unicode version of the callback function. Otherwise,
|
|
// it calls the Ansi dispatch routine to translate the string to Ansi and
|
|
// then call the Ansi version of the callback function.
|
|
//
|
|
// This macro will do a break if the enumeration routine returns FALSE.
|
|
//
|
|
// DEFINED AS A MACRO.
|
|
//
|
|
// 11-10-93 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define NLS_CALL_ENUMPROC_BREAK( Locale, \
|
|
lpNlsEnumProc, \
|
|
dwFlags, \
|
|
pUnicodeBuffer, \
|
|
fUnicodeVer ) \
|
|
{ \
|
|
/* \
|
|
* Call the appropriate callback function. \
|
|
*/ \
|
|
if (fUnicodeVer) \
|
|
{ \
|
|
/* \
|
|
* Call the Unicode callback function. \
|
|
*/ \
|
|
if (((*lpNlsEnumProc)(pUnicodeBuffer)) != TRUE) \
|
|
{ \
|
|
break; \
|
|
} \
|
|
} \
|
|
else \
|
|
{ \
|
|
/* \
|
|
* Call the Ansi callback function. \
|
|
*/ \
|
|
if (NlsDispatchAnsiEnumProc( Locale, \
|
|
lpNlsEnumProc, \
|
|
dwFlags, \
|
|
pUnicodeBuffer, \
|
|
NULL, \
|
|
0, \
|
|
0, \
|
|
0, \
|
|
0 ) != TRUE) \
|
|
{ \
|
|
break; \
|
|
} \
|
|
} \
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// NLS_CALL_ENUMPROC_BREAK_2
|
|
//
|
|
// Calls the appropriate EnumProc routine. If the fUnicodeVer flag is TRUE,
|
|
// then it calls the Unicode version of the callback function. Otherwise,
|
|
// it calls the Ansi dispatch routine to translate the strings to Ansi and
|
|
// then call the Ansi version of the callback function.
|
|
//
|
|
// This macro will do a break if the enumeration routine returns FALSE.
|
|
//
|
|
// DEFINED AS A MACRO.
|
|
//
|
|
// 03-10-98 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define NLS_CALL_ENUMPROC_BREAK_2( Locale, \
|
|
lpNlsEnumProc, \
|
|
dwFlags, \
|
|
LanguageGroup, \
|
|
EnumLocale, \
|
|
pUnicodeBuffer, \
|
|
lParam, \
|
|
fUnicodeVer ) \
|
|
{ \
|
|
/* \
|
|
* Call the appropriate callback function. \
|
|
*/ \
|
|
if (fUnicodeVer) \
|
|
{ \
|
|
/* \
|
|
* Call the Unicode callback function. \
|
|
*/ \
|
|
if (((*((NLS_ENUMPROC2)lpNlsEnumProc))( LanguageGroup, \
|
|
EnumLocale, \
|
|
pUnicodeBuffer, \
|
|
lParam )) != TRUE) \
|
|
{ \
|
|
break; \
|
|
} \
|
|
} \
|
|
else \
|
|
{ \
|
|
/* \
|
|
* Call the Ansi callback function. \
|
|
*/ \
|
|
if (NlsDispatchAnsiEnumProc( Locale, \
|
|
lpNlsEnumProc, \
|
|
dwFlags, \
|
|
pUnicodeBuffer, \
|
|
NULL, \
|
|
LanguageGroup, \
|
|
EnumLocale, \
|
|
lParam, \
|
|
2 ) != TRUE) \
|
|
{ \
|
|
break; \
|
|
} \
|
|
} \
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// NLS_CALL_ENUMPROC_BREAK_3
|
|
//
|
|
// Calls the appropriate EnumProc routine. If the fUnicodeVer flag is TRUE,
|
|
// then it calls the Unicode version of the callback function. Otherwise,
|
|
// it calls the Ansi dispatch routine to translate the strings to Ansi and
|
|
// then call the Ansi version of the callback function.
|
|
//
|
|
// This macro will do a break if the enumeration routine returns FALSE.
|
|
//
|
|
// DEFINED AS A MACRO.
|
|
//
|
|
// 03-10-98 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define NLS_CALL_ENUMPROC_BREAK_3( Locale, \
|
|
lpNlsEnumProc, \
|
|
dwFlags, \
|
|
LanguageGroup, \
|
|
pUnicodeBuffer1, \
|
|
pUnicodeBuffer2, \
|
|
dwInstall, \
|
|
lParam, \
|
|
fUnicodeVer ) \
|
|
{ \
|
|
/* \
|
|
* Call the appropriate callback function. \
|
|
*/ \
|
|
if (fUnicodeVer) \
|
|
{ \
|
|
/* \
|
|
* Call the Unicode callback function. \
|
|
*/ \
|
|
if (((*((NLS_ENUMPROC3)lpNlsEnumProc))( LanguageGroup, \
|
|
pUnicodeBuffer1, \
|
|
pUnicodeBuffer2, \
|
|
(dwInstall), \
|
|
lParam )) != TRUE) \
|
|
{ \
|
|
break; \
|
|
} \
|
|
} \
|
|
else \
|
|
{ \
|
|
/* \
|
|
* Call the Ansi callback function. \
|
|
*/ \
|
|
if (NlsDispatchAnsiEnumProc( Locale, \
|
|
lpNlsEnumProc, \
|
|
dwFlags, \
|
|
pUnicodeBuffer1, \
|
|
pUnicodeBuffer2, \
|
|
LanguageGroup, \
|
|
(dwInstall), \
|
|
lParam, \
|
|
3 ) != TRUE) \
|
|
{ \
|
|
break; \
|
|
} \
|
|
} \
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// NLS_CALL_ENUMPROC_BREAK_4
|
|
//
|
|
// Calls the appropriate EnumProc routine. If the fUnicodeVer flag is TRUE,
|
|
// then it calls the Unicode version of the callback function. Otherwise,
|
|
// it calls the Ansi dispatch routine to translate the string to Ansi and
|
|
// then call the Ansi version of the callback function.
|
|
//
|
|
// This macro will do a break if the enumeration routine returns FALSE.
|
|
// Used by EnumUILanguages.
|
|
//
|
|
// DEFINED AS A MACRO.
|
|
//
|
|
// 12-03-98 SamerA Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define NLS_CALL_ENUMPROC_BREAK_4( Locale, \
|
|
lpNlsEnumProc, \
|
|
dwFlags, \
|
|
pUnicodeBuffer, \
|
|
lParam, \
|
|
fUnicodeVer ) \
|
|
{ \
|
|
/* \
|
|
* Call the appropriate callback function. \
|
|
*/ \
|
|
if (fUnicodeVer) \
|
|
{ \
|
|
/* \
|
|
* Call the Unicode callback function. \
|
|
*/ \
|
|
if (((*((NLS_ENUMPROC4)lpNlsEnumProc))(pUnicodeBuffer, \
|
|
lParam)) != TRUE) \
|
|
{ \
|
|
break; \
|
|
} \
|
|
} \
|
|
else \
|
|
{ \
|
|
/* \
|
|
* Call the Ansi callback function. \
|
|
*/ \
|
|
if (NlsDispatchAnsiEnumProc( Locale, \
|
|
lpNlsEnumProc, \
|
|
dwFlags, \
|
|
pUnicodeBuffer, \
|
|
NULL, \
|
|
0, \
|
|
0, \
|
|
lParam, \
|
|
4 ) != TRUE) \
|
|
{ \
|
|
break; \
|
|
} \
|
|
} \
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// NLS_CALL_ENUMPROC_TRUE_4
|
|
//
|
|
// Calls the appropriate EnumProc routine. If the fUnicodeVer flag is TRUE,
|
|
// then it calls the Unicode version of the callback function. Otherwise,
|
|
// it calls the Ansi dispatch routine to translate the string to Ansi and
|
|
// then call the Ansi version of the callback function.
|
|
//
|
|
// This macro will do a break if the enumeration routine returns FALSE.
|
|
// Used by EnumUILanguages.
|
|
//
|
|
// DEFINED AS A MACRO.
|
|
//
|
|
// 12-03-98 SamerA Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define NLS_CALL_ENUMPROC_TRUE_4( Locale, \
|
|
lpNlsEnumProc, \
|
|
dwFlags, \
|
|
pUnicodeBuffer, \
|
|
lParam, \
|
|
fUnicodeVer ) \
|
|
{ \
|
|
/* \
|
|
* Call the appropriate callback function. \
|
|
*/ \
|
|
if (fUnicodeVer) \
|
|
{ \
|
|
/* \
|
|
* Call the Unicode callback function. \
|
|
*/ \
|
|
if (((*((NLS_ENUMPROC4)lpNlsEnumProc))(pUnicodeBuffer, \
|
|
lParam)) != TRUE) \
|
|
{ \
|
|
return (TRUE); \
|
|
} \
|
|
} \
|
|
else \
|
|
{ \
|
|
/* \
|
|
* Call the Ansi callback function. \
|
|
*/ \
|
|
if (NlsDispatchAnsiEnumProc( Locale, \
|
|
lpNlsEnumProc, \
|
|
dwFlags, \
|
|
pUnicodeBuffer, \
|
|
NULL, \
|
|
0, \
|
|
0, \
|
|
lParam, \
|
|
4 ) != TRUE) \
|
|
{ \
|
|
return (TRUE); \
|
|
} \
|
|
} \
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// NLS_CALL_ENUMPROC_TRUE
|
|
//
|
|
// Calls the appropriate EnumProc routine. If the fUnicodeVer flag is TRUE,
|
|
// then it calls the Unicode version of the callback function. Otherwise,
|
|
// it calls the Ansi dispatch routine to translate the string to Ansi and
|
|
// then call the Ansi version of the callback function.
|
|
//
|
|
// This macro will return TRUE if the enumeration routine returns FALSE.
|
|
//
|
|
// DEFINED AS A MACRO.
|
|
//
|
|
// 11-10-93 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define NLS_CALL_ENUMPROC_TRUE( Locale, \
|
|
lpNlsEnumProc, \
|
|
dwFlags, \
|
|
pUnicodeBuffer, \
|
|
CalId, \
|
|
fUnicodeVer, \
|
|
fVer ) \
|
|
{ \
|
|
/* \
|
|
* Call the appropriate callback function. \
|
|
*/ \
|
|
if (fUnicodeVer) \
|
|
{ \
|
|
/* \
|
|
* Call the Unicode callback function. \
|
|
*/ \
|
|
if (fVer == 1) \
|
|
{ \
|
|
if (((*((NLS_ENUMPROCEX)lpNlsEnumProc))( pUnicodeBuffer, \
|
|
CalId )) != TRUE) \
|
|
{ \
|
|
return (TRUE); \
|
|
} \
|
|
} \
|
|
else /* fVer == 0 */ \
|
|
{ \
|
|
if (((*lpNlsEnumProc)(pUnicodeBuffer)) != TRUE) \
|
|
{ \
|
|
return (TRUE); \
|
|
} \
|
|
} \
|
|
} \
|
|
else \
|
|
{ \
|
|
/* \
|
|
* Call the Ansi callback function. \
|
|
*/ \
|
|
if (NlsDispatchAnsiEnumProc( Locale, \
|
|
lpNlsEnumProc, \
|
|
dwFlags, \
|
|
pUnicodeBuffer, \
|
|
NULL, \
|
|
CalId, \
|
|
0, \
|
|
0, \
|
|
fVer ) != TRUE) \
|
|
{ \
|
|
return (TRUE); \
|
|
} \
|
|
} \
|
|
}
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------//
|
|
// API ROUTINES //
|
|
//-------------------------------------------------------------------------//
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// EnumSystemLanguageGroupsW
|
|
//
|
|
// Enumerates the system language groups that are installed or supported,
|
|
// based on the dwFlags parameter. It does so by passing the pointer to
|
|
// the string buffer containing the language group id to an
|
|
// application-defined callback function. It continues until the last
|
|
// language group id is found or the callback function returns FALSE.
|
|
//
|
|
// 03-10-98 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL WINAPI EnumSystemLanguageGroupsW(
|
|
LANGUAGEGROUP_ENUMPROCW lpLanguageGroupEnumProc,
|
|
DWORD dwFlags,
|
|
LONG_PTR lParam)
|
|
{
|
|
return (Internal_EnumSystemLanguageGroups(
|
|
(NLS_ENUMPROC)lpLanguageGroupEnumProc,
|
|
dwFlags,
|
|
lParam,
|
|
TRUE ));
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// EnumLanguageGroupLocalesW
|
|
//
|
|
// Enumerates the locales in a given language group. It does so by
|
|
// passing the appropriate information to an application-defined
|
|
// callback function. It continues until the last locale in the language
|
|
// group is found or the callback function returns FALSE.
|
|
//
|
|
// 03-10-98 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL WINAPI EnumLanguageGroupLocalesW(
|
|
LANGGROUPLOCALE_ENUMPROCW lpLangGroupLocaleEnumProc,
|
|
LGRPID LanguageGroup,
|
|
DWORD dwFlags,
|
|
LONG_PTR lParam)
|
|
{
|
|
return (Internal_EnumLanguageGroupLocales(
|
|
(NLS_ENUMPROC)lpLangGroupLocaleEnumProc,
|
|
LanguageGroup,
|
|
dwFlags,
|
|
lParam,
|
|
TRUE ));
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// EnumUILanguagesW
|
|
//
|
|
// Enumerates the system UI languages that are installed. It does so by
|
|
// passing the pointer to the string buffer containing the UI language id
|
|
// to an application-defined callback function. It continues until the
|
|
// last UI language id is found or the callback function returns FALSE.
|
|
//
|
|
// 03-10-98 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL WINAPI EnumUILanguagesW(
|
|
UILANGUAGE_ENUMPROCW lpUILanguageEnumProc,
|
|
DWORD dwFlags,
|
|
LONG_PTR lParam)
|
|
{
|
|
return (Internal_EnumUILanguages( (NLS_ENUMPROC)lpUILanguageEnumProc,
|
|
dwFlags,
|
|
lParam,
|
|
TRUE ));
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// EnumSystemLocalesW
|
|
//
|
|
// Enumerates the system locales that are installed or supported, based on
|
|
// the dwFlags parameter. It does so by passing the pointer to the string
|
|
// buffer containing the locale id to an application-defined callback
|
|
// function. It continues until the last locale id is found or the
|
|
// callback function returns FALSE.
|
|
//
|
|
// 08-02-93 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL WINAPI EnumSystemLocalesW(
|
|
LOCALE_ENUMPROCW lpLocaleEnumProc,
|
|
DWORD dwFlags)
|
|
{
|
|
return (Internal_EnumSystemLocales( (NLS_ENUMPROC)lpLocaleEnumProc,
|
|
dwFlags,
|
|
TRUE ));
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// EnumSystemCodePagesW
|
|
//
|
|
// Enumerates the system code pages that are installed or supported, based on
|
|
// the dwFlags parameter. It does so by passing the pointer to the string
|
|
// buffer containing the code page id to an application-defined callback
|
|
// function. It continues until the last code page is found or the
|
|
// callback function returns FALSE.
|
|
//
|
|
// 08-02-93 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL WINAPI EnumSystemCodePagesW(
|
|
CODEPAGE_ENUMPROCW lpCodePageEnumProc,
|
|
DWORD dwFlags)
|
|
{
|
|
return (Internal_EnumSystemCodePages( (NLS_ENUMPROC)lpCodePageEnumProc,
|
|
dwFlags,
|
|
TRUE ));
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// EnumCalendarInfoW
|
|
//
|
|
// Enumerates the specified calendar information that is available for the
|
|
// specified locale, based on the CalType parameter. It does so by
|
|
// passing the pointer to the string buffer containing the calendar info
|
|
// to an application-defined callback function. It continues until the
|
|
// last calendar info is found or the callback function returns FALSE.
|
|
//
|
|
// 10-14-93 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL WINAPI EnumCalendarInfoW(
|
|
CALINFO_ENUMPROCW lpCalInfoEnumProc,
|
|
LCID Locale,
|
|
CALID Calendar,
|
|
CALTYPE CalType)
|
|
{
|
|
return (Internal_EnumCalendarInfo( (NLS_ENUMPROC)lpCalInfoEnumProc,
|
|
Locale,
|
|
Calendar,
|
|
CalType,
|
|
TRUE,
|
|
FALSE ));
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// EnumCalendarInfoExW
|
|
//
|
|
// Enumerates the specified calendar information that is available for the
|
|
// specified locale, based on the CalType parameter. It does so by
|
|
// passing the pointer to the string buffer containing the calendar info
|
|
// and the calendar id to an application-defined callback function. It
|
|
// continues until the last calendar info is found or the callback function
|
|
// returns FALSE.
|
|
//
|
|
// 10-14-96 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL WINAPI EnumCalendarInfoExW(
|
|
CALINFO_ENUMPROCEXW lpCalInfoEnumProcEx,
|
|
LCID Locale,
|
|
CALID Calendar,
|
|
CALTYPE CalType)
|
|
{
|
|
return (Internal_EnumCalendarInfo( (NLS_ENUMPROC)lpCalInfoEnumProcEx,
|
|
Locale,
|
|
Calendar,
|
|
CalType,
|
|
TRUE,
|
|
TRUE ));
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// EnumTimeFormatsW
|
|
//
|
|
// Enumerates the time formats that are available for the
|
|
// specified locale, based on the dwFlags parameter. It does so by
|
|
// passing the pointer to the string buffer containing the time format
|
|
// to an application-defined callback function. It continues until the
|
|
// last time format is found or the callback function returns FALSE.
|
|
//
|
|
// 10-14-93 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL WINAPI EnumTimeFormatsW(
|
|
TIMEFMT_ENUMPROCW lpTimeFmtEnumProc,
|
|
LCID Locale,
|
|
DWORD dwFlags)
|
|
{
|
|
return (Internal_EnumTimeFormats( (NLS_ENUMPROC)lpTimeFmtEnumProc,
|
|
Locale,
|
|
dwFlags,
|
|
TRUE ));
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// EnumDateFormatsW
|
|
//
|
|
// Enumerates the short date, long date, or year/month formats that are
|
|
// available for the specified locale, based on the dwFlags parameter.
|
|
// It does so by passing the pointer to the string buffer containing the
|
|
// date format to an application-defined callback function. It continues
|
|
// until the last date format is found or the callback function returns
|
|
// FALSE.
|
|
//
|
|
// 10-14-93 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL WINAPI EnumDateFormatsW(
|
|
DATEFMT_ENUMPROCW lpDateFmtEnumProc,
|
|
LCID Locale,
|
|
DWORD dwFlags)
|
|
{
|
|
return (Internal_EnumDateFormats( (NLS_ENUMPROC)lpDateFmtEnumProc,
|
|
Locale,
|
|
dwFlags,
|
|
TRUE,
|
|
FALSE ));
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// EnumDateFormatsExW
|
|
//
|
|
// Enumerates the short date, long date, or year/month formats that are
|
|
// available for the specified locale, based on the dwFlags parameter.
|
|
// It does so by passing the pointer to the string buffer containing the
|
|
// date format and the calendar id to an application-defined callback
|
|
// function. It continues until the last date format is found or the
|
|
// callback function returns FALSE.
|
|
//
|
|
// 10-14-96 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL WINAPI EnumDateFormatsExW(
|
|
DATEFMT_ENUMPROCEXW lpDateFmtEnumProcEx,
|
|
LCID Locale,
|
|
DWORD dwFlags)
|
|
{
|
|
return (Internal_EnumDateFormats( (NLS_ENUMPROC)lpDateFmtEnumProcEx,
|
|
Locale,
|
|
dwFlags,
|
|
TRUE,
|
|
TRUE ));
|
|
}
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------//
|
|
// EXTERNAL ROUTINES //
|
|
//-------------------------------------------------------------------------//
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Internal_EnumSystemLanguageGroups
|
|
//
|
|
// Enumerates the system language groups that are installed or supported,
|
|
// based on the dwFlags parameter. It does so by passing the pointer to
|
|
// the string buffer containing the language group id to an
|
|
// application-defined callback function. It continues until the last
|
|
// language group id is found or the callback function returns FALSE.
|
|
//
|
|
// 03-10-98 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL Internal_EnumSystemLanguageGroups(
|
|
NLS_ENUMPROC lpLanguageGroupEnumProc,
|
|
DWORD dwFlags,
|
|
LONG_PTR lParam,
|
|
BOOL fUnicodeVer)
|
|
{
|
|
PKEY_VALUE_FULL_INFORMATION pKeyValueFull = NULL;
|
|
BYTE pStatic[MAX_KEY_VALUE_FULLINFO];
|
|
|
|
BOOL fInstalled; // if installed flag set
|
|
ULONG Index; // index for enumeration
|
|
ULONG ResultLength; // # bytes written
|
|
WCHAR wch; // first char of name
|
|
LPWSTR pName; // ptr to name string from registry
|
|
WCHAR szLGName[MAX_PATH]; // language group name
|
|
UNICODE_STRING ObUnicodeStr; // registry data value string
|
|
DWORD Data; // registry data value
|
|
ULONG NameLen; // length of name string
|
|
LGRPID LangGroup; // language group id
|
|
ULONG rc = 0L; // return code
|
|
|
|
|
|
//
|
|
// Invalid Parameter Check:
|
|
// - function pointer is null
|
|
//
|
|
if (lpLanguageGroupEnumProc == NULL)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// Invalid Flags Check:
|
|
// - flags other than valid ones
|
|
// - more than one of either supported or installed
|
|
//
|
|
if ( (dwFlags & ESLG_INVALID_FLAG) ||
|
|
(MORE_THAN_ONE(dwFlags, ESLG_SINGLE_FLAG)) )
|
|
{
|
|
SetLastError(ERROR_INVALID_FLAGS);
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// Initialize flag option.
|
|
//
|
|
fInstalled = dwFlags & LGRPID_INSTALLED;
|
|
|
|
//
|
|
// Initialize key handles.
|
|
//
|
|
OPEN_LANG_GROUPS_KEY(FALSE);
|
|
|
|
//
|
|
// Loop through the language group ids in the registry, call the
|
|
// function pointer for each one that meets the flag criteria.
|
|
//
|
|
// End loop if either FALSE is returned from the callback function
|
|
// or the end of the list is reached.
|
|
//
|
|
Index = 0;
|
|
pKeyValueFull = (PKEY_VALUE_FULL_INFORMATION)pStatic;
|
|
RtlZeroMemory(pKeyValueFull, MAX_KEY_VALUE_FULLINFO);
|
|
rc = NtEnumerateValueKey( hLangGroupsKey,
|
|
Index,
|
|
KeyValueFullInformation,
|
|
pKeyValueFull,
|
|
MAX_KEY_VALUE_FULLINFO,
|
|
&ResultLength );
|
|
|
|
while (rc != STATUS_NO_MORE_ENTRIES)
|
|
{
|
|
if (!NT_SUCCESS(rc))
|
|
{
|
|
//
|
|
// If we get a different error, then the registry
|
|
// is corrupt. Just return FALSE.
|
|
//
|
|
KdPrint(("NLSAPI: Language Group Enumeration Error - registry corrupt. - %lx.\n",
|
|
rc));
|
|
SetLastError(ERROR_BADDB);
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// Skip over any entry that does not have data associated with it
|
|
// if the LGRPID_INSTALLED flag is set.
|
|
//
|
|
pName = pKeyValueFull->Name;
|
|
wch = *pName;
|
|
NameLen = pKeyValueFull->NameLength / sizeof(WCHAR);
|
|
if ( (NameLen <= ENUM_MAX_LG_SIZE) &&
|
|
(((wch >= NLS_CHAR_ZERO) && (wch <= NLS_CHAR_NINE)) ||
|
|
(((wch | 0x0020) >= L'a') && ((wch | 0x0020) <= L'f'))) &&
|
|
(!((fInstalled) && (pKeyValueFull->DataLength <= 2))) )
|
|
{
|
|
//
|
|
// See if the language group is installed or not.
|
|
//
|
|
Data = 0;
|
|
if (pKeyValueFull->DataLength > 2)
|
|
{
|
|
RtlInitUnicodeString( &ObUnicodeStr,
|
|
GET_VALUE_DATA_PTR(pKeyValueFull) );
|
|
|
|
if (RtlUnicodeStringToInteger(&ObUnicodeStr, 16, &Data))
|
|
{
|
|
Data = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the installed flag is set, then skip the language group
|
|
// if it is not already installed.
|
|
//
|
|
if ((fInstalled) && (Data != 1))
|
|
{
|
|
goto EnumNextLanguageGroup;
|
|
}
|
|
|
|
//
|
|
// Store the language group id string in the callback buffer.
|
|
//
|
|
pName[NameLen] = 0;
|
|
|
|
//
|
|
// Get the language group id as a value and the localized
|
|
// language group name.
|
|
//
|
|
RtlInitUnicodeString(&ObUnicodeStr, pName);
|
|
if ((RtlUnicodeStringToInteger(&ObUnicodeStr, 16, &LangGroup)) ||
|
|
(GetStringTableEntry( LangGroup,
|
|
0,
|
|
szLGName,
|
|
MAX_PATH,
|
|
RC_LANGUAGE_GROUP_NAME ) == 0))
|
|
{
|
|
goto EnumNextLanguageGroup;
|
|
}
|
|
|
|
//
|
|
// Call the appropriate callback function.
|
|
//
|
|
NLS_CALL_ENUMPROC_BREAK_3( gSystemLocale,
|
|
lpLanguageGroupEnumProc,
|
|
dwFlags,
|
|
LangGroup,
|
|
pName,
|
|
szLGName,
|
|
(Data == 1)
|
|
? LGRPID_INSTALLED
|
|
: LGRPID_SUPPORTED,
|
|
lParam,
|
|
fUnicodeVer );
|
|
}
|
|
|
|
EnumNextLanguageGroup:
|
|
//
|
|
// Increment enumeration index value and get the next enumeration.
|
|
//
|
|
Index++;
|
|
RtlZeroMemory(pKeyValueFull, MAX_KEY_VALUE_FULLINFO);
|
|
rc = NtEnumerateValueKey( hLangGroupsKey,
|
|
Index,
|
|
KeyValueFullInformation,
|
|
pKeyValueFull,
|
|
MAX_KEY_VALUE_FULLINFO,
|
|
&ResultLength );
|
|
}
|
|
|
|
//
|
|
// Return success.
|
|
//
|
|
return (TRUE);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Internal_EnumLanguageGroupLocales
|
|
//
|
|
// Enumerates the locales in a given language group. It does so by
|
|
// passing the appropriate information to an application-defined
|
|
// callback function. It continues until the last locale in the language
|
|
// group is found or the callback function returns FALSE.
|
|
//
|
|
// 03-10-98 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL Internal_EnumLanguageGroupLocales(
|
|
NLS_ENUMPROC lpLangGroupLocaleEnumProc,
|
|
LGRPID LanguageGroup,
|
|
DWORD dwFlags,
|
|
LONG_PTR lParam,
|
|
BOOL fUnicodeVer)
|
|
{
|
|
UNICODE_STRING ObUnicodeStr; // locale string
|
|
WCHAR szSectionName[MAX_PATH]; // section name in inf file
|
|
WCHAR szBuffer[MAX_PATH * 4]; // buffer
|
|
WCHAR szInfPath[MAX_PATH_LEN]; // inf file
|
|
LPWSTR pStr, pEndStr; // ptr to szBuffer
|
|
DWORD LocaleValue; // locale id value
|
|
int Length; // length of string in buffer
|
|
HRESULT hr;
|
|
|
|
|
|
//
|
|
// Invalid Parameter Check:
|
|
// - function pointer is null
|
|
//
|
|
if (lpLangGroupLocaleEnumProc == NULL)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// Invalid Flags Check:
|
|
// - flags must be 0
|
|
//
|
|
if (dwFlags != 0)
|
|
{
|
|
SetLastError(ERROR_INVALID_FLAGS);
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// Get INTL.INF section name - LOCALE_LIST_#.
|
|
//
|
|
if (NlsConvertIntegerToString( LanguageGroup,
|
|
10,
|
|
1,
|
|
szBuffer,
|
|
ENUM_BUF_SIZE ) != NO_ERROR)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return (FALSE);
|
|
}
|
|
|
|
hr = StringCchCopyW(szSectionName, ARRAYSIZE(szSectionName), L"LOCALE_LIST_");
|
|
if(FAILED(hr))
|
|
{
|
|
SetLastError(HRESULT_CODE(hr));
|
|
return (FALSE);
|
|
}
|
|
|
|
hr = StringCchCatW(szSectionName, ARRAYSIZE(szSectionName), szBuffer);
|
|
if(FAILED(hr))
|
|
{
|
|
SetLastError(HRESULT_CODE(hr));
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// Get the locale list from the intl.inf file.
|
|
//
|
|
szBuffer[0] = 0;
|
|
if(0 == GetSystemWindowsDirectory(szInfPath, MAX_PATH_LEN))
|
|
{
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
return (FALSE);
|
|
}
|
|
|
|
hr = StringCchCatW(szInfPath, ARRAYSIZE(szInfPath), L"\\INF\\INTL.INF");
|
|
if(FAILED(hr))
|
|
{
|
|
SetLastError(HRESULT_CODE(hr));
|
|
return (FALSE);
|
|
}
|
|
Length = GetPrivateProfileSection( szSectionName,
|
|
szBuffer,
|
|
MAX_PATH * 4,
|
|
szInfPath );
|
|
if (Length == 0)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// Parse the buffer and call the callback function for each locale
|
|
// in the list. The buffer is double null terminated.
|
|
//
|
|
pStr = szBuffer;
|
|
pEndStr = szBuffer + Length;
|
|
while ((pStr < pEndStr) && (*pStr))
|
|
{
|
|
//
|
|
// See if the value starts with 0x or 0X. If so, go past it.
|
|
//
|
|
if ((*pStr == L'0') &&
|
|
((*(pStr + 1) == L'x') || (*(pStr + 1) == L'X')))
|
|
{
|
|
pStr += 2;
|
|
}
|
|
|
|
//
|
|
// Convert the string to an integer.
|
|
//
|
|
RtlInitUnicodeString(&ObUnicodeStr, pStr);
|
|
if (RtlUnicodeStringToInteger(&ObUnicodeStr, 16, &LocaleValue) != NO_ERROR)
|
|
{
|
|
KdPrint(("NLSAPI: Language Group Locale Enumeration Error - intl.inf corrupt.\n"));
|
|
SetLastError(ERROR_BADDB);
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// Call the appropriate callback function.
|
|
//
|
|
NLS_CALL_ENUMPROC_BREAK_2( gSystemLocale,
|
|
lpLangGroupLocaleEnumProc,
|
|
dwFlags,
|
|
LanguageGroup,
|
|
LocaleValue,
|
|
pStr,
|
|
lParam,
|
|
fUnicodeVer );
|
|
|
|
//
|
|
// Increment the pointer to the next string.
|
|
//
|
|
while (*pStr)
|
|
{
|
|
pStr++;
|
|
}
|
|
pStr++;
|
|
}
|
|
|
|
//
|
|
// Return success.
|
|
//
|
|
return (TRUE);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Internal_EnumUILanguages
|
|
//
|
|
// Enumerates the system UI languages that are installed. It does so by
|
|
// passing the pointer to the string buffer containing the UI language id
|
|
// to an application-defined callback function. It continues until the
|
|
// last UI language id is found or the callback function returns FALSE.
|
|
//
|
|
// 03-10-98 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL Internal_EnumUILanguages(
|
|
NLS_ENUMPROC lpUILanguageEnumProc,
|
|
DWORD dwFlags,
|
|
LONG_PTR lParam,
|
|
BOOL fUnicodeVer)
|
|
{
|
|
PKEY_VALUE_FULL_INFORMATION pKeyValueFull = NULL;
|
|
BYTE pStatic[MAX_KEY_VALUE_FULLINFO];
|
|
|
|
LANGID LangID; // language id
|
|
WCHAR szLang[MAX_PATH]; // language id string
|
|
HANDLE hKey = NULL; // handle to muilang key
|
|
ULONG Index; // index for enumeration
|
|
ULONG ResultLength; // # bytes written
|
|
WCHAR wch; // first char of name
|
|
LPWSTR pName; // ptr to name string from registry
|
|
ULONG NameLen; // length of name string
|
|
ULONG rc = 0L; // return code
|
|
|
|
|
|
//
|
|
// Invalid Parameter Check:
|
|
// - function pointer is null
|
|
//
|
|
if (lpUILanguageEnumProc == NULL)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// Invalid Flags Check:
|
|
// - flags must be 0
|
|
//
|
|
if (dwFlags != 0)
|
|
{
|
|
SetLastError(ERROR_INVALID_FLAGS);
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// Call the appropriate callback function with the user's UI
|
|
// language.
|
|
//
|
|
LangID = GetSystemDefaultUILanguage();
|
|
if (NlsConvertIntegerToString(LangID, 16, 4, szLang, MAX_PATH) == NO_ERROR)
|
|
{
|
|
NLS_CALL_ENUMPROC_TRUE_4( gSystemLocale,
|
|
lpUILanguageEnumProc,
|
|
dwFlags,
|
|
szLang,
|
|
lParam,
|
|
fUnicodeVer);
|
|
}
|
|
else
|
|
{
|
|
szLang[0] = 0;
|
|
}
|
|
|
|
//
|
|
// Open the MUILanguages registry key. It is acceptable if the key
|
|
// does not exist, so return TRUE as there are no items to enumerate.
|
|
//
|
|
OPEN_MUILANG_KEY(hKey, TRUE);
|
|
|
|
//
|
|
// Loop through the MUILanguage ids in the registry, call the
|
|
// function pointer for each.
|
|
//
|
|
// End loop if either FALSE is returned from the callback function
|
|
// or the end of the list is reached.
|
|
//
|
|
Index = 0;
|
|
pKeyValueFull = (PKEY_VALUE_FULL_INFORMATION)pStatic;
|
|
RtlZeroMemory(pKeyValueFull, MAX_KEY_VALUE_FULLINFO);
|
|
rc = NtEnumerateValueKey( hKey,
|
|
Index,
|
|
KeyValueFullInformation,
|
|
pKeyValueFull,
|
|
MAX_KEY_VALUE_FULLINFO,
|
|
&ResultLength );
|
|
|
|
while (rc != STATUS_NO_MORE_ENTRIES)
|
|
{
|
|
if (!NT_SUCCESS(rc))
|
|
{
|
|
//
|
|
// If we get a different error, then the registry
|
|
// is corrupt. Just return FALSE.
|
|
//
|
|
KdPrint(("NLSAPI: MUI Languages Enumeration Error - registry corrupt. - %lx.\n",
|
|
rc));
|
|
SetLastError(ERROR_BADDB);
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// Skip over any entry that does not have data associated with it.
|
|
//
|
|
pName = pKeyValueFull->Name;
|
|
wch = *pName;
|
|
NameLen = pKeyValueFull->NameLength / sizeof(WCHAR);
|
|
if ( (NameLen == ENUM_MAX_UILANG_SIZE) &&
|
|
(((wch >= NLS_CHAR_ZERO) && (wch <= NLS_CHAR_NINE)) ||
|
|
(((wch | 0x0020) >= L'a') && ((wch | 0x0020) <= L'f'))) &&
|
|
(pKeyValueFull->DataLength > 2) )
|
|
{
|
|
//
|
|
// Make sure the UI language is zero terminated.
|
|
//
|
|
pName[NameLen] = 0;
|
|
|
|
//
|
|
// Make sure it's not the same as the user UI language
|
|
// that we already enumerated.
|
|
//
|
|
if (lstrcmp(szLang, pName) != 0)
|
|
{
|
|
//
|
|
// Call the appropriate callback function.
|
|
//
|
|
NLS_CALL_ENUMPROC_BREAK_4( gSystemLocale,
|
|
lpUILanguageEnumProc,
|
|
dwFlags,
|
|
pName,
|
|
lParam,
|
|
fUnicodeVer );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Increment enumeration index value and get the next enumeration.
|
|
//
|
|
Index++;
|
|
RtlZeroMemory(pKeyValueFull, MAX_KEY_VALUE_FULLINFO);
|
|
rc = NtEnumerateValueKey( hKey,
|
|
Index,
|
|
KeyValueFullInformation,
|
|
pKeyValueFull,
|
|
MAX_KEY_VALUE_FULLINFO,
|
|
&ResultLength );
|
|
}
|
|
|
|
//
|
|
// Close the registry key.
|
|
//
|
|
CLOSE_REG_KEY(hKey);
|
|
|
|
//
|
|
// Return success.
|
|
//
|
|
return (TRUE);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Internal_EnumSystemLocales
|
|
//
|
|
// Enumerates the system locales that are installed or supported, based on
|
|
// the dwFlags parameter. It does so by passing the pointer to the string
|
|
// buffer containing the locale id to an application-defined callback
|
|
// function. It continues until the last locale id is found or the
|
|
// callback function returns FALSE.
|
|
//
|
|
// 08-02-93 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL Internal_EnumSystemLocales(
|
|
NLS_ENUMPROC lpLocaleEnumProc,
|
|
DWORD dwFlags,
|
|
BOOL fUnicodeVer)
|
|
{
|
|
PKEY_VALUE_FULL_INFORMATION pKeyValueFull1 = NULL;
|
|
PKEY_VALUE_FULL_INFORMATION pKeyValueFull2 = NULL;
|
|
BYTE pStatic1[MAX_KEY_VALUE_FULLINFO];
|
|
BYTE pStatic2[MAX_KEY_VALUE_FULLINFO];
|
|
|
|
BOOL fInstalled; // if installed flag set
|
|
ULONG Index; // index for enumeration
|
|
ULONG ResultLength; // # bytes written
|
|
WCHAR wch; // first char of name
|
|
WCHAR pBuffer[ENUM_BUF_SIZE]; // ptr to callback string buffer
|
|
LPWSTR pName; // ptr to name string from registry
|
|
LPWSTR pData; // ptr to data string from registry
|
|
UNICODE_STRING ObUnicodeStr; // registry data value string
|
|
DWORD Data; // registry data value
|
|
HKEY hKey; // handle to registry key
|
|
int Ctr; // loop counter
|
|
ULONG rc = 0L; // return code
|
|
|
|
|
|
//
|
|
// Invalid Parameter Check:
|
|
// - function pointer is null
|
|
//
|
|
if (lpLocaleEnumProc == NULL)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// Invalid Flags Check:
|
|
// - flags other than valid ones
|
|
// - more than one of either supported or installed
|
|
//
|
|
if ( (dwFlags & ESL_INVALID_FLAG) ||
|
|
(MORE_THAN_ONE(dwFlags, ESL_SINGLE_FLAG)) )
|
|
{
|
|
SetLastError(ERROR_INVALID_FLAGS);
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// Initialize flag option.
|
|
//
|
|
fInstalled = dwFlags & LCID_INSTALLED;
|
|
|
|
//
|
|
// Initialize key handles.
|
|
//
|
|
OPEN_LOCALE_KEY(FALSE);
|
|
OPEN_ALT_SORTS_KEY(FALSE);
|
|
OPEN_LANG_GROUPS_KEY(FALSE);
|
|
|
|
//
|
|
// Initialize the variables for the loop.
|
|
//
|
|
Ctr = 0;
|
|
if (dwFlags & LCID_ALTERNATE_SORTS)
|
|
{
|
|
Ctr++;
|
|
hKey = hAltSortsKey;
|
|
}
|
|
if (dwFlags != LCID_ALTERNATE_SORTS)
|
|
{
|
|
Ctr++;
|
|
hKey = hLocaleKey;
|
|
}
|
|
|
|
//
|
|
// Loop through the locale ids and/or the alternate sort ids.
|
|
//
|
|
for (; Ctr > 0; Ctr--)
|
|
{
|
|
//
|
|
// Loop through the locale ids in the registry, call the function
|
|
// pointer for each one that meets the flag criteria.
|
|
//
|
|
// End loop if either FALSE is returned from the callback function
|
|
// or the end of the list is reached.
|
|
//
|
|
// Always need to ignore the DEFAULT entry.
|
|
//
|
|
Index = 0;
|
|
pKeyValueFull1 = (PKEY_VALUE_FULL_INFORMATION)pStatic1;
|
|
pKeyValueFull2 = (PKEY_VALUE_FULL_INFORMATION)pStatic2;
|
|
RtlZeroMemory(pKeyValueFull1, MAX_KEY_VALUE_FULLINFO);
|
|
rc = NtEnumerateValueKey( hKey,
|
|
Index,
|
|
KeyValueFullInformation,
|
|
pKeyValueFull1,
|
|
MAX_KEY_VALUE_FULLINFO,
|
|
&ResultLength );
|
|
|
|
while (rc != STATUS_NO_MORE_ENTRIES)
|
|
{
|
|
if (!NT_SUCCESS(rc))
|
|
{
|
|
//
|
|
// If we get a different error, then the registry
|
|
// is corrupt. Just return FALSE.
|
|
//
|
|
KdPrint(("NLSAPI: LCID Enumeration Error - registry corrupt. - %lx.\n",
|
|
rc));
|
|
SetLastError(ERROR_BADDB);
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// Skip over the Default entry in the registry and any
|
|
// entry that does not have data associated with it if the
|
|
// LCID_INSTALLED flag is set.
|
|
//
|
|
pName = pKeyValueFull1->Name;
|
|
wch = *pName;
|
|
if ((pKeyValueFull1->NameLength == (ENUM_LOCALE_SIZE * sizeof(WCHAR))) &&
|
|
(((wch >= NLS_CHAR_ZERO) && (wch <= NLS_CHAR_NINE)) ||
|
|
(((wch | 0x0020) >= L'a') && ((wch | 0x0020) <= L'f'))))
|
|
{
|
|
//
|
|
// If the installed flag is set, then do some extra
|
|
// validation before calling the function proc.
|
|
//
|
|
if (fInstalled)
|
|
{
|
|
if (pKeyValueFull1->DataLength <= 2)
|
|
{
|
|
goto EnumNextLocale;
|
|
}
|
|
|
|
RtlInitUnicodeString( &ObUnicodeStr,
|
|
GET_VALUE_DATA_PTR(pKeyValueFull1) );
|
|
|
|
if ((RtlUnicodeStringToInteger(&ObUnicodeStr, 16, &Data)) ||
|
|
(Data == 0) ||
|
|
(QueryRegValue( hLangGroupsKey,
|
|
ObUnicodeStr.Buffer,
|
|
&pKeyValueFull2,
|
|
MAX_KEY_VALUE_FULLINFO,
|
|
NULL ) != NO_ERROR) ||
|
|
(pKeyValueFull2->DataLength <= 2))
|
|
{
|
|
goto EnumNextLocale;
|
|
}
|
|
pData = GET_VALUE_DATA_PTR(pKeyValueFull2);
|
|
if ((pData[0] != L'1') || (pData[1] != 0))
|
|
{
|
|
goto EnumNextLocale;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Store the locale id in the callback buffer.
|
|
//
|
|
*(pBuffer) = *pName;
|
|
*(pBuffer + 1) = *(pName + 1);
|
|
*(pBuffer + 2) = *(pName + 2);
|
|
*(pBuffer + 3) = *(pName + 3);
|
|
*(pBuffer + 4) = *(pName + 4);
|
|
*(pBuffer + 5) = *(pName + 5);
|
|
*(pBuffer + 6) = *(pName + 6);
|
|
*(pBuffer + 7) = *(pName + 7);
|
|
|
|
*(pBuffer + 8) = 0;
|
|
|
|
//
|
|
// Call the appropriate callback function.
|
|
//
|
|
NLS_CALL_ENUMPROC_BREAK( gSystemLocale,
|
|
lpLocaleEnumProc,
|
|
dwFlags,
|
|
pBuffer,
|
|
fUnicodeVer );
|
|
}
|
|
|
|
EnumNextLocale:
|
|
//
|
|
// Increment enumeration index value and get the next enumeration.
|
|
//
|
|
Index++;
|
|
RtlZeroMemory(pKeyValueFull1, MAX_KEY_VALUE_FULLINFO);
|
|
rc = NtEnumerateValueKey( hKey,
|
|
Index,
|
|
KeyValueFullInformation,
|
|
pKeyValueFull1,
|
|
MAX_KEY_VALUE_FULLINFO,
|
|
&ResultLength );
|
|
}
|
|
|
|
//
|
|
// The counter can be either 1 or 2 at this point. If it's 2, then
|
|
// we've just done the Locale key and we need to do the alternate
|
|
// sorts key. If it's 1, then it doesn't matter what this is set to
|
|
// since we're done with the loop.
|
|
//
|
|
hKey = hAltSortsKey;
|
|
}
|
|
|
|
//
|
|
// Return success.
|
|
//
|
|
return (TRUE);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Internal_EnumSystemCodePages
|
|
//
|
|
// Enumerates the system code pages that are installed or supported, based
|
|
// on the dwFlags parameter. It does so by passing the pointer to the
|
|
// string buffer containing the code page id to an application-defined
|
|
// callback function. It continues until the last code page is found or
|
|
// the callback function returns FALSE.
|
|
//
|
|
// 08-02-93 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL Internal_EnumSystemCodePages(
|
|
NLS_ENUMPROC lpCodePageEnumProc,
|
|
DWORD dwFlags,
|
|
BOOL fUnicodeVer)
|
|
{
|
|
PKEY_VALUE_FULL_INFORMATION pKeyValueFull = NULL;
|
|
BYTE pStatic[MAX_KEY_VALUE_FULLINFO];
|
|
|
|
BOOL fInstalled; // if installed flag set
|
|
ULONG Index = 0; // index for enumeration
|
|
ULONG ResultLength; // # bytes written
|
|
WCHAR wch; // first char of name
|
|
LPWSTR pName; // ptr to name string from registry
|
|
ULONG NameLen; // length of name string
|
|
ULONG rc = 0L; // return code
|
|
|
|
|
|
//
|
|
// Invalid Parameter Check:
|
|
// - function pointer is null
|
|
//
|
|
if (lpCodePageEnumProc == NULL)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// Invalid Flags Check:
|
|
// - flags other than valid ones
|
|
// - more than one of either supported or installed
|
|
//
|
|
if ( (dwFlags & ESCP_INVALID_FLAG) ||
|
|
(MORE_THAN_ONE(dwFlags, ESCP_SINGLE_FLAG)) )
|
|
{
|
|
SetLastError(ERROR_INVALID_FLAGS);
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// Initialize flag option.
|
|
//
|
|
fInstalled = dwFlags & CP_INSTALLED;
|
|
|
|
//
|
|
// Loop through the code page ids in the registry, call the function
|
|
// pointer for each one that meets the flag criteria.
|
|
//
|
|
// End loop if either FALSE is returned from the callback function
|
|
// or the end of the list is reached.
|
|
//
|
|
// Always need to ignore the ACP, OEMCP, MACCP, and OEMHAL entries.
|
|
//
|
|
OPEN_CODEPAGE_KEY(FALSE);
|
|
|
|
pKeyValueFull = (PKEY_VALUE_FULL_INFORMATION)pStatic;
|
|
RtlZeroMemory(pKeyValueFull, MAX_KEY_VALUE_FULLINFO);
|
|
rc = NtEnumerateValueKey( hCodePageKey,
|
|
Index,
|
|
KeyValueFullInformation,
|
|
pKeyValueFull,
|
|
MAX_KEY_VALUE_FULLINFO,
|
|
&ResultLength );
|
|
|
|
while (rc != STATUS_NO_MORE_ENTRIES)
|
|
{
|
|
if (!NT_SUCCESS(rc))
|
|
{
|
|
//
|
|
// If we get a different error, then the registry
|
|
// is corrupt. Just return FALSE.
|
|
//
|
|
KdPrint(("NLSAPI: CP Enumeration Error - registry corrupt. - %lx.\n",
|
|
rc));
|
|
SetLastError(ERROR_BADDB);
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// Skip over the ACP, OEMCP, MACCP, and OEMHAL entries in the
|
|
// registry, and any entry that does not have data associated
|
|
// with it if the CP_INSTALLED flag is set.
|
|
//
|
|
pName = pKeyValueFull->Name;
|
|
wch = *pName;
|
|
NameLen = pKeyValueFull->NameLength / sizeof(WCHAR);
|
|
if ( (NameLen <= ENUM_MAX_CP_SIZE) &&
|
|
(wch >= NLS_CHAR_ZERO) && (wch <= NLS_CHAR_NINE) &&
|
|
(!((fInstalled) && (pKeyValueFull->DataLength <= 2))) )
|
|
{
|
|
//
|
|
// Store the code page id string in the callback buffer.
|
|
//
|
|
pName[NameLen] = 0;
|
|
|
|
//
|
|
// Call the appropriate callback function.
|
|
//
|
|
NLS_CALL_ENUMPROC_TRUE( gSystemLocale,
|
|
lpCodePageEnumProc,
|
|
dwFlags,
|
|
pName,
|
|
0,
|
|
fUnicodeVer,
|
|
0 );
|
|
}
|
|
|
|
//
|
|
// Increment enumeration index value and get the next enumeration.
|
|
//
|
|
Index++;
|
|
RtlZeroMemory(pKeyValueFull, MAX_KEY_VALUE_FULLINFO);
|
|
rc = NtEnumerateValueKey( hCodePageKey,
|
|
Index,
|
|
KeyValueFullInformation,
|
|
pKeyValueFull,
|
|
MAX_KEY_VALUE_FULLINFO,
|
|
&ResultLength );
|
|
}
|
|
|
|
//
|
|
// Include UTF-7 and UTF-8 code pages in the enumeration -
|
|
// both installed and supported.
|
|
//
|
|
NLS_CALL_ENUMPROC_TRUE( gSystemLocale,
|
|
lpCodePageEnumProc,
|
|
dwFlags,
|
|
L"65000",
|
|
0,
|
|
fUnicodeVer,
|
|
0 );
|
|
NLS_CALL_ENUMPROC_TRUE( gSystemLocale,
|
|
lpCodePageEnumProc,
|
|
dwFlags,
|
|
L"65001",
|
|
0,
|
|
fUnicodeVer,
|
|
0 );
|
|
|
|
//
|
|
// Return success.
|
|
//
|
|
return (TRUE);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Internal_EnumCalendarInfo
|
|
//
|
|
// Enumerates the specified calendar information that is available for the
|
|
// specified locale, based on the CalType parameter. It does so by
|
|
// passing the pointer to the string buffer containing the calendar info
|
|
// to an application-defined callback function. It continues until the
|
|
// last calendar info is found or the callback function returns FALSE.
|
|
//
|
|
// 10-14-93 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL Internal_EnumCalendarInfo(
|
|
NLS_ENUMPROC lpCalInfoEnumProc,
|
|
LCID Locale,
|
|
CALID Calendar,
|
|
CALTYPE CalType,
|
|
BOOL fUnicodeVer,
|
|
BOOL fExVersion)
|
|
{
|
|
PLOC_HASH pHashN; // ptr to LOC hash node
|
|
ULONG CalFieldOffset; // field offset in calendar structure
|
|
ULONG EndCalFieldOffset; // field offset in calendar structure
|
|
ULONG LocFieldOffset; // field offset in locale structure
|
|
ULONG EndLocFieldOffset; // field offset in locale structure
|
|
LPWSTR pOptCal; // ptr to optional calendar values
|
|
LPWSTR pEndOptCal; // ptr to end of optional calendars
|
|
PCAL_INFO pCalInfo; // ptr to calendar info
|
|
BOOL fIfName = FALSE; // if caltype is a name
|
|
UINT fEra = 0; // if era caltype
|
|
BOOL fLocaleInfo = TRUE; // if locale information
|
|
LPWSTR pString; // ptr to enumeration string
|
|
LPWSTR pEndString; // ptr to end of enumeration string
|
|
CALID CalNum; // calendar number
|
|
DWORD UseCPACP; // original caltype - if use system ACP
|
|
WCHAR pTemp[MAX_REG_VAL_SIZE];// temp buffer to hold two-digit-year-max
|
|
|
|
|
|
//
|
|
// Invalid Parameter Check:
|
|
// - validate LCID
|
|
// - function pointer is null
|
|
//
|
|
// - CalType will be checked in switch statement below.
|
|
//
|
|
VALIDATE_LOCALE(Locale, pHashN, FALSE);
|
|
if ((pHashN == NULL) || (lpCalInfoEnumProc == NULL))
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// Initialize the pointers to the optional calendar data.
|
|
//
|
|
if (Calendar == ENUM_ALL_CALENDARS)
|
|
{
|
|
pOptCal = (LPWORD)(pHashN->pLocaleHdr) + pHashN->pLocaleHdr->IOptionalCal;
|
|
pEndOptCal = (LPWORD)(pHashN->pLocaleHdr) + pHashN->pLocaleHdr->SDayName1;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Validate the Calendar parameter.
|
|
//
|
|
if ((pOptCal = IsValidCalendarType(pHashN, Calendar)) == NULL)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return (FALSE);
|
|
}
|
|
pEndOptCal = pOptCal + ((POPT_CAL)pOptCal)->Offset;
|
|
}
|
|
|
|
//
|
|
// Enumerate the information based on CalType.
|
|
//
|
|
UseCPACP = (DWORD)CalType;
|
|
CalType = NLS_GET_CALTYPE_VALUE(CalType);
|
|
switch (CalType)
|
|
{
|
|
case ( CAL_ICALINTVALUE ) :
|
|
{
|
|
//
|
|
// Get the integer value for each of the alternate
|
|
// calendars (as a string).
|
|
//
|
|
while (pOptCal < pEndOptCal)
|
|
{
|
|
if (((POPT_CAL)pOptCal)->CalId != CAL_NO_OPTIONAL)
|
|
{
|
|
//
|
|
// Call the appropriate callback function.
|
|
//
|
|
NLS_CALL_ENUMPROC_TRUE( Locale,
|
|
lpCalInfoEnumProc,
|
|
UseCPACP,
|
|
((POPT_CAL)pOptCal)->pCalStr,
|
|
((POPT_CAL)pOptCal)->CalId,
|
|
fUnicodeVer,
|
|
fExVersion );
|
|
}
|
|
|
|
//
|
|
// Advance ptr to next optional calendar.
|
|
//
|
|
pOptCal += ((POPT_CAL)pOptCal)->Offset;
|
|
}
|
|
|
|
return (TRUE);
|
|
|
|
break;
|
|
}
|
|
case ( CAL_SCALNAME ) :
|
|
{
|
|
//
|
|
// Get the calendar name for each of the alternate
|
|
// calendars.
|
|
//
|
|
while (pOptCal < pEndOptCal)
|
|
{
|
|
if (((POPT_CAL)pOptCal)->CalId != CAL_NO_OPTIONAL)
|
|
{
|
|
//
|
|
// Call the appropriate callback function.
|
|
//
|
|
NLS_CALL_ENUMPROC_TRUE(
|
|
Locale,
|
|
lpCalInfoEnumProc,
|
|
UseCPACP,
|
|
((POPT_CAL)pOptCal)->pCalStr +
|
|
NlsStrLenW(((POPT_CAL)pOptCal)->pCalStr) + 1,
|
|
((POPT_CAL)pOptCal)->CalId,
|
|
fUnicodeVer,
|
|
fExVersion );
|
|
}
|
|
|
|
//
|
|
// Advance ptr to next optional calendar.
|
|
//
|
|
pOptCal += ((POPT_CAL)pOptCal)->Offset;
|
|
}
|
|
|
|
return (TRUE);
|
|
|
|
break;
|
|
}
|
|
case ( CAL_ITWODIGITYEARMAX ) :
|
|
{
|
|
fLocaleInfo = FALSE;
|
|
CalFieldOffset = FIELD_OFFSET(CALENDAR_VAR, STwoDigitYearMax);
|
|
EndCalFieldOffset = FIELD_OFFSET(CALENDAR_VAR, SEraRanges);
|
|
|
|
if (!(UseCPACP & CAL_NOUSEROVERRIDE))
|
|
{
|
|
while (pOptCal < pEndOptCal)
|
|
{
|
|
CalNum = ((POPT_CAL)pOptCal)->CalId;
|
|
|
|
if (CalNum != CAL_NO_OPTIONAL)
|
|
{
|
|
//
|
|
// Look into the registry first
|
|
//
|
|
if (GetTwoDigitYearInfo(CalNum, pTemp, ARRAYSIZE(pTemp), NLS_POLICY_TWO_DIGIT_YEAR_KEY) ||
|
|
GetTwoDigitYearInfo(CalNum, pTemp, ARRAYSIZE(pTemp), NLS_TWO_DIGIT_YEAR_KEY))
|
|
{
|
|
NLS_CALL_ENUMPROC_TRUE(
|
|
Locale,
|
|
lpCalInfoEnumProc,
|
|
UseCPACP,
|
|
pTemp,
|
|
CalNum,
|
|
fUnicodeVer,
|
|
fExVersion );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Try to find the system default if we couldn't find the
|
|
// user setting in the registry or the user has asked for
|
|
// system default.
|
|
//
|
|
if (GetCalendar(CalNum, &pCalInfo) == NO_ERROR)
|
|
{
|
|
pString = (LPWORD)pCalInfo +
|
|
*((LPWORD)((LPBYTE)(pCalInfo) + CalFieldOffset));
|
|
pEndString = (LPWORD)pCalInfo +
|
|
*((LPWORD)((LPBYTE)(pCalInfo) + EndCalFieldOffset));
|
|
|
|
if (*pString)
|
|
{
|
|
while (pString < pEndString)
|
|
{
|
|
//
|
|
// Make sure the string is NOT empty.
|
|
//
|
|
if (*pString)
|
|
{
|
|
//
|
|
// Call the appropriate callback function.
|
|
//
|
|
NLS_CALL_ENUMPROC_TRUE(
|
|
Locale,
|
|
lpCalInfoEnumProc,
|
|
UseCPACP,
|
|
pString,
|
|
CalNum,
|
|
fUnicodeVer,
|
|
fExVersion );
|
|
}
|
|
|
|
//
|
|
// Advance pointer to next string.
|
|
//
|
|
pString += NlsStrLenW(pString) + 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Advance ptr to next optional calendar.
|
|
//
|
|
pOptCal += ((POPT_CAL)pOptCal)->Offset;
|
|
}
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
break;
|
|
}
|
|
case ( CAL_IYEAROFFSETRANGE ) :
|
|
case ( CAL_SERASTRING ) :
|
|
{
|
|
fEra = CalType;
|
|
CalFieldOffset = FIELD_OFFSET(CALENDAR_VAR, SEraRanges);
|
|
EndCalFieldOffset = FIELD_OFFSET(CALENDAR_VAR, SShortDate);
|
|
|
|
break;
|
|
}
|
|
case ( CAL_SSHORTDATE ) :
|
|
{
|
|
CalFieldOffset = FIELD_OFFSET(CALENDAR_VAR, SShortDate);
|
|
EndCalFieldOffset = FIELD_OFFSET(CALENDAR_VAR, SYearMonth);
|
|
LocFieldOffset = FIELD_OFFSET(LOCALE_VAR, SShortDate);
|
|
EndLocFieldOffset = FIELD_OFFSET(LOCALE_VAR, SDate);
|
|
|
|
break;
|
|
}
|
|
case ( CAL_SLONGDATE ) :
|
|
{
|
|
CalFieldOffset = FIELD_OFFSET(CALENDAR_VAR, SLongDate);
|
|
EndCalFieldOffset = FIELD_OFFSET(CALENDAR_VAR, SDayName1);
|
|
LocFieldOffset = FIELD_OFFSET(LOCALE_VAR, SLongDate);
|
|
EndLocFieldOffset = FIELD_OFFSET(LOCALE_VAR, IOptionalCal);
|
|
|
|
break;
|
|
}
|
|
case ( CAL_SYEARMONTH ) :
|
|
{
|
|
CalFieldOffset = FIELD_OFFSET(CALENDAR_VAR, SYearMonth);
|
|
EndCalFieldOffset = FIELD_OFFSET(CALENDAR_VAR, SLongDate);
|
|
LocFieldOffset = FIELD_OFFSET(LOCALE_VAR, SYearMonth);
|
|
EndLocFieldOffset = FIELD_OFFSET(LOCALE_VAR, SLongDate);
|
|
|
|
break;
|
|
}
|
|
case ( CAL_SDAYNAME1 ) :
|
|
case ( CAL_SDAYNAME2 ) :
|
|
case ( CAL_SDAYNAME3 ) :
|
|
case ( CAL_SDAYNAME4 ) :
|
|
case ( CAL_SDAYNAME5 ) :
|
|
case ( CAL_SDAYNAME6 ) :
|
|
case ( CAL_SDAYNAME7 ) :
|
|
case ( CAL_SABBREVDAYNAME1 ) :
|
|
case ( CAL_SABBREVDAYNAME2 ) :
|
|
case ( CAL_SABBREVDAYNAME3 ) :
|
|
case ( CAL_SABBREVDAYNAME4 ) :
|
|
case ( CAL_SABBREVDAYNAME5 ) :
|
|
case ( CAL_SABBREVDAYNAME6 ) :
|
|
case ( CAL_SABBREVDAYNAME7 ) :
|
|
case ( CAL_SMONTHNAME1 ) :
|
|
case ( CAL_SMONTHNAME2 ) :
|
|
case ( CAL_SMONTHNAME3 ) :
|
|
case ( CAL_SMONTHNAME4 ) :
|
|
case ( CAL_SMONTHNAME5 ) :
|
|
case ( CAL_SMONTHNAME6 ) :
|
|
case ( CAL_SMONTHNAME7 ) :
|
|
case ( CAL_SMONTHNAME8 ) :
|
|
case ( CAL_SMONTHNAME9 ) :
|
|
case ( CAL_SMONTHNAME10 ) :
|
|
case ( CAL_SMONTHNAME11 ) :
|
|
case ( CAL_SMONTHNAME12 ) :
|
|
case ( CAL_SMONTHNAME13 ) :
|
|
case ( CAL_SABBREVMONTHNAME1 ) :
|
|
case ( CAL_SABBREVMONTHNAME2 ) :
|
|
case ( CAL_SABBREVMONTHNAME3 ) :
|
|
case ( CAL_SABBREVMONTHNAME4 ) :
|
|
case ( CAL_SABBREVMONTHNAME5 ) :
|
|
case ( CAL_SABBREVMONTHNAME6 ) :
|
|
case ( CAL_SABBREVMONTHNAME7 ) :
|
|
case ( CAL_SABBREVMONTHNAME8 ) :
|
|
case ( CAL_SABBREVMONTHNAME9 ) :
|
|
case ( CAL_SABBREVMONTHNAME10 ) :
|
|
case ( CAL_SABBREVMONTHNAME11 ) :
|
|
case ( CAL_SABBREVMONTHNAME12 ) :
|
|
case ( CAL_SABBREVMONTHNAME13 ) :
|
|
{
|
|
fIfName = TRUE;
|
|
CalFieldOffset = FIELD_OFFSET(CALENDAR_VAR, SDayName1) +
|
|
((CalType - CAL_SDAYNAME1) * sizeof(WORD));
|
|
EndCalFieldOffset = FIELD_OFFSET(CALENDAR_VAR, SDayName1) +
|
|
((CalType - CAL_SDAYNAME1 + 1) * sizeof(WORD));
|
|
LocFieldOffset = FIELD_OFFSET(LOCALE_VAR, SDayName1) +
|
|
((CalType - CAL_SDAYNAME1) * sizeof(WORD));
|
|
EndLocFieldOffset = FIELD_OFFSET(LOCALE_VAR, SDayName1) +
|
|
((CalType - CAL_SDAYNAME1 + 1) * sizeof(WORD));
|
|
|
|
break;
|
|
}
|
|
default :
|
|
{
|
|
SetLastError(ERROR_INVALID_FLAGS);
|
|
return (FALSE);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get the requested information for each of the alternate calendars.
|
|
//
|
|
// This loop is used for the following CalTypes:
|
|
//
|
|
// iYearOffsetRange (fEra = TRUE)
|
|
// sEraString (fEra = TRUE)
|
|
//
|
|
// sShortDate
|
|
// sLongDate
|
|
// sYearMonth
|
|
//
|
|
// sDayName1-7 (fIfName = TRUE)
|
|
// sAbbrevDayName1-7 (fIfName = TRUE)
|
|
// sMonthName1-7 (fIfName = TRUE)
|
|
// sAbbrevMonthName1-7 (fIfName = TRUE)
|
|
//
|
|
while (pOptCal < pEndOptCal)
|
|
{
|
|
//
|
|
// Get the pointer to the appropriate calendar.
|
|
//
|
|
CalNum = ((POPT_CAL)pOptCal)->CalId;
|
|
if (GetCalendar(CalNum, &pCalInfo) == NO_ERROR)
|
|
{
|
|
//
|
|
// Check era information flag.
|
|
//
|
|
if (fEra)
|
|
{
|
|
//
|
|
// Get the pointer to the appropriate calendar string.
|
|
//
|
|
pString = (LPWORD)pCalInfo +
|
|
*((LPWORD)((LPBYTE)(pCalInfo) + CalFieldOffset));
|
|
|
|
pEndString = (LPWORD)pCalInfo +
|
|
*((LPWORD)((LPBYTE)(pCalInfo) + EndCalFieldOffset));
|
|
|
|
//
|
|
// Make sure the string is NOT empty.
|
|
//
|
|
if (*pString)
|
|
{
|
|
//
|
|
// See which era information to get.
|
|
//
|
|
if (fEra == CAL_IYEAROFFSETRANGE)
|
|
{
|
|
while (pString < pEndString)
|
|
{
|
|
//
|
|
// Call the appropriate callback function.
|
|
//
|
|
NLS_CALL_ENUMPROC_TRUE(
|
|
Locale,
|
|
lpCalInfoEnumProc,
|
|
UseCPACP,
|
|
((PERA_RANGE)pString)->pYearStr,
|
|
CalNum,
|
|
fUnicodeVer,
|
|
fExVersion );
|
|
|
|
//
|
|
// Advance pointer to next era range.
|
|
//
|
|
pString += ((PERA_RANGE)pString)->Offset;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while (pString < pEndString)
|
|
{
|
|
//
|
|
// Call the appropriate callback function.
|
|
//
|
|
NLS_CALL_ENUMPROC_TRUE(
|
|
Locale,
|
|
lpCalInfoEnumProc,
|
|
UseCPACP,
|
|
((PERA_RANGE)pString)->pYearStr +
|
|
NlsStrLenW(((PERA_RANGE)pString)->pYearStr) + 1,
|
|
CalNum,
|
|
fUnicodeVer,
|
|
fExVersion );
|
|
|
|
//
|
|
// Advance pointer to next era range.
|
|
//
|
|
pString += ((PERA_RANGE)pString)->Offset;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Get the pointer to the appropriate calendar string.
|
|
//
|
|
if ((!fIfName) ||
|
|
(((PCALENDAR_VAR)pCalInfo)->IfNames))
|
|
{
|
|
pString = (LPWORD)pCalInfo +
|
|
*((LPWORD)((LPBYTE)(pCalInfo) + CalFieldOffset));
|
|
|
|
pEndString = (LPWORD)pCalInfo +
|
|
*((LPWORD)((LPBYTE)(pCalInfo) + EndCalFieldOffset));
|
|
}
|
|
else
|
|
{
|
|
pString = L"";
|
|
}
|
|
|
|
//
|
|
// Make sure we have a string. Otherwise, use the
|
|
// information from the locale section (if appropriate).
|
|
//
|
|
if ((*pString == 0) && (fLocaleInfo) &&
|
|
((CalNum == CAL_GREGORIAN) ||
|
|
(Calendar != ENUM_ALL_CALENDARS)))
|
|
{
|
|
//
|
|
// Use the default locale string.
|
|
//
|
|
pString = (LPWORD)(pHashN->pLocaleHdr) +
|
|
*((LPWORD)((LPBYTE)(pHashN->pLocaleHdr) +
|
|
LocFieldOffset));
|
|
|
|
pEndString = (LPWORD)(pHashN->pLocaleHdr) +
|
|
*((LPWORD)((LPBYTE)(pHashN->pLocaleHdr) +
|
|
EndLocFieldOffset));
|
|
}
|
|
|
|
//
|
|
// Go through each of the strings.
|
|
//
|
|
if (*pString)
|
|
{
|
|
while (pString < pEndString)
|
|
{
|
|
//
|
|
// Make sure the string is NOT empty.
|
|
//
|
|
if (*pString)
|
|
{
|
|
//
|
|
// Call the appropriate callback function.
|
|
//
|
|
NLS_CALL_ENUMPROC_TRUE( Locale,
|
|
lpCalInfoEnumProc,
|
|
UseCPACP,
|
|
pString,
|
|
CalNum,
|
|
fUnicodeVer,
|
|
fExVersion );
|
|
}
|
|
|
|
//
|
|
// Advance pointer to next string.
|
|
//
|
|
pString += NlsStrLenW(pString) + 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Advance ptr to next optional calendar.
|
|
//
|
|
pOptCal += ((POPT_CAL)pOptCal)->Offset;
|
|
}
|
|
|
|
//
|
|
// Return success.
|
|
//
|
|
return (TRUE);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Internal_EnumTimeFormats
|
|
//
|
|
// Enumerates the time formats that are available for the
|
|
// specified locale, based on the dwFlags parameter. It does so by
|
|
// passing the pointer to the string buffer containing the time format
|
|
// to an application-defined callback function. It continues until the
|
|
// last time format is found or the callback function returns FALSE.
|
|
//
|
|
// 10-14-93 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL Internal_EnumTimeFormats(
|
|
NLS_ENUMPROC lpTimeFmtEnumProc,
|
|
LCID Locale,
|
|
DWORD dwFlags,
|
|
BOOL fUnicodeVer)
|
|
{
|
|
PLOC_HASH pHashN; // ptr to LOC hash node
|
|
|
|
|
|
//
|
|
// Invalid Parameter Check:
|
|
// - validate LCID
|
|
// - function pointer is null
|
|
//
|
|
VALIDATE_LOCALE(Locale, pHashN, FALSE);
|
|
if ((pHashN == NULL) || (lpTimeFmtEnumProc == NULL))
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// Invalid Flags Check:
|
|
// - flags other than valid ones
|
|
//
|
|
if (dwFlags & ETF_INVALID_FLAG)
|
|
{
|
|
SetLastError(ERROR_INVALID_FLAGS);
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// Enumerate the time formats.
|
|
//
|
|
return ( EnumDateTime( lpTimeFmtEnumProc,
|
|
Locale,
|
|
LOCALE_STIMEFORMAT,
|
|
dwFlags,
|
|
FIELD_OFFSET(NLS_USER_INFO, sTimeFormat),
|
|
NLS_VALUE_STIMEFORMAT,
|
|
pHashN->pLocaleHdr,
|
|
(LPWORD)(pHashN->pLocaleHdr) +
|
|
pHashN->pLocaleHdr->STimeFormat,
|
|
(LPWORD)(pHashN->pLocaleHdr) +
|
|
pHashN->pLocaleHdr->STime,
|
|
(ULONG)0,
|
|
(ULONG)0,
|
|
FALSE,
|
|
fUnicodeVer,
|
|
FALSE ) );
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Internal_EnumDateFormats
|
|
//
|
|
// Enumerates the short date, long date, or year/month formats that are
|
|
// available for the specified locale, based on the dwFlags parameter.
|
|
// It does so by passing the pointer to the string buffer containing the
|
|
// date format (and the calendar id if called from the Ex version) to an
|
|
// application-defined callback function. It continues until the last
|
|
// date format is found or the callback function returns FALSE.
|
|
//
|
|
// 10-14-93 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL Internal_EnumDateFormats(
|
|
NLS_ENUMPROC lpDateFmtEnumProc,
|
|
LCID Locale,
|
|
DWORD dwFlags,
|
|
BOOL fUnicodeVer,
|
|
BOOL fExVersion)
|
|
{
|
|
PLOC_HASH pHashN; // ptr to LOC hash node
|
|
|
|
|
|
//
|
|
// Invalid Parameter Check:
|
|
// - validate LCID
|
|
// - function pointer is null
|
|
//
|
|
// - flags will be validated in switch statement below
|
|
//
|
|
VALIDATE_LOCALE(Locale, pHashN, FALSE);
|
|
if ((pHashN == NULL) || (lpDateFmtEnumProc == NULL))
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// Enumerate the date pictures based on the flags.
|
|
//
|
|
switch (dwFlags & (~LOCALE_USE_CP_ACP))
|
|
{
|
|
case ( 0 ) :
|
|
case ( DATE_SHORTDATE ) :
|
|
{
|
|
//
|
|
// Enumerate the short date formats.
|
|
//
|
|
return ( EnumDateTime( lpDateFmtEnumProc,
|
|
Locale,
|
|
LOCALE_SSHORTDATE,
|
|
dwFlags,
|
|
FIELD_OFFSET(NLS_USER_INFO, sShortDate),
|
|
NLS_VALUE_SSHORTDATE,
|
|
pHashN->pLocaleHdr,
|
|
(LPWORD)(pHashN->pLocaleHdr) +
|
|
pHashN->pLocaleHdr->SShortDate,
|
|
(LPWORD)(pHashN->pLocaleHdr) +
|
|
pHashN->pLocaleHdr->SDate,
|
|
(ULONG)FIELD_OFFSET(CALENDAR_VAR, SShortDate),
|
|
(ULONG)FIELD_OFFSET(CALENDAR_VAR, SYearMonth),
|
|
TRUE,
|
|
fUnicodeVer,
|
|
fExVersion ) );
|
|
|
|
break;
|
|
}
|
|
|
|
case ( DATE_LONGDATE ) :
|
|
{
|
|
//
|
|
// Enumerate the long date formats.
|
|
//
|
|
return ( EnumDateTime( lpDateFmtEnumProc,
|
|
Locale,
|
|
LOCALE_SLONGDATE,
|
|
dwFlags,
|
|
FIELD_OFFSET(NLS_USER_INFO, sLongDate),
|
|
NLS_VALUE_SLONGDATE,
|
|
pHashN->pLocaleHdr,
|
|
(LPWORD)(pHashN->pLocaleHdr) +
|
|
pHashN->pLocaleHdr->SLongDate,
|
|
(LPWORD)(pHashN->pLocaleHdr) +
|
|
pHashN->pLocaleHdr->IOptionalCal,
|
|
(ULONG)FIELD_OFFSET(CALENDAR_VAR, SLongDate),
|
|
(ULONG)FIELD_OFFSET(CALENDAR_VAR, SDayName1),
|
|
TRUE,
|
|
fUnicodeVer,
|
|
fExVersion ) );
|
|
|
|
break;
|
|
}
|
|
|
|
case ( DATE_YEARMONTH ) :
|
|
{
|
|
//
|
|
// Enumerate the year month formats.
|
|
//
|
|
return ( EnumDateTime( lpDateFmtEnumProc,
|
|
Locale,
|
|
LOCALE_SYEARMONTH,
|
|
dwFlags,
|
|
FIELD_OFFSET(NLS_USER_INFO, sYearMonth),
|
|
NLS_VALUE_SYEARMONTH,
|
|
pHashN->pLocaleHdr,
|
|
(LPWORD)(pHashN->pLocaleHdr) +
|
|
pHashN->pLocaleHdr->SYearMonth,
|
|
(LPWORD)(pHashN->pLocaleHdr) +
|
|
pHashN->pLocaleHdr->SLongDate,
|
|
(ULONG)FIELD_OFFSET(CALENDAR_VAR, SYearMonth),
|
|
(ULONG)FIELD_OFFSET(CALENDAR_VAR, SLongDate),
|
|
TRUE,
|
|
fUnicodeVer,
|
|
fExVersion ) );
|
|
|
|
break;
|
|
}
|
|
|
|
default :
|
|
{
|
|
SetLastError(ERROR_INVALID_FLAGS);
|
|
return (FALSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------//
|
|
// INTERNAL ROUTINES //
|
|
//-------------------------------------------------------------------------//
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// EnumDateTime
|
|
//
|
|
// Enumerates the short date, long date, year/month, or time formats that
|
|
// are available for the specified locale. This is the worker routine for
|
|
// the EnumTimeFormats and EnumDateFormats apis.
|
|
//
|
|
// 10-14-93 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL EnumDateTime(
|
|
NLS_ENUMPROC lpDateTimeFmtEnumProc,
|
|
LCID Locale,
|
|
LCTYPE LCType,
|
|
DWORD dwFlags,
|
|
SIZE_T CacheOffset,
|
|
LPWSTR pRegValue,
|
|
PLOCALE_VAR pLocaleHdr,
|
|
LPWSTR pDateTime,
|
|
LPWSTR pEndDateTime,
|
|
ULONG CalDateOffset,
|
|
ULONG EndCalDateOffset,
|
|
BOOL fCalendarInfo,
|
|
BOOL fUnicodeVer,
|
|
BOOL fExVersion)
|
|
{
|
|
LPWSTR pUser = NULL; // ptr to user date/time string
|
|
LPWSTR pOptCal; // ptr to optional calendar values
|
|
LPWSTR pEndOptCal; // ptr to end of optional calendars
|
|
PCAL_INFO pCalInfo; // ptr to calendar info
|
|
CALID CalNum = 1; // calendar number
|
|
WCHAR pTemp[MAX_REG_VAL_SIZE]; // temp buffer
|
|
UNICODE_STRING ObUnicodeStr; // calendar id string
|
|
|
|
|
|
//
|
|
// Get the user's Calendar ID.
|
|
//
|
|
if (fExVersion)
|
|
{
|
|
if (GetUserInfo( Locale,
|
|
LOCALE_ICALENDARTYPE,
|
|
FIELD_OFFSET(NLS_USER_INFO, iCalType),
|
|
NLS_VALUE_ICALENDARTYPE,
|
|
pTemp,
|
|
ARRAYSIZE(pTemp),
|
|
TRUE ))
|
|
{
|
|
RtlInitUnicodeString(&ObUnicodeStr, pTemp);
|
|
if ((RtlUnicodeStringToInteger(&ObUnicodeStr, 10, &CalNum)) ||
|
|
(CalNum < 1) || (CalNum > CAL_LAST))
|
|
{
|
|
CalNum = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get the user defined string.
|
|
//
|
|
if (GetUserInfo( Locale,
|
|
LCType,
|
|
CacheOffset,
|
|
pRegValue,
|
|
pTemp,
|
|
ARRAYSIZE(pTemp),
|
|
TRUE ))
|
|
{
|
|
pUser = pTemp;
|
|
|
|
//
|
|
// Call the appropriate callback function.
|
|
//
|
|
NLS_CALL_ENUMPROC_TRUE( Locale,
|
|
lpDateTimeFmtEnumProc,
|
|
dwFlags,
|
|
pUser,
|
|
CalNum,
|
|
fUnicodeVer,
|
|
fExVersion );
|
|
}
|
|
|
|
//
|
|
// Get the default strings defined for the Gregorian
|
|
// calendar.
|
|
//
|
|
while (pDateTime < pEndDateTime)
|
|
{
|
|
//
|
|
// Call the callback function if the string is not
|
|
// the same as the user string.
|
|
//
|
|
if ((!pUser) || (!NlsStrEqualW(pUser, pDateTime)))
|
|
{
|
|
//
|
|
// Call the appropriate callback function.
|
|
//
|
|
NLS_CALL_ENUMPROC_TRUE( Locale,
|
|
lpDateTimeFmtEnumProc,
|
|
dwFlags,
|
|
pDateTime,
|
|
CAL_GREGORIAN,
|
|
fUnicodeVer,
|
|
fExVersion );
|
|
}
|
|
|
|
//
|
|
// Advance pDateTime pointer.
|
|
//
|
|
pDateTime += NlsStrLenW(pDateTime) + 1;
|
|
}
|
|
|
|
if (fCalendarInfo)
|
|
{
|
|
//
|
|
// Get any alternate calendar dates.
|
|
//
|
|
pOptCal = (LPWORD)(pLocaleHdr) + pLocaleHdr->IOptionalCal;
|
|
if (((POPT_CAL)pOptCal)->CalId == CAL_NO_OPTIONAL)
|
|
{
|
|
//
|
|
// No optional calendars, so done.
|
|
//
|
|
return (TRUE);
|
|
}
|
|
|
|
//
|
|
// Get the requested information for each of the alternate
|
|
// calendars.
|
|
//
|
|
pEndOptCal = (LPWORD)(pLocaleHdr) + pLocaleHdr->SDayName1;
|
|
while (pOptCal < pEndOptCal)
|
|
{
|
|
//
|
|
// Get the pointer to the calendar information.
|
|
//
|
|
CalNum = ((POPT_CAL)pOptCal)->CalId;
|
|
if (GetCalendar(CalNum, &pCalInfo) == NO_ERROR)
|
|
{
|
|
//
|
|
// Get the pointer to the date/time information for the
|
|
// current calendar.
|
|
//
|
|
pDateTime = (LPWORD)pCalInfo +
|
|
*((LPWORD)((LPBYTE)(pCalInfo) + CalDateOffset));
|
|
|
|
pEndDateTime = (LPWORD)pCalInfo +
|
|
*((LPWORD)((LPBYTE)(pCalInfo) + EndCalDateOffset));
|
|
|
|
//
|
|
// Go through each of the strings.
|
|
//
|
|
while (pDateTime < pEndDateTime)
|
|
{
|
|
//
|
|
// Make sure the string is NOT empty and that it is
|
|
// NOT the same as the user's string.
|
|
//
|
|
if ((*pDateTime) &&
|
|
((!pUser) || (!NlsStrEqualW(pUser, pDateTime))))
|
|
{
|
|
//
|
|
// Call the appropriate callback function.
|
|
//
|
|
NLS_CALL_ENUMPROC_TRUE( Locale,
|
|
lpDateTimeFmtEnumProc,
|
|
dwFlags,
|
|
pDateTime,
|
|
CalNum,
|
|
fUnicodeVer,
|
|
fExVersion );
|
|
}
|
|
|
|
//
|
|
// Advance pointer to next date string.
|
|
//
|
|
pDateTime += NlsStrLenW(pDateTime) + 1;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Advance ptr to next optional calendar.
|
|
//
|
|
pOptCal += ((POPT_CAL)pOptCal)->Offset;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Return success.
|
|
//
|
|
return (TRUE);
|
|
}
|