windows-nt/Source/XPSP1/NT/base/win32/winnls/enum.c

2503 lines
94 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
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"
//
// 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
//
// 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);
}
NlsStrCpyW(szSectionName, L"LOCALE_LIST_");
NlsStrCatW(szSectionName, szBuffer);
//
// Get the locale list from the intl.inf file.
//
szBuffer[0] = 0;
GetSystemWindowsDirectory(szInfPath, MAX_PATH_LEN);
NlsStrCatW(szInfPath, L"\\INF\\INTL.INF");
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, NLS_POLICY_TWO_DIGIT_YEAR_KEY) ||
GetTwoDigitYearInfo(CalNum, 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);
}