Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

954 lines
28 KiB

///////////////////////////////////////////////////////////////////////////////
//
// 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);
}
}