|
|
#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; }
|