|
|
////////////////////////////////////////////////////////////////////////////
//
// MUISetup.cpp
//
// This file contains the WinMain() and the UI handling of MUISetup.
//
// MUISetup is compiled as an Unicode application.
//
////////////////////////////////////////////////////////////////////////////
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <userenv.h>
#include <shellapi.h>
#include <regstr.h>
#include <wmistr.h>
#include <wmiumkm.h>
#include <setupapi.h>
#include <shlwapi.h>
#include "sxsapi.h"
#include "muisetup.h"
#define STRSAFE_LIB
#include <strsafe.h>
//
// Context Help IDs
//
//
// Context Help Ids.
//
STDAPI_(BOOL) IsUserAnAdmin(); static int aMuisetupHelpIds[] = { 207, IDH_COMM_GROUPBOX, // Group Box
IDC_LIST1, IDH_MUISETUP_UILANGUAGE_LIST, // UI Language ListView
IDC_DEF_UI_LANG_COMBO, IDH_MUISETUP_UILANGUAGECOMBO, // UI ComboBox selection
IDC_CHECK_LOCALE, IDH_MUISETUP_CHECKLOCALE, // Match system locale with UI language
IDC_CHECK_UIFONT, IDH_MUISETUP_MATCHUIFONT, // Match system locale with UI language
0, 0 }; //
// Global variables
//
BOOL g_bMatchUIFont; // Store the special directories listed under [Directories] in mui.inf
TCHAR DirNames[MFL][MAX_PATH],DirNames_ie[MFL][MAX_PATH]; TCHAR szWindowsDir[MAX_PATH]; // The FOLDER where MUISetup.exe is executed.
TCHAR g_szMUISetupFolder[MAX_PATH]; // The FULL PATH for MUISetup.exe.
TCHAR g_szMuisetupPath[MAX_PATH]; // The full path where MUI.inf is located.
TCHAR g_szMUIInfoFilePath[MAX_PATH]; TCHAR g_szVolumeName[MAX_PATH],g_szVolumeRoot[MAX_PATH]; TCHAR g_szMUIHelpFilePath[MAX_PATH],g_szPlatformPath[16],g_szCDLabel[MAX_PATH]; // Windows directory
TCHAR g_szWinDir[MAX_PATH]; TCHAR g_AddLanguages[BUFFER_SIZE]; HANDLE ghMutex = NULL; HINSTANCE ghInstance; HWND ghProgDialog; // The progress dialog showed during installation/uninstallation.
HWND ghProgress; // The progress bar in the progress dialog
LANGID gUserUILangId, gSystemUILangId; BOOL gbIsWorkStation,gbIsServer,gbIsAdvanceServer,gbIsDataCenter,gbIsDomainController; HINSTANCE g_hUserEnvDll = NULL; HMODULE g_hAdvPackDll = NULL; HMODULE g_hSxSDll = NULL; DWORD g_dwVolumeSerialNo; BOOL g_InstallCancelled,g_IECopyError,g_bRemoveDefaultUI,g_bRemoveUserUI,g_bCmdMatchLocale,g_bCmdMatchUIFont, g_bReboot; UILANGUAGEGROUP g_UILanguageGroup; int g_cdnumber; // Number of MUI languges to insatll
int gNumLanguages,gNumLanguages_Install,gNumLanguages_Uninstall; // Flag to indicate whether a language group is found for the locale or not.
BOOL gFoundLangGroup; LGRPID gLangGroup; LCID gLCID; // The language groups installed in the system.
LGRPID gLanguageGroups[32] ; int gNumLanguageGroups; PFILERENAME_TABLE g_pFileRenameTable; int g_nFileRename; PTYPENOTFALLBACK_TABLE g_pNotFallBackTable; int g_nNotFallBack; BOOL g_bSilent=FALSE; // indicate that muisetup should need no user interaction
BOOL g_bNoUI=FALSE; // indicate that muisetup should install with no UI displayed and no user interaction
BOOL g_bRunFromOSSetup=FALSE; // indicated that muisetup is called as part of NT setup/upgrade
BOOL g_bLipLanguages; BOOL g_bLipAllowSwitch; //
// Required pfns
//
pfnNtSetDefaultUILanguage gpfnNtSetDefaultUILanguage; pfnGetUserDefaultUILanguage gpfnGetUserDefaultUILanguage; pfnGetSystemDefaultUILanguage gpfnGetSystemDefaultUILanguage; pfnIsValidLanguageGroup gpfnIsValidLanguageGroup; pfnEnumLanguageGroupLocalesW gpfnEnumLanguageGroupLocalesW; pfnEnumSystemLanguageGroupsW gpfnEnumSystemLanguageGroupsW; pfnRtlAdjustPrivilege gpfnRtlAdjustPrivilege; pfnProcessIdToSessionId gpfnProcessIdToSessionId; pfnGetDefaultUserProfileDirectoryW gpfnGetDefaultUserProfileDirectoryW = NULL; pfnLaunchINFSection gpfnLaunchINFSection = NULL; PSXS_INSTALL_W gpfnSxsInstallW = NULL; PSXS_UNINSTALL_ASSEMBLYW gpfnSxsUninstallW = NULL;
//
// GetWindowsDirectory stuff
//
UINT WINAPI NT4_GetWindowsDir(LPWSTR pBuf, UINT uSize) { return GetWindowsDirectoryW(pBuf, uSize); } //
// shlwapi StrToIntEx doesn't work for us
//
DWORD HexStrToInt(LPTSTR lpsz) { DWORD dw = 0L; TCHAR c; if (! lpsz) { return dw; } 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); } UINT (WINAPI *pfnGetWindowsDir)(LPWSTR pBuf, UINT uSize) = NT4_GetWindowsDir;
void InitGetWindowsDirectoryPFN(HMODULE hMod) { pfnGetWindowsDir = (UINT (WINAPI *) (LPWSTR pBuf, UINT uSize)) GetProcAddress(hMod, "GetSystemWindowsDirectoryW"); if (!pfnGetWindowsDir) { pfnGetWindowsDir = NT4_GetWindowsDir; } }
////////////////////////////////////////////////////////////////////////////
//
// GetLanguageDisplayName
//
// Get the display name (in the form of "Language (Region)") for the specified
// language ID.
//
// Parameters:
// [IN] langID Language ID
// [OUT] lpBuffer the buffer to receive the display name.
// [IN] nBufferSize the size of buffer, in TCHAR.
//
// Return Values:
// TRUE if succeed. FALSE if the buffer is not big enough.
//
//
// 01-11-2001 YSLin Created.
//
////////////////////////////////////////////////////////////////////////////
BOOL GetLanguageDisplayName(LANGID langID, LPTSTR lpBuffer, int nBufferSize) { TCHAR lpLangName[BUFFER_SIZE]; TCHAR lpRegionName[BUFFER_SIZE]; int nCharCount = 0; HRESULT hresult = S_OK; nCharCount = GetLocaleInfo(langID, LOCALE_SENGLANGUAGE, lpLangName, ARRAYSIZE(lpLangName)-1); nCharCount += GetLocaleInfo(langID, LOCALE_SENGCOUNTRY , lpRegionName, ARRAYSIZE(lpRegionName)-1); nCharCount += 3; if (nCharCount > nBufferSize) { if (nBufferSize) //*STRSAFE* lstrcpy(lpBuffer, TEXT(""));
hresult = StringCchCopy(lpBuffer , nBufferSize, TEXT("")); if (!SUCCEEDED(hresult)) { return FALSE; } return (FALSE); } //*STRSAFE* wsprintf(lpBuffer, TEXT("%s (%s)"), lpLangName, lpRegionName);
hresult = StringCchPrintf(lpBuffer , nBufferSize, TEXT("%s (%s)"), lpLangName, lpRegionName); if (!SUCCEEDED(hresult)) { return FALSE; } return (TRUE); } //
// Our Message Box
//
int DoMessageBox(HWND hwndParent, UINT uIdString, UINT uIdCaption, UINT uType) { TCHAR szString[MAX_PATH+MAX_PATH]; TCHAR szCaption[MAX_PATH]; szString[0] = szCaption[0] = TEXT('\0'); if (uIdString) LoadString(NULL, uIdString, szString, MAX_PATH+MAX_PATH-1); if (uIdCaption) LoadString(NULL, uIdCaption, szCaption, MAX_PATH-1); return MESSAGEBOX(hwndParent, szString, szCaption, uType); } ////////////////////////////////////////////////////////////////////////////
//
// DoMessageBoxFromResource
//
// Load a format string from resource, and format the string using the
// specified arguments. Display a message box using the formatted string.
//
// Parameters:
//
// Return Values:
// The return value from MessageBox.
//
// Remarks:
// The length of the formatted string is limited by BUFFER_SIZE.
//
// 08-07-2000 YSLin Created.
//
////////////////////////////////////////////////////////////////////////////
int DoMessageBoxFromResource(HWND hwndParent, HMODULE hInstance, UINT uIdString, LONG_PTR* lppArgs, UINT uIdCaption, UINT uType) { TCHAR szString[BUFFER_SIZE]; TCHAR szCaption[BUFFER_SIZE]; szString[0] = szCaption[0] = TEXT('\0'); if (uIdCaption) LoadString(hInstance, uIdCaption, szCaption, MAX_PATH-1); FormatStringFromResource(szString, sizeof(szString)/sizeof(TCHAR), hInstance, uIdString, lppArgs); return (MESSAGEBOX(hwndParent, szString, szCaption, uType)); } BOOL IsMatchingPlatform(void) { BOOL bx86Image = FALSE; BOOL bRet = TRUE; TCHAR szWOW64Path[MAX_PATH]; #ifdef _X86_
bx86Image = TRUE; #endif
if (GetSystemWow64Directory(szWOW64Path, ARRAYSIZE(szWOW64Path)) && bx86Image) bRet = FALSE; return bRet; } //
// Program Entry Point
//
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow) { int result = 0; BOOL bForwardCall=FALSE; TCHAR lpCommandLine[BUFFER_SIZE+1]; HMODULE hMod; int error,nNumArgs=0,i; LONG_PTR lppArgs[3]; LPWSTR *pszArgv=NULL; HRESULT hresult; if (!IsUserAnAdmin()) { //
// "You must have administrator right to run muisetup.\n\n"
// "If you want to switch your UI language, please use the regional option from control panel."
//
LogFormattedMessage(ghInstance, IDS_ADMIN_L, NULL); DoMessageBox(NULL, IDS_ADMIN, IDS_MAIN_TITLE, MB_OK); return result; } //
// Bail out if image doesn't match the running platform
//
if (!IsMatchingPlatform()) { DoMessageBox(NULL, IDS_WRONG_IMAGE, IDS_MAIN_TITLE, MB_OK | MB_DEFBUTTON1); return result; } ghInstance = hInstance; //
// Let make sure this NT5, and let's initialize all our pfns
//
if (!InitializePFNs()) { //
// Not an NT5 system. The following should be ANSI to work on Win9x.
//
CHAR szString[MAX_PATH]; CHAR szCaption[MAX_PATH]; LoadStringA(NULL, IDS_ERROR_NT5_ONLY, szString, MAX_PATH-1); LoadStringA(NULL, IDS_MAIN_TITLE, szCaption, MAX_PATH-1); MessageBoxA(NULL, szString, szCaption, MB_OK | MB_ICONINFORMATION); result = 1; goto Exit; } //
// Check if the program has already been running ?
//
if (CheckMultipleInstances()) { result = 1; goto Exit; } //
// Initialize any global vars
//
InitGlobals(); //
// Check if I'm launching from previous version of muisetup
//
// I.E. muisetup /$_transfer_$ path_of_MUI_installation_files
//
pszArgv = CommandLineToArgvW((LPCWSTR) GetCommandLineW(), &nNumArgs); lpCommandLine[0]=TEXT('\0'); if (pszArgv) { for (i=1; i<nNumArgs;i++) { if (!_tcsicmp(pszArgv[i],MUISETUP_FORWARDCALL_TAG) && ((i+1) < nNumArgs) ) { Set_SourcePath_FromForward(pszArgv[i+1]); bForwardCall=TRUE; i++; } else { //*STRSAFE* _tcscat(lpCommandLine,pszArgv[i]);
hresult = StringCchCat(lpCommandLine , ARRAYSIZE(lpCommandLine), pszArgv[i]); if (!SUCCEEDED(hresult)) { result = 1; goto Exit; } //*STRSAFE* _tcscat(lpCommandLine,TEXT(" "));
hresult = StringCchCat(lpCommandLine , ARRAYSIZE(lpCommandLine), TEXT(" ")); if (!SUCCEEDED(hresult)) { result = 1; goto Exit; }
} } }
//
// Check if there is a new version of muisetup.exe at %windir%\mui
//
// If it's the case, transfer all the control to it
//
if (!bForwardCall) { if ( MUIShouldSwitchToNewVersion(lpCommandLine) ) { result = 0; goto Exit;; } }
InitCommonControls();
BeginLog(); //
// Block the installation of Personal and Professional
// NOTE: this is here for only the .NET server release, re-enable pro sku after this.
//
#ifdef MUI_MAGIC
if (CheckProductType(MUI_IS_WIN2K_PERSONAL) || CheckProductType(MUI_IS_WIN2K_PRO)) #else
if (CheckProductType(MUI_IS_WIN2K_PERSONAL)) #endif
{ //
// "Windows XP MultiLanguage Version cannot be installed on this platform."
//
DoMessageBox(NULL, IDS_ERROR_NT5_ONLY, IDS_MAIN_TITLE, MB_OK | MB_DEFBUTTON1); result = 1; goto Exit; } //
// Check to see if a command line has been used
//
if(lpCommandLine && NextCommandTag(lpCommandLine)) { lppArgs[0] = (LONG_PTR)lpCommandLine; LogFormattedMessage(NULL, IDS_COMMAND_LOG, lppArgs); LogMessage(TEXT("")); //Add a carriage return and newline
ParseCommandLine(lpCommandLine); } else { //
// MUI version needs to match OS version
//
if (!checkversion(TRUE)) { DoMessageBox(NULL, IDS_WRONG_VERSION, IDS_MAIN_TITLE, MB_OK | MB_DEFBUTTON1); result = 1; goto Exit; } if (WelcomeDialog(0)) { DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG_MAIN), 0, DialogFunc); } result = 1; } Exit: //
// Cleanup
//
if ( pszArgv) { GlobalFree((HGLOBAL) pszArgv); } Muisetup_Cleanup(); return result; } ////////////////////////////////////////////////////////////////////////////////////
//
// CheckMultipleInstances
//
// Checks if another instance is running, and if so, it switches to it.
//
////////////////////////////////////////////////////////////////////////////////////
BOOL CheckMultipleInstances(void) { ghMutex = CreateMutex(NULL, TRUE, TEXT("Muisetup_Mutex")); if (ghMutex && (GetLastError() == ERROR_ALREADY_EXISTS)) { const int idsTitles[] = {IDS_MAIN_TITLE, IDS_INSTALL_TITLE, IDS_PROG_TITLE_2, IDS_PROG_TITLE_3, IDS_UNINSTALL_TITLE}; HWND hWnd; TCHAR szTitle[MAX_PATH]; int i; //
// Find the running instance by searching possible Window titles
//
for (i=0; i<ARRAYSIZE(idsTitles); i++) { LoadString(NULL, idsTitles[i], szTitle, MAX_PATH-1); hWnd = FindWindow(NULL,szTitle); if (hWnd && IsWindow(hWnd)) { if (IsIconic(hWnd)) ShowWindow(hWnd, SW_RESTORE); SetForegroundWindow(hWnd); break; } } //
// Always bail out if there is another running instance
//
return TRUE; } return FALSE; } ////////////////////////////////////////////////////////////////////////////////////
//
// InitializePFNs
//
// Initialize NT5 specific pfns
//
////////////////////////////////////////////////////////////////////////////////////
BOOL InitializePFNs() { HMODULE hModule; SYSTEM_INFO SystemInfo; LONG_PTR lppArgs[2]; HRESULT hresult; //
// Determine platform
//
GetSystemInfo( &SystemInfo ); if (SystemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL || SystemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 || SystemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64) { #if defined(_AMD64_)
//*STRSAFE* _tcscpy(g_szPlatformPath, TEXT("amd64\\"));
hresult = StringCchCopy(g_szPlatformPath , ARRAYSIZE(g_szPlatformPath), TEXT("amd64\\")); if (!SUCCEEDED(hresult)) { return FALSE; } #elif defined(_IA64_)
//*STRSAFE* _tcscpy(g_szPlatformPath, TEXT("ia64\\"));
hresult = StringCchCopy(g_szPlatformPath , ARRAYSIZE(g_szPlatformPath), TEXT("ia64\\")); if (!SUCCEEDED(hresult)) { return FALSE; } #else
//*STRSAFE* _tcscpy(g_szPlatformPath, TEXT("i386\\"));
hresult = StringCchCopy(g_szPlatformPath , ARRAYSIZE(g_szPlatformPath), TEXT("i386\\")); if (!SUCCEEDED(hresult)) { return FALSE; } #endif
} else { // This is NOT supported yet
return FALSE; } //
// Let's bring ntdll!NtSetDefaultUILanguage
//
hModule = GetModuleHandle(TEXT("ntdll.dll")); if (!hModule) return FALSE; gpfnNtSetDefaultUILanguage = (pfnNtSetDefaultUILanguage)GetProcAddress(hModule, "NtSetDefaultUILanguage"); if (!gpfnNtSetDefaultUILanguage) return FALSE; gpfnRtlAdjustPrivilege = (pfnRtlAdjustPrivilege)GetProcAddress(hModule, "RtlAdjustPrivilege"); if (!gpfnRtlAdjustPrivilege) return FALSE; //
// Let's get out from kernel32.dll :
// - GetUserDefaultUILanguage
// - GetSystemDefaultUILanguage
// - EnumLanguageGroupLocalesW
//
hModule = GetModuleHandle(TEXT("kernel32.dll")); if (!hModule) return FALSE; gpfnGetUserDefaultUILanguage = (pfnGetUserDefaultUILanguage)GetProcAddress(hModule, "GetUserDefaultUILanguage"); if (!gpfnGetUserDefaultUILanguage) return FALSE; gpfnGetSystemDefaultUILanguage = (pfnGetSystemDefaultUILanguage)GetProcAddress(hModule, "GetSystemDefaultUILanguage"); if (!gpfnGetSystemDefaultUILanguage) return FALSE; gpfnIsValidLanguageGroup = (pfnIsValidLanguageGroup)GetProcAddress(hModule, "IsValidLanguageGroup"); if (!gpfnIsValidLanguageGroup) return FALSE; gpfnEnumLanguageGroupLocalesW = (pfnEnumLanguageGroupLocalesW)GetProcAddress(hModule, "EnumLanguageGroupLocalesW"); if (!gpfnEnumLanguageGroupLocalesW) return FALSE; gpfnEnumSystemLanguageGroupsW = (pfnEnumSystemLanguageGroupsW)GetProcAddress(hModule, "EnumSystemLanguageGroupsW"); if (!gpfnEnumSystemLanguageGroupsW) return FALSE; gpfnProcessIdToSessionId = (pfnProcessIdToSessionId) GetProcAddress(hModule, "ProcessIdToSessionId"); //
// Initialize the pfnGetWindowsDirectory
//
InitGetWindowsDirectoryPFN(hModule); //
// Try to load userenv.dll
//
g_hUserEnvDll = LoadLibrary(TEXT("userenv.dll")); if (g_hUserEnvDll) { gpfnGetDefaultUserProfileDirectoryW = (pfnGetDefaultUserProfileDirectoryW)GetProcAddress(g_hUserEnvDll, "GetDefaultUserProfileDirectoryW"); } else { LogFormattedMessage(ghInstance, IDS_LOAD_USERENV_L, NULL); return (FALSE); } g_hAdvPackDll = LoadLibrary(TEXT("AdvPack.dll")); if (g_hAdvPackDll == NULL) { LogFormattedMessage(ghInstance, IDS_LOAD_ADVPACK_L, NULL); return (FALSE); } gpfnLaunchINFSection = (pfnLaunchINFSection)GetProcAddress(g_hAdvPackDll, "LaunchINFSection"); if (gpfnLaunchINFSection == NULL) { lppArgs[0] = (LONG_PTR)TEXT("LaunchINFSection"); LogFormattedMessage(ghInstance, IDS_LOAD_ADVPACK_API_L, lppArgs); return (FALSE); } g_hSxSDll = LoadLibrary(TEXT("SxS.dll")); if (g_hSxSDll) { gpfnSxsInstallW = (PSXS_INSTALL_W)GetProcAddress(g_hSxSDll, SXS_INSTALL_W); gpfnSxsUninstallW = (PSXS_UNINSTALL_ASSEMBLYW)GetProcAddress(g_hSxSDll, SXS_UNINSTALL_ASSEMBLYW); } else { LogFormattedMessage(ghInstance, IDS_LOAD_SXS_L, NULL); return (FALSE); } return TRUE; } ////////////////////////////////////////////////////////////////////////////////////
//
// Find the path of execution file and set path for MUI.INF
//
//
////////////////////////////////////////////////////////////////////////////////////
void SetSourcePath(LPTSTR lpszPreviousMUIPath) { UINT_PTR cb; LPTSTR lpszPath,lpszNext=NULL; TCHAR szHelpPath[MAX_PATH+1],szHelpFile[MAX_PATH+1]; HRESULT hresult;
if (!lpszPreviousMUIPath) { g_szMUISetupFolder[0]=TEXT('\0'); cb = GetModuleFileName (ghInstance, g_szMuisetupPath, MAX_PATH); //*STRSAFE* _tcscpy(g_szMUISetupFolder,g_szMuisetupPath);
hresult = StringCchCopy(g_szMUISetupFolder , ARRAYSIZE(g_szMUISetupFolder), g_szMuisetupPath); if (!SUCCEEDED(hresult)) { return; } //
// Get folder for MUISetup.
//
lpszPath = g_szMUISetupFolder; while ( (lpszNext=_tcschr(lpszPath,TEXT('\\'))) ) { lpszPath = lpszNext+1; } *lpszPath=TEXT('\0'); } else { //*STRSAFE* _tcscpy(g_szMUISetupFolder,lpszPreviousMUIPath);
hresult = StringCchCopy(g_szMUISetupFolder , ARRAYSIZE(g_szMUISetupFolder), lpszPreviousMUIPath); if (!SUCCEEDED(hresult)) { return ; } } //*STRSAFE* _tcscpy(g_szMUIInfoFilePath,g_szMUISetupFolder);
hresult = StringCchCopy(g_szMUIInfoFilePath , ARRAYSIZE(g_szMUIInfoFilePath), g_szMUISetupFolder); if (!SUCCEEDED(hresult)) { return; } //*STRSAFE* _tcscat(g_szMUIInfoFilePath,MUIINFFILENAME);
hresult = StringCchCat(g_szMUIInfoFilePath , ARRAYSIZE(g_szMUIInfoFilePath), MUIINFFILENAME); if (!SUCCEEDED(hresult)) { return ; } //
// Check the location of help file
//
//*STRSAFE* _tcscpy(szHelpPath,g_szMUISetupFolder);
hresult = StringCchCopy(szHelpPath , ARRAYSIZE(szHelpPath), g_szMUISetupFolder); if (!SUCCEEDED(hresult)) { return ; } LoadString(NULL, IDS_HELPFILE,szHelpFile,MAX_PATH); //*STRSAFE* _tcscat(szHelpPath,szHelpFile);
hresult = StringCchCat(szHelpPath , ARRAYSIZE(szHelpPath), szHelpFile); if (!SUCCEEDED(hresult)) { return; } if (!FileExists(szHelpPath)) { pfnGetWindowsDir(szHelpPath, MAX_PATH); //*STRSAFE* _tcscat(szHelpPath, TEXT("\\"));
hresult = StringCchCat(szHelpPath , ARRAYSIZE(szHelpPath), TEXT("\\")); if (!SUCCEEDED(hresult)) { return ; } //*STRSAFE* _tcscat(szHelpPath,HELPDIR); // HELP\MUI
hresult = StringCchCat(szHelpPath , ARRAYSIZE(szHelpPath), HELPDIR); if (!SUCCEEDED(hresult)) { return ; } //*STRSAFE* _tcscat(szHelpPath, TEXT("\\"));
hresult = StringCchCat(szHelpPath , ARRAYSIZE(szHelpPath), TEXT("\\")); if (!SUCCEEDED(hresult)) { return ; } //*STRSAFE* _tcscat(szHelpPath,szHelpFile);
hresult = StringCchCat(szHelpPath , ARRAYSIZE(szHelpPath), szHelpFile); if (!SUCCEEDED(hresult)) { return ; } if (FileExists(szHelpPath)) { //*STRSAFE* _tcscpy(g_szMUIHelpFilePath,szHelpPath);
hresult = StringCchCopy(g_szMUIHelpFilePath , ARRAYSIZE(g_szMUIHelpFilePath), szHelpPath); if (!SUCCEEDED(hresult)) { return ; } } } else { //*STRSAFE* _tcscpy(g_szMUIHelpFilePath,szHelpPath);
hresult = StringCchCopy(g_szMUIHelpFilePath , ARRAYSIZE(g_szMUIHelpFilePath), szHelpPath); if (!SUCCEEDED(hresult)) { return ; } } if(g_szMUIInfoFilePath[1] == TEXT(':')) { _tcsncpy(g_szVolumeRoot,g_szMUIInfoFilePath,3); g_szVolumeRoot[3]=TEXT('\0'); GetVolumeInformation(g_szVolumeRoot, g_szVolumeName, sizeof(g_szVolumeName)/sizeof(TCHAR), &g_dwVolumeSerialNo, 0, 0, 0, 0); } if (!GetPrivateProfileString( MUI_CDLAYOUT_SECTION, MUI_CDLABEL, TEXT(""), g_szCDLabel, MAX_PATH-1, g_szMUIInfoFilePath)) { LoadString(NULL, IDS_CHANGE_CDROM, g_szCDLabel, MAX_PATH-1); } }
//
// Set MUI installation source path from the instance that transfer control to this instance
//
void Set_SourcePath_FromForward(LPCTSTR lpszPath) { TCHAR szMUIPath[MAX_PATH+1]; int nidx=0;
if (!lpszPath) { return; } while (*lpszPath) { if (*lpszPath == MUI_FILLER_CHAR) { szMUIPath[nidx++]=TEXT(' '); } else { szMUIPath[nidx++]=*lpszPath; } lpszPath++; } szMUIPath[nidx]=TEXT('\0');
SetSourcePath(szMUIPath);
}
//
// Check if the version of current instance is older than that in %windir%\mui.
// If it's the case, then we transfer control to %windir%\mui\muisetup.
//
BOOL MUIShouldSwitchToNewVersion(LPTSTR lpszCommandLine) { BOOL bResult=FALSE;
TCHAR szTarget[ MAX_PATH+1 ]; HRESULT hresult;
ULONG ulHandle,ulBytes;
pfnGetWindowsDir(szTarget, MAX_PATH); //%windir% //
//*STRSAFE* _tcscat(szTarget, TEXT("\\"));
hresult = StringCchCat(szTarget , ARRAYSIZE(szTarget), TEXT("\\")); if (!SUCCEEDED(hresult)) { return bResult; } //*STRSAFE* _tcscat(szTarget, MUIDIR); // \MUI //
hresult = StringCchCat(szTarget , ARRAYSIZE(szTarget), MUIDIR); if (!SUCCEEDED(hresult)) { return bResult; } //*STRSAFE* _tcscat(szTarget, TEXT("\\"));
hresult = StringCchCat(szTarget , ARRAYSIZE(szTarget), TEXT("\\")); if (!SUCCEEDED(hresult)) { return bResult; } //*STRSAFE* _tcscat(szTarget,MUISETUP_EXECUTION_FILENAME);
hresult = StringCchCat(szTarget , ARRAYSIZE(szTarget), MUISETUP_EXECUTION_FILENAME); if (!SUCCEEDED(hresult)) { return bResult; } //
// If %windir%\mui\muisetup.exe doesn't exist or current muisetup.exe is launched from %windir%\mui then
// do nothing
//
if (!FileExists(szTarget) || !_tcsicmp(szTarget,g_szMuisetupPath)) { return bResult; } //
// If %windir%mui\muisetup.exe is not a execuatble then do nothing
//
ulBytes = GetFileVersionInfoSize( szTarget, &ulHandle );
if ( ulBytes == 0 ) return bResult;
//
// Compare the version stamp
//
// if version of g_szMuisetupPath (cuurent process) < %windir%\mui\muisetup
// then switch control to it
//
if (CompareMuisetupVersion(g_szMuisetupPath,szTarget)) { bResult = TRUE; MUI_TransferControlToNewVersion(szTarget,lpszCommandLine); } return bResult; } ////////////////////////////////////////////////////////////////////////////////////
//
// MUI_TransferControlToNewVersion
//
// Call %windir%\mui\muisetup.exe /$_transfer_$ mui_installation_file_path command_line
//
////////////////////////////////////////////////////////////////////////////////////
BOOL MUI_TransferControlToNewVersion(LPTSTR lpszExecutable,LPTSTR lpszCommandLine) {
STARTUPINFO si; PROCESS_INFORMATION pi; TCHAR szAppName[BUFFER_SIZE],szDropPath[MAX_PATH]; int nIdx,nLen; BOOL bResult=FALSE;
HRESULT hresult;
if (!lpszExecutable) { return bResult; } nLen=_tcslen(g_szMUISetupFolder);
for (nIdx=0; nIdx <nLen ; nIdx++) { if (g_szMUISetupFolder[nIdx]==TEXT(' ')) { szDropPath[nIdx]=MUI_FILLER_CHAR; } else { szDropPath[nIdx]=g_szMUISetupFolder[nIdx]; } } szDropPath[nIdx]=TEXT('\0');
//*STRSAFE* wsprintf(szAppName,TEXT("%s %s %s %s"),lpszExecutable,MUISETUP_FORWARDCALL_TAG,szDropPath,lpszCommandLine);
hresult = StringCchPrintf(szAppName , ARRAYSIZE(szAppName), TEXT("%s %s %s %s"),lpszExecutable,MUISETUP_FORWARDCALL_TAG,szDropPath,lpszCommandLine); if (!SUCCEEDED(hresult)) { return bResult; } //
// Run the process
//
memset( &si, 0x00, sizeof(si)); si.cb = sizeof(STARTUPINFO); if (!CreateProcess(NULL, szAppName, NULL, NULL, FALSE, 0L, NULL, NULL, &si, &pi) )
return bResult;
bResult =TRUE;
return bResult;
}
////////////////////////////////////////////////////////////////////////////////////
//
// CheckVolumeChange
//
// Make sure that MUI CD-ROM is put in the CD drive.
//
////////////////////////////////////////////////////////////////////////////////////
BOOL CheckVolumeChange() { BOOL bResult = FALSE; TCHAR szVolumeName[MAX_PATH],szCaption[MAX_PATH+1],szMsg[MAX_PATH+1],szMsg00[MAX_PATH+1],szMsg01[MAX_PATH+1]; DWORD dwVolumeSerialNo; BOOL bInit=TRUE; LONG_PTR lppArgs[3]; if( *g_szVolumeName && GetVolumeInformation(g_szVolumeRoot, szVolumeName, ARRAYSIZE(szVolumeName), &dwVolumeSerialNo, 0, 0, 0, 0) ) { while( lstrcmp(szVolumeName,g_szVolumeName) || (dwVolumeSerialNo != g_dwVolumeSerialNo) ) { if (bInit) { szCaption[0]=szMsg00[0]=szMsg01[0]=TEXT('\0'); LoadString(NULL, IDS_MAIN_TITLE, szCaption, MAX_PATH); lppArgs[0] = (LONG_PTR)g_szCDLabel; lppArgs[1] = (LONG_PTR)g_cdnumber; FormatStringFromResource(szMsg, ARRAYSIZE(szMsg), ghInstance, IDS_CHANGE_CDROM2, lppArgs); bInit=FALSE; } if (MESSAGEBOX(NULL, szMsg,szCaption, MB_YESNO | MB_ICONQUESTION) == IDNO) { return TRUE; } GetVolumeInformation(g_szVolumeRoot, szVolumeName, ARRAYSIZE(szVolumeName), &dwVolumeSerialNo, 0, 0, 0, 0); } } return bResult; } ////////////////////////////////////////////////////////////////////////////////////
//
// InitGlobals
//
// Initialize global variables
//
////////////////////////////////////////////////////////////////////////////////////
void InitGlobals(void) { // User UI Language Id
gUserUILangId = gpfnGetUserDefaultUILanguage(); gSystemUILangId = gpfnGetSystemDefaultUILanguage(); // System Windows directory
szWindowsDir[0] = TEXT('\0'); pfnGetWindowsDir(szWindowsDir, MAX_PATH); // Does this have admin privliges ?
gbIsWorkStation=CheckProductType(MUI_IS_WIN2K_PRO); gbIsServer= CheckProductType(MUI_IS_WIN2K_SERVER); gbIsAdvanceServer= (CheckProductType(MUI_IS_WIN2K_ADV_SERVER_OR_DATACENTER) || CheckProductType(MUI_IS_WIN2K_ENTERPRISE)); gbIsDataCenter=(CheckProductType(MUI_IS_WIN2K_DATACENTER) || CheckProductType(MUI_IS_WIN2K_DC_DATACENTER)); gbIsDomainController=CheckProductType(MUI_IS_WIN2K_DC); if (gbIsDomainController) { if ( (!gbIsWorkStation) && (!gbIsServer) && (!gbIsAdvanceServer)) { gbIsServer=TRUE; } } // Fill in system supported language groups
gpfnEnumSystemLanguageGroupsW(EnumLanguageGroupsProc, LGRPID_SUPPORTED, 0); pfnGetWindowsDir(g_szWinDir, sizeof(g_szWinDir)); g_AddLanguages[0]=TEXT('\0'); g_szVolumeName[0]=TEXT('\0'); g_szVolumeRoot[0]=TEXT('\0'); g_szMUIHelpFilePath[0]=TEXT('\0'); g_szCDLabel[0]=TEXT('\0'); g_dwVolumeSerialNo = 0; gNumLanguages=0; gNumLanguages_Install=0; gNumLanguages_Uninstall=0; g_InstallCancelled = FALSE; g_bRemoveDefaultUI=FALSE; g_cdnumber=0; g_pFileRenameTable=NULL; g_nFileRename=0; g_pNotFallBackTable=NULL; g_nNotFallBack=0; // Detect source path for installation
SetSourcePath(NULL); // Initialize the context for diamond FDI
Muisetup_InitDiamond(); // Get all installed UI languages
MUIGetAllInstalledUILanguages(); }
BOOL CALLBACK EnumLanguageGroupsProc( LGRPID LanguageGroup, // language group identifier
LPTSTR lpLanguageGroupString, // pointer to language group identifier string
LPTSTR lpLanguageGroupNameString, // pointer to language group name string
DWORD dwFlags, // flags
LONG_PTR lParam) // user-supplied parameter
{ gLanguageGroups[gNumLanguageGroups] = LanguageGroup; gNumLanguageGroups++; return TRUE; } ////////////////////////////////////////////////////////////////////////////////////
//
// Muisetup_Cleanup
//
// Muisetup cleanup code.
//
////////////////////////////////////////////////////////////////////////////////////
void Muisetup_Cleanup() { //
// Free userenv.dll, if needed
//
if (g_hUserEnvDll) { FreeLibrary(g_hUserEnvDll); } if (g_hAdvPackDll) { FreeLibrary(g_hAdvPackDll); } if (g_hSxSDll) { FreeLibrary(g_hSxSDll); } if (ghMutex) { CloseHandle(ghMutex); } // Free/release diamond DLL
Muisetup_FreeDiamond(); return; } ////////////////////////////////////////////////////////////////////////////////////
//
// OpenMuiKey
//
// Opens the Registry Key where installed languages are stored
//
////////////////////////////////////////////////////////////////////////////////////
HKEY OpenMuiKey(REGSAM samDesired) { DWORD dwDisposition; HKEY hKey; TCHAR lpSubKey[BUFFER_SIZE]; HRESULT hresult; //*STRSAFE* _tcscpy(lpSubKey, REG_MUI_PATH);
hresult = StringCchCopy(lpSubKey , ARRAYSIZE(lpSubKey), REG_MUI_PATH); if (!SUCCEEDED(hresult)) { return NULL; } if(RegCreateKeyEx(HKEY_LOCAL_MACHINE, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, samDesired, NULL, &hKey, &dwDisposition) != ERROR_SUCCESS) { hKey = NULL; } return hKey; } void DialogCleanUp(HWND hwndDlg) { HWND hList = GetDlgItem(hwndDlg, IDC_LIST1); int iCount = ListView_GetItemCount(hList); LVITEM lvItem; PMUILANGINFO pMuiLangInfo; while (iCount--) { lvItem.mask = LVIF_PARAM; lvItem.iItem = iCount; lvItem.iSubItem = 0; lvItem.state = 0; lvItem.stateMask = 0; lvItem.pszText = 0; lvItem.cchTextMax = 0; lvItem.iImage = 0; lvItem.lParam = 0; ListView_GetItem(hList, &lvItem); pMuiLangInfo = (PMUILANGINFO)lvItem.lParam; if (pMuiLangInfo) { if (pMuiLangInfo->lpszLcid) LocalFree(pMuiLangInfo->lpszLcid); LocalFree(pMuiLangInfo); } } } ////////////////////////////////////////////////////////////////////////////////////
//
// DialogFunc
//
// Callback function for main dialog (102)
//
////////////////////////////////////////////////////////////////////////////////////
INT_PTR CALLBACK DialogFunc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_INITDIALOG: SendMessage(hwndDlg, WM_SETICON , (WPARAM)ICON_BIG, (LPARAM)LoadIcon(ghInstance,MAKEINTRESOURCE(MUI_ICON))); SendMessage(hwndDlg, WM_SETICON , (WPARAM)ICON_SMALL, (LPARAM)LoadIcon(ghInstance,MAKEINTRESOURCE(MUI_ICON))); InitializeInstallDialog(hwndDlg, uMsg, wParam, lParam); return TRUE; case WM_HELP: { WinHelp( (HWND)((LPHELPINFO)lParam)->hItemHandle, g_szMUIHelpFilePath, HELP_WM_HELP, (DWORD_PTR)(LPTSTR)aMuisetupHelpIds ); break; } case WM_CONTEXTMENU: // right mouse click
{ WinHelp( (HWND)wParam, g_szMUIHelpFilePath, HELP_CONTEXTMENU, (DWORD_PTR)(LPTSTR)aMuisetupHelpIds ); break; } case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: EnableWindow(hwndDlg, FALSE); if (StartGUISetup(hwndDlg)) { EndDialog(hwndDlg, 0); } else { EnableWindow(hwndDlg, TRUE); SetFocus(hwndDlg); } return TRUE; case IDCANCEL: EndDialog(hwndDlg, 0); return TRUE; case IDC_DEF_UI_LANG_COMBO: switch(HIWORD(wParam)) { case CBN_SELCHANGE: UpdateCombo(hwndDlg); return TRUE; default: break; } break; case IDC_CHECK_LOCALE: if (BST_CHECKED == IsDlgButtonChecked( hwndDlg, IDC_CHECK_LOCALE)) { EnableWindow(GetDlgItem(hwndDlg, IDC_CHECK_UIFONT), TRUE); } else { CheckDlgButton(hwndDlg, IDC_CHECK_UIFONT, BST_UNCHECKED); EnableWindow(GetDlgItem(hwndDlg, IDC_CHECK_UIFONT), FALSE); } break; } //
// End of WM_COMMAND case
//
break; case WM_NOTIFY: switch (((NMHDR *)lParam)->code) { case(NM_CUSTOMDRAW): ListViewCustomDraw(hwndDlg, (LPNMLVCUSTOMDRAW)lParam); return TRUE; break; case (LVN_ITEMCHANGING): return ListViewChanging( hwndDlg, IDC_LIST1, (NM_LISTVIEW *)lParam); break; case (LVN_ITEMCHANGED) : ListViewChanged( hwndDlg, IDC_LIST1, (NM_LISTVIEW *)lParam ); break; default: return FALSE; } break; case WM_CLOSE: EndDialog(hwndDlg, 0); return TRUE; case WM_DESTROY: DialogCleanUp(hwndDlg); return TRUE; default: return FALSE; } return TRUE; } ////////////////////////////////////////////////////////////////////////////////////
//
// ListViewChanging
//
// Processing for a LVN_ITEMCHANGING message
//
////////////////////////////////////////////////////////////////////////////////////
BOOL ListViewChanging(HWND hDlg, int iID, NM_LISTVIEW *pLV) { HWND hwndLV = GetDlgItem(hDlg, iID); PMUILANGINFO pMuiLangInfo; //
// Make sure it's a state change message
//
if ((!(pLV->uChanged & LVIF_STATE)) || ((pLV->uNewState & 0x3000) == 0)) return FALSE; //
// Don't let the System Default be unchecked
//
GetMuiLangInfoFromListView(hwndLV, pLV->iItem, &pMuiLangInfo); if (MAKELCID(gSystemUILangId, SORT_DEFAULT) == pMuiLangInfo->lcid) return TRUE; return FALSE; } ////////////////////////////////////////////////////////////////////////////////////
//
// ListViewChanged
//
// Processing for a LVN_ITEMCHANGED message
//
////////////////////////////////////////////////////////////////////////////////////
BOOL ListViewChanged(HWND hDlg, int iID, NM_LISTVIEW *pLV) { HWND hwndLV = GetDlgItem(hDlg, iID); PMUILANGINFO pMuiLangInfo; int iCount; BOOL bChecked; //
// Make sure it's a state change message.
//
if ((!(pLV->uChanged & LVIF_STATE)) || ((pLV->uNewState & 0x3000) == 0)) { return (FALSE); } //
// Get the state of the check box for the currently selected item.
//
bChecked = ListView_GetCheckState(hwndLV, pLV->iItem) ? TRUE : FALSE; //
// Don't let the System Default or the current user UI language be unchecked
//
GetMuiLangInfoFromListView(hwndLV, pLV->iItem, &pMuiLangInfo); if (MAKELCID(gSystemUILangId, SORT_DEFAULT) == pMuiLangInfo->lcid) { //
// Set Default check state
//
if (bChecked == FALSE) { ListView_SetCheckState( hwndLV, pLV->iItem, TRUE ); } return FALSE; } //
// Deselect all items.
//
iCount = ListView_GetItemCount(hwndLV); while (iCount > 0) { iCount--; ListView_SetItemState( hwndLV, iCount, 0, LVIS_FOCUSED | LVIS_SELECTED ); } //
// Make sure this item is selected.
//
ListView_SetItemState( hwndLV, pLV->iItem, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED ); //
// Update the combo box
//
PostMessage( hDlg, WM_COMMAND, MAKEWPARAM(IDC_DEF_UI_LANG_COMBO, CBN_SELCHANGE), 0L); //
// Return success.
//
return (TRUE); } ////////////////////////////////////////////////////////////////////////////////////
//
// ListViewCustomDraw
//
// Processing for list view WM_CUSTOMDRAW notification.
//
////////////////////////////////////////////////////////////////////////////////////
void ListViewCustomDraw(HWND hDlg, LPNMLVCUSTOMDRAW pDraw) { HWND hwndLV = GetDlgItem(hDlg, IDC_LIST1); PMUILANGINFO pMuiLangInfo; //
// Tell the list view to notify me of item draws.
//
if (pDraw->nmcd.dwDrawStage == CDDS_PREPAINT) { SetWindowLongPtr(hDlg, DWLP_MSGRESULT, CDRF_NOTIFYITEMDRAW); return; } //
// Handle the Item Prepaint.
//
if (pDraw->nmcd.dwDrawStage & CDDS_ITEMPREPAINT) { //
// Check to see if the item being drawn is the system default or
// the current active ui language
//
GetMuiLangInfoFromListView(hwndLV, (int)pDraw->nmcd.dwItemSpec, &pMuiLangInfo); if (MAKELCID(gSystemUILangId, SORT_DEFAULT) == pMuiLangInfo->lcid) { pDraw->clrText = (GetSysColor(COLOR_GRAYTEXT)); } } //
// Do the default action.
//
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, CDRF_DODEFAULT); } ////////////////////////////////////////////////////////////////////////////////////
//
// StartGUISetup
//
// Creates dialog with progress bar for installation
//
////////////////////////////////////////////////////////////////////////////////////
BOOL StartGUISetup(HWND hwndDlg) { LONG_PTR lppArgs[3]; ULONG ulParam[2]; TCHAR lpMessage[BUFFER_SIZE]; TCHAR szBuf[BUFFER_SIZE]; INT64 ulSizeNeed,ulSizeAvailable; BOOL success; HWND hList; HWND hCombo; int iIndex; TCHAR lpAddLanguages[BUFFER_SIZE]; TCHAR lpRemoveLanguages[BUFFER_SIZE]; TCHAR lpDefaultUILang[BUFFER_SIZE]; TCHAR szPostParameter[BUFFER_SIZE]; int installLangCount; // The number of MUI languages to be installed
int uninstallLangCount; // The number of MUI langauges to be uninstalled.
LANGID langID; HRESULT hresult; INSTALL_LANG_GROUP installLangGroup; //
// (0) Check available disk space
//
if(!IsSpaceEnough(hwndDlg,&ulSizeNeed,&ulSizeAvailable)) { ulParam[0] = (ULONG) (ulSizeNeed/1024); ulParam[1] = (ULONG) (ulSizeAvailable/1024); LoadString(ghInstance, IDS_DISKSPACE_NOTENOUGH, lpMessage, ARRAYSIZE(lpMessage)-1); LoadString(ghInstance, IDS_ERROR_DISKSPACE, szBuf, ARRAYSIZE(szBuf)-1); FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, lpMessage, 0, 0, lpMessage, ARRAYSIZE(lpMessage)-1, (va_list *)ulParam); LogMessage(lpMessage); MESSAGEBOX(NULL, lpMessage, szBuf, MB_OK | MB_DEFBUTTON1 | MB_ICONWARNING); //
// Let User has another chance to reselect
//
return FALSE; } installLangGroup.bFontLinkRegistryTouched = FALSE; installLangGroup.NotDeleted = 0; //
// (1) Install Language Group First
//
ConvertMUILangToLangGroup(hwndDlg, &installLangGroup); hList=GetDlgItem(hwndDlg, IDC_LIST1); hCombo=GetDlgItem(hwndDlg, IDC_DEF_UI_LANG_COMBO); installLangCount = EnumSelectedLanguages(hList, lpAddLanguages); memmove(g_AddLanguages,lpAddLanguages,ARRAYSIZE(lpAddLanguages)); uninstallLangCount = EnumUnselectedLanguages(hList, lpRemoveLanguages); //
// Let's read the user's UI language selection,
// and then call the kernel to update the registry.
//
hList = GetDlgItem(hwndDlg, IDC_LIST1); hCombo = GetDlgItem(hwndDlg, IDC_DEF_UI_LANG_COMBO); iIndex = (int)SendMessage(hCombo, CB_GETCURSEL, 0, 0); if (iIndex == CB_ERR) { return FALSE; } langID = LANGIDFROMLCID((LCID) SendMessage(hCombo, CB_GETITEMDATA, iIndex, 0L)); //*STRSAFE* wsprintf(lpDefaultUILang, TEXT("%X"), langID);
hresult = StringCchPrintf(lpDefaultUILang , ARRAYSIZE(lpDefaultUILang), TEXT("%X"), langID); if (!SUCCEEDED(hresult)) { return FALSE; } DEBUGMSGBOX(NULL, TEXT("About to do setup"), NULL, MB_OK); success = DoSetup( hwndDlg, uninstallLangCount, lpRemoveLanguages, installLangGroup, installLangCount, lpAddLanguages, g_bLipLanguages? lpAddLanguages:lpDefaultUILang, TRUE, TRUE, TRUE); return (success); } ////////////////////////////////////////////////////////////////////////////////////
//
// ProgressDialogFunc
//
// Callback function for progresss dialog
//
////////////////////////////////////////////////////////////////////////////////////
INT_PTR CALLBACK ProgressDialogFunc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_INITDIALOG: return TRUE; case WM_COMMAND: switch (LOWORD(wParam)) { case IDCANCEL: EndDialog(hwndDlg, 0); return TRUE; } break; case WM_CLOSE: EndDialog(hwndDlg, 0); return TRUE; case WM_DESTROY: EndDialog(hwndDlg, 0); return TRUE; default: return FALSE; } return TRUE; } ////////////////////////////////////////////////////////////////////////////////////
//
// InitializeInstallDialog
//
// Sets contents of list view and combo box in installation dialog
//
////////////////////////////////////////////////////////////////////////////////////
BOOL InitializeInstallDialog(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { HWND hList, hCombo; PTSTR lpLanguages; TCHAR tchBuffer[BUFFER_SIZE]; TCHAR lpDefaultSystemLanguage[BUFFER_SIZE],lpUILanguage[BUFFER_SIZE]; TCHAR lpMessage[BUFFER_SIZE]; int iIndex; int iChkIndex,iCnt,iMUIDirectories=0; HRESULT hresult; lpLanguages = tchBuffer; SetWindowTitleFromResource(hwndDlg, IDS_MAIN_TITLE); hList = GetDlgItem(hwndDlg, IDC_LIST1); hCombo=GetDlgItem(hwndDlg, IDC_DEF_UI_LANG_COMBO); InitializeListView(hList); //
// Insert the default system language in the list view
//
//*STRSAFE* _stprintf(lpDefaultSystemLanguage, TEXT("%04x"), gSystemUILangId);
hresult = StringCchPrintf(lpDefaultSystemLanguage , ARRAYSIZE(lpDefaultSystemLanguage), TEXT("%04x"), gSystemUILangId); if (!SUCCEEDED(hresult)) { return FALSE; } iIndex=InsertLanguageInListView(hList, lpDefaultSystemLanguage, TRUE); //
// Insert the languages in MUI.INF in the list view
//
if ( ( (iMUIDirectories =EnumLanguages(lpLanguages)) == 0) && (g_UILanguageGroup.iCount == 0 ) ) { //
// No languages found in MUI.INF
//
LoadString(ghInstance, IDS_NO_LANG_L, lpMessage, ARRAYSIZE(lpMessage)-1); LogMessage(lpMessage); return FALSE; } while (*lpLanguages != TEXT('\0')) { if (CheckLanguageIsQualified(lpLanguages)) { InsertLanguageInListView(hList, lpLanguages, FALSE); } lpLanguages = _tcschr(lpLanguages, '\0'); lpLanguages++; } //
// We should also check all installed UI languages
//
for (iCnt=0; iCnt<g_UILanguageGroup.iCount; iCnt++) { if (!GetLcidItemIndexFromListView(hList, g_UILanguageGroup.lcid[iCnt], &iChkIndex)) { //*STRSAFE* _stprintf(lpUILanguage, TEXT("%04x"), g_UILanguageGroup.lcid[iCnt]);
hresult = StringCchPrintf(lpUILanguage , ARRAYSIZE(lpUILanguage), TEXT("%04x"), g_UILanguageGroup.lcid[iCnt]); if (!SUCCEEDED(hresult)) { return FALSE; } if (CheckLanguageIsQualified(lpUILanguage)) { InsertLanguageInListView(hList, lpUILanguage, FALSE); } } } //
// Let's detect which language groups are installed
//
DetectLanguageGroups(hwndDlg); SelectInstalledLanguages(hList); SetDefault(hCombo); //
// Deselect all items.
//
iIndex = ListView_GetItemCount(hList); while (iIndex > 0) { iIndex--; ListView_SetItemState( hList, iIndex, 0, LVIS_FOCUSED | LVIS_SELECTED ); } //
// Select the first one in the list.
//
ListView_SetItemState( hList, 0, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED ); //
// Match system locale with the default UI language
//
if (CheckMUIRegSetting(MUI_MATCH_LOCALE)) { CheckDlgButton(hwndDlg, IDC_CHECK_LOCALE, BST_CHECKED); //
// Match UI font with the default UI language
//
if (g_bMatchUIFont = CheckMUIRegSetting(MUI_MATCH_UIFONT)) { CheckDlgButton(hwndDlg, IDC_CHECK_UIFONT, BST_CHECKED); } } else { SetMUIRegSetting(MUI_MATCH_UIFONT, FALSE); EnableWindow(GetDlgItem(hwndDlg, IDC_CHECK_UIFONT), FALSE); } return TRUE; } ////////////////////////////////////////////////////////////////////////////////////
//
// CheckForUsingCountryName
//
// Fetch MUIINF file if the selected UI lang needs to be displayed as a language
// name or a country name.
//
////////////////////////////////////////////////////////////////////////////////////
BOOL CheckForUsingCountryName(PMUILANGINFO pMuiLangInfo) { TCHAR szSource[MAX_PATH]; szSource[0] = TEXT('\0'); //
// Try check if there is a value for it under [UseCountryName]
//
GetPrivateProfileString( MUI_COUNTRYNAME_SECTION, pMuiLangInfo->lpszLcid, TEXT(""), szSource, MAX_PATH, g_szMUIInfoFilePath); if (szSource[0] == TEXT('1')) { return (TRUE); } return (FALSE); } ////////////////////////////////////////////////////////////////////////////////////
//
// GetDisplayName
//
// Fetch MUIINF file if the selected UI lang needs to be displayed using the
// name specified in [LanguageDisplayName] section of mui.inf.
// Otherwise, get the display name according to the values in [UseCountryName].
// If the value for the specified LCID is 1, use the country name. Otherwise,
// use the locale name.
//
////////////////////////////////////////////////////////////////////////////////////
BOOL GetDisplayName(PMUILANGINFO pMuiLangInfo) { //
// Try check if there is a customized display name for the specified LCID under [LanguageDisplayName].
//
pMuiLangInfo->szDisplayName[0] = L'\0'; if (pMuiLangInfo->lpszLcid) { GetPrivateProfileString( MUI_DISPLAYNAME_SECTION, pMuiLangInfo->lpszLcid, TEXT(""), pMuiLangInfo->szDisplayName, MAX_PATH, g_szMUIInfoFilePath); } if (pMuiLangInfo->szDisplayName[0] == L'\0') { //
// There is no entry in [LanguageDisplayName]. Use the country name or locale name.
//
Muisetup_GetLocaleLanguageInfo( pMuiLangInfo->lcid, pMuiLangInfo->szDisplayName, ARRAYSIZE(pMuiLangInfo->szDisplayName)-1, CheckForUsingCountryName(pMuiLangInfo)); } return TRUE; } ////////////////////////////////////////////////////////////////////////////////////
//
// GetLanguageGroupDisplayName
// Get language group display name for MUI install/uninstall dialog
//
////////////////////////////////////////////////////////////////////////////////////
BOOL GetLanguageGroupDisplayName(LANGID LangId, LPTSTR lpBuffer, int nSize) { BOOL bRet = FALSE; MUILANGINFO MuiLangInfo = {0}; HRESULT hresult; if ( (!lpBuffer) || (nSize == 0)) { return bRet; } MuiLangInfo.lcid = MAKELCID(LangId, SORT_DEFAULT); MuiLangInfo.lgrpid = GetLanguageGroup(MuiLangInfo.lcid); if (GetDisplayName(&MuiLangInfo) && nSize >= lstrlen(MuiLangInfo.szDisplayName)) { //*STRSAFE* lstrcpy(lpBuffer, MuiLangInfo.szDisplayName);
hresult = StringCchCopy(lpBuffer , nSize, MuiLangInfo.szDisplayName); if (!SUCCEEDED(hresult)) { return bRet; } bRet = TRUE; } return bRet; } ////////////////////////////////////////////////////////////////////////////////////
//
// Get UI, IE and LPK files size for the lcid
//
////////////////////////////////////////////////////////////////////////////////////
BOOL GetUIFileSize(PMUILANGINFO pMuiLangInfo) { TCHAR szSize[MAX_PATH]; int nCD; pMuiLangInfo->ulUISize = 0; pMuiLangInfo->ulLPKSize = 0; #if defined(_IA64_)
BOOL bIA64 = TRUE; #else
BOOL bIA64 = FALSE; #endif
if (!pMuiLangInfo) { return FALSE; } szSize[0] = TEXT('\0'); //
// Try to get UI files size under [FileSize_UI]
//
if (GetPrivateProfileString( bIA64? MUI_UIFILESIZE_SECTION_IA64 : MUI_UIFILESIZE_SECTION, pMuiLangInfo->lpszLcid, TEXT(""), szSize, MAX_PATH, g_szMUIInfoFilePath)) { pMuiLangInfo->ulUISize =_wtoi64(szSize); } szSize[0] = TEXT('\0'); //
// Try to get LPK files size under [FileSize_LPK]
//
if (GetPrivateProfileString( bIA64? MUI_LPKFILESIZE_SECTION_IA64 : MUI_LPKFILESIZE_SECTION, pMuiLangInfo->lpszLcid, TEXT(""), szSize, MAX_PATH, g_szMUIInfoFilePath)) { pMuiLangInfo->ulLPKSize =_wtoi64(szSize); } //
// Try to get CD # under [CD_LAYOUT]
//
nCD=GetPrivateProfileInt(bIA64? MUI_CDLAYOUT_SECTION_IA64 : MUI_CDLAYOUT_SECTION, pMuiLangInfo->lpszLcid, 0, g_szMUIInfoFilePath); if (nCD) { pMuiLangInfo->cd_number = nCD; if (g_cdnumber == 0) { g_cdnumber = pMuiLangInfo->cd_number; } } else { pMuiLangInfo->cd_number = DEFAULT_CD_NUMBER; } return TRUE; } BOOL GetUIFileSize_commandline(LPTSTR lpszLcid, INT64 *ulUISize,INT64 *ulLPKSize) { TCHAR szSize[MAX_PATH]; *ulUISize = 0; *ulLPKSize = 0; #if defined(_IA64_)
BOOL bIA64 = TRUE; #else
BOOL bIA64 = FALSE; #endif
if ( (!lpszLcid) || (!ulUISize) || (!ulLPKSize)) { return FALSE; } szSize[0] = TEXT('\0'); //
// Try to get UI files size under [FileSize_UI]
//
if (GetPrivateProfileString( bIA64? MUI_UIFILESIZE_SECTION_IA64 : MUI_UIFILESIZE_SECTION, lpszLcid, TEXT(""), szSize, MAX_PATH, g_szMUIInfoFilePath)) { *ulUISize =_wtoi64(szSize); } szSize[0] = TEXT('\0'); //
// Try to get LPK files size under [FileSize_LPK]
//
if (GetPrivateProfileString( bIA64? MUI_LPKFILESIZE_SECTION_IA64 : MUI_LPKFILESIZE_SECTION, lpszLcid, TEXT(""), szSize, MAX_PATH, g_szMUIInfoFilePath)) { *ulLPKSize =_wtoi64(szSize); } // Try to get CD # under [CD_LAYOUT]
//
if (g_cdnumber == 0) { g_cdnumber=GetPrivateProfileInt( bIA64? MUI_CDLAYOUT_SECTION_IA64 : MUI_CDLAYOUT_SECTION, lpszLcid, 0, g_szMUIInfoFilePath); } return TRUE; } ////////////////////////////////////////////////////////////////////////////////////
//
// InitializeListView
//
// Gets the list view ready for inserting items
//
////////////////////////////////////////////////////////////////////////////////////
BOOL InitializeListView(HWND hList) { DWORD dwExStyle; LV_COLUMN Column; RECT Rect; GetClientRect(hList, &Rect); Column.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; Column.fmt = LVCFMT_LEFT; Column.cx = Rect.right - GetSystemMetrics(SM_CYHSCROLL); Column.pszText = NULL; Column.cchTextMax = 0; Column.iSubItem = 0; ListView_InsertColumn(hList, 0, &Column); dwExStyle = ListView_GetExtendedListViewStyle(hList); ListView_SetExtendedListViewStyle(hList, dwExStyle | LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT); return TRUE; } ////////////////////////////////////////////////////////////////////////////////////
//
//
// Check if specified language can install on the target machine.
// I.E. Arabic, Turkish, Greek and Hebrew MUI can only install on NT Workstation;
// They are not allowed on NT Server
//
////////////////////////////////////////////////////////////////////////////////////
BOOL CheckLanguageIsQualified(LPTSTR lpLanguage) { #ifdef XCHECK_LANGUAGE_FOR_PLATFORM
BOOL bResult = FALSE; LANGID LgLang;
if (!lpLanguage) { return bResult; } LgLang = (LANGID)_tcstol(lpLanguage, NULL, 16); LgLang = PRIMARYLANGID(LgLang); if(gbIsAdvanceServer) { if (LgLang == LANG_GERMAN || LgLang == LANG_FRENCH || LgLang == LANG_SPANISH || LgLang == LANG_JAPANESE || LgLang == LANG_KOREAN || LgLang == LANG_CHINESE) { bResult = TRUE; } } else if(gbIsServer) { if (LgLang == LANG_GERMAN || LgLang == LANG_FRENCH || LgLang == LANG_SPANISH || LgLang == LANG_JAPANESE || LgLang == LANG_KOREAN || LgLang == LANG_CHINESE || LgLang == LANG_SWEDISH || LgLang == LANG_ITALIAN || LgLang == LANG_DUTCH || LgLang == LANG_PORTUGUESE || LgLang == LANG_CZECH || LgLang == LANG_HUNGARIAN || LgLang == LANG_POLISH || LgLang == LANG_RUSSIAN || LgLang == LANG_TURKISH) { bResult = TRUE; } } else if(gbIsWorkStation) { bResult = TRUE; } return bResult; #else
return TRUE; #endif
} ////////////////////////////////////////////////////////////////////////////////////
//
// InsertLanguageInListView
//
// Returns the index of the item in the list view after inserting it.
//
////////////////////////////////////////////////////////////////////////////////////
int InsertLanguageInListView(HWND hList, LPTSTR lpLanguage, BOOL bCheckState) { LANGID LgLang; LV_ITEM lvItem; PMUILANGINFO pMuiLangInfo; int iIndex; HRESULT hresult;
if (!lpLanguage) { return -1; } lvItem.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE | LVIF_IMAGE; lvItem.iItem = 0; lvItem.iSubItem = 0; lvItem.state = 0; lvItem.stateMask = LVIS_STATEIMAGEMASK; lvItem.cchTextMax = 0; lvItem.iImage = 0; //
// Allocate enough space to hold pszLcid and MUILANGINFO
//
pMuiLangInfo = (PMUILANGINFO) LocalAlloc(LPTR, sizeof(MUILANGINFO)); if (pMuiLangInfo == NULL) { ExitFromOutOfMemory(); } else { pMuiLangInfo->lpszLcid = (LPTSTR) LocalAlloc(LMEM_FIXED, (_tcslen(lpLanguage) + 1) * sizeof(TCHAR)); } if (pMuiLangInfo->lpszLcid == NULL) { ExitFromOutOfMemory(); } else { //
// Init pszLcid
//
lvItem.lParam = (LPARAM)pMuiLangInfo; //*STRSAFE* _tcscpy((LPTSTR)pMuiLangInfo->lpszLcid, lpLanguage);
hresult = StringCchCopy((LPTSTR)pMuiLangInfo->lpszLcid ,_tcslen(lpLanguage) + 1 , lpLanguage); if (!SUCCEEDED(hresult)) { return -1; } } //
// Init lcid
//
LgLang = (LANGID)_tcstol(lpLanguage, NULL, 16); pMuiLangInfo->lcid = MAKELCID(LgLang, SORT_DEFAULT); if (pMuiLangInfo->szDisplayName[0] == L'\0') { GetDisplayName(pMuiLangInfo); } lvItem.pszText = pMuiLangInfo->szDisplayName; GetUIFileSize(pMuiLangInfo); iIndex = ListView_InsertItem(hList, &lvItem); if (iIndex >= 0) { ListView_SetCheckState(hList, iIndex, bCheckState); } return iIndex; } ////////////////////////////////////////////////////////////////////////////////////
//
// GetMuiLangInfoFromListView
//
// Get the MuiLangInfo of the corresponding ListView Item
//
////////////////////////////////////////////////////////////////////////////////////
BOOL GetMuiLangInfoFromListView(HWND hList, int i, PMUILANGINFO *ppMuiLangInfo) { LVITEM lvItem;
if (!ppMuiLangInfo) { return FALSE; } //
// Check if Language Group is installed
//
lvItem.mask = LVIF_PARAM; lvItem.iItem = i; lvItem.iSubItem = 0; lvItem.state = 0; lvItem.stateMask = 0; lvItem.pszText = 0; lvItem.cchTextMax = 0; lvItem.iImage = 0; lvItem.lParam = 0; ListView_GetItem(hList, &lvItem); *ppMuiLangInfo = (PMUILANGINFO)lvItem.lParam; return TRUE; } ////////////////////////////////////////////////////////////////////////////////////
//
// Muisetup_GetLocaleLanguageInfo
//
// Read the locale info of the language or country name.
//
////////////////////////////////////////////////////////////////////////////////////
int Muisetup_GetLocaleLanguageInfo(LCID lcid, PTSTR pBuf, int iLen, BOOL fUseCountryName) { TCHAR tchBuf[ MAX_PATH ] ; int iRet; HRESULT hresult;
if ( (!pBuf) || (iLen == 0)) { return 0; } //
// If this is either 0x0404 or 0x0804, then mark them specially
//
if (0x0404 == lcid) { iRet = LoadString(ghInstance, IDS_MUI_CHT, pBuf, iLen); } else if (0x0804 == lcid) { iRet = LoadString(ghInstance, IDS_MUI_CHS, pBuf, iLen); } else { iRet = GetLocaleInfo( lcid, LOCALE_SENGLANGUAGE, pBuf, iLen); if (fUseCountryName) { iRet = GetLocaleInfo( lcid, LOCALE_SENGCOUNTRY, tchBuf, (sizeof(tchBuf)/sizeof(TCHAR))); if (iRet) { //*STRSAFE* _tcscat(pBuf, TEXT(" ("));
hresult = StringCchCat(pBuf , iLen, TEXT(" (")); if (!SUCCEEDED(hresult)) { return 0; } //*STRSAFE* _tcscat(pBuf, tchBuf);
hresult = StringCchCat(pBuf , iLen, tchBuf); if (!SUCCEEDED(hresult)) { return 0; } //*STRSAFE* _tcscat(pBuf, TEXT(")"));
hresult = StringCchCat(pBuf , iLen, TEXT(")")); if (!SUCCEEDED(hresult)) { return 0; } } } } return iRet; } ////////////////////////////////////////////////////////////////////////////////////
//
// GetLcidFromComboBox
//
// Retreives the index of the combo box item that corresponds to this UI Language
//
////////////////////////////////////////////////////////////////////////////////////
BOOL GetLcidFromComboBox(HWND hCombo, LCID lcid, int *piIndex) { LCID ItemLcid; int i; int iCount = (int)SendMessage(hCombo, CB_GETCOUNT, 0L, 0L); if (!piIndex) { return FALSE; } if (CB_ERR != iCount) { i = 0; while (i < iCount) { ItemLcid = (LCID)SendMessage(hCombo, CB_GETITEMDATA, (WPARAM)i, (LPARAM)0); if ((CB_ERR != ItemLcid) && (ItemLcid == lcid)) { *piIndex = i; return TRUE; } i++; } } return FALSE; } ////////////////////////////////////////////////////////////////////////////////////
//
// GetMuiLangInfoFromListView
//
// Retreives the index of the listview item that corresponds to this UI Language
//
////////////////////////////////////////////////////////////////////////////////////
BOOL GetLcidItemIndexFromListView(HWND hList, LCID lcid, int *piIndex) { int iCount = ListView_GetItemCount(hList); int i; PMUILANGINFO pMuiLangInfo; LVITEM lvItem; if (!piIndex) { return FALSE; } i = 0; while (i < iCount) { //
// Check if Language Group is installed
//
lvItem.mask = LVIF_PARAM; lvItem.iItem = i; lvItem.iSubItem = 0; lvItem.state = 0; lvItem.stateMask = 0; lvItem.pszText = 0; lvItem.cchTextMax = 0; lvItem.iImage = 0; lvItem.lParam = 0; ListView_GetItem(hList, &lvItem); pMuiLangInfo = (PMUILANGINFO)lvItem.lParam; if (pMuiLangInfo->lcid == lcid) { *piIndex = i; return TRUE; } i++; } return FALSE; } ////////////////////////////////////////////////////////////////////////////////////
//
// SelectInstalledLanguages
//
// Sets the list view check state for insalled languages
//
// TODO: We should perhaps use the MSI to check for installed packages instead...
////////////////////////////////////////////////////////////////////////////////////
BOOL SelectInstalledLanguages(HWND hList) { DWORD dwData; DWORD dwIndex; DWORD dwValue; HKEY hKey; LANGID LgLang; LONG rc; TCHAR lpItemString[BUFFER_SIZE]; TCHAR szData[BUFFER_SIZE]; TCHAR szValue[BUFFER_SIZE]; int iIndex; int nLvIndex; if (hKey = OpenMuiKey(KEY_READ)) { dwIndex = 0; rc = ERROR_SUCCESS; iIndex = ListView_GetItemCount(hList); while(rc==ERROR_SUCCESS) { dwValue=sizeof(szValue)/sizeof(TCHAR); szValue[0]=TEXT('\0'); dwData = sizeof(szData); szData[0] = TEXT('\0'); DWORD dwType; rc = RegEnumValue(hKey, dwIndex, szValue, &dwValue, 0, &dwType, (LPBYTE)szData, &dwData); if (rc == ERROR_SUCCESS) { if (dwType != REG_SZ) { dwIndex++; continue; } LgLang=(WORD)_tcstol(szValue, NULL, 16); if (GetLcidItemIndexFromListView(hList, MAKELCID(LgLang, SORT_DEFAULT), &nLvIndex)) { ListView_SetCheckState(hList, nLvIndex, TRUE); } } dwIndex++; } RegCloseKey(hKey); return TRUE; } return FALSE; } ////////////////////////////////////////////////////////////////////////////////////
//
// UpdateCombo
//
// Updates the combo box to correspond to the languages selected in the list view
//
////////////////////////////////////////////////////////////////////////////////////
BOOL UpdateCombo(HWND hwndDlg) { BOOL bDefaultSet=FALSE; HWND hCombo; HWND hList; TCHAR lpBuffer[BUFFER_SIZE]; TCHAR lpSystemDefault[BUFFER_SIZE]; int i; int iIndex; int iLbIndex; int iListIndex; WPARAM iPrevDefault; LCID lcidPrev; PMUILANGINFO pMuiLangInfo; hList = GetDlgItem(hwndDlg, IDC_LIST1); hCombo = GetDlgItem(hwndDlg, IDC_DEF_UI_LANG_COMBO); //
// If the Previous Default is still selected, keep it as the default
//
iPrevDefault = SendMessage(hCombo, CB_GETCURSEL, 0, 0); if (iPrevDefault == CB_ERR) return FALSE; lcidPrev = (LCID) SendMessage(hCombo, CB_GETITEMDATA, (WPARAM)iPrevDefault, 0); //
// Get the text of the currently selected default
//
GetLcidItemIndexFromListView(hList, lcidPrev, &iLbIndex); SendMessage(hCombo, CB_RESETCONTENT, 0, 0); iIndex = ListView_GetItemCount(hList); iListIndex = 0; //
// See if we can preserve the default.
//
i = 0; while (i < iIndex) { if (ListView_GetCheckState(hList, i)) { ListView_GetItemText(hList, i, 0, lpBuffer, ARRAYSIZE(lpBuffer)-1); iListIndex = (int) SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM)(LPTSTR)lpBuffer); if (CB_ERR != iListIndex) { GetMuiLangInfoFromListView(hList, i, &pMuiLangInfo); SendMessage(hCombo, CB_SETITEMDATA, iListIndex, (LPARAM)(LCID)pMuiLangInfo->lcid); if (pMuiLangInfo->lcid == lcidPrev) { SendMessage(hCombo, CB_SETCURSEL, (WPARAM)iListIndex, 0); bDefaultSet = TRUE; } } } i++; } //
// If no default, force the system default.
//
if (!bDefaultSet) { lcidPrev = MAKELCID(gSystemUILangId, SORT_DEFAULT); if (!GetLcidFromComboBox(hCombo, lcidPrev, &iIndex)) { GetLocaleInfo(lcidPrev, LOCALE_SENGLANGUAGE, lpSystemDefault, ARRAYSIZE(lpSystemDefault)-1); iIndex = (int) SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM)lpSystemDefault); SendMessage(hCombo, CB_SETITEMDATA, (WPARAM)iIndex, (LPARAM)(LCID)lcidPrev); } SendMessage(hCombo, CB_SETCURSEL, (WPARAM)iIndex, 0); } return TRUE; } ////////////////////////////////////////////////////////////////////////////////////
//
// SetDefault
//
// Sets the default user setting in the combo box
//
////////////////////////////////////////////////////////////////////////////////////
BOOL SetDefault(HWND hCombo) { int iIndex; TCHAR lpBuffer[BUFFER_SIZE]; LCID lcid = MAKELCID(GetDotDefaultUILanguage(), SORT_DEFAULT); GetLocaleInfo(lcid, LOCALE_SENGLANGUAGE, lpBuffer, ARRAYSIZE(lpBuffer)-1); iIndex = (int)SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM)lpBuffer); if (CB_ERR != iIndex) { SendMessage(hCombo, CB_SETITEMDATA, (WPARAM)iIndex, (LPARAM)(DWORD) lcid); SendMessage(hCombo, CB_SETCURSEL, (WPARAM)iIndex, 0); } return TRUE; } ////////////////////////////////////////////////////////////////////////////////////
//
// SetUserDefaultLanguage
//
// Sets the default language in the registry
//
////////////////////////////////////////////////////////////////////////////////////
BOOL SetUserDefaultLanguage(LANGID langID, BOOL bApplyCurrentUser, BOOL bApplyAllUsers) { TCHAR szCommands[BUFFER_SIZE]; TCHAR szBuf[BUFFER_SIZE]; BOOL success; LONG_PTR lppArgs[2]; HRESULT hresult; //
// Set the UI language now
//
// status = gpfnNtSetDefaultUILanguage(LANGIDFROMLCID(langID));
szCommands[0] = TEXT('\0'); if (bApplyCurrentUser) { // E.g. MUILanguage = "0411".
//*STRSAFE* wsprintf(szCommands, TEXT("MUILanguage=\"%x\"\n"), langID);
hresult = StringCchPrintf(szCommands , ARRAYSIZE(szCommands), TEXT("MUILanguage=\"%x\"\n"), langID); if (!SUCCEEDED(hresult)) { return FALSE; } } if (bApplyAllUsers) { //*STRSAFE* wsprintf(szBuf, TEXT("MUILanguage_DefaultUser = \"%x\""), langID);
hresult = StringCchPrintf(szBuf , ARRAYSIZE(szBuf), TEXT("MUILanguage_DefaultUser = \"%x\""), langID); if (!SUCCEEDED(hresult)) { return FALSE; } //*STRSAFE* _tcscat(szCommands, szBuf);
hresult = StringCchCat(szCommands , ARRAYSIZE(szCommands), szBuf); if (!SUCCEEDED(hresult)) { return FALSE; } } success = RunRegionalOptionsApplet(szCommands); lppArgs[0] = langID; if (success) { if (bApplyCurrentUser) { LogFormattedMessage(NULL, IDS_SET_UILANG_CURRENT, lppArgs); } if (bApplyAllUsers) { LogFormattedMessage(NULL, IDS_SET_UILANG_ALLUSERS, lppArgs); } } else { if (bApplyCurrentUser) { LogFormattedMessage(NULL, IDS_ERROR_SET_UILANG_CURRENT, lppArgs); } if (bApplyAllUsers) { LogFormattedMessage(NULL, IDS_ERROR_SET_UILANG_ALLUSERS, lppArgs); } } return (success); } ////////////////////////////////////////////////////////////////////////////////////
//
// GetDotDefaultUILanguage
//
// Retrieve the UI language stored in the HKCU\.Default.
// This is the default UI language for new users.
//
////////////////////////////////////////////////////////////////////////////////////
LANGID GetDotDefaultUILanguage() { HKEY hKey; DWORD dwKeyType; DWORD dwSize; BOOL success = FALSE; TCHAR szBuffer[BUFFER_SIZE]; LANGID langID; //
// Get the value in .DEFAULT.
//
if (RegOpenKeyEx( HKEY_USERS, TEXT(".DEFAULT\\Control Panel\\Desktop"), 0L, KEY_READ, &hKey ) == ERROR_SUCCESS) { dwSize = sizeof(szBuffer); if (RegQueryValueEx( hKey, TEXT("MultiUILanguageId"), 0L, &dwKeyType, (LPBYTE)szBuffer, &dwSize) == ERROR_SUCCESS) { if (dwKeyType == REG_SZ) { langID = (LANGID)_tcstol(szBuffer, NULL, 16); success = TRUE; } } RegCloseKey(hKey); }
// here, check to see if the key is actually meaningful, if not, return SystemDefaultUILanguage
if (success && (!IsInstalled(szBuffer))) { success = FALSE; } if (!success) { langID = GetSystemDefaultUILanguage(); } return (langID); } ////////////////////////////////////////////////////////////////////////////////////
//
// CheckLangGroupCommandLine
//
// Command line version of CheckSupport
//
////////////////////////////////////////////////////////////////////////////////////
BOOL CheckLangGroupCommandLine(PINSTALL_LANG_GROUP pInstallLangGroup, LPTSTR lpArg) { int i = 0; int iArg; LGRPID lgrpid;
if ( (!pInstallLangGroup) || (!lpArg)) { return FALSE; } iArg = _tcstol(lpArg, NULL, 16); //
// See if the lang group for this MUI lang is installed or not
//
lgrpid = GetLanguageGroup(MAKELCID(iArg, SORT_DEFAULT)); if (AddMUILangGroup(pInstallLangGroup, lgrpid)) { return TRUE; } return FALSE; } ////////////////////////////////////////////////////////////////////////////////////
//
// SetWindowTitleFromResource
//
// Set the window title using the specified resource string ID.
//
////////////////////////////////////////////////////////////////////////////////////
void SetWindowTitleFromResource(HWND hwnd, int resourceID) { TCHAR szBuffer[BUFFER_SIZE]; LoadString(NULL, resourceID, szBuffer, sizeof(szBuffer)/sizeof(TCHAR)); SetWindowText(hwnd, szBuffer); }
BOOL RemoveFileReadOnlyAttribute(LPTSTR lpszFileName) { BOOL bResult = FALSE; DWORD dwAttrib; if (! lpszFileName) { return bResult; } dwAttrib = GetFileAttributes (lpszFileName); if ( dwAttrib & FILE_ATTRIBUTE_READONLY ) { dwAttrib &= ~FILE_ATTRIBUTE_READONLY; SetFileAttributes (lpszFileName, dwAttrib); bResult=TRUE; } return bResult; } BOOL MUI_DeleteFile(LPTSTR lpszFileName) { if (!lpszFileName) { return FALSE; } RemoveFileReadOnlyAttribute(lpszFileName); return DeleteFile(lpszFileName); }
BOOL DeleteSideBySideMUIAssemblyIfExisted(LPTSTR Languages, TCHAR pszLogFile[BUFFER_SIZE]) { HRESULT hresult; if (!Languages) { return FALSE; } //*STRSAFE* lstrcpy(pszLogFile, g_szWinDir); // c:\windows
hresult = StringCchCopy(pszLogFile , BUFFER_SIZE, g_szWinDir); if (!SUCCEEDED(hresult)) { return FALSE; } //*STRSAFE* lstrcat(pszLogFile, MUISETUP_PATH_SEPARATOR); // c:\windows
hresult = StringCchCat(pszLogFile , BUFFER_SIZE, MUISETUP_PATH_SEPARATOR); if (!SUCCEEDED(hresult)) { return FALSE; } //*STRSAFE* lstrcat(pszLogFile, MUIDIR); // c:\windows\mui
hresult = StringCchCat(pszLogFile , BUFFER_SIZE, MUIDIR); if (!SUCCEEDED(hresult)) { return FALSE; } //*STRSAFE* lstrcat(pszLogFile, MUISETUP_PATH_SEPARATOR); // c:\windows\mui
hresult = StringCchCat(pszLogFile , BUFFER_SIZE, MUISETUP_PATH_SEPARATOR); if (!SUCCEEDED(hresult)) { return FALSE; } //*STRSAFE* lstrcat(pszLogFile, MUISETUP_ASSEMBLY_INSTALLATION_LOG_FILENAME); // c:\windows\mui\muisetup.log.
hresult = StringCchCat(pszLogFile , BUFFER_SIZE, MUISETUP_ASSEMBLY_INSTALLATION_LOG_FILENAME); if (!SUCCEEDED(hresult)) { return FALSE; } //*STRSAFE* lstrcat(pszLogFile, Languages); // c:\windows\mui\muisetup.log.1234
hresult = StringCchCat(pszLogFile , BUFFER_SIZE, Languages); if (!SUCCEEDED(hresult)) { return FALSE; } if (GetFileAttributes(pszLogFile) != 0xFFFFFFFF) // existed
{ // open it and delete assemblies in the list
SXS_UNINSTALLW UninstallData = {sizeof(UninstallData)}; UninstallData.dwFlags = SXS_UNINSTALL_FLAG_USE_INSTALL_LOG; UninstallData.lpInstallLogFile = pszLogFile; return gpfnSxsUninstallW(&UninstallData,NULL); }else return TRUE; } ////////////////////////////////////////////////////////////////////////////////////
//
// InstallSelected
//
// Install the languages specified
//
// Return:
// TURE if the operation succeeds. Otherwise FALSE.
//
////////////////////////////////////////////////////////////////////////////////////
BOOL InstallSelected(LPTSTR Languages, BOOL *lpbFontLinkRegistryTouched) { TCHAR lpMessage[BUFFER_SIZE]; if (!Languages) { return FALSE; } //
// Next step is to create a list of install directories from layout
// the directories are listed in the [Directories] section of MUI.INF
//
if (!EnumDirectories()) { //
// "LOG: Error reading directory list."
//
LoadString(ghInstance, IDS_DIRECTORY_L, lpMessage, ARRAYSIZE(lpMessage)-1); LogMessage(lpMessage); return (FALSE); } EnumFileRename(); EnumTypeNotFallback(); //
// Copy the common files
//
if (Languages) { //
// Copy MUI files for the selected languages.
//
#ifdef MUI_MAGIC
if (!g_bNoUI) { SetWindowTitleFromResource(ghProgDialog, IDS_INSTALL_TITLE); } #endif
if (!CopyFiles(ghProgDialog, Languages)) { //
// "LOG: Error copying files."
//
// stop install if copy fails
//
LoadString(ghInstance, IDS_COPY_L, lpMessage, ARRAYSIZE(lpMessage)-1); LogMessage(lpMessage); #ifndef IGNORE_COPY_ERRORS
gNumLanguages_Install = 0; return (FALSE); #endif
} #ifndef MUI_MAGIC
CopyRemoveMuiItself(TRUE); #endif
} #ifndef MUI_MAGIC
//
// register MUI as installed in registry
//
if (!UpdateRegistry(Languages,lpbFontLinkRegistryTouched)) { //
// LOG: Error updating registry
//
LoadString(ghInstance, IDS_REGISTRY_L, lpMessage, ARRAYSIZE(lpMessage)-1); LogMessage(lpMessage); return (FALSE); } if (!InstallExternalComponents(Languages)) { return (FALSE); } #endif
return (TRUE); } ////////////////////////////////////////////////////////////////////////////////////
//
// UninstallSelected
//
// Uninstall the languages specified
//
// Return:
// TRUE if the operation succeeds. Otherwise FALSE.
//
////////////////////////////////////////////////////////////////////////////////////
BOOL UninstallSelected(LPTSTR Languages,int *lpNotDeleted) { TCHAR lpMessage[BUFFER_SIZE]; BOOL bResult = TRUE; HRESULT hresult;
if (!Languages) { return FALSE; }
//
// Next step is to create a list of install directories
// the directories are listed in the [Directories] section
//
//
// this enumerates the directories and fills the array DirNames
//
if (!EnumDirectories()) { //
// "LOG: Error reading directory list."
//
LoadString(ghInstance, IDS_DIRECTORY_L, lpMessage, ARRAYSIZE(lpMessage)-1); LogMessage(lpMessage); return (FALSE); } #ifndef MUI_MAGIC
UninstallExternalComponents(Languages); if (!g_bNoUI) { SetWindowTitleFromResource(ghProgDialog, IDS_UNINSTALL_TITLE); } #endif
//
// Copy the common files
//
if (!DeleteFiles(Languages,lpNotDeleted)) { //
// "LOG: Error deleting files"
//
LoadString(ghInstance, IDS_DELETE_L, lpMessage, ARRAYSIZE(lpMessage)-1); LogMessage(lpMessage); bResult = FALSE; // even though something failed, we will continue to try to uninstall the product here so upgrade uninstallation will continue clean up
} //
// register MUI as installed in registry, the function logs messages already, so we don't need to log another one here.
//
UninstallUpdateRegistry(Languages); //
// Delete sxs Assembly
//
if (gpfnSxsUninstallW) { TCHAR pszLogFile[BUFFER_SIZE]; if ( ! DeleteSideBySideMUIAssemblyIfExisted(Languages, pszLogFile)) { TCHAR errInfo[BUFFER_SIZE]; //*STRSAFE* swprintf(errInfo, TEXT("Assembly UnInstallation of %s failed"), pszLogFile);
hresult = StringCchPrintf(errInfo , ARRAYSIZE(errInfo), TEXT("Assembly UnInstallation of %s failed"), pszLogFile); if (!SUCCEEDED(hresult)) { return FALSE; } OutputDebugString(errInfo); } } return (bResult); } ////////////////////////////////////////////////////////////////////////////////////
//
// UninstallUpdateRegistry
//
// Update the Registry to account for languages that have been uninstalled
//
////////////////////////////////////////////////////////////////////////////////////
BOOL UninstallUpdateRegistry(LPTSTR Languages) { LPTSTR Language; HKEY hKeyMUI = 0; HKEY hKeyFileVersions = 0; DWORD dwDisp; BOOL bRet = TRUE; TCHAR tcMessage[BUFFER_SIZE]; if (!Languages) { return FALSE; }
if (RegCreateKeyEx( HKEY_LOCAL_MACHINE, REG_MUI_PATH, 0, TEXT("REG_SZ"), REG_OPTION_NON_VOLATILE , KEY_ALL_ACCESS, NULL, &hKeyMUI, &dwDisp) != ERROR_SUCCESS) { bRet = FALSE; goto Exit; } if (RegCreateKeyEx( HKEY_CURRENT_USER, REG_FILEVERSION_PATH, 0, TEXT("REG_SZ"), REG_OPTION_NON_VOLATILE , KEY_ALL_ACCESS, NULL, &hKeyFileVersions, &dwDisp) != ERROR_SUCCESS) { bRet = FALSE; goto Exit; } Language = Languages; while (*Language) { //
// Don't remove system UI language for registry
//
if (HexStrToInt(Language) != gSystemUILangId) { //
// Delete UI Language key, subkeys and values.
//
if (RegDeleteValue(hKeyMUI, Language) != ERROR_SUCCESS) { bRet = FALSE; } if (DeleteRegTree(hKeyFileVersions, Language) != ERROR_SUCCESS) { bRet = FALSE; } }
//
// Attempt to delete the Windows installer regkey entry if we are in OS upgrade setup
//
if (TRUE == g_bRunFromOSSetup) { DeleteMSIRegSettings(Language); } while (*Language++) // go to the next language and repeat
{ } } // of while (*Language)
//
// Delete Match UI Font and Match locale Key
//
DeleteMUIRegSetting();
Exit: //
// Clean up
//
if (hKeyMUI) RegCloseKey(hKeyMUI); if (hKeyFileVersions) RegCloseKey(hKeyFileVersions); return bRet; } ////////////////////////////////////////////////////////////////////////////////////
//
// EnumSelectedLanguages
//
// Enumerate the languages marked for installation
//
// Return:
// The total number of MUI languages to be added.
//
////////////////////////////////////////////////////////////////////////////////////
int EnumSelectedLanguages(HWND hList, LPTSTR lpAddLanguages) { TCHAR szBuffer[BUFFER_SIZE]; TCHAR *p; LPTSTR lpszLcid; int iIndex; int i = 0; PMUILANGINFO pMuiLangInfo; int installLangCount = 0; iIndex = ListView_GetItemCount(hList); HRESULT hresult;
if (!lpAddLanguages) { return 0; } *lpAddLanguages=TEXT('\0'); while(i<iIndex) { if(ListView_GetCheckState(hList, i)) { GetMuiLangInfoFromListView(hList, i, &pMuiLangInfo); lpszLcid = pMuiLangInfo->lpszLcid; if (!IsInstalled(lpszLcid) && HaveFiles(lpszLcid)) { //*STRSAFE* _tcscat(lpAddLanguages, lpszLcid);
hresult = StringCchCat(lpAddLanguages , BUFFER_SIZE, lpszLcid); if (!SUCCEEDED(hresult)) { return 0; } //*STRSAFE* _tcscat(lpAddLanguages, TEXT("*"));
hresult = StringCchCat(lpAddLanguages , BUFFER_SIZE, TEXT("*")); if (!SUCCEEDED(hresult)) { return 0; } //
// Count how many languages are being installed/uninstalled for the progress bar
//
gNumLanguages++; gNumLanguages_Install++; installLangCount++; } } i++; } p = lpAddLanguages; while (p=_tcschr(p, TEXT('*'))) { *p=TEXT('\0'); p++; } return (installLangCount); } ////////////////////////////////////////////////////////////////////////////////////
//
// EnumUnselectedLanguages
//
// Enumerate the languages marked for removal
//
// Return:
// The total number of MUI languages to be added.
//
////////////////////////////////////////////////////////////////////////////////////
int EnumUnselectedLanguages(HWND hList, LPTSTR lpRemoveLanguages) { LPTSTR p; TCHAR szBuffer[BUFFER_SIZE]; LPTSTR lpszLcid; int iIndex; int i = 0; PMUILANGINFO pMuiLangInfo; int uninstallLangCount = 0; HRESULT hresult; iIndex = ListView_GetItemCount(hList); if (!lpRemoveLanguages) { return 0; } *lpRemoveLanguages=TEXT('\0'); g_bRemoveDefaultUI=FALSE; while (i < iIndex) { if (!ListView_GetCheckState(hList, i)) { GetMuiLangInfoFromListView(hList, i, &pMuiLangInfo); lpszLcid = pMuiLangInfo->lpszLcid; if (IsInstalled(lpszLcid)) { //*STRSAFE* _tcscat(lpRemoveLanguages, lpszLcid);
hresult = StringCchCat(lpRemoveLanguages , BUFFER_SIZE, lpszLcid); if (!SUCCEEDED(hresult)) { return 0; } //*STRSAFE* _tcscat(lpRemoveLanguages, TEXT("*"));
hresult = StringCchCat(lpRemoveLanguages , BUFFER_SIZE, TEXT("*")); if (!SUCCEEDED(hresult)) { return 0; } if (GetDotDefaultUILanguage() == pMuiLangInfo->lcid) { g_bRemoveDefaultUI=TRUE; } if (GetUserDefaultUILanguage() == pMuiLangInfo->lcid) { g_bRemoveUserUI = TRUE; } //
// Count how many languages are being installed/uninstalled for the progress bar
//
gNumLanguages++; gNumLanguages_Uninstall++; uninstallLangCount++; } } i++; } p = lpRemoveLanguages; while (p=_tcschr(p, TEXT('*'))) { *p = TEXT('\0'); p++; } return (uninstallLangCount); } ////////////////////////////////////////////////////////////////////////////////////
//
// SkipBlanks
//
// Skips spaces and tabs in string. Returns pointer to next character
//
////////////////////////////////////////////////////////////////////////////////////
PTCHAR SkipBlanks(PTCHAR pszText) { if (!pszText) { return NULL; } while (*pszText==TEXT(' ') || *pszText==TEXT('\t')) { pszText++; } return pszText; } ////////////////////////////////////////////////////////////////////////////////////
//
// NextCommandTag
//
// pointing to next command tag (TEXT('-') or TEXT('/')
//
////////////////////////////////////////////////////////////////////////////////////
LPTSTR NextCommandTag(LPTSTR lpcmd) { LPTSTR p=NULL; if(!lpcmd) { return (p); } while(*lpcmd) { if ((*lpcmd == TEXT('-')) || (*lpcmd == TEXT('/'))) { // Skip to the character after the '-','/'.
p = lpcmd + 1; break; } lpcmd++; } return (p); } ////////////////////////////////////////////////////////////////////////////////////
//
// IsInInstallList
//
// Check if a target is in the string list
//
// Structure of string list:
//
// <string 1><NULL><string 2><NULL>......<string n><NULL><NULL>
//
////////////////////////////////////////////////////////////////////////////////////
BOOL IsInInstallList(LPTSTR lpList,LPTSTR lpTarget) { BOOL bResult=FALSE; if (!lpList || !lpTarget) return bResult; while (*lpList) { if (!_tcsicmp(lpList,lpTarget)) { bResult=TRUE; break; } while (*lpList++) // move to next
{ } } return bResult; } ////////////////////////////////////////////////////////////////////////////////////
//
// CreateProgressDialog
//
// Globals affected:
// ghProgDialog
// ghProgress
//
////////////////////////////////////////////////////////////////////////////////////
void CreateProgressDialog(HWND hwnd) { ghProgDialog = CreateDialog(ghInstance, MAKEINTRESOURCE(IDD_DIALOG_INSTALL_PROGRESS), hwnd, ProgressDialogFunc); ghProgress = GetDlgItem(ghProgDialog, IDC_PROGRESS1); } ////////////////////////////////////////////////////////////////////////////////////
//
// CheckLanguageGroupInstalled
// Check if the Language groups for specified languages is installed correctly.
//
// Parameters:
// [IN] lpLanguages The double-null-terminated string which contains the hex LCID
// strings to be checked.
// Return:
// TURE if all the required language packs are installed in the system. Otherwise, FALSE is
// returned.
//
// CheckLanguageGroupInstalled
// Check if the Language groups for specified languages is installed correctly.
//
// Parameters:
// [IN] lpLanguages The double-null-terminated string which contains the hex LCID
// strings to be checked.
// Return:
// TURE if all the required language packs are installed in the system. Otherwise, FALSE is
// returned.
//
// Remarks:
// 01-18-2001 YSLin Created.
////////////////////////////////////////////////////////////////////////////////////
BOOL CheckLanguageGroupInstalled(LPTSTR lpLanguages) { LANGID langID; LGRPID lgrpID; if (!lpLanguages) { return FALSE; } while (*lpLanguages != TEXT('\0')) { langID = (LANGID)TransNum(lpLanguages); lgrpID = GetLanguageGroup(langID); if (!gpfnIsValidLanguageGroup(lgrpID, LGRPID_INSTALLED)) { return (FALSE); } // Go to the null character.
lpLanguages = _tcschr(lpLanguages, TEXT('\0')); // Skip to next char after the null character.
lpLanguages++; } return (TRUE); } ////////////////////////////////////////////////////////////////////////////////////
//
// DoSetup
//
// Parameters:
// hwnd The hwnd of the MUISetup main dialog. Pass null if the muisetup is run from command line.
// UnistallLangCount The number of languages to be uninstalled.
// lpUninstall The double-null-terminated string which contains the hex LCID strings for the
// languages to be uninstalled.
// installLangGroup
// InstallLangCount The number of languages to be installed.
// lpInstall The double-null-terminated string which contains the hex LCID strings for the
// languages to be installed.
// lpDefaultUILang The language to be set as system default UI language. Pass NULL if the system default
// UI language is not changed.
// fAllowReboot The flag to indicate if this function should check if reboot is necessary.
// bInteractive TRUE if run in interactive mode, or FALSE if run in silent mode.
// bDisplayUI TRUE if UI is desired, FALSE if UI is to be suppressed
//
//
// Return:
// TRUE if installation is successful. Otherwise FALSE.
//
// Notes:
// This functions serves as the entry point of the real installation process, shared by both the GUI setup
// and the command line mode setup.
//
// There are several steps in doing MUI setup.
// 1. Uninstall the selected MUI languages.
// 2. Install the necessary language packs according to the selected MUI languges(if any).
// 3. Install the selected MUI languages.
// 4. Change the default UI language.
// 5. Check for rebooting.
//
// Please note that to save space, we do the uninstallation first, then do the installation.
////////////////////////////////////////////////////////////////////////////////////
BOOL DoSetup( HWND hwnd, int UninstallLangCount, LPTSTR lpUninstall, INSTALL_LANG_GROUP installLangGroup, int InstallLangCount, LPTSTR lpInstall, LPTSTR lpDefaultUILang, BOOL fAllowReboot, BOOL bInteractive, BOOL bDisplayUI) { LONG_PTR lppArgs[3]; TCHAR lpMessage[BUFFER_SIZE]; TCHAR lpForceUILang[BUFFER_SIZE]; TCHAR lpTemp[BUFFER_SIZE]; TCHAR lpTemp2[BUFFER_SIZE]; LANGID defaultLangID; HCURSOR hCurSave; int NotDeleted; BOOL bDefaultUIChanged = FALSE; BOOL bErrorOccurred = FALSE; LANGID lidSys = GetSystemDefaultLangID(); BOOL isReboot; ghProgDialog = NULL; ghProgress = NULL; HRESULT hresult; if ( (! lpUninstall) || (!lpInstall) ) { return FALSE; } hCurSave=SetCursor(LoadCursor(NULL, IDC_WAIT)); if(UninstallLangCount > 0) { #ifndef MUI_MAGIC
if (bDisplayUI) { CreateProgressDialog(hwnd); SendMessage(ghProgress, PBM_SETRANGE, (WPARAM)(int)0, (LPARAM)MAKELPARAM(0, UninstallLangCount * INSTALLED_FILES)); SendMessage(ghProgress, PBM_SETPOS, (WPARAM)0, 0); SetWindowTitleFromResource(ghProgDialog, IDS_UNINSTALL_TITLE); } #endif
//
// Uninstall MUI languages
//
if (!UninstallSelected(lpUninstall, &NotDeleted)) { #ifndef MUI_MAGIC
if (bDisplayUI) { DestroyWindow(ghProgDialog); ghProgDialog = NULL; } #endif
// prompt a messagebox about uninstallation error
if (bDisplayUI) { DoMessageBoxFromResource(hwnd, ghInstance, IDS_ERROR_UNINSTALL_LANG, lppArgs, IDS_MAIN_TITLE, MB_OK); SetCursor(hCurSave); } bErrorOccurred = TRUE; goto PostSetup; } #ifndef MUI_MAGIC
if (bDisplayUI) { SendMessage(ghProgress, PBM_SETPOS, (WPARAM)(UninstallLangCount * INSTALLED_FILES), 0); } #endif
} if(InstallLangCount > 0) { #ifndef MUI_MAGIC
//
// Install Language Group First
//
if (!InstallLanguageGroups(&installLangGroup)) { if (bDisplayUI) { DestroyWindow(ghProgDialog); ghProgDialog = NULL; } if (bDisplayUI) { SetCursor(hCurSave); } bErrorOccurred = TRUE; goto PostSetup; } //
// Check if language group in installLangGroup is installed correctly
//
if (!CheckLanguageGroupInstalled(lpInstall)) { LogFormattedMessage(NULL, IDS_LG_NOT_INSTALL_L, NULL); if (bDisplayUI || bInteractive) { DoMessageBox(NULL, IDS_LG_NOT_INSTALL, IDS_MAIN_TITLE, MB_OK); } return (FALSE); } #endif
//
// Make sure MUI CD-ROM is put in the CD-ROM drive.
//
if(CheckVolumeChange()) { if (bDisplayUI) { #ifndef MUI_MAGIC
DestroyWindow(ghProgDialog); ghProgDialog = NULL; #endif
SetCursor(hCurSave); } return (FALSE); } #ifndef MUI_MAGIC
if (bDisplayUI) { if (ghProgDialog == NULL) { CreateProgressDialog(hwnd); } SendMessage(ghProgress, PBM_SETRANGE, (WPARAM)(int)0, (LPARAM)MAKELPARAM(0, InstallLangCount * INSTALLED_FILES)); SendMessage(ghProgress, PBM_SETPOS, (WPARAM)0, 0); SetWindowTitleFromResource(ghProgDialog, IDS_INSTALL_TITLE); } #endif
if (!InstallSelected(lpInstall,&installLangGroup.bFontLinkRegistryTouched)) { if (bDisplayUI) { DoMessageBoxFromResource(hwnd, ghInstance, IDS_ERROR_INSTALL_LANG, lppArgs, IDS_MAIN_TITLE, MB_OK); #ifndef MUI_MAGIC
DestroyWindow(ghProgDialog); ghProgDialog = NULL; #endif
SetCursor(hCurSave); } bErrorOccurred = TRUE; goto PostSetup; } #ifndef MUI_MAGIC
if (bDisplayUI) { SendMessage(ghProgress, PBM_SETPOS, (WPARAM)((UninstallLangCount+InstallLangCount) * INSTALLED_FILES), 0); } #endif
} if (bDisplayUI) { #ifndef MUI_MAGIC
DestroyWindow(ghProgDialog); ghProgDialog = NULL; #endif
SetCursor(hCurSave); } if (UninstallLangCount + InstallLangCount > 0) { //
// "Installation Complete"
// "Installation was completed successfully."
//
if (bInteractive || bDisplayUI) { DoMessageBox(hwnd, InstallLangCount > 0 ? IDS_MUISETUP_SUCCESS : IDS_MUISETUP_UNINSTALL_SUCCESS, IDS_MAIN_TITLE, MB_OK | MB_DEFBUTTON1); } } //
// In command line mode, if "/D" is specified, we should ask user to confirm making default UI language change.
// In command line mode, if "/D" is NOT specified, we should NOT try to change the default UI language.
// In command line mode, if "/D" & "/S" are specified, we will NOT ask user's confirmation.
// In GUI mode, we always ask user to confirm making default UI language change.
//
//
// Special case:
// If the current default UI language is going to be removed and user doesn't choose a new UI language,
// we will force to set the default UI language to be the system UI language.
//
if(g_bRemoveDefaultUI) { //
// Delete shell cache for the current user
//
SHDeleteKey(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Windows\\ShellNoRoam\\MUICache")); } if (lpDefaultUILang) { defaultLangID = (LANGID)_tcstol(lpDefaultUILang, NULL, 16); if (IsInstalled(lpDefaultUILang)) { //
// If the assigned UI language ID (defaultLangID) is already the default user UI language,
// we don't do anything. Otherwise, change the default user UI langauge.
//
if (defaultLangID != GetDotDefaultUILanguage()) { if (SetUserDefaultLanguage(defaultLangID, FALSE, TRUE)) { bDefaultUIChanged = TRUE; } else { if (bInteractive) { DoMessageBox(hwnd, IDS_DEFAULT_USER_ERROR, IDS_MAIN_TITLE, (MB_OK | MB_ICONEXCLAMATION)); } } } else { // Do nothing here. I leave this here intentionally to highlight that
// we don't do antying if the specified defaultLangID is already the default UI language.
} //
// Make sure registry is set correctly
//
if(BST_CHECKED == IsDlgButtonChecked( hwnd, IDC_CHECK_LOCALE )) { SetMUIRegSetting(MUI_MATCH_LOCALE, TRUE); SetMUIRegSetting(MUI_MATCH_UIFONT, BST_CHECKED == IsDlgButtonChecked(hwnd, IDC_CHECK_UIFONT)); } else { SetMUIRegSetting(MUI_MATCH_LOCALE, FALSE); SetMUIRegSetting(MUI_MATCH_UIFONT, FALSE); } //
// Notify intl.cpl if we have system locale or UI font setting change
//
if ((BST_CHECKED == IsDlgButtonChecked( hwnd, IDC_CHECK_LOCALE) || g_bCmdMatchLocale || g_bLipLanguages) && defaultLangID != lidSys) { TCHAR szCommands[BUFFER_SIZE]; //
// Invoke intl.cpl to change system locale to match the default UI language
//
//*STRSAFE* wsprintf(szCommands, TEXT("SystemLocale = \"%x\""), defaultLangID);
hresult = StringCchPrintf(szCommands , ARRAYSIZE(szCommands), TEXT("SystemLocale = \"%x\""), defaultLangID); if (!SUCCEEDED(hresult)) { return FALSE; } //
// Always reboot if system locale is changed
//
if (RunRegionalOptionsApplet(szCommands)) { g_bReboot = TRUE; } } else if (g_bMatchUIFont != (BST_CHECKED == IsDlgButtonChecked(hwnd, IDC_CHECK_UIFONT)) || g_bCmdMatchUIFont) { TCHAR szCommands[BUFFER_SIZE]; //
// We're not really changing system locale here, it is used to invoke intl.cpl for font setting changes
//
//*STRSAFE* wsprintf(szCommands, TEXT("SystemLocale = \"%x\""), lidSys);
hresult = StringCchPrintf(szCommands , ARRAYSIZE(szCommands), TEXT("SystemLocale = \"%x\""), lidSys); if (!SUCCEEDED(hresult)) { return FALSE; } if (RunRegionalOptionsApplet(szCommands) && defaultLangID == MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT)) { // Don't prompt for reboot, intl.cpl will cause muisetup to lose focus if we do so.
// Need to fix this in XP server release
g_bReboot = TRUE; } } //
// Change user locale for LIP languages
//
if (g_bLipLanguages) { TCHAR szCommands[BUFFER_SIZE]; //
// Invoke intl.cpl to change system locale to match the default UI language
//
//*STRSAFE* wsprintf(szCommands, TEXT("UserLocale = \"%x\"\x0d\x0aUserLocale_DefaultUser = \"%x\"\x0d\x0aMUILanguage=\"%x\""), defaultLangID, defaultLangID, defaultLangID);
hresult = StringCchPrintf(szCommands , ARRAYSIZE(szCommands), TEXT("UserLocale = \"%x\"\x0d\x0aUserLocale_DefaultUser = \"%x\"\x0d\x0aMUILanguage=\"%x\""), defaultLangID, defaultLangID, defaultLangID); if (!SUCCEEDED(hresult)) { return FALSE; } if (RunRegionalOptionsApplet(szCommands) && defaultLangID == MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT)) { // Don't prompt for reboot, intl.cpl will cause muisetup to loose focus if we do so.
// Need to fix this in XP server release
g_bReboot = TRUE; } } } else { //
// "ERROR: %1 was not set as the default. It is not installed.\r\nNo default UI language change."
//
lppArgs[0] = (LONG_PTR)lpDefaultUILang; LogFormattedMessage(NULL, IDS_DEFAULT_L, lppArgs); return (FALSE); } } PostSetup: //
// Check for reboot, and if we are allowed to do so.
//
if (fAllowReboot) { //
// Check if we need to reboot?
//
if (!CheckForReboot(hwnd, &installLangGroup)) { //
// Check if we recommend a reboot?
//
if ((bInteractive || bDisplayUI) && bDefaultUIChanged) { GetLanguageDisplayName(defaultLangID, lpTemp, ARRAYSIZE(lpTemp)-1); lppArgs[0] = (LONG_PTR)lpTemp; if (lidSys == defaultLangID) { if (bDisplayUI) { isReboot = (DoMessageBoxFromResource(hwnd, ghInstance, IDS_CHANGE_UI_NEED_RBOOT, lppArgs, IDS_MAIN_TITLE, MB_YESNO) == IDYES); } else { isReboot = TRUE; } } else { GetLanguageDisplayName(lidSys, lpTemp2, ARRAYSIZE(lpTemp2)-1); lppArgs[1] = (LONG_PTR)lpTemp2;
if (bDisplayUI) { isReboot = (DoMessageBoxFromResource(hwnd, ghInstance, IDS_CHANGE_UI_NEED_RBOOT_SYSTEM_LCID, lppArgs, IDS_MAIN_TITLE, MB_YESNO) == IDYES); } else { isReboot = TRUE; } } if (isReboot) { Muisetup_RebootTheSystem(); } } } } if (bErrorOccurred) return (FALSE); return (TRUE); } int ParseUninstallLangs(LPTSTR p, LPTSTR lpUninstall, int cchUninstall, INT64* pulUISize, INT64* pulLPKSize, INT64* pulSpaceNeed, BOOL* pbLogError) { int iCopied; TCHAR lpBuffer[BUFFER_SIZE]; LONG_PTR lppArgs[2]; int cLanguagesToUnInstall = 0; LANGID LgId; LPTSTR pU = lpUninstall; if ((!p) || (! lpUninstall) || (!pulUISize) || (!pulLPKSize) || (!pulSpaceNeed) || (!pbLogError)) { return FALSE; } p = SkipBlanks(p);
if (!p) return FALSE; iCopied = 0; while((*p != TEXT('-')) && (*p != TEXT('/')) && (*p != TEXT('\0'))) { iCopied = CopyArgument(lpBuffer, p); if(!HaveFiles(lpBuffer, FALSE)) { //
// "LOG: %1 was not installed. It is not listed in MUI.INF."
//
lppArgs[0] = (LONG_PTR)lpBuffer; LogFormattedMessage(NULL, IDS_NOT_LISTED_L, lppArgs); *pbLogError = TRUE; } else if (!IsInstalled(lpBuffer)) { //
// "LOG: %1 was not uninstalled, because it is not installed. "
//
lppArgs[0] = (LONG_PTR)lpBuffer; LogFormattedMessage(NULL, IDS_IS_NOT_INSTALLED_L, lppArgs); *pbLogError = TRUE; } else if (!IsInInstallList(lpUninstall,lpBuffer)) { iCopied = CopyArgument(pU, p); //
// Check if we are going to remove the current UI language
//
LgId = (LANGID)_tcstol(pU, NULL, 16); if (LgId == GetDotDefaultUILanguage()) { g_bRemoveDefaultUI = TRUE; } if (LgId == GetUserDefaultUILanguage()) { g_bRemoveUserUI = TRUE; } //
// Calculate the space required
//
GetUIFileSize_commandline(lpBuffer, pulUISize,pulLPKSize); *pulSpaceNeed-=*pulUISize; pU += iCopied; pU++; //skip over NULL
cLanguagesToUnInstall++; } p += iCopied; p = SkipBlanks(p); } //
// Uninstall all MUI languages if there is no language argument after /U
//
if (iCopied == 0) { cLanguagesToUnInstall = GetInstalledMUILanguages(lpUninstall, cchUninstall); if (cLanguagesToUnInstall == 0) { LogFormattedMessage(ghInstance, IDS_NO_MUI_LANG, NULL); *pbLogError = TRUE; } else { if (0x0409 != GetDotDefaultUILanguage()) { g_bRemoveDefaultUI = TRUE; } if (0x0409 != GetUserDefaultUILanguage()) { g_bRemoveUserUI = TRUE; } } } else { *pU=TEXT('\0'); } return (cLanguagesToUnInstall); } ////////////////////////////////////////////////////////////////////////////
//
// GetCDNameFromLang
//
// Given a langange ID (in hex string), return the CD name where the language
// installation folder exist.
// This can also be used to check if the language is supported MUI language.
//
// Parameters:
// [IN] lpLangName the language to be installed in hex string.
// [OUT] lpCDName the number of the CD (e.g. "2" or "3").
// [IN] nCDNameSize the size of lpCDName, in TCHAR.
//
// Return Values:
// TRUE if lpLangName is a supported MUI language. lpCDName will contain
// the name of the CD.
// FALSE if the language ID is not a supported langauge. lpCDNAme will be
// empty string.
//
// Remarks:
//
// 01-01-2001 YSLin Created.
//
////////////////////////////////////////////////////////////////////////////
BOOL GetCDNameFromLang(LPTSTR lpLangName, LPTSTR lpCDName, int nCDNameSize) { if (!GetPrivateProfileString( MUI_CDLAYOUT_SECTION, lpLangName, TEXT(""), lpCDName, nCDNameSize, g_szMUIInfoFilePath)) { return (FALSE); } return (TRUE); } ////////////////////////////////////////////////////////////////////////////////////
//
// ParseCommandLine
//
// Runs installation functions with command line specifications
//
////////////////////////////////////////////////////////////////////////////////////
BOOL ParseCommandLine(LPTSTR lpCommandLine) { BOOL bSetDefaultUI=FALSE; // Specify if the /D switch is used to change the user default UI language.
BOOL bInstall=FALSE; BOOL bLogError=FALSE; BOOL bFELangpackAdded=FALSE; BOOL bResult = FALSE; DWORD dwDisp; LANGID LgId; TCHAR lpBuffer[BUFFER_SIZE]; TCHAR lpDefault[BUFFER_SIZE]; TCHAR lpDefaultText[MAX_PATH]; TCHAR lpInstall[BUFFER_SIZE]; TCHAR lpMessage[BUFFER_SIZE]; TCHAR lpUninstall[BUFFER_SIZE]; TCHAR lpSystemDefault[BUFFER_SIZE]; TCHAR lpTemp[BUFFER_SIZE]; TCHAR szWinDir[MAX_PATH]; INSTALL_LANG_GROUP installLangGroup; LONG_PTR lppArgs[4]; PTCHAR pI; PTCHAR pD; PTCHAR p; BOOL fAllowReboot = TRUE; int cLanguagesToInstall = 0L; int cLanguagesToUnInstall = 0L; int iCopied; TCHAR chOpt; INT64 ulSpaceNeed=0,ulSpaceAvailable=0,ulUISize=0,ulLPKSize=0; ULONG ulParam[2]; ULARGE_INTEGER ulgiFreeBytesAvailableToCaller; ULARGE_INTEGER ulgiTotalNumberOfBytes; BOOL bHasLangArgs = FALSE; BOOL bHelpDisplayed=FALSE; //PREFAST TCHAR lpCDName[BUFFER_SIZE];
LPTSTR lpCDName=NULL;
if (!lpCommandLine) { return FALSE; } //
// Allocate space for Heap variable
//
lpCDName = new TCHAR[BUFFER_SIZE]; if (! lpCDName) { goto exit_ParseCommandLine; } //
// Initialize Lang-Groups to install
//
installLangGroup.iCount = 0L; installLangGroup.NotDeleted = 0L; installLangGroup.bFontLinkRegistryTouched = FALSE; lpInstall[0] = TEXT('\0'); lpUninstall[0] = TEXT('\0'); lpDefault[0] = TEXT('\0'); pI = lpInstall; pD = lpDefault; p = lpCommandLine; CharLower(p); while(p=NextCommandTag(p)) { chOpt = *p++; switch (chOpt) { case '?': case 'h': if (!bHelpDisplayed) { DisplayHelpWindow(); bHelpDisplayed=TRUE; } // if we encountered a help switch, after displaying the window, we just exit
bResult = TRUE; goto exit_ParseCommandLine; // p = SkipBlanks(p);
break; case 'i': if (!FileExists(g_szMUIInfoFilePath)) { //
// "The file MUI.INF cannot be found."
//
DoMessageBox(NULL, IDS_NO_MUI_FILE, IDS_MAIN_TITLE, MB_OK | MB_DEFBUTTON1); break; } //
// MUI version needs to match OS version
//
if (!checkversion(TRUE)) { DoMessageBox(NULL, IDS_WRONG_VERSION, IDS_MAIN_TITLE, MB_OK | MB_DEFBUTTON1); break; } p = SkipBlanks(p); while ((*p != TEXT('-')) && (*p != TEXT('/')) && (*p != TEXT('\0'))) { bHasLangArgs = TRUE; iCopied=CopyArgument(lpBuffer, p); if (!IsInstalled(lpBuffer) && CheckLanguageIsQualified(lpBuffer) && HaveFiles(lpBuffer) && (!IsInInstallList(lpInstall,lpBuffer)) ) { //
// Calculate the space required
//
GetUIFileSize_commandline(lpBuffer, &ulUISize,&ulLPKSize); ulSpaceNeed+=ulUISize; if(CheckLangGroupCommandLine(&installLangGroup, lpBuffer)) { if (IS_FE_LANGPACK(_tcstol(lpBuffer, NULL, 16))) { if (!bFELangpackAdded) { ulSpaceNeed+=ulLPKSize; bFELangpackAdded = TRUE; } }else { ulSpaceNeed+=ulLPKSize; } } AddExtraLangGroupsFromINF(lpBuffer, &installLangGroup); iCopied=CopyArgument(pI, p); pI += iCopied; pI++; //skip over NULL
bInstall = TRUE; cLanguagesToInstall++; } else { lppArgs[0]=(LONG_PTR)lpBuffer; if(IsInstalled(lpBuffer)|| IsInInstallList(lpInstall,lpBuffer)) { // "LOG: %1 was not installed, because it is already installed. "
LogFormattedMessage(ghInstance, IDS_IS_INSTALLED_L, lppArgs); } if(!HaveFiles(lpBuffer)) { if (!GetCDNameFromLang(lpBuffer, lpCDName, ARRAYSIZE(lpCDName))) { // lpBuffer is not a supported MUI language.
// "LOG: %1 was not installed, because it is not listed in MUI.INF. Please check if it is a valid UI language ID."
LogFormattedMessage(ghInstance, IDS_NOT_LISTED_L, lppArgs); } else { // lpBuffer is a supported MUI language, ask user to change CD and
// rerun setup.
LoadString(ghInstance, IDS_CHANGE_CDROM, lpTemp, ARRAYSIZE(lpTemp)-1); lppArgs[1] = (LONG_PTR)lpTemp; lppArgs[2] = (LONG_PTR)lpCDName; // "ERROR: %1 was not installed, because it is located in %2 %3. Please insert that CD and rerun MUISetup."
LogFormattedMessage(ghInstance, IDS_LANG_IN_ANOTHER_CD_L, lppArgs); } } if(!CheckLanguageIsQualified(lpBuffer)) { // "LOG: %1 was not installed, because it cannot be installed on this platform\n"
LogFormattedMessage(ghInstance, IDS_NOT_QUALIFIED_L, lppArgs); } bLogError = TRUE; } p += iCopied; p = SkipBlanks(p); } if (!bHasLangArgs) { lppArgs[0] = (LONG_PTR)TEXT("/I"); FormatStringFromResource(lpMessage, sizeof(lpMessage)/sizeof(TCHAR), ghInstance, IDS_ERROR_NO_LANG_ARG, lppArgs); LogMessage(lpMessage); bLogError = TRUE; } *pI = TEXT('\0'); break; case 'u': if (!checkversion(FALSE)) { DoMessageBox(NULL, IDS_WRONG_VERSION, IDS_MAIN_TITLE, MB_OK | MB_DEFBUTTON1); break; } cLanguagesToUnInstall = ParseUninstallLangs(p, lpUninstall, ARRAYSIZE(lpUninstall), &ulUISize, &ulLPKSize, &ulSpaceNeed, &bLogError); break; case 'd': if (!checkversion(FALSE)) { DoMessageBox(NULL, IDS_WRONG_VERSION, IDS_MAIN_TITLE, MB_OK | MB_DEFBUTTON1); break; } bSetDefaultUI = TRUE; p = SkipBlanks(p); if (CopyArgument(lpDefault, p) == 0) { lppArgs[0] = (LONG_PTR)TEXT("/D"); FormatStringFromResource(lpMessage, sizeof(lpMessage)/sizeof(TCHAR), ghInstance, IDS_ERROR_NO_LANG_ARG, lppArgs); LogMessage(lpMessage); bLogError = FALSE; } break; case 'r': fAllowReboot = FALSE; break; case 's' : g_bSilent = TRUE; // check if desktop is interactive or not, if not, hide all UI
if (FALSE == IsWindowVisible(GetDesktopWindow())) { g_bNoUI = TRUE; } break; case 't' : // use this switch to totally suppress all the possible UI that can be popped up by muisetup and the processes it
// launches.
g_bSilent = TRUE; g_bNoUI = TRUE; break; case 'l': g_bCmdMatchLocale = TRUE; break; case 'f': g_bCmdMatchUIFont = TRUE; break; case 'o': g_bRunFromOSSetup = TRUE; break; default: // if we encounter an invalid switch at any stage, treat it the same as help and quit afterwards
if (!bHelpDisplayed) { DisplayHelpWindow(); bHelpDisplayed=TRUE; } // if we encountered a help switch, after displaying the window, we just exit
bResult = TRUE; goto exit_ParseCommandLine; break; } } //
// UI Font depends on system locale
//
if (!g_bCmdMatchLocale && g_bCmdMatchUIFont) { g_bCmdMatchUIFont = FALSE; } //
// Check the disk space
//
//
pfnGetWindowsDir( szWinDir, MAX_PATH); szWinDir[3]=TEXT('\0'); if (GetDiskFreeSpaceEx(szWinDir, &ulgiFreeBytesAvailableToCaller, &ulgiTotalNumberOfBytes, NULL)) { ulSpaceAvailable= ulgiFreeBytesAvailableToCaller.QuadPart; if ( ulSpaceAvailable < ulSpaceNeed ) { ulParam[0] = (ULONG) (ulSpaceNeed/1024); ulParam[1] = (ULONG) (ulSpaceAvailable/1024); LoadString(ghInstance, IDS_DISKSPACE_NOTENOUGH, lpMessage, ARRAYSIZE(lpMessage)-1); LoadString(ghInstance, IDS_ERROR_DISKSPACE, lpTemp, ARRAYSIZE(lpTemp)-1); FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, lpMessage, 0, 0, lpMessage, ARRAYSIZE(lpMessage)-1, (va_list *) ulParam); LogMessage(lpMessage); bLogError = TRUE; MESSAGEBOX(NULL, lpMessage, lpTemp, MB_OK | MB_DEFBUTTON1 | MB_ICONWARNING); bInstall = FALSE; cLanguagesToUnInstall = 0; } } if (!bLogError) { //
// Let's set the default UI language
//
if (!DoSetup( NULL, cLanguagesToUnInstall, lpUninstall, installLangGroup, cLanguagesToInstall, lpInstall, (bSetDefaultUI ? lpDefault : NULL), fAllowReboot, !g_bSilent, !g_bNoUI)) { bLogError = TRUE; } } if (bLogError && !g_bSilent && !g_bNoUI) { //
// "Installation Error"
// "One or more errors occurred during installation.
// Please see %1\muisetup.log for more information."
//
lppArgs[0] = (LONG_PTR)szWindowsDir; DoMessageBoxFromResource(NULL, ghInstance, IDS_ERROR, lppArgs, IDS_ERROR_T, MB_OK | MB_DEFBUTTON1 | MB_ICONWARNING); } bResult = TRUE; exit_ParseCommandLine: if (lpCDName) { delete [] lpCDName; } return bResult; } ////////////////////////////////////////////////////////////////////////////////////
//
// DisplayHelpWindow
//
// Displays help window for command line version
//
////////////////////////////////////////////////////////////////////////////////////
void DisplayHelpWindow() { STARTUPINFO si; PROCESS_INFORMATION pi = {0}; TCHAR Appname[MAX_PATH+MAX_PATH+1],szFilePath[MAX_PATH+1]; HRESULT hresult; int nLen; szFilePath[0] = UNICODE_NULL; if (!pfnGetWindowsDir(szFilePath, MAX_PATH)) { return; } nLen = lstrlen(szFilePath); if (szFilePath[nLen-1] != TEXT('\\')) { hresult = StringCchCat(szFilePath , ARRAYSIZE(szFilePath), TEXT("\\")); if (!SUCCEEDED(hresult)) { return; } } hresult = StringCchCat(szFilePath , ARRAYSIZE(szFilePath), WINHELP32PATH); if (!SUCCEEDED(hresult)) { return ; } if (FileExists(g_szMUIHelpFilePath)) { //*STRSAFE* wsprintf(Appname,TEXT("\"%s\" -n%d %s"),szFilePath,IDH_MUISETUP_COMMANDLINE,g_szMUIHelpFilePath);
hresult = StringCchPrintf(Appname , ARRAYSIZE(Appname), TEXT("\"%s\" -n%d %s"),szFilePath, IDH_MUISETUP_COMMANDLINE,g_szMUIHelpFilePath); if (!SUCCEEDED(hresult)) { return; } memset( &si, 0x00, sizeof(si)); si.cb = sizeof(STARTUPINFO); if (!CreateProcess(NULL, Appname, NULL, NULL, FALSE, 0L, NULL, NULL, &si, &pi) ) return; WaitForSingleObject(pi.hProcess, INFINITE); //
// Close Handle
//
CloseHandle( pi.hProcess ); CloseHandle( pi.hThread ); } else { //////////////////////////////////////////////
// MessageBox should be changed to Dialog
//////////////////////////////////////////////
DoMessageBox(NULL, IDS_HELP, IDS_HELP_T, MB_OK | MB_DEFBUTTON1); } } ////////////////////////////////////////////////////////////////////////////////////
//
// CopyArgument
//
// Copies command line argument pointed to by src to dest
//
////////////////////////////////////////////////////////////////////////////////////
int CopyArgument(LPTSTR dest, LPTSTR src) { int i=0; if ((!dest) || (!src)) { return i; } while(*src!=TEXT(' ') && *src!=TEXT('\0')) { *dest=*src; dest++; src++; i++; } *dest = TEXT('\0'); return i; } ////////////////////////////////////////////////////////////////////////////////////
//
// IsInstalled
//
// Checks to see if lpArg is a language installed in the registry
//
////////////////////////////////////////////////////////////////////////////////////
BOOL IsInstalled(LPTSTR lpArg) { HKEY hKey; DWORD dwData; DWORD dwIndex; DWORD dwValue; TCHAR lpData[BUFFER_SIZE]; TCHAR lpValue[BUFFER_SIZE]; int rc; int iArg; if (!lpArg) { return FALSE; } hKey=OpenMuiKey(KEY_READ); if (hKey == NULL) { return (FALSE); } dwIndex=0; rc=ERROR_SUCCESS; iArg=_tcstol(lpArg, NULL, 16); if (iArg == gSystemUILangId) { RegCloseKey(hKey); return (TRUE); } while(rc==ERROR_SUCCESS) { dwValue=sizeof(lpValue)/sizeof(TCHAR); lpValue[0]=TEXT('\0'); dwData=sizeof(lpData); lpData[0]=TEXT('\0'); DWORD dwType; rc=RegEnumValue(hKey, dwIndex, lpValue, &dwValue, 0, &dwType, (LPBYTE)lpData, &dwData); if(rc==ERROR_SUCCESS) { if (dwType != REG_SZ) { dwIndex++; continue; } if(_tcstol(lpValue, NULL, 16)==iArg) { RegCloseKey(hKey); return TRUE; } } dwIndex++; } RegCloseKey(hKey); return FALSE; } ////////////////////////////////////////////////////////////////////////////////////
//
// GetInstalledMUILanguages
//
// Get installed MUI languages, dump it to lpUninstall buffer in a MULTI_SZ format
//
////////////////////////////////////////////////////////////////////////////////////
DWORD GetInstalledMUILanguages(LPTSTR lpUninstall, int cch) { HKEY hKey; DWORD dwIndex = 0; DWORD dwCount = 0; DWORD dwValue = cch; DWORD dwType = 0;
if (!lpUninstall) { return dwCount; } if (hKey = OpenMuiKey(KEY_READ)) { while(ERROR_NO_MORE_ITEMS != RegEnumValue(hKey, dwIndex++, lpUninstall, &dwValue, 0, &dwType, NULL, NULL) && cch > 0) { if (dwType != REG_SZ) continue; if (_tcstol(lpUninstall, NULL, 16) != gSystemUILangId) { //
// Count in NULL
//
dwValue++; lpUninstall += dwValue; cch -= dwValue; dwCount++; } dwValue = cch; } RegCloseKey(hKey); *lpUninstall = TEXT('\0'); } return dwCount; } ////////////////////////////////////////////////////////////////////////////////////
//
// HaveFiles
//
// Checks that the language in lpBuffer is in MUI.INF
//
////////////////////////////////////////////////////////////////////////////////////
BOOL HaveFiles(LPTSTR lpBuffer, BOOL bCheckDir) { LPTSTR lpLanguages = NULL; TCHAR lpMessage[BUFFER_SIZE]; TCHAR tchBuffer[BUFFER_SIZE]; if (!lpBuffer) { return FALSE; } lpLanguages = tchBuffer; if (EnumLanguages(lpLanguages, bCheckDir) == 0) { //
// "LOG: No languages found in MUI.INF"
//
LoadString(ghInstance, IDS_NO_LANG_L, lpMessage, ARRAYSIZE(lpMessage)-1); LogMessage(lpMessage); return FALSE; } if(!lpLanguages) return FALSE; while (*lpLanguages != TEXT('\0')) { if (_tcscmp(lpBuffer, lpLanguages) == 0) { return TRUE; } lpLanguages = _tcschr(lpLanguages, '\0'); lpLanguages++; } return FALSE; } ////////////////////////////////////////////////////////////////////////////////////
//
// OpenLogFile
//
// Opens the setup log for writing
//
////////////////////////////////////////////////////////////////////////////////////
HANDLE OpenLogFile() { DWORD dwSize; DWORD dwUnicodeHeader; HANDLE hFile; SECURITY_ATTRIBUTES SecurityAttributes; TCHAR lpPath[BUFFER_SIZE]; int error; HRESULT hresult; pfnGetWindowsDir(lpPath, MAX_PATH); error=GetLastError(); //*STRSAFE* _tcscat(lpPath, LOG_FILE);
hresult = StringCchCat(lpPath , ARRAYSIZE(lpPath), LOG_FILE); if (!SUCCEEDED(hresult)) { return NULL; } 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
error=GetLastError(); return hFile; } ////////////////////////////////////////////////////////////////////////////////////
//
// LogMessage
//
// Writes lpMessage to the setup log
//
////////////////////////////////////////////////////////////////////////////////////
BOOL LogMessage(LPCTSTR lpMessage) { DWORD dwBytesWritten; HANDLE hFile;
if (!lpMessage) { return FALSE; } hFile=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; } ////////////////////////////////////////////////////////////////////////////////////
//
// LogFormattedMessage
//
// Writes a formatted lpMessage to the setup log
//
////////////////////////////////////////////////////////////////////////////////////
BOOL LogFormattedMessage(HINSTANCE hInstance, int messageID, LONG_PTR* lppArgs) { TCHAR szBuffer[BUFFER_SIZE]; LoadString(hInstance, messageID, szBuffer, ARRAYSIZE(szBuffer)); if (lppArgs == NULL) { return (LogMessage(szBuffer)); } FormatMessage( FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, szBuffer, 0, 0, szBuffer, sizeof(szBuffer) / sizeof(TCHAR), (va_list *)lppArgs); return (LogMessage(szBuffer)); } ////////////////////////////////////////////////////////////////////////////
//
// FormatStringFromResource
//
// Format a string using the format specified in the resource and the
// specified arguments.
//
// Parameters:
//
// Return Values:
// the formatted string.
//
// Remarks:
//
// 08-07-2000 YSLin Created.
//
////////////////////////////////////////////////////////////////////////////
LPTSTR FormatStringFromResource(LPTSTR pszBuffer, UINT bufferSize, HMODULE hInstance, int messageID, LONG_PTR* lppArgs) { TCHAR szFormatStr[BUFFER_SIZE]; LoadString(hInstance, messageID, szFormatStr, ARRAYSIZE(szFormatStr)-1); if (!lppArgs) { LogMessage(szFormatStr); return NULL; } FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, szFormatStr, 0, 0, pszBuffer, bufferSize , (va_list *)lppArgs); return (pszBuffer); } ////////////////////////////////////////////////////////////////////////////////////
//
// BeginLog
//
// Writes a header to the setup log
//
////////////////////////////////////////////////////////////////////////////////////
void BeginLog(void) { TCHAR lpMessage[BUFFER_SIZE]; SYSTEMTIME stSysTime; HRESULT hresult; //
// "**********************************************************
// Language Module Installation Log
// **********************************************************" (LOG)
//
LoadString(ghInstance, IDS_LOG_HEAD, lpMessage, ARRAYSIZE(lpMessage)-1); LogMessage(lpMessage); // Also log the time the mui installation is started.
GetLocalTime(&stSysTime); //*STRSAFE* wsprintf(lpMessage, TEXT("Muisetup.exe started on day %2d/%2d/%4d at time %2d:%2d:%2d"),
//*STRSAFE* stSysTime.wMonth,
//*STRSAFE* stSysTime.wDay,
//*STRSAFE* stSysTime.wYear,
//*STRSAFE* stSysTime.wHour,
//*STRSAFE* stSysTime.wMinute,
//*STRSAFE* stSysTime.wSecond
//);
hresult = StringCchPrintf(lpMessage , ARRAYSIZE(lpMessage) , TEXT("Muisetup.exe started on day %2d/%2d/%4d at time %2d:%2d:%2d"), stSysTime.wMonth, stSysTime.wDay, stSysTime.wYear, stSysTime.wHour, stSysTime.wMinute, stSysTime.wSecond ); if (!SUCCEEDED(hresult)) { return; } LogMessage(lpMessage); } ////////////////////////////////////////////////////////////////////////////////////
//
// GetLanguageGroup
//
// Retreive the Language Group of this locale.
//
////////////////////////////////////////////////////////////////////////////////////
LGRPID GetLanguageGroup(LCID lcid) { int i; gLangGroup = LGRPID_WESTERN_EUROPE; gFoundLangGroup = FALSE; gLCID = lcid; for (i=0 ; i<gNumLanguageGroups; i++) { // The globals gLangGroup and gFoundLangGroup is used in the callback function
// EnumLanguageGroupLocalesProc.
gpfnEnumLanguageGroupLocalesW(EnumLanguageGroupLocalesProc, gLanguageGroups[i], 0L, 0L); //
// If we found it, then break now
//
if (gFoundLangGroup) break; } return gLangGroup; } BOOL EnumLanguageGroupLocalesProc( LGRPID langGroupId, LCID lcid, LPTSTR lpszLocale, LONG_PTR lParam) { if (lcid == gLCID) { gLangGroup = langGroupId; gFoundLangGroup = TRUE; // stop iterating
return FALSE; } // next iteration
return TRUE; } ////////////////////////////////////////////////////////////////////////////////////
//
// DetectLanguageGroups
//
// Detect language groups installed.
//
////////////////////////////////////////////////////////////////////////////////////
BOOL DetectLanguageGroups(HWND hwndDlg) { int i; HWND hwndList = GetDlgItem(hwndDlg, IDC_LIST1); HWND hwndProgress, hwndStatus,hProgDlg; int iCount = ListView_GetItemCount(hwndList); LVITEM lvItem; PMUILANGINFO pMuiLangInfo; TCHAR szBuf[MAX_PATH], szStatus[MAX_PATH]; PVOID ppArgs[1]; hProgDlg = CreateDialog(ghInstance, MAKEINTRESOURCE(IDD_DIALOG_INSTALL_PROGRESS), hwndDlg, ProgressDialogFunc); hwndProgress = GetDlgItem(hProgDlg, IDC_PROGRESS1); hwndStatus = GetDlgItem(hProgDlg, IDC_STATUS); //
// Reflect that we doing something on the UI
//
LoadString(ghInstance, IDS_INSTALLLANGGROUP, szBuf, MAX_PATH-1); SetWindowText(hProgDlg, szBuf); SendMessage(hwndProgress, PBM_SETRANGE, (WPARAM)(int)0, (LPARAM)MAKELPARAM(0, iCount)); SendMessage(hwndProgress, PBM_SETPOS, (WPARAM)(int)(0), 0); SetWindowText(hwndStatus, TEXT("")); i = 0; while (i < iCount) { //
// Check if Language Group is installed
//
lvItem.mask = LVIF_PARAM; lvItem.iItem = i; lvItem.iSubItem = 0; lvItem.state = 0; lvItem.stateMask = 0; lvItem.pszText = 0; lvItem.cchTextMax = 0; lvItem.iImage = 0; lvItem.lParam = 0; ListView_GetItem(hwndList, &lvItem); pMuiLangInfo = (PMUILANGINFO)lvItem.lParam; SendMessage(hwndProgress, PBM_SETPOS, (WPARAM)(int)i+1, 0L); LoadString(ghInstance, IDS_CHECK_LANG_GROUP, szStatus, MAX_PATH-1); if (pMuiLangInfo->szDisplayName[0] == L'\0') { GetDisplayName(pMuiLangInfo); } ppArgs[0] = pMuiLangInfo->szDisplayName; FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, szStatus, 0, 0, szStatus, MAX_PATH-1, (va_list *)ppArgs); SetWindowText(hwndStatus, szStatus); pMuiLangInfo->lgrpid = GetLanguageGroup(pMuiLangInfo->lcid); i++; }; SendMessage(hwndProgress, PBM_SETPOS, (WPARAM)(int)i+1, 0L); DestroyWindow(hProgDlg); return TRUE; } ////////////////////////////////////////////////////////////////////////////////////
//
// AddExtraLangGroupsFromINF
//
// Look at the [LanguagePack] section to see if we need to install extra
// language packs for the language specified in lpszLcid.
//
// This is basically used to support pseudo localized build.
//
// Parameter:
// lpszLcid the LCID of UI language to be installed in string form.
// pInstallLangGroup points to a strcutre which stores language groups to be installed.
//
// Remarks:
//
// 10-11-2000 YSLin Created.
////////////////////////////////////////////////////////////////////////////////////
BOOL AddExtraLangGroupsFromINF(LPTSTR lpszLcid, PINSTALL_LANG_GROUP pInstallLangGroup) { WCHAR szBuffer[BUFFER_SIZE]; HINF hInf; INFCONTEXT InfContext; LONG_PTR lppArgs[2]; int LangGroup; int i; HRESULT hresult; if (!pInstallLangGroup) { return FALSE; } hInf = SetupOpenInfFile(g_szMUIInfoFilePath, NULL, INF_STYLE_WIN4, NULL); if (hInf == INVALID_HANDLE_VALUE) { //*STRSAFE* _stprintf(szBuffer, TEXT("%d"), GetLastError());
hresult = StringCchPrintf(szBuffer , ARRAYSIZE(szBuffer), TEXT("%d"), GetLastError()); if (!SUCCEEDED(hresult)) { return FALSE; } lppArgs[0] = (LONG_PTR)szBuffer; lppArgs[1] = (LONG_PTR)g_szMUIInfoFilePath; LogFormattedMessage(ghInstance, IDS_NO_READ_L, lppArgs); return (FALSE); } if (SetupFindFirstLine(hInf, MUI_LANGPACK_SECTION, lpszLcid, &InfContext)) { i = 1; while (SetupGetIntField(&InfContext, i++, &LangGroup)) { AddMUILangGroup(pInstallLangGroup, LangGroup); } } SetupCloseInfFile(hInf); return (TRUE); } ////////////////////////////////////////////////////////////////////////////////////
//
// ConvertMUILangToLangGroup
//
// Generate Lang-Group IDs for the selected items in the listview,
// in preparation to pass them to InstallLanguageGroups(...)
////////////////////////////////////////////////////////////////////////////////////
BOOL ConvertMUILangToLangGroup(HWND hwndDlg, PINSTALL_LANG_GROUP pInstallLangGroup) { int i; LVITEM lvItem; HWND hwndList = GetDlgItem(hwndDlg, IDC_LIST1); int iCount = ListView_GetItemCount(hwndList); PMUILANGINFO pMuiLangInfo;
if (!pInstallLangGroup) { return FALSE; } //
// Initialize to "No lang-groups to install"
//
pInstallLangGroup->iCount = 0L; i = 0; while (i < iCount) { if (ListView_GetCheckState(hwndList, i)) { //
// Check if Language Group is installed
//
lvItem.mask = LVIF_PARAM; lvItem.iItem = i; lvItem.iSubItem = 0; lvItem.state = 0; lvItem.stateMask = 0; lvItem.pszText = 0; lvItem.cchTextMax = 0; lvItem.iImage = 0; lvItem.lParam = 0; ListView_GetItem(hwndList, &lvItem); pMuiLangInfo = (PMUILANGINFO)lvItem.lParam; //
// Make sure there are no redundant elements
//
AddMUILangGroup(pInstallLangGroup, pMuiLangInfo->lgrpid); //
// Add extra language groups specified in [LangPack] section of mui.inf
// This is used to support Pesudo Localized Build.
//
AddExtraLangGroupsFromINF(pMuiLangInfo->lpszLcid, pInstallLangGroup); } i++; }; return TRUE; } ////////////////////////////////////////////////////////////////////////////////////
//
// AddMUILangGroup
//
// Add a language a group to INSTALL_LANG_GROUP. Takes care of duplicates.
////////////////////////////////////////////////////////////////////////////////////
BOOL AddMUILangGroup(PINSTALL_LANG_GROUP pInstallLangGroup, LGRPID lgrpid) { int j = 0L; BOOL bFound = FALSE; if (!pInstallLangGroup) { return FALSE; } //
// Check if it is installed by default
//
if (gpfnIsValidLanguageGroup(lgrpid, LGRPID_INSTALLED)) { return FALSE; } while (j < pInstallLangGroup->iCount) { if (pInstallLangGroup->lgrpid[j] == lgrpid) { bFound = TRUE; } j++; } if (!bFound) { pInstallLangGroup->lgrpid[j] = lgrpid; pInstallLangGroup->iCount++; return TRUE; } return FALSE; } ////////////////////////////////////////////////////////////////////////////////////
//
// RunRegionalOptionsApplet
//
// Run the Regional Option silent mode installation using the specified pCommands.
//
// This function will create the "[RegigionalSettings]" string, so there is no need
// to supply that in pCommands.
//
////////////////////////////////////////////////////////////////////////////////////
BOOL RunRegionalOptionsApplet(LPTSTR pCommands) { HANDLE hFile; TCHAR szFilePath[MAX_PATH], szCmdLine[MAX_PATH]; DWORD dwNumWritten = 0L; STARTUPINFO si; PROCESS_INFORMATION pi = {0}; int i; LONG_PTR lppArgs[3]; HRESULT hresult; TCHAR szRunDllPath[MAX_PATH]; TCHAR szSection[MAX_PATH] = TEXT("[RegionalSettings]\r\n"); if (!pCommands) { return FALSE; } //
// prepare the file for un-attended mode setup
//
szFilePath[0] = UNICODE_NULL; if (!pfnGetWindowsDir(szFilePath, MAX_PATH-1)) { return FALSE; } i = lstrlen(szFilePath); if (szFilePath[i-1] != TEXT('\\')) { //*STRSAFE* lstrcat(szFilePath, TEXT("\\"));
hresult = StringCchCat(szFilePath , ARRAYSIZE(szFilePath), TEXT("\\")); if (!SUCCEEDED(hresult)) { return FALSE; } } hresult = StringCchCopy(szRunDllPath , ARRAYSIZE(szRunDllPath), szFilePath); if (!SUCCEEDED(hresult)) { return FALSE; } //*STRSAFE* lstrcat(szFilePath, MUI_LANG_GROUP_FILE);
hresult = StringCchCat(szFilePath , ARRAYSIZE(szFilePath), MUI_LANG_GROUP_FILE); if (!SUCCEEDED(hresult)) { return FALSE; } hresult = StringCchCat(szRunDllPath , ARRAYSIZE(szRunDllPath), RUNDLLNAME); if (!SUCCEEDED(hresult)) { return FALSE; } hFile = CreateFile(szFilePath, GENERIC_WRITE, 0L, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hFile) { lppArgs[0] = (LONG_PTR)szFilePath; LogFormattedMessage(ghInstance, IDS_ERROR_FILE_CREATE, lppArgs); return FALSE; } WriteFile(hFile, szSection, (lstrlen(szSection) * sizeof(TCHAR)), &dwNumWritten, NULL); if (dwNumWritten != (lstrlen(szSection) * sizeof(TCHAR))) { lppArgs[0] = (LONG_PTR)szFilePath; LogFormattedMessage(ghInstance, IDS_ERROR_FILE_CREATE, lppArgs); CloseHandle(hFile); return FALSE; } WriteFile(hFile, pCommands, (lstrlen(pCommands) * sizeof(TCHAR)), &dwNumWritten, NULL); if (dwNumWritten != (lstrlen(pCommands) * sizeof(TCHAR))) { #if SAMER_DBG
OutputDebugString(TEXT("Unable to write to Language Groups to muilang.txt\n")); #endif
CloseHandle(hFile); return (FALSE); } CloseHandle(hFile); //
// Call the control panel regional-options applet, and wait for it to complete
//
//*STRSAFE* lstrcpy(szCmdLine, TEXT("rundll32 shell32,Control_RunDLL intl.cpl,, /f:\""));
hresult=StringCchPrintf(szCmdLine,ARRAYSIZE(szCmdLine),TEXT("\"%s\" shell32,Control_RunDLL intl.cpl,, /f:\""),szRunDllPath); if (!SUCCEEDED(hresult)) { DeleteFile(szFilePath); return FALSE; } //*STRSAFE* lstrcat(szCmdLine, szFilePath);
hresult = StringCchCat(szCmdLine , ARRAYSIZE(szCmdLine), szFilePath); if (!SUCCEEDED(hresult)) { DeleteFile(szFilePath); return FALSE; } // only pop up progress bar UI if we are showing UI "/g" param for intl.cpl dictates this
// also add a /D so that intl.cpl will not prompt for a source dialog if no UI is to be shown
if (!g_bNoUI) { //*STRSAFE* lstrcat(szCmdLine, TEXT("\"/g "f));
hresult = StringCchCat(szCmdLine , ARRAYSIZE(szCmdLine), TEXT("\" /g")); if (!SUCCEEDED(hresult)) { DeleteFile(szFilePath); return FALSE; } } else { #ifdef MUI_MAGIC
//*STRSAFE* lstrcat(szCmdLine, TEXT("\" /D"));
hresult = StringCchCat(szCmdLine , ARRAYSIZE(szCmdLine), TEXT("\" /D ")); // hresult = StringCchCat(szCmdLine , ARRAYSIZE(szCmdLine), TEXT("\" "));
if (!SUCCEEDED(hresult)) { DeleteFile(szFilePath); return FALSE; } #else
//*STRSAFE* lstrcat(szCmdLine, TEXT("\" /D"));
hresult = StringCchCat(szCmdLine , ARRAYSIZE(szCmdLine), TEXT("\" ")); // hresult = StringCchCat(szCmdLine , ARRAYSIZE(szCmdLine), TEXT("\" "));
if (!SUCCEEDED(hresult)) { DeleteFile(szFilePath); return FALSE; } #endif
}
// intl.cpl matches the UI font if /t is specified on the command line
if (g_bCmdMatchUIFont) { //*STRSAFE* lstrcat(szCmdLine, TEXT("/t "));
hresult = StringCchCat(szCmdLine , ARRAYSIZE(szCmdLine), TEXT("/t ")); if (!SUCCEEDED(hresult)) { DeleteFile(szFilePath); return FALSE; } }
memset( &si, 0x00, sizeof(si)); si.cb = sizeof(STARTUPINFO); if (!CreateProcess(NULL, szCmdLine, NULL, NULL, FALSE, 0L, NULL, NULL, &si, &pi)) { lppArgs[0] = (LONG_PTR)szCmdLine; LogFormattedMessage(ghInstance, IDS_ERROR_LAUNCH_INTLCPL, lppArgs); DeleteFile(szFilePath); return FALSE; } //
// Wait forever till intl.cpl terminates.
//
WaitForSingleObject(pi.hProcess, INFINITE); //
// Close Handle
//
CloseHandle( pi.hProcess ); CloseHandle( pi.hThread ); //
// Delete the File
//
DeleteFile(szFilePath); return (TRUE); } ////////////////////////////////////////////////////////////////////////////////////
//
// InstallLanguageGroups
//
// Checks whether a language group is needed to be installed or not. If
// any lang-group needs to be installed, then the routine will invoke
// the Regional-Options applet in unattended mode setup.
//
// Return:
// TURE if the operation succeeds. Otherwise FALSE.
//
////////////////////////////////////////////////////////////////////////////////////
BOOL InstallLanguageGroups(PINSTALL_LANG_GROUP pInstallLangGroup) { TCHAR pCommands[MAX_PATH]; int i, iCount = pInstallLangGroup->iCount; BOOL bFirstTime=FALSE; HRESULT hresult;
if (!pInstallLangGroup) { return FALSE; } //
// If nothing to do, then just return
//
if (0L == iCount) { return TRUE; } i = 0; while (i < iCount) { if (!gpfnIsValidLanguageGroup(pInstallLangGroup->lgrpid[i], LGRPID_INSTALLED)) { if (!bFirstTime) { bFirstTime = TRUE; //*STRSAFE* wsprintf(pCommands, TEXT("LanguageGroup = %d\0"), pInstallLangGroup->lgrpid[i]);
hresult = StringCchPrintf(pCommands , ARRAYSIZE(pCommands), TEXT("LanguageGroup = %d\0"), pInstallLangGroup->lgrpid[i]); if (!SUCCEEDED(hresult)) { return FALSE; } } else { //*STRSAFE* wsprintf(&pCommands[lstrlen(pCommands)], TEXT(",%d\0"), pInstallLangGroup->lgrpid[i]);
hresult = StringCchPrintf(&pCommands[lstrlen(pCommands)] , ARRAYSIZE(pCommands) -lstrlen(pCommands) , TEXT(",%d\0"), pInstallLangGroup->lgrpid[i]); if (!SUCCEEDED(hresult)) { return FALSE; } } } i++; }; if (!bFirstTime) { //
// There is no language group to be added.
return (FALSE); } return (RunRegionalOptionsApplet(pCommands)); } ////////////////////////////////////////////////////////////////////////////
//
// Muisetup_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 Muisetup_RebootTheSystem(void) { 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, SHTDN_REASON_FLAG_PLANNED | SHTDN_REASON_MAJOR_OPERATINGSYSTEM | SHTDN_REASON_MINOR_RECONFIG); AdjustTokenPrivileges( Token, FALSE, OldState, 0, NULL, NULL ); } } } } if (NewState != NULL) { LocalFree(NewState); } if (OldState != NULL) { LocalFree(OldState); } if (Token != NULL) { CloseHandle(Token); } } ////////////////////////////////////////////////////////////////////////////
//
// CheckForReboot
//
// Check if we need to reboot the system, if a lang group is installed
//
// Return:
// TRUE if we need user to reboot, otherwise FALSE.
//
////////////////////////////////////////////////////////////////////////////
BOOL CheckForReboot(HWND hwnd, PINSTALL_LANG_GROUP pInstallLangGroup) { int nIDS,nMask=MB_YESNO | MB_ICONQUESTION; if (!pInstallLangGroup) { return FALSE; } if (pInstallLangGroup->iCount || pInstallLangGroup->bFontLinkRegistryTouched || pInstallLangGroup->NotDeleted || g_bRemoveDefaultUI || g_bRemoveUserUI || g_bReboot) { if (g_bRemoveUserUI) { nIDS=IDS_MUST_REBOOT_STRING1; nMask=MB_YESNO | MB_ICONWARNING; } else if (g_bRemoveDefaultUI) { nMask=MB_YESNO | MB_ICONWARNING; nIDS=IDS_MUST_REBOOT_STRING2; } else { nIDS=IDS_REBOOT_STRING; }
SetForegroundWindow(hwnd); // muisetup lost focus when it show reboot dialog so we force it as foreground window.
if (DoMessageBox(hwnd, nIDS, IDS_MAIN_TITLE, nMask) == IDYES) { Muisetup_RebootTheSystem(); } return (TRUE); } return (FALSE); } ////////////////////////////////////////////////////////////////////////////
//
// Following code are stolen from intl.cpl
//
// We want to enumulate all installed UI languages
//
////////////////////////////////////////////////////////////////////////////
DWORD_PTR TransNum( LPTSTR lpsz) { DWORD dw = 0L; TCHAR c; if (!lpsz) { return dw; }
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); } BOOL MUIGetAllInstalledUILanguages() { pfnEnumUILanguages fnEnumUILanguages; BOOL result = TRUE; HINSTANCE hKernel32; //
// Enumerate the installed UI languages.
//
g_UILanguageGroup.iCount = 0L; hKernel32 = LoadLibrary(TEXT("kernel32.dll")); fnEnumUILanguages = (pfnEnumUILanguages)GetProcAddress(hKernel32, "EnumUILanguagesW"); if (fnEnumUILanguages == NULL) { result = FALSE; } else { fnEnumUILanguages(Region_EnumUILanguagesProc, 0, (LONG_PTR)&g_UILanguageGroup); } FreeLibrary(hKernel32); return (result); } BOOL CALLBACK Region_EnumUILanguagesProc( LPWSTR pwszUILanguage, LONG_PTR lParam) { int Ctr = 0; LGRPID lgrp; PUILANGUAGEGROUP pUILangGroup = (PUILANGUAGEGROUP)lParam; if ( (!pwszUILanguage) || (!pUILangGroup)) { return FALSE; } LCID UILanguage = (LCID)TransNum( pwszUILanguage ); if (UILanguage) { while (Ctr < pUILangGroup->iCount) { if (pUILangGroup->lcid[Ctr] == UILanguage) { break; } Ctr++; } //
// Theoritically, we won't go over 64 language groups!
//
if ((Ctr == pUILangGroup->iCount) && (Ctr < MAX_UI_LANG_GROUPS)) { pUILangGroup->lcid[Ctr] = UILanguage; pUILangGroup->iCount++; } } return (TRUE); } BOOL IsSpaceEnough(HWND hwndDlg,INT64 *ulSizeNeed,INT64 *ulSizeAvailable) { HWND hList; LGRPID lgrpid[MAX_MUI_LANGUAGES]; LPTSTR lpszLcid; int iIndex; int i = 0; int iCount=0,iArrayIndex=0; PMUILANGINFO pMuiLangInfo; BOOL bChked,bResult=TRUE; INT64 ulTotalBytesRequired=0,ulSpaceAvailable; TCHAR szWinDir[MAX_PATH]; BOOL bFELangpackAdded = FALSE; ULARGE_INTEGER ulgiFreeBytesAvailableToCaller; ULARGE_INTEGER ulgiTotalNumberOfBytes; if ((!ulSizeNeed) || (!ulSizeAvailable)) { return FALSE; } *ulSizeNeed=0; *ulSizeAvailable=0; hList=GetDlgItem(hwndDlg, IDC_LIST1); iIndex = ListView_GetItemCount(hList); while(i<iIndex) { bChked=ListView_GetCheckState(hList, i); GetMuiLangInfoFromListView(hList, i, &pMuiLangInfo); lpszLcid = pMuiLangInfo->lpszLcid; //
// Install required
//
if (bChked && !IsInstalled(lpszLcid) && HaveFiles(lpszLcid)) { if (!gpfnIsValidLanguageGroup(pMuiLangInfo->lgrpid, LGRPID_INSTALLED)) { for(iArrayIndex=0;iArrayIndex < iCount;iArrayIndex++) { if (lgrpid[iArrayIndex]==pMuiLangInfo->lgrpid) break; } if(iArrayIndex == iCount) { if (IS_FE_LANGPACK(pMuiLangInfo->lcid)) { if (!bFELangpackAdded) { ulTotalBytesRequired+=pMuiLangInfo->ulLPKSize; bFELangpackAdded = TRUE; } } else { ulTotalBytesRequired+=pMuiLangInfo->ulLPKSize; } lgrpid[iCount]= pMuiLangInfo->lgrpid; iCount++; } } ulTotalBytesRequired+=pMuiLangInfo->ulUISize; } // Uninstall required
if (!bChked && IsInstalled(lpszLcid)) { ulTotalBytesRequired-=pMuiLangInfo->ulUISize; } i++; } //
// Let's check available disk space of system drive
//
pfnGetWindowsDir( szWinDir, MAX_PATH); szWinDir[3]=TEXT('\0'); if (GetDiskFreeSpaceEx(szWinDir, &ulgiFreeBytesAvailableToCaller, &ulgiTotalNumberOfBytes, NULL)) { ulSpaceAvailable= ulgiFreeBytesAvailableToCaller.QuadPart; if ( ulSpaceAvailable < ulTotalBytesRequired ) { *ulSizeNeed =ulTotalBytesRequired; *ulSizeAvailable=ulSpaceAvailable; bResult=FALSE; } } return bResult; } void ExitFromOutOfMemory() { LONG_PTR lppArgs[1]; lppArgs[0] = (LONG_PTR)GetLastError(); DoMessageBox(NULL, IDS_OUT_OF_MEMORY, IDS_MAIN_TITLE, MB_ICONEXCLAMATION | MB_OK); LogFormattedMessage(ghInstance, IDS_OUT_OF_MEMORY_L, lppArgs); ExitProcess(1); } ////////////////////////////////////////////////////////////////////////////
//
// Call the kernel to notify it that a new language is being added or
// removed
//
////////////////////////////////////////////////////////////////////////////
void NotifyKernel( LPTSTR LangList, ULONG Flags ) { HANDLE Handle; WMILANGUAGECHANGE LanguageChange; ULONG ReturnSize; BOOL IoctlSuccess; HRESULT hresult; if ((LangList != NULL) && (*LangList != 0)) { Handle = CreateFile(WMIAdminDeviceName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (Handle != INVALID_HANDLE_VALUE) { while (*LangList != 0) { memset(&LanguageChange, 0, sizeof(LanguageChange)); //*STRSAFE* _tcscpy(LanguageChange.Language, LangList);
hresult = StringCchCopy(LanguageChange.Language , MAX_LANGUAGE_SIZE, LangList); if (!SUCCEEDED(hresult)) { CloseHandle(Handle); return ; } LanguageChange.Flags = Flags; IoctlSuccess = DeviceIoControl(Handle, IOCTL_WMI_NOTIFY_LANGUAGE_CHANGE, &LanguageChange, sizeof(LanguageChange), NULL, 0, &ReturnSize, NULL); #if ALANWAR_DBG
{ WCHAR Buf[256]; //*STRSAFE* wsprintf(Buf, L"MUISetup: Notify Lang change -> %d for %ws\n", GetLastError(), LangList);
hresult = StringCchPrintfW(Buf , ARRAYSIZE(Buf), L"MUISetup: Notify Lang change -> %d for %ws\n", GetLastError(), LangList); if (!SUCCEEDED(hresult)) { CloseHandle(Handle); return ; } OutputDebugStringW(Buf); } #endif
while (*LangList++ != 0) ; } CloseHandle(Handle); } } } //
// Query MUI registry setting
//
BOOL CheckMUIRegSetting(DWORD dwFlag) { BOOL bRet = FALSE; HKEY hKey; if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_MUI_SETTING, 0, KEY_READ, &hKey)) { DWORD dwValue; DWORD dwSize = sizeof(dwValue); DWORD dwType; if (ERROR_SUCCESS == RegQueryValueEx(hKey, (dwFlag & MUI_MATCH_UIFONT)? REGSTR_VALUE_MATCH_UIFONT : REGSTR_VALUE_MATCH_LOCALE, 0, &dwType, (LPBYTE)&dwValue, &dwSize)) { bRet = (BOOL) dwValue; } RegCloseKey(hKey); } return bRet; } //
// Set MUI registry setting
//
BOOL SetMUIRegSetting(DWORD dwFlag, BOOL bEnable) { BOOL bRet = FALSE; HKEY hKey; if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_LOCAL_MACHINE, REGSTR_MUI_SETTING, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,NULL, &hKey, NULL)) { DWORD dwValue = (DWORD) bEnable; if (ERROR_SUCCESS == RegSetValueEx(hKey, (dwFlag & MUI_MATCH_UIFONT)? REGSTR_VALUE_MATCH_UIFONT : REGSTR_VALUE_MATCH_LOCALE, 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(DWORD))) { bRet = TRUE; } RegCloseKey(hKey); } return bRet; } //
// Delete MUI registry setting
//
BOOL DeleteMUIRegSetting() { BOOL bRet = TRUE; HKEY hKey; TCHAR tcMessage[BUFFER_SIZE]; if (ERROR_SUCCESS ==RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_MUI_SETTING, 0, KEY_ALL_ACCESS, &hKey)) { DWORD dwValue; DWORD dwSize = sizeof(dwValue); DWORD dwType; if (ERROR_SUCCESS == RegQueryValueEx(hKey, REGSTR_VALUE_MATCH_UIFONT, 0, &dwType, (LPBYTE)&dwValue, &dwSize)) { if (RegDeleteValue(hKey, REGSTR_VALUE_MATCH_UIFONT) != ERROR_SUCCESS) { wnsprintf(tcMessage, ARRAYSIZE(tcMessage) ,TEXT("MuiSetup: DeleteMUIRegSetting: WARNING - Failed to delete regkey HKLM\\%s regvalue %s"), REGSTR_MUI_SETTING,REGSTR_VALUE_MATCH_UIFONT); LogMessage(tcMessage); bRet = FALSE; } } dwSize = sizeof(dwValue); if (ERROR_SUCCESS == RegQueryValueEx(hKey, REGSTR_VALUE_MATCH_LOCALE, 0, &dwType, (LPBYTE)&dwValue, &dwSize)) { if (RegDeleteValue(hKey, REGSTR_VALUE_MATCH_LOCALE) != ERROR_SUCCESS) { wnsprintf(tcMessage, ARRAYSIZE(tcMessage) ,TEXT("MuiSetup: DeleteMUIRegSetting: WARNING - Failed to delete regkey HKLM\\%s regvalue %s"), REGSTR_MUI_SETTING,REGSTR_VALUE_MATCH_LOCALE); LogMessage(tcMessage); bRet = FALSE; } } RegCloseKey(hKey); } return bRet; } ////////////////////////////////////////////////////////////////////////////
//
// 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 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 = DeleteRegTree(hKey, szSubKey); } } RegCloseKey(hKey); } else if (dwRtn == ERROR_FILE_NOT_FOUND) { dwRtn = ERROR_SUCCESS; } } else { dwRtn = ERROR_BADKEY; } return (dwRtn); } ////////////////////////////////////////////////////////////////////////////////////
//
// InstallExternalComponents
//
//
// Return:
// TURE if the operation succeeds. Otherwise FALSE.
//
////////////////////////////////////////////////////////////////////////////////////
BOOL InstallExternalComponents(LPTSTR Languages) { BOOL bRet = TRUE; TCHAR lpMessage[BUFFER_SIZE];
if (! Languages) { return FALSE; } //
// call WBEM API to mofcompile MUI MFL's for each language
//
if (!MofCompileLanguages(Languages)) { //
// LOG: Error mofcompiling
//
LoadString(ghInstance, IDS_MOFCOMPILE_L, lpMessage, ARRAYSIZE(lpMessage)-1); LogMessage(lpMessage); bRet = FALSE; } if (bRet) { //
// Inform kernel that new languages have been added
//
NotifyKernel(Languages, WMILANGUAGECHANGE_FLAG_ADDED); } return bRet; } ////////////////////////////////////////////////////////////////////////////////////
//
// UninstallExternalComponents
//
////////////////////////////////////////////////////////////////////////////////////
VOID UninstallExternalComponents(LPTSTR Languages) { if (!Languages) { return ; } //
// Inform kernel that new languages have been added
//
NotifyKernel(Languages, WMILANGUAGECHANGE_FLAG_REMOVED); }
|