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.
 
 
 
 
 
 

635 lines
18 KiB

#include "private.h"
#include "mui.h"
#include "immxutil.h"
#include "ciccs.h"
struct Tag_MuiInfo
{
HINSTANCE hinstLocRes;
HINSTANCE hinstOrg;
TCHAR szLocResDll[MAX_PATH];
TCHAR szCodePage[10];
DWORD dwCodePage;
BOOL fLoaded;
} g_muiInfo;
typedef struct
{
LANGID langid;
BOOL fFoundLang;
} ENUMLANGDATA;
typedef BOOL (WINAPI *PFNGETFILEVERSIONINFO)(LPTSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData);
typedef DWORD (WINAPI *PFNGETFILEVERSIONINFOSIZE)(LPTSTR lptstrFilename, LPDWORD lpdwHandle);
typedef BOOL (WINAPI *PFNVERQUERYVALUE)(const LPVOID pBlock, LPTSTR lpSubBlock, LPVOID *lplpBuffer, PUINT puLen);
static struct
{
PFNGETFILEVERSIONINFO pfnGetFileVersionInfo;
PFNGETFILEVERSIONINFOSIZE pfnGetFileVersionInfoSize;
PFNVERQUERYVALUE pfnVerQueryValue;
} g_VersionFuncTbl = { 0 };
static HINSTANCE g_hVersion = NULL;
CCicCriticalSectionStatic g_csMuiLib;
static BOOL g_bEnableMui = FALSE;
const TCHAR c_szMuiDir[] = TEXT("\\mui\\fallback\\");
const TCHAR c_szMuiExt[] = TEXT(".mui");
const TCHAR c_szVerTranslate[] = TEXT("\\VarFileInfo\\Translation");
#define VERSIONSIZE 11
#define VERSION_MINOR_INDEX 9
typedef UINT (WINAPI *PFNGETSYSTEMWINDOWSDIRECTORY) (LPSTR lpBuffer, UINT uSize);
static PFNGETSYSTEMWINDOWSDIRECTORY pfnGetSystemWindowsDirectory = NULL;
BOOL GetFileVersionString(LPSTR pszFileName, LPTSTR pszVerStr, UINT uVerStrLen);
////////////////////////////////////////////////////////////////////////////
//
// MuiResAssure
//
////////////////////////////////////////////////////////////////////////////
__inline void MuiResAssure()
{
if(g_bEnableMui && g_muiInfo.hinstLocRes == NULL && !g_muiInfo.fLoaded)
{
g_muiInfo.hinstLocRes = MuiLoadLibrary(g_muiInfo.szLocResDll,
g_muiInfo.hinstOrg);
}
}
////////////////////////////////////////////////////////////////////////////
//
// MuiLoadResource
//
////////////////////////////////////////////////////////////////////////////
void MuiLoadResource(HINSTANCE hinstOrg, LPTSTR pszLocResDll)
{
LANGID langRes = 0;
InitOSVer();
if (!g_csMuiLib.Init())
return;
if (!IsOnNT51())
g_bEnableMui = TRUE;
if (g_muiInfo.hinstLocRes == NULL)
{
if (g_bEnableMui)
{
g_muiInfo.hinstOrg = hinstOrg;
StringCchCopy(g_muiInfo.szLocResDll,
ARRAYSIZE(g_muiInfo.szLocResDll),
pszLocResDll);
}
else
{
g_muiInfo.hinstLocRes = hinstOrg;
}
}
langRes = GetPlatformResourceLangID();
GetLocaleInfo(MAKELCID(langRes, SORT_DEFAULT),
LOCALE_IDEFAULTANSICODEPAGE,
g_muiInfo.szCodePage,
ARRAYSIZE(g_muiInfo.szCodePage));
if (!AsciiToNumDec(g_muiInfo.szCodePage, &g_muiInfo.dwCodePage) ||
IsValidCodePage(g_muiInfo.dwCodePage) == 0)
{
g_muiInfo.dwCodePage = GetACP();
}
g_muiInfo.fLoaded = FALSE;
}
void MuiLoadResourceW(HINSTANCE hinstOrg, LPWSTR pszLocResDll)
{
TCHAR szResName[MAX_PATH];
WideCharToMultiByte(1252, NULL, pszLocResDll, -1, szResName, MAX_PATH, NULL, NULL);
return MuiLoadResource(hinstOrg, szResName);
}
////////////////////////////////////////////////////////////////////////////
//
// MuiFlushDlls
//
// Call this routine to free all loaded dlls.
// Caller can keep using mui apis, the dlls will be reloaded on demand.
////////////////////////////////////////////////////////////////////////////
void MuiFlushDlls(HINSTANCE hinstOrg)
{
if (g_muiInfo.hinstLocRes != NULL && g_muiInfo.hinstLocRes != hinstOrg)
{
FreeLibrary(g_muiInfo.hinstLocRes);
g_muiInfo.hinstLocRes = NULL;
g_muiInfo.fLoaded = FALSE;
}
if (g_hVersion != NULL)
{
FreeLibrary(g_hVersion);
g_hVersion = NULL;
}
}
////////////////////////////////////////////////////////////////////////////
//
// MuiClearResource
//
// Safe to call from dll detach.
// Call this routine to free all static resources.
// Must call MuiLoadReource again before using mui apis.
////////////////////////////////////////////////////////////////////////////
void MuiClearResource()
{
g_csMuiLib.Delete();
}
////////////////////////////////////////////////////////////////////////////
//
// MuiFreeResource
//
// Not safe to call from dll detach -- libraries may be freed.
////////////////////////////////////////////////////////////////////////////
void MuiFreeResource(HINSTANCE hinstOrg)
{
MuiFlushDlls(hinstOrg);
MuiClearResource();
}
////////////////////////////////////////////////////////////////////////////
//
// MuiGetHinstance
//
////////////////////////////////////////////////////////////////////////////
HINSTANCE MuiGetHinstance()
{
MuiResAssure();
return g_muiInfo.hinstLocRes;
}
////////////////////////////////////////////////////////////////////////////
//
// MuiLoadLibrary
//
////////////////////////////////////////////////////////////////////////////
HINSTANCE MuiLoadLibrary(LPCTSTR lpLibFileName, HMODULE hModule)
{
HINSTANCE hResInst = NULL;
TCHAR szTemp[10];
TCHAR szMuiPath[MAX_PATH * 2];
TCHAR szOrgDllPath[MAX_PATH];
TCHAR szMuiVerStr[MAX_PATH];
TCHAR szOrgVerStr[MAX_PATH];
LPCTSTR lpMuiPath = NULL;
LANGID langid;
UINT uSize = 0;
EnterCriticalSection(g_csMuiLib);
langid = GetPlatformResourceLangID();
// 409 is default resource langid in base dll, so we can skip the extra work
if (langid == 0x0409)
goto Exit;
if (hModule)
{
if (GetWindowsDirectory(szMuiPath, MAX_PATH))
{
StringCchCat(szMuiPath, ARRAYSIZE(szMuiPath), c_szMuiDir);
StringCchPrintf(szTemp, ARRAYSIZE(szTemp), TEXT("%04x\\"), langid);
StringCchCat(szMuiPath, ARRAYSIZE(szMuiPath), szTemp);
StringCchCat(szMuiPath, ARRAYSIZE(szMuiPath), lpLibFileName);
StringCchCat(szMuiPath, ARRAYSIZE(szMuiPath), c_szMuiExt);
if (lstrlen(szMuiPath) >= MAX_PATH*2)
goto Exit;
}
if (hModule)
{
//
// Get current full file path.
//
GetModuleFileName(hModule, szOrgDllPath, ARRAYSIZE(szOrgDllPath));
}
else
{
*szOrgDllPath = TEXT('\0');
}
}
if (!(GetFileVersionString(szMuiPath, szMuiVerStr, ARRAYSIZE(szMuiVerStr)) &&
GetFileVersionString(szOrgDllPath, szOrgVerStr, ARRAYSIZE(szOrgVerStr))))
{
goto Exit;
}
//
// Checking the major version and ignore the minor version
//
if (strncmp(szMuiVerStr, szOrgVerStr, VERSION_MINOR_INDEX) != 0)
goto Exit;
if (!hResInst)
{
//hResInst = LoadLibraryEx(szMuiPath, NULL, LOAD_LIBRARY_AS_DATAFILE);
hResInst = LoadLibrary(szMuiPath);
}
Exit:
g_muiInfo.fLoaded = TRUE;
LeaveCriticalSection(g_csMuiLib);
return hResInst;
}
////////////////////////////////////////////////////////////////////////////
//
// MuiLoadString
//
////////////////////////////////////////////////////////////////////////////
int MuiLoadString(HINSTANCE hinstOrg, UINT uID, LPSTR lpBuffer, INT nBufferMax)
{
LPWSTR lpWCBuf;
UINT cch = 0;
lpWCBuf = (LPWSTR) LocalAlloc(LPTR, sizeof(WCHAR) * (nBufferMax + 1));
if (lpWCBuf && MuiLoadStringWrapW(hinstOrg, uID, lpWCBuf, nBufferMax))
{
cch = WideCharToMultiByte(g_muiInfo.dwCodePage, NULL, lpWCBuf, -1, lpBuffer, nBufferMax, NULL, NULL);
}
if (lpWCBuf)
LocalFree(lpWCBuf);
return cch;
}
////////////////////////////////////////////////////////////////////////////
//
// MuiLoadStringWrapW
//
////////////////////////////////////////////////////////////////////////////
int MuiLoadStringWrapW(HINSTANCE hinstOrg, UINT uID, LPWSTR lpBuffer, UINT nBufferMax)
{
HINSTANCE hinstLocRes;
MuiResAssure();
if (g_muiInfo.hinstLocRes && g_muiInfo.hinstOrg == hinstOrg)
hinstLocRes = g_muiInfo.hinstLocRes;
else
hinstLocRes = hinstOrg;
if (nBufferMax <= 0) return 0; // sanity check
PWCHAR pwch;
/*
* String tables are broken up into "bundles" of 16 strings each.
*/
HRSRC hrsrc;
int cwch = 0;
hrsrc = FindResourceA(hinstLocRes, (LPSTR)(LONG_PTR)(1 + uID / 16), (LPSTR)RT_STRING);
if (hrsrc) {
pwch = (PWCHAR)LoadResource(hinstLocRes, hrsrc);
if (pwch) {
/*
* Now skip over the strings in the resource until we
* hit the one we want. Each entry is a counted string,
* just like Pascal.
*/
for (uID %= 16; uID; uID--) {
pwch += *pwch + 1;
}
cwch = min(*pwch, nBufferMax - 1);
memcpy(lpBuffer, pwch+1, cwch * sizeof(WCHAR)); /* Copy the goo */
}
}
lpBuffer[cwch] = L'\0'; /* Terminate the string */
return cwch;
}
////////////////////////////////////////////////////////////////////////////
//
// MuiDialogBoxParam
//
////////////////////////////////////////////////////////////////////////////
INT_PTR MuiDialogBoxParam(
HINSTANCE hInstance,
LPCTSTR lpTemplateName,
HWND hwndParent,
DLGPROC lpDialogFunc,
LPARAM dwInitParam)
{
HRSRC hrsr;
HGLOBAL hGlobal;
LPDLGTEMPLATE pTemplate;
INT_PTR iRet = -1;
HINSTANCE hMuiInstance;
if (!IsOnNT51() && g_muiInfo.hinstLocRes)
hMuiInstance = g_muiInfo.hinstLocRes;
else
hMuiInstance = hInstance;
if (hrsr = FindResource(hMuiInstance, lpTemplateName, RT_DIALOG))
{
if (hGlobal = LoadResource(hMuiInstance, hrsr))
{
if (pTemplate = (LPDLGTEMPLATE)LockResource(hGlobal))
{
if(IsOnNT())
iRet = DialogBoxIndirectParamW(hMuiInstance, pTemplate, hwndParent, lpDialogFunc, dwInitParam);
else
iRet = DialogBoxIndirectParamA(hMuiInstance, pTemplate, hwndParent, lpDialogFunc, dwInitParam);
}
}
}
return iRet;
}
////////////////////////////////////////////////////////////////////////////
//
// EnumLangProc
//
////////////////////////////////////////////////////////////////////////////
BOOL
CALLBACK
EnumLangProc(
HANDLE hModule, // resource-module handle
LPCTSTR lpszType, // pointer to resource type
LPCTSTR lpszName, // pointer to resource name
WORD wIDLanguage, // resource language identifier
LONG_PTR lParam // application-defined parameter
)
{
ENUMLANGDATA *pLangData;
pLangData = (ENUMLANGDATA *) lParam;
//
// for localized build contains multiple resource,
// it usually contains 0409 as backup lang.
//
// if LangInfo->LangID != 0 means we already assigned an ID to it
//
// so when wIDLanguage == 0x409, we keep the one we got from last time
//
if ((wIDLanguage == 0x409) && (pLangData->fFoundLang)) {
return TRUE;
}
pLangData->langid = wIDLanguage;
pLangData->fFoundLang = TRUE;
return TRUE; // continue enumeration
}
const TCHAR c_szKeyResLocale[] = TEXT(".Default\\Control Panel\\desktop\\ResourceLocale");
const TCHAR c_szNlsLocale[] = TEXT("System\\CurrentControlSet\\Control\\Nls\\Locale");
////////////////////////////////////////////////////////////////////////////
//
// GetPlatformResourceLangID
//
////////////////////////////////////////////////////////////////////////////
LANGID GetPlatformResourceLangID(void)
{
static LANGID langRes = 0;
// we do this only once
if (langRes == 0)
{
LANGID langidTemp = 0;
if (IsOnNT5()) // w2k or above
{
HMODULE hmod = GetSystemModuleHandle(TEXT("KERNEL32"));
FARPROC pfn = NULL;
if (hmod)
{
pfn = GetProcAddress(hmod, "GetUserDefaultUILanguage");
}
if (pfn)
langidTemp = (LANGID) pfn();
}
else if (IsOnNT())
{
ENUMLANGDATA LangData = {0};
HMODULE hmod = GetSystemModuleHandle(TEXT("ntdll.dll"));
if (hmod)
{
EnumResourceLanguages(
hmod,
(LPCTSTR) RT_VERSION,
(LPCTSTR) UIntToPtr(1),
(ENUMRESLANGPROC)EnumLangProc,
(LONG_PTR)&LangData );
langidTemp = LangData.langid;
}
}
else if (IsOn95() || IsOn98()) // win9x, Me
{
HKEY hkey = NULL;
DWORD dwCnt;
TCHAR szLocale[128];
dwCnt = ARRAYSIZE(szLocale);
if (ERROR_SUCCESS
== RegOpenKeyEx(HKEY_USERS, c_szKeyResLocale, 0, KEY_READ, &hkey))
{
if (ERROR_SUCCESS==RegQueryValueEx(hkey, NULL, NULL, NULL, (LPBYTE)szLocale, &dwCnt))
{
langidTemp = (LANGID)AsciiToNum(szLocale);
}
}
else if (ERROR_SUCCESS
== RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szNlsLocale, 0, KEY_READ, &hkey))
{
if (ERROR_SUCCESS==RegQueryValueEx(hkey, NULL, NULL, NULL, (LPBYTE)szLocale, &dwCnt))
{
langidTemp = (LANGID)AsciiToNum(szLocale);
}
}
RegCloseKey(hkey);
}
if (!langidTemp)
{
langidTemp = GetSystemDefaultLangID();
}
EnterCriticalSection(g_csMuiLib);
langRes = langidTemp;
LeaveCriticalSection(g_csMuiLib);
}
return langRes;
}
////////////////////////////////////////////////////////////////////////////
//
// GetFileVersionString
//
////////////////////////////////////////////////////////////////////////////
BOOL GetFileVersionString(LPTSTR pszFileName, LPTSTR pszVerStr, UINT uVerStrLen)
{
BOOL bRet = FALSE;
DWORD dwVerHandle;
DWORD dwVerInfoSize;
LPVOID lpVerData = NULL;
LANGID langid;
// for perf, since we only execute this code once or zero times
// per process, we'll do an explicit LoadLibrary instead of
// statically linking
if (g_hVersion == NULL)
{
if ((g_hVersion = LoadSystemLibrary(TEXT("version.dll"))) == NULL)
return FALSE;
g_VersionFuncTbl.pfnGetFileVersionInfo = (PFNGETFILEVERSIONINFO)GetProcAddress(g_hVersion, TEXT("GetFileVersionInfoA"));
g_VersionFuncTbl.pfnGetFileVersionInfoSize = (PFNGETFILEVERSIONINFOSIZE)GetProcAddress(g_hVersion, TEXT("GetFileVersionInfoSizeA"));
g_VersionFuncTbl.pfnVerQueryValue = (PFNVERQUERYVALUE)GetProcAddress(g_hVersion, TEXT("VerQueryValueA"));
}
if (g_VersionFuncTbl.pfnGetFileVersionInfo == NULL ||
g_VersionFuncTbl.pfnGetFileVersionInfoSize == NULL ||
g_VersionFuncTbl.pfnVerQueryValue == NULL)
{
return FALSE;
}
langid = GetPlatformResourceLangID();
dwVerInfoSize = g_VersionFuncTbl.pfnGetFileVersionInfoSize(pszFileName, &dwVerHandle);
if (dwVerInfoSize)
{
int i;
UINT cbTranslate;
UINT cchVer = 0;
LPDWORD lpTranslate;
LPTSTR lpszVer = NULL;
TCHAR szVerName[MAX_PATH];
lpVerData = LocalAlloc(LPTR, dwVerInfoSize);
g_VersionFuncTbl.pfnGetFileVersionInfo(pszFileName, dwVerHandle, dwVerInfoSize, lpVerData);
szVerName[0] = TEXT('\0');
if (g_VersionFuncTbl.pfnVerQueryValue(lpVerData, (LPTSTR)c_szVerTranslate, (LPVOID*)&lpTranslate, &cbTranslate))
{
cbTranslate /= sizeof(DWORD);
for (i = 0; (UINT) i < cbTranslate; i++)
{
if (LOWORD(*(lpTranslate + i)) == langid)
{
StringCchPrintf(szVerName, ARRAYSIZE(szVerName), TEXT("\\StringFileInfo\\%04X%04X\\"), LOWORD(*(lpTranslate + i)), HIWORD(*(lpTranslate + i)));
break;
}
}
}
if (szVerName[0] == TEXT('\0'))
{
StringCchCopy(szVerName, ARRAYSIZE(szVerName), TEXT("\\StringFileInfo\\040904B0\\"));
}
StringCchCat(szVerName, ARRAYSIZE(szVerName), TEXT("FileVersion"));
if (g_VersionFuncTbl.pfnVerQueryValue(lpVerData, szVerName, (LPVOID*)&lpszVer, &cchVer))
{
StringCchCopy(pszVerStr, uVerStrLen, lpszVer);
*(pszVerStr + VERSIONSIZE) = TEXT('\0');
bRet = TRUE;
}
if (lpVerData)
LocalFree((HANDLE)lpVerData);
}
return bRet;
}
////////////////////////////////////////////////////////////////////////////
//
// GetUIACP
//
////////////////////////////////////////////////////////////////////////////
DWORD GetUIACP()
{
if (!(g_muiInfo.dwCodePage))
{
LANGID langRes = 0;
langRes = GetPlatformResourceLangID();
GetLocaleInfo(MAKELCID(langRes, SORT_DEFAULT),
LOCALE_IDEFAULTANSICODEPAGE,
g_muiInfo.szCodePage,
ARRAYSIZE(g_muiInfo.szCodePage));
if (!AsciiToNumDec(g_muiInfo.szCodePage, &g_muiInfo.dwCodePage))
{
g_muiInfo.dwCodePage = GetACP();
}
}
if (IsValidCodePage(g_muiInfo.dwCodePage) == 0)
g_muiInfo.dwCodePage = GetACP();
return g_muiInfo.dwCodePage;
}