windows-nt/Source/XPSP1/NT/base/ntsetup/syssetup/intl.c
2020-09-26 16:20:57 +08:00

1546 lines
37 KiB
C

/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
intl.c
Abstract:
Module with code for NLS-related stuff.
This module is designed to be used with intl.inf and font.inf
by control panel applets.
Author:
Ted Miller (tedm) 15-Aug-1995
Revision History:
--*/
#include "setupp.h"
#pragma hdrstop
//
// This structure and the callback function below are used to set the
// hidden attribute bit on certain font files. That bit causes the font folder
// app to not autoinstall these files.
//
typedef struct _FONTQCONTEXT {
PVOID SetupQueueContext;
HINF FontInf;
} FONTQCONTEXT, *PFONTQCONTEXT;
PCWSTR szHiddenFontFiles = L"HiddenFontFiles";
VOID
pSetLocaleSummaryText(
IN HWND hdlg
);
VOID
pSetKeyboardLayoutSummaryText(
IN HWND hdlg
);
void
pSetupRunRegApps()
{
HKEY hkey;
BOOL bOK = TRUE;
DWORD cbData, cbValue, dwType, ctr;
TCHAR szValueName[32], szCmdLine[MAX_PATH];
STARTUPINFO startup;
PROCESS_INFORMATION pi;
if (RegOpenKey( HKEY_LOCAL_MACHINE,
TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\IntlRun"),
&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);
}
}
VOID
InstallServerNLSFiles(
IN HWND Window
)
/*++
Routine Description:
Installs a bunch of code pages for servers. We install sections in intl.inf
named [CODEPAGE_INSTALL_<n>], where the values for <n> are listed in the
section [CodePages].
Arguments:
Window - handle to parent window
Return Value:
None.
--*/
{
HINF hInf;
INFCONTEXT InfContext;
BOOL b;
PCWSTR CodePage;
WCHAR InstallSection[30];
HSPFILEQ FileQueue;
DWORD QueueFlags;
PVOID pQueueContext;
hInf = SetupOpenInfFile(L"INTL.INF",NULL,INF_STYLE_WIN4,NULL);
if(hInf == INVALID_HANDLE_VALUE) {
SetupDebugPrint( L"SETUP: pSetupInstallNLSFiles: Unable to open intl.inf" );
return;
}
if(!SetupOpenAppendInfFile( NULL, hInf, NULL )) {
SetupDebugPrint( L"SETUP: pSetupInstallNLSFiles: Unable to open intl.inf layout" );
return;
}
if(!SetupFindFirstLine(hInf,L"CodePages",NULL,&InfContext)) {
SetupDebugPrint( L"SETUP: pSetupInstallNLSFiles: Unable to find [CodePages] section" );
goto c1;
}
//
// Create a setup file queue and initialize default Setup copy queue
// callback context.
//
QueueFlags = SP_COPY_FORCE_NOOVERWRITE;
FileQueue = SetupOpenFileQueue();
if(!FileQueue || (FileQueue == INVALID_HANDLE_VALUE)) {
SetupDebugPrint( L"SETUP: pSetupInstallNLSFiles: SetupOpenFileQueue failed" );
goto c1;
}
//
// Disable the file-copy progress dialog.
//
pQueueContext = InitSysSetupQueueCallbackEx(
Window,
INVALID_HANDLE_VALUE,
0,0,NULL);
if(!pQueueContext) {
SetupDebugPrint( L"SETUP: pSetupInstallNLSFiles: InitSysSetupQueueCallbackEx failed" );
goto c2;
}
do {
if(CodePage = pSetupGetField(&InfContext,0)) {
wsprintf( InstallSection, L"CODEPAGE_INSTALL_%s", CodePage );
//
// Enqueue locale-related files for copy.
//
b = SetupInstallFilesFromInfSection(
hInf,
NULL,
FileQueue,
InstallSection,
NULL,
QueueFlags
);
if(!b) {
SetupDebugPrint( L"SETUP: pSetupInstallNLSFiles: SetupInstallFilesFromInfSection failed" );
goto c3;
}
}
} while(SetupFindNextLine(&InfContext,&InfContext));
//
// Copy enqueued files.
//
b = SetupCommitFileQueue(
Window,
FileQueue,
SysSetupQueueCallback,
pQueueContext
);
if(!b) {
SetupDebugPrint( L"SETUP: pSetupInstallNLSFiles: SetupCommitFileQueue failed" );
goto c3;
}
if(!SetupFindFirstLine(hInf,L"CodePages",NULL,&InfContext)) {
SetupDebugPrint( L"SETUP: pSetupInstallNLSFiles: Unable to find [CodePages] section (2nd pass)" );
goto c3;
}
do {
if(CodePage = pSetupGetField(&InfContext,0)) {
wsprintf( InstallSection, L"CODEPAGE_INSTALL_%s", CodePage );
//
// Complete installation of locale stuff.
//
b = SetupInstallFromInfSection(
Window,
hInf,
InstallSection,
SPINST_ALL & ~SPINST_FILES,
NULL,
NULL,
0,
NULL,
NULL,
NULL,
NULL
);
if(!b) {
SetupDebugPrint( L"SETUP: pSetupInstallNLSFiles: SetupInstallFromInfSection failed" );
goto c3;
}
}
} while(SetupFindNextLine(&InfContext,&InfContext));
c3:
TermSysSetupQueueCallback(pQueueContext);
c2:
SetupCloseFileQueue(FileQueue);
c1:
SetupCloseInfFile(hInf);
return;
}
DWORD
pSetupInitRegionalSettings(
IN HWND Window
)
{
HINF IntlInf;
LONG l;
HKEY hKey;
DWORD d;
BOOL b;
DWORD Type;
INFCONTEXT LineContext;
WCHAR IdFromRegistry[9];
WCHAR KeyName[9];
WCHAR LanguageGroup[9];
WCHAR LanguageInstallSection[25];
LCID SystemLocale;
HSPFILEQ FileQueue;
DWORD QueueFlags;
PVOID pQueueContext;
//
// Open intl.inf. The locale descriptions are in there.
// Lines in the [Locales] section have keys that are 32-bit
// locale ids but the sort part is always 0, so they're more like
// zero-extended language ids.
//
IntlInf = SetupOpenInfFile(L"intl.inf",NULL,INF_STYLE_WIN4,NULL);
if(IntlInf == INVALID_HANDLE_VALUE) {
SetupDebugPrint( L"SETUP: pSetupInitRegionalSettings: Unable to open intl.inf" );
l = GetLastError();
goto c0;
}
if(!SetupOpenAppendInfFile( NULL, IntlInf, NULL )) {
SetupDebugPrint( L"SETUP: pSetupInitRegionalSettings: Unable to open intl.inf layout" );
l = GetLastError();
goto c0;
}
//
// Read the system locale from the registry. and look up in intl.inf.
// The value in the registry is a 16-bit language id, so we need to
// zero-extend it to index intl.inf.
//
l = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
L"SYSTEM\\CurrentControlSet\\Control\\Nls\\Language",
0,
KEY_QUERY_VALUE,
&hKey
);
if(l == NO_ERROR) {
d = sizeof(IdFromRegistry);
l = RegQueryValueEx(hKey,L"Default",NULL,&Type,(LPBYTE)IdFromRegistry,&d);
RegCloseKey(hKey);
if((l == NO_ERROR) && ((Type != REG_SZ) || (d != 10))) {
l = ERROR_INVALID_DATA;
}
}
if(l == NO_ERROR) {
l = ERROR_INVALID_DATA;
wsprintf(KeyName,L"0000%s",IdFromRegistry);
if(SetupFindFirstLine(IntlInf,L"Locales",KeyName,&LineContext)
&& SetupGetStringField(&LineContext,3,LanguageGroup,
sizeof(LanguageGroup)/sizeof(WCHAR),NULL)) {
l = NO_ERROR;
}
}
if(l == NO_ERROR) {
wsprintf(LanguageInstallSection,L"LG_INSTALL_%s",LanguageGroup);
//
// We copy the files in textmode setup now, so we don't need to do that
// here anymore.
//
#define DO_COPY_FILES
#ifdef DO_COPY_FILES
//
// Create a setup file queue and initialize default Setup copy queue
// callback context.
//
QueueFlags = SP_COPY_FORCE_NOOVERWRITE;
FileQueue = SetupOpenFileQueue();
if(!FileQueue || (FileQueue == INVALID_HANDLE_VALUE)) {
l = ERROR_OUTOFMEMORY;
goto c1;
}
//
// Disable the file-copy progress dialog.
//
pQueueContext = InitSysSetupQueueCallbackEx(
Window,
INVALID_HANDLE_VALUE,
0,0,NULL);
if(!pQueueContext) {
l = ERROR_OUTOFMEMORY;
goto c2;
}
//
// Enqueue locale-related files for copy. We install locales for the
// system default and the Western language group, which is group 1.
//
b = SetupInstallFilesFromInfSection(
IntlInf,
NULL,
FileQueue,
LanguageInstallSection,
NULL,
QueueFlags
);
if(!b) {
l = GetLastError();
goto c3;
}
if(wcscmp(LanguageGroup,L"1")) {
b = SetupInstallFilesFromInfSection(
IntlInf,
NULL,
FileQueue,
L"LG_INSTALL_1",
NULL,
QueueFlags
);
}
if(!b) {
l = GetLastError();
goto c3;
}
//
// Determine whether the queue actually needs to be committed.
//
b = SetupScanFileQueue(
FileQueue,
SPQ_SCAN_FILE_VALIDITY | SPQ_SCAN_PRUNE_COPY_QUEUE,
Window,
NULL,
NULL,
&d
);
if(!b) {
l = GetLastError();
goto c3;
}
//
// d = 0: User wants new files or some files were missing;
// Must commit queue.
//
// d = 1: User wants to use existing files and queue is empty;
// Can skip committing queue.
//
// d = 2: User wants to use existing files but del/ren queues not empty.
// Must commit queue. The copy queue will have been emptied,
// so only del/ren functions will be performed.
//
if(d == 1) {
b = TRUE;
} else {
//
// Copy enqueued files.
//
b = SetupCommitFileQueue(
Window,
FileQueue,
SysSetupQueueCallback,
pQueueContext
);
}
if(!b) {
l = GetLastError();
goto c3;
}
#endif
//
// Complete installation of locale stuff.
//
b = SetupInstallFromInfSection(
Window,
IntlInf,
LanguageInstallSection,
SPINST_ALL & ~SPINST_FILES,
NULL,
NULL,
0,
NULL,
NULL,
NULL,
NULL
);
if(!b) {
l = GetLastError();
#ifdef DO_COPY_FILES
goto c3;
#else
goto c1;
#endif
}
if(wcscmp(LanguageGroup,L"1")) {
b = SetupInstallFromInfSection(
Window,
IntlInf,
L"LG_INSTALL_1",
SPINST_ALL & ~SPINST_FILES,
NULL,
NULL,
0,
NULL,
NULL,
NULL,
NULL
);
}
if(!b) {
l = GetLastError();
#ifdef DO_COPY_FILES
goto c3;
#else
goto c1;
#endif
}
}
pSetupRunRegApps();
SystemLocale = wcstol(IdFromRegistry,NULL,16);
if (l == NO_ERROR) {
l = SetupChangeLocaleEx(
Window,
SystemLocale,
SourcePath,
SP_INSTALL_FILES_QUIETLY,
NULL,0);
#ifdef DO_COPY_FILES
c3:
TermSysSetupQueueCallback(pQueueContext);
c2:
SetupCloseFileQueue(FileQueue);
#endif
}
c1:
SetupCloseInfFile(IntlInf);
c0:
SetupDebugPrint2( L"SETUP: pSetupInitRegionalSettings returned %d (0x%08x)", l, l);
return l;
}
UINT
pSetupFontQueueCallback(
IN PFONTQCONTEXT Context,
IN UINT Notification,
IN UINT_PTR Param1,
IN UINT_PTR Param2
)
{
PFILEPATHS FilePaths;
PWCHAR p;
INFCONTEXT InfContext;
//
// If a file is finished being copied, set its attributes
// to include the hidden attribute if necessary.
//
if((Notification == SPFILENOTIFY_ENDCOPY)
&& (FilePaths = (PFILEPATHS)Param1)
&& (FilePaths->Win32Error == NO_ERROR)
&& (p = wcsrchr(FilePaths->Target,L'\\'))
&& SetupFindFirstLine(Context->FontInf,szHiddenFontFiles,p+1,&InfContext)) {
SetFileAttributes(FilePaths->Target,FILE_ATTRIBUTE_HIDDEN);
}
return( IsSetup ?
SysSetupQueueCallback(Context->SetupQueueContext,Notification,Param1,Param2) :
SetupDefaultQueueCallback(Context->SetupQueueContext,Notification,Param1,Param2)
);
}
VOID
pSetupMarkHiddenFonts(
VOID
)
{
HINF hInf;
INFCONTEXT InfContext;
BOOL b;
WCHAR Path[MAX_PATH];
PWCHAR p;
PCWSTR q;
int Space;
hInf = SetupOpenInfFile(L"FONT.INF",NULL,INF_STYLE_WIN4,NULL);
if(hInf != INVALID_HANDLE_VALUE) {
GetWindowsDirectory(Path,MAX_PATH);
lstrcat(Path,L"\\FONTS\\");
p = Path + lstrlen(Path);
Space = MAX_PATH - (int)(p - Path);
if(SetupFindFirstLine(hInf,szHiddenFontFiles,NULL,&InfContext)) {
do {
if(q = pSetupGetField(&InfContext,0)) {
lstrcpyn(p,q,Space);
if(FileExists(Path,NULL)) {
SetFileAttributes(Path,FILE_ATTRIBUTE_HIDDEN);
}
}
} while(SetupFindNextLine(&InfContext,&InfContext));
}
SetupCloseInfFile(hInf);
}
}
DWORD
pSetupNLSInstallFonts(
IN HWND Window,
IN HINF InfHandle,
IN PCWSTR OemCodepage,
IN PCWSTR FontSize,
IN HSPFILEQ FileQueue,
IN PCWSTR SourcePath, OPTIONAL
IN DWORD QueueFlags
)
{
BOOL b;
WCHAR SectionName[64];
//
// Form section name.
//
wsprintf(SectionName,L"Font.CP%s.%s",OemCodepage,FontSize);
if(FileQueue) {
//
// First pass: just enqueue files for copy.
//
b = SetupInstallFilesFromInfSection(
InfHandle,
NULL,
FileQueue,
SectionName,
SourcePath,
QueueFlags
);
} else {
//
// Second pass: do registry munging, etc.
//
b = SetupInstallFromInfSection(
Window,
InfHandle,
SectionName,
SPINST_ALL & ~SPINST_FILES,
NULL,
NULL,
0,
NULL,
NULL,
NULL,
NULL
);
}
return(b ? NO_ERROR : GetLastError());
}
DWORD
pSetupNLSLoadInfs(
OUT HINF *FontInfHandle,
OUT HINF *IntlInfHandle OPTIONAL
)
{
HINF fontInfHandle;
HINF intlInfHandle;
DWORD d;
fontInfHandle = SetupOpenInfFile(L"font.inf",NULL,INF_STYLE_WIN4,NULL);
if(fontInfHandle == INVALID_HANDLE_VALUE) {
d = GetLastError();
goto c0;
}
if(!SetupOpenAppendInfFile(NULL,fontInfHandle,NULL)) {
d = GetLastError();
goto c1;
}
if(IntlInfHandle) {
intlInfHandle = SetupOpenInfFile(L"intl.inf",NULL,INF_STYLE_WIN4,NULL);
if(intlInfHandle == INVALID_HANDLE_VALUE) {
d = GetLastError();
goto c1;
}
if(!SetupOpenAppendInfFile(NULL,intlInfHandle,NULL)) {
d = GetLastError();
goto c2;
}
*IntlInfHandle = intlInfHandle;
}
*FontInfHandle = fontInfHandle;
return(NO_ERROR);
c2:
SetupCloseInfFile(intlInfHandle);
c1:
SetupCloseInfFile(fontInfHandle);
c0:
return(d);
}
DWORD
SetupChangeLocale(
IN HWND Window,
IN LCID NewLocale
)
{
return(SetupChangeLocaleEx(Window,NewLocale,NULL,0,NULL,0));
}
DWORD
SetupChangeLocaleEx(
IN HWND Window,
IN LCID NewLocale,
IN PCWSTR SourcePath, OPTIONAL
IN DWORD Flags,
IN PVOID Reserved1,
IN DWORD Reserved2
)
{
DWORD d;
BOOL b;
HINF IntlInfHandle;
INFCONTEXT InfContext;
WCHAR Codepage[24];
WCHAR NewLocaleString[24];
FONTQCONTEXT QueueContext;
HSPFILEQ FileQueue;
PCWSTR SizeSpec;
HDC hdc;
PCWSTR p;
DWORD QueueFlags;
HKEY hKey;
DWORD DataType;
DWORD SizeDword;
DWORD DataSize;
SizeSpec = L"96";
#if 0
// This is no longer reliable.
if(hdc = CreateDC(L"DISPLAY",NULL,NULL,NULL)) {
if(GetDeviceCaps(hdc,LOGPIXELSY) > 108) {
SizeSpec = L"120";
}
DeleteDC(hdc);
}
#else
//
// Determine the current font size. Default to 96.
//
d = (DWORD)RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
L"System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
0,
KEY_QUERY_VALUE,
&hKey
);
if(d == NO_ERROR) {
DataSize = sizeof(DWORD);
d = (DWORD)RegQueryValueEx(
hKey,
L"LogPixels",
NULL,
&DataType,
(LPBYTE)&SizeDword,
&DataSize
);
if( (d == NO_ERROR) && (DataType == REG_DWORD) &&
(DataSize == sizeof(DWORD)) && (SizeDword > 108) ) {
SizeSpec = L"120";
}
RegCloseKey(hKey);
}
#endif
QueueFlags = SP_COPY_NEWER | BaseCopyStyle;
if(Flags & SP_INSTALL_FILES_QUIETLY) {
QueueFlags |= SP_COPY_FORCE_NOOVERWRITE;
}
//
// Load inf files.
//
d = pSetupNLSLoadInfs(&QueueContext.FontInf,&IntlInfHandle);
if(d != NO_ERROR) {
goto c0;
}
//
// Get oem codepage for the locale. This is also a sanity check
// to see that the locale is supported.
//
wsprintf(NewLocaleString,L"%.8x",NewLocale);
if(!SetupFindFirstLine(IntlInfHandle,L"Locales",NewLocaleString,&InfContext)) {
d = ERROR_INVALID_PARAMETER;
goto c1;
}
p = pSetupGetField(&InfContext,2);
if(!p) {
d = ERROR_INVALID_PARAMETER;
goto c1;
}
//
// Copy into local storage since p points into internal structures
// that could move as we call INF APIs
//
lstrcpyn(Codepage,p,sizeof(Codepage)/sizeof(Codepage[0]));
//
// Create a setup file queue and initialize default Setup copy queue
// callback context.
//
FileQueue = SetupOpenFileQueue();
if(!FileQueue || (FileQueue == INVALID_HANDLE_VALUE)) {
d = ERROR_OUTOFMEMORY;
goto c1;
}
QueueContext.SetupQueueContext = IsSetup ?
InitSysSetupQueueCallbackEx(
Window,
INVALID_HANDLE_VALUE,
0,0,NULL) :
SetupInitDefaultQueueCallbackEx(
Window,
INVALID_HANDLE_VALUE,
0,0,NULL);
if(!QueueContext.SetupQueueContext) {
d = ERROR_OUTOFMEMORY;
goto c2;
}
//
// Enqueue locale-related files for copy.
//
b = SetupInstallFilesFromInfSection(
IntlInfHandle,
NULL,
FileQueue,
NewLocaleString,
SourcePath,
QueueFlags
);
if(!b) {
d = GetLastError();
goto c3;
}
//
// Enqueue font-related files for copy.
//
d = pSetupNLSInstallFonts(
Window,
QueueContext.FontInf,
Codepage,
SizeSpec,
FileQueue,
SourcePath,
QueueFlags
);
if(d != NO_ERROR) {
goto c3;
}
//
// Determine whether the queue actually needs to be committed.
//
b = SetupScanFileQueue(
FileQueue,
SPQ_SCAN_FILE_VALIDITY | ((Flags & SP_INSTALL_FILES_QUIETLY) ? SPQ_SCAN_PRUNE_COPY_QUEUE : SPQ_SCAN_INFORM_USER),
Window,
NULL,
NULL,
&d
);
if(!b) {
d = GetLastError();
goto c3;
}
//
// d = 0: User wants new files or some files were missing;
// Must commit queue.
//
// d = 1: User wants to use existing files and queue is empty;
// Can skip committing queue.
//
// d = 2: User wants to use existing files but del/ren queues not empty.
// Must commit queue. The copy queue will have been emptied,
// so only del/ren functions will be performed.
//
if(d == 1) {
b = TRUE;
} else {
//
// Copy enqueued files.
//
b = SetupCommitFileQueue(
Window,
FileQueue,
pSetupFontQueueCallback,
&QueueContext
);
}
if(!b) {
d = GetLastError();
goto c3;
}
//
// Complete installation of locale stuff.
//
b = SetupInstallFromInfSection(
Window,
IntlInfHandle,
NewLocaleString,
SPINST_ALL & ~SPINST_FILES,
NULL,
NULL,
0,
NULL,
NULL,
NULL,
NULL
);
if(!b) {
d = GetLastError();
goto c3;
}
//
// Perform font magic associated with the new locale's codepage(s).
//
d = pSetupNLSInstallFonts(Window,QueueContext.FontInf,Codepage,SizeSpec,NULL,NULL,0);
c3:
if(IsSetup) {
TermSysSetupQueueCallback(QueueContext.SetupQueueContext);
} else {
SetupTermDefaultQueueCallback(QueueContext.SetupQueueContext);
}
c2:
SetupCloseFileQueue(FileQueue);
c1:
SetupCloseInfFile(QueueContext.FontInf);
SetupCloseInfFile(IntlInfHandle);
c0:
if (IsSetup) {
SetupDebugPrint2( L"SETUP: SetupChangeLocaleEx returned %d (0x%08x)", d, d);
}
return(d);
}
DWORD
SetupChangeFontSize(
IN HWND Window,
IN PCWSTR SizeSpec
)
{
DWORD d;
WCHAR cp[24];
FONTQCONTEXT QueueContext;
HSPFILEQ FileQueue;
BOOL b;
//
// Get the current OEM CP
//
wsprintf(cp,L"%u",GetOEMCP());
//
// Load NLS inf.
//
d = pSetupNLSLoadInfs(&QueueContext.FontInf,NULL);
if(d != NO_ERROR) {
goto c0;
}
//
// Create queue and initialize default callback routine.
//
FileQueue = SetupOpenFileQueue();
if(!FileQueue || (FileQueue == INVALID_HANDLE_VALUE)) {
d = ERROR_OUTOFMEMORY;
goto c1;
}
QueueContext.SetupQueueContext = IsSetup ?
InitSysSetupQueueCallbackEx(
Window,
INVALID_HANDLE_VALUE,
0,0,NULL) :
SetupInitDefaultQueueCallbackEx(
Window,
INVALID_HANDLE_VALUE,
0,0,NULL);
if(!QueueContext.SetupQueueContext) {
d = ERROR_OUTOFMEMORY;
goto c2;
}
//
// First pass: copy files.
//
d = pSetupNLSInstallFonts(
Window,
QueueContext.FontInf,
cp,
SizeSpec,
FileQueue,
NULL,
SP_COPY_NEWER | BaseCopyStyle
);
if(d != NO_ERROR) {
goto c3;
}
//
// Determine whether the queue actually needs to be committed.
//
b = SetupScanFileQueue(
FileQueue,
SPQ_SCAN_FILE_VALIDITY | SPQ_SCAN_INFORM_USER,
Window,
NULL,
NULL,
&d
);
if(!b) {
d = GetLastError();
goto c3;
}
//
// d = 0: User wants new files or some files were missing;
// Must commit queue.
//
// d = 1: User wants to use existing files and queue is empty;
// Can skip committing queue.
//
// d = 2: User wants to use existing files but del/ren queues not empty.
// Must commit queue. The copy queue will have been emptied,
// so only del/ren functions will be performed.
//
if(d == 1) {
b = TRUE;
} else {
b = SetupCommitFileQueue(
Window,
FileQueue,
pSetupFontQueueCallback,
&QueueContext
);
}
if(!b) {
d = GetLastError();
goto c3;
}
//
// Second pass: perform registry munging, etc.
//
d = pSetupNLSInstallFonts(Window,QueueContext.FontInf,cp,SizeSpec,NULL,NULL,0);
c3:
if(IsSetup) {
TermSysSetupQueueCallback(QueueContext.SetupQueueContext);
} else {
SetupTermDefaultQueueCallback(QueueContext.SetupQueueContext);
}
c2:
SetupCloseFileQueue(FileQueue);
c1:
SetupCloseInfFile(QueueContext.FontInf);
c0:
return(d);
}
////////////////////////////////////////////////////////////////////
//
// Code below here is for regional settings stuff that occurs during
// gui mode setup
//
////////////////////////////////////////////////////////////////////
INT_PTR
CALLBACK
RegionalSettingsDlgProc(
IN HWND hdlg,
IN UINT msg,
IN WPARAM wParam,
IN LPARAM lParam
)
{
BOOL b;
NMHDR *NotifyParams;
WCHAR CmdLine[MAX_PATH];
b = TRUE;
switch(msg) {
case WM_SIMULATENEXT:
PropSheet_PressButton(GetParent(hdlg),PSBTN_NEXT);
break;
case WMX_VALIDATE:
// Empty page
return ReturnDlgResult (hdlg, VALIDATE_DATA_OK);
case WM_NOTIFY:
NotifyParams = (NMHDR *)lParam;
switch(NotifyParams->code) {
case PSN_SETACTIVE:
TESTHOOK(502);
BEGIN_SECTION(L"Regional Settings Page");
SetWizardButtons(hdlg,WizPageRegionalSettings);
//
// Set message text.
//
pSetLocaleSummaryText(hdlg);
pSetKeyboardLayoutSummaryText(hdlg);
//
// Allow activation.
//
//
// Show unless OEMSkipRegional = 1
//
if( Preinstall ) {
//
// Always show the page in a Preinstall, unless the user
// has sent us OEMSkipRegional.
//
if (GetPrivateProfileInt(pwGuiUnattended,L"OEMSkipRegional",0,AnswerFile))
{
SetWindowLongPtr(hdlg, DWLP_MSGRESULT, -1 );
}
else
{
// Page becomes active, make page visible.
SendMessage(GetParent(hdlg), WMX_BBTEXT, (WPARAM)FALSE, 0);
SetWindowLongPtr(hdlg, DWLP_MSGRESULT,0);
}
} else {
SetWindowLongPtr( hdlg, DWLP_MSGRESULT, 0 );
if(Unattended) {
if (!UnattendSetActiveDlg(hdlg,IDD_REGIONAL_SETTINGS))
{
break;
}
}
// Page becomes active, make page visible.
SendMessage(GetParent(hdlg), WMX_BBTEXT, (WPARAM)FALSE, 0);
}
break;
case PSN_WIZNEXT:
case PSN_WIZFINISH:
//
// Allow next page to be activated.
//
SetWindowLongPtr(hdlg,DWLP_MSGRESULT,0);
break;
case PSN_KILLACTIVE:
WizardKillHelp(hdlg);
SetWindowLongPtr(hdlg,DWLP_MSGRESULT,FALSE);
END_SECTION(L"Regional Settings Page");
break;
case PSN_HELP:
WizardBringUpHelp(hdlg,WizPageRegionalSettings);
break;
default:
b = FALSE;
break;
}
break;
case WM_COMMAND:
switch(LOWORD(wParam)) {
case IDB_LOCALE:
case IDB_KBDLAYOUT:
if(HIWORD(wParam) == BN_CLICKED) {
PropSheet_SetWizButtons(GetParent(hdlg),0);
EnableWindow(GetParent(hdlg),FALSE);
wsprintf(
CmdLine,
L"/%c /s:\"%s\"",
(LOWORD(wParam) == IDB_LOCALE) ? L'R' : L'I',
LegacySourcePath
);
InvokeControlPanelApplet(L"intl.cpl",L"",0,CmdLine);
if(LOWORD(wParam) == IDB_LOCALE) {
pSetLocaleSummaryText(hdlg);
}
pSetKeyboardLayoutSummaryText(hdlg);
EnableWindow(GetParent(hdlg),TRUE);
SetWizardButtons(hdlg,WizPageRegionalSettings);
// Get the focus tot he wizard and set it to the button the user selected.
SetForegroundWindow(GetParent(hdlg));
SetFocus(GetDlgItem(hdlg,LOWORD(wParam)));
} else {
b = FALSE;
}
break;
default:
b = FALSE;
break;
}
break;
default:
b = FALSE;
break;
}
return(b);
}
VOID
pSetLocaleSummaryText(
IN HWND hdlg
)
{
HINF IntlInf;
LONG l;
HKEY hKey;
DWORD d;
DWORD Type;
INFCONTEXT LineContext;
WCHAR IdFromRegistry[9];
WCHAR KeyName[9];
WCHAR UserLocale[100],GeoLocation[100];
WCHAR FormatString[300];
WCHAR MessageText[500];
LPCWSTR args[2];
DWORD dwGeoID;
//
// Open intl.inf. The locale descriptions are in there.
// Lines in the [Locales] section have keys that are 32-bit
// locale ids but the sort part is always 0, so they're more like
// zero-extended language ids.
//
IntlInf = SetupOpenInfFile(L"intl.inf",NULL,INF_STYLE_WIN4,NULL);
if(IntlInf == INVALID_HANDLE_VALUE) {
LoadString(MyModuleHandle,IDS_UNKNOWN_PARENS,UserLocale,sizeof(UserLocale)/sizeof(WCHAR));
lstrcpy(GeoLocation,UserLocale);
} else {
//
// Read the user locale, which is stored as a full 32-bit LCID.
// We have to chop off the sort id part to index intl.inf.
//
l = RegOpenKeyEx(
HKEY_CURRENT_USER,
L"Control Panel\\International",
0,
KEY_QUERY_VALUE,
&hKey
);
if(l == NO_ERROR) {
d = sizeof(IdFromRegistry);
l = RegQueryValueEx(hKey,L"Locale",NULL,&Type,(LPBYTE)IdFromRegistry,&d);
RegCloseKey(hKey);
if((l == NO_ERROR) && ((Type != REG_SZ) || (d != 18))) {
l = ERROR_INVALID_DATA;
}
}
if(l == NO_ERROR) {
l = ERROR_INVALID_DATA;
wsprintf(KeyName,L"0000%s",IdFromRegistry+4);
if(SetupFindFirstLine(IntlInf,L"Locales",KeyName,&LineContext)
&& SetupGetStringField(&LineContext,1,UserLocale,sizeof(UserLocale)/sizeof(WCHAR),NULL)) {
l = NO_ERROR;
}
}
if(l != NO_ERROR) {
LoadString(MyModuleHandle,IDS_UNKNOWN_PARENS,UserLocale,sizeof(UserLocale)/sizeof(WCHAR));
}
SetupCloseInfFile(IntlInf);
//
// Read the GEO location
//
l = RegOpenKeyEx(
HKEY_CURRENT_USER,
L"Control Panel\\International\\Geo",
0,
KEY_QUERY_VALUE,
&hKey
);
if(l == NO_ERROR) {
d = sizeof(IdFromRegistry);
l = RegQueryValueEx(hKey,L"Nation",NULL,&Type,(LPBYTE)IdFromRegistry,&d);
RegCloseKey(hKey);
if((l == NO_ERROR) && (Type != REG_SZ)) {
l = ERROR_INVALID_DATA;
}
}
if(l == NO_ERROR) {
l = ERROR_INVALID_DATA;
dwGeoID = wcstoul ( IdFromRegistry, NULL, 10 );
if (GetGeoInfo (
dwGeoID,
GEO_FRIENDLYNAME,
GeoLocation,
sizeof(GeoLocation)/sizeof(WCHAR),
0 )
) {
l = NO_ERROR;
}
}
if(l != NO_ERROR) {
LoadString(MyModuleHandle,IDS_UNKNOWN_PARENS,GeoLocation,sizeof(GeoLocation)/sizeof(WCHAR));
}
}
args[0] = UserLocale;
args[1] = GeoLocation;
LoadString(MyModuleHandle,IDS_LOCALE_MSG,FormatString,sizeof(FormatString)/sizeof(WCHAR));
FormatMessage(
FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
FormatString,
0,0,
MessageText,
sizeof(MessageText)/sizeof(WCHAR),
(va_list *)args
);
SetDlgItemText(hdlg,IDT_LOCALE,MessageText);
}
VOID
pSetKeyboardLayoutSummaryText(
IN HWND hdlg
)
{
LONG l;
HKEY hKey;
BOOL MultipleLayouts;
DWORD d;
DWORD Type;
WCHAR IdFromRegistry[9];
WCHAR Substitute[9];
WCHAR Name[200];
WCHAR FormatString[300];
WCHAR MessageText[500];
//
// Open the Preload key in the registry.
//
l = RegOpenKeyEx(
HKEY_CURRENT_USER,
L"Keyboard Layout\\Preload",
0,
KEY_QUERY_VALUE,
&hKey
);
MultipleLayouts = FALSE;
if(l == NO_ERROR) {
//
// Pull out 2=. If it's there, then we're in a "complex" config
// situation, which will change our message text a little.
//
d = sizeof(IdFromRegistry);
if(RegQueryValueEx(hKey,L"2",NULL,&Type,(LPBYTE)IdFromRegistry,&d) == NO_ERROR) {
MultipleLayouts = TRUE;
}
//
// Get 1=, which is the main layout.
//
d = sizeof(IdFromRegistry);
l = RegQueryValueEx(hKey,L"1",NULL,&Type,(LPBYTE)IdFromRegistry,&d);
if((l == NO_ERROR) && (Type != REG_SZ)) {
l = ERROR_INVALID_DATA;
}
RegCloseKey(hKey);
//
// Now we look in the substitutes key to see whether there is a
// substitute there.
//
if(RegOpenKeyEx(HKEY_CURRENT_USER,L"Keyboard Layout\\Substitutes",0,KEY_QUERY_VALUE,&hKey) == NO_ERROR) {
d = sizeof(Substitute);
if((RegQueryValueEx(hKey,IdFromRegistry,NULL,&Type,(LPBYTE)Substitute,&d) == NO_ERROR)
&& (Type == REG_SZ)) {
lstrcpy(IdFromRegistry,Substitute);
}
RegCloseKey(hKey);
}
//
// Form the name of the subkey that contains layout data.
//
wsprintf(
Name,
L"System\\CurrentControlSet\\Control\\Keyboard Layouts\\%s",
IdFromRegistry
);
//
// Open the key and retrieve the layout name.
//
l = RegOpenKeyEx(HKEY_LOCAL_MACHINE,Name,0,KEY_QUERY_VALUE,&hKey);
if(l == NO_ERROR) {
d = sizeof(Name);
l = RegQueryValueEx(hKey,L"Layout Text",NULL,&Type,(LPBYTE)Name,&d);
if((l == NO_ERROR) && (Type != REG_SZ)) {
l = ERROR_INVALID_DATA;
}
RegCloseKey(hKey);
}
}
if(l != NO_ERROR) {
LoadString(MyModuleHandle,IDS_UNKNOWN_PARENS,Name,sizeof(Name)/sizeof(WCHAR));
}
LoadString(
MyModuleHandle,
IDS_KBDLAYOUT_MSG,
FormatString,
sizeof(FormatString)/sizeof(WCHAR)
);
wsprintf(MessageText,FormatString,Name);
SetDlgItemText(hdlg,IDT_KBD_LAYOUT,MessageText);
}