1030 lines
30 KiB
C
1030 lines
30 KiB
C
/*++
|
|
|
|
Copyright (c) 1994-2000, Microsoft Corporation All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
intl.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the main routines for the Regional Options applet.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
|
|
//
|
|
// Include Files.
|
|
//
|
|
|
|
#include "intl.h"
|
|
#include <cpl.h>
|
|
#include <tchar.h>
|
|
|
|
|
|
|
|
|
|
//
|
|
// Constant Declarations.
|
|
//
|
|
|
|
#define MAX_PAGES 3 // limit on the number of pages on the first level
|
|
|
|
#define LANGUAGE_PACK_KEY TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\LanguagePack")
|
|
#define LANGUAGE_PACK_VALUE TEXT("COMPLEXSCRIPTS")
|
|
#define LANGUAGE_PACK_DLL TEXT("lpk.dll")
|
|
|
|
static const TCHAR c_szLanguages[] =
|
|
TEXT("System\\CurrentControlSet\\Control\\Nls\\Language");
|
|
|
|
static const TCHAR c_szControlPanelIntl[] =
|
|
TEXT("Control Panel\\International");
|
|
|
|
|
|
|
|
|
|
//
|
|
// Global Variables.
|
|
//
|
|
|
|
HANDLE g_hMutex = NULL;
|
|
TCHAR szMutexName[] = TEXT("RegionalSettings_InputLocaleMutex");
|
|
|
|
HANDLE g_hEvent = NULL;
|
|
TCHAR szEventName[] = TEXT("RegionalSettings_InputLocaleEvent");
|
|
|
|
TCHAR aInt_Str[cInt_Str][3] = { TEXT("0"),
|
|
TEXT("1"),
|
|
TEXT("2"),
|
|
TEXT("3"),
|
|
TEXT("4"),
|
|
TEXT("5"),
|
|
TEXT("6"),
|
|
TEXT("7"),
|
|
TEXT("8"),
|
|
TEXT("9")
|
|
};
|
|
|
|
BOOL g_bAdmin_Privileges = FALSE;
|
|
DWORD g_dwLastSorting;
|
|
DWORD g_dwCurSorting;
|
|
BOOL g_bCustomize = FALSE;
|
|
BOOL g_bDefaultUser = FALSE;
|
|
DWORD g_dwCustChange = 0L;
|
|
BOOL g_bShowSortingTab = FALSE;
|
|
BOOL g_bInstallComplex = FALSE;
|
|
BOOL g_bInstallCJK = FALSE;
|
|
|
|
TCHAR szSample_Number[] = TEXT("123456789.00");
|
|
TCHAR szNegSample_Number[] = TEXT("-123456789.00");
|
|
TCHAR szTimeChars[] = TEXT(" Hhmst,-./:;\\ ");
|
|
TCHAR szTCaseSwap[] = TEXT(" MST");
|
|
TCHAR szTLetters[] = TEXT("Hhmst");
|
|
TCHAR szSDateChars[] = TEXT(" dgMy,-./:;\\ ");
|
|
TCHAR szSDCaseSwap[] = TEXT(" DGmY");
|
|
TCHAR szSDLetters[] = TEXT("dgMy");
|
|
TCHAR szLDateChars[] = TEXT(" dgMy,-./:;\\");
|
|
TCHAR szLDCaseSwap[] = TEXT(" DGmY");
|
|
TCHAR szLDLetters[] = TEXT("dgHhMmsty");
|
|
TCHAR szStyleH[3];
|
|
TCHAR szStyleh[3];
|
|
TCHAR szStyleM[3];
|
|
TCHAR szStylem[3];
|
|
TCHAR szStyles[3];
|
|
TCHAR szStylet[3];
|
|
TCHAR szStyled[3];
|
|
TCHAR szStyley[3];
|
|
TCHAR szLocaleGetError[SIZE_128];
|
|
TCHAR szIntl[] = TEXT("intl");
|
|
|
|
TCHAR szInvalidSDate[] = TEXT("Mdyg'");
|
|
TCHAR szInvalidSTime[] = TEXT("Hhmst'");
|
|
|
|
HINSTANCE hInstance;
|
|
int Verified_Regional_Chg = 0;
|
|
int RegionalChgState = 0;
|
|
BOOL Styles_Localized;
|
|
LCID UserLocaleID;
|
|
LCID SysLocaleID;
|
|
LCID RegUserLocaleID;
|
|
LCID RegSysLocaleID;
|
|
BOOL bShowArabic;
|
|
BOOL bShowRtL;
|
|
BOOL bHebrewUI;
|
|
BOOL bLPKInstalled;
|
|
TCHAR szSetupSourcePath[MAX_PATH];
|
|
TCHAR szSetupSourcePathWithArchitecture[MAX_PATH];
|
|
LPTSTR pSetupSourcePath = NULL;
|
|
LPTSTR pSetupSourcePathWithArchitecture = NULL;
|
|
|
|
BOOL g_bCDROM = FALSE;
|
|
|
|
BOOL g_bSetupCase = FALSE;
|
|
BOOL g_bLog = FALSE;
|
|
BOOL g_bProgressBarDisplay = FALSE;
|
|
BOOL g_bSettingsChanged = FALSE;
|
|
BOOL g_bUnttendMode = FALSE;
|
|
BOOL g_bMatchUIFont = FALSE;
|
|
|
|
const TCHAR c_szInstalledLocales[] = TEXT("System\\CurrentControlSet\\Control\\Nls\\Locale");
|
|
const TCHAR c_szLanguageGroups[] = TEXT("System\\CurrentControlSet\\Control\\Nls\\Language Groups");
|
|
const TCHAR c_szMUILanguages[] = TEXT("System\\CurrentControlSet\\Control\\Nls\\MUILanguages");
|
|
const TCHAR c_szLIPInstalled[] = TEXT("Software\\Microsoft\\Windows Interface Pack\\LIPInstalled");
|
|
const TCHAR c_szFontSubstitute[] = TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes");
|
|
const TCHAR c_szSetupKey[] = TEXT("System\\Setup");
|
|
const TCHAR c_szCPanelIntl[] = TEXT("Control Panel\\International");
|
|
const TCHAR c_szCPanelIntl_DefUser[] = TEXT(".DEFAULT\\Control Panel\\International");
|
|
const TCHAR c_szCtfmon[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Run");
|
|
const TCHAR c_szCtfmon_DefUser[] = TEXT(".DEFAULT\\Software\\Microsoft\\Windows\\CurrentVersion\\Run");
|
|
const TCHAR c_szCPanelDesktop[] = TEXT("Control Panel\\Desktop");
|
|
const TCHAR c_szCPanelDesktop_DefUser[] = TEXT(".DEFAULT\\Control Panel\\Desktop");
|
|
const TCHAR c_szKbdLayouts[] = TEXT("Keyboard Layout");
|
|
const TCHAR c_szKbdLayouts_DefUser[] = TEXT(".DEFAULT\\Keyboard Layout");
|
|
const TCHAR c_szInputMethod[] = TEXT("Control Panel\\Input Method");
|
|
const TCHAR c_szInputMethod_DefUser[] = TEXT(".DEFAULT\\Control Panel\\Input Method");
|
|
const TCHAR c_szInputTips[] = TEXT("Software\\Microsoft\\CTF");
|
|
const TCHAR c_szInputTips_DefUser[] = TEXT(".DEFAULT\\Software\\Microsoft\\CTF");
|
|
const TCHAR c_szMUIPolicyKeyPath[] = TEXT("Software\\Policies\\Microsoft\\Control Panel\\Desktop");
|
|
const TCHAR c_szMUIValue[] = TEXT("MultiUILanguageId");
|
|
const TCHAR c_szIntlRun[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\IntlRun");
|
|
const TCHAR c_szSysocmgr[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\IntlRun.OC");
|
|
|
|
TCHAR szIntlInf[] = TEXT("intl.inf");
|
|
TCHAR szHelpFile[] = TEXT("windows.hlp");
|
|
TCHAR szFontSubstitute[] = TEXT("FontSubstitute");
|
|
TCHAR szLocaleListPrefix[] = TEXT("LOCALE_LIST_");
|
|
TCHAR szLGBasicInstall[] = TEXT("LANGUAGE_COLLECTION.BASIC.INSTALL");
|
|
TCHAR szLGComplexInstall[] = TEXT("LANGUAGE_COLLECTION.COMPLEX.INSTALL");
|
|
TCHAR szLGComplexRemove[] = TEXT("LANGUAGE_COLLECTION.COMPLEX.REMOVE");
|
|
TCHAR szLGExtInstall[] = TEXT("LANGUAGE_COLLECTION.EXTENDED.INSTALL");
|
|
TCHAR szLGExtRemove[] = TEXT("LANGUAGE_COLLECTION.EXTENDED.REMOVE");
|
|
TCHAR szCPInstallPrefix[] = TEXT("CODEPAGE_INSTALL_");
|
|
TCHAR szCPRemovePrefix[] = TEXT("CODEPAGE_REMOVE_");
|
|
TCHAR szKbdLayoutIds[] = TEXT("KbdLayoutIds");
|
|
TCHAR szInputLibrary[] = TEXT("input.dll");
|
|
|
|
TCHAR szUIFontSubstitute[] = TEXT("UIFontSubstitute");
|
|
TCHAR szSetupInProgress[] = TEXT("SystemSetupInProgress");
|
|
TCHAR szSetupUpgrade[] = TEXT("UpgradeInProgress");
|
|
TCHAR szMUILangPending[] = TEXT("MUILanguagePending");
|
|
TCHAR szCtfmonValue[] = TEXT("ctfmon.exe");
|
|
|
|
TCHAR szRegionalSettings[] = TEXT("RegionalSettings");
|
|
TCHAR szLanguageGroup[] = TEXT("LanguageGroup");
|
|
TCHAR szLanguage[] = TEXT("Language");
|
|
TCHAR szSystemLocale[] = TEXT("SystemLocale");
|
|
TCHAR szUserLocale[] = TEXT("UserLocale");
|
|
TCHAR szInputLocale[] = TEXT("InputLocale");
|
|
TCHAR szMUILanguage[] = TEXT("MUILanguage");
|
|
TCHAR szUserLocale_DefUser[] = TEXT("UserLocale_DefaultUser");
|
|
TCHAR szInputLocale_DefUser[] = TEXT("InputLocale_DefaultUser");
|
|
TCHAR szMUILanguage_DefUSer[] = TEXT("MUILanguage_DefaultUser");
|
|
|
|
HINF g_hIntlInf = NULL;
|
|
|
|
LPLANGUAGEGROUP pLanguageGroups = NULL;
|
|
LPCODEPAGE pCodePages = NULL;
|
|
|
|
int g_NumAltSorts = 0;
|
|
HANDLE hAltSorts = NULL;
|
|
LPDWORD pAltSorts = NULL;
|
|
|
|
HINSTANCE hInputDLL = NULL;
|
|
BOOL (*pfnInstallInputLayout)(LCID, DWORD, BOOL, HKL, BOOL, BOOL) = NULL;
|
|
BOOL (*pfnUninstallInputLayout)(LCID, DWORD, BOOL) = NULL;
|
|
|
|
UILANGUAGEGROUP UILangGroup;
|
|
|
|
|
|
|
|
|
|
//
|
|
// Function Prototypes.
|
|
//
|
|
|
|
void
|
|
DoProperties(
|
|
HWND hwnd,
|
|
LPCTSTR pCmdLine);
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// LibMain
|
|
//
|
|
// This routine is called from LibInit to perform any initialization that
|
|
// is required.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL APIENTRY LibMain(
|
|
HANDLE hDll,
|
|
DWORD dwReason,
|
|
LPVOID lpReserved)
|
|
{
|
|
switch (dwReason)
|
|
{
|
|
case ( DLL_PROCESS_ATTACH ) :
|
|
{
|
|
hInstance = hDll;
|
|
|
|
//
|
|
// Create the mutex used for the Input Locale property page.
|
|
//
|
|
g_hMutex = CreateMutex(NULL, FALSE, szMutexName);
|
|
g_hEvent = CreateEvent(NULL, TRUE, TRUE, szEventName);
|
|
|
|
DisableThreadLibraryCalls(hDll);
|
|
|
|
break;
|
|
}
|
|
case ( DLL_PROCESS_DETACH ) :
|
|
{
|
|
if (g_hMutex)
|
|
{
|
|
CloseHandle(g_hMutex);
|
|
}
|
|
if (g_hEvent)
|
|
{
|
|
CloseHandle(g_hEvent);
|
|
}
|
|
break;
|
|
}
|
|
case ( DLL_THREAD_DETACH ) :
|
|
{
|
|
break;
|
|
}
|
|
case ( DLL_THREAD_ATTACH ) :
|
|
default :
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CreateGlobals
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL CreateGlobals()
|
|
{
|
|
HKEY hKey;
|
|
TCHAR szData[MAX_PATH];
|
|
DWORD cbData;
|
|
|
|
//
|
|
// Get the localized strings.
|
|
//
|
|
LoadString(hInstance, IDS_LOCALE_GET_ERROR, szLocaleGetError, SIZE_128);
|
|
LoadString(hInstance, IDS_STYLEUH, szStyleH, 3);
|
|
LoadString(hInstance, IDS_STYLELH, szStyleh, 3);
|
|
LoadString(hInstance, IDS_STYLEUM, szStyleM, 3);
|
|
LoadString(hInstance, IDS_STYLELM, szStylem, 3);
|
|
LoadString(hInstance, IDS_STYLELS, szStyles, 3);
|
|
LoadString(hInstance, IDS_STYLELT, szStylet, 3);
|
|
LoadString(hInstance, IDS_STYLELD, szStyled, 3);
|
|
LoadString(hInstance, IDS_STYLELY, szStyley, 3);
|
|
|
|
Styles_Localized = (szStyleH[0] != TEXT('H') || szStyleh[0] != TEXT('h') ||
|
|
szStyleM[0] != TEXT('M') || szStylem[0] != TEXT('m') ||
|
|
szStyles[0] != TEXT('s') || szStylet[0] != TEXT('t') ||
|
|
szStyled[0] != TEXT('d') || szStyley[0] != TEXT('y'));
|
|
|
|
//
|
|
// Get the user and system default locale ids.
|
|
//
|
|
UserLocaleID = GetUserDefaultLCID();
|
|
SysLocaleID = GetSystemDefaultLCID();
|
|
|
|
//
|
|
// Get the system locale id from the registry. This may be
|
|
// different from the current system default locale id if the user
|
|
// changed the system locale and chose not to reboot.
|
|
//
|
|
if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
c_szLanguages,
|
|
0L,
|
|
KEY_READ,
|
|
&hKey ) == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Query the default locale id.
|
|
//
|
|
szData[0] = 0;
|
|
cbData = sizeof(szData);
|
|
RegQueryValueEx(hKey, TEXT("Default"), NULL, NULL, (LPBYTE)szData, &cbData);
|
|
RegCloseKey(hKey);
|
|
|
|
if ((RegSysLocaleID = TransNum(szData)) == 0)
|
|
{
|
|
RegSysLocaleID = SysLocaleID;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RegSysLocaleID = SysLocaleID;
|
|
}
|
|
|
|
//
|
|
// Get the user locale id from the registry.
|
|
//
|
|
if (RegOpenKeyEx( HKEY_CURRENT_USER,
|
|
c_szControlPanelIntl,
|
|
0L,
|
|
KEY_READ,
|
|
&hKey ) == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Query the locale id.
|
|
//
|
|
szData[0] = 0;
|
|
cbData = sizeof(szData);
|
|
RegQueryValueEx(hKey, TEXT("Locale"), NULL, NULL, (LPBYTE)szData, &cbData);
|
|
RegCloseKey(hKey);
|
|
|
|
if ((RegUserLocaleID = TransNum(szData)) == 0)
|
|
{
|
|
RegUserLocaleID = UserLocaleID;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RegUserLocaleID = UserLocaleID;
|
|
}
|
|
|
|
//
|
|
// See if the user locale id is Arabic or/and right to left.
|
|
//
|
|
bShowRtL = IsRtLLocale(UserLocaleID);
|
|
bShowArabic = (bShowRtL &&
|
|
(PRIMARYLANGID(LANGIDFROMLCID(UserLocaleID)) != LANG_HEBREW));
|
|
bHebrewUI = (PRIMARYLANGID(UserLocaleID) == LANG_HEBREW);
|
|
|
|
//
|
|
// See if there is an LPK installed.
|
|
//
|
|
if (GetModuleHandle(LANGUAGE_PACK_DLL))
|
|
{
|
|
bLPKInstalled = TRUE;
|
|
}
|
|
else
|
|
{
|
|
bLPKInstalled = FALSE;
|
|
}
|
|
|
|
//
|
|
// Return success.
|
|
//
|
|
return (TRUE);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// DestroyGlobals
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void DestroyGlobals()
|
|
{
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CPlApplet
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
LONG CALLBACK CPlApplet(
|
|
HWND hwnd,
|
|
UINT Msg,
|
|
LPARAM lParam1,
|
|
LPARAM lParam2)
|
|
{
|
|
switch (Msg)
|
|
{
|
|
case ( CPL_INIT ) :
|
|
{
|
|
//
|
|
// First message to CPlApplet(), sent once only.
|
|
// Perform all control panel applet initialization and return
|
|
// true for further processing.
|
|
//
|
|
InitCommonControls();
|
|
return (CreateGlobals());
|
|
}
|
|
case ( CPL_GETCOUNT ) :
|
|
{
|
|
//
|
|
// Second message to CPlApplet(), sent once only.
|
|
// Return the number of control applets to be displayed in the
|
|
// control panel window. For this applet, return 1.
|
|
//
|
|
return (1);
|
|
}
|
|
case ( CPL_INQUIRE ) :
|
|
{
|
|
//
|
|
// Third message to CPlApplet().
|
|
// It is sent as many times as the number of applets returned by
|
|
// CPL_GETCOUNT message. Each applet must register by filling
|
|
// in the CPLINFO structure referenced by lParam2 with the
|
|
// applet's icon, name, and information string. Since there is
|
|
// only one applet, simply set the information for this
|
|
// singular case.
|
|
//
|
|
LPCPLINFO lpCPlInfo = (LPCPLINFO)lParam2;
|
|
|
|
lpCPlInfo->idIcon = IDI_ICON;
|
|
lpCPlInfo->idName = IDS_NAME;
|
|
lpCPlInfo->idInfo = IDS_INFO;
|
|
lpCPlInfo->lData = 0;
|
|
|
|
break;
|
|
}
|
|
case ( CPL_NEWINQUIRE ) :
|
|
{
|
|
//
|
|
// Third message to CPlApplet().
|
|
// It is sent as many times as the number of applets returned by
|
|
// CPL_GETCOUNT message. Each applet must register by filling
|
|
// in the NEWCPLINFO structure referenced by lParam2 with the
|
|
// applet's icon, name, and information string. Since there is
|
|
// only one applet, simply set the information for this
|
|
// singular case.
|
|
//
|
|
LPNEWCPLINFO lpNewCPlInfo = (LPNEWCPLINFO)lParam2;
|
|
|
|
lpNewCPlInfo->dwSize = sizeof(NEWCPLINFO);
|
|
lpNewCPlInfo->dwFlags = 0;
|
|
lpNewCPlInfo->dwHelpContext = 0UL;
|
|
lpNewCPlInfo->lData = 0;
|
|
lpNewCPlInfo->hIcon = LoadIcon( hInstance,
|
|
(LPCTSTR)MAKEINTRESOURCE(IDI_ICON) );
|
|
LoadString(hInstance, IDS_NAME, lpNewCPlInfo->szName, 32);
|
|
LoadString(hInstance, IDS_INFO, lpNewCPlInfo->szInfo, 64);
|
|
lpNewCPlInfo->szHelpFile[0] = CHAR_NULL;
|
|
|
|
break;
|
|
}
|
|
case ( CPL_SELECT ) :
|
|
{
|
|
//
|
|
// Applet has been selected, do nothing.
|
|
//
|
|
break;
|
|
}
|
|
case ( CPL_DBLCLK ) :
|
|
{
|
|
//
|
|
// Applet icon double clicked -- invoke property sheet with
|
|
// the first property sheet page on top.
|
|
//
|
|
DoProperties(hwnd, (LPCTSTR)NULL);
|
|
break;
|
|
}
|
|
case ( CPL_STARTWPARMS ) :
|
|
{
|
|
//
|
|
// Same as CPL_DBLCLK, but lParam2 is a long pointer to
|
|
// a string of extra directions that are to be supplied to
|
|
// the property sheet that is to be initiated.
|
|
//
|
|
DoProperties(hwnd, (LPCTSTR)lParam2);
|
|
break;
|
|
}
|
|
case ( CPL_STOP ) :
|
|
{
|
|
//
|
|
// Sent once for each applet prior to the CPL_EXIT msg.
|
|
// Perform applet specific cleanup.
|
|
//
|
|
break;
|
|
}
|
|
case ( CPL_EXIT ) :
|
|
{
|
|
//
|
|
// Last message, sent once only, before MMCPL.EXE calls
|
|
// FreeLibrary() on this DLL. Do non-applet specific cleanup.
|
|
//
|
|
DestroyGlobals();
|
|
break;
|
|
}
|
|
default :
|
|
{
|
|
return (FALSE);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Return success.
|
|
//
|
|
return (TRUE);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// DoProperties
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void DoProperties(
|
|
HWND hwnd,
|
|
LPCTSTR pCmdLine)
|
|
{
|
|
HPROPSHEETPAGE rPages[MAX_PAGES];
|
|
PROPSHEETHEADER psh;
|
|
LPARAM lParam = SETUP_SWITCH_NONE;
|
|
LPTSTR pStartPage;
|
|
LPTSTR pSrc;
|
|
LPTSTR pSrcDrv;
|
|
BOOL bShortDate = FALSE;
|
|
BOOL bNoUI = FALSE;
|
|
BOOL bUnattended = FALSE;
|
|
TCHAR szUnattendFile[MAX_PATH * 2];
|
|
HKEY hKey;
|
|
TCHAR szSetupSourceDrive[MAX_PATH];
|
|
|
|
//
|
|
// Log if the command line is not null.
|
|
//
|
|
if (pCmdLine != NULL)
|
|
{
|
|
g_bLog = TRUE;
|
|
}
|
|
|
|
//
|
|
// Begin Log and log command line parameters.
|
|
//
|
|
Intl_LogSimpleMessage(IDS_LOG_HEAD, NULL);
|
|
Intl_LogMessage(pCmdLine);
|
|
Intl_LogMessage(TEXT("")); // add a carriage return and newline
|
|
|
|
//
|
|
// Load the library used for Text Services.
|
|
//
|
|
if (!hInputDLL)
|
|
{
|
|
hInputDLL = LoadLibrary(szInputLibrary);
|
|
}
|
|
|
|
//
|
|
// Initialize the Install/Remove function from the Input applet.
|
|
//
|
|
if (hInputDLL)
|
|
{
|
|
//
|
|
// Initialize Install function.
|
|
//
|
|
pfnInstallInputLayout = (BOOL (*)(LCID, DWORD, BOOL, HKL, BOOL, BOOL))
|
|
GetProcAddress(hInputDLL, MAKEINTRESOURCEA(ORD_INPUT_INST_LAYOUT));
|
|
|
|
//
|
|
// Initialize Uninstall function.
|
|
//
|
|
pfnUninstallInputLayout = (BOOL (*)(LCID, DWORD, BOOL))
|
|
GetProcAddress(hInputDLL, MAKEINTRESOURCEA(ORD_INPUT_UNINST_LAYOUT));
|
|
}
|
|
|
|
//
|
|
// See if there is a command line switch from Setup.
|
|
//
|
|
psh.nStartPage = (UINT)-1;
|
|
while (pCmdLine && *pCmdLine)
|
|
{
|
|
if (*pCmdLine == TEXT('/'))
|
|
{
|
|
//
|
|
// Legend:
|
|
// gG: allow progress bar to show when setup is copying files
|
|
// iI: bring up the Input Locale page only
|
|
// rR: bring up the General page on top
|
|
// sS: setup source string passed on command line
|
|
// [example: /s:"c:\winnt"]
|
|
//
|
|
// NO UI IS SHOWN IF THE FOLLOWING OPTIONS ARE SPECIFIED:
|
|
// fF: unattend mode file - no UI is shown
|
|
// [example: /f:"c:\unattend.txt"]
|
|
// uU: update short date format to 4-digit year - no UI is shown
|
|
// (registry only updated if current setting is the
|
|
// same as the default setting except for the
|
|
// "yy" vs. "yyyy")
|
|
// tT: Match system UI font with the default UI language
|
|
//
|
|
switch (*++pCmdLine)
|
|
{
|
|
case ( TEXT('g') ) :
|
|
case ( TEXT('G') ) :
|
|
{
|
|
//
|
|
// Log switch.
|
|
//
|
|
Intl_LogSimpleMessage(IDS_LOG_SWITCH_G, NULL);
|
|
|
|
//
|
|
// Do switch related processing.
|
|
//
|
|
g_bProgressBarDisplay = TRUE;
|
|
pCmdLine++;
|
|
break;
|
|
}
|
|
case ( TEXT('i') ) :
|
|
case ( TEXT('I') ) :
|
|
{
|
|
//
|
|
// Log switch.
|
|
//
|
|
Intl_LogSimpleMessage(IDS_LOG_SWITCH_I, NULL);
|
|
|
|
//
|
|
// Do switch related processing
|
|
//
|
|
lParam |= SETUP_SWITCH_I;
|
|
psh.nStartPage = 0;
|
|
pCmdLine++;
|
|
break;
|
|
}
|
|
case ( TEXT('r') ) :
|
|
case ( TEXT('R') ) :
|
|
{
|
|
//
|
|
// Log switch.
|
|
//
|
|
Intl_LogSimpleMessage(IDS_LOG_SWITCH_R, NULL);
|
|
|
|
//
|
|
// Do switch related processing
|
|
//
|
|
lParam |= SETUP_SWITCH_R;
|
|
psh.nStartPage = 0;
|
|
pCmdLine++;
|
|
break;
|
|
}
|
|
case ( TEXT('s') ) :
|
|
case ( TEXT('S') ) :
|
|
{
|
|
//
|
|
// Log switch.
|
|
//
|
|
Intl_LogSimpleMessage(IDS_LOG_SWITCH_S, NULL);
|
|
|
|
//
|
|
// Get the name of the setup source path.
|
|
//
|
|
lParam |= SETUP_SWITCH_S;
|
|
if ((*++pCmdLine == TEXT(':')) && (*++pCmdLine == TEXT('"')))
|
|
{
|
|
pCmdLine++;
|
|
pSrc = szSetupSourcePath;
|
|
pSrcDrv = szSetupSourceDrive;
|
|
while (*pCmdLine && (*pCmdLine != TEXT('"')))
|
|
{
|
|
*pSrc = *pCmdLine;
|
|
pSrc++;
|
|
*pSrcDrv = *pCmdLine;
|
|
pSrcDrv++;
|
|
pCmdLine++;
|
|
}
|
|
*pSrc = 0;
|
|
*pSrcDrv = 0;
|
|
wcscpy(szSetupSourcePathWithArchitecture, szSetupSourcePath);
|
|
pSetupSourcePathWithArchitecture = szSetupSourcePathWithArchitecture;
|
|
|
|
//
|
|
// Remove the architecture-specific portion of
|
|
// the source path (that gui-mode setup sent us).
|
|
//
|
|
pSrc = wcsrchr(szSetupSourcePath, TEXT('\\'));
|
|
if (pSrc)
|
|
{
|
|
*pSrc = TEXT('\0');
|
|
}
|
|
pSetupSourcePath = szSetupSourcePath;
|
|
}
|
|
if (*pCmdLine == TEXT('"'))
|
|
{
|
|
pCmdLine++;
|
|
}
|
|
pSrcDrv = szSetupSourceDrive;
|
|
while (*pSrcDrv)
|
|
{
|
|
if (*pSrcDrv == TEXT('\\'))
|
|
{
|
|
pSrcDrv[1] = 0;
|
|
}
|
|
pSrcDrv++;
|
|
}
|
|
g_bCDROM = (GetDriveType(szSetupSourceDrive) == DRIVE_CDROM);
|
|
break;
|
|
}
|
|
case ( TEXT('f') ) :
|
|
case ( TEXT('F') ) :
|
|
{
|
|
//
|
|
// Log switch.
|
|
//
|
|
Intl_LogSimpleMessage(IDS_LOG_SWITCH_F, NULL);
|
|
|
|
//
|
|
// Get the name of the unattend file.
|
|
//
|
|
g_bUnttendMode = TRUE;
|
|
bNoUI = TRUE;
|
|
szUnattendFile[0] = 0;
|
|
if ((*++pCmdLine == TEXT(':')) && (*++pCmdLine == TEXT('"')))
|
|
{
|
|
pCmdLine++;
|
|
pSrc = szUnattendFile;
|
|
while (*pCmdLine && (*pCmdLine != TEXT('"')))
|
|
{
|
|
*pSrc = *pCmdLine;
|
|
pSrc++;
|
|
pCmdLine++;
|
|
}
|
|
*pSrc = 0;
|
|
}
|
|
if (*pCmdLine == TEXT('"'))
|
|
{
|
|
pCmdLine++;
|
|
}
|
|
break;
|
|
}
|
|
case ( TEXT('u') ) :
|
|
case ( TEXT('U') ) :
|
|
{
|
|
//
|
|
// Log switch.
|
|
//
|
|
Intl_LogSimpleMessage(IDS_LOG_SWITCH_U, NULL);
|
|
|
|
//
|
|
// Do switch related processing.
|
|
//
|
|
bShortDate = TRUE;
|
|
bNoUI = TRUE;
|
|
break;
|
|
}
|
|
|
|
case ( TEXT('t') ) :
|
|
case ( TEXT('T') ) :
|
|
{
|
|
g_bMatchUIFont = TRUE;
|
|
}
|
|
|
|
default :
|
|
{
|
|
//
|
|
// Log switch.
|
|
//
|
|
Intl_LogSimpleMessage(IDS_LOG_SWITCH_DEFAULT, pCmdLine);
|
|
|
|
//
|
|
// Fall out, maybe it's a number...
|
|
//
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if (*pCmdLine == TEXT(' '))
|
|
{
|
|
pCmdLine++;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// See if we are in setup mode.
|
|
//
|
|
g_bSetupCase = Intl_IsSetupMode();
|
|
|
|
//
|
|
// See if the user has Administrative privileges by checking for
|
|
// write permission to the registry key.
|
|
//
|
|
if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
c_szInstalledLocales,
|
|
0UL,
|
|
KEY_WRITE,
|
|
&hKey ) == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// See if the user can write into the registry. Due to a registry
|
|
// modification, we can open a registry key with write access and
|
|
// be unable to write to the key... thanks to terminal server.
|
|
//
|
|
if (RegSetValueEx( hKey,
|
|
TEXT("Test"),
|
|
0UL,
|
|
REG_SZ,
|
|
(LPBYTE)TEXT("Test"),
|
|
(DWORD)(lstrlen(TEXT("Test")) + 1) * sizeof(TCHAR) ) == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Delete the value created
|
|
//
|
|
RegDeleteValue(hKey, TEXT("Test"));
|
|
|
|
//
|
|
// We can write to the HKEY_LOCAL_MACHINE key, so the user
|
|
// has Admin privileges.
|
|
//
|
|
g_bAdmin_Privileges = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The user does not have admin privileges.
|
|
//
|
|
g_bAdmin_Privileges = FALSE;
|
|
}
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
//
|
|
// See if we are in setup mode.
|
|
//
|
|
if (g_bSetupCase)
|
|
{
|
|
//
|
|
// We need to remove the hard coded LPK registry key.
|
|
//
|
|
if (RegOpenKey( HKEY_LOCAL_MACHINE,
|
|
LANGUAGE_PACK_KEY,
|
|
&hKey ) == ERROR_SUCCESS)
|
|
{
|
|
RegDeleteValue(hKey, LANGUAGE_PACK_VALUE);
|
|
RegCloseKey(hKey);
|
|
}
|
|
}
|
|
|
|
//
|
|
// See if the unattend mode file switch was used.
|
|
//
|
|
if (g_bUnttendMode)
|
|
{
|
|
//
|
|
// Use the unattend mode file to carry out the appropriate commands.
|
|
//
|
|
Region_DoUnattendModeSetup(szUnattendFile);
|
|
|
|
if (Intl_IsWinntUpgrade())
|
|
{
|
|
//
|
|
// Remove MUI files.
|
|
//
|
|
Intl_RemoveMUIFile();
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the update to 4-digit year switch was used and the user's short
|
|
// date setting is still set to the default for the chosen locale, then
|
|
// update the current user's short date setting to the new 4-digit year
|
|
// default.
|
|
//
|
|
if (bShortDate)
|
|
{
|
|
Region_UpdateShortDate();
|
|
}
|
|
|
|
//
|
|
// If we're not to show any UI, then return.
|
|
//
|
|
if (bNoUI)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Make sure we have a start page.
|
|
//
|
|
if (psh.nStartPage == (UINT)-1)
|
|
{
|
|
psh.nStartPage = 0;
|
|
if (pCmdLine && *pCmdLine)
|
|
{
|
|
//
|
|
// Get the start page from the command line.
|
|
//
|
|
pStartPage = (LPTSTR)pCmdLine;
|
|
while ((*pStartPage >= TEXT('0')) && (*pStartPage <= TEXT('9')))
|
|
{
|
|
psh.nStartPage *= 10;
|
|
psh.nStartPage += *pStartPage++ - CHAR_ZERO;
|
|
}
|
|
|
|
//
|
|
// Make sure that the requested starting page is less than
|
|
// the max page for the selected applet.
|
|
//
|
|
if (psh.nStartPage >= MAX_PAGES)
|
|
{
|
|
psh.nStartPage = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set up the property sheet information.
|
|
//
|
|
psh.dwSize = sizeof(psh);
|
|
psh.dwFlags = 0;
|
|
psh.hwndParent = hwnd;
|
|
psh.hInstance = hInstance;
|
|
psh.nPages = 0;
|
|
psh.phpage = rPages;
|
|
|
|
//
|
|
// Add the appropriate property pages.
|
|
//
|
|
if (lParam &= SETUP_SWITCH_I)
|
|
{
|
|
psh.pszCaption = MAKEINTRESOURCE(IDS_TEXT_INPUT_METHODS);
|
|
Intl_AddExternalPage( &psh,
|
|
DLG_INPUT_LOCALES,
|
|
hInputDLL,
|
|
MAKEINTRESOURCEA(ORD_INPUT_DLG_PROC),
|
|
MAX_PAGES ); // One page
|
|
}
|
|
else
|
|
{
|
|
psh.pszCaption = MAKEINTRESOURCE(IDS_NAME);
|
|
Intl_AddPage(&psh, DLG_GENERAL, GeneralDlgProc, lParam, MAX_PAGES);
|
|
Intl_AddPage(&psh, DLG_LANGUAGES, LanguageDlgProc, lParam, MAX_PAGES);
|
|
if (g_bAdmin_Privileges == TRUE)
|
|
{
|
|
Intl_AddPage(&psh, DLG_ADVANCED, AdvancedDlgProc, lParam, MAX_PAGES);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Make the property sheet.
|
|
//
|
|
PropertySheet(&psh);
|
|
|
|
//
|
|
// Free the Text Services Library.
|
|
//
|
|
if (hInputDLL)
|
|
{
|
|
FreeLibrary(hInputDLL);
|
|
pfnInstallInputLayout = NULL;
|
|
pfnUninstallInputLayout = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// IsRtLLocale
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define MAX_FONTSIGNATURE 16 // length of font signature string
|
|
|
|
BOOL IsRtLLocale(
|
|
LCID iLCID)
|
|
{
|
|
WORD wLCIDFontSignature[MAX_FONTSIGNATURE];
|
|
BOOL bRet = FALSE;
|
|
|
|
//
|
|
// Verify that this is an RTL (BiDi) locale. Call GetLocaleInfo with
|
|
// LOCALE_FONTSIGNATURE which always gives back 16 WORDs.
|
|
//
|
|
if (GetLocaleInfo( iLCID,
|
|
LOCALE_FONTSIGNATURE,
|
|
(LPTSTR) &wLCIDFontSignature,
|
|
(sizeof(wLCIDFontSignature) / sizeof(TCHAR)) ))
|
|
{
|
|
//
|
|
// Verify the bits show a BiDi UI locale.
|
|
//
|
|
if (wLCIDFontSignature[7] & 0x0800)
|
|
{
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Return the result.
|
|
//
|
|
return (bRet);
|
|
}
|