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.

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