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.

967 lines
28 KiB

  1. #include "priv.h"
  2. #include <regapix.h>
  3. #include <htmlhelp.h>
  4. #include <shlwapi.h>
  5. #include <wininet.h> // INTERNET_MAX_URL_LENGTH
  6. #include "mlui.h"
  7. #include "cstrinout.h"
  8. //
  9. // Registry Key
  10. //
  11. const CHAR c_szLocale[] = "Locale";
  12. const CHAR c_szInternational[] = "Software\\Microsoft\\Internet Explorer\\International";
  13. const WCHAR c_wszAppPaths[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\iexplore.exe";
  14. const WCHAR c_wszMUI[] = L"mui";
  15. const WCHAR c_wszWebTemplate[] = L"\\Web\\%s";
  16. const WCHAR c_wszMuiTemplate[] = L"\\Web\\mui\\%04x\\%s";
  17. const CHAR c_szCheckVersion[] = "CheckVersion";
  18. //
  19. // MLGetUILanguage(void)
  20. //
  21. LWSTDAPI_(LANGID) MLGetUILanguage(void)
  22. {
  23. return GetUserDefaultUILanguage();
  24. }
  25. static const TCHAR s_szUrlMon[] = TEXT("urlmon.dll");
  26. static const TCHAR s_szFncFaultInIEFeature[] = TEXT("FaultInIEFeature");
  27. const CLSID CLSID_Satellite = {0x85e57160,0x2c09,0x11d2,{0xb5,0x46,0x00,0xc0,0x4f,0xc3,0x24,0xa1}};
  28. HRESULT
  29. _FaultInIEFeature(HWND hwnd, uCLSSPEC *pclsspec, QUERYCONTEXT *pQ, DWORD dwFlags)
  30. {
  31. HRESULT hr = E_FAIL;
  32. typedef HRESULT (WINAPI *PFNJIT)(
  33. HWND hwnd,
  34. uCLSSPEC *pclsspec,
  35. QUERYCONTEXT *pQ,
  36. DWORD dwFlags);
  37. PFNJIT pfnJIT = NULL;
  38. BOOL fDidLoadLib = FALSE;
  39. HINSTANCE hUrlMon = GetModuleHandle(s_szUrlMon);
  40. if (!hUrlMon)
  41. {
  42. hUrlMon = LoadLibrary(s_szUrlMon);
  43. fDidLoadLib = TRUE;
  44. }
  45. if (hUrlMon)
  46. {
  47. pfnJIT = (PFNJIT)GetProcAddress(hUrlMon, s_szFncFaultInIEFeature);
  48. }
  49. if (pfnJIT)
  50. hr = pfnJIT(hwnd, pclsspec, pQ, dwFlags);
  51. if (fDidLoadLib && hUrlMon)
  52. FreeLibrary(hUrlMon);
  53. return hr;
  54. }
  55. HRESULT GetMUIPathOfIEFileW(LPWSTR pszMUIFilePath, int cchMUIFilePath, LPCWSTR pcszFileName, LANGID lidUI)
  56. {
  57. HRESULT hr = S_OK;
  58. ASSERT(pszMUIFilePath);
  59. ASSERT(pcszFileName);
  60. // deal with the case that pcszFileName has full path
  61. LPWSTR pchT = StrRChrW(pcszFileName, NULL, L'\\');
  62. if (pchT)
  63. {
  64. pcszFileName = pchT;
  65. }
  66. static WCHAR s_szMUIPath[MAX_PATH] = { L'\0' };
  67. static LANGID s_lidLast = 0;
  68. DWORD cb;
  69. // use cached string if possible
  70. if ( !s_szMUIPath[0] || s_lidLast != lidUI)
  71. {
  72. WCHAR szAppPath[MAXIMUM_VALUE_NAME_LENGTH];
  73. s_lidLast = lidUI;
  74. cb = sizeof(szAppPath);
  75. if (ERROR_SUCCESS == SHGetValueW(HKEY_LOCAL_MACHINE, c_wszAppPaths, NULL, NULL, szAppPath, &cb))
  76. PathRemoveFileSpecW(szAppPath);
  77. else
  78. szAppPath[0] = L'0';
  79. wnsprintfW(s_szMUIPath, cchMUIFilePath, L"%s\\%s\\%04x\\", szAppPath, c_wszMUI, lidUI );
  80. }
  81. StrCpyNW(pszMUIFilePath, s_szMUIPath, cchMUIFilePath);
  82. StrCatBuffW(pszMUIFilePath, pcszFileName, cchMUIFilePath);
  83. return hr;
  84. }
  85. #define CP_THAI 874
  86. #define CP_ARABIC 1256
  87. #define CP_HEBREW 1255
  88. BOOL fDoMungeLangId(LANGID lidUI)
  89. {
  90. LANGID lidInstall = GetSystemDefaultUILanguage();
  91. BOOL fRet = FALSE;
  92. if (0x0409 != lidUI && lidUI != lidInstall) // US resource is always no need to munge
  93. {
  94. CHAR szUICP[8];
  95. static UINT uiACP = GetACP();
  96. GetLocaleInfoA(MAKELCID(lidUI, SORT_DEFAULT), LOCALE_IDEFAULTANSICODEPAGE, szUICP, ARRAYSIZE(szUICP));
  97. if (uiACP != (UINT) StrToIntA(szUICP))
  98. fRet = TRUE;
  99. }
  100. return fRet;
  101. }
  102. LANGID GetNormalizedLangId(DWORD dwFlag)
  103. {
  104. LANGID lidUI = GetUserDefaultUILanguage();
  105. if (ML_NO_CROSSCODEPAGE == (dwFlag & ML_CROSSCODEPAGE_MASK))
  106. {
  107. if (fDoMungeLangId(lidUI))
  108. lidUI = 0;
  109. }
  110. return (lidUI) ? lidUI: GetSystemDefaultUILanguage();
  111. }
  112. //
  113. // MLLoadLibrary
  114. //
  115. HDPA g_hdpaPUI = NULL;
  116. typedef struct tagPUIITEM
  117. {
  118. HINSTANCE hinstRes;
  119. LANGID lidUI;
  120. } PUIITEM, *PPUIITEM;
  121. EXTERN_C BOOL InitPUI(void)
  122. {
  123. if (NULL == g_hdpaPUI)
  124. {
  125. ENTERCRITICAL;
  126. if (NULL == g_hdpaPUI)
  127. g_hdpaPUI = DPA_Create(4);
  128. LEAVECRITICAL;
  129. }
  130. return (g_hdpaPUI)? TRUE: FALSE;
  131. }
  132. int GetPUIITEM(HINSTANCE hinst)
  133. {
  134. int i = 0, cItems = 0;
  135. ASSERTCRITICAL;
  136. if (InitPUI())
  137. {
  138. cItems = DPA_GetPtrCount(g_hdpaPUI);
  139. for (i = 0; i < cItems; i++)
  140. {
  141. PPUIITEM pItem = (PPUIITEM)DPA_FastGetPtr(g_hdpaPUI, i);
  142. if (pItem && pItem->hinstRes == hinst)
  143. break;
  144. }
  145. }
  146. return (i < cItems)? i: -1;
  147. }
  148. EXTERN_C void DeinitPUI(void)
  149. {
  150. if (g_hdpaPUI)
  151. {
  152. ENTERCRITICAL;
  153. if (g_hdpaPUI)
  154. {
  155. int i, cItems = 0;
  156. cItems = DPA_GetPtrCount(g_hdpaPUI);
  157. // clean up if there is anything left
  158. for (i = 0; i < cItems; i++)
  159. LocalFree(DPA_FastGetPtr(g_hdpaPUI, i));
  160. DPA_DeleteAllPtrs(g_hdpaPUI);
  161. DPA_Destroy(g_hdpaPUI);
  162. g_hdpaPUI = NULL;
  163. }
  164. LEAVECRITICAL;
  165. }
  166. }
  167. LWSTDAPI MLSetMLHInstance(HINSTANCE hInst, LANGID lidUI)
  168. {
  169. int i=-1;
  170. if (hInst)
  171. {
  172. PPUIITEM pItem = (PPUIITEM)LocalAlloc(LPTR, sizeof(PUIITEM));
  173. if (pItem)
  174. {
  175. pItem->hinstRes = hInst;
  176. pItem->lidUI = lidUI;
  177. if (InitPUI())
  178. {
  179. ENTERCRITICAL;
  180. i = DPA_AppendPtr(g_hdpaPUI, pItem);
  181. LEAVECRITICAL;
  182. }
  183. if (-1 == i)
  184. LocalFree(pItem);
  185. }
  186. }
  187. return (-1 == i) ? E_OUTOFMEMORY : S_OK;
  188. }
  189. LWSTDAPI MLClearMLHInstance(HINSTANCE hInst)
  190. {
  191. int i;
  192. ENTERCRITICAL;
  193. i = GetPUIITEM(hInst);
  194. if (0 <= i)
  195. {
  196. LocalFree(DPA_FastGetPtr(g_hdpaPUI, i));
  197. DPA_DeletePtr(g_hdpaPUI, i);
  198. }
  199. LEAVECRITICAL;
  200. return S_OK;
  201. }
  202. LWSTDAPI
  203. SHGetWebFolderFilePathW(LPCWSTR pszFileName, LPWSTR pszMUIPath, UINT cchMUIPath)
  204. {
  205. HRESULT hr;
  206. UINT cchWinPath;
  207. LANGID lidUI;
  208. LANGID lidInstall;
  209. LPWSTR pszWrite;
  210. UINT cchMaxWrite;
  211. BOOL fPathChosen;
  212. RIP(IS_VALID_STRING_PTRW(pszFileName, -1));
  213. RIP(IS_VALID_WRITE_BUFFER(pszMUIPath, WCHAR, cchMUIPath));
  214. hr = E_FAIL;
  215. fPathChosen = FALSE;
  216. //
  217. // build the path to the windows\web folder...
  218. //
  219. cchWinPath = GetSystemWindowsDirectoryW(pszMUIPath, cchMUIPath);
  220. if (cchWinPath >= cchMUIPath)
  221. {
  222. return hr; // buffer would have overflowed
  223. }
  224. if (cchWinPath > 0 &&
  225. pszMUIPath[cchWinPath-1] == L'\\')
  226. {
  227. // don't have two L'\\' in a row
  228. cchWinPath--;
  229. }
  230. lidUI = GetNormalizedLangId(ML_CROSSCODEPAGE);
  231. lidInstall = GetSystemDefaultUILanguage();
  232. pszWrite = pszMUIPath+cchWinPath;
  233. cchMaxWrite = cchMUIPath-cchWinPath;
  234. if (lidUI != lidInstall)
  235. {
  236. //
  237. // add L"\\Web\\mui\\xxxx\\<filename>"
  238. // where xxxx is the langid specific folder name
  239. //
  240. wnsprintfW(pszWrite, cchMaxWrite, c_wszMuiTemplate, lidUI, pszFileName);
  241. if (PathFileExistsW(pszMUIPath))
  242. {
  243. fPathChosen = TRUE;
  244. }
  245. }
  246. if (!fPathChosen)
  247. {
  248. //
  249. // add L"\\Web\\<filename>"
  250. //
  251. wnsprintfW(pszWrite, cchMaxWrite, c_wszWebTemplate, pszFileName);
  252. if (PathFileExistsW(pszMUIPath))
  253. {
  254. fPathChosen = TRUE;
  255. }
  256. }
  257. if (fPathChosen)
  258. {
  259. hr = S_OK;
  260. }
  261. return hr;
  262. }
  263. LWSTDAPI
  264. SHGetWebFolderFilePathA(LPCSTR pszFileName, LPSTR pszMUIPath, UINT cchMUIPath)
  265. {
  266. RIP(IS_VALID_STRING_PTRA(pszFileName, -1));
  267. RIP(IS_VALID_WRITE_BUFFER(pszMUIPath, CHAR, cchMUIPath));
  268. HRESULT hr;
  269. CStrInW strFN(pszFileName);
  270. CStrOutW strMP(pszMUIPath, cchMUIPath);
  271. hr = SHGetWebFolderFilePathW(strFN, strMP, strMP.BufSize());
  272. return hr;
  273. }
  274. // Given a string of form 5.00.2919.6300, this function gets the equivalent dword
  275. // representation of it.
  276. #define NUM_VERSION_NUM 4
  277. void ConvertVersionStrToDwords(LPSTR pszVer, LPDWORD pdwVer, LPDWORD pdwBuild)
  278. {
  279. WORD rwVer[NUM_VERSION_NUM];
  280. for(int i = 0; i < NUM_VERSION_NUM; i++)
  281. rwVer[i] = 0;
  282. for(i = 0; i < NUM_VERSION_NUM && pszVer; i++)
  283. {
  284. rwVer[i] = (WORD) StrToInt(pszVer);
  285. pszVer = StrChr(pszVer, TEXT('.'));
  286. if (pszVer)
  287. pszVer++;
  288. }
  289. *pdwVer = (rwVer[0]<< 16) + rwVer[1];
  290. *pdwBuild = (rwVer[2] << 16) + rwVer[3];
  291. }
  292. /*
  293. For SP's we don't update the MUI package. So in order for the golden MUI package to work
  294. with SP's, we now check if the MUI package is compatible with range of version numbers.
  295. Since we have different modules calling into this, and they have different version numbers,
  296. we read the version range from registry for a particular module.
  297. This Function takes the lower and upper version number of the MUI package. It gets the caller's
  298. info and reads the version range from registry. If the MUI package version lies in the version
  299. range specified in the registry, it returns TRUE.
  300. */
  301. BOOL IsMUICompatible(DWORD dwMUIFileVersionMS, DWORD dwMUIFileVersionLS)
  302. {
  303. TCHAR szVersionInfo[MAX_PATH];
  304. DWORD dwType, dwSize;
  305. TCHAR szProcess[MAX_PATH];
  306. dwSize = sizeof(szVersionInfo);
  307. //Get the caller process
  308. if(!GetModuleFileName(NULL, szProcess, MAX_PATH))
  309. return FALSE;
  310. //Get the file name from the path
  311. LPTSTR lpszFileName = PathFindFileName(szProcess);
  312. //Query the registry for version info. If the key doesn't exists or there is an
  313. //error, return false.
  314. if(ERROR_SUCCESS != SHRegGetUSValueA(c_szInternational, lpszFileName,
  315. &dwType, (LPVOID)szVersionInfo, &dwSize, TRUE, NULL, 0))
  316. {
  317. return FALSE;
  318. }
  319. LPTSTR lpszLowerBound = szVersionInfo;
  320. LPTSTR lpszUpperBound = StrChr(szVersionInfo, TEXT('-'));
  321. if(!lpszUpperBound || !*(lpszUpperBound+1))
  322. return FALSE;
  323. *(lpszUpperBound++) = NULL;
  324. DWORD dwLBMS, dwLBLS, dwUBMS, dwUBLS;
  325. ConvertVersionStrToDwords(lpszLowerBound, &dwLBMS, &dwLBLS);
  326. ConvertVersionStrToDwords(lpszUpperBound, &dwUBMS, &dwUBLS);
  327. //check if MUI version is in the specified range.
  328. if( (dwMUIFileVersionMS < dwLBMS) ||
  329. (dwMUIFileVersionMS == dwLBMS && dwMUIFileVersionLS < dwLBLS) ||
  330. (dwMUIFileVersionMS > dwUBMS) ||
  331. (dwMUIFileVersionMS == dwUBMS && dwMUIFileVersionLS > dwUBLS) )
  332. {
  333. return FALSE;
  334. }
  335. return TRUE;
  336. }
  337. BOOL CheckFileVersion(LPWSTR lpFile, LPWSTR lpFileMUI)
  338. {
  339. DWORD dwSize, dwHandle, dwSizeMUI, dwHandleMUI;
  340. LPVOID lpVerInfo, lpVerInfoMUI;
  341. VS_FIXEDFILEINFO *pvsffi, *pvsffiMUI;
  342. BOOL fRet = FALSE;
  343. dwSize = GetFileVersionInfoSizeW(lpFile, &dwHandle);
  344. dwSizeMUI = GetFileVersionInfoSizeW(lpFileMUI, &dwHandleMUI);
  345. if (dwSize && dwSizeMUI)
  346. {
  347. if (lpVerInfo = LocalAlloc(LPTR, dwSize))
  348. {
  349. if (lpVerInfoMUI = LocalAlloc(LPTR, dwSizeMUI))
  350. {
  351. if (GetFileVersionInfoW(lpFile, dwHandle, dwSize, lpVerInfo) &&
  352. GetFileVersionInfoW(lpFileMUI, dwHandleMUI, dwSizeMUI, lpVerInfoMUI))
  353. {
  354. if (VerQueryValueW(lpVerInfo, L"\\", (LPVOID *)&pvsffi, (PUINT)&dwSize) &&
  355. VerQueryValueW(lpVerInfoMUI, L"\\", (LPVOID *)&pvsffiMUI, (PUINT)&dwSizeMUI))
  356. {
  357. if ((pvsffi->dwFileVersionMS == pvsffiMUI->dwFileVersionMS &&
  358. pvsffi->dwFileVersionLS == pvsffiMUI->dwFileVersionLS)||
  359. IsMUICompatible(pvsffiMUI->dwFileVersionMS, pvsffiMUI->dwFileVersionLS))
  360. {
  361. fRet = TRUE;
  362. }
  363. }
  364. }
  365. LocalFree(lpVerInfoMUI);
  366. }
  367. LocalFree(lpVerInfo);
  368. }
  369. }
  370. return fRet;
  371. }
  372. LWSTDAPI_(HINSTANCE) MLLoadLibraryW(LPCWSTR lpLibFileName, HMODULE hModule, DWORD dwCrossCodePage)
  373. {
  374. LANGID lidUI;
  375. WCHAR szPath[MAX_PATH], szMUIPath[MAX_PATH];
  376. LPCWSTR lpPath = NULL;
  377. HINSTANCE hInst;
  378. static BOOL fCheckVersion = SHRegGetBoolUSValueA(c_szInternational, c_szCheckVersion, TRUE, TRUE);;
  379. if (!lpLibFileName)
  380. return NULL;
  381. szPath[0] = szMUIPath[0] = NULL;
  382. lidUI = GetNormalizedLangId(dwCrossCodePage);
  383. if (hModule)
  384. {
  385. if (GetModuleFileNameW(hModule, szPath, ARRAYSIZE(szPath)))
  386. {
  387. PathRemoveFileSpecW(szPath);
  388. if (PathAppendW(szPath, lpLibFileName) &&
  389. GetSystemDefaultUILanguage() == lidUI)
  390. lpPath = szPath;
  391. }
  392. }
  393. if (!lpPath)
  394. {
  395. GetMUIPathOfIEFileW(szMUIPath, ARRAYSIZE(szMUIPath), lpLibFileName, lidUI);
  396. lpPath = szMUIPath;
  397. }
  398. // Check version between module and resource. If different, use default one.
  399. if (fCheckVersion && szPath[0] && szMUIPath[0] && !CheckFileVersion(szPath, szMUIPath))
  400. {
  401. lidUI = GetSystemDefaultUILanguage();
  402. lpPath = szPath;
  403. }
  404. ASSERT(lpPath);
  405. // PERF: This should use PathFileExist first then load what exists
  406. // failing in LoadLibrary is slow
  407. hInst = LoadLibraryW(lpPath);
  408. if (NULL == hInst)
  409. {
  410. // All failed. Try to load default one lastly.
  411. if (!hInst && lpPath != szPath)
  412. {
  413. lidUI = GetSystemDefaultUILanguage();
  414. hInst = LoadLibraryW(szPath);
  415. }
  416. }
  417. if (NULL == hInst)
  418. hInst = LoadLibraryW(lpLibFileName);
  419. // if we load any resource, save info into dpa table
  420. MLSetMLHInstance(hInst, lidUI);
  421. return hInst;
  422. }
  423. //
  424. // Wide-char wrapper for MLLoadLibraryA
  425. //
  426. LWSTDAPI_(HINSTANCE) MLLoadLibraryA(LPCSTR lpLibFileName, HMODULE hModule, DWORD dwCrossCodePage)
  427. {
  428. WCHAR szLibFileName[MAX_PATH];
  429. SHAnsiToUnicode(lpLibFileName, szLibFileName, ARRAYSIZE(szLibFileName));
  430. return MLLoadLibraryW(szLibFileName, hModule, dwCrossCodePage);
  431. }
  432. LWSTDAPI_(BOOL) MLFreeLibrary(HMODULE hModule)
  433. {
  434. MLClearMLHInstance(hModule);
  435. return FreeLibrary(hModule);
  436. }
  437. LWSTDAPI_(BOOL) MLIsMLHInstance(HINSTANCE hInst)
  438. {
  439. int i;
  440. ENTERCRITICAL;
  441. i = GetPUIITEM(hInst);
  442. LEAVECRITICAL;
  443. return (0 <= i);
  444. }
  445. const WCHAR c_szResPrefix[] = L"res://";
  446. LWSTDAPI
  447. MLBuildResURLW(LPCWSTR pszLibFile,
  448. HMODULE hModule,
  449. DWORD dwCrossCodePage,
  450. LPCWSTR pszResName,
  451. LPWSTR pszResUrlOut,
  452. int cchResUrlOut)
  453. {
  454. HRESULT hr;
  455. LPWSTR pszWrite;
  456. int cchBufRemaining;
  457. int cchWrite;
  458. RIP(IS_VALID_STRING_PTRW(pszLibFile, -1));
  459. RIP(hModule != INVALID_HANDLE_VALUE);
  460. RIP(hModule != NULL);
  461. RIP(IS_VALID_STRING_PTRW(pszResName, -1));
  462. RIP(IS_VALID_WRITE_BUFFER(pszResUrlOut, WCHAR, cchResUrlOut));
  463. hr = E_INVALIDARG;
  464. if (pszLibFile != NULL &&
  465. hModule != NULL &&
  466. hModule != INVALID_HANDLE_VALUE &&
  467. (dwCrossCodePage == ML_CROSSCODEPAGE || dwCrossCodePage == ML_NO_CROSSCODEPAGE) &&
  468. pszResName != NULL &&
  469. pszResUrlOut != NULL)
  470. {
  471. hr = E_FAIL;
  472. pszWrite = pszResUrlOut;
  473. cchBufRemaining = cchResUrlOut;
  474. // write in the res protocol prefix
  475. cchWrite = lstrlenW(c_szResPrefix);
  476. if (cchBufRemaining >= cchWrite+1)
  477. {
  478. HINSTANCE hinstLocRes;
  479. StrCpyNW(pszWrite, c_szResPrefix, cchBufRemaining);
  480. pszWrite += cchWrite;
  481. cchBufRemaining -= cchWrite;
  482. // figure out the module path
  483. // unfortunately the module path might only exist
  484. // after necessary components are JIT'd, and
  485. // we don't know whether a JIT is necessary unless
  486. // certain LoadLibrary's have failed.
  487. hinstLocRes = MLLoadLibraryW(pszLibFile, hModule, dwCrossCodePage);
  488. if (hinstLocRes != NULL)
  489. {
  490. BOOL fGotModulePath;
  491. WCHAR szLocResPath[MAX_PATH];
  492. fGotModulePath = GetModuleFileNameW(hinstLocRes, szLocResPath, ARRAYSIZE(szLocResPath));
  493. MLFreeLibrary(hinstLocRes);
  494. if (fGotModulePath)
  495. {
  496. // copy in the module path
  497. cchWrite = lstrlenW(szLocResPath);
  498. if (cchBufRemaining >= cchWrite+1)
  499. {
  500. StrCpyNW(pszWrite, szLocResPath, cchBufRemaining);
  501. pszWrite += cchWrite;
  502. cchBufRemaining -= cchWrite;
  503. // write the next L'/' and the resource name
  504. cchWrite = 1 + lstrlenW(pszResName);
  505. if (cchBufRemaining >= cchWrite+1)
  506. {
  507. *(pszWrite++) = L'/';
  508. cchBufRemaining--;
  509. StrCpyNW(pszWrite, pszResName, cchBufRemaining);
  510. ASSERT(pszWrite[lstrlenW(pszResName)] == '\0');
  511. hr = S_OK;
  512. }
  513. }
  514. }
  515. }
  516. }
  517. if (FAILED(hr))
  518. {
  519. pszResUrlOut[0] = L'\0';
  520. }
  521. }
  522. return hr;
  523. }
  524. LWSTDAPI
  525. MLBuildResURLA(LPCSTR pszLibFile,
  526. HMODULE hModule,
  527. DWORD dwCrossCodePage,
  528. LPCSTR pszResName,
  529. LPSTR pszResUrlOut,
  530. int cchResUrlOut)
  531. {
  532. HRESULT hr;
  533. RIP(IS_VALID_STRING_PTR(pszLibFile, -1));
  534. RIP(hModule != INVALID_HANDLE_VALUE);
  535. RIP(hModule != NULL);
  536. RIP(IS_VALID_STRING_PTRA(pszResName, -1));
  537. RIP(IS_VALID_WRITE_BUFFER(pszResUrlOut, CHAR, cchResUrlOut));
  538. CStrInW strLF(pszLibFile);
  539. CStrInW strRN(pszResName);
  540. CStrOutW strRUO(pszResUrlOut, cchResUrlOut);
  541. hr = MLBuildResURLW(strLF, hModule, dwCrossCodePage, strRN, strRUO, strRUO.BufSize());
  542. return hr;
  543. }
  544. #define MAXRCSTRING 514
  545. // this will check to see if lpcstr is a resource id or not. if it
  546. // is, it will return a LPSTR containing the loaded resource.
  547. // the caller must LocalFree this lpstr. if pszText IS a string, it
  548. // will return pszText
  549. //
  550. // returns:
  551. // pszText if it is already a string
  552. // or
  553. // LocalAlloced() memory to be freed with LocalFree
  554. // if pszRet != pszText free pszRet
  555. LPWSTR ResourceCStrToStr(HINSTANCE hInst, LPCWSTR pszText)
  556. {
  557. WCHAR szTemp[MAXRCSTRING];
  558. LPWSTR pszRet = NULL;
  559. if (!IS_INTRESOURCE(pszText))
  560. return (LPWSTR)pszText;
  561. if (LOWORD((DWORD_PTR)pszText) && LoadStringW(hInst, LOWORD((DWORD_PTR)pszText), szTemp, ARRAYSIZE(szTemp)))
  562. {
  563. int cchRet = lstrlenW(szTemp) + 1;
  564. pszRet = (LPWSTR)LocalAlloc(LPTR, cchRet * sizeof(WCHAR));
  565. if (pszRet)
  566. {
  567. StringCchCopyW(pszRet, cchRet, szTemp);
  568. }
  569. }
  570. return pszRet;
  571. }
  572. LPWSTR _ConstructMessageString(HINSTANCE hInst, LPCWSTR pszMsg, va_list *ArgList)
  573. {
  574. LPWSTR pszRet;
  575. LPWSTR pszRes = ResourceCStrToStr(hInst, pszMsg);
  576. if (!pszRes)
  577. {
  578. DebugMsg(DM_ERROR, TEXT("_ConstructMessageString: Failed to load string template"));
  579. return NULL;
  580. }
  581. if (!FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
  582. pszRes, 0, 0, (LPWSTR)&pszRet, 0, ArgList))
  583. {
  584. DebugMsg(DM_ERROR, TEXT("_ConstructMessageString: FormatMessage failed %d"),GetLastError());
  585. DebugMsg(DM_ERROR, TEXT(" pszRes = %s"), pszRes );
  586. DebugMsg(DM_ERROR, !IS_INTRESOURCE(pszMsg) ?
  587. TEXT(" pszMsg = %s") :
  588. TEXT(" pszMsg = 0x%x"), pszMsg );
  589. pszRet = NULL;
  590. }
  591. if (pszRes != pszMsg)
  592. LocalFree(pszRes);
  593. return pszRet; // free with LocalFree()
  594. }
  595. LWSTDAPIV_(int) ShellMessageBoxWrapW(HINSTANCE hInst, HWND hWnd, LPCWSTR pszMsg, LPCWSTR pszTitle, UINT fuStyle, ...)
  596. {
  597. LPWSTR pszText;
  598. int result;
  599. WCHAR szBuffer[80];
  600. va_list ArgList;
  601. // BUG 95214
  602. #ifdef DEBUG
  603. IUnknown* punk = NULL;
  604. if (SUCCEEDED(SHGetThreadRef(&punk)) && punk)
  605. {
  606. ASSERTMSG(hWnd != NULL, TEXT("shlwapi\\mlui.cpp : ShellMessageBoxW - Caller should either be not under a browser or should have a parent hwnd"));
  607. punk->Release();
  608. }
  609. #endif
  610. if (!IS_INTRESOURCE(pszTitle))
  611. {
  612. // do nothing
  613. }
  614. else if (LoadStringW(hInst, LOWORD((DWORD_PTR)pszTitle), szBuffer, ARRAYSIZE(szBuffer)))
  615. {
  616. // Allow this to be a resource ID or NULL to specifiy the parent's title
  617. pszTitle = szBuffer;
  618. }
  619. else if (hWnd)
  620. {
  621. // The caller didn't give us a Title, so let's use the Window Text.
  622. // Grab the title of the parent
  623. GetWindowTextW(hWnd, szBuffer, ARRAYSIZE(szBuffer));
  624. // HACKHACK YUCK!!!!
  625. // Is the window the Desktop window?
  626. if (!StrCmpW(szBuffer, L"Program Manager"))
  627. {
  628. // Yes, so we now have two problems,
  629. // 1. The title should be "Desktop" and not "Program Manager", and
  630. // 2. Only the desktop thread can call this or it will hang the desktop
  631. // window.
  632. // Is the window Prop valid?
  633. if (GetWindowThreadProcessId(hWnd, 0) == GetCurrentThreadId())
  634. {
  635. // Yes, so let's get it...
  636. // Problem #1, load a localized version of "Desktop"
  637. pszTitle = (LPCWSTR) GetProp(hWnd, TEXT("pszDesktopTitleW"));
  638. if (!pszTitle)
  639. {
  640. // Oops, this must have been some app with "Program Manager" as the title.
  641. pszTitle = szBuffer;
  642. }
  643. }
  644. else
  645. {
  646. // No, so we hit problem 2...
  647. // Problem #2, Someone is going to
  648. // hang the desktop window by using it as the parent
  649. // of a dialog that belongs to a thread other than
  650. // the desktop thread.
  651. RIPMSG(0, "****************ERROR********** The caller is going to hang the desktop window by putting a modal dlg on it.");
  652. }
  653. }
  654. else
  655. pszTitle = szBuffer;
  656. }
  657. else
  658. {
  659. pszTitle = L"";
  660. }
  661. va_start(ArgList, fuStyle);
  662. pszText = _ConstructMessageString(hInst, pszMsg, &ArgList);
  663. va_end(ArgList);
  664. if (pszText)
  665. {
  666. result = MessageBoxW(hWnd, pszText, pszTitle, fuStyle | MB_SETFOREGROUND);
  667. LocalFree(pszText);
  668. }
  669. else
  670. {
  671. DebugMsg(DM_ERROR, TEXT("smb: Not enough memory to put up dialog."));
  672. result = -1; // memory failure
  673. }
  674. return result;
  675. }
  676. HRESULT GetFilePathFromLangId (LPCWSTR pszFile, LPWSTR pszOut, int cchOut, DWORD dwFlag)
  677. {
  678. HRESULT hr = S_OK;
  679. WCHAR szMUIPath[MAX_PATH];
  680. LPCWSTR lpPath;
  681. LANGID lidUI;
  682. if (pszFile)
  683. {
  684. // FEATURE: should support '>' format but not now
  685. if (*pszFile == L'>') return E_FAIL;
  686. lidUI = GetNormalizedLangId(dwFlag);
  687. if (0 == lidUI || GetSystemDefaultUILanguage() == lidUI)
  688. lpPath = pszFile;
  689. else
  690. {
  691. GetMUIPathOfIEFileW(szMUIPath, ARRAYSIZE(szMUIPath), pszFile, lidUI);
  692. lpPath = szMUIPath;
  693. }
  694. lstrcpynW(pszOut, lpPath, min(MAX_PATH, cchOut));
  695. }
  696. else
  697. hr = E_FAIL;
  698. return hr;
  699. }
  700. //
  701. // MLHtmlHelp / MLWinHelp
  702. //
  703. // Function: load a help file corresponding to the current UI lang setting
  704. // from \mui\<Lang ID>
  705. //
  706. //
  707. HWND MLHtmlHelpW(HWND hwndCaller, LPCWSTR pszFile, UINT uCommand, DWORD_PTR dwData, DWORD dwCrossCodePage)
  708. {
  709. WCHAR szPath[MAX_PATH];
  710. HRESULT hr = E_FAIL;
  711. HWND hwnd = NULL;
  712. // FEATURE: 1) At this moment we only support the cases that pszFile points to
  713. // a fully qualified file path, like when uCommand == HH_DISPLAY_TOPIC
  714. // or uCommand == HH_DISPLAY_TEXT_POPUP.
  715. // 2) We should support '>' format to deal with secondary window
  716. // 3) we may need to thunk file names within HH_WINTYPE structures?
  717. //
  718. if (uCommand == HH_DISPLAY_TOPIC || uCommand == HH_DISPLAY_TEXT_POPUP)
  719. {
  720. hr = GetFilePathFromLangId(pszFile, szPath, ARRAYSIZE(szPath), dwCrossCodePage);
  721. if (hr == S_OK)
  722. hwnd = HtmlHelpW(hwndCaller, szPath, uCommand, dwData);
  723. }
  724. // if there was any failure in getting ML path of help file
  725. // we call the help engine with original file path.
  726. if (hr != S_OK)
  727. {
  728. hwnd = HtmlHelpW(hwndCaller, pszFile, uCommand, dwData);
  729. }
  730. return hwnd;
  731. }
  732. BOOL MLWinHelpW(HWND hwndCaller, LPCWSTR lpszHelp, UINT uCommand, DWORD_PTR dwData)
  733. {
  734. WCHAR szPath[MAX_PATH];
  735. BOOL fret;
  736. HRESULT hr = GetFilePathFromLangId(lpszHelp, szPath, ARRAYSIZE(szPath), ML_NO_CROSSCODEPAGE);
  737. if (hr == S_OK)
  738. {
  739. fret = WinHelpW(hwndCaller, szPath, uCommand, dwData);
  740. }
  741. else
  742. fret = WinHelpW(hwndCaller, lpszHelp, uCommand, dwData);
  743. return fret;
  744. }
  745. //
  746. // Note that we cannot thunk to MLHtmlHelpW because we must call through
  747. // HtmlHelpA to get the dwData interpreted correctly.
  748. //
  749. HWND MLHtmlHelpA(HWND hwndCaller, LPCSTR pszFile, UINT uCommand, DWORD_PTR dwData, DWORD dwCrossCodePage)
  750. {
  751. HRESULT hr = E_FAIL;
  752. HWND hwnd = NULL;
  753. // FEATURE: 1) At this moment we only support the cases that pszFile points to
  754. // a fully qualified file path, like when uCommand == HH_DISPLAY_TOPIC
  755. // or uCommand == HH_DISPLAY_TEXT_POPUP.
  756. // 2) We should support '>' format to deal with secondary window
  757. // 3) we may need to thunk file names within HH_WINTYPE structures?
  758. //
  759. if (uCommand == HH_DISPLAY_TOPIC || uCommand == HH_DISPLAY_TEXT_POPUP)
  760. {
  761. WCHAR wszFileName[MAX_PATH];
  762. LPCWSTR pszFileParam = NULL;
  763. if (pszFile)
  764. {
  765. SHAnsiToUnicode(pszFile, wszFileName, ARRAYSIZE(wszFileName));
  766. pszFileParam = wszFileName;
  767. }
  768. hr = GetFilePathFromLangId(pszFileParam, wszFileName, ARRAYSIZE(wszFileName), dwCrossCodePage);
  769. if (hr == S_OK)
  770. {
  771. ASSERT(NULL != pszFileParam); // GetFilePathFromLangId returns E_FAIL with NULL input
  772. CHAR szFileName[MAX_PATH];
  773. SHUnicodeToAnsi(wszFileName, szFileName, ARRAYSIZE(szFileName));
  774. hwnd = HtmlHelpA(hwndCaller, szFileName, uCommand, dwData);
  775. }
  776. }
  777. // if there was any failure in getting ML path of help file
  778. // we call the help engine with original file path.
  779. if (hr != S_OK)
  780. {
  781. hwnd = HtmlHelpA(hwndCaller, pszFile, uCommand, dwData);
  782. }
  783. return hwnd;
  784. }
  785. BOOL MLWinHelpA(HWND hWndMain, LPCSTR lpszHelp, UINT uCommand, DWORD_PTR dwData)
  786. {
  787. WCHAR szFileName[MAX_PATH];
  788. LPCWSTR pszHelpParam = NULL;
  789. if (lpszHelp && SHAnsiToUnicode(lpszHelp, szFileName, ARRAYSIZE(szFileName)))
  790. {
  791. pszHelpParam = szFileName;
  792. }
  793. return MLWinHelpW(hWndMain, pszHelpParam, uCommand, dwData);
  794. }