Source code of Windows XP (NT5)
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.

1772 lines
49 KiB

  1. // Util.cpp : Helper functions and classes
  2. #include "private.h"
  3. #include "mlmain.h"
  4. #include <setupapi.h>
  5. #include <tchar.h>
  6. const CLSID CLSID_Japanese = {0x76C19B30,0xF0C8,0x11cf,{0x87,0xCC,0x00,0x20,0xAF,0xEE,0xCF,0x20}};
  7. const CLSID CLSID_Korean = {0x76C19B31,0xF0C8,0x11cf,{0x87,0xCC,0x00,0x20,0xAF,0xEE,0xCF,0x20}};
  8. const CLSID CLSID_PanEuro = {0x76C19B32,0xF0C8,0x11cf,{0x87,0xCC,0x00,0x20,0xAF,0xEE,0xCF,0x20}};
  9. const CLSID CLSID_TradChinese = {0x76C19B33,0xF0C8,0x11cf,{0x87,0xCC,0x00,0x20,0xAF,0xEE,0xCF,0x20}};
  10. const CLSID CLSID_SimpChinese = {0x76C19B34,0xF0C8,0x11cf,{0x87,0xCC,0x00,0x20,0xAF,0xEE,0xCF,0x20}};
  11. const CLSID CLSID_Thai = {0x76C19B35,0xF0C8,0x11cf,{0x87,0xCC,0x00,0x20,0xAF,0xEE,0xCF,0x20}};
  12. const CLSID CLSID_Hebrew = {0x76C19B36,0xF0C8,0x11cf,{0x87,0xCC,0x00,0x20,0xAF,0xEE,0xCF,0x20}};
  13. const CLSID CLSID_Vietnamese = {0x76C19B37,0xF0C8,0x11cf,{0x87,0xCC,0x00,0x20,0xAF,0xEE,0xCF,0x20}};
  14. const CLSID CLSID_Arabic = {0x76C19B38,0xF0C8,0x11cf,{0x87,0xCC,0x00,0x20,0xAF,0xEE,0xCF,0x20}};
  15. const CLSID CLSID_Auto = {0x76C19B50,0xF0C8,0x11cf,{0x87,0xCC,0x00,0x20,0xAF,0xEE,0xCF,0x20}};
  16. TCHAR szFonts[]=TEXT("fonts");
  17. static TCHAR s_szJaFont[] = TEXT("msgothic.ttf,msgothic.ttc");
  18. // a-ehuang: mail-Hyo Kyoung Kim-Kevin Gjerstad-9/14/98
  19. // OLD: static TCHAR s_szKorFont[] = TEXT("gulimche.ttf, gulim.ttf,gulim.ttc");
  20. static TCHAR s_szKorFont[] = TEXT("gulim.ttf,gulim.ttc,gulimche.ttf");
  21. // end-of-change
  22. static TCHAR s_szZhtFont[] = TEXT("mingliu.ttf,mingliu.ttc");
  23. static TCHAR s_szZhcFont[] = TEXT("mssong.ttf,simsun.ttc,mshei.ttf");
  24. static TCHAR s_szThaiFont[] = TEXT("angsa.ttf,angsa.ttf,angsab.ttf,angsai.ttf,angsaz.ttf,upcil.ttf,upcib.ttf,upcibi.ttf, cordia.ttf, cordiab.ttf, cordiai.ttf, coradiaz.ttf");
  25. static TCHAR s_szPeFont[] = TEXT("larial.ttf,larialbd.ttf,larialbi.ttf,lariali.ttf,lcour.ttf,lcourbd.ttf,lcourbi.ttf,lcouri.ttf,ltimes.ttf,ltimesbd.ttf,ltimesbi.ttf,ltimesi.ttf,symbol.ttf");
  26. static TCHAR s_szArFont[] = TEXT("andlso.ttf, artrbdo.ttf, artro.ttf, simpbdo.ttf, simpfxo.ttf, tradbdo.ttf, trado.ttf");
  27. static TCHAR s_szViFont[] = TEXT("VARIAL.TTF, VARIALBD.TTF, VARIALBI.TTF, VARIALI.TTF, VCOUR.TTF, VCOURBD.TTF, VCOURBI.TTF, VCOURI.TTF, VTIMES.TTF, VTIMESBD.TTF, VTIMESBI.TTF, VTIMESI.TTF");
  28. static TCHAR s_szIwFont[] = TEXT("DAVID.TTF, DAVIDBD.TTF, DAVIDTR.TTF, MRIAM.TTF, MRIAMC.TTF, MRIAMFX.TTF, MRIAMTR.TTF, ROD.TTF");
  29. #define IS_DBCSCODEPAGE(j) \
  30. (((j) == 932) || \
  31. ((j) == 936) || \
  32. ((j) == 949) || \
  33. ((j) == 950))
  34. #define IS_COMPLEXSCRIPT_CODEPAGE(j) \
  35. (((j) == 874) || \
  36. ((j) == 1255) || \
  37. ((j) == 1256) || \
  38. ((j) == 1258))
  39. #ifdef NEWMLSTR
  40. #include "util.h"
  41. /////////////////////////////////////////////////////////////////////////////
  42. // Helper functions
  43. HRESULT RegularizePosLen(long lStrLen, long* plPos, long* plLen)
  44. {
  45. ASSERT_WRITE_PTR(plPos);
  46. ASSERT_WRITE_PTR(plLen);
  47. long lPos = *plPos;
  48. long lLen = *plLen;
  49. if (lPos < 0)
  50. lPos = lStrLen;
  51. else
  52. lPos = min(lPos, lStrLen);
  53. if (lLen < 0)
  54. lLen = lStrLen - lPos;
  55. else
  56. lLen = min(lLen, lStrLen - lPos);
  57. *plPos = lPos;
  58. *plLen = lLen;
  59. return S_OK;
  60. }
  61. HRESULT LocaleToCodePage(LCID locale, UINT* puCodePage)
  62. {
  63. HRESULT hr = S_OK;
  64. if (puCodePage)
  65. {
  66. TCHAR szCodePage[8];
  67. if (::GetLocaleInfo(locale, LOCALE_IDEFAULTANSICODEPAGE, szCodePage, ARRAYSIZE(szCodePage)) > 0)
  68. *puCodePage = _ttoi(szCodePage);
  69. else
  70. hr = E_FAIL; // NLS failed
  71. }
  72. return hr;
  73. }
  74. HRESULT StartEndConnection(IUnknown* const pUnkCPC, const IID* const piid, IUnknown* const pUnkSink, DWORD* const pdwCookie, DWORD dwCookie)
  75. {
  76. ASSERT_READ_PTR(pUnkCPC);
  77. ASSERT_READ_PTR(piid);
  78. if (pdwCookie)
  79. ASSERT_WRITE_PTR(pUnkSink);
  80. ASSERT_READ_PTR_OR_NULL(pdwCookie);
  81. HRESULT hr;
  82. IConnectionPointContainer* pcpc;
  83. if (SUCCEEDED(hr = pUnkCPC->QueryInterface(IID_IConnectionPointContainer, (void**)&pcpc)))
  84. {
  85. ASSERT_READ_PTR(pcpc);
  86. IConnectionPoint* pcp;
  87. if (SUCCEEDED(hr = pcpc->FindConnectionPoint(*piid, &pcp)))
  88. {
  89. ASSERT_READ_PTR(pcp);
  90. if (pdwCookie)
  91. hr = pcp->Advise(pUnkSink, pdwCookie);
  92. else
  93. hr = pcp->Unadvise(dwCookie);
  94. pcp->Release();
  95. }
  96. pcpc->Release();
  97. }
  98. return hr;
  99. }
  100. /////////////////////////////////////////////////////////////////////////////
  101. // CMLAlloc
  102. CMLAlloc::CMLAlloc(void)
  103. {
  104. if (FAILED(::CoGetMalloc(1, &m_pIMalloc)))
  105. m_pIMalloc = NULL;
  106. }
  107. CMLAlloc::~CMLAlloc(void)
  108. {
  109. if (m_pIMalloc)
  110. m_pIMalloc->Release();
  111. }
  112. void* CMLAlloc::Alloc(ULONG cb)
  113. {
  114. if (m_pIMalloc)
  115. return m_pIMalloc->Alloc(cb);
  116. else
  117. return ::malloc(cb);
  118. }
  119. void* CMLAlloc::Realloc(void* pv, ULONG cb)
  120. {
  121. if (m_pIMalloc)
  122. return m_pIMalloc->Realloc(pv, cb);
  123. else
  124. return ::realloc(pv, cb);
  125. }
  126. void CMLAlloc::Free(void* pv)
  127. {
  128. if (m_pIMalloc)
  129. m_pIMalloc->Free(pv);
  130. else
  131. ::free(pv);
  132. }
  133. /////////////////////////////////////////////////////////////////////////////
  134. // CMLList
  135. HRESULT CMLList::Add(void** ppv)
  136. {
  137. if (!m_pFree) // No free cell
  138. {
  139. // Determine new size of the buffer
  140. const int cNewCell = (m_cbCell * m_cCell + m_cbIncrement + m_cbCell - 1) / m_cbCell;
  141. ASSERT(cNewCell > m_cCell);
  142. const long lNewSize = cNewCell * m_cbCell;
  143. // Allocate the buffer
  144. void *pNewBuf;
  145. if (!m_pBuf)
  146. {
  147. pNewBuf = MemAlloc(lNewSize);
  148. }
  149. else
  150. {
  151. pNewBuf = MemRealloc((void*)m_pBuf, lNewSize);
  152. ASSERT(m_pBuf == pNewBuf);
  153. }
  154. ASSERT_WRITE_BLOCK_OR_NULL((BYTE*)pNewBuf, lNewSize);
  155. if (pNewBuf)
  156. {
  157. // Add new cells to free link
  158. m_pFree = m_pBuf[m_cCell].m_pNext;
  159. for (int iCell = m_cCell; iCell + 1 < cNewCell; iCell++)
  160. m_pBuf[iCell].m_pNext = &m_pBuf[iCell + 1];
  161. m_pBuf[iCell].m_pNext = NULL;
  162. m_pBuf = (CCell*)pNewBuf;
  163. m_cCell = cNewCell;
  164. }
  165. }
  166. if (m_pFree)
  167. {
  168. // Get a new element from free link
  169. CCell* const pNewCell = m_pFree;
  170. m_pFree = pNewCell->m_pNext;
  171. *ppv = pNewCell;
  172. return S_OK;
  173. }
  174. else
  175. {
  176. *ppv = NULL;
  177. return E_OUTOFMEMORY;
  178. }
  179. }
  180. HRESULT CMLList::Remove(void* pv)
  181. {
  182. AssertPV(pv);
  183. #ifdef DEBUG
  184. for (CCell* pWalk = m_pFree; pWalk && pWalk != pv; pWalk = pWalk->m_pNext)
  185. ;
  186. ASSERT(!pWalk); // pv is already in free link
  187. #endif
  188. CCell* const pCell = (CCell* const)pv;
  189. pCell->m_pNext = m_pFree;
  190. m_pFree = pCell;
  191. return S_OK;
  192. }
  193. /////////////////////////////////////////////////////////////////////////////
  194. // CMLListLru
  195. HRESULT CMLListLru::Add(void** ppv)
  196. {
  197. HRESULT hr;
  198. CCell* pCell;
  199. if (SUCCEEDED(hr = CMLList::Add((void**)&pCell)))
  200. {
  201. // Add the cell at the bottom of LRU link
  202. for (CCell** ppCell = &m_pTop; *ppCell; ppCell = &(*ppCell)->m_pNext)
  203. ;
  204. *ppCell = pCell;
  205. pCell->m_pNext = NULL;
  206. }
  207. *ppv = (void*)pCell;
  208. return hr;
  209. }
  210. HRESULT CMLListLru::Remove(void* pv)
  211. {
  212. AssertPV(pv);
  213. // Look for previous cell of given
  214. for (CCell** ppWalk = &m_pTop; *ppWalk != pv && *ppWalk; ppWalk = &(*ppWalk)->m_pNext)
  215. ;
  216. ASSERT(!*ppWalk); // Not found in LRU link
  217. if (*ppWalk)
  218. {
  219. // Remove from LRU link
  220. CCell* const pCell = *ppWalk;
  221. *ppWalk = pCell->m_pNext;
  222. }
  223. // Add to free link
  224. return CMLList::Remove(pv);
  225. }
  226. /////////////////////////////////////////////////////////////////////////////
  227. // CMLListFast
  228. HRESULT CMLListFast::Add(void** ppv)
  229. {
  230. HRESULT hr;
  231. CCell* pCell;
  232. if (SUCCEEDED(hr = CMLList::Add((void**)&pCell)))
  233. {
  234. // Add to top of double link
  235. pCell->m_pNext = m_pTop;
  236. CCell* const pPrev = m_pTop->m_pPrev;
  237. pCell->m_pPrev = pPrev;
  238. m_pTop = pCell;
  239. pPrev->m_pNext = pCell;
  240. }
  241. *ppv = (void*)pCell;
  242. return hr;
  243. }
  244. HRESULT CMLListFast::Remove(void* pv)
  245. {
  246. AssertPV(pv);
  247. // Remove from double link
  248. CCell* const pCell = (CCell*)pv;
  249. CCell* const pPrev = pCell->m_pPrev;
  250. CCell* const pNext = (CCell*)pCell->m_pNext;
  251. pPrev->m_pNext = pNext;
  252. pNext->m_pPrev = pPrev;
  253. // Add to free link
  254. return CMLList::Remove(pv);
  255. }
  256. #endif // NEWMLSTR
  257. HRESULT
  258. _FaultInIEFeature(HWND hwnd, uCLSSPEC *pclsspec, QUERYCONTEXT *pQ, DWORD dwFlags)
  259. {
  260. HRESULT hr = E_FAIL;
  261. typedef HRESULT (WINAPI *PFNJIT)(
  262. HWND hwnd,
  263. uCLSSPEC *pclsspec,
  264. QUERYCONTEXT *pQ,
  265. DWORD dwFlags);
  266. static PFNJIT pfnJIT = NULL;
  267. if (!pfnJIT && !g_hUrlMon)
  268. {
  269. g_hUrlMon = LoadLibrary(TEXT("urlmon.DLL"));
  270. if (g_hUrlMon)
  271. pfnJIT = (PFNJIT)GetProcAddress(g_hUrlMon, "FaultInIEFeature");
  272. }
  273. if (pfnJIT)
  274. hr = pfnJIT(hwnd, pclsspec, pQ, dwFlags);
  275. return hr;
  276. }
  277. HRESULT InstallIEFeature(HWND hWnd, CLSID *clsid, DWORD dwfIODControl)
  278. {
  279. HRESULT hr = REGDB_E_CLASSNOTREG;
  280. uCLSSPEC classpec;
  281. DWORD dwfIEF = 0;
  282. classpec.tyspec=TYSPEC_CLSID;
  283. classpec.tagged_union.clsid=*clsid;
  284. if (dwfIODControl & CPIOD_PEEK)
  285. dwfIEF |= FIEF_FLAG_PEEK;
  286. if (dwfIODControl & CPIOD_FORCE_PROMPT)
  287. dwfIEF |= FIEF_FLAG_FORCE_JITUI;
  288. hr = _FaultInIEFeature(hWnd, &classpec, NULL, dwfIEF);
  289. if (hr != S_OK) {
  290. hr = REGDB_E_CLASSNOTREG;
  291. }
  292. return hr;
  293. }
  294. HRESULT _GetJITClsIDForCodePage(UINT uiCP, CLSID *clsid)
  295. {
  296. switch(uiCP)
  297. {
  298. case 932: // JA
  299. *clsid = CLSID_Japanese;
  300. break;
  301. case 949: // KOR
  302. *clsid = CLSID_Korean;
  303. break;
  304. case 950: // ZHT
  305. *clsid = CLSID_TradChinese;
  306. break;
  307. case 936: // ZHC
  308. *clsid = CLSID_SimpChinese;
  309. break;
  310. case 874:
  311. *clsid = CLSID_Thai;
  312. break;
  313. case 1255:
  314. *clsid = CLSID_Hebrew;
  315. break;
  316. case 1256:
  317. *clsid = CLSID_Arabic;
  318. break;
  319. case 1258:
  320. *clsid = CLSID_Vietnamese;
  321. break;
  322. case 1250: // PANEURO
  323. case 1251:
  324. case 1253:
  325. case 1254:
  326. case 1257:
  327. *clsid = CLSID_PanEuro;
  328. break;
  329. case 50001:
  330. *clsid = CLSID_Auto;
  331. break;
  332. default:
  333. return E_INVALIDARG;
  334. }
  335. return S_OK;
  336. }
  337. // Only good for family code pages.
  338. HRESULT _ValidateCPInfo(UINT uiCP)
  339. {
  340. HRESULT hr = E_FAIL;
  341. if (g_pMimeDatabase) // just a paranoid
  342. {
  343. switch(uiCP)
  344. {
  345. case 932: // JA
  346. case 949: // KOR
  347. case 874: // Thai
  348. case 950: // ZHT
  349. case 936: // ZHC
  350. case 1255: // Hebrew
  351. case 1256: // Arabic
  352. case 1258: // Vietnamese
  353. case 50001: // CP_AUTO
  354. // just validate what's given
  355. hr = g_pMimeDatabase->ValidateCP(uiCP);
  356. break;
  357. case 1250: // PANEURO
  358. case 1251:
  359. case 1253:
  360. case 1254:
  361. case 1257:
  362. // have to validate
  363. // all of these
  364. hr = g_pMimeDatabase->ValidateCP(1250);
  365. if (SUCCEEDED(hr))
  366. hr = g_pMimeDatabase->ValidateCP(1251);
  367. if (SUCCEEDED(hr))
  368. hr = g_pMimeDatabase->ValidateCP(1253);
  369. if (SUCCEEDED(hr))
  370. hr = g_pMimeDatabase->ValidateCP(1254);
  371. if (SUCCEEDED(hr))
  372. hr = g_pMimeDatabase->ValidateCP(1257);
  373. break;
  374. default:
  375. return E_INVALIDARG;
  376. }
  377. }
  378. return hr;
  379. }
  380. // assumes the corresponding fontfile name for now
  381. HRESULT _AddFontForCP(UINT uiCP)
  382. {
  383. TCHAR szFontsPath[MAX_PATH];
  384. LPTSTR szFontFile;
  385. HRESULT hr = S_OK;
  386. BOOL bAtLeastOneFontAdded = FALSE;
  387. switch(uiCP)
  388. {
  389. case 932: // JA
  390. szFontFile = s_szJaFont;
  391. break;
  392. case 949: // KOR
  393. szFontFile = s_szKorFont;
  394. break;
  395. case 950: // ZHT
  396. szFontFile = s_szZhtFont;
  397. break;
  398. case 936: // ZHC
  399. szFontFile = s_szZhcFont;
  400. break;
  401. case 874:
  402. szFontFile = s_szThaiFont;
  403. break;
  404. case 1255:
  405. szFontFile = s_szIwFont;
  406. break;
  407. case 1256:
  408. szFontFile = s_szArFont;
  409. break;
  410. case 1258:
  411. szFontFile = s_szViFont;
  412. break;
  413. case 1251: // PANEURO
  414. case 1253:
  415. case 1254:
  416. case 1257:
  417. szFontFile = s_szPeFont;
  418. break;
  419. default:
  420. hr = E_INVALIDARG;
  421. }
  422. // addfontresource, then broadcast WM_FONTCHANGE
  423. if (SUCCEEDED(hr))
  424. {
  425. if (MLGetWindowsDirectory(szFontsPath, ARRAYSIZE(szFontsPath)))
  426. {
  427. TCHAR szFontFilePath[MAX_PATH];
  428. LPTSTR psz, pszT;
  429. MLPathCombine(szFontsPath, szFontsPath, szFonts);
  430. for (psz = szFontFile; *psz; psz = pszT + 1)
  431. {
  432. pszT = MLStrChr(psz, TEXT(','));
  433. if (pszT)
  434. {
  435. *pszT=TEXT('\0');
  436. }
  437. MLPathCombine(szFontFilePath, szFontsPath, psz);
  438. if (AddFontResource(szFontFilePath))
  439. {
  440. bAtLeastOneFontAdded = TRUE;
  441. }
  442. if (!pszT)
  443. break;
  444. }
  445. if (!bAtLeastOneFontAdded)
  446. hr = E_FAIL;
  447. }
  448. else
  449. hr = E_FAIL;
  450. }
  451. // Clients will take care of WM_FONTCHANGE notification
  452. return hr;
  453. }
  454. int _LoadStringExA(
  455. HMODULE hModule,
  456. UINT wID,
  457. LPSTR lpBuffer,
  458. int cchBufferMax,
  459. WORD wLangId)
  460. {
  461. int iRet = 0;
  462. LPWSTR lpwStr = (LPWSTR) LocalAlloc(LPTR, cchBufferMax*sizeof(WCHAR));
  463. if (lpwStr)
  464. {
  465. iRet = _LoadStringExW(hModule, wID, lpwStr, cchBufferMax, wLangId);
  466. if (iRet)
  467. iRet = WideCharToMultiByte(CP_ACP, 0, lpwStr, iRet, lpBuffer, cchBufferMax, NULL, NULL);
  468. if(iRet >= cchBufferMax)
  469. iRet = cchBufferMax-1;
  470. lpBuffer[iRet] = 0;
  471. LocalFree(lpwStr);
  472. }
  473. return iRet;
  474. }
  475. // Extend LoadString() to to _LoadStringExW() to take LangId parameter
  476. int _LoadStringExW(
  477. HMODULE hModule,
  478. UINT wID,
  479. LPWSTR lpBuffer, // Unicode buffer
  480. int cchBufferMax, // cch in Unicode buffer
  481. WORD wLangId)
  482. {
  483. HRSRC hResInfo;
  484. HANDLE hStringSeg;
  485. LPWSTR lpsz;
  486. int cch;
  487. // Make sure the parms are valid.
  488. if (lpBuffer == NULL || cchBufferMax == 0)
  489. {
  490. return 0;
  491. }
  492. cch = 0;
  493. // String Tables are broken up into 16 string segments. Find the segment
  494. // containing the string we are interested in.
  495. if (hResInfo = FindResourceExW(hModule, (LPCWSTR)RT_STRING,
  496. (LPWSTR)IntToPtr(((USHORT)wID >> 4) + 1), wLangId))
  497. {
  498. // Load that segment.
  499. hStringSeg = LoadResource(hModule, hResInfo);
  500. // Lock the resource.
  501. if (lpsz = (LPWSTR)LockResource(hStringSeg))
  502. {
  503. // Move past the other strings in this segment.
  504. // (16 strings in a segment -> & 0x0F)
  505. wID &= 0x0F;
  506. while (TRUE)
  507. {
  508. cch = *((WORD *)lpsz++); // PASCAL like string count
  509. // first UTCHAR is count if TCHARs
  510. if (wID-- == 0) break;
  511. lpsz += cch; // Step to start if next string
  512. }
  513. // Account for the NULL
  514. cchBufferMax--;
  515. // Don't copy more than the max allowed.
  516. if (cch > cchBufferMax)
  517. cch = cchBufferMax-1;
  518. // Copy the string into the buffer.
  519. CopyMemory(lpBuffer, lpsz, cch*sizeof(WCHAR));
  520. // Attach Null terminator.
  521. lpBuffer[cch] = 0;
  522. }
  523. }
  524. return cch;
  525. }
  526. typedef struct tagCPLGID
  527. {
  528. UINT uiCodepage;
  529. TCHAR szLgId[3];
  530. TCHAR szLgIdHex[3]; // Darn it! NT should be persistent on presenting language group numbers
  531. // It uses decimal string in INF and hex string in registry.
  532. // We have to add this field to save conversion, this is fine for a small array of data.
  533. } CPLGID;
  534. const CPLGID CpLgId[] =
  535. {
  536. {1252, TEXT("1"), TEXT("1")}, // WESTERN EUROPE
  537. {1250, TEXT("2"), TEXT("2")}, // CENTRAL EUROPE
  538. {1257, TEXT("3"), TEXT("3")}, // BALTIC
  539. {1253, TEXT("4"), TEXT("4")}, // GREEK
  540. {1251, TEXT("5"), TEXT("5")}, // CYRILLIC
  541. {1254, TEXT("6"), TEXT("6")}, // TURKISH
  542. {932, TEXT("7"), TEXT("7")}, // JAPANESE
  543. {949, TEXT("8"), TEXT("8")}, // KOREAN
  544. {950, TEXT("9"), TEXT("9")}, // TRADITIONAL CHINESE
  545. {936, TEXT("10"), TEXT("a")}, // SIMPLIFIED CHINESE
  546. {874, TEXT("11"), TEXT("b")}, // THAI
  547. {1255, TEXT("12"), TEXT("c")}, // HEBREW
  548. {1256, TEXT("13"), TEXT("d")}, // ARABIC
  549. {1258, TEXT("14"), TEXT("e")}, // VIETNAMESE
  550. // ISCII encodings don't really have code pages or family code page
  551. // Code pages number are made up in W2K for conveniences,
  552. // So, we have to list them all to install the same Indian language group
  553. {57002,TEXT("15"), TEXT("f")}, // INDIAN
  554. {57003,TEXT("15"), TEXT("f")}, // INDIAN
  555. {57004,TEXT("15"), TEXT("f")}, // INDIAN
  556. {57005,TEXT("15"), TEXT("f")}, // INDIAN
  557. {57006,TEXT("15"), TEXT("f")}, // INDIAN
  558. {57007,TEXT("15"), TEXT("f")}, // INDIAN
  559. {57008,TEXT("15"), TEXT("f")}, // INDIAN
  560. {57009,TEXT("15"), TEXT("f")}, // INDIAN
  561. {57010,TEXT("15"), TEXT("f")}, // INDIAN
  562. {57011,TEXT("15"), TEXT("f")}, // INDIAN
  563. };
  564. typedef BOOL (WINAPI *PFNISNTADMIN) ( DWORD dwReserved, DWORD *lpdwReserved );
  565. typedef INT (WINAPI *PFNSETUPPROMPTREBOOT) (
  566. HSPFILEQ FileQueue, // optional, handle to a file queue
  567. HWND Owner, // parent window of this dialog box
  568. BOOL ScanOnly // optional, do not prompt user
  569. );
  570. typedef PSP_FILE_CALLBACK PFNSETUPDEFAULTQUEUECALLBACK;
  571. typedef VOID (WINAPI *PFNSETUPCLOSEINFFILE) (
  572. HINF InfHandle
  573. );
  574. typedef BOOL (WINAPI *PFNSETUPINSTALLFROMINFSECTION) (
  575. HWND Owner,
  576. HINF InfHandle,
  577. LPCTSTR SectionName,
  578. UINT Flags,
  579. HKEY RelativeKeyRoot, OPTIONAL
  580. LPCTSTR SourceRootPath, OPTIONAL
  581. UINT CopyFlags,
  582. PSP_FILE_CALLBACK MsgHandler,
  583. PVOID Context,
  584. HDEVINFO DeviceInfoSet, OPTIONAL
  585. PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
  586. );
  587. typedef HINF (WINAPI *PFNSETUPOPENINFFILE) (
  588. LPCTSTR FileName,
  589. LPCTSTR InfClass, OPTIONAL
  590. DWORD InfStyle,
  591. PUINT ErrorLine OPTIONAL
  592. );
  593. typedef PVOID (WINAPI *PFNSETUPINITDEFAULTQUEUECALLBACK) (
  594. IN HWND OwnerWindow
  595. );
  596. typedef BOOL (WINAPI *PFNSETUPOPENAPPENDINFFILE) (
  597. PCTSTR FileName, // optional, name of the file to append
  598. HINF InfHandle, // handle of the file to append to
  599. PUINT ErrorLine // optional, receives error information
  600. );
  601. HRESULT IsNTLangpackAvailable(UINT uiCP)
  602. {
  603. HRESULT hr = S_FALSE;
  604. // check if there is a valid W2K language group
  605. for (int i=0; i < ARRAYSIZE(CpLgId); i++)
  606. {
  607. if (uiCP == CpLgId[i].uiCodepage)
  608. {
  609. hr = S_OK;
  610. break;
  611. }
  612. }
  613. // check if it is already installed, if so, we don't install it again
  614. if (S_OK == hr)
  615. {
  616. HKEY hkey;
  617. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  618. REGSTR_PATH_NT5LPK_INSTALL,
  619. 0, KEY_READ, &hkey))
  620. {
  621. DWORD dwType = REG_SZ;
  622. TCHAR szLpkInstall[16] = {0};
  623. DWORD dwSize = sizeof(szLpkInstall);
  624. if (ERROR_SUCCESS == RegQueryValueEx(hkey, CpLgId[i].szLgIdHex, 0,
  625. &dwType, (LPBYTE)&szLpkInstall, &dwSize))
  626. {
  627. if (!lstrcmp(szLpkInstall, TEXT("1")))
  628. hr = S_FALSE;
  629. }
  630. RegCloseKey(hkey);
  631. }
  632. }
  633. return hr;
  634. }
  635. HRESULT _InstallNT5Langpack(HWND hwnd, UINT uiCP)
  636. {
  637. HRESULT hr = E_FAIL;
  638. HINF hIntlInf = NULL;
  639. TCHAR szIntlInf[MAX_PATH];
  640. TCHAR szIntlInfSection[MAX_PATH];
  641. PVOID QueueContext = NULL;
  642. HINSTANCE hDllAdvPack = NULL;
  643. HINSTANCE hDllSetupApi = NULL;
  644. PFNSETUPINSTALLFROMINFSECTION lpfnSetupInstallFromInfSection = NULL;
  645. PFNSETUPCLOSEINFFILE lpfnSetupCloseInfFile = NULL;
  646. PFNSETUPDEFAULTQUEUECALLBACK lpfnSetupDefaultQueueCallback = NULL;
  647. PFNSETUPOPENINFFILE lpfnSetupOpenInfFile = NULL;
  648. PFNISNTADMIN lpfnIsNTAdmin = NULL;
  649. PFNSETUPINITDEFAULTQUEUECALLBACK lpfnSetupInitDefaultQueueCallback = NULL;
  650. PFNSETUPOPENAPPENDINFFILE lpfnSetupOpenAppendInfFile = NULL;
  651. for (int i=0; i < ARRAYSIZE(CpLgId); i++)
  652. {
  653. if (uiCP == CpLgId[i].uiCodepage)
  654. {
  655. _tcscpy(szIntlInfSection, TEXT("LG_INSTALL_"));
  656. _tcscat(szIntlInfSection, CpLgId[i].szLgId);
  657. break;
  658. }
  659. }
  660. if (i >= ARRAYSIZE(CpLgId))
  661. {
  662. goto LANGPACK_EXIT;
  663. }
  664. hDllAdvPack = LoadLibrary(TEXT("advpack.dll"));
  665. hDllSetupApi = LoadLibrary(TEXT("setupapi.dll"));
  666. if (!hDllAdvPack || !hDllSetupApi)
  667. {
  668. goto LANGPACK_EXIT;
  669. }
  670. lpfnIsNTAdmin = (PFNISNTADMIN) GetProcAddress( hDllAdvPack, "IsNTAdmin");
  671. lpfnSetupCloseInfFile = (PFNSETUPCLOSEINFFILE) GetProcAddress( hDllSetupApi, "SetupCloseInfFile");
  672. lpfnSetupInitDefaultQueueCallback = (PFNSETUPINITDEFAULTQUEUECALLBACK) GetProcAddress(hDllSetupApi, "SetupInitDefaultQueueCallback");
  673. #ifdef UNICODE
  674. lpfnSetupOpenInfFile = (PFNSETUPOPENINFFILE) GetProcAddress( hDllSetupApi, "SetupOpenInfFileW"));
  675. lpfnSetupInstallFromInfSection = (PFNSETUPINSTALLFROMINFSECTION) GetProcAddress( hDllSetupApi, "SetupInstallFromInfSectionW");
  676. lpfnSetupDefaultQueueCallback = (PFNSETUPDEFAULTQUEUECALLBACK) GetProcAddress(hDllSetupApi, "SetupDefaultQueueCallbackW");
  677. lpfnSetupOpenAppendInfFile = (PFNSETUPDEFAULTQUEUECALLBACK) GetProcAddress(hDllSetupApi, "SetupOpenAppendInfFileW");
  678. #else
  679. lpfnSetupOpenInfFile = (PFNSETUPOPENINFFILE) GetProcAddress( hDllSetupApi, "SetupOpenInfFileA");
  680. lpfnSetupInstallFromInfSection = (PFNSETUPINSTALLFROMINFSECTION) GetProcAddress( hDllSetupApi, "SetupInstallFromInfSectionA");
  681. lpfnSetupDefaultQueueCallback = (PFNSETUPDEFAULTQUEUECALLBACK) GetProcAddress(hDllSetupApi, "SetupDefaultQueueCallbackA");
  682. lpfnSetupOpenAppendInfFile = (PFNSETUPOPENAPPENDINFFILE) GetProcAddress(hDllSetupApi, "SetupOpenAppendInfFileA");
  683. #endif
  684. if (!lpfnIsNTAdmin || !lpfnSetupOpenInfFile || !lpfnSetupCloseInfFile || !lpfnSetupDefaultQueueCallback
  685. || !lpfnSetupInstallFromInfSection || !lpfnSetupInitDefaultQueueCallback || !lpfnSetupOpenAppendInfFile)
  686. {
  687. goto LANGPACK_EXIT;
  688. }
  689. if (!lpfnIsNTAdmin(0, NULL))
  690. {
  691. WCHAR wszLangInstall[MAX_PATH];
  692. WCHAR wszNoAdmin[1024];
  693. LANGID LangId = GetNT5UILanguage();
  694. // Fall back to English (US) if we don't have a specific language resource
  695. if (!_LoadStringExW(g_hInst, IDS_LANGPACK_INSTALL, wszLangInstall, ARRAYSIZE(wszLangInstall), LangId) ||
  696. !_LoadStringExW(g_hInst, IDS_NO_ADMIN, wszNoAdmin, ARRAYSIZE(wszNoAdmin), LangId))
  697. {
  698. LangId = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
  699. _LoadStringExW(g_hInst, IDS_LANGPACK_INSTALL, wszLangInstall, ARRAYSIZE(wszLangInstall), LangId);
  700. _LoadStringExW(g_hInst, IDS_NO_ADMIN, wszNoAdmin, ARRAYSIZE(wszNoAdmin), LangId);
  701. }
  702. ULONG_PTR uCookie = 0;
  703. SHActivateContext(&uCookie);
  704. MessageBoxW(hwnd, wszNoAdmin, wszLangInstall, MB_OK);
  705. if (uCookie)
  706. {
  707. SHDeactivateContext(uCookie);
  708. }
  709. goto LANGPACK_EXIT;
  710. }
  711. QueueContext = lpfnSetupInitDefaultQueueCallback(hwnd);
  712. MLGetWindowsDirectory(szIntlInf, MAX_PATH);
  713. MLPathCombine(szIntlInf, szIntlInf, TEXT("inf\\intl.inf"));
  714. hIntlInf = lpfnSetupOpenInfFile(szIntlInf, NULL, INF_STYLE_WIN4, NULL);
  715. if (!lpfnSetupOpenAppendInfFile(NULL, hIntlInf, NULL))
  716. {
  717. lpfnSetupCloseInfFile(hIntlInf);
  718. goto LANGPACK_EXIT;
  719. }
  720. if (INVALID_HANDLE_VALUE != hIntlInf)
  721. {
  722. if (lpfnSetupInstallFromInfSection( hwnd,
  723. hIntlInf,
  724. szIntlInfSection,
  725. SPINST_FILES,
  726. NULL,
  727. NULL,
  728. SP_COPY_NEWER,
  729. lpfnSetupDefaultQueueCallback,
  730. QueueContext,
  731. NULL,
  732. NULL ))
  733. {
  734. if (lpfnSetupInstallFromInfSection( hwnd,
  735. hIntlInf,
  736. szIntlInfSection,
  737. SPINST_ALL & ~SPINST_FILES,
  738. NULL,
  739. NULL,
  740. 0,
  741. lpfnSetupDefaultQueueCallback,
  742. QueueContext,
  743. NULL,
  744. NULL ))
  745. {
  746. hr = S_OK;
  747. }
  748. }
  749. lpfnSetupCloseInfFile(hIntlInf);
  750. }
  751. LANGPACK_EXIT:
  752. if(hDllSetupApi)
  753. FreeLibrary(hDllSetupApi);
  754. if(hDllAdvPack)
  755. FreeLibrary(hDllAdvPack);
  756. //
  757. // Bug #289905, On Whistler, language pack will be installed with a groups of languages,
  758. // So, MLang need to validate codepage and fonts for all languages in the same group
  759. // After intl.cpl is modified for font validation, we'll remove this hardcoded language group.
  760. //
  761. if (hr == S_OK)
  762. {
  763. // This has to match Whistler language group
  764. UINT uiDBCSCps[] = {932, 936, 949, 950, 0};
  765. UINT uiCompCps[] = {874, 1255, 1256, 1258, 0};
  766. UINT uiOtherCps[] = {uiCP, 0};
  767. UINT *pCps = uiOtherCps;
  768. if (MLIsOS(OS_WHISTLERORGREATER))
  769. {
  770. if (IS_DBCSCODEPAGE(uiCP))
  771. pCps = uiDBCSCps;
  772. else if (IS_COMPLEXSCRIPT_CODEPAGE(uiCP))
  773. pCps = uiCompCps;
  774. }
  775. while (*pCps)
  776. {
  777. hr = _ValidateCPInfo(*pCps);
  778. if (SUCCEEDED(hr))
  779. {
  780. _AddFontForCP(*pCps);
  781. }
  782. pCps++;
  783. }
  784. }
  785. return hr;
  786. }
  787. BOOL _IsValidCodePage(UINT uiCodePage)
  788. {
  789. BOOL bRet;
  790. if (50001 == uiCodePage)
  791. {
  792. HANDLE hFile = NULL;
  793. CHAR szFileName[MAX_PATH];
  794. LPSTR psz;
  795. if (GetModuleFileNameA(g_hInst, szFileName, ARRAYSIZE(szFileName)) == 0)
  796. return GetLastError();
  797. if ( (psz = strrchr (szFileName, '\\')) != NULL ||
  798. (psz = strrchr (szFileName, ':')) != NULL )
  799. {
  800. *++psz = 0;
  801. }
  802. else
  803. *szFileName = 0;
  804. strcat (szFileName, DETECTION_DATA_FILENAME);
  805. if (INVALID_HANDLE_VALUE == (hFile = CreateFileA(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
  806. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)))
  807. {
  808. bRet = FALSE;
  809. }
  810. else
  811. {
  812. bRet = TRUE;
  813. CloseHandle(hFile);
  814. }
  815. }
  816. else
  817. {
  818. bRet = IsValidCodePage(uiCodePage);
  819. }
  820. return bRet;
  821. }
  822. WCHAR *MLStrCpyNW(WCHAR *strDest, const WCHAR *strSource, int nCount)
  823. {
  824. return wcsncpy(strDest, strSource, nCount);
  825. }
  826. WCHAR *MLStrCpyW(WCHAR *strDest, const WCHAR *strSource)
  827. {
  828. return wcscpy(strDest, strSource);
  829. }
  830. LPTSTR MLStrChr( const TCHAR *string, int c )
  831. {
  832. return _tcschr(string, c);
  833. }
  834. LPTSTR MLStrCpyN(LPTSTR strDest, const LPTSTR strSource, UINT nCount)
  835. {
  836. return _tcsncpy(strDest, strSource, nCount);
  837. }
  838. LPTSTR MLStrStr(const LPTSTR Str, const LPTSTR subStr)
  839. {
  840. return _tcsstr(Str, subStr);
  841. }
  842. LPTSTR MLPathCombine(LPTSTR szPath, LPTSTR szPath1, LPTSTR szPath2)
  843. {
  844. int len;
  845. if (!szPath)
  846. return NULL;
  847. if (szPath != szPath1)
  848. {
  849. _tcscpy(szPath, szPath1);
  850. }
  851. len = _tcslen(szPath1);
  852. if (szPath[len-1] != TEXT('\\'))
  853. {
  854. szPath[len++] = TEXT('\\');
  855. szPath[len] = 0;
  856. }
  857. return _tcscat(szPath, szPath2);
  858. }
  859. DWORD HexToNum(LPTSTR lpsz)
  860. {
  861. DWORD dw = 0L;
  862. TCHAR c;
  863. while(*lpsz)
  864. {
  865. c = *lpsz++;
  866. if (c >= TEXT('A') && c <= TEXT('F'))
  867. {
  868. c -= TEXT('A') - 0xa;
  869. }
  870. else if (c >= TEXT('0') && c <= TEXT('9'))
  871. {
  872. c -= TEXT('0');
  873. }
  874. else if (c >= TEXT('a') && c <= TEXT('f'))
  875. {
  876. c -= TEXT('a') - 0xa;
  877. }
  878. else
  879. {
  880. break;
  881. }
  882. dw *= 0x10;
  883. dw += c;
  884. }
  885. return(dw);
  886. }
  887. // Following code is borrowed from shlwapi
  888. BOOL AnsiFromUnicode(
  889. LPSTR * ppszAnsi,
  890. LPCWSTR pwszWide, // NULL to clean up
  891. LPSTR pszBuf,
  892. int cchBuf)
  893. {
  894. BOOL bRet;
  895. // Convert the string?
  896. if (pwszWide)
  897. {
  898. // Yes; determine the converted string length
  899. int cch;
  900. LPSTR psz;
  901. cch = WideCharToMultiByte(CP_ACP, 0, pwszWide, -1, NULL, 0, NULL, NULL);
  902. // String too big, or is there no buffer?
  903. if (cch > cchBuf || NULL == pszBuf)
  904. {
  905. // Yes; allocate space
  906. cchBuf = cch + 1;
  907. psz = (LPSTR)LocalAlloc(LPTR, CbFromCchA(cchBuf));
  908. }
  909. else
  910. {
  911. // No; use the provided buffer
  912. ASSERT(pszBuf);
  913. psz = pszBuf;
  914. }
  915. if (psz)
  916. {
  917. // Convert the string
  918. cch = WideCharToMultiByte(CP_ACP, 0, pwszWide, -1, psz, cchBuf, NULL, NULL);
  919. bRet = (0 < cch);
  920. }
  921. else
  922. {
  923. bRet = FALSE;
  924. }
  925. *ppszAnsi = psz;
  926. }
  927. else
  928. {
  929. // No; was this buffer allocated?
  930. if (*ppszAnsi && pszBuf != *ppszAnsi)
  931. {
  932. // Yes; clean up
  933. LocalFree((HLOCAL)*ppszAnsi);
  934. *ppszAnsi = NULL;
  935. }
  936. bRet = TRUE;
  937. }
  938. return bRet;
  939. }
  940. int MLStrCmpI(IN LPCTSTR pwsz1, IN LPCTSTR pwsz2)
  941. {
  942. #ifdef UNICODE
  943. return MLStrCmpIW(pwsz1, pwsz2);
  944. #else
  945. return lstrcmpiA(pwsz1, pwsz2);
  946. #endif
  947. }
  948. int MLStrCmpNI(IN LPCTSTR pstr1, IN LPCTSTR pstr2, IN int count)
  949. {
  950. #ifdef UNICODE
  951. return MLStrCmpNIW(pstr1, pstr2, count);
  952. #else
  953. return MLStrCmpNIA(pstr1, pstr2, count);
  954. #endif
  955. }
  956. int MLStrCmpIW(
  957. IN LPCWSTR pwsz1,
  958. IN LPCWSTR pwsz2)
  959. {
  960. int iRet;
  961. ASSERT(IS_VALID_STRING_PTRW(pwsz1, -1));
  962. ASSERT(IS_VALID_STRING_PTRW(pwsz2, -1));
  963. if (g_bIsNT)
  964. {
  965. iRet = CompareStringW(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT), NORM_IGNORECASE, pwsz1, -1, pwsz2, -1) - CSTR_EQUAL;
  966. }
  967. else
  968. {
  969. CHAR sz1[512];
  970. CHAR sz2[512];
  971. LPSTR psz1;
  972. LPSTR psz2;
  973. iRet = -1; // arbitrary on failure
  974. if (pwsz1 && pwsz2)
  975. {
  976. if (AnsiFromUnicode(&psz1, pwsz1, sz1, SIZECHARS(sz1)))
  977. {
  978. if (AnsiFromUnicode(&psz2, pwsz2, sz2, SIZECHARS(sz2)))
  979. {
  980. iRet = CompareStringA(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT), NORM_IGNORECASE, psz1, -1, psz2, -1) - CSTR_EQUAL;
  981. AnsiFromUnicode(&psz2, NULL, sz2, 0); // Free
  982. }
  983. AnsiFromUnicode(&psz1, NULL, sz1, 0); // Free
  984. }
  985. }
  986. }
  987. return iRet;
  988. }
  989. #ifdef UNIX
  990. #ifdef BIG_ENDIAN
  991. #define READNATIVEWORD(x) MAKEWORD(*(char*)(x), *(char*)((char*)(x) + 1))
  992. #else
  993. #define READNATIVEWORD(x) MAKEWORD(*(char*)((char*)(x) + 1), *(char*)(x))
  994. #endif
  995. #else
  996. #define READNATIVEWORD(x) (*(UNALIGNED WORD *)x)
  997. #endif
  998. int WINAPI MLStrToIntA(
  999. LPCSTR lpSrc)
  1000. {
  1001. int n = 0;
  1002. BOOL bNeg = FALSE;
  1003. if (*lpSrc == '-') {
  1004. bNeg = TRUE;
  1005. lpSrc++;
  1006. }
  1007. while (IS_DIGITA(*lpSrc)) {
  1008. n *= 10;
  1009. n += *lpSrc - '0';
  1010. lpSrc++;
  1011. }
  1012. return bNeg ? -n : n;
  1013. }
  1014. int WINAPI MLStrToIntW(
  1015. LPCWSTR lpSrc)
  1016. {
  1017. int n = 0;
  1018. BOOL bNeg = FALSE;
  1019. if (*lpSrc == L'-') {
  1020. bNeg = TRUE;
  1021. lpSrc++;
  1022. }
  1023. while (IS_DIGITW(*lpSrc)) {
  1024. n *= 10;
  1025. n += *lpSrc - L'0';
  1026. lpSrc++;
  1027. }
  1028. return bNeg ? -n : n;
  1029. }
  1030. /*
  1031. * ChrCmpI - Case insensitive character comparison for DBCS
  1032. * Assumes w1, wMatch are characters to be compared;
  1033. * HIBYTE of wMatch is 0 if not a DBC
  1034. * Return FALSE if match, TRUE if not
  1035. */
  1036. BOOL ChrCmpIA(WORD w1, WORD wMatch)
  1037. {
  1038. char sz1[3], sz2[3];
  1039. if (IsDBCSLeadByte(sz1[0] = LOBYTE(w1)))
  1040. {
  1041. sz1[1] = HIBYTE(w1);
  1042. sz1[2] = '\0';
  1043. }
  1044. else
  1045. sz1[1] = '\0';
  1046. #if defined(MWBIG_ENDIAN)
  1047. sz2[0] = LOBYTE(wMatch);
  1048. sz2[1] = HIBYTE(wMatch);
  1049. #else
  1050. *(WORD *)sz2 = wMatch;
  1051. #endif
  1052. sz2[2] = '\0';
  1053. return lstrcmpiA(sz1, sz2);
  1054. }
  1055. BOOL ChrCmpIW(WCHAR w1, WCHAR wMatch)
  1056. {
  1057. WCHAR sz1[2], sz2[2];
  1058. sz1[0] = w1;
  1059. sz1[1] = '\0';
  1060. sz2[0] = wMatch;
  1061. sz2[1] = '\0';
  1062. return lstrcmpiW(sz1, sz2);
  1063. }
  1064. /*
  1065. * StrCmpNI - Compare n bytes, case insensitive
  1066. *
  1067. * returns See lstrcmpi return values.
  1068. */
  1069. int MLStrCmpNIA(LPCSTR lpStr1, LPCSTR lpStr2, int nChar)
  1070. {
  1071. int i;
  1072. LPCSTR lpszEnd = lpStr1 + nChar;
  1073. for ( ; (lpszEnd > lpStr1) && (*lpStr1 || *lpStr2); (lpStr1 = AnsiNext(lpStr1)), (lpStr2 = AnsiNext(lpStr2))) {
  1074. WORD w1;
  1075. WORD w2;
  1076. // If either pointer is at the null terminator already,
  1077. // we want to copy just one byte to make sure we don't read
  1078. // past the buffer (might be at a page boundary).
  1079. w1 = (*lpStr1) ? READNATIVEWORD(lpStr1) : 0;
  1080. w2 = (UINT)(IsDBCSLeadByte(*lpStr2)) ? (UINT)READNATIVEWORD(lpStr2) : (WORD)(BYTE)(*lpStr2);
  1081. i = ChrCmpIA(w1, w2);
  1082. if (i)
  1083. return i;
  1084. }
  1085. return 0;
  1086. }
  1087. int MLStrCmpNIW(LPCWSTR lpStr1, LPCWSTR lpStr2, int nChar)
  1088. {
  1089. int i;
  1090. LPCWSTR lpszEnd = lpStr1 + nChar;
  1091. for ( ; (lpszEnd > lpStr1) && (*lpStr1 || *lpStr2); lpStr1++, lpStr2++) {
  1092. i = ChrCmpIW(*lpStr1, *lpStr2);
  1093. if (i) {
  1094. return i;
  1095. }
  1096. }
  1097. return 0;
  1098. }
  1099. HRESULT _IsCodePageInstallable(UINT uiCodePage)
  1100. {
  1101. MIMECPINFO cpInfo;
  1102. UINT uiFamCp;
  1103. HRESULT hr;
  1104. if (NULL != g_pMimeDatabase)
  1105. hr = g_pMimeDatabase->GetCodePageInfo(uiCodePage, 0x409, &cpInfo);
  1106. else
  1107. hr = E_OUTOFMEMORY;
  1108. if (FAILED(hr))
  1109. return E_INVALIDARG;
  1110. uiFamCp = cpInfo.uiFamilyCodePage;
  1111. if (g_bIsNT5)
  1112. {
  1113. hr = IsNTLangpackAvailable(uiFamCp);
  1114. }
  1115. else
  1116. {
  1117. CLSID clsid;
  1118. // clsid is just used for place holder
  1119. hr = _GetJITClsIDForCodePage(uiFamCp, &clsid);
  1120. }
  1121. return hr;
  1122. }
  1123. //
  1124. // CML2 specific utilities
  1125. //
  1126. //
  1127. // CMultiLanguage2::EnsureIEStatus()
  1128. //
  1129. // ensures CML2::m_pIEStat
  1130. //
  1131. HRESULT CMultiLanguage2::EnsureIEStatus(void)
  1132. {
  1133. HRESULT hr = S_OK;
  1134. // initialize IE status cache
  1135. if (!m_pIEStat)
  1136. {
  1137. m_pIEStat = new CIEStatus();
  1138. if (m_pIEStat)
  1139. {
  1140. hr = m_pIEStat->Init();
  1141. }
  1142. }
  1143. return hr;
  1144. }
  1145. //
  1146. // CIEStatus::Init()
  1147. //
  1148. // initializes the IE status;
  1149. //
  1150. HRESULT CMultiLanguage2::CIEStatus::Init(void)
  1151. {
  1152. HRESULT hr = S_OK;
  1153. HKEY hkey;
  1154. // Get JIT satus
  1155. if (RegOpenKeyEx(HKEY_CURRENT_USER,
  1156. REGSTR_PATH_MAIN,
  1157. 0, KEY_READ, &hkey) == ERROR_SUCCESS)
  1158. {
  1159. DWORD dwVal, dwType;
  1160. DWORD dwSize = sizeof(dwVal);
  1161. RegQueryValueEx(hkey, TEXT("nojitsetup"), 0, &dwType, (LPBYTE)&dwVal, &dwSize);
  1162. RegCloseKey(hkey);
  1163. if (dwType == REG_DWORD && dwSize == sizeof(dwVal))
  1164. {
  1165. if (dwVal > 0 )
  1166. _IEFlags.fJITDisabled = TRUE;
  1167. else
  1168. _IEFlags.fJITDisabled = FALSE;
  1169. }
  1170. }
  1171. else
  1172. hr = E_FAIL;
  1173. // any other status to get initialized
  1174. // ...
  1175. return hr;
  1176. }
  1177. #define NT5LPK_DLG_STRING "MLang.NT5LpkDlg"
  1178. //
  1179. // LangpackDlgProc()
  1180. //
  1181. // Message handler for the NT5 langpack dialog.
  1182. //
  1183. INT_PTR CALLBACK LangpackDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1184. {
  1185. ASSERT(g_bIsNT5);
  1186. switch (uMsg)
  1187. {
  1188. case WM_INITDIALOG:
  1189. HWND hwndCheckBox;
  1190. RECT rc1, rc2;
  1191. MIMECPINFO cpInfo;
  1192. SetProp(hDlg, NT5LPK_DLG_STRING, (HANDLE)lParam);
  1193. if ((NULL != g_pMimeDatabase) &&
  1194. SUCCEEDED(g_pMimeDatabase->GetCodePageInfo(HIWORD(lParam), GetNT5UILanguage(), &cpInfo)))
  1195. {
  1196. for (int i=0; i<MAX_MIMECP_NAME && cpInfo.wszDescription[i]; i++)
  1197. {
  1198. if (cpInfo.wszDescription[i] == L'(')
  1199. {
  1200. cpInfo.wszDescription[i] = 0;
  1201. break;
  1202. }
  1203. }
  1204. // Use W version regardlessly since we're only running this on NT5
  1205. SetDlgItemTextW(hDlg, IDC_STATIC_LANG, cpInfo.wszDescription);
  1206. }
  1207. // Center the dialog in the area of parent window
  1208. if (GetWindowRect(GetParent(hDlg), &rc1) && GetWindowRect(hDlg, &rc2))
  1209. {
  1210. MoveWindow(hDlg, (rc1.right+rc2.left+rc1.left-rc2.right)/2, (rc1.bottom+rc2.top+rc1.top-rc2.bottom)/2, rc2.right-rc2.left, rc2.bottom-rc2.top, FALSE);
  1211. }
  1212. hwndCheckBox = GetDlgItem(hDlg, IDC_CHECK_LPK);
  1213. // Set CheckBox state according to current registry setting
  1214. PostMessage(hwndCheckBox, BM_SETCHECK, LOWORD(lParam)? BST_UNCHECKED:BST_CHECKED, 0);
  1215. break;
  1216. case WM_COMMAND:
  1217. if (LOWORD(wParam) != IDC_CHECK_LPK)
  1218. {
  1219. HKEY hkey;
  1220. DWORD dwInstallOut = (BST_CHECKED == SendMessage(GetDlgItem(hDlg, IDC_CHECK_LPK), BM_GETCHECK, 0, 0)? 0:1);
  1221. DWORD dwInstallIn = LOWORD(GetProp(hDlg, NT5LPK_DLG_STRING));
  1222. if ((dwInstallOut != dwInstallIn) &&
  1223. ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER,
  1224. REGSTR_PATH_INTERNATIONAL,
  1225. NULL, KEY_READ|KEY_SET_VALUE, &hkey))
  1226. {
  1227. DWORD dwType = REG_DWORD;
  1228. DWORD dwSize = sizeof(DWORD);
  1229. RegSetValueEx(hkey, REG_KEY_NT5LPK, 0, REG_DWORD, (LPBYTE)&dwInstallOut, sizeof(dwInstallOut));
  1230. RegCloseKey(hkey);
  1231. }
  1232. EndDialog(hDlg, LOWORD(wParam) == IDOK? 1: 0);
  1233. }
  1234. break;
  1235. case WM_HELP:
  1236. // Do we need help file for this simply dialog?
  1237. // If needed, we can always add it at later time.
  1238. break;
  1239. default:
  1240. return FALSE;
  1241. }
  1242. return TRUE;
  1243. }
  1244. // To get real Windows directory on Terminal Server,
  1245. // Instead of using internal Kernel32 API GetSystemWindowsDirectory with LoadLibrary/GetProcAddress,
  1246. // We cast GetSystemDirectory return to Windows directory
  1247. UINT MLGetWindowsDirectory(
  1248. LPTSTR lpBuffer, // address of buffer for Windows directory
  1249. UINT uSize // size of directory buffer
  1250. )
  1251. {
  1252. UINT uLen;
  1253. if (g_bIsNT)
  1254. {
  1255. if (uLen = GetSystemDirectory(lpBuffer, uSize))
  1256. {
  1257. if (lpBuffer[uLen-1] == TEXT('\\'))
  1258. uLen--;
  1259. while (uLen-- > 0)
  1260. {
  1261. if (lpBuffer[uLen] == TEXT('\\'))
  1262. {
  1263. lpBuffer[uLen] = NULL;
  1264. break;
  1265. }
  1266. }
  1267. }
  1268. }
  1269. else
  1270. uLen = GetWindowsDirectory(lpBuffer, uSize);
  1271. return uLen;
  1272. }
  1273. // To speed up basic ANSI string compare,
  1274. // We avoid using lstrcmpi in LOW-ASCII case
  1275. int LowAsciiStrCmpNIA(LPCSTR lpstr1, LPCSTR lpstr2, int count)
  1276. {
  1277. int delta;
  1278. while (count-- > 0)
  1279. {
  1280. delta = *lpstr1 - *lpstr2;
  1281. if (delta &&
  1282. !(IS_CHARA(*lpstr1) && IS_CHARA(*lpstr2) && (delta == 0x20 || delta == -0x20)))
  1283. return delta;
  1284. lpstr1++;
  1285. lpstr2++;
  1286. }
  1287. return 0;
  1288. }
  1289. //
  1290. // GetNT5UILanguage(void)
  1291. //
  1292. LANGID GetNT5UILanguage(void)
  1293. {
  1294. if (g_bIsNT5)
  1295. {
  1296. static LANGID (CALLBACK* pfnGetUserDefaultUILanguage)(void) = NULL;
  1297. if (pfnGetUserDefaultUILanguage == NULL)
  1298. {
  1299. HMODULE hmod = GetModuleHandle(TEXT("KERNEL32"));
  1300. if (hmod)
  1301. pfnGetUserDefaultUILanguage = (LANGID (CALLBACK*)(void))GetProcAddress(hmod, "GetUserDefaultUILanguage");
  1302. }
  1303. if (pfnGetUserDefaultUILanguage)
  1304. return pfnGetUserDefaultUILanguage();
  1305. }
  1306. return 0;
  1307. }
  1308. // Special characters that we should filter out
  1309. WCHAR wszBestFit[] = {0x00A6, 0x00A9, 0x00AB, 0x00AD, 0x00AE, 0x00B7, 0x00BB, 0x02C6, 0x02DC, 0x2013,
  1310. 0x2014, 0x2018, 0x2019, 0x201A, 0x201C,0x201D, 0x201E, 0x2022, 0x2026, 0x2039, 0x203A,0x2122, 0x0000};
  1311. DWORD OutBoundDetectPreScan(LPWSTR lpWideCharStr, UINT cchWideChar, WCHAR *pwszCopy, WCHAR *lpBestFitChar)
  1312. {
  1313. DWORD dwRet = 0;
  1314. WCHAR *lpStart;
  1315. if (!lpBestFitChar)
  1316. lpBestFitChar = wszBestFit;
  1317. lpStart = lpBestFitChar;
  1318. if (pwszCopy)
  1319. {
  1320. MLStrCpyNW(pwszCopy, lpWideCharStr, cchWideChar);
  1321. lpWideCharStr = pwszCopy;
  1322. }
  1323. if (lpWideCharStr)
  1324. {
  1325. for (UINT ui=0; ui<cchWideChar; ui++)
  1326. {
  1327. if (IS_CJK_CHAR(*lpWideCharStr))
  1328. dwRet |= FS_CJK;
  1329. else if (IS_HINDI_CHAR(*lpWideCharStr))
  1330. dwRet |= FS_HINDI;
  1331. else if (IS_PUA_CHAR(*lpWideCharStr))
  1332. dwRet |= FS_PUA;
  1333. else if (pwszCopy)
  1334. {
  1335. while (*lpBestFitChar)
  1336. {
  1337. if (*lpWideCharStr == *lpBestFitChar)
  1338. *lpWideCharStr = 0x20;
  1339. lpBestFitChar++;
  1340. }
  1341. lpBestFitChar = lpStart;
  1342. }
  1343. lpWideCharStr++;
  1344. }
  1345. }
  1346. return dwRet;
  1347. }
  1348. //
  1349. // Whistler bug #90433 WEIWU 07/06/00
  1350. //
  1351. // Outlook has a bug its RTFHTML, this component doesn't CoInitialize/
  1352. // CoUninitialize COM, but, it uses MLang COM services, it depends on
  1353. // other threads (components) to deal with COM, when COM is unloaded by those threads.
  1354. // Invoking the interface pointer causes AV. RTFHTML should CoInit/CoUnInit by
  1355. // itself.
  1356. //
  1357. // The reason for this to be working before is - MLang was depending on ATL
  1358. // for objects management, ATL create heap for MLang object allocations, MLang
  1359. // notifies ATL to destroy the heap at DLL detach time and RTFHTML's IsBadReadPtr
  1360. // () caught the invalid pointer. Now in Whistler, MLang includes crtfree.h
  1361. // which overwrites ATL memory management functions (same as other shell
  1362. // components), so, nothing is allocated from the process heap, this is fine for
  1363. // MLang since it assumes that clients use COM correctly.
  1364. //
  1365. // Now, we add this function to check Outlook version, if it is the buggy Outlook,
  1366. // We'll load mlang.dll itself DllGetClassObject() to increase the Dll ref count
  1367. //
  1368. BOOL NeedToLoadMLangForOutlook(void)
  1369. {
  1370. TCHAR szModulePath[MAX_PATH];
  1371. CHAR chBuffer[4096];
  1372. DWORD dwHandle;
  1373. VS_FIXEDFILEINFO * pszVersion;
  1374. static BOOL bMLangLoaded = FALSE;
  1375. if (!bMLangLoaded)
  1376. {
  1377. if (GetModuleFileName(GetModuleHandle(NULL), szModulePath, ARRAYSIZE(szModulePath)))
  1378. {
  1379. if (MLStrStr(szModulePath, TEXT("OUTLOOK.EXE")))
  1380. {
  1381. UINT cb = GetFileVersionInfoSize(szModulePath, &dwHandle);
  1382. if (cb <= sizeof(chBuffer) &&
  1383. GetFileVersionInfo(szModulePath, dwHandle, sizeof(chBuffer), (void *)chBuffer) &&
  1384. VerQueryValue((void *)chBuffer, TEXT("\\"), (void **) &pszVersion, &cb) &&
  1385. (HIWORD(pszVersion->dwProductVersionMS) <= 0x09))
  1386. {
  1387. bMLangLoaded = TRUE;
  1388. return TRUE;
  1389. }
  1390. }
  1391. }
  1392. }
  1393. return FALSE;
  1394. }
  1395. //
  1396. // staticIsOS() doesn't support newer Whistler OS flags.
  1397. // Borrow code from shlwapi - IsOS()
  1398. //
  1399. BOOL MLIsOS(DWORD dwOS)
  1400. {
  1401. BOOL bRet;
  1402. static OSVERSIONINFOEXA s_osvi = {0};
  1403. static BOOL s_bVersionCached = FALSE;
  1404. if (!s_bVersionCached)
  1405. {
  1406. s_bVersionCached = TRUE;
  1407. s_osvi.dwOSVersionInfoSize = sizeof(s_osvi);
  1408. if (!GetVersionExA((OSVERSIONINFOA*)&s_osvi))
  1409. {
  1410. // If it failed, it must be a down level platform
  1411. s_osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
  1412. GetVersionExA((OSVERSIONINFOA*)&s_osvi);
  1413. }
  1414. }
  1415. switch (dwOS)
  1416. {
  1417. case OS_TERMINALREMOTEADMIN:
  1418. // this checks to see if TS has been installed in the "Remote Administration" mode. This is
  1419. // the default for server installs on win2k and whistler
  1420. bRet = ((VER_SUITE_TERMINAL & s_osvi.wSuiteMask) &&
  1421. (VER_SUITE_SINGLEUSERTS & s_osvi.wSuiteMask));
  1422. break;
  1423. case 4: // used to be OS_NT5, is the same as OS_WIN2000ORGREATER so use that instead
  1424. case OS_WIN2000ORGREATER:
  1425. bRet = (VER_PLATFORM_WIN32_NT == s_osvi.dwPlatformId &&
  1426. s_osvi.dwMajorVersion >= 5);
  1427. break;
  1428. // NOTE: The flags in this section are bogus and SHOULD NOT BE USED (but downlevel shell32 uses them, so don't RIP there)
  1429. case OS_WIN2000PRO:
  1430. RIPMSG(!MLIsOS(OS_WHISTLERORGREATER), "IsOS: use OS_PROFESSIONAL instead of OS_WIN2000PRO !");
  1431. bRet = (VER_NT_WORKSTATION == s_osvi.wProductType &&
  1432. s_osvi.dwMajorVersion == 5);
  1433. break;
  1434. case OS_WIN2000ADVSERVER:
  1435. RIPMSG(!MLIsOS(OS_WHISTLERORGREATER), "IsOS: use OS_ADVSERVER instead of OS_WIN2000ADVSERVER !");
  1436. bRet = ((VER_NT_SERVER == s_osvi.wProductType ||
  1437. VER_NT_DOMAIN_CONTROLLER == s_osvi.wProductType) &&
  1438. s_osvi.dwMajorVersion == 5 &&
  1439. (VER_SUITE_ENTERPRISE & s_osvi.wSuiteMask) &&
  1440. !(VER_SUITE_DATACENTER & s_osvi.wSuiteMask));
  1441. break;
  1442. case OS_WIN2000DATACENTER:
  1443. RIPMSG(!MLIsOS(OS_WHISTLERORGREATER), "IsOS: use OS_DATACENTER instead of OS_WIN2000DATACENTER !");
  1444. bRet = ((VER_NT_SERVER == s_osvi.wProductType ||
  1445. VER_NT_DOMAIN_CONTROLLER == s_osvi.wProductType) &&
  1446. s_osvi.dwMajorVersion == 5 &&
  1447. (VER_SUITE_DATACENTER & s_osvi.wSuiteMask));
  1448. break;
  1449. case OS_WIN2000SERVER:
  1450. RIPMSG(!MLIsOS(OS_WHISTLERORGREATER), "IsOS: use OS_SERVER instead of OS_WIN2000SERVER !");
  1451. bRet = ((VER_NT_SERVER == s_osvi.wProductType ||
  1452. VER_NT_DOMAIN_CONTROLLER == s_osvi.wProductType) &&
  1453. !(VER_SUITE_DATACENTER & s_osvi.wSuiteMask) &&
  1454. !(VER_SUITE_ENTERPRISE & s_osvi.wSuiteMask) &&
  1455. s_osvi.dwMajorVersion == 5);
  1456. break;
  1457. // END bogus Flags
  1458. case OS_EMBEDDED:
  1459. bRet = (VER_SUITE_EMBEDDEDNT & s_osvi.wSuiteMask);
  1460. break;
  1461. case OS_WINDOWS:
  1462. bRet = (VER_PLATFORM_WIN32_WINDOWS == s_osvi.dwPlatformId);
  1463. break;
  1464. case OS_NT:
  1465. bRet = (VER_PLATFORM_WIN32_NT == s_osvi.dwPlatformId);
  1466. break;
  1467. case OS_WIN98ORGREATER:
  1468. bRet = (VER_PLATFORM_WIN32_WINDOWS == s_osvi.dwPlatformId &&
  1469. (s_osvi.dwMajorVersion > 4 ||
  1470. s_osvi.dwMajorVersion == 4 && s_osvi.dwMinorVersion >= 10));
  1471. break;
  1472. case OS_WIN98_GOLD:
  1473. bRet = (VER_PLATFORM_WIN32_WINDOWS == s_osvi.dwPlatformId &&
  1474. s_osvi.dwMajorVersion == 4 && s_osvi.dwMinorVersion == 10 &&
  1475. LOWORD(s_osvi.dwBuildNumber) == 1998);
  1476. break;
  1477. case OS_MILLENNIUMORGREATER:
  1478. bRet = (VER_PLATFORM_WIN32_WINDOWS == s_osvi.dwPlatformId &&
  1479. ((s_osvi.dwMajorVersion == 4 && s_osvi.dwMinorVersion >= 90) ||
  1480. s_osvi.dwMajorVersion > 4));
  1481. break;
  1482. case OS_WHISTLERORGREATER:
  1483. bRet = (VER_PLATFORM_WIN32_NT == s_osvi.dwPlatformId &&
  1484. ((s_osvi.dwMajorVersion > 5) ||
  1485. (s_osvi.dwMajorVersion == 5 && (s_osvi.dwMinorVersion > 0 ||
  1486. (s_osvi.dwMinorVersion == 0 && LOWORD(s_osvi.dwBuildNumber) > 2195)))));
  1487. break;
  1488. case OS_PERSONAL:
  1489. bRet = (VER_PLATFORM_WIN32_NT == s_osvi.dwPlatformId &&
  1490. (VER_SUITE_PERSONAL & s_osvi.wSuiteMask));
  1491. break;
  1492. default:
  1493. bRet = FALSE;
  1494. break;
  1495. }
  1496. return bRet;
  1497. }