|
|
/******************************************************************************
Copyright (c) 2002 Microsoft Corporation
Module Name: muiutil.cpp
Abstract: Implements helper functions for self-updating MUI stuff
******************************************************************************/
#include "pch.h"
#include "muiutil.h"
#include "osdet.h"
typedef struct tagSLangIDStringMap { LANGID langid; LPTSTR szISOName; } SLangIDStringMap;
/*
// this is a combination of the languages used by WU and the languages used
// by MUI
// Mappings determined from the following sources
// For langid to full language name : MSDN
// full language name to 2 char name: http://www.oasis-open.org/cover/iso639a.html
// country name to 2 character name : http://www.din.de/gremien/nas/nabd/iso3166ma
This table is no longer used, but is kept as a reference for langid -> string mappings
const SLangIDStringMap g_rgLangMap[] = { { 0x0401, _T("ar") }, { 0x0402, _T("bg") }, { 0x0403, _T("ca") }, { 0x0404, _T("zhTW") }, { 0x0405, _T("cs") }, { 0x0406, _T("da") }, { 0x0407, _T("de") }, { 0x0408, _T("el") }, { 0x0409, _T("en") }, { 0x040b, _T("fi") }, { 0x040c, _T("fr") }, { 0x040d, _T("he") }, { 0x040e, _T("hu") }, { 0x0410, _T("it") }, { 0x0411, _T("ja") }, { 0x0412, _T("ko") }, { 0x0413, _T("nl") }, { 0x0414, _T("no") }, { 0x0415, _T("pl") }, { 0x0416, _T("ptBR") }, { 0x0418, _T("ro") }, { 0x0419, _T("ru") }, { 0x041a, _T("hr") }, { 0x041b, _T("sk") }, { 0x041d, _T("sv") }, { 0x041e, _T("en") }, { 0x041f, _T("tr") }, { 0x0424, _T("sl") }, { 0x0425, _T("et") }, { 0x0426, _T("lv") }, { 0x0427, _T("lt") }, { 0x042d, _T("eu") }, { 0x0804, _T("zhCN") }, { 0x080a, _T("es") }, { 0x0816, _T("pt") }, { 0x0c0a, _T("es") } }; */
// ******************************************************************************
BOOL MapLangIdToStringName(LANGID langid, LPCTSTR pszIdentFile, LPTSTR pszLangString, DWORD cchLangString) { LOG_Block("MapLangIdToStringName");
TCHAR szLang[32]; DWORD cch; LCID lcid; BOOL fRet = FALSE;
lcid = MAKELCID(langid, SORT_DEFAULT);
fRet = LookupLocaleStringFromLCID(lcid, szLang, ARRAYSIZE(szLang)); if (fRet == FALSE) { LOG_ErrorMsg(GetLastError()); goto done; }
// first try the whole string ("<lang>-<country>")
cch = GetPrivateProfileString(IDENT_LANG, szLang, _T(""), pszLangString, cchLangString, pszIdentFile); if (cch == cchLangString - 1) { SetLastError(ERROR_INSUFFICIENT_BUFFER); LOG_ErrorMsg(ERROR_INSUFFICIENT_BUFFER); goto done; }
// if that fails, strip off the country code & just try the language
else if (cch == 0) { LPTSTR pszDash;
pszDash = StrChr(szLang, _T('-')); if (pszDash != NULL) { *pszDash = _T('\0'); cch = GetPrivateProfileString(IDENT_LANG, szLang, _T(""), pszLangString, cchLangString, pszIdentFile); if (cch == cchLangString - 1) { SetLastError(ERROR_INSUFFICIENT_BUFFER); LOG_ErrorMsg(ERROR_INSUFFICIENT_BUFFER); goto done; } } }
if (cch > 0 && pszLangString[0] == _T('/')) { // want to use the full cch (& not cch - 1) because we want to copy the
// NULL terminator also...
MoveMemory(&pszLangString[0], &pszLangString[1], cch * sizeof(TCHAR)); }
fRet = TRUE;
done: return fRet; }
// ******************************************************************************
BOOL CALLBACK EnumUILangProc(LPTSTR szUILang, LONG_PTR lParam) { LOG_Block("EnumUILangProc");
AU_LANGLIST *paull = (AU_LANGLIST *)lParam; AU_LANG *paulNew = NULL; HRESULT hr; LANGID langid; LPTSTR pszStop; TCHAR szAUName[32]; DWORD cchMuiName, cchAUName, cbNeed, cchAvail, dwLangID; BOOL fRet = FALSE, fMap;
if (szUILang == NULL || lParam == NULL) goto done;
langid = (LANGID)_tcstoul(szUILang, &pszStop, 16);
// if we don't have a mapping for a langid, then just skip the language
// and return success
szAUName[0] = _T('\0'); fMap = MapLangIdToStringName(langid, paull->pszIdentFile, szAUName, ARRAYSIZE(szAUName)); if (fMap == FALSE || szAUName[0] == _T('\0')) { fRet = TRUE; goto done; }
if (paull->cLangs >= paull->cSlots) { AU_LANG **rgpaulNew = NULL; DWORD cNewSlots = paull->cSlots * 2;
if (cNewSlots == 0) cNewSlots = 32;
if (paull->rgpaulLangs != NULL) { rgpaulNew = (AU_LANG **)HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, paull->rgpaulLangs, cNewSlots * sizeof(AU_LANG *)); } else { rgpaulNew = (AU_LANG **)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cNewSlots * sizeof(AU_LANG *)); } if (rgpaulNew == NULL) goto done;
paull->rgpaulLangs = rgpaulNew; paull->cSlots = cNewSlots; }
// we will be adding an '_' to the beginning of the AUName, so make sure
// the size we compute here reflects that.
cchAUName = lstrlen(szAUName) + 1; cchMuiName = lstrlen(szUILang);
// alloc a buffer to hold the AU_LANG struct plus the two strings (and
// don't forget the NULL terminators!).
// The layout of the buffer is as follows:
// <AU_LANG>
// <szMuiName>
// _<szAUName>
// NOTE: if this buffer format ever change, gotta make sure that the
// contents are aligned properly (otherwise, we'll fault on ia64)
cbNeed = sizeof(AU_LANG); cbNeed += ((cchMuiName + cchAUName + 2) * sizeof(TCHAR)); paulNew = (AU_LANG *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbNeed); if (paulNew == NULL) goto done;
paulNew->szMuiName = (LPTSTR)((PBYTE)paulNew + sizeof(AU_LANG)); paulNew->szAUName = paulNew->szMuiName + cchMuiName + 1;
// this should never truncate the buffers cuz we calc'ed the size above and
// allocated a buffer exactly long enuf to hold all of this
cchAvail = (cbNeed - sizeof(AU_LANG)) / sizeof(TCHAR); hr = StringCchCopyEx(paulNew->szMuiName, cchAvail, szUILang, NULL, NULL, MISTSAFE_STRING_FLAGS); if (FAILED(hr)) goto done;
cchAvail -= (cchMuiName + 1);
// need to put an '_' in front of the AU name, so add it to the buffer and
// reduce the available size by one. Also make sure to start copying the
// AUName *after* the '_' character.
paulNew->szAUName[0] = _T('_'); cchAvail--; hr = StringCchCopyEx(&paulNew->szAUName[1], cchAvail, szAUName, NULL, NULL, MISTSAFE_STRING_FLAGS); if (FAILED(hr)) goto done; paull->rgpaulLangs[paull->cLangs++] = paulNew; paulNew = NULL;
fRet = TRUE;
done: if (paulNew != NULL) HeapFree(GetProcessHeap(), 0, paulNew); return fRet; }
// ******************************************************************************
HRESULT GetMuiLangList(AU_LANGLIST *paull, LPTSTR pszMuiDir, DWORD *pcchMuiDir, LPTSTR pszHelpMuiDir, DWORD *pcchHelpMuiDir) { LOG_Block("GetMuiLangList");
HRESULT hr = NOERROR; DWORD cMuiLangs; int iLang;
paull->cLangs = 0; paull->cSlots = 0; paull->rgpaulLangs = NULL; if (EnumUILanguages(EnumUILangProc, 0, (LONG_PTR)paull) == FALSE) { hr = HRESULT_FROM_WIN32(GetLastError()); goto done; }
// We need to deal with MUI stuff only if we've have more than 0 languages
// to worry about
if (paull->cLangs > 0) { LPTSTR pszHelp = NULL, pszMui = NULL; size_t cchAvail, cchAvailHelp; TCHAR szPath[MAX_PATH + 1]; DWORD dwAttrib; DWORD cch, cLangs = (int)paull->cLangs; BOOL fDeleteLang; // need to get the directory we'll stuff MUI updates into
cch = GetSystemWindowsDirectory(pszMuiDir, *pcchMuiDir);
// note 2nd compare takes into account the addition of an extra '\\' after
// the system windows dir
if (cch == 0 || cch >= *pcchMuiDir) { hr = HRESULT_FROM_WIN32(GetLastError()); goto done; }
// tack on an extra '\\' if necessary
if (pszMuiDir[cch - 1] != _T('\\')) { pszMuiDir[cch++] = _T('\\'); pszMuiDir[cch] = _T('\0'); }
hr = StringCchCopyEx(pszHelpMuiDir, *pcchHelpMuiDir, pszMuiDir, NULL, NULL, MISTSAFE_STRING_FLAGS); if (FAILED(hr)) goto done;
hr = StringCchCatEx(pszHelpMuiDir, *pcchHelpMuiDir, MUI_HELPSUBDIR, &pszHelp, &cchAvailHelp, MISTSAFE_STRING_FLAGS); if (FAILED(hr)) goto done; hr = StringCchCatEx(pszMuiDir, *pcchMuiDir, MUI_SUBDIR, &pszMui, &cchAvail, MISTSAFE_STRING_FLAGS); if (FAILED(hr)) goto done; *pcchMuiDir -= cchAvail; *pcchHelpMuiDir -= cchAvailHelp;
// check and make sure that the MUI directories exist- remove all those that
// do not. This section also checks to make sure that the buffer passed in
// is large enuf to hold the language
for(iLang = (int)(cLangs - 1); iLang >= 0; iLang--) { fDeleteLang = FALSE;
hr = StringCchCopyEx(pszMui, cchAvail, paull->rgpaulLangs[iLang]->szMuiName, NULL, NULL, MISTSAFE_STRING_FLAGS); if (FAILED(hr)) goto done; dwAttrib = GetFileAttributes(pszMuiDir); if (dwAttrib == INVALID_FILE_ATTRIBUTES || (dwAttrib & FILE_ATTRIBUTE_DIRECTORY) == 0) { fDeleteLang = TRUE; } else { hr = StringCchCopyEx(pszHelp, cchAvailHelp, paull->rgpaulLangs[iLang]->szMuiName, NULL, NULL, MISTSAFE_STRING_FLAGS); if (FAILED(hr)) goto done; dwAttrib = GetFileAttributes(pszHelpMuiDir); if (dwAttrib == INVALID_FILE_ATTRIBUTES || (dwAttrib & FILE_ATTRIBUTE_DIRECTORY) == 0) { fDeleteLang = TRUE; } }
if (fDeleteLang) { HeapFree(GetProcessHeap(), 0, paull->rgpaulLangs[iLang]); if (iLang != paull->cLangs - 1) { MoveMemory(&paull->rgpaulLangs[iLang], &paull->rgpaulLangs[iLang + 1], (paull->cLangs - iLang - 1) * sizeof(AU_LANG *)); } paull->rgpaulLangs[--paull->cLangs] = NULL; } }
pszMuiDir[*pcchMuiDir] = _T('\0'); pszHelpMuiDir[*pcchHelpMuiDir] = _T('\0'); }
done: if (FAILED(hr)) CleanupMuiLangList(paull);
return hr; }
// ******************************************************************************
HRESULT CleanupMuiLangList(AU_LANGLIST *paull) { LOG_Block("CleanupMuiLangList");
HRESULT hr = S_OK; DWORD i;
// if it's NULL, just return success
if (paull == NULL) return hr;
if (paull->rgpaulLangs == NULL) goto done;
for (i = 0; i < paull->cLangs; i++) { if (paull->rgpaulLangs[i] != NULL) HeapFree(GetProcessHeap(), 0, paull->rgpaulLangs[i]); }
HeapFree(GetProcessHeap(), 0, paull->rgpaulLangs);
done: ZeroMemory(paull, sizeof(AU_LANGLIST)); return hr; }
|