windows-nt/Source/XPSP1/NT/enduser/windows.com/wuau/wuaueng/muiutil.cpp
2020-09-26 16:20:57 +08:00

413 lines
12 KiB
C++

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