/*++ 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_], where the values for 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); }