|
|
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2001, Microsoft Corporation All rights reserved.
//
// Module Name:
//
// euroconv.c
//
// Abstract:
//
// This file contains the entry point of the euroconv.exe utility.
//
// NOTE: If you want to add exception for new locale, please add it to the
// base list named gBaseEuroException. See the structure definition for more
// information. Empty string represented by "\0" means that we don't need
// to update the information. The chThousandSep member of gBaseEuroException
// should always be different from "\0".
//
// Revision History:
//
// 2001-07-30 lguindon Created.
//
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//
// Includes Files.
//
///////////////////////////////////////////////////////////////////////////////
#include "euroconv.h"
#include "util.h"
#include "welcome.h"
#include "confirm.h"
///////////////////////////////////////////////////////////////////////////////
//
// Global variable.
//
///////////////////////////////////////////////////////////////////////////////
EURO_EXCEPTION gBaseEuroException[] = { {0x00000403, "\0", "2", "."}, // Catalan - Spain
{0x00000407, "\0", "\0", "."}, // German - Germany
{0x00000c07, "\0", "\0", "."}, // German - Austria
{0x00001007, "\0", "\0", "."}, // German - Luzembourg
{0x00000408, "\0", "\0", "."}, // Greek - Greece
{0x00001809, ".", "\0", ","}, // English - Ireland
{0x0000040a, "\0", "2", "."}, // Spanish - Spain (traditional sort)
{0x00000c0a, "\0", "2", "."}, // Spanish - Spain (international sort)
{0x0000040b, "\0", "\0", " "}, // Finnish - Finland
{0x0000040c, "\0", "\0", " "}, // French - France
{0x0000080c, "\0", "\0", "."}, // French - Belgium
{0x0000140c, "\0", "\0", " "}, // French - Luxembourg
{0x0000180c, "\0", "\0", " "}, // French - Monaco
{0x00000410, ",", "2", "."}, // Italian - Italy
{0x00000413, "\0", "\0", "."}, // Dutch - Netherlands
{0x00000813, "\0", "\0", "."}, // Dutch - Belgium
{0x00000816, ",", "\0", "."}, // Portuguese - Portugal
{0x0000081d, "\0", "\0", " "}, // Swedish - Finland
{0x0000042d, "\0", "2", "."}, // Basque - Spain
{0x00000456, "\0", "\0", "."} // Galician - Spain
}; UINT gNbBaseEuroException = sizeof(gBaseEuroException)/sizeof(EURO_EXCEPTION);
UINT gNbOverrideEuroException = 0; PEURO_EXCEPTION gOverrideEuroException; HGLOBAL hOverrideEuroException = NULL;
HINSTANCE ghInstance = NULL;
BOOL gbSilence = FALSE; BOOL gbAll = TRUE; DWORD gdwVersion = (-1); #ifdef DEBUG
BOOL gbPatchCheck = TRUE; #endif // DEBUG
const CHAR c_szCPanelIntl[] = "Control Panel\\International"; const CHAR c_szCPanelIntl_DefUser[] = ".DEFAULT\\Control Panel\\International"; const CHAR c_szLocale[] = "Locale"; const CHAR c_szCurrencySymbol[] = "sCurrency"; const WCHAR c_wszCurrencySymbol[] = L"sCurrency"; const CHAR c_szCurrencyDecimalSep[] = "sMonDecimalSep"; const CHAR c_szCurrencyThousandSep[] = "sMonThousandSep"; const CHAR c_szCurrencyDigits[] = "iCurrDigits"; const CHAR c_szIntl[] = "intl";
HINSTANCE hUserenvDLL = NULL; BOOL (*pfnGetProfilesDirectory)(LPSTR, LPDWORD) = NULL;
HINSTANCE hUser32DLL = NULL; long (*pfnBroadcastSystemMessage)(DWORD, LPDWORD, UINT, WPARAM, LPARAM) = NULL;
HINSTANCE hNtdllDLL = NULL; LONG (*pfnRtlAdjustPrivilege)(ULONG, BOOLEAN, BOOLEAN, PBOOLEAN) = NULL;
///////////////////////////////////////////////////////////////////////////////
//
// Prototypes.
//
///////////////////////////////////////////////////////////////////////////////
BOOL ParseCmdLine(LPSTR argIndex); DWORD ApplyEuroSettings(); DWORD ApplyEuroSettingsToRegistry(); DWORD ApplyEuroSettingsToFile(); BOOL UpdateFileLocaleInfo(LPCSTR szProfile, PEURO_EXCEPTION pInfo); BOOL UpdateRegLocaleInfo(HKEY hKey, PEURO_EXCEPTION pInfo); BOOL UpdateLocaleInfo(HKEY hKey, PEURO_EXCEPTION pInfo); void Usage();
///////////////////////////////////////////////////////////////////////////////
//
// Main entry point.
//
///////////////////////////////////////////////////////////////////////////////
INT APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow) { DWORD dwRecipients; DWORD nbChanged; //
// Save instance.
//
ghInstance = hInstance;
//
// Set language.
//
// SetThreadLocale((LCID)0x00001809); // English - Ireland
// SetThreadLocale((LCID)0x0000040c); // French - France
// SetThreadLocale((LCID)0x0000080c); // French - Belgium
// SetThreadLocale((LCID)0x0000140c); // French - Luxembourg
// SetThreadLocale((LCID)0x0000180c); // French - Monaco
// SetThreadLocale((LCID)0x00000410); // Italian - Italia
// SetThreadLocale((LCID)0x0000040b); // Finnish - Finland
// SetThreadLocale((LCID)0x00000408); // Greek - Greece
// SetThreadLocale((LCID)0x00000816); // Portuguese - Portugal
// SetThreadLocale((LCID)0x00000403); // Catalan - Spain
// SetThreadLocale((LCID)0x0000040a); // Spanish - Spain (traditional sort)
// SetThreadLocale((LCID)0x00000c0a); // Spanish - Spain (international sort)
// SetThreadLocale((LCID)0x0000042d); // Basque - Spain
// SetThreadLocale((LCID)0x00000456); // Galician - Spain
// SetThreadLocale((LCID)0x00000407); // German - Germany
// SetThreadLocale((LCID)0x00000c07); // German - Austria
// SetThreadLocale((LCID)0x00001007); // German - Luzembourg
// SetThreadLocale((LCID)0x0000081d); // Swedish - Finland
// SetThreadLocale((LCID)0x00000413); // Dutch - Netherlands
// SetThreadLocale((LCID)0x00000813); // Dutch - Belgium
//
// Parse command line arguments.
//
if (!ParseCmdLine(lpCmdLine)) { return (-1); }
//
// Install the patch. The path for UI and Non-UI cases are seperated for
// cleared understanding of both cases.
//
if (!gbSilence) { //
// Verify administrative privileges.
//
if (gbAll && !IsAdmin()) { if (ShowMsg(NULL, IDS_NOADMIN, IDS_TITLE, MB_YN_OOPS) == IDYES) { gbAll = FALSE; } else { CleanUp(hOverrideEuroException); return (0); } } //
// Verify if Euro patch is there.
//
if (!IsEuroPatchInstalled()) { ShowMsg(NULL, IDS_PATCH, IDS_TITLE, MB_OK_OOPS); CleanUp(hOverrideEuroException); return (-1); }
//
// Load needed library
//
if (!IsWindows9x() && gbAll) { if (!LoadLibraries()) { ShowMsg(NULL, IDS_LIB_ERROR, IDS_TITLE, MB_OK_OOPS); CleanUp(hOverrideEuroException); return (-1); } }
//
// Show welcome screen.
//
if (!WelcomeDialog()) { CleanUp(hOverrideEuroException); return (0); } //
// Show Confirmation dialog.
//
if (!ConfirmDialog()) { CleanUp(hOverrideEuroException); return (0); } //
// Apply EURO changes.
//
if ((nbChanged = ApplyEuroSettings()) != 0) { //
// Show success message.
//
if (IsWindows9x()) { if (ShowMsg(NULL, IDS_SUCCESS, IDS_TITLE, MB_YESNO | MB_ICONQUESTION) == IDYES) { RebootTheSystem(); } } else { if (ShowMsg(NULL, IDS_SUCCESS_DEF, IDS_TITLE, MB_YESNO | MB_ICONQUESTION) == IDYES) { if (gbAll) { RebootTheSystem(); } } } } else { ShowMsg(NULL, IDS_NOTHING, IDS_TITLE, MB_OK_OOPS); } } else { //
// Verify administrative privileges.
//
if (!IsAdmin()) { gbAll = FALSE; }
//
// Load libraries.
//
if (!IsWindows9x() && gbAll) { LoadLibraries(); }
//
// Verify if the patch is installed.
//
if (IsEuroPatchInstalled()) { //
// Apply Euro settings.
//
nbChanged = ApplyEuroSettings(); } }
//
// Broadcast the message that the international settings in the
// registry have changed.
//
if ((nbChanged != 0) && pfnBroadcastSystemMessage) { dwRecipients = BSM_APPLICATIONS | BSM_ALLDESKTOPS; (*pfnBroadcastSystemMessage)( BSF_FORCEIFHUNG | BSF_IGNORECURRENTTASK | BSF_NOHANG | BSF_NOTIMEOUTIFNOTHUNG, &dwRecipients, WM_WININICHANGE, 0, (LPARAM)c_szIntl ); }
//
// Unload unneeded library
//
UnloadLibraries(); CleanUp(hOverrideEuroException);
// Make sure we return "failure" (non-zero) if no info was changed. This would
// apply to both (a) permission problems and (b) being outside the Euro zone.
return (((nbChanged != 0) ? 0 : -1)); }
///////////////////////////////////////////////////////////////////////////////
//
// ParseCmdLine
//
// Parse the command line and search for supported argument.
//
///////////////////////////////////////////////////////////////////////////////
BOOL ParseCmdLine(LPSTR argIndex) { //
// Parse the command line.
//
while (argIndex = NextCommandArg(argIndex)) { switch(*argIndex) { case('s'): // Silent mode
case('S'): { gbSilence = TRUE; break; } case('c'): // Current user only
case('C'): { gbAll = FALSE; break; } case('a'): // Exception
case('A'): { UINT nbException = 1; UINT idx = 0; LPSTR strPtrHead; LPSTR strPtrTail; BOOL bInsideQuote = FALSE;
//
// Change the separator used between each block in order to avoid
// mistake with the data itself inside the double quote.
//
strPtrHead = argIndex + 2; while (*strPtrHead) { if (*strPtrHead == '"') { bInsideQuote = bInsideQuote ? FALSE : TRUE; } else if (*strPtrHead == ';') { if (!bInsideQuote) { *strPtrHead = '@'; } } strPtrHead++; }
//
// Compute the number of exception override.
//
strPtrHead = argIndex + 2; while (strPtrHead = strchr(strPtrHead, '@')) { strPtrHead++; nbException++; }
//
// Allocation a structure for exception override.
//
if (!(hOverrideEuroException = GlobalAlloc(GHND, sizeof(EURO_EXCEPTION)*nbException))) { return (FALSE); } gOverrideEuroException = GlobalLock(hOverrideEuroException); gNbOverrideEuroException = nbException;
//
// Fill out the structure.
//
strPtrHead = argIndex + 2; while (idx < nbException) { CHAR buffer[128]; UINT strLen; //
// Extract the exception override information.
//
if (strPtrTail = strchr(strPtrHead, '@')) { strLen = (UINT)(strPtrTail - strPtrHead); } else { strLen = strlen(strPtrHead); }
//
// Copy the triplet.
//
strncpy(buffer, strPtrHead, strLen + 1);
//
// Add to the exception override list.
//
AddExceptionOverride(&gOverrideEuroException[idx], buffer);
//
// Next triplet.
//
if (strPtrTail) { strPtrHead = strPtrTail + 1; } idx++; } break; } #ifdef DEBUG
case('z'): // private flag for disabling the patch detection.
case('Z'): { gbPatchCheck = FALSE; break; } #endif // DEBUG
case('h'): // Usage
case('H'): // Usage
case('?'): { Usage(); return (FALSE); } default: { //
// Usage.
//
if (!gbSilence) { Usage(); } return (FALSE); } } } return (TRUE); }
///////////////////////////////////////////////////////////////////////////////
//
// ApplyEuroSettings
//
// Apply new Euro settings to the current user and/or to all user.
//
///////////////////////////////////////////////////////////////////////////////
DWORD ApplyEuroSettings() { HCURSOR hcurSave; DWORD nbChanged; //
// Show hour glass
//
hcurSave = SetCursor(LoadCursor(NULL, IDC_WAIT));
//
// Update available registry information.
//
nbChanged = ApplyEuroSettingsToRegistry(); //
// This is not complete because Windows NT security don't
// allows to change other users because information in
// registry is not available
//
if (!IsWindows9x()) { //
// Update all NTUSER.DAT file. This way we can update all users.
//
nbChanged += ApplyEuroSettingsToFile(); } //
// Revert cursor and return number changed.
//
SetCursor(hcurSave); return (nbChanged); }
///////////////////////////////////////////////////////////////////////////////
//
// ApplyEuroSettingsToFile
//
// Apply new Euro settings to the current user and/or to all user.
//
///////////////////////////////////////////////////////////////////////////////
DWORD ApplyEuroSettingsToFile() { LCID locale; PEURO_EXCEPTION pInfo; DWORD nbAffected = 0; //
// Proceed with all users if requested.
//
if (gbAll) { CHAR docFolder[MAX_PATH] = {0}; CHAR userFileData[MAX_PATH] = {0}; CHAR searchPattern[MAX_PATH] = {0}; WIN32_FIND_DATA fileData; HANDLE hList;
//
// Get Documents and Settings folder
//
if (!GetDocumentAndSettingsFolder(docFolder)) { return (nbAffected); }
//
// Append a wildcard after the directory path to find
// out all files/folders under it.
//
//strcpy(searchPattern, docFolder);
//strcat(searchPattern, "\\*.*");
StringCbCopy(searchPattern, MAX_PATH, docFolder); StringCbCatA(searchPattern, MAX_PATH, "\\*.*"); //
// List all files/folder under the profile directory
//
hList = FindFirstFile(searchPattern, &fileData); if (hList == INVALID_HANDLE_VALUE) { return (nbAffected); }
//
// Search through the Documents and settings folder for users.
//
do { //
// Check if it's a directory
//
if (fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { //
// Build a full path for the User data file.
//
//strcpy(userFileData, docFolder);
//strcat(userFileData, "\\");
//strcat(userFileData, fileData.cFileName);
//strcat(userFileData, "\\NTUSER.DAT");
StringCbCopy(userFileData, MAX_PATH, docFolder); StringCbCatA(userFileData, MAX_PATH, "\\"); StringCbCatA(userFileData, MAX_PATH, fileData.cFileName); StringCbCatA(userFileData, MAX_PATH, "\\NTUSER.DAT");
//
// Check if the file is associated to a valid user and
// get user locale from the user data file.
//
if (IsValidUserDataFile(userFileData) && (locale = GetLocaleFromFile(userFileData))) { //
// Search for an exception.
//
if ((pInfo = GetLocaleOverrideInfo(locale)) != NULL) { if( UpdateFileLocaleInfo(userFileData, pInfo)) { nbAffected++; } } } } } while (FindNextFile(hList, &fileData)); //
// Close handle.
//
FindClose(hList); }
return (nbAffected); }
///////////////////////////////////////////////////////////////////////////////
//
// ApplyEuroSettingsToRegistry
//
// Apply new Euro settings to the current user and/or to all user.
//
///////////////////////////////////////////////////////////////////////////////
DWORD ApplyEuroSettingsToRegistry() { LCID locale; PEURO_EXCEPTION pInfo; DWORD nbAffected = 0; //
// Proceed with all users if requested.
//
if (gbAll) { DWORD dwKeyLength, dwKeyIndex = 0; CHAR szKey[REGSTR_MAX_VALUE_LENGTH]; // this should be dynamic.
HKEY hKey; DWORD lRet; LPSTR endPtr;
//
// Go through all users for registry settings.
//
for (;;) { dwKeyLength = REGSTR_MAX_VALUE_LENGTH; lRet = RegEnumKeyEx( HKEY_USERS, dwKeyIndex, szKey, &dwKeyLength, NULL, NULL, NULL, NULL );
if (lRet == ERROR_NO_MORE_ITEMS) { lRet = ERROR_SUCCESS; break; } else if (lRet == ERROR_SUCCESS) { //
// Open the registry
//
if (RegOpenKeyEx( HKEY_USERS, szKey, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { //
// Get user locale
//
if (locale = GetLocaleFromRegistry(hKey)) { //
// Search for an exception.
//
if ((pInfo = GetLocaleOverrideInfo(locale)) != NULL) { if (UpdateRegLocaleInfo(hKey, pInfo)) { nbAffected++; } } } //
// Close handle
//
RegCloseKey(hKey); } } else { break; }
//
// Next keys
//
++dwKeyIndex; } } else { //
// Update current user settings.
//
locale = GetUserDefaultLCID(); if ((pInfo = GetLocaleOverrideInfo(locale)) != NULL) { if (UpdateRegLocaleInfo(HKEY_CURRENT_USER, pInfo)) { nbAffected++; } } }
return (nbAffected); }
///////////////////////////////////////////////////////////////////////////////
//
// GetLocaleOverrideInfo
//
// Search for locale information that need to be updated. First, search in
// the default table. Second, search in the override table for more locales.
//
///////////////////////////////////////////////////////////////////////////////
PEURO_EXCEPTION GetLocaleOverrideInfo(LCID locale) { UINT idx; PEURO_EXCEPTION euroException = NULL; //
// Search the base table. We still need to look in the second table even
// if found something in the first table because information can be
// overrided in the second table.
//
idx = 0; while (idx < gNbBaseEuroException) { if (LANGIDFROMLCID(locale) == LANGIDFROMLCID(gBaseEuroException[idx].dwLocale)) { euroException = &gBaseEuroException[idx]; break; } idx++; }
//
// Search the override table.
//
idx = 0; while (idx < gNbOverrideEuroException) { if (LANGIDFROMLCID(locale) == LANGIDFROMLCID(gOverrideEuroException[idx].dwLocale)) { euroException = &gOverrideEuroException[idx]; break; } idx++; }
return (euroException); }
///////////////////////////////////////////////////////////////////////////////
//
// UpdateRegLocaleInfo
//
// Update the registry values sCurrency, sMonDecimalSep and iCurrDigits if
// needed. Before applying the Decimal separator, we check is the Thousand
// separator is the same to the value in our table. In the case, we need to
// replacement also the the Thousand separator with our data.
//
///////////////////////////////////////////////////////////////////////////////
BOOL UpdateRegLocaleInfo(HKEY hKey, PEURO_EXCEPTION pInfo) { HKEY hIntlKey = NULL; BOOL bRet; //
// Open the International registry key.
//
if(RegOpenKeyEx( hKey, c_szCPanelIntl, 0, KEY_ALL_ACCESS, &hIntlKey) != ERROR_SUCCESS) { return (FALSE); }
//
// Update specific registry entries
//
bRet = UpdateLocaleInfo(hIntlKey, pInfo);
//
// Clean Up
//
RegCloseKey(hIntlKey); return (bRet); }
///////////////////////////////////////////////////////////////////////////////
//
// UpdateFileLocaleInfo
//
// Update the registry values sCurrency, sMonDecimalSep and iCurrDigits if
// needed. Before applying the Decimal separator, we check is the Thousand
// separator is the same to the value in our table. In the case, we need to
// replacement also the the Thousand separator with our data.
//
///////////////////////////////////////////////////////////////////////////////
BOOL UpdateFileLocaleInfo(LPCSTR szProfile, PEURO_EXCEPTION pInfo) { HKEY hIntlKey = NULL; BOOL bRet; BOOLEAN wasEnabled;
//
// Load hive.
//
if ((hIntlKey = LoadHive( szProfile, TEXT("TempKey"), c_szCPanelIntl, &wasEnabled )) == NULL) { return (FALSE); }
//
// Update specific registry entries
//
bRet = UpdateLocaleInfo(hIntlKey, pInfo);
//
// Unload hive
//
RegCloseKey(hIntlKey); UnloadHive(TEXT("TempKey"), &wasEnabled); return (bRet); }
///////////////////////////////////////////////////////////////////////////////
//
// UpdateLocaleInfo
//
///////////////////////////////////////////////////////////////////////////////
BOOL UpdateLocaleInfo(HKEY hIntlKey, PEURO_EXCEPTION pInfo) { //
// Update the sCurrency value. We have to use the Unicode version for
// Windows NTx because the euro character doesn't have the same ANSI
// value depending of the System Locale and it's associated Code Page.
// using the Unicode value fixes the problem.
//
if (IsWindows9x()) { //
// If the ACP code page is 1251, we need to store the proper value
// for the euro symbol.
//
if (GetACP() == 1251) { RegSetValueExA( hIntlKey, c_szCurrencySymbol, 0L, REG_SZ, (CONST BYTE *)"\x88", strlen("\x88") + 1); } else { RegSetValueExA( hIntlKey, c_szCurrencySymbol, 0L, REG_SZ, (CONST BYTE *)"\x80", strlen("\x80") + 1); } } else { RegSetValueExW( hIntlKey, c_wszCurrencySymbol, 0L, REG_SZ, (CONST BYTE *)L"\x20AC", wcslen(L"\x20AC") + 1); }
//
// Update the sMonDecimalSep value.
//
if( pInfo->chDecimalSep[0] != '\0' ) { RegSetValueEx( hIntlKey, c_szCurrencyDecimalSep, 0L, REG_SZ, (CONST BYTE *)pInfo->chDecimalSep, strlen(pInfo->chDecimalSep)+1); }
//
// Update the iCurrDigits value if needed.
//
if( pInfo->chDigits[0] != '\0' ) { RegSetValueEx( hIntlKey, c_szCurrencyDigits, 0L, REG_SZ, (CONST BYTE *)pInfo->chDigits, strlen(pInfo->chDigits)+1); } //
// Update the SMonThousandSep value.
//
if( pInfo->chThousandSep[0] != '\0' ) { RegSetValueEx( hIntlKey, c_szCurrencyThousandSep, 0L, REG_SZ, (CONST BYTE *)pInfo->chThousandSep, strlen(pInfo->chThousandSep)+1); }
return (TRUE); }
///////////////////////////////////////////////////////////////////////////////
//
// Usage
//
// Show command line Usage.
//
///////////////////////////////////////////////////////////////////////////////
void Usage() { TCHAR szMsg[MAX_PATH*8];
if (LoadString(ghInstance, IDS_USAGE, szMsg, MAX_PATH*8)) { ShowMsg(NULL, IDS_USAGE, IDS_TITLE, MB_OK); } }
|