windows-nt/Source/XPSP1/NT/shell/osshell/cpls/intl/util.c
2020-09-26 16:20:57 +08:00

6458 lines
175 KiB
C

/*++
Copyright (c) 1994-2000, Microsoft Corporation All rights reserved.
Module Name:
util.c
Abstract:
This module implements the utility functions used by the Regional
Options applet.
Revision History:
--*/
//
// Include Files.
//
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <shlwapi.h>
#include "intl.h"
#include <tchar.h>
#include <windowsx.h>
#include <userenv.h>
#include <regstr.h>
#include "intlhlp.h"
#include "maxvals.h"
#include "winnlsp.h"
//
// Global Variables.
//
#ifdef UNICODE
#define NUM_CURRENCY_SYMBOLS 2
LPWSTR pCurrencySymbols[] =
{
L"$",
L"\x20ac"
};
#endif
#define NUM_DATE_SEPARATORS 3
LPTSTR pDateSeparators[] =
{
TEXT("/"),
TEXT("-"),
TEXT(".")
};
#define NUM_NEG_NUMBER_FORMATS 5
LPTSTR pNegNumberFormats[] =
{
TEXT("(1.1)"),
TEXT("-1.1"),
TEXT("- 1.1"),
TEXT("1.1-"),
TEXT("1.1 -")
};
#define NUM_POS_CURRENCY_FORMATS 4
LPTSTR pPosCurrencyFormats[] =
{
TEXT("¤1.1"),
TEXT("1.1¤"),
TEXT("¤ 1.1"),
TEXT("1.1 ¤")
};
#define NUM_NEG_CURRENCY_FORMATS 16
LPTSTR pNegCurrencyFormats[] =
{
TEXT("(¤1.1)"),
TEXT("-¤1.1"),
TEXT("¤-1.1"),
TEXT("¤1.1-"),
TEXT("(1.1¤)"),
TEXT("-1.1¤"),
TEXT("1.1-¤"),
TEXT("1.1¤-"),
TEXT("-1.1 ¤"),
TEXT("-¤ 1.1"),
TEXT("1.1 ¤-"),
TEXT("¤ 1.1-"),
TEXT("¤ -1.1"),
TEXT("1.1- ¤"),
TEXT("(¤ 1.1)"),
TEXT("(1.1 ¤)")
};
#define NUM_AM_SYMBOLS 1
LPTSTR pAMSymbols[] =
{
TEXT("AM")
};
#define NUM_PM_SYMBOLS 1
LPTSTR pPMSymbols[] =
{
TEXT("PM")
};
////////////////////////////////////////////////////////////////////////////
//
// Intl_StrToLong
//
// Returns the long integer value stored in the string. Since these
// values are coming back form the NLS API as ordinal values, do not
// worry about double byte characters.
//
////////////////////////////////////////////////////////////////////////////
LONG Intl_StrToLong(
LPTSTR szNum)
{
LONG Rtn_Val = 0;
while (*szNum)
{
Rtn_Val = (Rtn_Val * 10) + (*szNum - CHAR_ZERO);
szNum++;
}
return (Rtn_Val);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_FileExists
//
// Determines if the file exists and is accessible.
//
////////////////////////////////////////////////////////////////////////////
BOOL Intl_FileExists(
LPTSTR pFileName)
{
WIN32_FIND_DATA FindData;
HANDLE FindHandle;
BOOL bRet;
UINT OldMode;
OldMode = SetErrorMode(SEM_FAILCRITICALERRORS);
FindHandle = FindFirstFile(pFileName, &FindData);
if (FindHandle == INVALID_HANDLE_VALUE)
{
bRet = FALSE;
}
else
{
FindClose(FindHandle);
bRet = TRUE;
}
SetErrorMode(OldMode);
return (bRet);
}
////////////////////////////////////////////////////////////////////////////
//
// TransNum
//
// Converts a number string to a dword value (in hex).
//
////////////////////////////////////////////////////////////////////////////
DWORD TransNum(
LPTSTR lpsz)
{
DWORD dw = 0L;
TCHAR c;
while (*lpsz)
{
c = *lpsz++;
if (c >= TEXT('A') && c <= TEXT('F'))
{
c -= TEXT('A') - 0xa;
}
else if (c >= TEXT('0') && c <= TEXT('9'))
{
c -= TEXT('0');
}
else if (c >= TEXT('a') && c <= TEXT('f'))
{
c -= TEXT('a') - 0xa;
}
else
{
break;
}
dw *= 0x10;
dw += c;
}
return (dw);
}
////////////////////////////////////////////////////////////////////////////
//
// Item_Has_Digits
//
// Return true if the combo box specified by item in the property sheet
// specified by the dialog handle contains any digits.
//
////////////////////////////////////////////////////////////////////////////
BOOL Item_Has_Digits(
HWND hDlg,
int nItemId,
BOOL Allow_Empty)
{
TCHAR szBuf[SIZE_128];
LPTSTR lpszBuf = szBuf;
HWND hCtrl = GetDlgItem(hDlg, nItemId);
int dwIndex = ComboBox_GetCurSel(hCtrl);
//
// If there is no selection, get whatever is in the edit box.
//
if (dwIndex == CB_ERR)
{
dwIndex = GetDlgItemText(hDlg, nItemId, szBuf, SIZE_128);
if (dwIndex)
{
//
// Get text succeeded.
//
szBuf[dwIndex] = 0;
}
else
{
//
// Get text failed.
//
dwIndex = CB_ERR;
}
}
else
{
ComboBox_GetLBText(hCtrl, dwIndex, szBuf);
}
if (dwIndex != CB_ERR)
{
while (*lpszBuf)
{
#ifndef UNICODE
if (IsDBCSLeadByte(*lpszBuf))
{
//
// Skip 2 bytes in the array.
//
lpszBuf += 2;
}
else
#endif
{
if ((*lpszBuf >= CHAR_ZERO) && (*lpszBuf <= CHAR_NINE))
{
return (TRUE);
}
lpszBuf++;
}
}
return (FALSE);
}
//
// The data retrieval failed.
// If !Allow_Empty, just return TRUE.
//
return (!Allow_Empty);
}
////////////////////////////////////////////////////////////////////////////
//
// Item_Has_Digits_Or_Invalid_Chars
//
// Return true if the combo box specified by item in the property sheet
// specified by the dialog handle contains any digits or any of the
// given invalid characters.
//
////////////////////////////////////////////////////////////////////////////
BOOL Item_Has_Digits_Or_Invalid_Chars(
HWND hDlg,
int nItemId,
BOOL Allow_Empty,
LPTSTR pInvalid)
{
TCHAR szBuf[SIZE_128];
LPTSTR lpszBuf = szBuf;
HWND hCtrl = GetDlgItem(hDlg, nItemId);
int dwIndex = ComboBox_GetCurSel(hCtrl);
//
// If there is no selection, get whatever is in the edit box.
//
if (dwIndex == CB_ERR)
{
dwIndex = GetDlgItemText(hDlg, nItemId, szBuf, SIZE_128);
if (dwIndex)
{
//
// Get text succeeded.
//
szBuf[dwIndex] = 0;
}
else
{
//
// Get text failed.
//
dwIndex = CB_ERR;
}
}
else
{
dwIndex = ComboBox_GetLBText(hCtrl, dwIndex, szBuf);
}
if (dwIndex != CB_ERR)
{
while (*lpszBuf)
{
#ifndef UNICODE
if (IsDBCSLeadByte(*lpszBuf))
{
//
// Skip 2 bytes in the array.
//
lpszBuf += 2;
}
else
#endif
{
if ( ((*lpszBuf >= CHAR_ZERO) && (*lpszBuf <= CHAR_NINE)) ||
(_tcschr(pInvalid, *lpszBuf)) )
{
return (TRUE);
}
lpszBuf++;
}
}
return (FALSE);
}
//
// The data retrieval failed.
// If !Allow_Empty, just return TRUE.
//
return (!Allow_Empty);
}
////////////////////////////////////////////////////////////////////////////
//
// Item_Check_Invalid_Chars
//
// Return true if the input string contains any characters that are not in
// lpCkChars or in the string contained in the check id control combo box.
// If there is an invalid character and the character is contained in
// lpChgCase, change the invalid character's case so that it will be a
// vaild character.
//
////////////////////////////////////////////////////////////////////////////
BOOL Item_Check_Invalid_Chars(
HWND hDlg,
LPTSTR lpszBuf,
LPTSTR lpCkChars,
int nCkIdStr,
BOOL Allow_Empty,
LPTSTR lpChgCase,
int nItemId)
{
TCHAR szCkBuf[SIZE_128];
LPTSTR lpCCaseChar;
LPTSTR lpszSaveBuf = lpszBuf;
int nCkBufLen;
BOOL bInQuote = FALSE;
BOOL UpdateEditTest = FALSE;
HWND hCtrl = GetDlgItem(hDlg, nCkIdStr);
DWORD dwIndex = ComboBox_GetCurSel(hCtrl);
BOOL TextFromEditBox = (ComboBox_GetCurSel(GetDlgItem(hDlg, nItemId)) == CB_ERR);
if (!lpszBuf)
{
return (!Allow_Empty);
}
if (dwIndex != CB_ERR)
{
nCkBufLen = ComboBox_GetLBText(hCtrl, dwIndex, szCkBuf);
if (nCkBufLen == CB_ERR)
{
nCkBufLen = 0;
}
}
else
{
//
// No selection, so pull the string from the edit portion.
//
nCkBufLen = GetDlgItemText(hDlg, nCkIdStr, szCkBuf, SIZE_128);
szCkBuf[nCkBufLen] = 0;
}
while (*lpszBuf)
{
#ifndef UNICODE
if (IsDBCSLeadByte(*lpszBuf))
{
//
// If the the text is in the midst of a quote, skip it.
// Otherwise, if there is a string from the check ID to
// compare, determine if the current string is equal to the
// string in the combo box. If it is not equal, return true
// (there are invalid characters). Otherwise, skip the entire
// length of the "check" combo box's string in lpszBuf.
//
if (bInQuote)
{
lpszBuf += 2;
}
else if (nCkBufLen &&
lstrlen(lpszBuf) >= nCkBufLen)
{
if (CompareString( UserLocaleID,
0,
szCkBuf,
nCkBufLen,
lpszBuf,
nCkBufLen ) != CSTR_EQUAL)
{
//
// Invalid DB character.
//
return (TRUE);
}
lpszBuf += nCkBufLen;
}
}
else
#endif
{
if (bInQuote)
{
bInQuote = (*lpszBuf != CHAR_QUOTE);
lpszBuf++;
}
else if (_tcschr(lpCkChars, *lpszBuf))
{
lpszBuf++;
}
else if (TextFromEditBox &&
(lpCCaseChar = _tcschr(lpChgCase, *lpszBuf), lpCCaseChar))
{
*lpszBuf = lpCkChars[lpCCaseChar - lpChgCase];
UpdateEditTest = TRUE;
lpszBuf++;
}
else if (*lpszBuf == CHAR_QUOTE)
{
lpszBuf++;
bInQuote = TRUE;
}
else if ( (nCkBufLen) &&
(lstrlen(lpszBuf) >= nCkBufLen) &&
(CompareString( UserLocaleID,
0,
szCkBuf,
nCkBufLen,
lpszBuf,
nCkBufLen ) == CSTR_EQUAL) )
{
lpszBuf += nCkBufLen;
}
else
{
//
// Invalid character.
//
return (TRUE);
}
}
}
//
// Parsing passed.
// If the edit text changed, update edit box only if returning true.
//
if (!bInQuote && UpdateEditTest)
{
return (!SetDlgItemText(hDlg, nItemId, lpszSaveBuf));
}
//
// If there are unmatched quotes return TRUE. Otherwise, return FALSE.
//
if (bInQuote)
{
return (TRUE);
}
return (FALSE);
}
////////////////////////////////////////////////////////////////////////////
//
// No_Numerals_Error
//
// Display the no numerals allowed in "some control" error.
//
////////////////////////////////////////////////////////////////////////////
void No_Numerals_Error(
HWND hDlg,
int nItemId,
int iStrId)
{
TCHAR szBuf[SIZE_300];
TCHAR szBuf2[SIZE_128];
TCHAR szErrorMessage[SIZE_300+SIZE_128];
LoadString(hInstance, IDS_LOCALE_NO_NUMS_IN, szBuf, SIZE_300);
LoadString(hInstance, iStrId, szBuf2, SIZE_128);
wsprintf(szErrorMessage, szBuf, szBuf2);
MessageBox(hDlg, szErrorMessage, NULL, MB_OK | MB_ICONINFORMATION);
SetFocus(GetDlgItem(hDlg, nItemId));
}
////////////////////////////////////////////////////////////////////////////
//
// Invalid_Chars_Error
//
// Display the invalid chars in "some style" error.
//
////////////////////////////////////////////////////////////////////////////
void Invalid_Chars_Error(
HWND hDlg,
int nItemId,
int iStrId)
{
TCHAR szBuf[SIZE_300];
TCHAR szBuf2[SIZE_128];
TCHAR szErrorMessage[SIZE_300+SIZE_128];
LoadString(hInstance, IDS_LOCALE_STYLE_ERR, szBuf, SIZE_300);
LoadString(hInstance, iStrId, szBuf2, SIZE_128);
wsprintf(szErrorMessage, szBuf, szBuf2);
MessageBox(hDlg, szErrorMessage, NULL, MB_OK | MB_ICONINFORMATION);
SetFocus(GetDlgItem(hDlg, nItemId));
}
////////////////////////////////////////////////////////////////////////////
//
// Localize_Combobox_Styles
//
// Transform either all date or time style, as indicated by LCType, in
// the indicated combobox from a value that the NLS will provide to a
// localized value.
//
////////////////////////////////////////////////////////////////////////////
void Localize_Combobox_Styles(
HWND hDlg,
int nItemId,
LCTYPE LCType)
{
BOOL bInQuote = FALSE;
BOOL Map_Char = TRUE;
TCHAR szBuf1[SIZE_128];
TCHAR szBuf2[SIZE_128];
LPTSTR lpszInBuf = szBuf1;
LPTSTR lpszOutBuf = szBuf2;
HWND hCtrl = GetDlgItem(hDlg, nItemId);
DWORD ItemCnt = ComboBox_GetCount(hCtrl);
DWORD Position = 0;
DWORD dwIndex;
if (!Styles_Localized)
{
return;
}
while (Position < ItemCnt)
{
//
// Could check character count with CB_GETLBTEXTLEN to make sure
// that the item text will fit in 128, but max values for these
// items is 79 chars.
//
dwIndex = ComboBox_GetLBText(hCtrl, Position, szBuf1);
if (dwIndex != CB_ERR)
{
lpszInBuf = szBuf1;
lpszOutBuf = szBuf2;
while (*lpszInBuf)
{
Map_Char = TRUE;
#ifndef UNICODE
if (IsDBCSLeadByte(*lpszInBuf))
{
//
// Copy any double byte character straight through.
//
*lpszOutBuf++ = *lpszInBuf++;
*lpszOutBuf++ = *lpszInBuf++;
}
else
#endif
{
if (*lpszInBuf == CHAR_QUOTE)
{
bInQuote = !bInQuote;
*lpszOutBuf++ = *lpszInBuf++;
}
else
{
if (!bInQuote)
{
if (LCType == LOCALE_STIMEFORMAT ||
LCType == LOCALE_SLONGDATE)
{
Map_Char = FALSE;
if (CompareString( UserLocaleID,
0,
lpszInBuf,
1,
TEXT("H"),
1 ) == CSTR_EQUAL)
{
*lpszOutBuf++ = szStyleH[0];
#ifndef UNICODE
if (IsDBCSLeadByte(*szStyleH))
{
*lpszOutBuf++ = szStyleH[1];
}
#endif
}
else if (CompareString( UserLocaleID,
0,
lpszInBuf,
1,
TEXT("h"),
1 ) == CSTR_EQUAL)
{
*lpszOutBuf++ = szStyleh[0];
#ifndef UNICODE
if (IsDBCSLeadByte(*szStyleh))
{
*lpszOutBuf++ = szStyleh[1];
}
#endif
}
else if (CompareString( UserLocaleID,
0,
lpszInBuf,
1,
TEXT("m"),
1 ) == CSTR_EQUAL)
{
*lpszOutBuf++ = szStylem[0];
#ifndef UNICODE
if (IsDBCSLeadByte(*szStylem))
{
*lpszOutBuf++ = szStylem[1];
}
#endif
}
else if (CompareString( UserLocaleID,
0,
lpszInBuf,
1,
TEXT("s"),
1 ) == CSTR_EQUAL)
{
*lpszOutBuf++ = szStyles[0];
#ifndef UNICODE
if (IsDBCSLeadByte(*szStyles))
{
*lpszOutBuf++ = szStyles[1];
}
#endif
}
else if (CompareString( UserLocaleID,
0,
lpszInBuf,
1,
TEXT("t"),
1 ) == CSTR_EQUAL)
{
*lpszOutBuf++ = szStylet[0];
#ifndef UNICODE
if (IsDBCSLeadByte(*szStylet))
{
*lpszOutBuf++ = szStylet[1];
}
#endif
}
else
{
Map_Char = TRUE;
}
}
if (LCType == LOCALE_SSHORTDATE ||
(LCType == LOCALE_SLONGDATE && Map_Char))
{
Map_Char = FALSE;
if (CompareString( UserLocaleID,
0,
lpszInBuf,
1,
TEXT("d"),
1 ) == CSTR_EQUAL)
{
*lpszOutBuf++ = szStyled[0];
#ifndef UNICODE
if (IsDBCSLeadByte(*szStyled))
{
*lpszOutBuf++ = szStyled[1];
}
#endif
}
else if (CompareString( UserLocaleID,
0,
lpszInBuf,
1,
TEXT("M"),
1 ) == CSTR_EQUAL)
{
*lpszOutBuf++ = szStyleM[0];
#ifndef UNICODE
if (IsDBCSLeadByte(*szStyleM))
{
*lpszOutBuf++ = szStyleM[1];
}
#endif
}
else if (CompareString( UserLocaleID,
0,
lpszInBuf,
1,
TEXT("y"),
1 ) == CSTR_EQUAL)
{
*lpszOutBuf++ = szStyley[0];
#ifndef UNICODE
if (IsDBCSLeadByte(*szStyley))
{
*lpszOutBuf++ = szStyley[1];
}
#endif
}
else
{
Map_Char = TRUE;
}
}
}
if (Map_Char)
{
*lpszOutBuf++ = *lpszInBuf++;
}
else
{
lpszInBuf++;
}
}
}
}
//
// Append null to localized string.
//
*lpszOutBuf = 0;
ComboBox_DeleteString(hCtrl, Position);
ComboBox_InsertString(hCtrl, Position, szBuf2);
}
Position++;
}
}
////////////////////////////////////////////////////////////////////////////
//
// NLSize_Style
//
// Transform either date or time style, as indicated by LCType, from a
// localized value to one that the NLS API will recognize.
//
////////////////////////////////////////////////////////////////////////////
BOOL NLSize_Style(
HWND hDlg,
int nItemId,
LPTSTR lpszOutBuf,
LCTYPE LCType)
{
BOOL bInQuote = FALSE;
BOOL Map_Char = TRUE;
TCHAR szBuf[SIZE_128];
LPTSTR lpszInBuf = szBuf;
LPTSTR lpNLSChars1;
LPTSTR lpNLSChars2;
HWND hCtrl = GetDlgItem(hDlg, nItemId);
DWORD dwIndex = ComboBox_GetCurSel(hCtrl);
BOOL TextFromEditBox = dwIndex == CB_ERR;
int Cmp_Size;
#ifndef UNICODE
BOOL Is_Dbl = FALSE;
#endif
//
// If there is no selection, get whatever is in the edit box.
//
if (TextFromEditBox)
{
dwIndex = GetDlgItemText(hDlg, nItemId, szBuf, SIZE_128);
if (dwIndex)
{
//
// Get text succeeded.
//
szBuf[dwIndex] = 0;
}
else
{
//
// Get text failed.
//
dwIndex = (DWORD)CB_ERR;
}
}
else
{
dwIndex = ComboBox_GetLBText(hCtrl, dwIndex, szBuf);
}
if (!Styles_Localized)
{
lstrcpy(lpszOutBuf, lpszInBuf);
return (FALSE);
}
switch (LCType)
{
case ( LOCALE_STIMEFORMAT ) :
{
lpNLSChars1 = szTLetters;
lpNLSChars2 = szTCaseSwap;
break;
}
case ( LOCALE_SLONGDATE ) :
{
lpNLSChars1 = szLDLetters;
lpNLSChars2 = szLDCaseSwap;
break;
}
case ( LOCALE_SSHORTDATE ) :
{
lpNLSChars1 = szSDLetters;
lpNLSChars2 = szSDCaseSwap;
break;
}
}
while (*lpszInBuf)
{
Map_Char = TRUE;
#ifdef UNICODE
Cmp_Size = 1;
#else
Is_Dbl = IsDBCSLeadByte(*lpszInBuf);
Cmp_Size = Is_Dbl ? 2 : 1;
#endif
if (*lpszInBuf == CHAR_QUOTE)
{
bInQuote = !bInQuote;
*lpszOutBuf++ = *lpszInBuf++;
}
else
{
if (!bInQuote)
{
if (LCType == LOCALE_STIMEFORMAT || LCType == LOCALE_SLONGDATE)
{
Map_Char = FALSE;
if (CompareString( UserLocaleID,
0,
lpszInBuf,
Cmp_Size,
szStyleH,
-1 ) == CSTR_EQUAL)
{
*lpszOutBuf++ = CHAR_CAP_H;
}
else if (CompareString( UserLocaleID,
0,
lpszInBuf,
Cmp_Size,
szStyleh,
-1 ) == CSTR_EQUAL)
{
*lpszOutBuf++ = CHAR_SML_H;
}
else if (CompareString( UserLocaleID,
0,
lpszInBuf,
Cmp_Size,
szStylem,
-1 ) == CSTR_EQUAL)
{
*lpszOutBuf++ = CHAR_SML_M;
}
else if (CompareString( UserLocaleID,
0,
lpszInBuf,
Cmp_Size,
szStyles,
-1 ) == CSTR_EQUAL)
{
*lpszOutBuf++ = CHAR_SML_S;
}
else if (CompareString( UserLocaleID,
0,
lpszInBuf,
Cmp_Size,
szStylet,
-1 ) == CSTR_EQUAL)
{
*lpszOutBuf++ = CHAR_SML_T;
}
else
{
Map_Char = TRUE;
}
}
if (LCType == LOCALE_SSHORTDATE ||
(LCType == LOCALE_SLONGDATE && Map_Char))
{
Map_Char = FALSE;
if (CompareString( UserLocaleID,
0,
lpszInBuf,
Cmp_Size,
szStyled,
-1 ) == CSTR_EQUAL)
{
*lpszOutBuf++ = CHAR_SML_D;
}
else if (CompareString( UserLocaleID,
0,
lpszInBuf,
Cmp_Size,
szStyleM,
-1) == CSTR_EQUAL)
{
*lpszOutBuf++ = CHAR_CAP_M;
}
else if (CompareString( UserLocaleID,
0,
lpszInBuf,
Cmp_Size,
szStyley,
-1 ) == CSTR_EQUAL)
{
*lpszOutBuf++ = CHAR_SML_Y;
}
else if (CompareString( UserLocaleID,
0,
lpszInBuf,
Cmp_Size,
TEXT("g"),
-1) == CSTR_EQUAL)
{
//
// g is not localized, but it's legal.
//
*lpszOutBuf++ = CHAR_SML_G;
}
else
{
Map_Char = TRUE;
}
}
}
if (Map_Char)
{
//
// Just copy chars in quotes or chars that are not
// recognized. Leave the char checking to the other
// function. However, do check for NLS standard chars
// that were not supposed to be here due to localization.
//
if ( !bInQuote &&
#ifndef UNICODE
!Is_Dbl &&
#endif
(CompareString( UserLocaleID,
0,
lpszInBuf,
Cmp_Size,
TEXT(" "),
-1 ) != CSTR_EQUAL) &&
( _tcschr(lpNLSChars1, *lpszInBuf) ||
_tcschr(lpNLSChars2, *lpszInBuf) ) )
{
return (TRUE);
}
*lpszOutBuf++ = *lpszInBuf++;
#ifndef UNICODE
if (Is_Dbl)
{
//
// Copy 2nd byte.
//
*lpszOutBuf++ = *lpszInBuf++;
}
#endif
}
#ifndef UNICODE
else if (Is_Dbl)
{
lpszInBuf += 2;
}
#endif
else
{
lpszInBuf++;
}
}
}
//
// Append null to localized string.
//
*lpszOutBuf = 0;
return (FALSE);
}
#ifndef WINNT
////////////////////////////////////////////////////////////////////////////
//
// SDate3_1_Compatibility
//
// There is a requirement to keep windows 3.1 compatibility in the
// registry (win.ini). Only allow 1 or 2 'M's, 1 or 2 'd's, and
// 2 or 4 'y's. The remainder of the date style is compatible.
//
////////////////////////////////////////////////////////////////////////////
void SDate3_1_Compatibility(
LPTSTR lpszBuf,
int Buf_Size)
{
BOOL bInQuote = FALSE;
int Index, Del_Cnt;
int Len = lstrlen(lpszBuf);
int MCnt = 0; // running total of Ms
int dCnt = 0; // running total of ds
int yCnt = 0; // running total of ys
while (*lpszBuf)
{
#ifndef UNICODE
if (IsDBCSLeadByte(*lpszBuf))
{
lpszBuf += 2;
}
else
#endif
{
if (bInQuote)
{
bInQuote = (*lpszBuf != CHAR_QUOTE);
lpszBuf++;
}
else if (*lpszBuf == CHAR_CAP_M)
{
if (MCnt++ < 2)
{
lpszBuf++;
}
else
{
//
// At least 1 extra M. Move all of the chars, including
// null, up by Del_Cnt.
//
Del_Cnt = 1;
Index = 1;
while (lpszBuf[Index++] == CHAR_CAP_M)
{
Del_Cnt++;
}
for (Index = 0; Index <= Len - Del_Cnt + 1; Index++)
{
lpszBuf[Index] = lpszBuf[Index + Del_Cnt];
}
Len -= Del_Cnt;
}
}
else if (*lpszBuf == CHAR_SML_D)
{
if (dCnt++ < 2)
{
lpszBuf++;
}
else
{
//
// At least 1 extra d. Move all of the chars, including
// null, up by Del_Cnt.
//
Del_Cnt = 1;
Index = 1;
while (lpszBuf[Index++] == CHAR_SML_D)
{
Del_Cnt++;
}
for (Index = 0; Index <= Len - Del_Cnt + 1; Index++)
{
lpszBuf[Index] = lpszBuf[Index + Del_Cnt];
}
Len -= Del_Cnt;
}
}
else if (*lpszBuf == CHAR_SML_Y)
{
if (yCnt == 0 || yCnt == 2)
{
if (lpszBuf[1] == CHAR_SML_Y)
{
lpszBuf += 2;
yCnt += 2;
}
else if (Len < Buf_Size - 1)
{
//
// Odd # of ys & room for one more.
// Move the remaining text down by 1 (the y will
// be copied).
//
// Use Del_Cnt for unparsed string length.
//
Del_Cnt = lstrlen(lpszBuf);
for (Index = Del_Cnt + 1; Index > 0; Index--)
{
lpszBuf[Index] = lpszBuf[Index - 1];
}
}
else
{
//
// No room, move all of the chars, including null,
// up by 1.
//
for (Index = 0; Index <= Len; Index++)
{
lpszBuf[Index] = lpszBuf[Index + 1];
}
Len--;
}
}
else
{
//
// At least 1 extra y. Move all of the chars, including
// null, up by Del_Cnt.
//
Del_Cnt = 1;
Index = 1;
while (lpszBuf[Index++] == CHAR_SML_Y)
{
Del_Cnt++;
}
for (Index = 0; Index <= Len - Del_Cnt + 1; Index++)
{
lpszBuf[Index] = lpszBuf[Index + Del_Cnt];
}
Len -= Del_Cnt;
}
}
else if (*lpszBuf == CHAR_QUOTE)
{
lpszBuf++;
bInQuote = TRUE;
}
else
{
lpszBuf++;
}
}
}
}
#endif
////////////////////////////////////////////////////////////////////////////
//
// Set_Locale_Values
//
// Set_Locale_Values is called for each LCType that has either been
// directly modified via a user change, or indirectly modified by the user
// changing the regional locale setting. When a dialog handle is available,
// Set_Locale_Values will pull the new value of the LCType from the
// appropriate list box (this is a direct change), register it in the
// locale database, and then update the registry string. If no dialog
// handle is available, it will simply update the registry string based on
// the locale registry. If the registration succeeds, return true.
// Otherwise, return false.
//
////////////////////////////////////////////////////////////////////////////
BOOL Set_Locale_Values(
HWND hDlg,
LCTYPE LCType,
int nItemId,
LPTSTR lpIniStr,
BOOL bValue,
int Ordinal_Offset,
LPTSTR Append_Str,
LPTSTR NLS_Str)
{
DWORD dwIndex;
BOOL bSuccess = TRUE;
TCHAR szBuf[SIZE_128 + 1];
LPTSTR pBuf = szBuf;
HWND hCtrl;
if (NLS_Str)
{
//
// Use a non-localized string.
//
lstrcpy(pBuf, NLS_Str);
bSuccess = SetLocaleInfo(UserLocaleID, LCType, pBuf);
}
else if (hDlg)
{
//
// Get the new value from the list box.
//
hCtrl = GetDlgItem(hDlg, nItemId);
dwIndex = ComboBox_GetCurSel(hCtrl);
//
// If there is no selection, get whatever is in the edit box.
//
if (dwIndex == CB_ERR)
{
dwIndex = GetDlgItemText(hDlg, nItemId, pBuf, SIZE_128);
if (dwIndex)
{
//
// Get text succeeded.
//
pBuf[dwIndex] = 0;
}
else
{
//
// Get text failed.
// Allow the AM/PM symbols to be set as empty strings.
// Otherwise, fail.
//
if ((LCType == LOCALE_S1159) || (LCType == LOCALE_S2359))
{
pBuf[0] = 0;
}
else
{
bSuccess = FALSE;
}
}
}
else if (bValue)
{
//
// Need string representation of ordinal locale value.
//
if (nItemId == IDC_CALENDAR_TYPE)
{
dwIndex = (DWORD)ComboBox_GetItemData(hCtrl, dwIndex);
}
else
{
//
// Ordinal_Offset is required since calendar is 1 based,
// not 0 based.
//
dwIndex += Ordinal_Offset;
}
//
// Special case the grouping string.
//
if (nItemId == IDC_NUM_DIGITS_GROUP)
{
switch (dwIndex)
{
case ( 0 ) :
{
lstrcpy(pBuf, TEXT("0"));
break;
}
case ( 1 ) :
{
lstrcpy(pBuf, TEXT("3"));
break;
}
case ( 2 ) :
{
lstrcpy(pBuf, TEXT("3;2"));
break;
}
case ( 3 ) :
{
wsprintf( pBuf,
TEXT("%d"),
ComboBox_GetItemData(hCtrl, dwIndex) );
break;
}
}
}
else if (dwIndex < cInt_Str)
{
lstrcpy(pBuf, aInt_Str[dwIndex]);
}
else
{
wsprintf(pBuf, TEXT("%d"), dwIndex);
}
}
else
{
//
// Get actual value of locale data.
//
bSuccess = (ComboBox_GetLBText(hCtrl, dwIndex, pBuf) != CB_ERR);
}
if (bSuccess)
{
//
// If edit text, index value or selection text succeeds...
//
if (Append_Str)
{
lstrcat(pBuf, Append_Str);
}
//
// If this is sNativeDigits, the LPK is installed, and the
// first char is 0x206f (nominal digit shapes), then do not
// store the first char in the registry.
//
if ((LCType == LOCALE_SNATIVEDIGITS) &&
(bLPKInstalled) &&
(pBuf[0] == TEXT('\x206f')))
{
pBuf++;
}
bSuccess = SetLocaleInfo( UserLocaleID, LCType, pBuf );
}
}
if (lpIniStr && bSuccess)
{
//
// Set the registry string to the string that is stored in the list
// box. If there is no dialog handle, get the required string
// locale value from the NLS function. Write the associated string
// into the registry.
//
if (!hDlg && !NLS_Str)
{
GetLocaleInfo( UserLocaleID,
LCType | LOCALE_NOUSEROVERRIDE,
pBuf,
SIZE_128 );
}
#ifndef WINNT
//
// There is a requirement to keep windows 3.1 compatibility in the
// win.ini. There are some win32 short date formats that are
// incompatible with exisiting win 3.1 apps... modify these styles.
//
if (LCType == LOCALE_SSHORTDATE)
{
SDate3_1_Compatibility(pBuf, SIZE_128);
}
#endif
//
// Check the value whether it is empty or not.
//
switch (LCType)
{
case ( LOCALE_STHOUSAND ) :
case ( LOCALE_SDECIMAL ) :
case ( LOCALE_SDATE ) :
case ( LOCALE_STIME ) :
case ( LOCALE_SLIST ) :
{
CheckEmptyString(pBuf);
break;
}
}
//
// Set the locale information in the registry.
//
// NOTE: We want to use SetLocaleInfo if possible so that the
// NLS cache is updated right away. Otherwise, we'll
// simply use WriteProfileString.
//
if (!SetLocaleInfo(UserLocaleID, LCType, pBuf))
{
WriteProfileString(szIntl, lpIniStr, pBuf);
}
}
else if (!bSuccess)
{
LoadString(hInstance, IDS_LOCALE_SET_ERROR, szBuf, SIZE_128);
MessageBox(hDlg, szBuf, NULL, MB_OK | MB_ICONINFORMATION);
SetFocus(GetDlgItem(hDlg, nItemId));
return (FALSE);
}
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// Set_List_Values
//
// Set_List_Values is called several times for each drop down list which is
// populated via an enum function. The first call to this function should
// be with a valid dialog handle, valid dialog item ID, and null string
// value. If the function is not already in use, it will clear the list box
// and store the handle and id information for the subsequent calls to this
// function that will be made by the enumeration function. The calls from
// the enumeration function will add the specified string values to the
// list box. When the enumeration function is complete, this function
// should be called with a null dialog handle, the valid dialog item id,
// and a null string value. This will clear all of the state information,
// including the lock flag.
//
////////////////////////////////////////////////////////////////////////////
BOOL Set_List_Values(
HWND hDlg,
int nItemId,
LPTSTR lpValueString)
{
static BOOL bLock, bString;
static HWND hDialog;
static int nDItemId, nID;
if (!lpValueString)
{
//
// Clear the lock if there is no dialog handle and the item IDs
// match.
//
if (bLock && !hDlg && (nItemId == nDItemId))
{
if (nItemId != IDC_CALENDAR_TYPE)
{
hDialog = 0;
nDItemId = 0;
bLock = FALSE;
}
else
{
if (bString)
{
hDialog = 0;
nDItemId = 0;
bLock = FALSE;
bString = FALSE;
}
else
{
nID = 0;
bString = TRUE;
}
}
return (TRUE);
}
//
// Return false, for failure, if the function is locked or if the
// handle or ID parameters are null.
//
if (bLock || !hDlg || !nItemId)
{
return (FALSE);
}
//
// Prepare for subsequent calls to populate the list box.
//
bLock = TRUE;
hDialog = hDlg;
nDItemId = nItemId;
}
else if (bLock && hDialog && nDItemId)
{
//
// Add the string to the list box.
//
if (!bString)
{
ComboBox_InsertString( GetDlgItem(hDialog, nDItemId),
-1,
lpValueString );
}
else
{
ComboBox_SetItemData( GetDlgItem(hDialog, nDItemId),
nID++,
Intl_StrToLong(lpValueString) );
}
}
else
{
return (FALSE);
}
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// DropDown_Use_Locale_Values
//
// Get the user locale value for the locale type specifier. Add it to
// the list box and make this value the current selection. If the user
// locale value for the locale type is different than the system value,
// add the system value to the list box. If the user default is different
// than the user override, add the user default.
//
////////////////////////////////////////////////////////////////////////////
void DropDown_Use_Locale_Values(
HWND hDlg,
LCTYPE LCType,
int nItemId)
{
TCHAR szBuf[SIZE_128];
TCHAR szCmpBuf1[SIZE_128];
TCHAR szCmpBuf2[SIZE_128];
HWND hCtrl = GetDlgItem(hDlg, nItemId);
int ctr;
if (GetLocaleInfo(UserLocaleID, LCType, szBuf, SIZE_128))
{
ComboBox_SetCurSel(hCtrl, ComboBox_InsertString(hCtrl, -1, szBuf));
//
// If the system setting is different, add it to the list box.
//
if (GetLocaleInfo( SysLocaleID,
LCType | LOCALE_NOUSEROVERRIDE,
szCmpBuf1,
SIZE_128 ))
{
if (CompareString( UserLocaleID,
0,
szCmpBuf1,
-1,
szBuf,
-1 ) != CSTR_EQUAL)
{
ComboBox_InsertString(hCtrl, -1, szCmpBuf1);
}
}
//
// If the default user locale setting is different than the user
// overridden setting and different than the system setting, add
// it to the list box.
//
if (GetLocaleInfo( UserLocaleID,
LCType | LOCALE_NOUSEROVERRIDE,
szCmpBuf2,
SIZE_128 ))
{
if (CompareString(UserLocaleID, 0, szCmpBuf2, -1, szBuf, -1) != CSTR_EQUAL &&
CompareString(UserLocaleID, 0, szCmpBuf2, -1, szCmpBuf1, -1) != CSTR_EQUAL)
{
ComboBox_InsertString(hCtrl, -1, szCmpBuf2);
}
}
}
else
{
//
// Failed to get user value, try for system value. If system value
// fails, display a message box indicating that there was a locale
// problem.
//
if (GetLocaleInfo( SysLocaleID,
LCType | LOCALE_NOUSEROVERRIDE,
szBuf,
SIZE_128 ))
{
ComboBox_SetCurSel(hCtrl, ComboBox_InsertString(hCtrl, -1, szBuf));
}
else
{
MessageBox(hDlg, szLocaleGetError, NULL, MB_OK | MB_ICONINFORMATION);
}
}
//
// If it's the date separator, then we want slash, dot, and dash in
// the list in addition to the user and system settings (if different).
//
if (LCType == LOCALE_SDATE)
{
for (ctr = 0; ctr < NUM_DATE_SEPARATORS; ctr++)
{
if (ComboBox_FindStringExact( hCtrl,
-1,
pDateSeparators[ctr] ) == CB_ERR)
{
ComboBox_InsertString(hCtrl, -1, pDateSeparators[ctr]);
}
}
}
//
// If it's the AM symbol, then we want AM in the list in addition
// to the user and system settings (if different).
//
if (LCType == LOCALE_S1159)
{
for (ctr = 0; ctr < NUM_AM_SYMBOLS; ctr++)
{
if (ComboBox_FindStringExact( hCtrl,
-1,
pAMSymbols[ctr] ) == CB_ERR)
{
ComboBox_InsertString(hCtrl, -1, pAMSymbols[ctr]);
}
}
}
//
// If it's the PM symbol, then we want PM in the list in addition
// to the user and system settings (if different).
//
if (LCType == LOCALE_S2359)
{
for (ctr = 0; ctr < NUM_PM_SYMBOLS; ctr++)
{
if (ComboBox_FindStringExact( hCtrl,
-1,
pPMSymbols[ctr] ) == CB_ERR)
{
ComboBox_InsertString(hCtrl, -1, pPMSymbols[ctr]);
}
}
}
#ifdef UNICODE
//
// If it's the currency symbol, then we want the Euro symbol and dollar
// sign in the list in addition to the user and system settings (if
// different).
//
if (LCType == LOCALE_SCURRENCY)
{
for (ctr = 0; ctr < NUM_CURRENCY_SYMBOLS; ctr++)
{
if (ComboBox_FindStringExact( hCtrl,
-1,
pCurrencySymbols[ctr] ) == CB_ERR)
{
ComboBox_InsertString(hCtrl, -1, pCurrencySymbols[ctr]);
}
}
}
#endif
}
////////////////////////////////////////////////////////////////////////////
//
// EnumProc
//
// This call back function calls Set_List_Values assuming that whatever
// code called the NLS enumeration function (or dummied enumeration
// function) has properly set up Set_List_Values for the list box
// population.
//
////////////////////////////////////////////////////////////////////////////
BOOL CALLBACK EnumProc(
LPTSTR lpValueString)
{
return (Set_List_Values(0, 0, lpValueString));
}
////////////////////////////////////////////////////////////////////////////
//
// EnumProcEx
//
// This call back function calls Set_List_Values assuming that whatever
// code called the enumeration function has properly set up
// Set_List_Values for the list box population.
// Also, this function fixes the string passed in to contain the correct
// decimal separator and negative sign, if appropriate.
//
////////////////////////////////////////////////////////////////////////////
BOOL CALLBACK EnumProcEx(
LPTSTR lpValueString,
LPTSTR lpDecimalString,
LPTSTR lpNegativeString,
LPTSTR lpSymbolString)
{
TCHAR szString[SIZE_128];
LPTSTR pStr, pValStr, pTemp;
//
// Simplify things if we have a NULL string.
//
if (lpDecimalString && (*lpDecimalString == CHAR_NULL))
{
lpDecimalString = NULL;
}
if (lpNegativeString && (*lpNegativeString == CHAR_NULL))
{
lpNegativeString = NULL;
}
if (lpSymbolString && (*lpSymbolString == CHAR_NULL))
{
lpSymbolString = NULL;
}
//
// See if we need to do any substitutions.
//
if (lpDecimalString || lpNegativeString || lpSymbolString)
{
pValStr = lpValueString;
pStr = szString;
while (*pValStr)
{
if (lpDecimalString && (*pValStr == CHAR_DECIMAL))
{
//
// Substitute the current user decimal separator.
//
pTemp = lpDecimalString;
while (*pTemp)
{
*pStr = *pTemp;
pStr++;
pTemp++;
}
}
else if (lpNegativeString && (*pValStr == CHAR_HYPHEN))
{
//
// Substitute the current user negative sign.
//
pTemp = lpNegativeString;
while (*pTemp)
{
*pStr = *pTemp;
pStr++;
pTemp++;
}
}
else if (lpSymbolString && (*pValStr == CHAR_INTL_CURRENCY))
{
//
// Substitute the current user currency symbol.
//
pTemp = lpSymbolString;
while (*pTemp)
{
*pStr = *pTemp;
pStr++;
pTemp++;
}
}
else
{
//
// Simply copy the character.
//
*pStr = *pValStr;
pStr++;
}
pValStr++;
}
*pStr = CHAR_NULL;
return (Set_List_Values(0, 0, szString));
}
else
{
return (Set_List_Values(0, 0, lpValueString));
}
}
////////////////////////////////////////////////////////////////////////////
//
// EnumLeadingZeros
//
////////////////////////////////////////////////////////////////////////////
BOOL EnumLeadingZeros(
LEADINGZEROS_ENUMPROC lpLeadingZerosEnumProc,
LCID LCId,
DWORD dwFlags)
{
TCHAR szBuf[SIZE_128];
TCHAR szDecimal[SIZE_128];
//
// If there is no enum proc, return false to indicate a failure.
//
if (!lpLeadingZerosEnumProc)
{
return (FALSE);
}
//
// Get the Decimal Separator for the current user locale so that
// it may be displayed correctly.
//
if (!GetLocaleInfo(UserLocaleID, LOCALE_SDECIMAL, szDecimal, SIZE_128) ||
((szDecimal[0] == CHAR_DECIMAL) && (szDecimal[1] == CHAR_NULL)))
{
szDecimal[0] = CHAR_NULL;
}
//
// Call enum proc with the NO string. Check to make sure the
// enum proc requests continuation.
//
LoadString(hInstance, IDS_NO_LZERO, szBuf, SIZE_128);
if (!lpLeadingZerosEnumProc(szBuf, szDecimal, NULL, NULL))
{
return (TRUE);
}
//
// Call enum proc with the YES string.
//
LoadString(hInstance, IDS_LZERO, szBuf, SIZE_128);
lpLeadingZerosEnumProc(szBuf, szDecimal, NULL, NULL);
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// EnumNegNumFmt
//
////////////////////////////////////////////////////////////////////////////
BOOL EnumNegNumFmt(
NEGNUMFMT_ENUMPROC lpNegNumFmtEnumProc,
LCID LCId,
DWORD dwFlags)
{
TCHAR szDecimal[SIZE_128];
TCHAR szNeg[SIZE_128];
int ctr;
//
// If there is no enum proc, return false to indicate a failure.
//
if (!lpNegNumFmtEnumProc)
{
return (FALSE);
}
//
// Get the Decimal Separator for the current user locale so that
// it may be displayed correctly.
//
if (!GetLocaleInfo(UserLocaleID, LOCALE_SDECIMAL, szDecimal, SIZE_128) ||
((szDecimal[0] == CHAR_DECIMAL) && (szDecimal[1] == CHAR_NULL)))
{
szDecimal[0] = CHAR_NULL;
}
//
// Get the Negative Sign for the current user locale so that
// it may be displayed correctly.
//
if (!GetLocaleInfo(UserLocaleID, LOCALE_SNEGATIVESIGN, szNeg, SIZE_128) ||
((szNeg[0] == CHAR_HYPHEN) && (szNeg[1] == CHAR_NULL)))
{
szNeg[0] = CHAR_NULL;
}
//
// Call enum proc with each format string. Check to make sure
// the enum proc requests continuation.
//
for (ctr = 0; ctr < NUM_NEG_NUMBER_FORMATS; ctr++)
{
if (!lpNegNumFmtEnumProc( pNegNumberFormats[ctr],
szDecimal,
szNeg,
NULL ))
{
return (TRUE);
}
}
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// EnumMeasureSystem
//
////////////////////////////////////////////////////////////////////////////
BOOL EnumMeasureSystem(
MEASURESYSTEM_ENUMPROC lpMeasureSystemEnumProc,
LCID LCId,
DWORD dwFlags)
{
TCHAR szBuf[SIZE_128];
//
// If there is no enum proc, return false to indicate a failure.
//
if (!lpMeasureSystemEnumProc)
{
return (FALSE);
}
//
// Call enum proc with the metric string. Check to make sure the
// enum proc requests continuation.
//
LoadString(hInstance, IDS_METRIC, szBuf, SIZE_128);
if (!lpMeasureSystemEnumProc(szBuf))
{
return (TRUE);
}
//
// Call enum proc with the U.S. string.
//
LoadString(hInstance, IDS_US, szBuf, SIZE_128);
lpMeasureSystemEnumProc(szBuf);
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// EnumPosCurrency
//
////////////////////////////////////////////////////////////////////////////
BOOL EnumPosCurrency(
POSCURRENCY_ENUMPROC lpPosCurrencyEnumProc,
LCID LCId,
DWORD dwFlags)
{
TCHAR szDecimal[SIZE_128];
TCHAR szSymbol[SIZE_128];
int ctr;
//
// If there is no enum proc, return false to indicate a failure.
//
if (!lpPosCurrencyEnumProc)
{
return (FALSE);
}
//
// Get the Decimal Separator for the current user locale so that
// it may be displayed correctly.
//
if (!GetLocaleInfo(UserLocaleID, LOCALE_SMONDECIMALSEP, szDecimal, SIZE_128) ||
((szDecimal[0] == CHAR_DECIMAL) && (szDecimal[1] == CHAR_NULL)))
{
szDecimal[0] = CHAR_NULL;
}
//
// Get the Currency Symbol for the current user locale so that
// it may be displayed correctly.
//
if (!GetLocaleInfo(UserLocaleID, LOCALE_SCURRENCY, szSymbol, SIZE_128) ||
((szSymbol[0] == CHAR_INTL_CURRENCY) && (szSymbol[1] == CHAR_NULL)))
{
szSymbol[0] = CHAR_NULL;
}
//
// Call enum proc with each format string. Check to make sure the
// enum proc requests continuation.
//
for (ctr = 0; ctr < NUM_POS_CURRENCY_FORMATS; ctr++)
{
if (!lpPosCurrencyEnumProc( pPosCurrencyFormats[ctr],
szDecimal,
NULL,
szSymbol ))
{
return (TRUE);
}
}
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// EnumNegCurrency
//
////////////////////////////////////////////////////////////////////////////
BOOL EnumNegCurrency(
NEGCURRENCY_ENUMPROC lpNegCurrencyEnumProc,
LCID LCId,
DWORD dwFlags)
{
TCHAR szDecimal[SIZE_128];
TCHAR szNeg[SIZE_128];
TCHAR szSymbol[SIZE_128];
int ctr;
//
// If there is no enum proc, return false to indicate a failure.
//
if (!lpNegCurrencyEnumProc)
{
return (FALSE);
}
//
// Get the Decimal Separator for the current user locale so that
// it may be displayed correctly.
//
if (!GetLocaleInfo(UserLocaleID, LOCALE_SMONDECIMALSEP, szDecimal, SIZE_128) ||
((szDecimal[0] == CHAR_DECIMAL) && (szDecimal[1] == CHAR_NULL)))
{
szDecimal[0] = CHAR_NULL;
}
//
// Get the Negative Sign for the current user locale so that
// it may be displayed correctly.
//
if (!GetLocaleInfo(UserLocaleID, LOCALE_SNEGATIVESIGN, szNeg, SIZE_128) ||
((szNeg[0] == CHAR_HYPHEN) && (szNeg[1] == CHAR_NULL)))
{
szNeg[0] = CHAR_NULL;
}
//
// Get the Currency Symbol for the current user locale so that
// it may be displayed correctly.
//
if (!GetLocaleInfo(UserLocaleID, LOCALE_SCURRENCY, szSymbol, SIZE_128) ||
((szSymbol[0] == CHAR_INTL_CURRENCY) && (szSymbol[1] == CHAR_NULL)))
{
szSymbol[0] = CHAR_NULL;
}
//
// Call enum proc with each format string. Check to make sure the
// enum proc requests continuation.
//
for (ctr = 0; ctr < NUM_NEG_CURRENCY_FORMATS; ctr++)
{
if (!lpNegCurrencyEnumProc( pNegCurrencyFormats[ctr],
szDecimal,
szNeg,
szSymbol ))
{
return (TRUE);
}
}
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// CheckEmptyString
//
// If lpStr is empty, then it fills it with a null ("") string.
// If lpStr is filled only by space, fills with a blank (" ") string.
//
////////////////////////////////////////////////////////////////////////////
void CheckEmptyString(
LPTSTR lpStr)
{
LPTSTR lpString;
WORD wStrCType[64];
if (!(*lpStr))
{
//
// Put "" string in buffer.
//
lstrcpy(lpStr, TEXT("\"\""));
}
else
{
for (lpString = lpStr; *lpString; lpString = CharNext(lpString))
{
GetStringTypeEx( LOCALE_USER_DEFAULT,
CT_CTYPE1,
lpString,
1,
wStrCType);
if (wStrCType[0] != CHAR_SPACE)
{
return;
}
}
//
// Put " " string in buffer.
//
lstrcpy(lpStr, TEXT("\" \""));
}
}
////////////////////////////////////////////////////////////////////////////
//
// SetDlgItemRTL
//
////////////////////////////////////////////////////////////////////////////
void SetDlgItemRTL(
HWND hDlg,
UINT uItem)
{
HWND hItem = GetDlgItem(hDlg, uItem);
DWORD dwExStyle = GetWindowLong(hItem, GWL_EXSTYLE);
SetWindowLong(hItem, GWL_EXSTYLE, dwExStyle | WS_EX_RTLREADING);
}
////////////////////////////////////////////////////////////////////////////
//
// ShowMsg
//
////////////////////////////////////////////////////////////////////////////
int ShowMsg(
HWND hDlg,
UINT iMsg,
UINT iTitle,
UINT iType,
LPTSTR pString)
{
TCHAR szTitle[MAX_PATH];
TCHAR szMsg[MAX_PATH*2];
TCHAR szErrMsg[MAX_PATH*2];
LPTSTR pTitle = NULL;
if (iTitle)
{
if (LoadString(hInstance, iTitle, szTitle, ARRAYSIZE(szTitle)))
{
pTitle = szTitle;
}
}
if (pString)
{
if (LoadString(hInstance, iMsg, szMsg, ARRAYSIZE(szMsg)))
{
wsprintf(szErrMsg, szMsg, pString);
return (MessageBox(hDlg, szErrMsg, pTitle, iType));
}
}
else
{
if (LoadString(hInstance, iMsg, szErrMsg, ARRAYSIZE(szErrMsg)))
{
return (MessageBox(hDlg, szErrMsg, pTitle, iType));
}
}
return (FALSE);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_EnumLocales
//
////////////////////////////////////////////////////////////////////////////
void Intl_EnumLocales(
HWND hDlg,
HWND hLocale,
BOOL EnumSystemLocales)
{
LPLANGUAGEGROUP pLG;
DWORD Locale, dwIndex;
BOOL fSpanish = FALSE;
UINT ctr;
TCHAR szBuf[SIZE_300];
DWORD dwLocaleACP;
INT iRet = TRUE;
//
// Go through the language groups to see which ones are installed.
// Display only the locales for the groups that are either already
// installed or the groups the user wants to be installed.
//
pLG = pLanguageGroups;
while (pLG)
{
//
// If the language group is originally installed and not marked for
// removal OR is marked to be installed, then add the locales for
// this language group to the System and User combo boxes.
//
if (pLG->wStatus & ML_INSTALL)
{
for (ctr = 0; ctr < pLG->NumLocales; ctr++)
{
//
// Save the locale id.
//
Locale = (pLG->pLocaleList)[ctr];
//
// See if we need to special case Spanish.
//
if ((LANGIDFROMLCID(Locale) == LANG_SPANISH_TRADITIONAL) ||
(LANGIDFROMLCID(Locale) == LANG_SPANISH_INTL))
{
//
// If we've already displayed Spanish (Spain), then
// don't display it again.
//
if (!fSpanish)
{
//
// Add the Spanish locale to the list box.
//
if (LoadString(hInstance, IDS_SPANISH_NAME, szBuf, SIZE_300))
{
dwIndex = ComboBox_AddString(hLocale, szBuf);
ComboBox_SetItemData( hLocale,
dwIndex,
LCID_SPANISH_INTL );
fSpanish = TRUE;
}
}
}
else
{
//
// Don't enum system locales that don't have an ACP.
//
if (EnumSystemLocales)
{
iRet = GetLocaleInfo( Locale,
LOCALE_IDEFAULTANSICODEPAGE |
LOCALE_NOUSEROVERRIDE |
LOCALE_RETURN_NUMBER,
(PTSTR) &dwLocaleACP,
sizeof(dwLocaleACP) / sizeof(TCHAR) );
if (iRet)
{
iRet = dwLocaleACP;
}
}
if (iRet)
{
//
// Get the name of the locale.
//
GetLocaleInfo(Locale, LOCALE_SLANGUAGE, szBuf, SIZE_300);
//
// Add the new locale to the list box.
//
dwIndex = ComboBox_AddString(hLocale, szBuf);
ComboBox_SetItemData(hLocale, dwIndex, Locale);
}
}
}
}
pLG = pLG->pNext;
}
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_EnumInstalledCPProc
//
////////////////////////////////////////////////////////////////////////////
BOOL CALLBACK Intl_EnumInstalledCPProc(
LPTSTR pString)
{
UINT CodePage;
LPCODEPAGE pCP;
//
// Convert the code page string to an integer.
//
CodePage = Intl_StrToLong(pString);
//
// Find the code page in the linked list and mark it as
// originally installed.
//
pCP = pCodePages;
while (pCP)
{
if (pCP->CodePage == CodePage)
{
pCP->wStatus |= ML_ORIG_INSTALLED;
break;
}
pCP = pCP->pNext;
}
//
// Return success.
//
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_InstallKeyboardLayout
//
// Install the Keyboard Layout requested. If the Layout parameter is 0,
// the function will proceed with the installation of the default layout
// for the Locale specified. No need to validate the Layout because it's
// done by the Text Services call.
//
////////////////////////////////////////////////////////////////////////////
BOOL Intl_InstallKeyboardLayout(
HWND hDlg,
LCID Locale,
DWORD Layout,
BOOL bDefaultLayout,
BOOL bDefaultUser,
BOOL bSystemLocale)
{
TCHAR szData[MAX_PATH];
DWORD dwLayout = Layout;
DWORD dwLocale = (DWORD)Locale;
TCHAR szLayout[50];
HKL hklValue = (HKL)NULL;
BOOL bOverrideDefaultLayout = FALSE;
//
// Check if input.dll is loaded.
//
if (hInputDLL && pfnInstallInputLayout)
{
//
// See if we need to look for the default layout.
//
if (!Layout)
{
//
// Look in the INF file for the default layout.
//
if (!Intl_GetDefaultLayoutFromInf(&dwLocale, &dwLayout))
{
//
// Try just the language id.
//
if (HIWORD(Locale) != 0)
{
dwLocale = LANGIDFROMLCID(Locale);
if (!Intl_GetDefaultLayoutFromInf(&dwLocale, &dwLayout))
{
if (g_bLog)
{
wsprintf(szLayout, TEXT("%08x:%08x"), dwLocale, dwLayout);
Intl_LogSimpleMessage(IDS_LOG_LOCALE_KBD_FAIL, szLayout);
}
return (FALSE);
}
}
else
{
if (g_bLog)
{
wsprintf(szLayout,TEXT("%08x:%08x"), dwLocale, dwLayout);
Intl_LogSimpleMessage(IDS_LOG_LOCALE_KBD_FAIL, szLayout);
}
return (FALSE);
}
}
}
//
// See if we need to provide the HKL. This case only occurs when
// we need to set the Layout as the default. Otherwise, the value
// can be NULL.
//
if (bDefaultLayout)
{
hklValue = Intl_GetHKL(dwLocale, dwLayout);
}
//
// Check if need to override the default layout.
//
if (g_bSetupCase && ((HIWORD(dwLayout) & 0xf000) == 0xe000))
{
bOverrideDefaultLayout = TRUE;
}
//
// Install the input Layout.
//
if (!(*pfnInstallInputLayout)( dwLocale,
dwLayout,
bOverrideDefaultLayout ? FALSE : bDefaultLayout,
hklValue,
bDefaultUser,
g_bSetupCase ? TRUE : bSystemLocale ))
{
if (hDlg != NULL)
{
GetLocaleInfo(Locale, LOCALE_SLANGUAGE, szData, MAX_PATH);
ShowMsg( hDlg,
IDS_KBD_LOAD_KBD_FAILED,
0,
MB_OK_OOPS,
szData );
}
else
{
if (g_bLog)
{
wsprintf(szLayout, TEXT("%08x:%08x"), dwLocale, dwLayout);
Intl_LogSimpleMessage(IDS_LOG_LOCALE_KBD_FAIL, szLayout);
}
}
return (FALSE);
}
//
// If the language has a default layout that has a different locale
// than the language (e.g. Thai), we want the default locale to be
// English (so that logon can occur with a US keyboard), but the
// first Thai keyboard layout should be installed when the Thai
// locale is chosen. This is why we have two locales and layouts
// passed back to the caller.
//
if (PRIMARYLANGID(LANGIDFROMLCID(dwLocale)) !=
PRIMARYLANGID(LANGIDFROMLCID(Locale)))
{
dwLocale = Locale;
dwLayout = 0;
if (!Intl_GetSecondValidLayoutFromInf(&dwLocale, &dwLayout))
{
//
// Try just the language id.
//
if (HIWORD(Locale) != 0)
{
dwLocale = LANGIDFROMLCID(Locale);
if (!Intl_GetSecondValidLayoutFromInf(&dwLocale, &dwLayout))
{
if (g_bLog)
{
wsprintf(szLayout, TEXT("%08x:%08x"), dwLocale, dwLayout);
Intl_LogSimpleMessage(IDS_LOG_LOCALE_KBD_FAIL, szLayout);
}
return (FALSE);
}
}
else
{
if (g_bLog)
{
wsprintf(szLayout,TEXT("%08x:%08x"), dwLocale, dwLayout);
Intl_LogSimpleMessage(IDS_LOG_LOCALE_KBD_FAIL, szLayout);
}
return (FALSE);
}
}
}
//
// See if we need to provide the HKL. This case only occurs when
// we need to set the Layout as the default. Otherwise, the value
// can be NULL.
//
if (bDefaultLayout)
{
hklValue = Intl_GetHKL(dwLocale, dwLayout);
}
//
// Install the input Layout.
//
if (!(*pfnInstallInputLayout)( dwLocale,
dwLayout,
FALSE,
hklValue,
bDefaultUser,
g_bSetupCase ? TRUE : bSystemLocale))
{
if (hDlg != NULL)
{
GetLocaleInfo(Locale, LOCALE_SLANGUAGE, szData, MAX_PATH);
ShowMsg( hDlg,
IDS_KBD_LOAD_KBD_FAILED,
0,
MB_OK_OOPS,
szData );
}
else
{
if (g_bLog)
{
wsprintf(szLayout, TEXT("%08x:%08x"), dwLocale, dwLayout);
Intl_LogSimpleMessage(IDS_LOG_LOCALE_KBD_FAIL, szLayout);
}
}
return (FALSE);
}
}
else
{
if (g_bLog)
{
wsprintf(szLayout, TEXT("%08x:%08x"), dwLocale, dwLayout);
Intl_LogSimpleMessage(IDS_LOG_LAYOUT_INSTALLED, szLayout);
}
}
//
// Return success.
//
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_InstallKeyboardLayoutList
//
// Install all keyboard requested. Pass through the layout list and ask the
// Text Services to process with the installation.
//
////////////////////////////////////////////////////////////////////////////
BOOL Intl_InstallKeyboardLayoutList(
PINFCONTEXT pContext,
DWORD dwStartField,
BOOL bDefaultUserCase)
{
DWORD dwNumFields, dwNumList, dwCtr;
DWORD Locale;
DWORD Layout;
BOOL bDefaultLayout = FALSE;
TCHAR szBuffer[MAX_PATH];
LPTSTR pPos;
//
// Get the number of items in the list.
//
dwNumFields = SetupGetFieldCount(pContext);
if (dwNumFields < dwStartField)
{
return (FALSE);
}
dwNumList = dwNumFields - dwStartField + 1;
//
// Install all Keyboard layouts from the list.
//
for (dwCtr = dwStartField; dwCtr <= dwNumFields; dwCtr++)
{
if (SetupGetStringField( pContext,
dwCtr,
szBuffer,
MAX_PATH,
NULL ))
{
//
// Find the colon in order to save the input locale
// and layout values separately.
//
pPos = szBuffer;
while (*pPos)
{
if ((*pPos == CHAR_COLON) && (pPos != szBuffer))
{
*pPos = 0;
pPos++;
//
// Check if related to the invariant locale.
//
Locale = TransNum(szBuffer);
Layout = TransNum(pPos);
if (Locale != LOCALE_INVARIANT)
{
//
// Only the first one in list would be installed as
// the default in the Preload section.
//
if (dwCtr == dwStartField)
{
bDefaultLayout = TRUE;
}
else
{
bDefaultLayout = FALSE;
}
//
// Install the keyboard layout requested
//
if (Intl_InstallKeyboardLayout( NULL,
Locale,
Layout,
bDefaultLayout,
bDefaultUserCase,
FALSE ))
{
//
// Log Layout installation info.
//
if (g_bLog)
{
Intl_LogSimpleMessage(IDS_LOG_LAYOUT, szBuffer);
}
}
}
else
{
//
// Log invariant locale blocked.
//
if (g_bLog)
{
Intl_LogSimpleMessage(IDS_LOG_INV_BLOCK, NULL);
}
}
break;
}
pPos++;
}
}
}
//
// Return success.
//
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_InstallAllKeyboardLayout
//
// Install all keyboard layouts associated with a Language groups.
//
////////////////////////////////////////////////////////////////////////////
BOOL Intl_InstallAllKeyboardLayout(
LANGID Language)
{
BOOL bRet = TRUE;
HINF hIntlInf;
LCID Locale = MAKELCID(Language, SORT_DEFAULT);
TCHAR szLCID[25];
INFCONTEXT Context;
//
// Open the INF file
//
if (Intl_OpenIntlInfFile(&hIntlInf))
{
//
// Get the locale.
//
wsprintf(szLCID, TEXT("%08x"), Locale);
//
// Look for the keyboard section.
//
if (SetupFindFirstLine( hIntlInf,
TEXT("Locales"),
szLCID,
&Context ))
{
bRet = Intl_InstallKeyboardLayoutList(&Context, 5, FALSE);
}
Intl_CloseInfFile(&hIntlInf);
}
return (bRet);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_UninstallAllKeyboardLayout
//
// Remove all keyboard layouts associated with a Language groups.
//
////////////////////////////////////////////////////////////////////////////
BOOL Intl_UninstallAllKeyboardLayout(
UINT uiLangGroup,
BOOL DefaultUserCase)
{
LPLANGUAGEGROUP pLG = pLanguageGroups;
LANGID lidCurrent, lidPrev = 0;
LCID *pLocale;
BOOL bRet = TRUE;
//
// Bail out if we can't get this API from input.dll.
//
if (pfnUninstallInputLayout)
{
//
// Walk through all language groups.
//
while (pLG)
{
if (pLG->LanguageGroup == uiLangGroup)
{
TCHAR szLang[MAX_PATH];
pLocale = pLG->pLocaleList;
//
// Walk through the locale list, remove relevant keyboard
// layouts by the locale's primary language.
//
while (*pLocale)
{
lidCurrent = PRIMARYLANGID(*pLocale);
//
// Don't uninstall any US keyboard layouts.
//
if (lidCurrent == 0x09)
{
pLocale++;
continue;
}
//
// The locale list is sorted, so we can avoid redundant
// UninstallInputLayout calls.
//
if (lidCurrent != lidPrev)
{
//
// Uninstall the input layouts associated with
// this current locale in the list.
//
BOOL bSuccess =
(*pfnUninstallInputLayout)( (LCID) lidCurrent,
0L,
DefaultUserCase );
if (g_bLog)
{
wsprintf(szLang, TEXT("%04x"), lidCurrent);
Intl_LogSimpleMessage( bSuccess
? IDS_LOG_LOCALE_LG_REM
: IDS_LOG_LOCALE_LG_FAIL,
szLang );
}
if (!bSuccess && bRet)
{
bRet = bSuccess;
}
lidPrev = lidCurrent;
}
pLocale++;
}
break;
}
pLG = pLG->pNext;
}
}
return bRet;
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_GetHKL
//
////////////////////////////////////////////////////////////////////////////
HKL Intl_GetHKL(
DWORD dwLocale,
DWORD dwLayout)
{
TCHAR szData[MAX_PATH];
INFCONTEXT Context;
HINF hIntlInf;
TCHAR szLayout[25];
//
// Get the HKL based on the input locale value and the layout value.
//
if (dwLayout == 0)
{
//
// See if it's the default layout for the input locale or an IME.
//
if (HIWORD(dwLocale) == 0)
{
return ((HKL)MAKELPARAM(dwLocale, dwLocale));
}
else if ((HIWORD(dwLocale) & 0xf000) == 0xe000)
{
return ((HKL)IntToPtr(dwLocale));
}
}
else
{
//
// Open the INF file.
//
if (Intl_OpenIntlInfFile(&hIntlInf))
{
//
// Create the Layout string.
//
wsprintf(szLayout, TEXT("%08x"), dwLayout);
//
// Use the layout to make the hkl.
//
if (HIWORD(dwLayout) != 0)
{
//
// We have a special id. Need to find out what the layout id
// should be.
//
if ((SetupFindFirstLine(hIntlInf, szKbdLayoutIds, szLayout, &Context)) &&
(SetupGetStringField(&Context, 1, szData, MAX_PATH, NULL)))
{
dwLayout = (DWORD)(LOWORD(TransNum(szData)) | 0xf000);
}
}
//
// Close the handle
//
Intl_CloseInfFile(&hIntlInf);
//
// Return the hkl:
// loword = input locale id
// hiword = layout id
//
return ((HKL)MAKELPARAM(dwLocale, dwLayout));
}
}
//
// Return failure.
//
return (0);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_GetDefaultLayoutFromInf
//
////////////////////////////////////////////////////////////////////////////
BOOL Intl_GetDefaultLayoutFromInf(
LPDWORD pdwLocale,
LPDWORD pdwLayout)
{
BOOL bRet = TRUE;
HINF hIntlInf;
if (Intl_OpenIntlInfFile(&hIntlInf))
{
bRet = Intl_ReadDefaultLayoutFromInf(pdwLocale, pdwLayout, hIntlInf);
Intl_CloseInfFile(&hIntlInf);
}
return (bRet);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_GetSecondValidLayoutFromInf
//
////////////////////////////////////////////////////////////////////////////
BOOL Intl_GetSecondValidLayoutFromInf(
LPDWORD pdwLocale,
LPDWORD pdwLayout)
{
BOOL bRet = TRUE;
HINF hIntlInf;
if (Intl_OpenIntlInfFile(&hIntlInf))
{
bRet = Intl_ReadSecondValidLayoutFromInf(pdwLocale, pdwLayout, hIntlInf);
Intl_CloseInfFile(&hIntlInf);
}
return (bRet);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_InitInf
//
////////////////////////////////////////////////////////////////////////////
BOOL Intl_InitInf(
HWND hDlg,
HINF *phIntlInf,
LPTSTR pszInf,
HSPFILEQ *pFileQueue,
PVOID *pQueueContext)
{
BOOL bSpecialCase = TRUE;
//
// Open the Inf file.
//
*phIntlInf = SetupOpenInfFile(pszInf, NULL, INF_STYLE_WIN4, NULL);
if (*phIntlInf == INVALID_HANDLE_VALUE)
{
if (g_bLog)
{
Intl_LogFormatMessage(IDS_LOG_INTL_ERROR);
}
return (FALSE);
}
if (!SetupOpenAppendInfFile(NULL, *phIntlInf, NULL))
{
if (g_bLog)
{
Intl_LogFormatMessage(IDS_LOG_SETUP_ERROR);
}
SetupCloseInfFile(*phIntlInf);
return (FALSE);
}
//
// Create a setup file queue and initialize default setup
// copy queue callback context.
//
*pFileQueue = SetupOpenFileQueue();
if ((!*pFileQueue) || (*pFileQueue == INVALID_HANDLE_VALUE))
{
if (g_bLog)
{
Intl_LogFormatMessage(IDS_LOG_SETUP_ERROR);
}
SetupCloseInfFile(*phIntlInf);
return (FALSE);
}
//
// Determine if we are dealing with a special case.
//
if ((g_bUnttendMode || g_bSetupCase) && !g_bProgressBarDisplay)
{
bSpecialCase = FALSE;
}
//
// Don't display FileCopy progress operation during GUI mode setup or Unattend mode.
//
*pQueueContext = SetupInitDefaultQueueCallbackEx( GetParent(hDlg),
(bSpecialCase ? NULL : INVALID_HANDLE_VALUE),
0L,
0L,
NULL );
if (!*pQueueContext)
{
if (g_bLog)
{
Intl_LogFormatMessage(IDS_LOG_SETUP_ERROR);
}
SetupCloseFileQueue(*pFileQueue);
SetupCloseInfFile(*phIntlInf);
return (FALSE);
}
//
// Return success.
//
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_OpenIntlInfFile
//
////////////////////////////////////////////////////////////////////////////
BOOL Intl_OpenIntlInfFile(
HINF *phInf)
{
HINF hIntlInf;
//
// Open the intl.inf file.
//
hIntlInf = SetupOpenInfFile(szIntlInf, NULL, INF_STYLE_WIN4, NULL);
if (hIntlInf == INVALID_HANDLE_VALUE)
{
return (FALSE);
}
if (!SetupOpenAppendInfFile(NULL, hIntlInf, NULL))
{
SetupCloseInfFile(hIntlInf);
return (FALSE);
}
*phInf = hIntlInf;
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_CloseInf
//
////////////////////////////////////////////////////////////////////////////
void Intl_CloseInf(
HINF hIntlInf,
HSPFILEQ FileQueue,
PVOID QueueContext)
{
//
// Terminate the Queue.
//
SetupTermDefaultQueueCallback(QueueContext);
//
// Close the file queue.
//
SetupCloseFileQueue(FileQueue);
//
// Close the Inf file.
//
SetupCloseInfFile(hIntlInf);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_ReadDefaultLayoutFromInf
//
////////////////////////////////////////////////////////////////////////////
BOOL Intl_ReadDefaultLayoutFromInf(
LPDWORD pdwLocale,
LPDWORD pdwLayout,
HINF hIntlInf)
{
INFCONTEXT Context;
TCHAR szPair[MAX_PATH * 2];
LPTSTR pPos;
TCHAR szLCID[25];
//
// Get the locale.
//
wsprintf(szLCID, TEXT("%08x"), *pdwLocale);
//
// Get the first (default) LANGID:HKL pair for the given locale.
// Example String: "0409:00000409"
//
szPair[0] = 0;
if (SetupFindFirstLine( hIntlInf,
TEXT("Locales"),
szLCID,
&Context ))
{
SetupGetStringField(&Context, 5, szPair, MAX_PATH, NULL);
}
//
// Make sure we have a string.
//
if (szPair[0] == 0)
{
return (FALSE);
}
//
// Find the colon in the string and then set the position
// pointer to the next character.
//
pPos = szPair;
while (*pPos)
{
if ((*pPos == CHAR_COLON) && (pPos != szPair))
{
*pPos = 0;
pPos++;
break;
}
pPos++;
}
//
// If there is a layout, then return the input locale and the layout.
//
if ((*pPos) &&
(*pdwLocale = TransNum(szPair)) &&
(*pdwLayout = TransNum(pPos)))
{
return (TRUE);
}
//
// Return failure.
//
return (FALSE);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_ReadSecondValidLayoutFromInf
//
////////////////////////////////////////////////////////////////////////////
BOOL Intl_ReadSecondValidLayoutFromInf(
LPDWORD pdwLocale,
LPDWORD pdwLayout,
HINF hIntlInf)
{
INFCONTEXT Context;
int iField = 6;
TCHAR szPair[MAX_PATH * 2];
LPTSTR pPos;
DWORD dwLoc, dwlay, savedLocale = *pdwLocale;
TCHAR szLCID[25];
//
// Get the locale.
//
wsprintf(szLCID, TEXT("%08x"), *pdwLocale);
//
// Get the first (default) LANGID:HKL pair for the given locale.
// Example String: "0409:00000409"
//
szPair[0] = 0;
if (SetupFindFirstLine(hIntlInf, TEXT("Locales"), szLCID, &Context))
{
while (SetupGetStringField(&Context, iField, szPair, MAX_PATH, NULL))
{
//
// Make sure we have a string.
//
if (szPair[0] == 0)
{
iField++;
continue;
}
//
// Find the colon in the string and then set the position
// pointer to the next character.
//
pPos = szPair;
while (*pPos)
{
if ((*pPos == CHAR_COLON) && (pPos != szPair))
{
*pPos = 0;
pPos++;
break;
}
pPos++;
}
if (*pPos == 0)
{
iField++;
continue;
}
//
// If there is a layout, then return the input locale and the
// layout.
//
if (((dwLoc = TransNum(szPair)) == 0) ||
((dwlay = TransNum(pPos)) == 0))
{
iField++;
continue;
}
if (PRIMARYLANGID(LANGIDFROMLCID(dwLoc)) ==
PRIMARYLANGID(LANGIDFROMLCID(savedLocale)))
{
*pdwLayout = dwlay;
*pdwLocale = dwLoc;
return (TRUE);
}
iField++;
}
}
//
// Return failure.
//
return (FALSE);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_CloseInfFile
//
////////////////////////////////////////////////////////////////////////////
BOOL Intl_CloseInfFile(
HINF *phInf)
{
SetupCloseInfFile(*phInf);
*phInf = INVALID_HANDLE_VALUE;
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_IsValidLayout
//
////////////////////////////////////////////////////////////////////////////
BOOL Intl_IsValidLayout(
DWORD dwLayout)
{
HKEY hKey1, hKey2;
TCHAR szLayout[MAX_PATH];
//
// Get the layout id as a string.
//
wsprintf(szLayout, TEXT("%08x"), dwLayout);
//
// Open the Keyboard Layouts key.
//
if (RegOpenKey(HKEY_LOCAL_MACHINE, szLayoutPath, &hKey1) != ERROR_SUCCESS)
{
return (FALSE);
}
//
// Try to open the layout id key under the Keyboard Layouts key.
//
if (RegOpenKey(hKey1, szLayout, &hKey2) != ERROR_SUCCESS)
{
RegCloseKey(hKey1);
return (FALSE);
}
//
// Close the keys.
//
RegCloseKey(hKey1);
RegCloseKey(hKey2);
//
// Return success.
//
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_RunRegApps
//
////////////////////////////////////////////////////////////////////////////
void Intl_RunRegApps(
LPCTSTR pszRegKey)
{
HKEY hkey;
DWORD cbData, cbValue, dwType, ctr;
TCHAR szValueName[32], szCmdLine[MAX_PATH];
STARTUPINFO startup;
PROCESS_INFORMATION pi;
if (RegOpenKey( HKEY_LOCAL_MACHINE,
pszRegKey,
&hkey ) == ERROR_SUCCESS)
{
startup.cb = sizeof(STARTUPINFO);
startup.lpReserved = NULL;
startup.lpDesktop = NULL;
startup.lpTitle = NULL;
startup.dwFlags = 0L;
startup.cbReserved2 = 0;
startup.lpReserved2 = NULL;
// startup.wShowWindow = wShowWindow;
for (ctr = 0; ; ctr++)
{
LONG lEnum;
cbValue = sizeof(szValueName) / sizeof(TCHAR);
cbData = sizeof(szCmdLine);
if ((lEnum = RegEnumValue( hkey,
ctr,
szValueName,
&cbValue,
NULL,
&dwType,
(LPBYTE)szCmdLine,
&cbData )) == ERROR_MORE_DATA)
{
//
// ERROR_MORE_DATA means the value name or data was too
// large, so skip to the next item.
//
continue;
}
else if (lEnum != ERROR_SUCCESS)
{
//
// This could be ERROR_NO_MORE_ENTRIES, or some kind of
// failure. We can't recover from any other registry
// problem anyway.
//
break;
}
//
// Found a value.
//
if (dwType == REG_SZ)
{
//
// Adjust for shift in value index.
//
ctr--;
//
// Delete the value.
//
RegDeleteValue(hkey, szValueName);
//
// Only run things marked with a "*" in clean boot.
//
if (CreateProcess( NULL,
szCmdLine,
NULL,
NULL,
FALSE,
CREATE_NEW_PROCESS_GROUP,
NULL,
NULL,
&startup,
&pi ))
{
WaitForSingleObjectEx(pi.hProcess, INFINITE, TRUE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
}
}
RegCloseKey(hkey);
}
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_RebootTheSystem
//
// This routine enables all privileges in the token, calls ExitWindowsEx
// to reboot the system, and then resets all of the privileges to their
// old state.
//
////////////////////////////////////////////////////////////////////////////
VOID Intl_RebootTheSystem()
{
HANDLE Token = NULL;
ULONG ReturnLength, Index;
PTOKEN_PRIVILEGES NewState = NULL;
PTOKEN_PRIVILEGES OldState = NULL;
BOOL Result;
Result = OpenProcessToken( GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
&Token );
if (Result)
{
ReturnLength = 4096;
NewState = (PTOKEN_PRIVILEGES)LocalAlloc(LPTR, ReturnLength);
OldState = (PTOKEN_PRIVILEGES)LocalAlloc(LPTR, ReturnLength);
Result = (BOOL)((NewState != NULL) && (OldState != NULL));
if (Result)
{
Result = GetTokenInformation( Token, // TokenHandle
TokenPrivileges, // TokenInformationClass
NewState, // TokenInformation
ReturnLength, // TokenInformationLength
&ReturnLength ); // ReturnLength
if (Result)
{
//
// Set the state settings so that all privileges are
// enabled...
//
if (NewState->PrivilegeCount > 0)
{
for (Index = 0; Index < NewState->PrivilegeCount; Index++)
{
NewState->Privileges[Index].Attributes = SE_PRIVILEGE_ENABLED;
}
}
Result = AdjustTokenPrivileges( Token, // TokenHandle
FALSE, // DisableAllPrivileges
NewState, // NewState
ReturnLength, // BufferLength
OldState, // PreviousState
&ReturnLength ); // ReturnLength
if (Result)
{
ExitWindowsEx(EWX_REBOOT, 0);
AdjustTokenPrivileges( Token,
FALSE,
OldState,
0,
NULL,
NULL );
}
}
}
}
if (NewState != NULL)
{
LocalFree(NewState);
}
if (OldState != NULL)
{
LocalFree(OldState);
}
if (Token != NULL)
{
CloseHandle(Token);
}
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_InstallUserLocale
//
// When the DefaultUserCase flag is FALSE, this function write information
// related to the locale for the current user. Otherwise, this function
// write information for the .DEFAULT user. In the Default user case, the
// the information are stored in the registry and the NTSUSER.DAT.
//
////////////////////////////////////////////////////////////////////////////
BOOL Intl_InstallUserLocale(
LCID Locale,
BOOL DefaultUserCase,
BOOL bChangeLocaleInfo )
{
HKEY hKey = NULL;
HKEY hHive = NULL;
BOOLEAN wasEnabled;
TCHAR szLCID[25];
DWORD dwRet;
//
// Save the locale id as a string.
//
wsprintf(szLCID, TEXT("%08x"), Locale);
//
// Make sure the locale is valid.
//
if (!IsValidLocale(Locale, LCID_INSTALLED))
{
if (g_bLog)
{
Intl_LogSimpleMessage(IDS_LOG_INVALID_LOCALE, szLCID);
}
return (FALSE);
}
//
// Log user locale info change.
//
if (g_bLog)
{
Intl_LogSimpleMessage(IDS_LOG_USER_LOCALE_CHG, szLCID);
}
//
// Open the right registry section.
//
if (!DefaultUserCase)
{
dwRet = RegOpenKeyEx( HKEY_CURRENT_USER,
c_szCPanelIntl,
0L,
KEY_READ | KEY_WRITE,
&hKey );
}
else
{
dwRet = RegOpenKeyEx( HKEY_USERS,
c_szCPanelIntl_DefUser,
0L,
KEY_READ | KEY_WRITE,
&hKey );
if (dwRet == ERROR_SUCCESS)
{
//
// Load the default hive.
//
if ((hHive = Intl_LoadNtUserHive( TEXT("tempKey"),
c_szCPanelIntl,
&wasEnabled )) == NULL )
{
RegCloseKey(hKey);
return (FALSE);
}
//
// Save the Locale value in NTUSER.DAT.
//
RegSetValueEx( hHive,
TEXT("Locale"),
0L,
REG_SZ,
(LPBYTE)szLCID,
(lstrlen(szLCID) + 1) * sizeof(TCHAR));
//
// Clean up.
//
RegCloseKey(hHive);
Intl_UnloadNtUserHive(TEXT("tempKey"), &wasEnabled);
}
}
//
// Set the locale value in the user's control panel international
// section of the registry.
//
if ((dwRet != ERROR_SUCCESS) ||
(RegSetValueEx( hKey,
TEXT("Locale"),
0L,
REG_SZ,
(LPBYTE)szLCID,
(lstrlen(szLCID) + 1) * sizeof(TCHAR) ) != ERROR_SUCCESS))
{
if (hKey != NULL)
{
RegCloseKey(hKey);
}
return (FALSE);
}
//
// When the locale changes, update ALL registry information when asked.
//
if (bChangeLocaleInfo)
{
Intl_SetLocaleInfo(Locale, LOCALE_SABBREVLANGNAME, TEXT("sLanguage"), DefaultUserCase);
Intl_SetLocaleInfo(Locale, LOCALE_SCOUNTRY, TEXT("sCountry"), DefaultUserCase);
Intl_SetLocaleInfo(Locale, LOCALE_ICOUNTRY, TEXT("iCountry"), DefaultUserCase);
Intl_SetLocaleInfo(Locale, LOCALE_S1159, TEXT("s1159"), DefaultUserCase);
Intl_SetLocaleInfo(Locale, LOCALE_S2359, TEXT("s2359"), DefaultUserCase);
Intl_SetLocaleInfo(Locale, LOCALE_STIMEFORMAT, TEXT("sTimeFormat"), DefaultUserCase);
Intl_SetLocaleInfo(Locale, LOCALE_STIME, TEXT("sTime"), DefaultUserCase);
Intl_SetLocaleInfo(Locale, LOCALE_ITIME, TEXT("iTime"), DefaultUserCase);
Intl_SetLocaleInfo(Locale, LOCALE_ITLZERO, TEXT("iTLZero"), DefaultUserCase);
Intl_SetLocaleInfo(Locale, LOCALE_ITIMEMARKPOSN, TEXT("iTimePrefix"), DefaultUserCase);
Intl_SetLocaleInfo(Locale, LOCALE_SSHORTDATE, TEXT("sShortDate"), DefaultUserCase);
Intl_SetLocaleInfo(Locale, LOCALE_IDATE, TEXT("iDate"), DefaultUserCase);
Intl_SetLocaleInfo(Locale, LOCALE_SDATE, TEXT("sDate"), DefaultUserCase);
Intl_SetLocaleInfo(Locale, LOCALE_SLONGDATE, TEXT("sLongDate"), DefaultUserCase);
Intl_SetLocaleInfo(Locale, LOCALE_SCURRENCY, TEXT("sCurrency"), DefaultUserCase);
Intl_SetLocaleInfo(Locale, LOCALE_ICURRENCY, TEXT("iCurrency"), DefaultUserCase);
Intl_SetLocaleInfo(Locale, LOCALE_INEGCURR, TEXT("iNegCurr"), DefaultUserCase);
Intl_SetLocaleInfo(Locale, LOCALE_ICURRDIGITS, TEXT("iCurrDigits"), DefaultUserCase);
Intl_SetLocaleInfo(Locale, LOCALE_SDECIMAL, TEXT("sDecimal"), DefaultUserCase);
Intl_SetLocaleInfo(Locale, LOCALE_SMONDECIMALSEP, TEXT("sMonDecimalSep"), DefaultUserCase);
Intl_SetLocaleInfo(Locale, LOCALE_STHOUSAND, TEXT("sThousand"), DefaultUserCase);
Intl_SetLocaleInfo(Locale, LOCALE_SMONTHOUSANDSEP, TEXT("sMonThousandSep"), DefaultUserCase);
Intl_SetLocaleInfo(Locale, LOCALE_SLIST, TEXT("sList"), DefaultUserCase);
Intl_SetLocaleInfo(Locale, LOCALE_IDIGITS, TEXT("iDigits"), DefaultUserCase);
Intl_SetLocaleInfo(Locale, LOCALE_ILZERO, TEXT("iLzero"), DefaultUserCase);
Intl_SetLocaleInfo(Locale, LOCALE_INEGNUMBER, TEXT("iNegNumber"), DefaultUserCase);
Intl_SetLocaleInfo(Locale, LOCALE_SNATIVEDIGITS, TEXT("sNativeDigits"), DefaultUserCase);
Intl_SetLocaleInfo(Locale, LOCALE_IDIGITSUBSTITUTION, TEXT("NumShape"), DefaultUserCase);
Intl_SetLocaleInfo(Locale, LOCALE_IMEASURE, TEXT("iMeasure"), DefaultUserCase);
Intl_SetLocaleInfo(Locale, LOCALE_ICALENDARTYPE, TEXT("iCalendarType"), DefaultUserCase);
Intl_SetLocaleInfo(Locale, LOCALE_IFIRSTDAYOFWEEK, TEXT("iFirstDayOfWeek"), DefaultUserCase);
Intl_SetLocaleInfo(Locale, LOCALE_IFIRSTWEEKOFYEAR, TEXT("iFirstWeekOfYear"), DefaultUserCase);
Intl_SetLocaleInfo(Locale, LOCALE_SGROUPING, TEXT("sGrouping"), DefaultUserCase);
Intl_SetLocaleInfo(Locale, LOCALE_SMONGROUPING, TEXT("sMonGrouping"), DefaultUserCase);
Intl_SetLocaleInfo(Locale, LOCALE_SPOSITIVESIGN, TEXT("sPositiveSign"), DefaultUserCase);
Intl_SetLocaleInfo(Locale, LOCALE_SNEGATIVESIGN, TEXT("sNegativeSign"), DefaultUserCase);
}
//
// Set the user's default locale in the system so that any new
// process will use the new locale.
//
if (!DefaultUserCase)
{
NtSetDefaultLocale(TRUE, Locale);
}
//
// Flush the International key.
//
if (hKey != NULL)
{
RegFlushKey(hKey);
RegCloseKey(hKey);
}
//
// Return success.
//
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_SetLocaleInfo
//
////////////////////////////////////////////////////////////////////////////
void Intl_SetLocaleInfo(
LCID Locale,
LCTYPE LCType,
LPTSTR lpIniStr,
BOOL bDefaultUserCase)
{
TCHAR pBuf[SIZE_128];
//
// Get the default information for the given locale.
//
if (GetLocaleInfo( Locale,
LCType | LOCALE_NOUSEROVERRIDE,
pBuf,
SIZE_128 ))
{
if (!bDefaultUserCase)
{
//
// Set the default information in the registry.
//
// NOTE: We want to use SetLocaleInfo if possible so that the
// NLS cache is updated right away. Otherwise, we'll
// simply use WriteProfileString.
//
if (!SetLocaleInfo(Locale, LCType, pBuf))
{
//
// If SetLocaleInfo failed, try WriteProfileString since
// some of the LCTypes are not supported in SetLocaleInfo.
//
WriteProfileString(szIntl, lpIniStr, pBuf);
}
}
else
{
//
// Set the default information in the registry and NTUSER.DAT.
//
Intl_SetDefaultUserLocaleInfo(lpIniStr, pBuf);
}
}
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_AddPage
//
////////////////////////////////////////////////////////////////////////////
void Intl_AddPage(
LPPROPSHEETHEADER ppsh,
UINT id,
DLGPROC pfn,
LPARAM lParam,
UINT iMaxPages)
{
if (ppsh->nPages < iMaxPages)
{
PROPSHEETPAGE psp;
psp.dwSize = sizeof(psp);
psp.dwFlags = PSP_DEFAULT;
psp.hInstance = hInstance;
psp.pszTemplate = MAKEINTRESOURCE(id);
psp.pfnDlgProc = pfn;
psp.lParam = lParam;
ppsh->phpage[ppsh->nPages] = CreatePropertySheetPage(&psp);
if (ppsh->phpage[ppsh->nPages])
{
ppsh->nPages++;
}
}
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_AddExternalPage
//
// Adds a property sheet page from the given dll.
//
////////////////////////////////////////////////////////////////////////////
void Intl_AddExternalPage(
LPPROPSHEETHEADER ppsh,
UINT id,
HINSTANCE hInst,
LPSTR ProcName,
UINT iMaxPages)
{
DLGPROC pfn;
if (ppsh->nPages < iMaxPages)
{
PROPSHEETPAGE psp;
if (hInst)
{
pfn = (DLGPROC)GetProcAddress(hInst, ProcName);
if (!pfn)
{
return;
}
psp.dwSize = sizeof(psp);
psp.dwFlags = PSP_DEFAULT;
psp.hInstance = hInst;
psp.pszTemplate = MAKEINTRESOURCE(id);
psp.pfnDlgProc = pfn;
psp.lParam = 0;
ppsh->phpage[ppsh->nPages] = CreatePropertySheetPage(&psp);
if (ppsh->phpage[ppsh->nPages])
{
ppsh->nPages++;
}
}
}
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_SetDefaultUserLocaleInfo
//
////////////////////////////////////////////////////////////////////////////
BOOL Intl_SetDefaultUserLocaleInfo(
LPCTSTR lpKeyName,
LPCTSTR lpString)
{
HKEY hKey = NULL;
LONG rc = 0L;
TCHAR szProfile[REGSTR_MAX_VALUE_LENGTH];
BOOLEAN wasEnabled;
//
// Open the .DEFAULT control panel international section.
//
if ((rc = RegOpenKeyEx( HKEY_USERS,
c_szCPanelIntl_DefUser,
0L,
KEY_READ | KEY_WRITE,
&hKey )) == ERROR_SUCCESS)
{
//
// Set the value
//
rc = RegSetValueEx( hKey,
lpKeyName,
0L,
REG_SZ,
(LPBYTE)lpString,
(lstrlen(lpString) + 1) * sizeof(TCHAR) );
//
// Flush the International key.
//
RegFlushKey(hKey);
RegCloseKey(hKey);
}
if (rc == ERROR_SUCCESS)
{
//
// Load the hive.
//
if ((hKey = Intl_LoadNtUserHive( TEXT("RegionalSettingsTempKey"),
c_szCPanelIntl,
&wasEnabled)) == NULL)
{
return (FALSE);
}
//
// Set the value.
//
rc = RegSetValueEx( hKey,
lpKeyName,
0L,
REG_SZ,
(LPBYTE)lpString,
(lstrlen(lpString) + 1) * sizeof(TCHAR) );
//
// Clean up.
//
RegCloseKey(hKey);
Intl_UnloadNtUserHive(TEXT("RegionalSettingsTempKey"), &wasEnabled);
}
else
{
return (FALSE);
}
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_DeleteRegKeyValues
//
// This deletes all values under a specific key.
//
////////////////////////////////////////////////////////////////////////////
void Intl_DeleteRegKeyValues(
HKEY hKey)
{
TCHAR szValueName[REGSTR_MAX_VALUE_LENGTH];
DWORD cbValue = REGSTR_MAX_VALUE_LENGTH;
//
// Sanity check.
//
if (hKey == NULL)
{
return;
}
//
// Enumerate values.
//
while (RegEnumValue( hKey,
0,
szValueName,
&cbValue,
NULL,
NULL,
NULL,
NULL ) == ERROR_SUCCESS)
{
//
// Delete the value.
//
RegDeleteValue(hKey, szValueName);
cbValue = REGSTR_MAX_VALUE_LENGTH;
}
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_DeleteRegTree
//
// This deletes all subkeys under a specific key.
//
// Note: The code makes no attempt to check or recover from partial
// deletions.
//
// A registry key that is opened by an application can be deleted
// without error by another application. This is by design.
//
////////////////////////////////////////////////////////////////////////////
DWORD Intl_DeleteRegTree(
HKEY hStartKey,
LPTSTR pKeyName)
{
DWORD dwRtn, dwSubKeyLength;
LPTSTR pSubKey = NULL;
TCHAR szSubKey[REGSTR_MAX_VALUE_LENGTH]; // (256) this should be dynamic.
HKEY hKey;
//
// Do not allow NULL or empty key name.
//
if (pKeyName && lstrlen(pKeyName))
{
if ((dwRtn = RegOpenKeyEx( hStartKey,
pKeyName,
0,
KEY_ENUMERATE_SUB_KEYS | DELETE,
&hKey )) == ERROR_SUCCESS)
{
while (dwRtn == ERROR_SUCCESS)
{
dwSubKeyLength = REGSTR_MAX_VALUE_LENGTH;
dwRtn = RegEnumKeyEx( hKey,
0, // always index zero
szSubKey,
&dwSubKeyLength,
NULL,
NULL,
NULL,
NULL );
if (dwRtn == ERROR_NO_MORE_ITEMS)
{
dwRtn = RegDeleteKey(hStartKey, pKeyName);
break;
}
else if (dwRtn == ERROR_SUCCESS)
{
dwRtn = Intl_DeleteRegTree(hKey, szSubKey);
}
}
RegCloseKey(hKey);
//
// Do not save return code because error has already occurred.
//
}
}
else
{
dwRtn = ERROR_BADKEY;
}
return (dwRtn);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_DeleteRegSubKeys
//
// This deletes all subkeys under a specific key.
//
////////////////////////////////////////////////////////////////////////////
void Intl_DeleteRegSubKeys(
HKEY hKey)
{
TCHAR szKeyName[REGSTR_MAX_VALUE_LENGTH];
DWORD cbKey = REGSTR_MAX_VALUE_LENGTH;
//
// Sanity check.
//
if (hKey == NULL)
{
return;
}
//
// Enumerate values.
//
while (RegEnumKeyEx( hKey,
0,
szKeyName,
&cbKey,
NULL,
NULL,
NULL,
NULL ) == ERROR_SUCCESS)
{
//
// Delete the value.
//
Intl_DeleteRegTree(hKey, szKeyName);
cbKey = REGSTR_MAX_VALUE_LENGTH;
}
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_CopyRegKeyValues
//
// This copies all values under the source key to the destination key.
//
////////////////////////////////////////////////////////////////////////////
DWORD Intl_CopyRegKeyValues(
HKEY hSrc,
HKEY hDest)
{
DWORD cbValue, dwSubKeyIndex=0, dwType, cdwBuf;
DWORD dwValues, cbMaxValueData, i;
TCHAR szValue[REGSTR_MAX_VALUE_LENGTH]; // this should be dynamic.
DWORD lRet = ERROR_SUCCESS;
LPBYTE pBuf;
if ((lRet = RegQueryInfoKey( hSrc,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
&dwValues,
NULL,
&cbMaxValueData,
NULL,
NULL )) == ERROR_SUCCESS)
{
if (dwValues)
{
if ((pBuf = HeapAlloc( GetProcessHeap(),
HEAP_ZERO_MEMORY,
cbMaxValueData )))
{
for (i = 0; i < dwValues; i++)
{
//
// Get values to create.
//
cbValue = REGSTR_MAX_VALUE_LENGTH;
cdwBuf = cbMaxValueData;
lRet = RegEnumValue( hSrc, // handle of key to query
i, // index of value to query
szValue, // buffer for value string
&cbValue, // address for size of buffer
NULL, // reserved
&dwType, // buffer address for type code
pBuf, // address of buffer for value data
&cdwBuf ); // address for size of buffer
if (lRet == ERROR_SUCCESS)
{
if ((lRet = RegSetValueEx( hDest,
szValue,
0,
dwType,
(CONST BYTE *)pBuf,
cdwBuf )) != ERROR_SUCCESS)
{
break;
}
}
else
{
break;
}
}
HeapFree(GetProcessHeap(), 0, pBuf);
}
}
}
return (lRet);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_CreateRegTree
//
// This copies all values and subkeys under the source key to the
// destination key.
//
////////////////////////////////////////////////////////////////////////////
DWORD Intl_CreateRegTree(
HKEY hSrc,
HKEY hDest)
{
DWORD cdwClass, dwSubKeyLength, dwDisposition, dwKeyIndex = 0;
LPTSTR pSubKey = NULL;
TCHAR szSubKey[REGSTR_MAX_VALUE_LENGTH]; // this should be dynamic.
TCHAR szClass[REGSTR_MAX_VALUE_LENGTH]; // this should be dynamic.
HKEY hNewKey, hKey;
DWORD lRet;
//
// Copy values
//
if ((lRet = Intl_CopyRegKeyValues( hSrc,
hDest )) != ERROR_SUCCESS)
{
return (lRet);
}
//
// Copy the subkeys and the subkey values.
//
for (;;)
{
dwSubKeyLength = REGSTR_MAX_VALUE_LENGTH;
cdwClass = REGSTR_MAX_VALUE_LENGTH;
lRet = RegEnumKeyEx( hSrc,
dwKeyIndex,
szSubKey,
&dwSubKeyLength,
NULL,
szClass,
&cdwClass,
NULL );
if (lRet == ERROR_NO_MORE_ITEMS)
{
lRet = ERROR_SUCCESS;
break;
}
else if (lRet == ERROR_SUCCESS)
{
if ((lRet = RegCreateKeyEx( hDest,
szSubKey,
0,
szClass,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hNewKey,
&dwDisposition )) == ERROR_SUCCESS)
{
//
// Copy all subkeys.
//
if ((lRet = RegOpenKeyEx( hSrc,
szSubKey,
0,
KEY_ALL_ACCESS,
&hKey )) == ERROR_SUCCESS)
{
//
// Recursively copy the remainder of the tree.
//
lRet = Intl_CreateRegTree(hKey, hNewKey);
CloseHandle(hKey);
CloseHandle(hNewKey);
if (lRet != ERROR_SUCCESS)
{
break;
}
}
else
{
CloseHandle(hNewKey);
break;
}
}
}
else
{
break;
}
++dwKeyIndex;
}
return (lRet);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_LoadNtUserHive
//
// The caller of this function needs to call Intl_UnloadNtUserHive() when
// the function succeeds in order to properly release the handle on the
// NTUSER.DAT file.
//
////////////////////////////////////////////////////////////////////////////
HKEY Intl_LoadNtUserHive(
LPCTSTR lpRoot,
LPCTSTR lpKeyName,
BOOLEAN *lpWasEnabled)
{
HKEY hKey = NULL;
LONG rc = 0L;
BOOL bRet = TRUE;
TCHAR szProfile[REGSTR_MAX_VALUE_LENGTH] = {0};
TCHAR szKeyName[REGSTR_MAX_VALUE_LENGTH] = {0};
DWORD cchSize;
//
// Get the file name for the Default User profile.
//
cchSize = MAX_PATH;
if (!GetDefaultUserProfileDirectory(szProfile, &cchSize))
{
return (NULL);
}
lstrcat(szProfile, TEXT("\\NTUSER.DAT"));
//
// Set the value in the Default User hive.
//
rc = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, lpWasEnabled);
if (NT_SUCCESS(rc))
{
//
// Load the hive and restore the privilege to its previous state.
//
rc = RegLoadKey(HKEY_USERS, lpRoot, szProfile);
RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, *lpWasEnabled, FALSE, lpWasEnabled);
//
// If the hive loaded properly, set the value.
//
if (rc == ERROR_SUCCESS)
{
//
// Get the temporary key name.
//
swprintf(szKeyName, TEXT("%s\\%s"), lpRoot, lpKeyName);
if ((rc = RegOpenKeyEx( HKEY_USERS,
szKeyName,
0L,
KEY_READ | KEY_WRITE,
&hKey )) == ERROR_SUCCESS)
{
return (hKey);
}
else
{
Intl_UnloadNtUserHive(lpRoot, lpWasEnabled);
return (NULL);
}
}
}
return (NULL);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_UnloadNtUserHive
//
////////////////////////////////////////////////////////////////////////////
void Intl_UnloadNtUserHive(
LPCTSTR lpRoot,
BOOLEAN *lpWasEnabled)
{
if (NT_SUCCESS(RtlAdjustPrivilege( SE_RESTORE_PRIVILEGE,
TRUE,
FALSE,
lpWasEnabled )))
{
RegUnLoadKey(HKEY_USERS, lpRoot);
RtlAdjustPrivilege( SE_RESTORE_PRIVILEGE,
*lpWasEnabled,
FALSE,
lpWasEnabled );
}
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_ChangeUILangForAllUsers
//
////////////////////////////////////////////////////////////////////////////
BOOL Intl_ChangeUILangForAllUsers(
LANGID UILanguageId)
{
HKEY hKey;
HKEY hHive;
TCHAR szData[MAX_PATH];
LONG rc = 0L;
BOOLEAN wasEnabled;
int i;
//
// Array of user accounts that we care
// S-1-5-19, local services, S-1-5-20, network services
//
LPTSTR ppDefaultUser[] = { TEXT(".DEFAULT"), TEXT("S-1-5-19"), TEXT("S-1-5-20")};
TCHAR szRegPath[MAX_PATH];
//
// Save the UILanguageId as a string.
//
wsprintf(szData, TEXT("%08x"), UILanguageId);
for (i=0; i< ARRAYSIZE(ppDefaultUser); i++)
{
if (!PathCombine(szRegPath, ppDefaultUser[i], TEXT("Control Panel\\Desktop")))
{
return (FALSE);
}
//
// Set the value in .DEFAULT registry.
//
if ((rc = RegOpenKeyEx( HKEY_USERS,
szRegPath,
0L,
KEY_READ | KEY_WRITE,
&hKey )) == ERROR_SUCCESS)
{
rc = RegSetValueEx( hKey,
c_szMUIValue,
0L,
REG_SZ,
(LPBYTE)szData,
(lstrlen(szData) + 1) * sizeof(TCHAR) );
//
// Sync up UI language pending key
//
if (rc == ERROR_SUCCESS)
{
rc = RegSetValueEx( hKey,
szMUILangPending,
0L,
REG_SZ,
(LPBYTE)szData,
(lstrlen(szData) + 1) * sizeof(TCHAR) );
}
RegCloseKey(hKey);
}
}
//
// Save the value into the .DEFAULT user hive
//
if (rc == ERROR_SUCCESS)
{
//
// Load the default hive
//
if ((hHive = Intl_LoadNtUserHive( TEXT("tempKey"),
c_szCPanelDesktop,
&wasEnabled )) == NULL )
{
return (FALSE);
}
//
// Save the MUI language value in the NTUSER.dat
//
RegSetValueEx( hHive,
c_szMUIValue,
0L,
REG_SZ,
(LPBYTE)szData,
(lstrlen(szData) + 1) * sizeof(TCHAR));
//
// Sync up UI language pending key
//
if (rc == ERROR_SUCCESS)
{
rc = RegSetValueEx( hHive,
szMUILangPending,
0L,
REG_SZ,
(LPBYTE)szData,
(lstrlen(szData) + 1) * sizeof(TCHAR) );
}
//
// Clean up
//
RegCloseKey(hHive);
Intl_UnloadNtUserHive(TEXT("tempKey"), &wasEnabled);
}
else
{
return (FALSE);
}
//
// Install Language Input locales.
//
return Intl_InstallKeyboardLayout(NULL,
MAKELCID(UILanguageId, SORT_DEFAULT),
0,
FALSE,
TRUE,
FALSE);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_LoadLanguageGroups
//
////////////////////////////////////////////////////////////////////////////
BOOL Intl_LoadLanguageGroups(
HWND hDlg)
{
LPLANGUAGEGROUP pLG;
DWORD dwExStyle;
RECT Rect;
LV_COLUMN Column;
LV_ITEM Item;
int iIndex;
//
// Open the Inf file.
//
g_hIntlInf = SetupOpenInfFile(szIntlInf, NULL, INF_STYLE_WIN4, NULL);
if (g_hIntlInf == INVALID_HANDLE_VALUE)
{
return (FALSE);
}
if (!SetupOpenAppendInfFile(NULL, g_hIntlInf, NULL))
{
SetupCloseInfFile(g_hIntlInf);
g_hIntlInf = NULL;
return (FALSE);
}
//
// Get all supported language groups from the inf file.
//
if (Intl_GetSupportedLanguageGroups() == FALSE)
{
return (FALSE);
}
//
// Close the inf file.
//
SetupCloseInfFile(g_hIntlInf);
g_hIntlInf = NULL;
//
// Enumerate all installed language groups.
//
if (Intl_EnumInstalledLanguageGroups() == FALSE)
{
return (FALSE);
}
//
// Return success.
//
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_GetSupportedLanguageGroups
//
////////////////////////////////////////////////////////////////////////////
BOOL Intl_GetSupportedLanguageGroups()
{
UINT LanguageGroup;
HANDLE hLanguageGroup;
LPLANGUAGEGROUP pLG;
INFCONTEXT Context;
TCHAR szSection[MAX_PATH];
TCHAR szTemp[MAX_PATH];
int LineCount, LineNum;
DWORD ItemCount;
WORD wItemStatus;
//
// Get the number of supported language groups from the inf file.
//
LineCount = (UINT)SetupGetLineCount(g_hIntlInf, TEXT("LanguageGroups"));
if (LineCount <= 0)
{
return (FALSE);
}
//
// Go through all supported language groups in the inf file.
//
for (LineNum = 0; LineNum < LineCount; LineNum++)
{
if (SetupGetLineByIndex(g_hIntlInf, TEXT("LanguageGroups"), LineNum, &Context) &&
SetupGetIntField(&Context, 0, &LanguageGroup))
{
//
// Create the new node.
//
if (!(hLanguageGroup = GlobalAlloc(GHND, sizeof(LANGUAGEGROUP))))
{
return (FALSE);
}
pLG = GlobalLock(hLanguageGroup);
//
// Fill in the new node with the appropriate info.
//
pLG->wStatus = 0;
pLG->LanguageGroup = LanguageGroup;
pLG->hLanguageGroup = hLanguageGroup;
(pLG->pszName)[0] = 0;
pLG->NumLocales = 0;
pLG->NumAltSorts = 0;
//
// Set the collection
//
if ((pLG->LanguageGroup == LGRPID_JAPANESE) ||
(pLG->LanguageGroup == LGRPID_KOREAN) ||
(pLG->LanguageGroup == LGRPID_TRADITIONAL_CHINESE) ||
(pLG->LanguageGroup == LGRPID_SIMPLIFIED_CHINESE) )
{
pLG->LanguageCollection = CJK_COLLECTION;
}
else if ((pLG->LanguageGroup == LGRPID_ARABIC) ||
(pLG->LanguageGroup == LGRPID_ARMENIAN) ||
(pLG->LanguageGroup == LGRPID_GEORGIAN) ||
(pLG->LanguageGroup == LGRPID_HEBREW) ||
(pLG->LanguageGroup == LGRPID_INDIC) ||
(pLG->LanguageGroup == LGRPID_VIETNAMESE) ||
(pLG->LanguageGroup == LGRPID_THAI))
{
pLG->LanguageCollection = COMPLEX_COLLECTION;
}
else
{
pLG->LanguageCollection = BASIC_COLLECTION;
}
//
// Get the appropriate display string.
//
if (!SetupGetStringField(&Context, 1, pLG->pszName, MAX_PATH, NULL))
{
GlobalUnlock(hLanguageGroup);
GlobalFree(hLanguageGroup);
continue;
}
//
// Get the list of locales for this language group.
//
if (Intl_GetLocaleList(pLG) == FALSE)
{
return (FALSE);
}
//
// Add the language group to the front of the linked list.
//
pLG->pNext = pLanguageGroups;
pLanguageGroups = pLG;
}
}
//
// Return success.
//
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_EnumInstalledLanguageGroups
//
////////////////////////////////////////////////////////////////////////////
BOOL Intl_EnumInstalledLanguageGroups()
{
HKEY hKey;
TCHAR szValue[MAX_PATH];
TCHAR szData[MAX_PATH];
TCHAR szDefault[SIZE_64];
DWORD dwIndex, cchValue, cbData;
LONG rc;
UINT LanguageGroup, OriginalGroup, DefaultGroup, UILanguageGroup;
LPLANGUAGEGROUP pLG;
LCID Locale;
LANGID Language;
int Ctr;
//
// Get the original install language so that we can mark that
// language group as permanent.
//
Language = GetSystemDefaultUILanguage();
if (SUBLANGID(Language) == SUBLANG_NEUTRAL)
{
Language = MAKELANGID(PRIMARYLANGID(Language), SUBLANG_DEFAULT);
}
if ((OriginalGroup = Intl_GetLanguageGroup(Language)) == 0)
{
OriginalGroup = 1;
}
//
// Get the default system locale so that we can mark that language
// group as permanent. During gui mode setup, read the system locale from
// the registry to make the info on the setup page consistent with intl.cpl.
// SysLocaleID will be the registry value in case of setup.
//
Locale = SysLocaleID;
if (Locale == (LCID)Language)
{
DefaultGroup = OriginalGroup;
}
else
{
if ((DefaultGroup = Intl_GetLanguageGroup(Locale)) == 0)
{
DefaultGroup = 1;
}
}
//
// Get the UI language's language groups to disable the user from
// un-installing them. MUISETUP makes sure that each installed UI
// language has its language group installed.
//
Intl_GetUILanguageGroups(&UILangGroup);
//
// Open the HKLM\SYSTEM\CurrentControlSet\Control\Nls\Language Groups
// key.
//
if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
c_szLanguageGroups,
0,
KEY_READ,
&hKey ) != ERROR_SUCCESS)
{
return (FALSE);
}
//
// Enumerate the values in the Language Groups key.
//
dwIndex = 0;
cchValue = sizeof(szValue) / sizeof(TCHAR);
szValue[0] = TEXT('\0');
cbData = sizeof(szData);
szData[0] = TEXT('\0');
rc = RegEnumValue( hKey,
dwIndex,
szValue,
&cchValue,
NULL,
NULL,
(LPBYTE)szData,
&cbData );
while (rc == ERROR_SUCCESS)
{
//
// If the language group contains data, then it is installed.
//
if ((szData[0] != 0) &&
(LanguageGroup = TransNum(szValue)))
{
//
// Find the language group in the linked list and mark it as
// originally installed.
//
pLG = pLanguageGroups;
while (pLG)
{
if (pLG->LanguageGroup == LanguageGroup)
{
pLG->wStatus |= ML_INSTALL;
//
// If this is a language group for a UI language that's
// installed, then disable the un-installation of this
// language group.
//
Ctr = 0;
while (Ctr < UILangGroup.iCount)
{
if (UILangGroup.lgrp[Ctr] == LanguageGroup)
{
pLG->wStatus |= ML_PERMANENT;
break;
}
Ctr++;
}
if (pLG->LanguageGroup == OriginalGroup)
{
pLG->wStatus |= ML_PERMANENT;
}
if (pLG->LanguageGroup == DefaultGroup)
{
pLG->wStatus |= (ML_PERMANENT | ML_DEFAULT);
if (LoadString(hInstance, IDS_DEFAULT, szDefault, SIZE_64))
{
lstrcat(pLG->pszName, szDefault);
}
}
break;
}
pLG = pLG->pNext;
}
}
//
// Get the next enum value.
//
dwIndex++;
cchValue = sizeof(szValue) / sizeof(TCHAR);
szValue[0] = TEXT('\0');
cbData = sizeof(szData);
szData[0] = TEXT('\0');
rc = RegEnumValue( hKey,
dwIndex,
szValue,
&cchValue,
NULL,
NULL,
(LPBYTE)szData,
&cbData );
}
//
// Close the registry key handle.
//
RegCloseKey(hKey);
//
// Return success.
//
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_LanguageGroupDirExist
//
////////////////////////////////////////////////////////////////////////////
BOOL Intl_LanguageGroupDirExist(
PTSTR pszLangDir)
{
TCHAR szLanguageGroupDir[MAX_PATH];
WIN32_FIND_DATA FindData;
HANDLE FindHandle;
TCHAR SavedChar;
//
// If it doesn't start with lang, then this is a core language.
//
SavedChar = pszLangDir[4];
pszLangDir[4] = TEXT('\0');
if (lstrcmp(pszLangDir, TEXT("lang")))
{
return (TRUE);
}
pszLangDir[4] = SavedChar;
//
// Format the path to the language group directory.
//
lstrcpy(szLanguageGroupDir, pSetupSourcePathWithArchitecture);
lstrcat(szLanguageGroupDir, TEXT("\\"));
lstrcat(szLanguageGroupDir, pszLangDir);
//
// See if the language group directory exists.
//
FindHandle = FindFirstFile(szLanguageGroupDir, &FindData);
if (FindHandle != INVALID_HANDLE_VALUE)
{
FindClose(FindHandle);
if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
//
// Return success.
//
return (TRUE);
}
}
//
// Return failure.
//
return (FALSE);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_LanguageGroupFilesExist
//
////////////////////////////////////////////////////////////////////////////
BOOL Intl_LanguageGroupFilesExist()
{
TCHAR szLanguageGroupDir[MAX_PATH];
WIN32_FIND_DATA FindData;
HANDLE FindHandle;
//
// Format the path to the language group directory. Add the wildcard
// to search for any files located in the lang directory.
//
lstrcpy(szLanguageGroupDir, pSetupSourcePathWithArchitecture);
lstrcat(szLanguageGroupDir, TEXT("\\Lang\\*"));
//
// See if at least one file exists.
//
FindHandle = FindFirstFile(szLanguageGroupDir, &FindData);
if (FindHandle != INVALID_HANDLE_VALUE)
{
FindClose(FindHandle);
//
// Return success.
//
return (TRUE);
}
//
// Return failure.
//
return (FALSE);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_GetLocaleList
//
////////////////////////////////////////////////////////////////////////////
BOOL Intl_GetLocaleList(
LPLANGUAGEGROUP pLG)
{
TCHAR szSection[MAX_PATH];
INFCONTEXT Context;
int LineCount, LineNum;
LCID Locale;
//
// Get the inf section name.
//
wsprintf(szSection, TEXT("%ws%d"), szLocaleListPrefix, pLG->LanguageGroup);
//
// Get the number of locales for the language group.
//
LineCount = (UINT)SetupGetLineCount(g_hIntlInf, szSection);
if (LineCount <= 0)
{
return (FALSE);
}
//
// Add each locale in the list to the language group node.
//
for (LineNum = 0; LineNum < LineCount; LineNum++)
{
if (SetupGetLineByIndex(g_hIntlInf, szSection, LineNum, &Context) &&
SetupGetIntField(&Context, 0, &Locale))
{
if (SORTIDFROMLCID(Locale))
{
//
// Add the locale to the alternate sort list for this
// language group.
//
if (pLG->NumAltSorts >= MAX_PATH)
{
return (FALSE);
}
pLG->pAltSortList[pLG->NumAltSorts] = Locale;
(pLG->NumAltSorts)++;
}
else
{
//
// Add the locale to the locale list for this
// language group.
//
if (pLG->NumLocales >= MAX_PATH)
{
return (FALSE);
}
pLG->pLocaleList[pLG->NumLocales] = Locale;
(pLG->NumLocales)++;
}
}
}
//
// Return success.
//
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// Region_GetLocaleLanguageGroup
//
// Reads the Language Group Id of the given language.
//
////////////////////////////////////////////////////////////////////////////
DWORD Intl_GetLanguageGroup(
LCID lcid)
{
TCHAR szValue[MAX_PATH];
TCHAR szData[MAX_PATH];
HKEY hKey;
DWORD cbData;
wsprintf(szValue, TEXT("%8.8x"), lcid);
szData[0] = 0;
if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
c_szInstalledLocales,
0,
KEY_READ,
&hKey ) == ERROR_SUCCESS)
{
cbData = sizeof(szData);
RegQueryValueEx(hKey, szValue, NULL, NULL, (LPBYTE)szData, &cbData);
RegCloseKey(hKey);
}
return (TransNum(szData));
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_GetUILanguageGroups
//
// Reads the language groups of all the UI languages installed on this
// machine.
//
////////////////////////////////////////////////////////////////////////////
BOOL Intl_GetUILanguageGroups(
PUILANGUAGEGROUP pUILanguageGroup)
{
//
// Enumerate the installed UI languages.
//
pUILanguageGroup->iCount = 0L;
EnumUILanguages(Intl_EnumUILanguagesProc, 0, (LONG_PTR)pUILanguageGroup);
//
// Return success.
//
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_EnumUILanguagesProc
//
////////////////////////////////////////////////////////////////////////////
BOOL CALLBACK Intl_EnumUILanguagesProc(
LPWSTR pwszUILanguage,
LONG_PTR lParam)
{
int Ctr = 0;
LGRPID lgrp;
PUILANGUAGEGROUP pUILangGroup = (PUILANGUAGEGROUP)lParam;
LCID UILanguage = TransNum(pwszUILanguage);
if (UILanguage)
{
if ((lgrp = Intl_GetLanguageGroup(UILanguage)) == 0)
{
lgrp = 1; // default;
}
while (Ctr < pUILangGroup->iCount)
{
if (pUILangGroup->lgrp[Ctr] == lgrp)
{
break;
}
Ctr++;
}
//
// Theoritically, we won't go over 64 language groups!
//
if ((Ctr == pUILangGroup->iCount) && (Ctr < MAX_UI_LANG_GROUPS))
{
pUILangGroup->lgrp[Ctr] = lgrp;
pUILangGroup->iCount++;
}
}
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_SaveValuesToDefault
//
// This function copies the current user settings under the srcKey to
// the Default user under the destKey.
//
////////////////////////////////////////////////////////////////////////////
void Intl_SaveValuesToDefault(
LPCTSTR srcKey,
LPCTSTR destKey)
{
HKEY hkeyLayouts;
HKEY hkeyLayouts_DefUser;
//
// 1. Open the Current user key.
//
if (RegOpenKeyEx( HKEY_CURRENT_USER,
srcKey,
0,
KEY_ALL_ACCESS,
&hkeyLayouts ) != ERROR_SUCCESS)
{
return;
}
//
// 2. Open the .Default hive key.
//
if (RegOpenKeyEx( HKEY_USERS,
destKey,
0,
KEY_ALL_ACCESS,
&hkeyLayouts_DefUser ) != ERROR_SUCCESS)
{
RegCloseKey(hkeyLayouts);
return;
}
//
// 3. Delete .Default key values.
//
Intl_DeleteRegKeyValues(hkeyLayouts_DefUser);
//
// 4. Delete .Default subkeys.
//
Intl_DeleteRegSubKeys(hkeyLayouts_DefUser);
//
// 5. Copy tree.
//
Intl_CreateRegTree(hkeyLayouts, hkeyLayouts_DefUser);
//
// 6. Clean up
//
RegCloseKey(hkeyLayouts_DefUser);
RegCloseKey(hkeyLayouts);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_SaveValuesToNtUserFile
//
// This function copy current user setting under the srcKey to the Default
// user hive under the destKey.
//
////////////////////////////////////////////////////////////////////////////
void Intl_SaveValuesToNtUserFile(
HKEY hSourceRegKey,
LPCTSTR srcKey,
LPCTSTR destKey)
{
HKEY hRegKey;
HKEY hHive;
BOOLEAN wasEnabled;
//
// 1. Open the Current user key.
//
if (RegOpenKeyEx( hSourceRegKey,
srcKey,
0,
KEY_READ,
&hRegKey ) != ERROR_SUCCESS)
{
return;
}
//
// 2. Load the hive to a temporary key location.
//
if ((hHive = Intl_LoadNtUserHive( TEXT("TempKey"),
destKey,
&wasEnabled )) == NULL)
{
RegCloseKey(hRegKey);
return;
}
//
// 3. Delete .Default key values.
//
Intl_DeleteRegKeyValues(hHive);
//
// 4. Delete .Default subkeys.
//
Intl_DeleteRegSubKeys(hHive);
//
// 5. Copy tree.
//
Intl_CreateRegTree(hRegKey, hHive);
//
// 6. Clean up.
//
RegCloseKey(hHive);
Intl_UnloadNtUserHive(TEXT("TempKey"), &wasEnabled);
RegCloseKey(hRegKey);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_IsSetupMode
//
// Look into the registry if we are currently in setup mode.
//
////////////////////////////////////////////////////////////////////////////
BOOL Intl_IsSetupMode()
{
HKEY hKey;
DWORD fSystemSetupInProgress = 0;
DWORD cbData = 0;
//
// Open the registry key used by setup
//
if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
c_szSetupKey,
0,
KEY_READ,
&hKey ) != ERROR_SUCCESS)
{
return (FALSE);
}
//
// Query for the value indicating that we are in setup.
//
cbData = sizeof(fSystemSetupInProgress);
if (RegQueryValueEx( hKey,
szSetupInProgress,
NULL,
NULL,
(LPBYTE)&fSystemSetupInProgress,
&cbData ) != ERROR_SUCCESS)
{
RegCloseKey(hKey);
return (FALSE);
}
//
// Clean up
//
RegCloseKey(hKey);
//
// Check the value
//
if (fSystemSetupInProgress)
{
//
// In setup mode...
//
if (g_bLog)
{
Intl_LogSimpleMessage(IDS_LOG_SETUP_MODE, NULL);
}
return (TRUE);
}
return (FALSE);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_IsWinntUpgrade
//
// Look into the registry if we are currently in winnt upgrade.
//
////////////////////////////////////////////////////////////////////////////
BOOL Intl_IsWinntUpgrade()
{
HKEY hKey;
DWORD fUpgradeInProgress = 0;
DWORD cbData = 0;
//
// Verify that we're in setup first.
//
if (!g_bSetupCase)
{
return (FALSE);
}
//
// Open the registry key used by setup.
//
if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
c_szSetupKey,
0,
KEY_READ,
&hKey ) != ERROR_SUCCESS)
{
return (FALSE);
}
//
// Query for the value indicating that we are in setup.
//
cbData = sizeof(fUpgradeInProgress);
if (RegQueryValueEx( hKey,
szSetupUpgrade,
NULL,
NULL,
(LPBYTE)&fUpgradeInProgress,
&cbData ) != ERROR_SUCCESS)
{
RegCloseKey(hKey);
return (FALSE);
}
//
// Clean up.
//
RegCloseKey(hKey);
//
// Check the value.
//
if (fUpgradeInProgress)
{
//
// Upgrade scenario.
//
if (g_bLog)
{
Intl_LogSimpleMessage(IDS_LOG_UPGRADE_SCENARIO, NULL);
}
return (TRUE);
}
return (FALSE);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_IsUIFontSubstitute
//
// Look into the registry if we need to substitute the font.
//
////////////////////////////////////////////////////////////////////////////
BOOL Intl_IsUIFontSubstitute()
{
HKEY hKey;
DWORD fUIFontSubstitute = 0;
DWORD cbData = 0;
//
// Command line call, no need to check registry
//
if (g_bMatchUIFont)
{
return (TRUE);
}
//
// Open the registry key used MUI font substitution.
//
if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
c_szMUILanguages,
0,
KEY_READ,
&hKey ) != ERROR_SUCCESS)
{
return (FALSE);
}
//
// Query for the value indicating that we need to apply font
// substitution.
//
cbData = sizeof(fUIFontSubstitute);
if (RegQueryValueEx( hKey,
szUIFontSubstitute,
NULL,
NULL,
(LPBYTE)&fUIFontSubstitute,
&cbData ) != ERROR_SUCCESS)
{
RegCloseKey(hKey);
return (FALSE);
}
//
// Clean up.
//
RegCloseKey(hKey);
//
// Check the value.
//
if (fUIFontSubstitute)
{
//
// Upgrade scenario.
//
if (g_bLog)
{
Intl_LogSimpleMessage(IDS_LOG_FONT_SUBSTITUTE, NULL);
}
return (TRUE);
}
return (FALSE);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_ApplyFontSubstitute
//
// Search into the intl.inf file to see of the SystemLocale need font
// substitution.
//
////////////////////////////////////////////////////////////////////////////
VOID Intl_ApplyFontSubstitute(LCID SystemLocale)
{
HINF hIntlInf;
TCHAR szLCID[25];
INFCONTEXT Context;
TCHAR szFont[MAX_PATH] = {0};
TCHAR szFontSubst[MAX_PATH] = {0};
HKEY hKey;
//
// Open the Intl.inf file.
//
if (Intl_OpenIntlInfFile(&hIntlInf))
{
//
// Get the locale.
//
wsprintf(szLCID, TEXT("%08x"), SystemLocale);
//
// Look for the Font Substitute section.
//
if (SetupFindFirstLine( hIntlInf,
szFontSubstitute,
szLCID,
&Context ))
{
//
// Look for the Font and Font Substitute
//
if (!SetupGetStringField( &Context,
1,
szFont,
MAX_PATH,
NULL ) ||
!SetupGetStringField( &Context,
2,
szFontSubst,
MAX_PATH,
NULL ))
{
//
// Clean up.
//
Intl_CloseInfFile(hIntlInf);
return;
}
}
else
{
//
// Nothing to do for this specific locale. Clean up.
//
Intl_CloseInfFile(hIntlInf);
return;
}
}
else
{
return;
}
//
// Close the Intl.inf file
//
Intl_CloseInfFile(hIntlInf);
//
// Proceed with the font replacement.
//
if (szFont[0] && szFontSubst[0])
{
//
// Open the Font Substitute registry key.
//
if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
c_szFontSubstitute,
0L,
KEY_READ | KEY_WRITE,
&hKey ) == ERROR_SUCCESS)
{
//
// Set the Font value with the Font Substitute.
//
RegSetValueEx( hKey,
szFont,
0L,
REG_SZ,
(LPBYTE)szFontSubst,
(lstrlen(szFontSubst) + 1) * sizeof(TCHAR) );
RegCloseKey(hKey);
}
}
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_OpenLogFile
//
// Opens the Region and Languages Options log for writing.
//
////////////////////////////////////////////////////////////////////////////
HANDLE Intl_OpenLogFile()
{
DWORD dwSize;
DWORD dwUnicodeHeader;
HANDLE hFile;
SECURITY_ATTRIBUTES SecurityAttributes;
TCHAR lpPath[MAX_PATH];
GetWindowsDirectory(lpPath, MAX_PATH);
_tcscat(lpPath, TEXT("\\regopt.log"));
SecurityAttributes.nLength = sizeof(SecurityAttributes);
SecurityAttributes.lpSecurityDescriptor = NULL;
SecurityAttributes.bInheritHandle = FALSE;
hFile = CreateFile( lpPath,
GENERIC_WRITE,
0,
&SecurityAttributes,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL );
#ifdef UNICODE
//
// If the file did not already exist, add the unicode header.
//
if (GetLastError() == 0)
{
dwUnicodeHeader = 0xFEFF;
WriteFile(hFile, &dwUnicodeHeader, 2, &dwSize, NULL);
}
#endif
return (hFile);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_LogMessage
//
// Writes lpMessage to the Region and Languages Options log.
//
////////////////////////////////////////////////////////////////////////////
BOOL Intl_LogMessage(
LPCTSTR lpMessage)
{
DWORD dwBytesWritten;
HANDLE hFile;
if (!g_bLog)
{
return (FALSE);
}
if (lpMessage == NULL)
{
return (TRUE);
}
hFile = Intl_OpenLogFile();
if (hFile == INVALID_HANDLE_VALUE)
{
return (FALSE);
}
SetFilePointer(hFile, 0, NULL, FILE_END);
WriteFile( hFile,
lpMessage,
_tcslen(lpMessage) * sizeof(TCHAR),
&dwBytesWritten,
NULL );
SetFilePointer(hFile, 0, NULL, FILE_END);
WriteFile( hFile,
TEXT("\r\n"),
_tcslen(TEXT("\r\n")) * sizeof(TCHAR),
&dwBytesWritten,
NULL );
CloseHandle(hFile);
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_LogUnattendFile
//
// Writes the unattended mode file to the setup log.
//
////////////////////////////////////////////////////////////////////////////
void Intl_LogUnattendFile(
LPCTSTR pFileName)
{
DWORD dwSize;
HANDLE hFile;
OFSTRUCT fileInfo;
BOOL bResult;
CHAR inBuffer[MAX_PATH] = {0};
DWORD nBytesRead;
WCHAR outBufferW[MAX_PATH] = {0};
int nWCharRead;
DWORD status;
//
// Open the unattended mode file.
//
if ((hFile = CreateFile( pFileName,
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL )) == INVALID_HANDLE_VALUE)
{
return;
}
//
// Write the header.
//
Intl_LogSimpleMessage(IDS_LOG_UNAT_HEADER, NULL);
//
// Read the unattended mode file in 259 byte chunks.
//
while (bResult = ReadFile( hFile,
(LPVOID)&inBuffer,
MAX_PATH - 1,
&nBytesRead,
NULL ) && (nBytesRead > 0))
{
//
// Null terminated string.
//
inBuffer[nBytesRead] = '\0';
//
// Convert the ansi data to unicode.
//
nWCharRead = MultiByteToWideChar( CP_ACP,
MB_PRECOMPOSED,
inBuffer,
nBytesRead,
outBufferW,
MAX_PATH );
//
// Write to the log file.
//
if (nWCharRead)
{
Intl_LogMessage((LPCTSTR)outBufferW);
}
}
//
// Write the footer.
//
Intl_LogSimpleMessage(IDS_LOG_UNAT_FOOTER, NULL);
//
// Cleanup.
//
CloseHandle(hFile);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_LogSimpleMessage
//
// Writes a simple message to the log file.
//
////////////////////////////////////////////////////////////////////////////
void Intl_LogSimpleMessage(
UINT LogId,
LPCTSTR pAppend)
{
TCHAR szLogBuffer[4 * MAX_PATH];
LoadString(hInstance, LogId, szLogBuffer, ARRAYSIZE(szLogBuffer) - 1);
if (pAppend)
{
_tcscat(szLogBuffer, pAppend);
}
Intl_LogMessage(szLogBuffer);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_LogFormatMessage
//
// Writes an error message using FormatMessage to the log file.
//
////////////////////////////////////////////////////////////////////////////
void Intl_LogFormatMessage(
UINT LogId)
{
LPVOID lpMsgBuf = NULL;
TCHAR szLogBuffer[4 * MAX_PATH];
//
// Get the message for the last error.
//
FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL );
//
// Load the log message.
//
LoadString( hInstance,
LogId,
szLogBuffer,
ARRAYSIZE(szLogBuffer) - 1 );
//
// Concatenate the log message and the last error.
//
_tcscat(szLogBuffer, lpMsgBuf);
//
// Log the message to the log file.
//
Intl_LogMessage(szLogBuffer);
//
// Free the buffer created by FormatMessage.
//
if (lpMsgBuf)
{
LocalFree(lpMsgBuf);
}
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_SaveDefaultUserSettings
//
// This function will get information from the the current user and write it in
// the .DEFAULT and NTUSER.DAT file.
//
////////////////////////////////////////////////////////////////////////////
void Intl_SaveDefaultUserSettings()
{
//
// Check if the Default user settings have been saved already.
//
if (g_bSettingsChanged)
{
DWORD dwDisposition;
HKEY hDesKey, hSrcKey;
//
// Set the UI Language for ALL new users of this machine.
//
Intl_ChangeUILangForAllUsers(Intl_GetPendingUILanguage());
//
// Copy the International keys and subkeys.
//
Intl_SaveValuesToDefault(c_szCPanelIntl, c_szCPanelIntl_DefUser);
Intl_SaveValuesToNtUserFile(HKEY_CURRENT_USER, c_szCPanelIntl, c_szCPanelIntl);
//
// Copy only the CTFMON information.
//
if(RegOpenKeyEx( HKEY_CURRENT_USER,
c_szCtfmon,
0,
KEY_ALL_ACCESS,
&hSrcKey) == ERROR_SUCCESS)
{
if(RegOpenKeyEx( HKEY_USERS,
c_szCtfmon_DefUser,
0,
KEY_ALL_ACCESS,
&hDesKey) == ERROR_SUCCESS)
{
DWORD dwValueLength, dwType;
TCHAR szValue[REGSTR_MAX_VALUE_LENGTH];
//
// Get the source value if exist.
//
szValue[0] = 0;
dwValueLength = sizeof(szValue);
if(RegQueryValueEx( hSrcKey,
szCtfmonValue,
NULL,
&dwType,
(LPBYTE)szValue,
&dwValueLength) == ERROR_SUCCESS)
{
//
// Set the destination value.
//
RegSetValueEx( hDesKey,
szCtfmonValue,
0L,
dwType,
(CONST BYTE *)szValue,
dwValueLength);
}
CloseHandle(hDesKey);
}
CloseHandle(hSrcKey);
}
Intl_SaveValuesToNtUserFile(HKEY_CURRENT_USER, c_szCtfmon, c_szCtfmon);
//
// Copy the Keyboard Layouts keys and subkeys.
//
Intl_SaveValuesToDefault(c_szKbdLayouts, c_szKbdLayouts_DefUser);
Intl_SaveValuesToNtUserFile(HKEY_CURRENT_USER, c_szKbdLayouts, c_szKbdLayouts);
//
// Copy the Input Method keys and subkeys.
//
Intl_SaveValuesToDefault(c_szInputMethod, c_szInputMethod_DefUser);
Intl_SaveValuesToNtUserFile(HKEY_CURRENT_USER, c_szInputMethod, c_szInputMethod);
//
// Copy the Tips keys and subkeys. Make sure that the CTF
// destination key exist.
//
if (RegCreateKeyEx( HKEY_USERS,
c_szInputTips_DefUser,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hDesKey,
&dwDisposition ) == ERROR_SUCCESS)
{
CloseHandle(hDesKey);
Intl_SaveValuesToDefault(c_szInputTips, c_szInputTips_DefUser);
Intl_SaveValuesToNtUserFile(HKEY_CURRENT_USER, c_szInputTips, c_szInputTips);
}
//
// Settings saved.
//
g_bSettingsChanged = FALSE;
}
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_SaveDefaultUserInputSettings
//
// This function copy .Default user input-related setting to ntuser.dat.
// There are four things to copy to make keyboard layout work for
// new users:
// * "Software\\Microsoft\\Windows\\CurrentVersion\\Run\\ctfmon.exe" (if any)
// * "Keyboard Layout"
// * "Control Panel\\Input Method"
// * "Software\\Microsoft\\CTF" (if any)
//
////////////////////////////////////////////////////////////////////////////
BOOL Intl_SaveDefaultUserInputSettings()
{
HKEY hDesKey;
DWORD dwDisposition;
//
// The following call will copy everything under Windows\CurrentVersion\Run
// to ntuser.dat.
//
Intl_SaveValuesToNtUserFile(HKEY_USERS, c_szCtfmon_DefUser, c_szCtfmon);
//
// Copy the Keyboard Layouts keys and subkeys.
//
Intl_SaveValuesToNtUserFile(HKEY_USERS, c_szKbdLayouts_DefUser, c_szKbdLayouts);
//
// Copy the Input Method keys and subkeys.
//
Intl_SaveValuesToNtUserFile(HKEY_USERS, c_szInputMethod_DefUser, c_szInputMethod);
//
// Copy the Tips keys and subkeys. Make sure that the CTF
// destination key exist.
//
if (RegCreateKeyEx( HKEY_USERS,
c_szInputTips_DefUser,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_READ,
NULL,
&hDesKey,
&dwDisposition ) == ERROR_SUCCESS)
{
CloseHandle(hDesKey);
Intl_SaveValuesToNtUserFile(HKEY_USERS, c_szInputTips_DefUser, c_szInputTips);
}
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_IsMUIFileVersionSameAsOS
//
////////////////////////////////////////////////////////////////////////////
#define MUISETUP_EXE_RELATIVE_PATH TEXT("mui\\muisetup.exe")
#define MUISETUP_INF_RELATIVE_PATH TEXT("mui\\mui.inf")
BOOL Intl_IsMUISetupVersionSameAsOS()
{
BOOL bSpUpgrade = FALSE;
DWORD dwDummy = 0;
DWORD dwBufSize = 0;
UINT uiLen = 0;
BYTE *pbBuffer = NULL;
VS_FIXEDFILEINFO *pvsFileInfo;
BOOL bResult = TRUE;
TCHAR tempmsg[MAX_PATH];
TCHAR build[MAX_PATH];
TCHAR szAppPath[MAX_PATH];
TCHAR szInfPath[MAX_PATH];
GetSystemWindowsDirectory(szAppPath, ARRAYSIZE(szAppPath));
GetSystemWindowsDirectory(szInfPath, ARRAYSIZE(szInfPath));
//
// Invoke muisetup to uninstall MUI languages.
//
if ((PathAppend(szAppPath, MUISETUP_EXE_RELATIVE_PATH) && Intl_FileExists(szAppPath)) &&
(PathAppend(szInfPath, MUISETUP_INF_RELATIVE_PATH) && Intl_FileExists(szInfPath)))
{
dwBufSize = GetFileVersionInfoSize(szAppPath, &dwDummy);
if (dwBufSize > 0)
{
// allocate enough buffer to store the file version info
pbBuffer = (BYTE*) LocalAlloc(LPTR, dwBufSize+1);
if (NULL == pbBuffer)
{
goto Exit;
}
else
{
// Get the file version info
if (!GetFileVersionInfo(szAppPath, dwDummy, dwBufSize, pbBuffer))
{
goto Exit;
}
else
{
// get the version from the file version info using VerQueryValue
if (!VerQueryValue(pbBuffer, TEXT("\\"), (LPVOID *) &pvsFileInfo, &uiLen))
{
goto Exit;
}
}
}
}
else
{
goto Exit;
}
// read the mui.inf version from mui.inf
GetPrivateProfileString( TEXT("Buildnumber"),
NULL,
TEXT("0"),
tempmsg,
ARRAYSIZE(tempmsg),
szInfPath);
wsprintf(build, TEXT("%d"), HIWORD(pvsFileInfo->dwFileVersionLS));
if (_tcscmp(tempmsg, build))
{
bSpUpgrade = FALSE;
}
else
{
bSpUpgrade = TRUE;
}
}
Exit:
if (pbBuffer)
{
LocalFree(pbBuffer);
}
return bSpUpgrade;
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_IsLIP
//
////////////////////////////////////////////////////////////////////////////
BOOL Intl_IsLIP()
{
BOOL bResult = TRUE;
UINT iLangCount = 0;
HKEY hKey;
TCHAR szValue[MAX_PATH];
TCHAR szData[MAX_PATH];
DWORD dwIndex, cchValue, cbData;
DWORD UILang;
DWORD dwType;
LONG rc;
//
// First check for the LIP System Key, if it is there, then we are done
//
if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
c_szLIPInstalled,
0,
KEY_READ,
&hKey ) == ERROR_SUCCESS)
{
RegCloseKey(hKey);
return (TRUE);
}
//
// if not found, then open the registry key used MUI to doublecheck
// for LIP enabled system
//
if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
c_szMUILanguages,
0,
KEY_READ,
&hKey ) != ERROR_SUCCESS)
{
return (FALSE);
}
//
// Enumerate the values in the MUILanguages key.
//
dwIndex = 0;
cchValue = sizeof(szValue) / sizeof(TCHAR);
szValue[0] = TEXT('\0');
cbData = sizeof(szData);
szData[0] = TEXT('\0');
rc = RegEnumValue( hKey,
dwIndex,
szValue,
&cchValue,
NULL,
&dwType,
(LPBYTE)szData,
&cbData );
while (rc == ERROR_SUCCESS)
{
//
// If the UI language contains data, then it is installed.
//
if ((szData[0] != 0) &&
(dwType == REG_SZ) &&
(UILang = TransNum(szValue)) &&
(GetLocaleInfo(UILang, LOCALE_SNATIVELANGNAME, szData, MAX_PATH)) &&
(IsValidUILanguage((LANGID)UILang)))
{
//
// if English 0409 key is found, we have a MUI system and not LIP
//
if (UILang == 0x0409)
{
bResult = FALSE;
break;
}
//
// If there are more than one language installed, or then it is
// also not a LIP system - this can be 0409 + any other language also.
//
iLangCount= iLangCount + 1;
if (iLangCount > 1)
{
bResult = FALSE;
break;
}
}
//
// Get the next enum value.
//
dwIndex++;
cchValue = sizeof(szValue) / sizeof(TCHAR);
szValue[0] = TEXT('\0');
cbData = sizeof(szData);
szData[0] = TEXT('\0');
rc = RegEnumValue( hKey,
dwIndex,
szValue,
&cchValue,
NULL,
&dwType,
(LPBYTE)szData,
&cbData );
}
//
// Clean up.
//
RegCloseKey(hKey);
return bResult;
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_RemoveMUIFile
//
////////////////////////////////////////////////////////////////////////////
void Intl_RemoveMUIFile()
{
TCHAR szAppPath[MAX_PATH];
GetSystemWindowsDirectory(szAppPath, ARRAYSIZE(szAppPath));
//
// Invoke muisetup to uninstall MUI languages.
//
if (PathAppend(szAppPath, MUISETUP_EXE_RELATIVE_PATH) &&
Intl_FileExists(szAppPath))
{
//
// Only remove MUI if we are not in an SP OS upgrade scenario
//
if (!Intl_IsMUISetupVersionSameAsOS() && !Intl_IsLIP())
{
SHELLEXECUTEINFO ExecInfo = {0};
//
// Don't delete muisetup.exe, this code is only for xpsp
//
/*
SHFILEOPSTRUCT shFile =
{
NULL, FO_DELETE, szAppPath, NULL, FOF_NOCONFIRMATION|FOF_SILENT|FOF_NOERRORUI, 0, 0, 0
};
*/
ExecInfo.lpParameters = TEXT("/u /r /s");
ExecInfo.fMask = SEE_MASK_FLAG_NO_UI;
ExecInfo.lpFile = szAppPath;
ExecInfo.nShow = SW_SHOWNORMAL;
ExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
ShellExecuteEx(&ExecInfo);
/*
//
// An additional NULL character must be appended for this
// multi-string buffer.
//
szAppPath[lstrlen(szAppPath) + 1] = 0x00;
SHFileOperation(&shFile);
*/
}
}
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_CallTextServices
//
////////////////////////////////////////////////////////////////////////////
void Intl_CallTextServices()
{
TCHAR szAppPath[MAX_PATH];
GetSystemDirectory(szAppPath, ARRAYSIZE(szAppPath));
//
// Invoke the Input applet.
//
if (PathAppend(szAppPath, TEXT("rundll32.exe")) &&
Intl_FileExists(szAppPath))
{
SHELLEXECUTEINFO ExecInfo = {0};
ExecInfo.lpParameters = TEXT("shell32.dll,Control_RunDLL input.dll");
ExecInfo.lpFile = szAppPath;
ExecInfo.nShow = SW_SHOWNORMAL;
ExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
ShellExecuteEx(&ExecInfo);
}
}
////////////////////////////////////////////////////////////////////////////
//
// Intl_GetPendingUILanguage
//
// Look into the registry for the pending UI Language. This function is
// used for the default user case.
//
////////////////////////////////////////////////////////////////////////////
LANGID Intl_GetPendingUILanguage()
{
HKEY hKey;
LANGID dwDefaultUILanguage = 0;
DWORD cbData = 0;
TCHAR szBuffer[MAX_PATH];
//
// Open the registry key used by setup.
//
if (RegOpenKeyEx( HKEY_CURRENT_USER,
c_szCPanelDesktop,
0,
KEY_READ,
&hKey ) != ERROR_SUCCESS)
{
return (GetUserDefaultUILanguage());
}
//
// Query the pending MUI Language.
//
cbData = ARRAYSIZE(szBuffer);
if (RegQueryValueEx( hKey,
szMUILangPending,
NULL,
NULL,
(LPBYTE)szBuffer,
&cbData ) != ERROR_SUCCESS)
{
RegCloseKey(hKey);
return (GetUserDefaultUILanguage());
}
else
{
if ((dwDefaultUILanguage = (LANGID)TransNum(szBuffer)) == 0)
{
RegCloseKey(hKey);
return (GetUserDefaultUILanguage());
}
else
{
RegCloseKey(hKey);
return ((LANGID)dwDefaultUILanguage);
}
}
}
////////////////////////////////////////////////////////////////////////////////////
//
// GetDotDefaultUILanguage
//
// Retrieve the UI language stored in the HKCU\.Default.
// This is the default UI language for new users.
//
////////////////////////////////////////////////////////////////////////////////////
LANGID Intl_GetDotDefaultUILanguage()
{
HKEY hKey;
DWORD dwKeyType;
DWORD dwSize;
BOOL success = FALSE;
TCHAR szBuffer[MAX_PATH];
LANGID langID;
//
// Get the value in .DEFAULT.
//
if (RegOpenKeyEx( HKEY_USERS,
c_szCPanelDesktop_DefUser,
0L,
KEY_READ,
&hKey ) == ERROR_SUCCESS)
{
dwSize = sizeof(szBuffer) * sizeof(TCHAR);
if (RegQueryValueEx( hKey,
c_szMUIValue,
0L,
&dwKeyType,
(LPBYTE)szBuffer,
&dwSize) == ERROR_SUCCESS)
{
if (dwKeyType == REG_SZ)
{
langID = (LANGID)_tcstol(szBuffer, NULL, 16);
success = TRUE;
}
}
RegCloseKey(hKey);
}
if (!success)
{
return (GetUserDefaultUILanguage());
}
return (langID);
}
////////////////////////////////////////////////////////////////////////////
//
// Set the specified control to be left-to-right or right-to-left reading order.
//
// bUseRightToLeft==FALSE: Use left-to-right reading order
// bUseRightToLeft==TRUE: Use right-to-left reading order
//
////////////////////////////////////////////////////////////////////////////
void SetControlReadingOrder(BOOL bUseRightToLeft, HWND hwnd)
{
BOOL bCurrentRTL;
if (IsRtLLocale(GetUserDefaultUILanguage()))
{
// If the current UI langauge is RTL, the dailog is already localized as RTL.
// In this case, don't change the direction of the control.
return;
}
bCurrentRTL = (GetWindowLongPtr(hwnd, GWL_EXSTYLE) & (WS_EX_RTLREADING)) != 0;
if (bCurrentRTL != bUseRightToLeft)
{
// Reverse the WS_EX_RTLREADING and WS_EX_RIGHT bit.
SetWindowLongPtr(hwnd, GWL_EXSTYLE, GetWindowLongPtr(hwnd, GWL_EXSTYLE) ^ (WS_EX_RTLREADING | WS_EX_RIGHT));
InvalidateRect(hwnd, NULL, FALSE);
}
}