Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

4270 lines
128 KiB

/*++
Copyright (c) 1991-1996, Microsoft Corporation All rights reserved.
Module Name:
getloc.c
Abstract:
This file contains functions that get information about a locale.
APIs found in this file:
IsValidLocale
ConvertDefaultLocale
GetThreadLocale
SetThreadLocale
GetSystemDefaultLangID
GetUserDefaultLangID
GetSystemDefaultLCID
GetUserDefaultLCID
VerLanguageNameW
VerLanguageNameA
GetLocaleInfoW
SetLocaleInfoW
Revision History:
05-31-91 JulieB Created.
--*/
//
// Include Files.
//
#include "nls.h"
//
// Allow this file to build without warnings when the DUnicode switch
// is turned off.
//
#undef MAKEINTRESOURCE
#define MAKEINTRESOURCE MAKEINTRESOURCEW
//
// Forward Declarations.
//
int
GetLocalizedLanguageName(
LANGID Language,
LPWSTR *ppLangName);
BOOL
GetLocalizedCountryName(
LANGID Language,
LPWSTR *ppCtryName);
BOOL
SetUserInfo(
LPWSTR pValue,
LPWSTR pCacheString,
LPWSTR pData,
ULONG DataLength);
BOOL
SetMultipleUserInfo(
DWORD dwFlags,
int cchData,
LPCWSTR pPicture,
LPCWSTR pSeparator,
LPCWSTR pOrder,
LPCWSTR pTLZero,
LPCWSTR pTimeMarkPosn);
//-------------------------------------------------------------------------//
// API ROUTINES //
//-------------------------------------------------------------------------//
////////////////////////////////////////////////////////////////////////////
//
// IsValidLocale
//
// Determines whether or not a locale is installed in the system if the
// LCID_INSTALLED flag is set, or whether or not a locale is supported in
// the system if the LCID_SUPPORTED flag is set.
//
// 07-26-93 JulieB Created.
////////////////////////////////////////////////////////////////////////////
BOOL WINAPI IsValidLocale(
LCID Locale,
DWORD dwFlags)
{
//
// Invalid Parameter Check:
// - flags other than valid ones
// - more than one of either supported or installed
// - invalid locale
//
if ( (dwFlags & IVL_INVALID_FLAG) ||
(MORE_THAN_ONE(dwFlags, IVL_SINGLE_FLAG)) ||
(IS_INVALID_LOCALE(Locale)) )
{
return (FALSE);
}
//
// See if the LOCALE information is in the system for the
// given locale.
//
if (GetLocHashNode(Locale) == NULL)
{
//
// Return failure.
//
return (FALSE);
}
//
// If the INSTALLED flag is set, see if the LANGUAGE information
// is in the system for the given locale.
//
if ((dwFlags & LCID_INSTALLED) && (GetLangHashNode(Locale, 0) == NULL))
{
//
// Return failure.
//
return (FALSE);
}
//
// Return success.
//
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// ConvertDefaultLocale
//
// Converts any of the special case locale values to an actual locale id.
// If none of the special case locales was given, the given locale id
// is returned.
//
// 09-01-93 JulieB Created.
////////////////////////////////////////////////////////////////////////////
LCID WINAPI ConvertDefaultLocale(
LCID Locale)
{
//
// Check for the special locale values.
//
CHECK_SPECIAL_LOCALES(Locale);
//
// Return the locale id.
//
return (Locale);
}
////////////////////////////////////////////////////////////////////////////
//
// GetThreadLocale
//
// Returns the locale id for the current thread.
//
// 03-11-93 JulieB Moved from base\client.
////////////////////////////////////////////////////////////////////////////
LCID WINAPI GetThreadLocale()
{
//
// Return the locale id stored in the TEB.
//
return ((LCID)(NtCurrentTeb()->CurrentLocale));
}
////////////////////////////////////////////////////////////////////////////
//
// SetThreadLocale
//
// Resets the locale id for the current thread. Any locale-dependent
// functions will reflect the new locale. If the locale passed in is
// not a valid locale id, then FALSE is returned.
//
// 03-11-93 JulieB Moved from base\client; Added Locale Validation.
////////////////////////////////////////////////////////////////////////////
BOOL WINAPI SetThreadLocale(
LCID Locale)
{
PLOC_HASH pHashN; // ptr to hash node
//
// Validate locale id.
//
VALIDATE_LANGUAGE(Locale, pHashN, 0);
if (pHashN == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// Set the locale id in the TEB.
//
NtCurrentTeb()->CurrentLocale = (ULONG)Locale;
//
// Return success.
//
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// GetSystemDefaultLangID
//
// Returns the default language for the system. If the registry value is
// not readable, then the chosen default language is used
// (NLS_DEFAULT_LANGID).
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
LANGID WINAPI GetSystemDefaultLangID()
{
//
// Get the language id from the locale id stored in the cache
// and return it.
//
return (LANGIDFROMLCID(gSystemLocale));
}
////////////////////////////////////////////////////////////////////////////
//
// GetUserDefaultLangID
//
// Returns the default language for the current user. If the current user's
// language is not set, then the system default language id is returned.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
LANGID WINAPI GetUserDefaultLangID()
{
//
// Get the language id from the locale id stored in the cache
// and return it.
//
return (LANGIDFROMLCID(pNlsUserInfo->UserLocaleId));
}
////////////////////////////////////////////////////////////////////////////
//
// GetSystemDefaultLCID
//
// Returns the default locale for the system.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
LCID WINAPI GetSystemDefaultLCID()
{
//
// Return the locale id stored in the cache.
//
return (gSystemLocale);
}
////////////////////////////////////////////////////////////////////////////
//
// GetUserDefaultLCID
//
// Returns the default locale for the current user. If current user's locale
// is not set, then the system default locale id is returned.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
LCID WINAPI GetUserDefaultLCID()
{
//
// Return the locale id stored in the cache.
//
return (pNlsUserInfo->UserLocaleId);
}
////////////////////////////////////////////////////////////////////////////
//
// VerLanguageNameW
//
// Returns the language name of the given language id in the language of
// the current user.
//
// 05-31-91 JulieB Moved and Rewrote from Version Library.
////////////////////////////////////////////////////////////////////////////
#define IDS_UNKNOWN 0
DWORD WINAPI VerLanguageNameW(
DWORD wLang,
LPWSTR szLang,
DWORD wSize)
{
DWORD Length; // length of string
LPWSTR pString; // pointer to string
//
// Try to get the localized language name for the given ID.
//
if (!(Length = GetLocalizedLanguageName((LANGID)wLang, &pString)))
{
//
// Can't get the name of the language id passed in, so get
// the "language neutral" name.
//
Length = GetLocalizedLanguageName(IDS_UNKNOWN, &pString);
}
//
// If the length is too big for the buffer, then reset the length
// to the size of the given buffer.
//
if (Length >= wSize)
{
Length = wSize - 1;
}
//
// Copy the string to the buffer and zero terminate it.
//
wcsncpy(szLang, pString, Length);
szLang[Length] = 0;
//
// Return the number of characters in the string, NOT including
// the null termination.
//
return (Length);
}
////////////////////////////////////////////////////////////////////////////
//
// VerLanguageNameA
//
// Returns the language name of the given language id in the language of
// the current user.
//
// 05-31-91 JulieB Moved from Version Library.
////////////////////////////////////////////////////////////////////////////
DWORD WINAPI VerLanguageNameA(
DWORD wLang,
LPSTR szLang,
DWORD wSize)
{
UNICODE_STRING Language; // unicode string buffer
ANSI_STRING AnsiString; // ansi string buffer
DWORD Status; // return status
//
// Allocate Unicode string structure and set the fields with the
// given parameters.
//
Language.Buffer = RtlAllocateHeap( RtlProcessHeap(),
0,
sizeof(WCHAR) * wSize );
Language.MaximumLength = (USHORT)(wSize * sizeof(WCHAR));
//
// Make sure the allocation succeeded.
//
if (Language.Buffer == NULL)
{
return (FALSE);
}
//
// Get the language name (in Unicode).
//
Status = VerLanguageNameW( wLang,
Language.Buffer,
wSize );
Language.Length = (USHORT)(Status * sizeof(WCHAR));
//
// Convert unicode string to ansi.
//
AnsiString.Buffer = szLang;
AnsiString.Length = AnsiString.MaximumLength = (USHORT)wSize;
RtlUnicodeStringToAnsiString(&AnsiString, &Language, FALSE);
Status = AnsiString.Length;
RtlFreeUnicodeString(&Language);
//
// Return the value returned from VerLanguageNameW.
//
return (Status);
}
////////////////////////////////////////////////////////////////////////////
//
// GetLocaleInfoW
//
// Returns one of the various pieces of information about a particular
// locale by querying the configuration registry. This call also indicates
// how much memory is necessary to contain the desired information.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
int WINAPI GetLocaleInfoW(
LCID Locale,
LCTYPE LCType,
LPWSTR lpLCData,
int cchData)
{
PLOC_HASH pHashN; // ptr to LOC hash node
int Length = 0; // length of info string
LPWSTR pString; // ptr to the info string
LPWORD pStart; // ptr to starting point
BOOL UserOverride = TRUE; // use user override
BOOL ReturnNum = FALSE; // return number instead of string
LPWSTR pTmp; // tmp ptr to info string
int Repeat; // # repetitions of same letter
WCHAR pTemp[MAX_REG_VAL_SIZE]; // temp buffer
UNICODE_STRING ObUnicodeStr; // value string
int Base = 0; // base for str to int conversion
//
// Invalid Parameter Check:
// - validate LCID
// - count is negative
// - NULL data pointer AND count is not zero
//
// NOTE: invalid type is checked in the switch statement below.
//
VALIDATE_LOCALE(Locale, pHashN);
if ( (pHashN == NULL) ||
(cchData < 0) ||
((lpLCData == NULL) && (cchData != 0)) )
{
SetLastError(ERROR_INVALID_PARAMETER);
return (0);
}
//
// Set the base value to add to in order to get the variable
// length strings.
//
pStart = (LPWORD)(pHashN->pLocaleHdr);
//
// Check for NO USER OVERRIDE flag and remove the USE CP ACP flag.
//
if (LCType & LOCALE_NOUSEROVERRIDE)
{
//
// Flag is set, so set the boolean value and remove the flag
// from the LCType parameter (for switch statement).
//
UserOverride = FALSE;
}
if (LCType & LOCALE_RETURN_NUMBER)
{
//
// Flag is set, so set the boolean value and remove the flag
// from the LCType parameter (for switch statement).
//
ReturnNum = TRUE;
}
LCType &= (~(LOCALE_NOUSEROVERRIDE | LOCALE_USE_CP_ACP | LOCALE_RETURN_NUMBER));
//
// Return the appropriate information for the given LCTYPE.
// If user information exists for the given LCTYPE, then
// the user default is returned instead of the system default.
//
switch (LCType)
{
case ( LOCALE_ILANGUAGE ) :
{
Base = 16;
pString = pHashN->pLocaleFixed->szILanguage;
break;
}
case ( LOCALE_SLANGUAGE ) :
{
//
// Get the information from the RC file.
//
// The pString pointer is set when GetLocalizedLanguageName
// is called.
//
Length = GetLocalizedLanguageName( LANGIDFROMLCID(Locale),
&pString );
if (Length == 0)
{
SetLastError(ERROR_INVALID_PARAMETER);
return (0);
}
break;
}
case ( LOCALE_SENGLANGUAGE ) :
{
pString = pStart + pHashN->pLocaleHdr->SEngLanguage;
break;
}
case ( LOCALE_SABBREVLANGNAME ) :
{
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->sAbbrevLangName,
pTemp,
TRUE ))
{
pString = pTemp;
}
else
{
pString = pStart + pHashN->pLocaleHdr->SAbbrevLang;
}
break;
}
case ( LOCALE_SISO639LANGNAME ) :
{
pString = pStart + pHashN->pLocaleHdr->SAbbrevLangISO;
break;
}
case ( LOCALE_SNATIVELANGNAME ) :
{
pString = pStart + pHashN->pLocaleHdr->SNativeLang;
break;
}
case ( LOCALE_ICOUNTRY ) :
{
Base = 10;
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->iCountry,
pTemp,
TRUE ))
{
pString = pTemp;
}
else
{
pString = pHashN->pLocaleFixed->szICountry;
}
break;
}
case ( LOCALE_SCOUNTRY ) :
{
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->sCountry,
pTemp,
TRUE ))
{
pString = pTemp;
}
else
{
//
// Get the information from the RC file.
//
// The pString pointer is set when GetLocalizedCountryName
// is called.
//
if (!GetLocalizedCountryName( LANGIDFROMLCID(Locale),
&pString ))
{
SetLastError(ERROR_INVALID_PARAMETER);
return (0);
}
}
break;
}
case ( LOCALE_SENGCOUNTRY ) :
{
pString = pStart + pHashN->pLocaleHdr->SEngCountry;
break;
}
case ( LOCALE_SABBREVCTRYNAME ) :
{
pString = pStart + pHashN->pLocaleHdr->SAbbrevCtry;
break;
}
case ( LOCALE_SISO3166CTRYNAME ) :
{
pString = pStart + pHashN->pLocaleHdr->SAbbrevCtryISO;
break;
}
case ( LOCALE_SNATIVECTRYNAME ) :
{
pString = pStart + pHashN->pLocaleHdr->SNativeCtry;
break;
}
case ( LOCALE_IDEFAULTLANGUAGE ) :
{
Base = 16;
pString = pHashN->pLocaleFixed->szIDefaultLang;
break;
}
case ( LOCALE_IDEFAULTCOUNTRY ) :
{
Base = 10;
pString = pHashN->pLocaleFixed->szIDefaultCtry;
break;
}
case ( LOCALE_IDEFAULTANSICODEPAGE ) :
{
if (ReturnNum)
{
if (cchData < 2)
{
if (cchData == 0)
{
//
// DWORD is needed for this option (2 WORDS),
// so return 2.
//
return (2);
}
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return (0);
}
//
// Copy the value to lpLCData and return 2
// (2 WORDS = 1 DWORD).
//
*((LPDWORD)lpLCData) = (DWORD)(pHashN->pLocaleFixed->DefaultACP);
return (2);
}
pString = pHashN->pLocaleFixed->szIDefaultACP;
break;
}
case ( LOCALE_IDEFAULTCODEPAGE ) :
{
Base = 10;
pString = pHashN->pLocaleFixed->szIDefaultOCP;
break;
}
case ( LOCALE_IDEFAULTMACCODEPAGE ) :
{
Base = 10;
pString = pHashN->pLocaleFixed->szIDefaultMACCP;
break;
}
case ( LOCALE_SLIST ) :
{
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->sList,
pTemp,
FALSE ))
{
pString = pTemp;
}
else
{
pString = pStart + pHashN->pLocaleHdr->SList;
}
break;
}
case ( LOCALE_IMEASURE ) :
{
Base = 10;
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->iMeasure,
pTemp,
TRUE ))
{
pString = pTemp;
}
else
{
pString = pHashN->pLocaleFixed->szIMeasure;
}
break;
}
case ( LOCALE_SDECIMAL ) :
{
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->sDecimal,
pTemp,
FALSE ))
{
pString = pTemp;
}
else
{
pString = pStart + pHashN->pLocaleHdr->SDecimal;
}
break;
}
case ( LOCALE_STHOUSAND ) :
{
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->sThousand,
pTemp,
FALSE ))
{
pString = pTemp;
}
else
{
pString = pStart + pHashN->pLocaleHdr->SThousand;
}
break;
}
case ( LOCALE_SGROUPING ) :
{
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->sGrouping,
pTemp,
TRUE ))
{
pString = pTemp;
}
else
{
pString = pStart + pHashN->pLocaleHdr->SGrouping;
}
break;
}
case ( LOCALE_IDIGITS ) :
{
Base = 10;
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->iDigits,
pTemp,
TRUE ))
{
pString = pTemp;
}
else
{
pString = pHashN->pLocaleFixed->szIDigits;
}
break;
}
case ( LOCALE_ILZERO ) :
{
Base = 10;
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->iLZero,
pTemp,
TRUE ))
{
pString = pTemp;
}
else
{
pString = pHashN->pLocaleFixed->szILZero;
}
break;
}
case ( LOCALE_INEGNUMBER ) :
{
Base = 10;
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->iNegNumber,
pTemp,
TRUE ))
{
pString = pTemp;
}
else
{
pString = pHashN->pLocaleFixed->szINegNumber;
}
break;
}
case ( LOCALE_SNATIVEDIGITS ) :
{
pString = pStart + pHashN->pLocaleHdr->SNativeDigits;
break;
}
case ( LOCALE_SCURRENCY ) :
{
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->sCurrency,
pTemp,
FALSE ))
{
pString = pTemp;
}
else
{
pString = pStart + pHashN->pLocaleHdr->SCurrency;
}
break;
}
case ( LOCALE_SINTLSYMBOL ) :
{
pString = pStart + pHashN->pLocaleHdr->SIntlSymbol;
break;
}
case ( LOCALE_SMONDECIMALSEP ) :
{
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->sMonDecSep,
pTemp,
FALSE ))
{
pString = pTemp;
}
else
{
pString = pStart + pHashN->pLocaleHdr->SMonDecSep;
}
break;
}
case ( LOCALE_SMONTHOUSANDSEP ) :
{
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->sMonThouSep,
pTemp,
FALSE ))
{
pString = pTemp;
}
else
{
pString = pStart + pHashN->pLocaleHdr->SMonThousSep;
}
break;
}
case ( LOCALE_SMONGROUPING ) :
{
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->sMonGrouping,
pTemp,
TRUE ))
{
pString = pTemp;
}
else
{
pString = pStart + pHashN->pLocaleHdr->SMonGrouping;
}
break;
}
case ( LOCALE_ICURRDIGITS ) :
{
Base = 10;
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->iCurrDigits,
pTemp,
TRUE ))
{
pString = pTemp;
}
else
{
pString = pHashN->pLocaleFixed->szICurrDigits;
}
break;
}
case ( LOCALE_IINTLCURRDIGITS ) :
{
Base = 10;
pString = pHashN->pLocaleFixed->szIIntlCurrDigits;
break;
}
case ( LOCALE_ICURRENCY ) :
{
Base = 10;
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->iCurrency,
pTemp,
TRUE ))
{
pString = pTemp;
}
else
{
pString = pHashN->pLocaleFixed->szICurrency;
}
break;
}
case ( LOCALE_INEGCURR ) :
{
Base = 10;
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->iNegCurr,
pTemp,
TRUE ))
{
pString = pTemp;
}
else
{
pString = pHashN->pLocaleFixed->szINegCurr;
}
break;
}
case ( LOCALE_SPOSITIVESIGN ) :
{
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->sPosSign,
pTemp,
FALSE ))
{
pString = pTemp;
}
else
{
pString = pStart + pHashN->pLocaleHdr->SPositiveSign;
}
break;
}
case ( LOCALE_SNEGATIVESIGN ) :
{
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->sNegSign,
pTemp,
FALSE ))
{
pString = pTemp;
}
else
{
pString = pStart + pHashN->pLocaleHdr->SNegativeSign;
}
break;
}
case ( LOCALE_IPOSSIGNPOSN ) :
{
//
// Since there is no positive sign in any of the ICURRENCY
// options, use the INEGCURR options instead. All known
// locales would use the positive sign in the same position
// as the negative sign.
//
// NOTE: For the 2 options that use parenthesis, put the
// positive sign at the beginning of the string
// (where the opening parenthesis is).
//
// 1 => 4, 5, 8, 15
// 2 => 3, 11
// 3 => 0, 1, 6, 9, 13, 14
// 4 => 2, 7, 10, 12
//
Base = 10;
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->iNegCurr,
pTemp,
TRUE ))
{
pString = pTemp;
//
// Set the appropriate value in pString.
//
switch (*pString)
{
case ( L'4' ) :
case ( L'5' ) :
case ( L'8' ) :
{
*pString = L'1';
*(pString + 1) = 0;
break;
}
case ( L'3' ) :
{
*pString = L'2';
*(pString + 1) = 0;
break;
}
case ( L'0' ) :
case ( L'6' ) :
case ( L'9' ) :
{
*pString = L'3';
*(pString + 1) = 0;
break;
}
case ( L'2' ) :
case ( L'7' ) :
{
*pString = L'4';
*(pString + 1) = 0;
break;
}
case ( L'1' ) :
{
switch (*(pString + 1))
{
case ( 0 ) :
case ( L'3' ) :
case ( L'4' ) :
default :
{
*pString = L'3';
*(pString + 1) = 0;
break;
}
case ( L'0' ) :
case ( L'2' ) :
{
*pString = L'4';
*(pString + 1) = 0;
break;
}
case ( L'1' ) :
{
*pString = L'2';
*(pString + 1) = 0;
break;
}
case ( L'5' ) :
{
*pString = L'1';
*(pString + 1) = 0;
break;
}
}
break;
}
default :
{
pString = pHashN->pLocaleFixed->szIPosSignPosn;
break;
}
}
}
else
{
pString = pHashN->pLocaleFixed->szIPosSignPosn;
}
break;
}
case ( LOCALE_INEGSIGNPOSN ) :
{
//
// Use the INEGCURR value from the user portion of the
// registry, if it exists.
//
// 0 => 0, 4, 14, 15
// 1 => 5, 8
// 2 => 3, 11
// 3 => 1, 6, 9, 13
// 4 => 2, 7, 10, 12
//
Base = 10;
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->iNegCurr,
pTemp,
TRUE ))
{
pString = pTemp;
//
// Set the appropriate value in pString.
//
switch (*pString)
{
case ( L'0' ) :
case ( L'4' ) :
{
*pString = L'0';
*(pString + 1) = 0;
break;
}
case ( L'5' ) :
case ( L'8' ) :
{
*pString = L'1';
*(pString + 1) = 0;
break;
}
case ( L'3' ) :
{
*pString = L'2';
*(pString + 1) = 0;
break;
}
case ( L'6' ) :
case ( L'9' ) :
{
*pString = L'3';
*(pString + 1) = 0;
break;
}
case ( L'2' ) :
case ( L'7' ) :
{
*pString = L'4';
*(pString + 1) = 0;
break;
}
case ( L'1' ) :
{
switch (*(pString + 1))
{
case ( 0 ) :
case ( L'3' ) :
default :
{
*pString = L'3';
*(pString + 1) = 0;
break;
}
case ( L'0' ) :
case ( L'2' ) :
{
*pString = L'4';
*(pString + 1) = 0;
break;
}
case ( L'1' ) :
{
*pString = L'2';
*(pString + 1) = 0;
break;
}
case ( L'4' ) :
case ( L'5' ) :
{
*pString = L'0';
*(pString + 1) = 0;
break;
}
}
break;
}
default :
{
pString = pHashN->pLocaleFixed->szINegSignPosn;
break;
}
}
}
else
{
pString = pHashN->pLocaleFixed->szINegSignPosn;
}
break;
}
case ( LOCALE_IPOSSYMPRECEDES ) :
{
//
// Use the ICURRENCY value from the user portion of the
// registry, if it exists.
//
// 0 => 1, 3
// 1 => 0, 2
//
Base = 10;
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->iCurrency,
pTemp,
TRUE ))
{
pString = pTemp;
//
// Set the appropriate value in pString.
//
switch (*pString)
{
case ( L'1' ) :
case ( L'3' ) :
{
*pString = L'0';
*(pString + 1) = 0;
break;
}
case ( L'0' ) :
case ( L'2' ) :
{
*pString = L'1';
*(pString + 1) = 0;
break;
}
default :
{
pString = pHashN->pLocaleFixed->szIPosSymPrecedes;
break;
}
}
}
else
{
pString = pHashN->pLocaleFixed->szIPosSymPrecedes;
}
break;
}
case ( LOCALE_IPOSSEPBYSPACE ) :
{
//
// Use the ICURRENCY value from the user portion of the
// registry, if it exists.
//
// 0 => 0, 1
// 1 => 2, 3
//
Base = 10;
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->iCurrency,
pTemp,
TRUE ))
{
pString = pTemp;
//
// Set the appropriate value in pString.
//
switch (*pString)
{
case ( L'0' ) :
case ( L'1' ) :
{
*pString = L'0';
*(pString + 1) = 0;
break;
}
case ( L'2' ) :
case ( L'3' ) :
{
*pString = L'1';
*(pString + 1) = 0;
break;
}
default :
{
pString = pHashN->pLocaleFixed->szIPosSepBySpace;
break;
}
}
}
else
{
pString = pHashN->pLocaleFixed->szIPosSepBySpace;
}
break;
}
case ( LOCALE_INEGSYMPRECEDES ) :
{
//
// Use the INEGCURR value from the user portion of the
// registry, if it exists.
//
// 0 => 4, 5, 6, 7, 8, 10, 13, 15
// 1 => 0, 1, 2, 3, 9, 11, 12, 14
//
Base = 10;
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->iNegCurr,
pTemp,
TRUE ))
{
pString = pTemp;
//
// Set the appropriate value in pString.
//
switch (*pString)
{
case ( L'4' ) :
case ( L'5' ) :
case ( L'6' ) :
case ( L'7' ) :
case ( L'8' ) :
{
*pString = L'0';
*(pString + 1) = 0;
break;
}
case ( L'0' ) :
case ( L'2' ) :
case ( L'3' ) :
case ( L'9' ) :
{
*pString = L'1';
*(pString + 1) = 0;
break;
}
case ( L'1' ) :
{
if ((*(pString + 1) == L'0') ||
(*(pString + 1) == L'3') ||
(*(pString + 1) == L'5'))
{
*pString = L'0';
*(pString + 1) = 0;
}
else
{
*pString = L'1';
*(pString + 1) = 0;
}
break;
}
default :
{
pString = pHashN->pLocaleFixed->szINegSymPrecedes;
break;
}
}
}
else
{
pString = pHashN->pLocaleFixed->szINegSymPrecedes;
}
break;
}
case ( LOCALE_INEGSEPBYSPACE ) :
{
//
// Use the INEGCURR value from the user portion of the
// registry, if it exists.
//
// 0 => 0, 1, 2, 3, 4, 5, 6, 7
// 1 => 8, 9, 10, 11, 12, 13, 14, 15
//
Base = 10;
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->iNegCurr,
pTemp,
TRUE ))
{
pString = pTemp;
//
// Set the appropriate value in pString.
//
switch (*pString)
{
case ( L'0' ) :
case ( L'2' ) :
case ( L'3' ) :
case ( L'4' ) :
case ( L'5' ) :
case ( L'6' ) :
case ( L'7' ) :
{
*pString = L'0';
*(pString + 1) = 0;
break;
}
case ( L'8' ) :
case ( L'9' ) :
{
*pString = L'1';
*(pString + 1) = 0;
break;
}
case ( L'1' ) :
{
if (*(pString + 1) == 0)
{
*pString = L'0';
*(pString + 1) = 0;
}
else
{
*pString = L'1';
*(pString + 1) = 0;
}
break;
}
default :
{
pString = pHashN->pLocaleFixed->szINegSepBySpace;
break;
}
}
}
else
{
pString = pHashN->pLocaleFixed->szINegSepBySpace;
}
break;
}
case ( LOCALE_STIMEFORMAT ) :
{
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->sTimeFormat,
pTemp,
TRUE ))
{
pString = pTemp;
}
else
{
pString = pStart + pHashN->pLocaleHdr->STimeFormat;
}
break;
}
case ( LOCALE_STIME ) :
{
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->sTime,
pTemp,
TRUE ))
{
pString = pTemp;
}
else
{
pString = pStart + pHashN->pLocaleHdr->STime;
}
break;
}
case ( LOCALE_ITIME ) :
{
Base = 10;
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->iTime,
pTemp,
TRUE ))
{
pString = pTemp;
}
else
{
pString = pHashN->pLocaleFixed->szITime;
}
break;
}
case ( LOCALE_ITLZERO ) :
{
Base = 10;
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->iTLZero,
pTemp,
TRUE ))
{
pString = pTemp;
}
else
{
pString = pHashN->pLocaleFixed->szITLZero;
}
break;
}
case ( LOCALE_ITIMEMARKPOSN ) :
{
Base = 10;
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->iTimeMarkPosn,
pTemp,
TRUE ))
{
pString = pTemp;
}
else
{
pString = pHashN->pLocaleFixed->szITimeMarkPosn;
}
break;
}
case ( LOCALE_S1159 ) :
{
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->s1159,
pTemp,
FALSE ))
{
pString = pTemp;
}
else
{
pString = pStart + pHashN->pLocaleHdr->S1159;
}
break;
}
case ( LOCALE_S2359 ) :
{
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->s2359,
pTemp,
FALSE ))
{
pString = pTemp;
}
else
{
pString = pStart + pHashN->pLocaleHdr->S2359;
}
break;
}
case ( LOCALE_SSHORTDATE ) :
{
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->sShortDate,
pTemp,
TRUE ))
{
pString = pTemp;
}
else
{
pString = pStart + pHashN->pLocaleHdr->SShortDate;
}
break;
}
case ( LOCALE_SDATE ) :
{
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->sDate,
pTemp,
TRUE ))
{
pString = pTemp;
}
else
{
pString = pStart + pHashN->pLocaleHdr->SDate;
}
break;
}
case ( LOCALE_IDATE ) :
{
Base = 10;
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->iDate,
pTemp,
TRUE ))
{
pString = pTemp;
}
else
{
pString = pHashN->pLocaleFixed->szIDate;
}
break;
}
case ( LOCALE_ICENTURY ) :
{
//
// Use the short date picture to get this information.
//
Base = 10;
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->sShortDate,
pTemp,
TRUE ))
{
pString = pTemp;
//
// Find out how many y's in string.
// No need to ignore quotes in short date.
//
pTmp = pString;
while ((*pTmp) &&
(*pTmp != L'y'))
{
pTmp++;
}
//
// Set the appropriate value in pString.
//
if (*pTmp == L'y')
{
//
// Get the number of 'y' repetitions in the format string.
//
pTmp++;
for (Repeat = 0; (*pTmp == L'y'); Repeat++, pTmp++)
;
switch (Repeat)
{
case ( 0 ) :
case ( 1 ) :
{
//
// Two-digit century with leading zero.
//
*pString = L'0';
*(pString + 1) = 0;
break;
}
case ( 2 ) :
case ( 3 ) :
default :
{
//
// Full century.
//
*pString = L'1';
*(pString + 1) = 0;
break;
}
}
break;
}
}
//
// Use the system default value.
//
pString = pHashN->pLocaleFixed->szICentury;
break;
}
case ( LOCALE_IDAYLZERO ) :
{
//
// Use the short date picture to get this information.
//
Base = 10;
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->sShortDate,
pTemp,
TRUE ))
{
pString = pTemp;
//
// Find out how many d's in string.
// No need to ignore quotes in short date.
//
pTmp = pString;
while ((*pTmp) &&
(*pTmp != L'd'))
{
pTmp++;
}
//
// Set the appropriate value in pString.
//
if (*pTmp == L'd')
{
//
// Get the number of 'd' repetitions in the format string.
//
pTmp++;
for (Repeat = 0; (*pTmp == L'd'); Repeat++, pTmp++)
;
switch (Repeat)
{
case ( 0 ) :
{
//
// No leading zero.
//
*pString = L'0';
*(pString + 1) = 0;
break;
}
case ( 1 ) :
default :
{
//
// Use leading zero.
//
*pString = L'1';
*(pString + 1) = 0;
break;
}
}
break;
}
}
//
// Use the system default value.
//
pString = pHashN->pLocaleFixed->szIDayLZero;
break;
}
case ( LOCALE_IMONLZERO ) :
{
//
// Use the short date picture to get this information.
//
Base = 10;
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->sShortDate,
pTemp,
TRUE ))
{
pString = pTemp;
//
// Find out how many M's in string.
// No need to ignore quotes in short date.
//
pTmp = pString;
while ((*pTmp) &&
(*pTmp != L'M'))
{
pTmp++;
}
//
// Set the appropriate value in pString.
//
if (*pTmp == L'M')
{
//
// Get the number of 'M' repetitions in the format string.
//
pTmp++;
for (Repeat = 0; (*pTmp == L'M'); Repeat++, pTmp++)
;
switch (Repeat)
{
case ( 0 ) :
{
//
// No leading zero.
//
*pString = L'0';
*(pString + 1) = 0;
break;
}
case ( 1 ) :
default :
{
//
// Use leading zero.
//
*pString = L'1';
*(pString + 1) = 0;
break;
}
}
break;
}
}
//
// Use the system default value.
//
pString = pHashN->pLocaleFixed->szIMonLZero;
break;
}
case ( LOCALE_SLONGDATE ) :
{
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->sLongDate,
pTemp,
TRUE ))
{
pString = pTemp;
}
else
{
pString = pStart + pHashN->pLocaleHdr->SLongDate;
}
break;
}
case ( LOCALE_ILDATE ) :
{
//
// Use the long date picture to get this information.
//
Base = 10;
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->sLongDate,
pTemp,
TRUE ))
{
pString = pTemp;
//
// Find out if d, M, or y is first, but ignore quotes.
// Also, if "ddd" or "dddd" is found, then skip it. Only
// want "d" or "dd".
//
pTmp = pString;
while (pTmp = wcspbrk(pTmp, L"dMy'"))
{
//
// Check special cases.
//
if (*pTmp == L'd')
{
//
// Check for d's. Ignore more than 2 d's.
//
for (Repeat = 0; (*pTmp == L'd'); Repeat++, pTmp++)
;
if (Repeat < 3)
{
//
// Break out of while loop. Found "d" or "dd".
//
pTmp--;
break;
}
}
else if (*pTmp == NLS_CHAR_QUOTE)
{
//
// Ignore quotes.
//
pTmp++;
while ((*pTmp) && (*pTmp != NLS_CHAR_QUOTE))
{
pTmp++;
}
pTmp++;
}
else
{
//
// Found one of the values, so break out of
// while loop.
//
break;
}
}
//
// Set the appropriate value in pString.
//
if (pTmp)
{
switch (*pTmp)
{
case ( L'd' ) :
{
*pString = L'1';
break;
}
case ( L'M' ) :
{
*pString = L'0';
break;
}
case ( L'y' ) :
{
*pString = L'2';
break;
}
}
//
// Null terminate the string.
//
*(pString + 1) = 0;
break;
}
}
//
// Use the default value.
//
pString = pHashN->pLocaleFixed->szILDate;
break;
}
case ( LOCALE_ICALENDARTYPE ) :
{
Base = 10;
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->iCalType,
pTemp,
TRUE ))
{
pString = pTemp;
}
else
{
pString = pHashN->pLocaleFixed->szICalendarType;
}
break;
}
case ( LOCALE_IOPTIONALCALENDAR ) :
{
Base = 10;
pString = pStart + pHashN->pLocaleHdr->IOptionalCal;
pString = ((POPT_CAL)pString)->pCalStr;
break;
}
case ( LOCALE_IFIRSTDAYOFWEEK ) :
{
Base = 10;
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->iFirstDay,
pTemp,
TRUE ))
{
pString = pTemp;
}
else
{
pString = pHashN->pLocaleFixed->szIFirstDayOfWk;
}
break;
}
case ( LOCALE_IFIRSTWEEKOFYEAR ) :
{
Base = 10;
if (UserOverride &&
GetUserInfo( Locale,
pNlsUserInfo->iFirstWeek,
pTemp,
TRUE ))
{
pString = pTemp;
}
else
{
pString = pHashN->pLocaleFixed->szIFirstWkOfYr;
}
break;
}
case ( LOCALE_SDAYNAME1 ) :
{
pString = pStart + pHashN->pLocaleHdr->SDayName1;
break;
}
case ( LOCALE_SDAYNAME2 ) :
{
pString = pStart + pHashN->pLocaleHdr->SDayName2;
break;
}
case ( LOCALE_SDAYNAME3 ) :
{
pString = pStart + pHashN->pLocaleHdr->SDayName3;
break;
}
case ( LOCALE_SDAYNAME4 ) :
{
pString = pStart + pHashN->pLocaleHdr->SDayName4;
break;
}
case ( LOCALE_SDAYNAME5 ) :
{
pString = pStart + pHashN->pLocaleHdr->SDayName5;
break;
}
case ( LOCALE_SDAYNAME6 ) :
{
pString = pStart + pHashN->pLocaleHdr->SDayName6;
break;
}
case ( LOCALE_SDAYNAME7 ) :
{
pString = pStart + pHashN->pLocaleHdr->SDayName7;
break;
}
case ( LOCALE_SABBREVDAYNAME1 ) :
{
pString = pStart + pHashN->pLocaleHdr->SAbbrevDayName1;
break;
}
case ( LOCALE_SABBREVDAYNAME2 ) :
{
pString = pStart + pHashN->pLocaleHdr->SAbbrevDayName2;
break;
}
case ( LOCALE_SABBREVDAYNAME3 ) :
{
pString = pStart + pHashN->pLocaleHdr->SAbbrevDayName3;
break;
}
case ( LOCALE_SABBREVDAYNAME4 ) :
{
pString = pStart + pHashN->pLocaleHdr->SAbbrevDayName4;
break;
}
case ( LOCALE_SABBREVDAYNAME5 ) :
{
pString = pStart + pHashN->pLocaleHdr->SAbbrevDayName5;
break;
}
case ( LOCALE_SABBREVDAYNAME6 ) :
{
pString = pStart + pHashN->pLocaleHdr->SAbbrevDayName6;
break;
}
case ( LOCALE_SABBREVDAYNAME7 ) :
{
pString = pStart + pHashN->pLocaleHdr->SAbbrevDayName7;
break;
}
case ( LOCALE_SMONTHNAME1 ) :
{
pString = pStart + pHashN->pLocaleHdr->SMonthName1;
break;
}
case ( LOCALE_SMONTHNAME2 ) :
{
pString = pStart + pHashN->pLocaleHdr->SMonthName2;
break;
}
case ( LOCALE_SMONTHNAME3 ) :
{
pString = pStart + pHashN->pLocaleHdr->SMonthName3;
break;
}
case ( LOCALE_SMONTHNAME4 ) :
{
pString = pStart + pHashN->pLocaleHdr->SMonthName4;
break;
}
case ( LOCALE_SMONTHNAME5 ) :
{
pString = pStart + pHashN->pLocaleHdr->SMonthName5;
break;
}
case ( LOCALE_SMONTHNAME6 ) :
{
pString = pStart + pHashN->pLocaleHdr->SMonthName6;
break;
}
case ( LOCALE_SMONTHNAME7 ) :
{
pString = pStart + pHashN->pLocaleHdr->SMonthName7;
break;
}
case ( LOCALE_SMONTHNAME8 ) :
{
pString = pStart + pHashN->pLocaleHdr->SMonthName8;
break;
}
case ( LOCALE_SMONTHNAME9 ) :
{
pString = pStart + pHashN->pLocaleHdr->SMonthName9;
break;
}
case ( LOCALE_SMONTHNAME10 ) :
{
pString = pStart + pHashN->pLocaleHdr->SMonthName10;
break;
}
case ( LOCALE_SMONTHNAME11 ) :
{
pString = pStart + pHashN->pLocaleHdr->SMonthName11;
break;
}
case ( LOCALE_SMONTHNAME12 ) :
{
pString = pStart + pHashN->pLocaleHdr->SMonthName12;
break;
}
case ( LOCALE_SMONTHNAME13 ) :
{
pString = pStart + pHashN->pLocaleHdr->SMonthName13;
break;
}
case ( LOCALE_SABBREVMONTHNAME1 ) :
{
pString = pStart + pHashN->pLocaleHdr->SAbbrevMonthName1;
break;
}
case ( LOCALE_SABBREVMONTHNAME2 ) :
{
pString = pStart + pHashN->pLocaleHdr->SAbbrevMonthName2;
break;
}
case ( LOCALE_SABBREVMONTHNAME3 ) :
{
pString = pStart + pHashN->pLocaleHdr->SAbbrevMonthName3;
break;
}
case ( LOCALE_SABBREVMONTHNAME4 ) :
{
pString = pStart + pHashN->pLocaleHdr->SAbbrevMonthName4;
break;
}
case ( LOCALE_SABBREVMONTHNAME5 ) :
{
pString = pStart + pHashN->pLocaleHdr->SAbbrevMonthName5;
break;
}
case ( LOCALE_SABBREVMONTHNAME6 ) :
{
pString = pStart + pHashN->pLocaleHdr->SAbbrevMonthName6;
break;
}
case ( LOCALE_SABBREVMONTHNAME7 ) :
{
pString = pStart + pHashN->pLocaleHdr->SAbbrevMonthName7;
break;
}
case ( LOCALE_SABBREVMONTHNAME8 ) :
{
pString = pStart + pHashN->pLocaleHdr->SAbbrevMonthName8;
break;
}
case ( LOCALE_SABBREVMONTHNAME9 ) :
{
pString = pStart + pHashN->pLocaleHdr->SAbbrevMonthName9;
break;
}
case ( LOCALE_SABBREVMONTHNAME10 ) :
{
pString = pStart + pHashN->pLocaleHdr->SAbbrevMonthName10;
break;
}
case ( LOCALE_SABBREVMONTHNAME11 ) :
{
pString = pStart + pHashN->pLocaleHdr->SAbbrevMonthName11;
break;
}
case ( LOCALE_SABBREVMONTHNAME12 ) :
{
pString = pStart + pHashN->pLocaleHdr->SAbbrevMonthName12;
break;
}
case ( LOCALE_SABBREVMONTHNAME13 ) :
{
pString = pStart + pHashN->pLocaleHdr->SAbbrevMonthName13;
break;
}
case ( LOCALE_FONTSIGNATURE ) :
{
//
// Check cchData for size of given buffer.
//
if (cchData == 0)
{
return (MAX_FONTSIGNATURE);
}
else if (cchData < MAX_FONTSIGNATURE)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return (0);
}
//
// This string does NOT get zero terminated.
//
pString = pHashN->pLocaleFixed->szFontSignature;
//
// Copy the string to lpLCData and return the number of
// characters copied.
//
RtlMoveMemory(lpLCData, pString, MAX_FONTSIGNATURE * sizeof(WCHAR));
return (MAX_FONTSIGNATURE);
break;
}
default :
{
SetLastError(ERROR_INVALID_FLAGS);
return (0);
}
}
//
// See if the caller wants the value in the form of a number instead
// of a string.
//
if (ReturnNum)
{
//
// Make sure the flags are valid and there is enough buffer
// space.
//
if (Base == 0)
{
SetLastError(ERROR_INVALID_FLAGS);
return (0);
}
if (cchData < 2)
{
if (cchData == 0)
{
//
// DWORD is needed for this option (2 WORDS), so return 2.
//
return (2);
}
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return (0);
}
//
// Convert the string to an int and return 2 (1 DWORD = 2 WORDS).
//
RtlInitUnicodeString(&ObUnicodeStr, pString);
if (RtlUnicodeStringToInteger(&ObUnicodeStr, Base, (LPDWORD)lpLCData))
{
SetLastError(ERROR_INVALID_FLAGS);
return (0);
}
return (2);
}
//
// Get the length (in characters) of the string to copy.
//
if (Length == 0)
{
Length = NlsStrLenW(pString);
}
//
// Add one for the null termination. All strings should be null
// terminated.
//
Length++;
//
// Check cchData for size of given buffer.
//
if (cchData == 0)
{
//
// If cchData is 0, then we can't use lpLCData. In this
// case, we simply want to return the length (in characters) of
// the string to be copied.
//
return (Length);
}
else if (cchData < Length)
{
//
// The buffer is too small for the string, so return an error
// and zero bytes written.
//
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return (0);
}
//
// Copy the string to lpLCData and null terminate it.
// Return the number of characters copied.
//
wcsncpy(lpLCData, pString, Length - 1);
lpLCData[Length - 1] = 0;
return (Length);
}
////////////////////////////////////////////////////////////////////////////
//
// SetLocaleInfoW
//
// Sets one of the various pieces of information about a particular
// locale by making an entry in the user's portion of the configuration
// registry. This will only affect the user override portion of the locale
// settings. The system defaults will never be reset.
//
// 07-14-93 JulieB Created.
////////////////////////////////////////////////////////////////////////////
BOOL WINAPI SetLocaleInfoW(
LCID Locale,
LCTYPE LCType,
LPCWSTR lpLCData)
{
PLOC_HASH pHashN; // ptr to LOC hash node
int cchData; // length of lpLCData
LPWSTR pString; // ptr to info string to change
LPWSTR pPos; // ptr to position in info string
LPWSTR pPos2; // ptr to position in info string
LPWSTR pSep; // ptr to separator string
WCHAR pTemp[MAX_PATH_LEN]; // ptr to temp storage buffer
WCHAR pOutput[MAX_REG_VAL_SIZE]; // ptr to output for GetInfo call
WCHAR pOutput2[MAX_REG_VAL_SIZE]; // ptr to output for GetInfo call
UINT Order; // ptr to order buffer
UINT TLZero; // ptr to time leading zero buffer
UINT TimeMarkPosn; // ptr to time mark position buffer
WCHAR pFind[3]; // ptr to chars to find
int SepLen; // length of separator string
//
// Invalid Parameter Check:
// - validate LCID
// - NULL data pointer
//
// NOTE: invalid type is checked in the switch statement below.
//
VALIDATE_LOCALE(Locale, pHashN);
if ((pHashN == NULL) || (lpLCData == NULL))
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// Get the length of the buffer.
//
cchData = NlsStrLenW(lpLCData) + 1;
//
// Set the appropriate user information for the given LCTYPE.
//
LCType &= (~LOCALE_USE_CP_ACP);
switch (LCType)
{
case ( LOCALE_SLIST ) :
{
//
// Validate the new value. It should be no longer than
// MAX_SLIST wide characters in length.
//
if (cchData > MAX_SLIST)
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// Set the registry with the new SLIST string.
//
return (SetUserInfo( NLS_VALUE_SLIST,
pNlsUserInfo->sList,
(LPWSTR)lpLCData,
cchData ));
break;
}
case ( LOCALE_IMEASURE ) :
{
//
// Validate the new value. It should be no longer than
// MAX_IMEASURE wide characters in length.
// It should be between 0 and MAX_VALUE_IMEASURE.
//
// NOTE: The string may not be NULL, so it must be at least
// 2 chars long (includes null).
//
// Optimized - since MAX_IMEASURE is 2.
//
if ((cchData != MAX_IMEASURE) ||
(*lpLCData < NLS_CHAR_ZERO) ||
(*lpLCData > MAX_CHAR_IMEASURE))
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// Set the registry with the new IMEASURE string.
//
return (SetUserInfo( NLS_VALUE_IMEASURE,
pNlsUserInfo->iMeasure,
(LPWSTR)lpLCData,
cchData ));
break;
}
case ( LOCALE_SDECIMAL ) :
{
//
// Validate the new value. It should be no longer than
// MAX_SDECIMAL wide characters in length and should not
// contain any integer values (L'0' thru L'9').
//
if (!IsValidSeparatorString( lpLCData,
MAX_SDECIMAL,
FALSE ))
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// Set the registry with the new SDECIMAL string.
//
return (SetUserInfo( NLS_VALUE_SDECIMAL,
pNlsUserInfo->sDecimal,
(LPWSTR)lpLCData,
cchData ));
break;
}
case ( LOCALE_STHOUSAND ) :
{
//
// Validate the new value. It should be no longer than
// MAX_STHOUSAND wide characters in length and should not
// contain any integer values (L'0' thru L'9').
//
if (!IsValidSeparatorString( lpLCData,
MAX_STHOUSAND,
FALSE ))
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// Set the registry with the new STHOUSAND string.
//
return (SetUserInfo( NLS_VALUE_STHOUSAND,
pNlsUserInfo->sThousand,
(LPWSTR)lpLCData,
cchData ));
break;
}
case ( LOCALE_SGROUPING ) :
{
//
// Validate the new value. It should be exactly
// MAX_SGROUPING (4) wide characters in length.
// The 1st value should be between 0 and MAX_VALUE_SGROUPING.
// The 2nd char should be a semicolon and the 3rd char
// should be integer 0.
//
// NOTE: The string may not be NULL, so it must be at least
// 2 chars long (includes null).
//
if ((cchData != MAX_SGROUPING) ||
(*lpLCData < NLS_CHAR_ZERO) ||
(*lpLCData > MAX_CHAR_SGROUPING) ||
(*(lpLCData + 1) != NLS_CHAR_SEMICOLON) ||
(*(lpLCData + 2) != NLS_CHAR_ZERO))
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// Set the registry with the new SGROUPING string.
//
return (SetUserInfo( NLS_VALUE_SGROUPING,
pNlsUserInfo->sGrouping,
(LPWSTR)lpLCData,
cchData ));
break;
}
case ( LOCALE_IDIGITS ) :
{
//
// Validate the new value. It should be no longer than
// MAX_IDIGITS wide characters in length.
// The value should be between 0 and MAX_VALUE_IDIGITS.
//
// NOTE: The string may not be NULL, so it must be at least
// 2 chars long (includes null).
//
// Optimized - since MAX_IDIGITS is 2.
//
if ((cchData != MAX_IDIGITS) ||
(*lpLCData < NLS_CHAR_ZERO) ||
(*lpLCData > MAX_CHAR_IDIGITS))
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// Set the registry with the new IDIGITS string.
//
return (SetUserInfo( NLS_VALUE_IDIGITS,
pNlsUserInfo->iDigits,
(LPWSTR)lpLCData,
cchData ));
break;
}
case ( LOCALE_ILZERO ) :
{
//
// Validate the new value. It should be no longer than
// MAX_ILZERO wide characters in length.
// The value should be between 0 and MAX_VALUE_ILZERO.
//
// NOTE: The string may not be NULL, so it must be at least
// 2 chars long (includes null).
//
// Optimized - since MAX_ILZERO is 2.
//
if ((cchData != MAX_ILZERO) ||
(*lpLCData < NLS_CHAR_ZERO) ||
(*lpLCData > MAX_CHAR_ILZERO))
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// Set the registry with the new ILZERO string.
//
return (SetUserInfo( NLS_VALUE_ILZERO,
pNlsUserInfo->iLZero,
(LPWSTR)lpLCData,
cchData ));
break;
}
case ( LOCALE_INEGNUMBER ) :
{
//
// Validate the new value. It should be no longer than
// MAX_INEGNUMBER wide characters in length.
// The value should be between 0 and MAX_VALUE_INEGNUMBER.
//
// NOTE: The string may not be NULL, so it must be at least
// 2 chars long (includes null).
//
// Optimized - since MAX_INEGNUMBER is 2.
//
if ((cchData != MAX_INEGNUMBER) ||
(*lpLCData < NLS_CHAR_ZERO) ||
(*lpLCData > MAX_CHAR_INEGNUMBER))
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// Set the registry with the new INEGNUMBER string.
//
return (SetUserInfo( NLS_VALUE_INEGNUMBER,
pNlsUserInfo->iNegNumber,
(LPWSTR)lpLCData,
cchData ));
break;
}
case ( LOCALE_SCURRENCY ) :
{
//
// Validate the new value. It should be no longer than
// MAX_SCURRENCY wide characters in length and should not
// contain any integer values (L'0' thru L'9').
//
if (!IsValidSeparatorString( lpLCData,
MAX_SCURRENCY,
FALSE ))
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// Set the registry with the new SCURRENCY string.
//
return (SetUserInfo( NLS_VALUE_SCURRENCY,
pNlsUserInfo->sCurrency,
(LPWSTR)lpLCData,
cchData ));
break;
}
case ( LOCALE_SMONDECIMALSEP ) :
{
//
// Validate the new value. It should be no longer than
// MAX_SMONDECSEP wide characters in length and should not
// contain any integer values (L'0' thru L'9').
//
if (!IsValidSeparatorString( lpLCData,
MAX_SMONDECSEP,
FALSE ))
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// Set the registry with the new SMONDECIMALSEP string.
//
return (SetUserInfo( NLS_VALUE_SMONDECIMALSEP,
pNlsUserInfo->sMonDecSep,
(LPWSTR)lpLCData,
cchData ));
break;
}
case ( LOCALE_SMONTHOUSANDSEP ) :
{
//
// Validate the new value. It should be no longer than
// MAX_SMONTHOUSEP wide characters in length and should not
// contain any integer values (L'0' thru L'9').
//
if (!IsValidSeparatorString( lpLCData,
MAX_SMONTHOUSEP,
FALSE ))
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// Set the registry with the new SMONTHOUSANDSEP string.
//
return (SetUserInfo( NLS_VALUE_SMONTHOUSANDSEP,
pNlsUserInfo->sMonThouSep,
(LPWSTR)lpLCData,
cchData ));
break;
}
case ( LOCALE_SMONGROUPING ) :
{
//
// Validate the new value. It should be exactly
// MAX_SMONGROUPING (4) wide characters in length.
// The 1st value should be between 0 and MAX_VALUE_SMONGROUPING.
// The 2nd char should be a semicolon and the 3rd char
// should be integer 0.
//
// NOTE: The string may not be NULL, so it must be at least
// 2 chars long (includes null).
//
if ((cchData != MAX_SMONGROUPING) ||
(*lpLCData < NLS_CHAR_ZERO) ||
(*lpLCData > MAX_CHAR_SMONGROUPING) ||
(*(lpLCData + 1) != NLS_CHAR_SEMICOLON) ||
(*(lpLCData + 2) != NLS_CHAR_ZERO))
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// Set the registry with the new SMONGROUPING string.
//
return (SetUserInfo( NLS_VALUE_SMONGROUPING,
pNlsUserInfo->sMonGrouping,
(LPWSTR)lpLCData,
cchData ));
break;
}
case ( LOCALE_ICURRDIGITS ) :
{
//
// Validate the new value. It should be no longer than
// MAX_ICURRDIGITS wide characters in length.
// The value should be between 0 and MAX_VALUE_ICURRDIGITS.
//
// NOTE: The string may not be NULL, so it must be at least
// 2 chars long (includes null).
//
switch (cchData)
{
case ( 2 ) :
{
if ((*lpLCData < NLS_CHAR_ZERO) ||
(*lpLCData > NLS_CHAR_NINE))
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
break;
}
case ( 3 ) :
{
if ((*lpLCData < NLS_CHAR_ZERO) ||
(*lpLCData > MAX_CHAR_ICURRDIGITS_1) ||
(*(lpLCData + 1) < NLS_CHAR_ZERO) ||
(*(lpLCData + 1) > MAX_CHAR_ICURRDIGITS_2))
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
break;
}
case ( 0 ) :
case ( 1 ) :
default :
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
}
//
// Set the registry with the new ICURRDIGITS string.
//
return (SetUserInfo( NLS_VALUE_ICURRDIGITS,
pNlsUserInfo->iCurrDigits,
(LPWSTR)lpLCData,
cchData ));
break;
}
case ( LOCALE_ICURRENCY ) :
{
//
// Validate the new value. It should be no longer than
// MAX_ICURRENCY wide characters in length.
// The value should be between 0 and MAX_VALUE_ICURRENCY.
//
// NOTE: The string may not be NULL, so it must be at least
// 2 chars long (includes null).
//
// Optimized - since MAX_ICURRENCY is 2.
//
if ((cchData != MAX_ICURRENCY) ||
(*lpLCData < NLS_CHAR_ZERO) ||
(*lpLCData > MAX_CHAR_ICURRENCY))
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// Set the registry with the new ICURRENCY string.
//
return (SetUserInfo( NLS_VALUE_ICURRENCY,
pNlsUserInfo->iCurrency,
(LPWSTR)lpLCData,
cchData ));
break;
}
case ( LOCALE_INEGCURR ) :
{
//
// Validate the new value. It should be no longer than
// MAX_INEGCURR wide characters in length.
// The value should be between 0 and MAX_VALUE_INEGCURR.
//
// NOTE: The string may not be NULL, so it must be at least
// 2 chars long (includes null).
//
switch (cchData)
{
case ( 2 ) :
{
if ((*lpLCData < NLS_CHAR_ZERO) ||
(*lpLCData > NLS_CHAR_NINE))
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
break;
}
case ( 3 ) :
{
if ((*lpLCData < NLS_CHAR_ZERO) ||
(*lpLCData > MAX_CHAR_INEGCURR_1) ||
(*(lpLCData + 1) < NLS_CHAR_ZERO) ||
(*(lpLCData + 1) > MAX_CHAR_INEGCURR_2))
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
break;
}
case ( 0 ) :
case ( 1 ) :
default :
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
}
//
// Set the registry with the new INEGCURR string.
//
return (SetUserInfo( NLS_VALUE_INEGCURR,
pNlsUserInfo->iNegCurr,
(LPWSTR)lpLCData,
cchData ));
break;
}
case ( LOCALE_SPOSITIVESIGN ) :
{
//
// Validate the new value. It should be no longer than
// MAX_SPOSSIGN wide characters in length and should not
// contain any integer values (L'0' thru L'9').
//
if (!IsValidSeparatorString( lpLCData,
MAX_SPOSSIGN,
FALSE ))
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// Set the registry with the new SPOSITIVESIGN string.
//
return (SetUserInfo( NLS_VALUE_SPOSITIVESIGN,
pNlsUserInfo->sPosSign,
(LPWSTR)lpLCData,
cchData ));
break;
}
case ( LOCALE_SNEGATIVESIGN ) :
{
//
// Validate the new value. It should be no longer than
// MAX_SNEGSIGN wide characters in length and should not
// contain any integer values (L'0' thru L'9').
//
if (!IsValidSeparatorString( lpLCData,
MAX_SNEGSIGN,
FALSE ))
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// Set the registry with the new SNEGATIVESIGN string.
//
return (SetUserInfo( NLS_VALUE_SNEGATIVESIGN,
pNlsUserInfo->sNegSign,
(LPWSTR)lpLCData,
cchData ));
break;
}
case ( LOCALE_STIMEFORMAT ) :
{
//
// Validate the new value. It should be no longer than
// MAX_STIMEFORMAT wide characters in length.
//
// NOTE: The string may not be NULL, so it must be at least
// 2 chars long (includes null). This is checked below
// in the check for whether or not there is an hour
// delimeter.
//
if (cchData > MAX_STIMEFORMAT)
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// NOTE: Must link the STIME, ITIME, ITLZERO, and
// ITIMEMARKPOSN values in the registry.
//
//
// Search for H or h, so that iTime and iTLZero can be
// set. If no H or h exists, return an error.
//
pPos = wcspbrk(lpLCData, L"Hh");
if (!pPos)
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// Get the appropriate ITIME value.
//
Order = (*pPos == L'h') ? 0 : 1;
//
// Get the appropriate ITLZERO value.
//
TLZero = ((*(pPos + 1) != L'h') && (*(pPos + 1) != L'H')) ? 0 : 1;
//
// Search for tt, so that ITIMEMARKPOSN can be
// set. If no tt exists, do not change the value.
//
pPos = (LPWSTR)lpLCData;
while ((pPos = wcspbrk(pPos, L"t")) && (*(pPos + 1) != L't'))
{
pPos++;
}
if (pPos)
{
//
// Get the appropriate ITIMEMARKPOSN value.
//
pPos2 = wcspbrk(lpLCData, L"Hhmst");
TimeMarkPosn = (pPos == pPos2) ? 1 : 0;
}
//
// Find the time separator so that STIME can be set.
//
pPos = (LPWSTR)lpLCData;
while (pPos = wcspbrk(pPos, L"Hhms"))
{
//
// Go to next position past sequence of H, h, m, or s.
//
pPos++;
while ((*pPos) && (wcschr( L"Hhms", *pPos )))
{
pPos++;
}
if (*pPos)
{
//
// Find the end of the separator string.
//
pPos2 = wcspbrk(pPos, L"Hhmst");
if (pPos2)
{
if (*pPos2 == L't')
{
//
// Found a time marker, so need to start over
// in search for separator. There are no
// separators around the time marker.
//
pPos = pPos2 + 1;
}
else
{
//
// Found end of separator, so break out of
// while loop.
//
break;
}
}
}
}
//
// Get the appropriate STIME string.
//
if (pPos)
{
//
// Copy to temp buffer so that it's zero terminated.
//
pString = pTemp;
while (pPos != pPos2)
{
*pString = *pPos;
pPos++;
pString++;
}
*pString = 0;
}
else
{
//
// There is no time separator, so use NULL.
//
*pTemp = 0;
}
//
// Call the server to set the registry.
//
return (SetMultipleUserInfo( LCType,
cchData,
lpLCData,
pTemp,
(Order == 0) ? L"0" : L"1",
(TLZero == 0) ? L"0" : L"1",
(TimeMarkPosn == 0) ? L"0" : L"1" ));
break;
}
case ( LOCALE_STIME ) :
{
//
// NOTE: Must link the STIMEFORMAT value in the registry.
//
//
// Validate the new value. It should be no longer than
// MAX_STIME wide characters in length and should not
// contain any integer values (L'0' thru L'9').
//
// NOTE: The string may not be NULL, so it must be at least
// 2 chars long (includes null).
//
if (!IsValidSeparatorString( lpLCData,
MAX_STIME,
TRUE ))
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// Make sure that the time separator does NOT contain any
// of the special time picture characters - h, H, m, s, t, '.
//
if (wcspbrk(lpLCData, L"Hhmst'"))
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// Get the current setting for STIMEFORMAT.
//
if (GetUserInfo( Locale,
pNlsUserInfo->sTimeFormat,
pOutput,
TRUE ))
{
pString = pOutput;
}
else
{
pString = (LPWORD)(pHashN->pLocaleHdr) +
pHashN->pLocaleHdr->STimeFormat;
}
//
// Get the current setting for STIME.
//
if (GetUserInfo( Locale,
pNlsUserInfo->sTime,
pOutput2,
TRUE ))
{
pSep = pOutput2;
}
else
{
pSep = (LPWORD)(pHashN->pLocaleHdr) +
pHashN->pLocaleHdr->STime;
}
//
// Get the length of the separator string.
//
SepLen = NlsStrLenW(pSep);
//
// Setup the string containing the characters to find in
// the timeformat string.
//
pFind[0] = NLS_CHAR_QUOTE;
pFind[1] = *pSep;
pFind[2] = 0;
//
// Find the time separator in the STIMEFORMAT string and
// replace it with the new time separator.
//
// The new separator may be a different length than
// the old one, so must use a static buffer for the new
// time format string.
//
pPos = pTemp;
while (pPos2 = wcspbrk(pString, pFind))
{
//
// Copy format string up to pPos2.
//
while (pString < pPos2)
{
*pPos = *pString;
pPos++;
pString++;
}
switch (*pPos2)
{
case ( NLS_CHAR_QUOTE ) :
{
//
// Copy the quote.
//
*pPos = *pString;
pPos++;
pString++;
//
// Copy what's inside the quotes.
//
while ((*pString) && (*pString != NLS_CHAR_QUOTE))
{
*pPos = *pString;
pPos++;
pString++;
}
//
// Copy the end quote.
//
*pPos = NLS_CHAR_QUOTE;
pPos++;
if (*pString)
{
pString++;
}
break;
}
default :
{
//
// Make sure it's the old separator.
//
if (NlsStrNEqualW(pString, pSep, SepLen))
{
//
// Adjust pointer to skip over old separator.
//
pString += SepLen;
//
// Copy the new separator.
//
pPos2 = (LPWSTR)lpLCData;
while (*pPos2)
{
*pPos = *pPos2;
pPos++;
pPos2++;
}
}
else
{
//
// Copy the code point and continue.
//
*pPos = *pString;
pPos++;
pString++;
}
break;
}
}
}
//
// Copy to the end of the string and null terminate it.
//
while (*pString)
{
*pPos = *pString;
pPos++;
pString++;
}
*pPos = 0;
//
// Call the server to set the registry.
//
return (SetMultipleUserInfo( LCType,
cchData,
pTemp,
lpLCData,
NULL,
NULL,
NULL ));
break;
}
case ( LOCALE_ITIME ) :
{
//
// NOTE: Must link the STIMEFORMAT value in the registry.
//
//
// Validate the new value. It should be no longer than
// MAX_ITIME wide characters in length.
// The value should be either 0 or MAX_VALUE_ITIME.
//
// NOTE: The string may not be NULL, so it must be at least
// 2 chars long (includes null).
//
// Optimized - since MAX_ITIME is 2.
//
if ((cchData != MAX_ITIME) ||
(*lpLCData < NLS_CHAR_ZERO) ||
(*lpLCData > MAX_CHAR_ITIME))
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// Get the current setting for STIMEFORMAT.
//
if (GetUserInfo( Locale,
pNlsUserInfo->sTimeFormat,
pOutput,
TRUE ))
{
pString = pOutput;
}
else
{
//
// Copy system default to temp buffer.
//
NlsStrCpyW( pTemp,
(LPWORD)(pHashN->pLocaleHdr) +
pHashN->pLocaleHdr->STimeFormat );
pString = pTemp;
}
//
// Search down the STIMEFORMAT string.
// If iTime = 0, then H -> h.
// If iTime = 1, then h -> H.
//
pPos = pString;
if (*lpLCData == NLS_CHAR_ZERO)
{
while (*pPos)
{
if (*pPos == L'H')
{
*pPos = L'h';
}
pPos++;
}
}
else
{
while (*pPos)
{
if (*pPos == L'h')
{
*pPos = L'H';
}
pPos++;
}
}
//
// Call the server to set the registry.
//
return (SetMultipleUserInfo( LCType,
cchData,
pString,
NULL,
lpLCData,
NULL,
NULL ));
break;
}
case ( LOCALE_S1159 ) :
{
//
// Validate the new value. It should be no longer than
// MAX_S1159 wide characters in length.
//
if (cchData > MAX_S1159)
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// Set the registry with the new S1159 string.
//
return (SetUserInfo( NLS_VALUE_S1159,
pNlsUserInfo->s1159,
(LPWSTR)lpLCData,
cchData ));
break;
}
case ( LOCALE_S2359 ) :
{
//
// Validate the new value. It should be no longer than
// MAX_S2359 wide characters in length.
//
if (cchData > MAX_S2359)
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// Set the registry with the new S2359 string.
//
return (SetUserInfo( NLS_VALUE_S2359,
pNlsUserInfo->s2359,
(LPWSTR)lpLCData,
cchData ));
break;
}
case ( LOCALE_SSHORTDATE ) :
{
//
// Validate the new value. It should be no longer than
// MAX_SSHORTDATE wide characters in length.
//
// NOTE: The string may not be NULL, so it must be at least
// 2 chars long (includes null). This is checked below
// in the check for whether or not there is a date,
// month, or year delimeter.
//
if (cchData > MAX_SSHORTDATE)
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// NOTE: Must link the IDATE and SDATE values in the registry.
//
//
// Search for the 'd' or 'M' or 'y' sequence in the date format
// string to set the new IDATE value.
//
// If none of these symbols exist in the date format string,
// then return an error.
//
pPos = wcspbrk(lpLCData, L"dMy");
if (!pPos)
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// Set the registry with the appropriate IDATE string.
//
switch (*pPos)
{
case ( L'M' ) :
{
Order = 0;
break;
}
case ( L'd' ) :
{
Order = 1;
break;
}
case ( L'y' ) :
{
Order = 2;
break;
}
}
//
// Set the registry with the appropriate SDATE string.
//
// The ptr "pPos" is pointing at either d, M, or y.
// Go to the next position past sequence of d, M, or y.
//
pPos++;
while ((*pPos) && (wcschr( L"dMy", *pPos )))
{
pPos++;
}
*pTemp = 0;
if (*pPos)
{
//
// Find the end of the separator string.
//
pPos2 = wcspbrk(pPos, L"dMy");
if (pPos2)
{
//
// Copy to temp buffer so that it's zero terminated.
//
pString = pTemp;
while (pPos != pPos2)
{
*pString = *pPos;
pPos++;
pString++;
}
*pString = 0;
}
}
//
// Call the server to set the registry.
//
return (SetMultipleUserInfo( LCType,
cchData,
lpLCData,
pTemp,
(Order == 0) ? L"0" :
((Order == 1) ? L"1" : L"2"),
NULL,
NULL ));
break;
}
case ( LOCALE_SDATE ) :
{
//
// NOTE: Must link the SSHORTDATE value in the registry.
//
//
// Validate the new value. It should be no longer than
// MAX_SDATE wide characters in length and should not
// contain any integer values (L'0' thru L'9').
//
// NOTE: The string may not be NULL, so it must be at least
// 2 chars long (includes null).
//
if (!IsValidSeparatorString( lpLCData,
MAX_SDATE,
TRUE ))
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// Make sure that the date separator does NOT contain any
// of the special date picture characters - d, M, y, g, '.
//
if (wcspbrk(lpLCData, L"dMyg'"))
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// Get the current setting for SSHORTDATE.
//
if (GetUserInfo( Locale,
pNlsUserInfo->sShortDate,
pOutput,
TRUE ))
{
pString = pOutput;
}
else
{
pString = (LPWORD)(pHashN->pLocaleHdr) +
pHashN->pLocaleHdr->SShortDate;
}
//
// Get the current setting for SDATE.
//
if (GetUserInfo( Locale,
pNlsUserInfo->sDate,
pOutput2,
TRUE ))
{
pSep = pOutput2;
}
else
{
pSep = (LPWORD)(pHashN->pLocaleHdr) +
pHashN->pLocaleHdr->SDate;
}
//
// Get the length of the separator string.
//
SepLen = NlsStrLenW(pSep);
//
// Setup the string containing the characters to find in
// the shortdate string.
//
pFind[0] = NLS_CHAR_QUOTE;
pFind[1] = *pSep;
pFind[2] = 0;
//
// Find the date separator in the SSHORTDATE string and
// replace it with the new date separator.
//
// The new separator may be a different length than
// the old one, so must use a static buffer for the new
// short date format string.
//
pPos = pTemp;
while (pPos2 = wcspbrk(pString, pFind))
{
//
// Copy format string up to pPos2.
//
while (pString < pPos2)
{
*pPos = *pString;
pPos++;
pString++;
}
switch (*pPos2)
{
case ( NLS_CHAR_QUOTE ) :
{
//
// Copy the quote.
//
*pPos = *pString;
pPos++;
pString++;
//
// Copy what's inside the quotes.
//
while ((*pString) && (*pString != NLS_CHAR_QUOTE))
{
*pPos = *pString;
pPos++;
pString++;
}
//
// Copy the end quote.
//
*pPos = NLS_CHAR_QUOTE;
pPos++;
if (*pString)
{
pString++;
}
break;
}
default :
{
//
// Make sure it's the old separator.
//
if (NlsStrNEqualW(pString, pSep, SepLen))
{
//
// Adjust pointer to skip over old separator.
//
pString += SepLen;
//
// Copy the new separator.
//
pPos2 = (LPWSTR)lpLCData;
while (*pPos2)
{
*pPos = *pPos2;
pPos++;
pPos2++;
}
}
else
{
//
// Copy the code point and continue.
//
*pPos = *pString;
pPos++;
pString++;
}
break;
}
}
}
//
// Copy to the end of the string and null terminate it.
//
while (*pString)
{
*pPos = *pString;
pPos++;
pString++;
}
*pPos = 0;
//
// Call the server to set the registry.
//
return (SetMultipleUserInfo( LCType,
cchData,
pTemp,
lpLCData,
NULL,
NULL,
NULL ));
break;
}
case ( LOCALE_SLONGDATE ) :
{
//
// Validate the new value. It should be no longer than
// MAX_SLONGDATE wide characters in length.
//
// NOTE: The string may not be NULL, so it must be at least
// 2 chars long (includes null). This is checked below
// in the check for whether or not there is a date,
// month, or year delimeter.
//
if (cchData > MAX_SLONGDATE)
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// Make sure one of 'd' or 'M' or 'y' exists in the date
// format string. If it does not, then return an error.
//
pPos = wcspbrk(lpLCData, L"dMy");
if (!pPos)
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// Set the registry with the new SLONGDATE string.
//
return (SetUserInfo( NLS_VALUE_SLONGDATE,
pNlsUserInfo->sLongDate,
(LPWSTR)lpLCData,
cchData ));
break;
}
case ( LOCALE_ICALENDARTYPE ) :
{
//
// Validate the new value. It should be no longer than
// MAX_ICALTYPE wide characters in length.
//
//
// NOTE: The string may not be NULL, so it must be at least
// 2 chars long (includes null).
//
// Optimized - since MAX_ICALTYPE is 2.
//
if ((cchData != MAX_ICALTYPE) ||
(!IsValidCalendarTypeStr( pHashN,
lpLCData )))
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// Set the registry with the new ICALENDARTYPE string.
//
return (SetUserInfo( NLS_VALUE_ICALENDARTYPE,
pNlsUserInfo->iCalType,
(LPWSTR)lpLCData,
cchData ));
break;
}
case ( LOCALE_IFIRSTDAYOFWEEK ) :
{
//
// Validate the new value. It should be no longer than
// MAX_IFIRSTDAY wide characters in length.
// The value should be between 0 and MAX_VALUE_IFIRSTDAY.
//
// NOTE: The string may not be NULL, so it must be at least
// 2 chars long (includes null).
//
// Optimized - since MAX_IFIRSTDAY is 2.
//
if ((cchData != MAX_IFIRSTDAY) ||
(*lpLCData < NLS_CHAR_ZERO) ||
(*lpLCData > MAX_CHAR_IFIRSTDAY))
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// Set the registry with the new IFIRSTDAYOFWEEK string.
//
return (SetUserInfo( NLS_VALUE_IFIRSTDAYOFWEEK,
pNlsUserInfo->iFirstDay,
(LPWSTR)lpLCData,
cchData ));
break;
}
case ( LOCALE_IFIRSTWEEKOFYEAR ) :
{
//
// Validate the new value. It should be no longer than
// MAX_IFIRSTWEEK wide characters in length.
// The value should be between 0 and MAX_VALUE_IFIRSTWEEK.
//
// NOTE: The string may not be NULL, so it must be at least
// 2 chars long (includes null).
//
// Optimized - since MAX_IFIRSTWEEK is 2.
//
if ((cchData != MAX_IFIRSTWEEK) ||
(*lpLCData < NLS_CHAR_ZERO) ||
(*lpLCData > MAX_CHAR_IFIRSTWEEK))
{
SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// Set the registry with the new IFIRSTWEEKOFYEAR string.
//
return (SetUserInfo( NLS_VALUE_IFIRSTWEEKOFYEAR,
pNlsUserInfo->iFirstWeek,
(LPWSTR)lpLCData,
cchData ));
break;
}
default :
{
SetLastError(ERROR_INVALID_FLAGS);
return (FALSE);
}
}
//
// Return success.
//
return (TRUE);
}
//-------------------------------------------------------------------------//
// INTERNAL ROUTINES //
//-------------------------------------------------------------------------//
////////////////////////////////////////////////////////////////////////////
//
// GetLocalizedLanguageName
//
// Returns the localized version of the language name for the given language
// id. It gets the information from the resource file in the language that
// the current user is using.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
int GetLocalizedLanguageName(
LANGID Language,
LPWSTR *ppLangName)
{
HANDLE hFindRes; // handle from find resource
HANDLE hLoadRes; // handle from load resource
LANGID LangId; // language id
LPWSTR pSearch; // ptr to search for correct string
int cch = 0; // count of characters
//
// String Tables are broken up into 16 string segments. Find the
// resource containing the string we want.
//
LangId = LANGIDFROMLCID(pNlsUserInfo->UserLocaleId);
if ((!(hFindRes = FindResourceExW(
hModule,
RT_STRING,
(LPWSTR)((LONG)(((USHORT)Language >> 4) + 1)),
(WORD)LangId ))))
{
//
// Could not find resource. Try NEUTRAL language id.
//
if ((!(hFindRes = FindResourceExW(
hModule,
RT_STRING,
(LPWSTR)((LONG)(((USHORT)Language >> 4) + 1)),
(WORD)0 ))))
{
//
// Could not find resource. Return 0.
//
return (cch);
}
}
//
// Load the resource.
//
hLoadRes = LoadResource(hModule, hFindRes);
//
// Lock the resource.
//
if (pSearch = (LPWSTR)LockResource(hLoadRes))
{
//
// Move past the other strings in this segment.
// (16 strings in a segment -> & 0x0F)
//
Language &= 0x0F;
//
// Find the correct string in this segment.
//
while (TRUE)
{
cch = *((WORD *)pSearch++);
if (Language-- == 0)
break;
pSearch += cch;
}
//
// Store the found pointer in the given language name pointer.
//
*ppLangName = pSearch;
}
//
// Return the number of characters in the string.
//
return (cch);
}
////////////////////////////////////////////////////////////////////////////
//
// GetLocalizedCountryName
//
// Returns the localized version of the country name for the given language
// id. It gets the information from the resource file in the language that
// the current user is using.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
BOOL GetLocalizedCountryName(
LANGID Language,
LPWSTR *ppCtryName)
{
HANDLE hFindRes; // handle from find resource
HANDLE hLoadRes; // handle from load resource
LANGID LangId; // language id
//
// Find the resource.
//
LangId = LANGIDFROMLCID(pNlsUserInfo->UserLocaleId);
if ((!(hFindRes = FindResourceExW( hModule,
RT_RCDATA,
MAKEINTRESOURCEW(Language),
(WORD)LangId ))))
{
//
// Could not find resource. Try NEUTRAL language id.
//
if ((!(hFindRes = FindResourceExW( hModule,
RT_RCDATA,
MAKEINTRESOURCEW(Language),
(WORD)0 ))))
{
//
// Could not find resource. Return failure.
//
return (FALSE);
}
}
//
// Load the resource.
//
if (hLoadRes = LoadResource(hModule, hFindRes))
{
//
// Lock the resource. Store the found pointer in the given
// country name pointer.
//
if (*ppCtryName = (LPWSTR)LockResource(hLoadRes))
{
return (TRUE);
}
}
//
// Return failure.
//
return (FALSE);
}
////////////////////////////////////////////////////////////////////////////
//
// SetUserInfo
//
// This routine sets the given value in the registry with the given data.
// All values must be of the type REG_SZ.
//
// NOTE: The handle to the registry key must be closed by the CALLER if
// the return value is NO_ERROR.
//
// 07-14-93 JulieB Created.
////////////////////////////////////////////////////////////////////////////
BOOL SetUserInfo(
LPWSTR pValue,
LPWSTR pCacheString,
LPWSTR pData,
ULONG DataLength)
{
ULONG ValueLength; // length of value string
BASE_API_MSG m;
PBASE_NLS_SET_USER_INFO_MSG a = &m.u.NlsSetUserInfo;
PCSR_CAPTURE_HEADER CaptureBuffer;
//
// Get the length of the value string.
//
ValueLength = (NlsStrLenW(pValue) + 1) * sizeof(WCHAR);
DataLength *= sizeof(WCHAR);
//
// Get the capture buffer for the strings.
//
CaptureBuffer = CsrAllocateCaptureBuffer( 2,
0,
ValueLength + DataLength );
CsrCaptureMessageBuffer( CaptureBuffer,
(PCHAR)pValue,
ValueLength,
(PVOID *)&a->pValue );
CsrCaptureMessageBuffer( CaptureBuffer,
(PCHAR)pData,
DataLength,
(PVOID *)&a->pData );
//
// Save the pointer to the cache string.
//
a->pCacheString = pCacheString;
//
// Save the length of the data in the msg structure.
//
a->DataLength = DataLength;
//
// Call the server to set the registry value.
//
CsrClientCallServer( (PCSR_API_MSG)&m,
CaptureBuffer,
CSR_MAKE_API_NUMBER(BASESRV_SERVERDLL_INDEX,
BasepNlsSetUserInfo),
sizeof(*a) );
//
// Free the capture buffer.
//
if (CaptureBuffer != NULL)
{
CsrFreeCaptureBuffer(CaptureBuffer);
}
//
// Check to see if the "set" operation succeeded.
//
if (!NT_SUCCESS(m.ReturnValue))
{
SetLastError(ERROR_INVALID_ACCESS);
return (FALSE);
}
//
// Return success.
//
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// SetMultipleUserInfo
//
// This routine calls the server to set multiple registry values. This way,
// only one client/server transition is necessary.
//
// 08-19-94 JulieB Created.
////////////////////////////////////////////////////////////////////////////
BOOL SetMultipleUserInfo(
DWORD dwFlags,
int cchData,
LPCWSTR pPicture,
LPCWSTR pSeparator,
LPCWSTR pOrder,
LPCWSTR pTLZero,
LPCWSTR pTimeMarkPosn)
{
ULONG CaptureLength; // length of capture buffer
ULONG Length; // temp storage for length of string
BASE_API_MSG m;
PBASE_NLS_SET_MULTIPLE_USER_INFO_MSG a = &m.u.NlsSetMultipleUserInfo;
PCSR_CAPTURE_HEADER CaptureBuffer;
//
// Initialize the msg structure to NULL.
//
RtlZeroMemory(a, sizeof(BASE_NLS_SET_MULTIPLE_USER_INFO_MSG));
//
// Save the flags and the length of the data in the msg structure.
//
a->Flags = dwFlags;
a->DataLength = cchData * sizeof(WCHAR);
//
// Save the appropriate strings in the msg structure.
//
switch (dwFlags)
{
case ( LOCALE_STIMEFORMAT ) :
{
//
// Get the length of the capture buffer.
//
Length = NlsStrLenW(pSeparator) + 1;
CaptureLength = (cchData + Length + 2 + 2 + 2) * sizeof(WCHAR);
//
// Get the capture buffer for the strings.
//
CaptureBuffer = CsrAllocateCaptureBuffer( 5,
0,
CaptureLength );
CsrCaptureMessageBuffer( CaptureBuffer,
(PCHAR)pPicture,
cchData * sizeof(WCHAR),
(PVOID *)&a->pPicture );
CsrCaptureMessageBuffer( CaptureBuffer,
(PCHAR)pSeparator,
Length * sizeof(WCHAR),
(PVOID *)&a->pSeparator );
CsrCaptureMessageBuffer( CaptureBuffer,
(PCHAR)pOrder,
2 * sizeof(WCHAR),
(PVOID *)&a->pOrder );
CsrCaptureMessageBuffer( CaptureBuffer,
(PCHAR)pTLZero,
2 * sizeof(WCHAR),
(PVOID *)&a->pTLZero );
CsrCaptureMessageBuffer( CaptureBuffer,
(PCHAR)pTimeMarkPosn,
2 * sizeof(WCHAR),
(PVOID *)&a->pTimeMarkPosn );
break;
}
case ( LOCALE_STIME ) :
{
//
// Get the length of the capture buffer.
//
Length = NlsStrLenW(pPicture) + 1;
CaptureLength = (Length + cchData) * sizeof(WCHAR);
//
// Get the capture buffer for the strings.
//
CaptureBuffer = CsrAllocateCaptureBuffer( 2,
0,
CaptureLength );
CsrCaptureMessageBuffer( CaptureBuffer,
(PCHAR)pPicture,
Length * sizeof(WCHAR),
(PVOID *)&a->pPicture );
CsrCaptureMessageBuffer( CaptureBuffer,
(PCHAR)pSeparator,
cchData * sizeof(WCHAR),
(PVOID *)&a->pSeparator );
break;
}
case ( LOCALE_ITIME ) :
{
//
// Get the length of the capture buffer.
//
Length = NlsStrLenW(pPicture) + 1;
CaptureLength = (Length + cchData) * sizeof(WCHAR);
//
// Get the capture buffer for the strings.
//
CaptureBuffer = CsrAllocateCaptureBuffer( 2,
0,
CaptureLength );
CsrCaptureMessageBuffer( CaptureBuffer,
(PCHAR)pPicture,
Length * sizeof(WCHAR),
(PVOID *)&a->pPicture );
CsrCaptureMessageBuffer( CaptureBuffer,
(PCHAR)pOrder,
cchData * sizeof(WCHAR),
(PVOID *)&a->pOrder );
break;
}
case ( LOCALE_SSHORTDATE ) :
{
//
// Get the length of the capture buffer.
//
Length = NlsStrLenW(pSeparator) + 1;
CaptureLength = (cchData + Length + 2) * sizeof(WCHAR);
//
// Get the capture buffer for the strings.
//
CaptureBuffer = CsrAllocateCaptureBuffer( 3,
0,
CaptureLength );
CsrCaptureMessageBuffer( CaptureBuffer,
(PCHAR)pPicture,
cchData * sizeof(WCHAR),
(PVOID *)&a->pPicture );
CsrCaptureMessageBuffer( CaptureBuffer,
(PCHAR)pSeparator,
Length * sizeof(WCHAR),
(PVOID *)&a->pSeparator );
CsrCaptureMessageBuffer( CaptureBuffer,
(PCHAR)pOrder,
2 * sizeof(WCHAR),
(PVOID *)&a->pOrder );
break;
}
case ( LOCALE_SDATE ) :
{
//
// Get the length of the capture buffer.
//
Length = NlsStrLenW(pPicture) + 1;
CaptureLength = (Length + cchData) * sizeof(WCHAR);
//
// Get the capture buffer for the strings.
//
CaptureBuffer = CsrAllocateCaptureBuffer( 2,
0,
CaptureLength );
CsrCaptureMessageBuffer( CaptureBuffer,
(PCHAR)pPicture,
Length * sizeof(WCHAR),
(PVOID *)&a->pPicture );
CsrCaptureMessageBuffer( CaptureBuffer,
(PCHAR)pSeparator,
cchData * sizeof(WCHAR),
(PVOID *)&a->pSeparator );
break;
}
}
//
// Call the server to set the registry values.
//
CsrClientCallServer( (PCSR_API_MSG)&m,
CaptureBuffer,
CSR_MAKE_API_NUMBER( BASESRV_SERVERDLL_INDEX,
BasepNlsSetMultipleUserInfo ),
sizeof(*a) );
//
// Free the capture buffer.
//
if (CaptureBuffer != NULL)
{
CsrFreeCaptureBuffer(CaptureBuffer);
}
//
// Check to see if the "set" operation succeeded.
//
if (!NT_SUCCESS(m.ReturnValue))
{
SetLastError(ERROR_INVALID_ACCESS);
return (FALSE);
}
//
// Return success.
//
return (TRUE);
}