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

  1. #include "private.h"
  2. #include "mui.h"
  3. #include "immxutil.h"
  4. #include "ciccs.h"
  5. struct Tag_MuiInfo
  6. {
  7. HINSTANCE hinstLocRes;
  8. HINSTANCE hinstOrg;
  9. TCHAR szLocResDll[MAX_PATH];
  10. TCHAR szCodePage[10];
  11. DWORD dwCodePage;
  12. BOOL fLoaded;
  13. } g_muiInfo;
  14. typedef struct
  15. {
  16. LANGID langid;
  17. BOOL fFoundLang;
  18. } ENUMLANGDATA;
  19. typedef BOOL (WINAPI *PFNGETFILEVERSIONINFO)(LPTSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData);
  20. typedef DWORD (WINAPI *PFNGETFILEVERSIONINFOSIZE)(LPTSTR lptstrFilename, LPDWORD lpdwHandle);
  21. typedef BOOL (WINAPI *PFNVERQUERYVALUE)(const LPVOID pBlock, LPTSTR lpSubBlock, LPVOID *lplpBuffer, PUINT puLen);
  22. static struct
  23. {
  24. PFNGETFILEVERSIONINFO pfnGetFileVersionInfo;
  25. PFNGETFILEVERSIONINFOSIZE pfnGetFileVersionInfoSize;
  26. PFNVERQUERYVALUE pfnVerQueryValue;
  27. } g_VersionFuncTbl = { 0 };
  28. static HINSTANCE g_hVersion = NULL;
  29. CCicCriticalSectionStatic g_csMuiLib;
  30. static BOOL g_bEnableMui = FALSE;
  31. const TCHAR c_szMuiDir[] = TEXT("\\mui\\fallback\\");
  32. const TCHAR c_szMuiExt[] = TEXT(".mui");
  33. const TCHAR c_szVerTranslate[] = TEXT("\\VarFileInfo\\Translation");
  34. #define VERSIONSIZE 11
  35. #define VERSION_MINOR_INDEX 9
  36. typedef UINT (WINAPI *PFNGETSYSTEMWINDOWSDIRECTORY) (LPSTR lpBuffer, UINT uSize);
  37. static PFNGETSYSTEMWINDOWSDIRECTORY pfnGetSystemWindowsDirectory = NULL;
  38. BOOL GetFileVersionString(LPSTR pszFileName, LPTSTR pszVerStr, UINT uVerStrLen);
  39. ////////////////////////////////////////////////////////////////////////////
  40. //
  41. // MuiResAssure
  42. //
  43. ////////////////////////////////////////////////////////////////////////////
  44. __inline void MuiResAssure()
  45. {
  46. if(g_bEnableMui && g_muiInfo.hinstLocRes == NULL && !g_muiInfo.fLoaded)
  47. {
  48. g_muiInfo.hinstLocRes = MuiLoadLibrary(g_muiInfo.szLocResDll,
  49. g_muiInfo.hinstOrg);
  50. }
  51. }
  52. ////////////////////////////////////////////////////////////////////////////
  53. //
  54. // MuiLoadResource
  55. //
  56. ////////////////////////////////////////////////////////////////////////////
  57. void MuiLoadResource(HINSTANCE hinstOrg, LPTSTR pszLocResDll)
  58. {
  59. LANGID langRes = 0;
  60. InitOSVer();
  61. if (!g_csMuiLib.Init())
  62. return;
  63. if (!IsOnNT51())
  64. g_bEnableMui = TRUE;
  65. if (g_muiInfo.hinstLocRes == NULL)
  66. {
  67. if (g_bEnableMui)
  68. {
  69. g_muiInfo.hinstOrg = hinstOrg;
  70. StringCchCopy(g_muiInfo.szLocResDll,
  71. ARRAYSIZE(g_muiInfo.szLocResDll),
  72. pszLocResDll);
  73. }
  74. else
  75. {
  76. g_muiInfo.hinstLocRes = hinstOrg;
  77. }
  78. }
  79. langRes = GetPlatformResourceLangID();
  80. GetLocaleInfo(MAKELCID(langRes, SORT_DEFAULT),
  81. LOCALE_IDEFAULTANSICODEPAGE,
  82. g_muiInfo.szCodePage,
  83. ARRAYSIZE(g_muiInfo.szCodePage));
  84. if (!AsciiToNumDec(g_muiInfo.szCodePage, &g_muiInfo.dwCodePage) ||
  85. IsValidCodePage(g_muiInfo.dwCodePage) == 0)
  86. {
  87. g_muiInfo.dwCodePage = GetACP();
  88. }
  89. g_muiInfo.fLoaded = FALSE;
  90. }
  91. void MuiLoadResourceW(HINSTANCE hinstOrg, LPWSTR pszLocResDll)
  92. {
  93. TCHAR szResName[MAX_PATH];
  94. WideCharToMultiByte(1252, NULL, pszLocResDll, -1, szResName, MAX_PATH, NULL, NULL);
  95. return MuiLoadResource(hinstOrg, szResName);
  96. }
  97. ////////////////////////////////////////////////////////////////////////////
  98. //
  99. // MuiFlushDlls
  100. //
  101. // Call this routine to free all loaded dlls.
  102. // Caller can keep using mui apis, the dlls will be reloaded on demand.
  103. ////////////////////////////////////////////////////////////////////////////
  104. void MuiFlushDlls(HINSTANCE hinstOrg)
  105. {
  106. if (g_muiInfo.hinstLocRes != NULL && g_muiInfo.hinstLocRes != hinstOrg)
  107. {
  108. FreeLibrary(g_muiInfo.hinstLocRes);
  109. g_muiInfo.hinstLocRes = NULL;
  110. g_muiInfo.fLoaded = FALSE;
  111. }
  112. if (g_hVersion != NULL)
  113. {
  114. FreeLibrary(g_hVersion);
  115. g_hVersion = NULL;
  116. }
  117. }
  118. ////////////////////////////////////////////////////////////////////////////
  119. //
  120. // MuiClearResource
  121. //
  122. // Safe to call from dll detach.
  123. // Call this routine to free all static resources.
  124. // Must call MuiLoadReource again before using mui apis.
  125. ////////////////////////////////////////////////////////////////////////////
  126. void MuiClearResource()
  127. {
  128. g_csMuiLib.Delete();
  129. }
  130. ////////////////////////////////////////////////////////////////////////////
  131. //
  132. // MuiFreeResource
  133. //
  134. // Not safe to call from dll detach -- libraries may be freed.
  135. ////////////////////////////////////////////////////////////////////////////
  136. void MuiFreeResource(HINSTANCE hinstOrg)
  137. {
  138. MuiFlushDlls(hinstOrg);
  139. MuiClearResource();
  140. }
  141. ////////////////////////////////////////////////////////////////////////////
  142. //
  143. // MuiGetHinstance
  144. //
  145. ////////////////////////////////////////////////////////////////////////////
  146. HINSTANCE MuiGetHinstance()
  147. {
  148. MuiResAssure();
  149. return g_muiInfo.hinstLocRes;
  150. }
  151. ////////////////////////////////////////////////////////////////////////////
  152. //
  153. // MuiLoadLibrary
  154. //
  155. ////////////////////////////////////////////////////////////////////////////
  156. HINSTANCE MuiLoadLibrary(LPCTSTR lpLibFileName, HMODULE hModule)
  157. {
  158. HINSTANCE hResInst = NULL;
  159. TCHAR szTemp[10];
  160. TCHAR szMuiPath[MAX_PATH * 2];
  161. TCHAR szOrgDllPath[MAX_PATH];
  162. TCHAR szMuiVerStr[MAX_PATH];
  163. TCHAR szOrgVerStr[MAX_PATH];
  164. LPCTSTR lpMuiPath = NULL;
  165. LANGID langid;
  166. UINT uSize = 0;
  167. EnterCriticalSection(g_csMuiLib);
  168. langid = GetPlatformResourceLangID();
  169. // 409 is default resource langid in base dll, so we can skip the extra work
  170. if (langid == 0x0409)
  171. goto Exit;
  172. if (hModule)
  173. {
  174. if (GetWindowsDirectory(szMuiPath, MAX_PATH))
  175. {
  176. StringCchCat(szMuiPath, ARRAYSIZE(szMuiPath), c_szMuiDir);
  177. StringCchPrintf(szTemp, ARRAYSIZE(szTemp), TEXT("%04x\\"), langid);
  178. StringCchCat(szMuiPath, ARRAYSIZE(szMuiPath), szTemp);
  179. StringCchCat(szMuiPath, ARRAYSIZE(szMuiPath), lpLibFileName);
  180. StringCchCat(szMuiPath, ARRAYSIZE(szMuiPath), c_szMuiExt);
  181. if (lstrlen(szMuiPath) >= MAX_PATH*2)
  182. goto Exit;
  183. }
  184. if (hModule)
  185. {
  186. //
  187. // Get current full file path.
  188. //
  189. GetModuleFileName(hModule, szOrgDllPath, ARRAYSIZE(szOrgDllPath));
  190. }
  191. else
  192. {
  193. *szOrgDllPath = TEXT('\0');
  194. }
  195. }
  196. if (!(GetFileVersionString(szMuiPath, szMuiVerStr, ARRAYSIZE(szMuiVerStr)) &&
  197. GetFileVersionString(szOrgDllPath, szOrgVerStr, ARRAYSIZE(szOrgVerStr))))
  198. {
  199. goto Exit;
  200. }
  201. //
  202. // Checking the major version and ignore the minor version
  203. //
  204. if (strncmp(szMuiVerStr, szOrgVerStr, VERSION_MINOR_INDEX) != 0)
  205. goto Exit;
  206. if (!hResInst)
  207. {
  208. //hResInst = LoadLibraryEx(szMuiPath, NULL, LOAD_LIBRARY_AS_DATAFILE);
  209. hResInst = LoadLibrary(szMuiPath);
  210. }
  211. Exit:
  212. g_muiInfo.fLoaded = TRUE;
  213. LeaveCriticalSection(g_csMuiLib);
  214. return hResInst;
  215. }
  216. ////////////////////////////////////////////////////////////////////////////
  217. //
  218. // MuiLoadString
  219. //
  220. ////////////////////////////////////////////////////////////////////////////
  221. int MuiLoadString(HINSTANCE hinstOrg, UINT uID, LPSTR lpBuffer, INT nBufferMax)
  222. {
  223. LPWSTR lpWCBuf;
  224. UINT cch = 0;
  225. lpWCBuf = (LPWSTR) LocalAlloc(LPTR, sizeof(WCHAR) * (nBufferMax + 1));
  226. if (lpWCBuf && MuiLoadStringWrapW(hinstOrg, uID, lpWCBuf, nBufferMax))
  227. {
  228. cch = WideCharToMultiByte(g_muiInfo.dwCodePage, NULL, lpWCBuf, -1, lpBuffer, nBufferMax, NULL, NULL);
  229. }
  230. if (lpWCBuf)
  231. LocalFree(lpWCBuf);
  232. return cch;
  233. }
  234. ////////////////////////////////////////////////////////////////////////////
  235. //
  236. // MuiLoadStringWrapW
  237. //
  238. ////////////////////////////////////////////////////////////////////////////
  239. int MuiLoadStringWrapW(HINSTANCE hinstOrg, UINT uID, LPWSTR lpBuffer, UINT nBufferMax)
  240. {
  241. HINSTANCE hinstLocRes;
  242. MuiResAssure();
  243. if (g_muiInfo.hinstLocRes && g_muiInfo.hinstOrg == hinstOrg)
  244. hinstLocRes = g_muiInfo.hinstLocRes;
  245. else
  246. hinstLocRes = hinstOrg;
  247. if (nBufferMax <= 0) return 0; // sanity check
  248. PWCHAR pwch;
  249. /*
  250. * String tables are broken up into "bundles" of 16 strings each.
  251. */
  252. HRSRC hrsrc;
  253. int cwch = 0;
  254. hrsrc = FindResourceA(hinstLocRes, (LPSTR)(LONG_PTR)(1 + uID / 16), (LPSTR)RT_STRING);
  255. if (hrsrc) {
  256. pwch = (PWCHAR)LoadResource(hinstLocRes, hrsrc);
  257. if (pwch) {
  258. /*
  259. * Now skip over the strings in the resource until we
  260. * hit the one we want. Each entry is a counted string,
  261. * just like Pascal.
  262. */
  263. for (uID %= 16; uID; uID--) {
  264. pwch += *pwch + 1;
  265. }
  266. cwch = min(*pwch, nBufferMax - 1);
  267. memcpy(lpBuffer, pwch+1, cwch * sizeof(WCHAR)); /* Copy the goo */
  268. }
  269. }
  270. lpBuffer[cwch] = L'\0'; /* Terminate the string */
  271. return cwch;
  272. }
  273. ////////////////////////////////////////////////////////////////////////////
  274. //
  275. // MuiDialogBoxParam
  276. //
  277. ////////////////////////////////////////////////////////////////////////////
  278. INT_PTR MuiDialogBoxParam(
  279. HINSTANCE hInstance,
  280. LPCTSTR lpTemplateName,
  281. HWND hwndParent,
  282. DLGPROC lpDialogFunc,
  283. LPARAM dwInitParam)
  284. {
  285. HRSRC hrsr;
  286. HGLOBAL hGlobal;
  287. LPDLGTEMPLATE pTemplate;
  288. INT_PTR iRet = -1;
  289. HINSTANCE hMuiInstance;
  290. if (!IsOnNT51() && g_muiInfo.hinstLocRes)
  291. hMuiInstance = g_muiInfo.hinstLocRes;
  292. else
  293. hMuiInstance = hInstance;
  294. if (hrsr = FindResource(hMuiInstance, lpTemplateName, RT_DIALOG))
  295. {
  296. if (hGlobal = LoadResource(hMuiInstance, hrsr))
  297. {
  298. if (pTemplate = (LPDLGTEMPLATE)LockResource(hGlobal))
  299. {
  300. if(IsOnNT())
  301. iRet = DialogBoxIndirectParamW(hMuiInstance, pTemplate, hwndParent, lpDialogFunc, dwInitParam);
  302. else
  303. iRet = DialogBoxIndirectParamA(hMuiInstance, pTemplate, hwndParent, lpDialogFunc, dwInitParam);
  304. }
  305. }
  306. }
  307. return iRet;
  308. }
  309. ////////////////////////////////////////////////////////////////////////////
  310. //
  311. // EnumLangProc
  312. //
  313. ////////////////////////////////////////////////////////////////////////////
  314. BOOL
  315. CALLBACK
  316. EnumLangProc(
  317. HANDLE hModule, // resource-module handle
  318. LPCTSTR lpszType, // pointer to resource type
  319. LPCTSTR lpszName, // pointer to resource name
  320. WORD wIDLanguage, // resource language identifier
  321. LONG_PTR lParam // application-defined parameter
  322. )
  323. {
  324. ENUMLANGDATA *pLangData;
  325. pLangData = (ENUMLANGDATA *) lParam;
  326. //
  327. // for localized build contains multiple resource,
  328. // it usually contains 0409 as backup lang.
  329. //
  330. // if LangInfo->LangID != 0 means we already assigned an ID to it
  331. //
  332. // so when wIDLanguage == 0x409, we keep the one we got from last time
  333. //
  334. if ((wIDLanguage == 0x409) && (pLangData->fFoundLang)) {
  335. return TRUE;
  336. }
  337. pLangData->langid = wIDLanguage;
  338. pLangData->fFoundLang = TRUE;
  339. return TRUE; // continue enumeration
  340. }
  341. const TCHAR c_szKeyResLocale[] = TEXT(".Default\\Control Panel\\desktop\\ResourceLocale");
  342. const TCHAR c_szNlsLocale[] = TEXT("System\\CurrentControlSet\\Control\\Nls\\Locale");
  343. ////////////////////////////////////////////////////////////////////////////
  344. //
  345. // GetPlatformResourceLangID
  346. //
  347. ////////////////////////////////////////////////////////////////////////////
  348. LANGID GetPlatformResourceLangID(void)
  349. {
  350. static LANGID langRes = 0;
  351. // we do this only once
  352. if (langRes == 0)
  353. {
  354. LANGID langidTemp = 0;
  355. if (IsOnNT5()) // w2k or above
  356. {
  357. HMODULE hmod = GetSystemModuleHandle(TEXT("KERNEL32"));
  358. FARPROC pfn = NULL;
  359. if (hmod)
  360. {
  361. pfn = GetProcAddress(hmod, "GetUserDefaultUILanguage");
  362. }
  363. if (pfn)
  364. langidTemp = (LANGID) pfn();
  365. }
  366. else if (IsOnNT())
  367. {
  368. ENUMLANGDATA LangData = {0};
  369. HMODULE hmod = GetSystemModuleHandle(TEXT("ntdll.dll"));
  370. if (hmod)
  371. {
  372. EnumResourceLanguages(
  373. hmod,
  374. (LPCTSTR) RT_VERSION,
  375. (LPCTSTR) UIntToPtr(1),
  376. (ENUMRESLANGPROC)EnumLangProc,
  377. (LONG_PTR)&LangData );
  378. langidTemp = LangData.langid;
  379. }
  380. }
  381. else if (IsOn95() || IsOn98()) // win9x, Me
  382. {
  383. HKEY hkey = NULL;
  384. DWORD dwCnt;
  385. TCHAR szLocale[128];
  386. dwCnt = ARRAYSIZE(szLocale);
  387. if (ERROR_SUCCESS
  388. == RegOpenKeyEx(HKEY_USERS, c_szKeyResLocale, 0, KEY_READ, &hkey))
  389. {
  390. if (ERROR_SUCCESS==RegQueryValueEx(hkey, NULL, NULL, NULL, (LPBYTE)szLocale, &dwCnt))
  391. {
  392. langidTemp = (LANGID)AsciiToNum(szLocale);
  393. }
  394. }
  395. else if (ERROR_SUCCESS
  396. == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szNlsLocale, 0, KEY_READ, &hkey))
  397. {
  398. if (ERROR_SUCCESS==RegQueryValueEx(hkey, NULL, NULL, NULL, (LPBYTE)szLocale, &dwCnt))
  399. {
  400. langidTemp = (LANGID)AsciiToNum(szLocale);
  401. }
  402. }
  403. RegCloseKey(hkey);
  404. }
  405. if (!langidTemp)
  406. {
  407. langidTemp = GetSystemDefaultLangID();
  408. }
  409. EnterCriticalSection(g_csMuiLib);
  410. langRes = langidTemp;
  411. LeaveCriticalSection(g_csMuiLib);
  412. }
  413. return langRes;
  414. }
  415. ////////////////////////////////////////////////////////////////////////////
  416. //
  417. // GetFileVersionString
  418. //
  419. ////////////////////////////////////////////////////////////////////////////
  420. BOOL GetFileVersionString(LPTSTR pszFileName, LPTSTR pszVerStr, UINT uVerStrLen)
  421. {
  422. BOOL bRet = FALSE;
  423. DWORD dwVerHandle;
  424. DWORD dwVerInfoSize;
  425. LPVOID lpVerData = NULL;
  426. LANGID langid;
  427. // for perf, since we only execute this code once or zero times
  428. // per process, we'll do an explicit LoadLibrary instead of
  429. // statically linking
  430. if (g_hVersion == NULL)
  431. {
  432. if ((g_hVersion = LoadSystemLibrary(TEXT("version.dll"))) == NULL)
  433. return FALSE;
  434. g_VersionFuncTbl.pfnGetFileVersionInfo = (PFNGETFILEVERSIONINFO)GetProcAddress(g_hVersion, TEXT("GetFileVersionInfoA"));
  435. g_VersionFuncTbl.pfnGetFileVersionInfoSize = (PFNGETFILEVERSIONINFOSIZE)GetProcAddress(g_hVersion, TEXT("GetFileVersionInfoSizeA"));
  436. g_VersionFuncTbl.pfnVerQueryValue = (PFNVERQUERYVALUE)GetProcAddress(g_hVersion, TEXT("VerQueryValueA"));
  437. }
  438. if (g_VersionFuncTbl.pfnGetFileVersionInfo == NULL ||
  439. g_VersionFuncTbl.pfnGetFileVersionInfoSize == NULL ||
  440. g_VersionFuncTbl.pfnVerQueryValue == NULL)
  441. {
  442. return FALSE;
  443. }
  444. langid = GetPlatformResourceLangID();
  445. dwVerInfoSize = g_VersionFuncTbl.pfnGetFileVersionInfoSize(pszFileName, &dwVerHandle);
  446. if (dwVerInfoSize)
  447. {
  448. int i;
  449. UINT cbTranslate;
  450. UINT cchVer = 0;
  451. LPDWORD lpTranslate;
  452. LPTSTR lpszVer = NULL;
  453. TCHAR szVerName[MAX_PATH];
  454. lpVerData = LocalAlloc(LPTR, dwVerInfoSize);
  455. g_VersionFuncTbl.pfnGetFileVersionInfo(pszFileName, dwVerHandle, dwVerInfoSize, lpVerData);
  456. szVerName[0] = TEXT('\0');
  457. if (g_VersionFuncTbl.pfnVerQueryValue(lpVerData, (LPTSTR)c_szVerTranslate, (LPVOID*)&lpTranslate, &cbTranslate))
  458. {
  459. cbTranslate /= sizeof(DWORD);
  460. for (i = 0; (UINT) i < cbTranslate; i++)
  461. {
  462. if (LOWORD(*(lpTranslate + i)) == langid)
  463. {
  464. StringCchPrintf(szVerName, ARRAYSIZE(szVerName), TEXT("\\StringFileInfo\\%04X%04X\\"), LOWORD(*(lpTranslate + i)), HIWORD(*(lpTranslate + i)));
  465. break;
  466. }
  467. }
  468. }
  469. if (szVerName[0] == TEXT('\0'))
  470. {
  471. StringCchCopy(szVerName, ARRAYSIZE(szVerName), TEXT("\\StringFileInfo\\040904B0\\"));
  472. }
  473. StringCchCat(szVerName, ARRAYSIZE(szVerName), TEXT("FileVersion"));
  474. if (g_VersionFuncTbl.pfnVerQueryValue(lpVerData, szVerName, (LPVOID*)&lpszVer, &cchVer))
  475. {
  476. StringCchCopy(pszVerStr, uVerStrLen, lpszVer);
  477. *(pszVerStr + VERSIONSIZE) = TEXT('\0');
  478. bRet = TRUE;
  479. }
  480. if (lpVerData)
  481. LocalFree((HANDLE)lpVerData);
  482. }
  483. return bRet;
  484. }
  485. ////////////////////////////////////////////////////////////////////////////
  486. //
  487. // GetUIACP
  488. //
  489. ////////////////////////////////////////////////////////////////////////////
  490. DWORD GetUIACP()
  491. {
  492. if (!(g_muiInfo.dwCodePage))
  493. {
  494. LANGID langRes = 0;
  495. langRes = GetPlatformResourceLangID();
  496. GetLocaleInfo(MAKELCID(langRes, SORT_DEFAULT),
  497. LOCALE_IDEFAULTANSICODEPAGE,
  498. g_muiInfo.szCodePage,
  499. ARRAYSIZE(g_muiInfo.szCodePage));
  500. if (!AsciiToNumDec(g_muiInfo.szCodePage, &g_muiInfo.dwCodePage))
  501. {
  502. g_muiInfo.dwCodePage = GetACP();
  503. }
  504. }
  505. if (IsValidCodePage(g_muiInfo.dwCodePage) == 0)
  506. g_muiInfo.dwCodePage = GetACP();
  507. return g_muiInfo.dwCodePage;
  508. }