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.

1914 lines
57 KiB

  1. ///////////////////////////////////////////////////////////////////////
  2. // Microsoft Windows //
  3. // Copyright(c) Microsoft Corp., 1995 //
  4. ///////////////////////////////////////////////////////////////////////
  5. //
  6. // LANG.CPP - "Language" property page for InetCpl
  7. //
  8. // HISTORY:
  9. //
  10. // 1/10/97 beomoh created
  11. //
  12. #include "inetcplp.h"
  13. #include <tchar.h>
  14. #include <mlang.h>
  15. #include "psapi.h"
  16. #include "tlhelp32.h"
  17. #include "process.h"
  18. #include <mluisupp.h>
  19. #include <shdocvw.h>
  20. #define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
  21. #define FORMAT_STR TEXT("%s [%s]")
  22. #define MAX_LIST_STRING_LEN MAX_LOCALE_NAME + MAX_RFC1766_NAME + 3
  23. #define MAX_ACCEPT_LANG_LEN 2048
  24. #define CP_THAI 874
  25. #define CP_ARABIC 1256
  26. #define CP_HEBREW 1255
  27. // used as the return value from setlang dialog
  28. #define RETURN_SETLANG_ENDLANGDIALOG 2
  29. #define RETURN_SETLANG_CLOSEDNORMAL 1
  30. #define RETURN_SETLANG_CANCELED 0
  31. typedef HRESULT (* PCOINIT) (LPVOID);
  32. typedef VOID (* PCOUNINIT) (VOID);
  33. typedef VOID (* PCOMEMFREE) (LPVOID);
  34. typedef HRESULT (* PCOCREINST) (REFCLSID, LPUNKNOWN, DWORD, REFIID, LPVOID * );
  35. extern HMODULE hOLE32;
  36. extern PCOINIT pCoInitialize;
  37. extern PCOUNINIT pCoUninitialize;
  38. extern PCOMEMFREE pCoTaskMemFree;
  39. extern PCOCREINST pCoCreateInstance;
  40. extern BOOL _StartOLE32();
  41. class CUILangList;
  42. INT_PTR KickSetLang(HWND hDlg, CUILangList * pLangList);
  43. static const TCHAR s_szResourceLocale[] = TEXT("ResourceLocale");
  44. // HKLM\Software\Microsoft\Internet Explorer\International used for url string
  45. static const TCHAR s_szUrlSPK[]
  46. = TEXT("http://www.microsoft.com/isapi/redir.dll?prd=ie&pver=6&ar=plugui&sba=install");
  47. static const TCHAR c_szInstall[]
  48. = TEXT("Software\\Microsoft\\Active Setup\\Installed Components\\{89820200-ECBD-11CF-8B85-00AA005B4383}");
  49. static const TCHAR c_szLocale[] = TEXT("Locale");
  50. static const TCHAR s_szLangPackPath[] = TEXT("Software\\Microsoft\\Internet Explorer");
  51. static const TCHAR s_szVersion[] = TEXT("LPKInstalled");
  52. typedef struct
  53. {
  54. WORD wlangid;
  55. BOOL fValid;
  56. TCHAR szName[MAX_LOCALE_NAME];
  57. } LANGLIST;
  58. static LANGLIST s_arryLangList[] =
  59. {
  60. {0x0409, FALSE, {0}},
  61. {0x0407, FALSE, {0}},
  62. {0x0411, FALSE, {0}},
  63. {0x0412, FALSE, {0}},
  64. {0x0404, FALSE, {0}},
  65. {0x0804, FALSE, {0}},
  66. {0x040c, FALSE, {0}},
  67. {0x0c0a, FALSE, {0}},
  68. {0x0416, FALSE, {0}},
  69. {0x0410, FALSE, {0}},
  70. {0x0413, FALSE, {0}},
  71. {0x041d, FALSE, {0}},
  72. {0x0406, FALSE, {0}},
  73. {0x040b, FALSE, {0}},
  74. {0x040e, FALSE, {0}},
  75. {0x0414, FALSE, {0}},
  76. {0x0408, FALSE, {0}},
  77. {0x0415, FALSE, {0}},
  78. {0x0419, FALSE, {0}},
  79. {0x0405, FALSE, {0}},
  80. {0x0816, FALSE, {0}},
  81. {0x041f, FALSE, {0}},
  82. {0x041b, FALSE, {0}},
  83. {0x0424, FALSE, {0}},
  84. {0x0401, FALSE, {0}},
  85. {0x040d, FALSE, {0}},
  86. {0x042d, FALSE, {0}},
  87. {0x040f, FALSE, {0}},
  88. };
  89. //
  90. // ISO639 ID table
  91. //
  92. typedef struct tagISO639
  93. {
  94. LPCTSTR ISO639;
  95. LANGID LangID;
  96. } ISO639, *LPISO639;
  97. const ISO639 c_ISO639[] =
  98. {
  99. { TEXT("EN"), 0x0409 },
  100. { TEXT("DE"), 0x0407 },
  101. { TEXT("JA"), 0x0411 },
  102. { TEXT("KO"), 0x0412 },
  103. { TEXT("TW"), 0x0404 },
  104. { TEXT("CN"), 0x0804 },
  105. { TEXT("FR"), 0x040C },
  106. { TEXT("ES"), 0x0C0A },
  107. { TEXT("BR"), 0x0416 },
  108. { TEXT("IT"), 0x0410 },
  109. { TEXT("NL"), 0x0413 },
  110. { TEXT("SV"), 0x041D },
  111. { TEXT("DA"), 0x0406 },
  112. { TEXT("FI"), 0x040B },
  113. { TEXT("HU"), 0x040E },
  114. { TEXT("NO"), 0x0414 },
  115. { TEXT("EL"), 0x0408 },
  116. { TEXT("PL"), 0x0415 },
  117. { TEXT("RU"), 0x0419 },
  118. { TEXT("CS"), 0x0405 },
  119. { TEXT("PT"), 0x0816 },
  120. { TEXT("TR"), 0x041F },
  121. { TEXT("SK"), 0x041B },
  122. { TEXT("SL"), 0x0424 },
  123. { TEXT("AR"), 0x0401 },
  124. { TEXT("HE"), 0x040D },
  125. { TEXT("EU"), 0x042D },
  126. { TEXT("IS"), 0x040F },
  127. };
  128. // GetInstallLanguage
  129. //
  130. // synopsis - borrowed this function from shlwapi. we can remove this
  131. // once we have it exported from shlwapi.dll
  132. //
  133. LANGID GetInstallLanguage(void)
  134. {
  135. static LANGID LangID = 0;
  136. TCHAR szISO639[3];
  137. DWORD cb;
  138. if (0 == LangID)
  139. {
  140. cb = sizeof(szISO639);
  141. if (ERROR_SUCCESS == SHGetValue(HKEY_LOCAL_MACHINE, c_szInstall, c_szLocale, NULL, szISO639, &cb))
  142. {
  143. int i;
  144. for (i = 0; i < ARRAYSIZE(c_ISO639); i++)
  145. {
  146. if (!StrCmpNI(szISO639, c_ISO639[i].ISO639, ARRAYSIZE(szISO639)))
  147. {
  148. LangID = c_ISO639[i].LangID;
  149. break;
  150. }
  151. }
  152. }
  153. }
  154. return LangID;
  155. }
  156. // CUILangList
  157. //
  158. // maintains the list of UI languages for user to choose
  159. //
  160. class CUILangList
  161. {
  162. public:
  163. CUILangList() {_iLangIdx = -1; lang = s_arryLangList;
  164. _nLangList = ARRAYSIZE(s_arryLangList);
  165. _fOffice9Installed = -1;};
  166. void ValidateLangList();
  167. BOOL IsValidLang(int idx) { return (idx < _nLangList) ? lang[idx].fValid: FALSE; };
  168. int GetCurrentLangIdx();
  169. void SetCurrentLangIdx(int idx);
  170. LPCTSTR GetCurrentLangName();
  171. LPCTSTR GetLangNameOfIdx(int idx);
  172. WORD GetLangIdOfIdx(int idx) { return (idx < _nLangList) ? lang[idx].wlangid:0; };
  173. UINT GetIds(int idx);
  174. int GetListSize() {return _nLangList;};
  175. BOOL IsOffice9Installed();
  176. static HRESULT GetLangList(HWND hdlg, CUILangList ** ppLangList);
  177. static HRESULT RemoveLangList(HWND hdlg);
  178. private:
  179. int _iLangIdx;
  180. int _nLangList;
  181. int _fOffice9Installed;
  182. LANGLIST *lang;
  183. };
  184. // CShutDownProcInfo
  185. //
  186. // manages information about processes we want
  187. // to shutdown/restart.
  188. //
  189. typedef enum
  190. {
  191. PS_UNKNOWN=0,
  192. PS_CANDIDATE,
  193. PS_TO_BE_SHUTDOWN,
  194. PS_IGNORE,
  195. PS_SHUTDOWN_OK,
  196. PS_WAITING,
  197. PS_TO_BE_SHUTDOWN_WITH_NO_RELAUNCH,
  198. PS_SHUTDOWN_OK_NO_RELAUNCH_NEEDED,
  199. } PROCSTATE;
  200. class CShutDownProcInfo : public CProcessInfo
  201. {
  202. public:
  203. CShutDownProcInfo(HWND hdlgParent);
  204. ~CShutDownProcInfo();
  205. HRESULT EnsureProcList();
  206. HRESULT IncreaseProcList();
  207. HRESULT NotifyShutDownToFolks(int *nProccess);
  208. HRESULT AddToProcList(HWND hwndShutDown);
  209. HRESULT WaitForOneProcess(int iProc);
  210. HRESULT WaitForFolksShutDown();
  211. HRESULT GetRestartAppPath(LPTSTR szPath, int cchPath, int iProc);
  212. HRESULT RestartFolks();
  213. static DWORD CALLBACK ShutDownThreadProc(void *pv);
  214. protected:
  215. typedef struct
  216. {
  217. DWORD dwPID;
  218. TCHAR szExeName[32];
  219. PROCSTATE State;
  220. } PROCLIST;
  221. PROCLIST *_pProcList;
  222. int _nAlloced;
  223. int _iProcList;
  224. HWND _hdlgParent;
  225. BOOL _fAllShutDown;
  226. };
  227. // this always fills '0' to empty digits
  228. // caller has to make sure sz has cdigit+1 of buffer
  229. void IntToHex(OUT LPTSTR sz, IN int cdigit, IN int value)
  230. {
  231. int i, idigit;
  232. if (sz && value > 0 && cdigit > 0)
  233. {
  234. // nul terminate the buffer
  235. sz[cdigit] = TEXT('\0');
  236. for (i = cdigit-1; i >= 0; i--, value /= 16)
  237. {
  238. idigit = value%16;
  239. if (idigit < 10)
  240. sz[i] = (TCHAR)idigit + TEXT('0');
  241. else
  242. sz[i] = (TCHAR)idigit - 10 + TEXT('A');
  243. }
  244. }
  245. }
  246. // set valid flags for the lang list
  247. // very expensive so expects to be called only once in a session
  248. // from CUILangList::GetLangList
  249. //
  250. #define MAX_SATELLITEPACKS 30 // 30 must be a practical number for satellite packs
  251. void CUILangList::ValidateLangList()
  252. {
  253. HKEY hKey;
  254. HRESULT hr;
  255. TCHAR szValueName[32];
  256. WORD aryValidLang[MAX_SATELLITEPACKS +1+1] = {0}; // +1 for install lang,
  257. // +1 for terminator
  258. int nMaxValidLang = ARRAYSIZE(aryValidLang)-1; // -1 for terminator
  259. WORD *pwValid = aryValidLang;
  260. // make the install language always valid
  261. *pwValid = GetInstallLanguage();
  262. if (*pwValid != 0)
  263. {
  264. *(pwValid+1) = 0; // terminator
  265. pwValid++;
  266. nMaxValidLang--;
  267. }
  268. if (ERROR_SUCCESS ==
  269. RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_INTERNATIONAL, NULL, KEY_READ, &hKey))
  270. {
  271. int i = 0;
  272. do {
  273. // see if the value has a match in the list
  274. DWORD dwType;
  275. DWORD cb = ARRAYSIZE(szValueName)-2;
  276. hr = SHEnumValue(hKey, i++, szValueName+2, &cb, &dwType, NULL, NULL);
  277. if (SUCCEEDED(hr) && dwType == REG_SZ)
  278. {
  279. UINT uiInstalled ;
  280. szValueName[0] = TEXT('0');
  281. szValueName[1] = TEXT('x');
  282. StrToIntEx(szValueName, STIF_SUPPORT_HEX, (LPINT)&uiInstalled);
  283. if (uiInstalled > 0)
  284. {
  285. *pwValid = (unsigned short) uiInstalled;
  286. *(pwValid+1) = 0; // terminator
  287. pwValid++;
  288. }
  289. }
  290. } while(hr == ERROR_SUCCESS && i < nMaxValidLang);
  291. RegCloseKey(hKey);
  292. }
  293. // this assumes we can use StrChrW to search a value in
  294. // a word array, it also assumes we never have 0 as a langid
  295. //
  296. Assert(sizeof(WORD) == sizeof(WCHAR)); // unix?
  297. int nValidLang = (int)(pwValid-aryValidLang);
  298. for(int idx = 0; idx < GetListSize(); idx++ )
  299. {
  300. // abusing the string function but this is a fast way
  301. if (StrChrW((WCHAR *)aryValidLang, (WCHAR)lang[idx].wlangid))
  302. {
  303. lang[idx].fValid = TRUE;
  304. if(--nValidLang <= 0)
  305. break;
  306. }
  307. }
  308. }
  309. static const TCHAR s_szPropLangList[] = TEXT("langlist");
  310. HRESULT CUILangList::GetLangList(HWND hdlg, CUILangList ** ppLangList)
  311. {
  312. HRESULT hr=S_OK;
  313. CUILangList *pLangList = (CUILangList *)GetProp(hdlg, s_szPropLangList);
  314. if (!pLangList)
  315. {
  316. pLangList = new CUILangList();
  317. if (pLangList)
  318. {
  319. pLangList->ValidateLangList();
  320. SetProp(hdlg, s_szPropLangList, (HANDLE)pLangList);
  321. }
  322. else
  323. hr = E_FAIL;
  324. }
  325. ASSERT(ppLangList);
  326. if (ppLangList)
  327. *ppLangList = pLangList;
  328. return hr;
  329. }
  330. HRESULT CUILangList::RemoveLangList(HWND hdlg)
  331. {
  332. HRESULT hr = S_OK;
  333. CUILangList *pLangList = (CUILangList *)GetProp(hdlg, s_szPropLangList);
  334. if (pLangList)
  335. {
  336. delete pLangList;
  337. RemoveProp(hdlg, s_szPropLangList);
  338. }
  339. else
  340. hr = S_FALSE;
  341. return hr;
  342. }
  343. void CUILangList::SetCurrentLangIdx(int idx)
  344. {
  345. TCHAR sz[4+1];
  346. if (idx != _iLangIdx)
  347. {
  348. // the resource id is always 4 digit
  349. IntToHex(sz, 4, lang[idx].wlangid);
  350. SHSetValue(HKEY_CURRENT_USER, REGSTR_PATH_INTERNATIONAL,
  351. s_szResourceLocale, REG_SZ, (void *)sz, sizeof(sz));
  352. _iLangIdx = idx;
  353. }
  354. }
  355. // returns idx to the lang array
  356. int CUILangList::GetCurrentLangIdx()
  357. {
  358. // show the current selection
  359. TCHAR sz[64];
  360. DWORD dwType;
  361. int isel;
  362. // see if it's cached already
  363. if (_iLangIdx == -1)
  364. {
  365. // We basically wants what we've set in the registry,
  366. // but if Office9 is installed we'll show whatever
  367. // Office sets, and we can't change the Office setting anyway
  368. // MLGetUILanguage returns Office's setting if its there
  369. // Also I suppose we want to show NT5's UI language here
  370. //
  371. if (IsOffice9Installed() || IsOS(OS_WIN2000ORGREATER))
  372. isel = INETCPL_GetUILanguage();
  373. else
  374. {
  375. DWORD dwcbData = sizeof(sz);
  376. HRESULT hr = SHGetValue(HKEY_CURRENT_USER, REGSTR_PATH_INTERNATIONAL,
  377. s_szResourceLocale, &dwType, (void *)&sz[2], &dwcbData);
  378. if (hr == ERROR_SUCCESS && dwType == REG_SZ)
  379. {
  380. sz[0] = TEXT('0');
  381. sz[1] = TEXT('x');
  382. StrToIntEx(sz, STIF_SUPPORT_HEX, (LPINT)&isel);
  383. }
  384. else
  385. {
  386. isel = GetInstallLanguage();
  387. }
  388. }
  389. for(int i = 0; i < GetListSize(); i++ )
  390. {
  391. if (isel == lang[i].wlangid)
  392. {
  393. _iLangIdx = i;
  394. break;
  395. }
  396. }
  397. // english for error case
  398. if (_iLangIdx < 0)
  399. _iLangIdx = 0;
  400. }
  401. return _iLangIdx;
  402. }
  403. LPCTSTR CUILangList::GetLangNameOfIdx(int idx)
  404. {
  405. LPCTSTR pszRet = NULL;
  406. IMultiLanguage2 *pML2;
  407. HRESULT hr;
  408. RFC1766INFO Rfc1766Info={0};
  409. if(!hOLE32)
  410. {
  411. if(!_StartOLE32())
  412. {
  413. ASSERT(FALSE);
  414. return NULL;
  415. }
  416. }
  417. hr = pCoInitialize(NULL);
  418. if (FAILED(hr))
  419. return NULL;
  420. hr = pCoCreateInstance(CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER, IID_IMultiLanguage2, (LPVOID *) &pML2);
  421. if (SUCCEEDED(hr))
  422. {
  423. if (idx >= 0)
  424. {
  425. if (!lang[idx].szName[0])
  426. {
  427. pML2->GetRfc1766Info(lang[idx].wlangid, INETCPL_GetUILanguage(), &Rfc1766Info);
  428. StrCpyNW(lang[idx].szName, Rfc1766Info.wszLocaleName, ARRAYSIZE(lang[0].szName));
  429. }
  430. pszRet = lang[idx].szName;
  431. }
  432. pML2->Release();
  433. }
  434. pCoUninitialize();
  435. return pszRet;
  436. }
  437. LPCTSTR CUILangList::GetCurrentLangName()
  438. {
  439. int idx = GetCurrentLangIdx();
  440. return GetLangNameOfIdx(idx);
  441. }
  442. BOOL CUILangList::IsOffice9Installed()
  443. {
  444. DWORD dwVersion;
  445. DWORD cb = sizeof(dwVersion);
  446. if (_fOffice9Installed < 0)
  447. {
  448. _fOffice9Installed ++;
  449. if (ERROR_SUCCESS ==
  450. SHGetValue(HKEY_LOCAL_MACHINE, s_szLangPackPath, s_szVersion, NULL, &dwVersion, &cb)
  451. && dwVersion > 0) // magic number - christw tells me so
  452. _fOffice9Installed ++;
  453. }
  454. return (BOOL)_fOffice9Installed;
  455. }
  456. void InitCurrentUILang(HWND hDlg)
  457. {
  458. BOOL fChanged = FALSE;
  459. CUILangList *pLangList;
  460. LPCTSTR pszLangSel = NULL;
  461. HRESULT hr;
  462. hr = CUILangList::GetLangList(hDlg, &pLangList);
  463. if (SUCCEEDED(hr))
  464. pszLangSel = pLangList->GetCurrentLangName();
  465. if (pszLangSel)
  466. {
  467. TCHAR szBig[1024], szSmall[256];
  468. GetDlgItemText(hDlg, IDC_LANG_CURSEL, szBig, ARRAYSIZE(szBig));
  469. if (szBig[0])
  470. fChanged = (StrStr(szBig, pszLangSel) == NULL);
  471. if (MLLoadString((fChanged)? IDS_LANG_FUTUREUSE: IDS_LANG_CURRENTUSE, szSmall, ARRAYSIZE(szSmall)) > 0)
  472. {
  473. wnsprintf(szBig, ARRAYSIZE(szBig), szSmall, pszLangSel);
  474. Static_SetText(GetDlgItem(hDlg, IDC_LANG_CURSEL), szBig);
  475. }
  476. }
  477. }
  478. //
  479. // FillAcceptListBox()
  480. //
  481. // Fills the accept language listbox with names of selected language
  482. //
  483. void FillAcceptListBox(IN HWND hDlg)
  484. {
  485. IMultiLanguage2 *pML2;
  486. HRESULT hr;
  487. HKEY hKey;
  488. DWORD cb;
  489. TCHAR sz[MAX_LIST_STRING_LEN], szBuf[MAX_ACCEPT_LANG_LEN], *p1, *p2, *p3;
  490. HWND hwndList = GetDlgItem(hDlg, IDC_LANG_ACCEPT_LIST);
  491. if(!hOLE32)
  492. {
  493. if(!_StartOLE32())
  494. {
  495. ASSERT(FALSE);
  496. return;
  497. }
  498. }
  499. hr = pCoInitialize(NULL);
  500. if (FAILED(hr))
  501. return;
  502. hr = pCoCreateInstance(CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER, IID_IMultiLanguage2, (LPVOID *) &pML2);
  503. if (SUCCEEDED(hr))
  504. {
  505. if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_CURRENT_USER, REGSTR_PATH_INTERNATIONAL, NULL, NULL, NULL, KEY_SET_VALUE|KEY_READ, NULL, &hKey, NULL))
  506. {
  507. LCID lcid;
  508. RFC1766INFO Rfc1766Info;
  509. TCHAR sz1[MAX_LIST_STRING_LEN], sz2[MAX_RFC1766_NAME];
  510. cb = sizeof(szBuf);
  511. if (ERROR_SUCCESS == RegQueryValueEx(hKey, REGSTR_VAL_ACCEPT_LANGUAGE, NULL, NULL, (LPBYTE)szBuf, &cb))
  512. {
  513. p1 = p2 = szBuf;
  514. while (NULL != *p1)
  515. {
  516. WCHAR wsz[MAX_LIST_STRING_LEN];
  517. BOOL bEnd = FALSE;
  518. while (TEXT(',') != *p2 && NULL != *p2)
  519. p2 = CharNext(p2);
  520. if (NULL != *p2)
  521. *p2 = NULL;
  522. else
  523. bEnd = TRUE;
  524. p3 = p1;
  525. while (TEXT(';') != *p3 && NULL != *p3)
  526. p3 = CharNext(p3);
  527. if (NULL != *p3)
  528. *p3 = NULL;
  529. #ifdef UNICODE
  530. StrCpyN(wsz, p1, ARRAYSIZE(wsz));
  531. #else
  532. MultiByteToWideChar(CP_ACP, 0, p1, -1, wsz, MAX_RFC1766_NAME);
  533. #endif
  534. hr = pML2->GetLcidFromRfc1766(&lcid, wsz);
  535. if (SUCCEEDED(hr))
  536. {
  537. hr = pML2->GetRfc1766Info(lcid, INETCPL_GetUILanguage(), &Rfc1766Info);
  538. if (SUCCEEDED(hr))
  539. {
  540. #ifdef UNICODE
  541. StrCpyN(sz1, Rfc1766Info.wszLocaleName, ARRAYSIZE(sz1));
  542. #else
  543. WideCharToMultiByte(CP_ACP, 0, Rfc1766Info.wszLocaleName, -1, sz1, MAX_LIST_STRING_LEN, NULL, NULL);
  544. #endif
  545. wnsprintf(sz, ARRAYSIZE(sz), FORMAT_STR, sz1, p1);
  546. }
  547. }
  548. else
  549. {
  550. MLLoadString(IDS_USER_DEFINED, sz1, ARRAYSIZE(sz1));
  551. wnsprintf(sz, ARRAYSIZE(sz), FORMAT_STR, sz1, p1);
  552. }
  553. ListBox_AddString(hwndList, sz);
  554. if (TRUE == bEnd)
  555. p1 = p2;
  556. else
  557. p1 = p2 = p2 + 1;
  558. }
  559. }
  560. else
  561. {
  562. lcid = GetUserDefaultLCID();
  563. hr = pML2->GetRfc1766Info(lcid, INETCPL_GetUILanguage(), &Rfc1766Info);
  564. if (SUCCEEDED(hr))
  565. {
  566. #ifdef UNICODE
  567. StrCpyN(sz1, Rfc1766Info.wszLocaleName, ARRAYSIZE(sz1));
  568. StrCpyN(sz2, Rfc1766Info.wszRfc1766, ARRAYSIZE(sz2));
  569. #else
  570. WideCharToMultiByte(CP_ACP, 0, Rfc1766Info.wszLocaleName, -1, sz1, MAX_LIST_STRING_LEN, NULL, NULL);
  571. WideCharToMultiByte(CP_ACP, 0, Rfc1766Info.wszRfc1766, -1, sz2, MAX_RFC1766_NAME, NULL, NULL);
  572. #endif
  573. wnsprintf(sz, ARRAYSIZE(sz), FORMAT_STR, sz1, sz2);
  574. ListBox_AddString(hwndList, sz);
  575. }
  576. }
  577. RegCloseKey(hKey);
  578. }
  579. pML2->Release();
  580. }
  581. pCoUninitialize();
  582. }
  583. //
  584. // LanguageDlgInit()
  585. //
  586. // Initializes the Language dialog.
  587. //
  588. BOOL LanguageDlgInit(IN HWND hDlg)
  589. {
  590. if (!hDlg)
  591. return FALSE; // nothing to initialize
  592. FillAcceptListBox(hDlg);
  593. EnableWindow(GetDlgItem(hDlg, IDC_LANG_REMOVE_BUTTON), FALSE);
  594. EnableWindow(GetDlgItem(hDlg, IDC_LANG_MOVE_UP_BUTTON), FALSE);
  595. EnableWindow(GetDlgItem(hDlg, IDC_LANG_MOVE_DOWN_BUTTON), FALSE);
  596. EnableWindow(GetDlgItem(hDlg, IDC_LANG_ADD_BUTTON), !g_restrict.fInternational);
  597. // On NT5, we use NT5's MUI feature instead of IE5 plugui
  598. if (IsOS(OS_WIN2000ORGREATER))
  599. ShowWindow(GetDlgItem(hDlg, IDC_LANG_UI_PREF), SW_HIDE);
  600. else
  601. {
  602. UINT uiACP = GetACP();
  603. // We don't support PlugUI on these platforms
  604. if (uiACP == CP_ARABIC || uiACP == CP_HEBREW || uiACP == CP_THAI)
  605. ShowWindow(GetDlgItem(hDlg, IDC_LANG_UI_PREF), SW_HIDE);
  606. else
  607. EnableWindow(GetDlgItem(hDlg, IDC_LANG_UI_PREF), !g_restrict.fInternational);
  608. }
  609. // show the current UI lang
  610. InitCurrentUILang(hDlg);
  611. // everything ok
  612. return TRUE;
  613. }
  614. //
  615. // SaveLanguageData()
  616. //
  617. // Save the new language settings into regestry
  618. //
  619. void SaveLanguageData(IN HWND hDlg)
  620. {
  621. HKEY hKey;
  622. DWORD dw;
  623. int i, iNumItems, iQ, n;
  624. TCHAR szBuf[MAX_ACCEPT_LANG_LEN];
  625. if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_CURRENT_USER, REGSTR_PATH_INTERNATIONAL, NULL, NULL, NULL, KEY_WRITE, NULL, &hKey, &dw ))
  626. {
  627. HWND hwndList = GetDlgItem(hDlg, IDC_LANG_ACCEPT_LIST);
  628. iNumItems = ListBox_GetCount(hwndList);
  629. for (n = 1, iQ = 10; iQ < iNumItems; iQ *= 10, n++)
  630. ;
  631. szBuf[0] = NULL;
  632. for (i = 0; i < iNumItems; i++)
  633. {
  634. TCHAR sz[MAX_LIST_STRING_LEN], *p1, *p2;
  635. ListBox_GetText(hwndList, i, sz);
  636. p1 = sz;
  637. // We can assume safely there is '[' and ']' in this string.
  638. while (TEXT('[') != *p1)
  639. p1 = CharNext(p1);
  640. p1 = p2 = p1 + 1;
  641. while (TEXT(']') != *p2)
  642. p2 = CharNext(p2);
  643. *p2 = NULL;
  644. if (0 == i)
  645. StrCpyN(szBuf, p1, ARRAYSIZE(szBuf));
  646. else
  647. {
  648. TCHAR szF[MAX_ACCEPT_LANG_LEN], szQ[MAX_ACCEPT_LANG_LEN];
  649. int len = lstrlen(szBuf);
  650. StrCpyN(szBuf + len, TEXT(","), ARRAYSIZE(szBuf) - len);
  651. len++;
  652. StrCpyN(szBuf + len, p1, ARRAYSIZE(szBuf) - len);
  653. wnsprintf(szF, ARRAYSIZE(szF), TEXT(";q=0.%%0%dd"), n);
  654. wnsprintf(szQ, ARRAYSIZE(szQ), szF, ((iNumItems - i) * iQ + (iNumItems / 2)) / iNumItems);
  655. len = lstrlen(szBuf);
  656. StrCpyN(szBuf + len , szQ, ARRAYSIZE(szBuf) - len);
  657. }
  658. }
  659. RegSetValueEx(hKey, REGSTR_VAL_ACCEPT_LANGUAGE, NULL, REG_SZ, (LPBYTE)szBuf, (lstrlen(szBuf)+1)*sizeof(TCHAR));
  660. RegCloseKey(hKey);
  661. }
  662. }
  663. // MoveUpDownListItem()
  664. //
  665. // Move selected list item up or down
  666. //
  667. void MoveUpDownListItem(HWND hDlg, HWND hwndList, BOOL bUp)
  668. {
  669. int i, iNumItems;
  670. TCHAR sz[MAX_LIST_STRING_LEN];
  671. i = ListBox_GetCurSel(hwndList);
  672. iNumItems = ListBox_GetCount(hwndList);
  673. ListBox_GetText(hwndList, i, sz);
  674. ListBox_DeleteString(hwndList, i);
  675. i += (bUp)? -1: 1;
  676. if (i < 0)
  677. i = 0;
  678. else if (i >= iNumItems)
  679. i = iNumItems - 1;
  680. ListBox_InsertString(hwndList, i, sz);
  681. ListBox_SetSel(hwndList, TRUE, i);
  682. ListBox_SetCurSel(hwndList, i);
  683. EnableWindow(GetDlgItem(hDlg, IDC_LANG_MOVE_UP_BUTTON), i != 0);
  684. EnableWindow(GetDlgItem(hDlg, IDC_LANG_MOVE_DOWN_BUTTON), i < iNumItems - 1);
  685. if (NULL == GetFocus()) // This prevent keyboard access disable
  686. SetFocus(hwndList);
  687. }
  688. //
  689. // FillLanguageListBox()
  690. //
  691. // Fills the language listbox with the names of available languages
  692. //
  693. BOOL FillLanguageListBox(IN HWND hDlg)
  694. {
  695. IMultiLanguage2 *pML2;
  696. HRESULT hr;
  697. TCHAR sz[MAX_LIST_STRING_LEN], sz1[MAX_LOCALE_NAME], sz2[MAX_RFC1766_NAME];
  698. HWND hwndEdit = GetDlgItem(hDlg, IDC_LANG_USER_DEFINED_EDIT);
  699. HWND hwndList = GetDlgItem(hDlg, IDC_LANG_AVAILABLE_LIST);
  700. HWND hwndAccept = GetDlgItem(GetParent(hDlg), IDC_LANG_ACCEPT_LIST);
  701. SendMessage(hwndEdit, EM_SETLIMITTEXT, 16, 0L); // Set Limit text as 16 characters
  702. if(!hOLE32)
  703. {
  704. if(!_StartOLE32())
  705. {
  706. ASSERT(FALSE);
  707. return FALSE;
  708. }
  709. }
  710. hr = pCoInitialize(NULL);
  711. if (FAILED(hr))
  712. return FALSE;
  713. hr = pCoCreateInstance(CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER, IID_IMultiLanguage2, (LPVOID *) &pML2);
  714. if (SUCCEEDED(hr))
  715. {
  716. IEnumRfc1766 *pEnumRfc1766;
  717. RFC1766INFO Rfc1766Info;
  718. if (SUCCEEDED(pML2->EnumRfc1766(INETCPL_GetUILanguage(), &pEnumRfc1766)))
  719. {
  720. while (S_OK == pEnumRfc1766->Next(1, &Rfc1766Info, NULL))
  721. {
  722. #ifdef UNICODE
  723. StrCpyN(sz1, Rfc1766Info.wszLocaleName, ARRAYSIZE(sz1));
  724. StrCpyN(sz2, Rfc1766Info.wszRfc1766, ARRAYSIZE(sz2));
  725. #else
  726. WideCharToMultiByte(CP_ACP, 0, Rfc1766Info.wszLocaleName, -1, sz1, MAX_LOCALE_NAME, NULL, NULL);
  727. WideCharToMultiByte(CP_ACP, 0, Rfc1766Info.wszRfc1766, -1, sz2, MAX_RFC1766_NAME, NULL, NULL);
  728. #endif
  729. wnsprintf(sz, ARRAYSIZE(sz), FORMAT_STR, sz1, sz2);
  730. if (LB_ERR == ListBox_FindStringExact(hwndAccept, -1, sz))
  731. ListBox_AddString(hwndList, sz);
  732. }
  733. pEnumRfc1766->Release();
  734. }
  735. pML2->Release();
  736. }
  737. pCoUninitialize();
  738. // everything ok
  739. return TRUE;
  740. }
  741. //
  742. // AddLanguage()
  743. //
  744. // Add selected language to accept language listbox.
  745. //
  746. void AddLanguage(IN HWND hDlg)
  747. {
  748. int i, j, *pItems, iNumItems, iIndex;
  749. TCHAR sz[MAX_LIST_STRING_LEN];
  750. HWND hdlgParent = GetParent(hDlg);
  751. HWND hwndFrom = GetDlgItem(hDlg, IDC_LANG_AVAILABLE_LIST);
  752. HWND hwndTo = GetDlgItem(hdlgParent, IDC_LANG_ACCEPT_LIST);
  753. i = ListBox_GetSelCount(hwndFrom);
  754. if (0 < i && (pItems = (PINT)LocalAlloc(LPTR, sizeof(int)*i)))
  755. {
  756. ListBox_GetSelItems(hwndFrom, i, pItems);
  757. for (j = 0; j < i; j++)
  758. {
  759. ListBox_GetText(hwndFrom, pItems[j], sz);
  760. ListBox_AddString(hwndTo, sz);
  761. }
  762. LocalFree(pItems);
  763. }
  764. if (GetWindowTextLength(GetDlgItem(hDlg, IDC_LANG_USER_DEFINED_EDIT)))
  765. {
  766. TCHAR *p, sz1[MAX_LIST_STRING_LEN], sz2[MAX_LIST_STRING_LEN];
  767. BOOL fValid = TRUE;
  768. GetWindowText(GetDlgItem(hDlg, IDC_LANG_USER_DEFINED_EDIT), sz2, ARRAYSIZE(sz2));
  769. p = sz2;
  770. while (NULL != *p && TRUE == fValid)
  771. {
  772. switch (*p)
  773. {
  774. // Invalid characters for user-defined string
  775. case TEXT(','):
  776. case TEXT(';'):
  777. case TEXT('['):
  778. case TEXT(']'):
  779. case TEXT('='):
  780. fValid = FALSE;
  781. break;
  782. default:
  783. p = CharNext(p);
  784. }
  785. }
  786. if (FALSE == fValid)
  787. {
  788. TCHAR szTitle[256], szErr[1024];
  789. MLLoadShellLangString(IDS_USER_DEFINED_ERR, szErr, ARRAYSIZE(szErr));
  790. GetWindowText(hDlg, szTitle, ARRAYSIZE(szTitle));
  791. MessageBox(hDlg, szErr, szTitle, MB_OK | MB_ICONHAND);
  792. }
  793. else
  794. {
  795. MLLoadString(IDS_USER_DEFINED, sz1, ARRAYSIZE(sz1));
  796. wnsprintf(sz, ARRAYSIZE(sz), FORMAT_STR, sz1, sz2);
  797. ListBox_AddString(hwndTo, sz);
  798. }
  799. }
  800. iIndex = ListBox_GetCurSel(hwndTo);
  801. if (LB_ERR != iIndex)
  802. {
  803. iNumItems = ListBox_GetCount(hwndTo);
  804. EnableWindow(GetDlgItem(hdlgParent, IDC_LANG_REMOVE_BUTTON), iNumItems > 0);
  805. EnableWindow(GetDlgItem(hdlgParent, IDC_LANG_MOVE_UP_BUTTON), iIndex > 0);
  806. EnableWindow(GetDlgItem(hdlgParent, IDC_LANG_MOVE_DOWN_BUTTON), iIndex < iNumItems - 1);
  807. }
  808. }
  809. int ComboBoxEx_AddString(IN HWND hwndCtl, IN LPCTSTR sz)
  810. {
  811. COMBOBOXEXITEM cbexItem = {0};
  812. int csz = _tcslen(sz);
  813. cbexItem.mask = CBEIF_TEXT;
  814. cbexItem.pszText = (LPTSTR)sz;
  815. cbexItem.cchTextMax = csz;
  816. // sort the string based on the current locale
  817. // we don't bother to use binary search because
  818. // the list is up to 25 item
  819. TCHAR szItem[MAX_LOCALE_NAME];
  820. int i, itemCount = ComboBox_GetCount(hwndCtl);
  821. for (i = 0; i < itemCount; i++)
  822. {
  823. ComboBox_GetLBText(hwndCtl, i, szItem);
  824. if (CompareString(INETCPL_GetUILanguage(),
  825. 0,
  826. sz,
  827. csz,
  828. szItem,
  829. ARRAYSIZE(szItem)) == CSTR_LESS_THAN)
  830. {
  831. break;
  832. }
  833. }
  834. cbexItem.iItem = i;
  835. SendMessage(hwndCtl, CBEM_INSERTITEM, (WPARAM)0, (LPARAM)(LPVOID)&cbexItem);
  836. return i;
  837. }
  838. BOOL FillUILangListBox(IN HWND hDlg, CUILangList *pLangList)
  839. {
  840. HWND hwndCombo = GetDlgItem(hDlg, IDC_COMBO_UILANG);
  841. BOOL bNT5 = IsOS(OS_WIN2000ORGREATER);
  842. DWORD dwAcp = GetACP();
  843. LPCTSTR pszLangName;
  844. if (!pLangList)
  845. return FALSE;
  846. // fill the list up.
  847. for (int i = 0; i < pLangList->GetListSize(); i++)
  848. {
  849. if (!pLangList->IsValidLang(i))
  850. continue;
  851. if (!bNT5)
  852. {
  853. LANGID lid = pLangList->GetLangIdOfIdx(i);
  854. if (dwAcp == CP_THAI || dwAcp == CP_ARABIC || dwAcp == CP_HEBREW)
  855. {
  856. // do not support cross codepage PlugUI
  857. // on Thai or Middle East platform(Arabic/Hebrew)
  858. static DWORD dwDefCP = 0;
  859. if (dwDefCP == 0)
  860. {
  861. TCHAR szLcData[6+1]; // +2 for '0x' +1 for terminator
  862. GetLocaleInfo( MAKELCID(lid, SUBLANG_NEUTRAL),
  863. LOCALE_IDEFAULTANSICODEPAGE, szLcData, ARRAYSIZE(szLcData));
  864. dwDefCP = StrToInt(szLcData);
  865. }
  866. if (dwDefCP != dwAcp && lid != 0x0409 && lid != GetInstallLanguage())
  867. continue;
  868. }
  869. else
  870. {
  871. // skip Arabic and Hebrew on non-supporting platform
  872. if (lid == 0x401 || lid == 0x40d)
  873. continue;
  874. }
  875. }
  876. pszLangName = pLangList->GetLangNameOfIdx(i);
  877. // ComboBox_FindStringExact has problems to handle DBCS Unicode characters
  878. if (pszLangName)
  879. {
  880. int ipos = ComboBoxEx_AddString(hwndCombo, pszLangName);
  881. if (ipos >= 0)
  882. {
  883. ComboBox_SetItemData(hwndCombo, ipos, i);
  884. }
  885. }
  886. }
  887. // show the current selection
  888. int iLangIdx = pLangList->GetCurrentLangIdx();
  889. if (iLangIdx >= 0)
  890. {
  891. int iCBPos;
  892. int iCBSize = ComboBox_GetCount(hwndCombo);
  893. for (iCBPos = 0; iCBPos < iCBSize; iCBPos++)
  894. {
  895. if (iLangIdx == ComboBox_GetItemData(hwndCombo, iCBPos))
  896. break;
  897. }
  898. if (iCBPos < iCBSize)
  899. ComboBox_SetCurSel(hwndCombo, iCBPos);
  900. }
  901. return TRUE;
  902. }
  903. //
  904. // Shutdown/reboot procedures implementation
  905. //
  906. // synopsis: CShutDownInfo class implements the method and the process list
  907. // which handle the sequence.
  908. // s_arryClsNames[] holds the list of target application
  909. // ChangeLanguage() (global) triggers the sequence being called from
  910. // LangChangeDlgProc().
  911. //
  912. static const LPTSTR s_arryClsNames[] =
  913. {
  914. TEXT("IEFrame"), // browser instance
  915. TEXT("ThorBrowserWndClass"), // OE
  916. TEXT("HH Parent"), // Html Help
  917. TEXT("MPWClass"), //
  918. TEXT("Outlook Express Browser Class"), // OE
  919. TEXT("ATH_Note"), // OE?
  920. TEXT("WABBrowseView"), // WAB
  921. TEXT("Afx:400000:8:10008:0:900d6"),
  922. TEXT("Media Player 2"),
  923. TEXT("FrontPageExpressWindow"),
  924. TEXT("MSBLUIManager"), // Messenger
  925. };
  926. //
  927. // CShutDownInfo
  928. // class methods implementation
  929. //
  930. #define SHUTDOWN_TIMEOUT 2000 // 2 sec
  931. #define RELAUNCH_TIMEOUT 1000 // 1 sec
  932. CShutDownProcInfo::CShutDownProcInfo(HWND hDlg)
  933. {
  934. _pProcList = NULL;
  935. _nAlloced = 0;
  936. _iProcList = 0;
  937. _hdlgParent = hDlg;
  938. _fAllShutDown = FALSE;
  939. }
  940. CShutDownProcInfo::~CShutDownProcInfo()
  941. {
  942. if (_pProcList)
  943. LocalFree(_pProcList);
  944. }
  945. HRESULT CShutDownProcInfo::EnsureProcList()
  946. {
  947. HRESULT hr = S_OK;
  948. if (!_pProcList)
  949. {
  950. // alloc mem for practical # of processes
  951. _nAlloced = ARRAYSIZE(s_arryClsNames);
  952. _pProcList = (PROCLIST *)LocalAlloc(LPTR, sizeof(PROCLIST)*_nAlloced);
  953. }
  954. if (!_pProcList)
  955. {
  956. _nAlloced = 0;
  957. hr = E_FAIL;
  958. }
  959. return hr;
  960. }
  961. HRESULT CShutDownProcInfo::IncreaseProcList()
  962. {
  963. HRESULT hr = S_OK;
  964. PROCLIST * pl = NULL;
  965. // realloc mem every so often
  966. if (_iProcList+1 > _nAlloced)
  967. {
  968. pl = (PROCLIST *)LocalReAlloc(_pProcList, sizeof(PROCLIST)*(ARRAYSIZE(s_arryClsNames)+_nAlloced),
  969. LMEM_MOVEABLE | LMEM_ZEROINIT);
  970. if (pl)
  971. {
  972. _nAlloced += ARRAYSIZE(s_arryClsNames);
  973. _pProcList = pl;
  974. }
  975. else
  976. hr = E_FAIL;
  977. }
  978. if (hr == S_OK)
  979. _iProcList++;
  980. return hr;
  981. }
  982. // CShutDownProcInfo::AddToProcList()
  983. //
  984. // synopsis: Get process info from given window handle
  985. // store it for shutdown procedure
  986. //
  987. //
  988. //
  989. HRESULT CShutDownProcInfo::AddToProcList(HWND hwnd)
  990. {
  991. HRESULT hr = S_OK;
  992. hr = EnsureProcList();
  993. if (SUCCEEDED(hr) && hwnd)
  994. {
  995. DWORD dwPID;
  996. BOOL fFoundDup = FALSE;
  997. GetWindowThreadProcessId(hwnd, &dwPID);
  998. // check to see if we already have the PID in the list
  999. for (int i=0; i < _iProcList; i++)
  1000. {
  1001. if (_pProcList[i].dwPID == dwPID)
  1002. {
  1003. fFoundDup = TRUE;
  1004. break;
  1005. }
  1006. }
  1007. // add proccess info only if we don't have it already
  1008. if (!fFoundDup)
  1009. {
  1010. hr = IncreaseProcList();
  1011. if (SUCCEEDED(hr))
  1012. {
  1013. int iCur = _iProcList-1;
  1014. GetExeNameFromPID(dwPID,
  1015. _pProcList[iCur].szExeName,
  1016. ARRAYSIZE(_pProcList[iCur].szExeName));
  1017. _pProcList[iCur].dwPID = dwPID;
  1018. _pProcList[iCur].State = PS_UNKNOWN;
  1019. }
  1020. }
  1021. }
  1022. return hr;
  1023. }
  1024. // CShutDownProcInfo::WaitForOneProcess
  1025. //
  1026. // synopsis: ensures the given process
  1027. // has terminated
  1028. //
  1029. //
  1030. HRESULT CShutDownProcInfo::WaitForOneProcess(int iProc)
  1031. {
  1032. HRESULT hr = S_OK;
  1033. if (iProc < _iProcList && _pProcList[iProc].State != PS_SHUTDOWN_OK)
  1034. {
  1035. DWORD dwProcessFlags = PROCESS_ALL_ACCESS |
  1036. (_fNT ? SYNCHRONIZE : 0 );
  1037. HANDLE hProc = OpenProcess(dwProcessFlags,
  1038. FALSE,
  1039. _pProcList[iProc].dwPID);
  1040. // pressume it has terminated, get it marked so
  1041. _pProcList[iProc].State = PS_SHUTDOWN_OK;
  1042. if (hProc)
  1043. {
  1044. // if the proccess in query is still alive,
  1045. // we'll wait with time out here
  1046. //
  1047. DWORD dwRet = WaitForSingleObject (hProc, SHUTDOWN_TIMEOUT);
  1048. if (dwRet == WAIT_TIMEOUT)
  1049. {
  1050. _pProcList[iProc].State = PS_WAITING;
  1051. }
  1052. CloseHandle(hProc);
  1053. }
  1054. }
  1055. return hr;
  1056. }
  1057. // CShutDownProcInfo::WaitForFolksShutDown
  1058. //
  1059. // synopsis: ensure the nominated processes terminate. If anyone
  1060. // doesn't want to terminate, wait for her retrying a couple of
  1061. // times and note her name so we can show it to the user.
  1062. //
  1063. //
  1064. #define MAXSHUTDOWNTRY 10
  1065. HRESULT CShutDownProcInfo::WaitForFolksShutDown()
  1066. {
  1067. HRESULT hr = S_OK;
  1068. int iTry = 0;
  1069. do
  1070. {
  1071. // pressume all will be fine
  1072. _fAllShutDown = TRUE;
  1073. // waiting loop
  1074. for (int i = 0; i < _iProcList; i++)
  1075. {
  1076. WaitForOneProcess(i);
  1077. if (_pProcList[i].State != PS_SHUTDOWN_OK)
  1078. _fAllShutDown = FALSE;
  1079. }
  1080. }
  1081. while( !_fAllShutDown && iTry++ < MAXSHUTDOWNTRY );
  1082. // FEATURE: here we should put up a dialog
  1083. // to ask user if they want to wait
  1084. // for the apps
  1085. return hr;
  1086. }
  1087. // CShutDownProcInfo::NotifyShutDownToFolks
  1088. //
  1089. // synopsis: send POI_OFFICE_COMMAND to possible candidates on the desktop
  1090. // if a candidate replies with valid value, save the proccess
  1091. // information for the later restart procedure.
  1092. //
  1093. HRESULT CShutDownProcInfo::NotifyShutDownToFolks(int *pnProcess)
  1094. {
  1095. HWND hwndShutDown, hwndAfter;
  1096. PLUGUI_QUERY pq;
  1097. HRESULT hr = S_OK;
  1098. int nProcToShutDown = 0;
  1099. for (int i = 0; i < ARRAYSIZE(s_arryClsNames); i++)
  1100. {
  1101. hwndAfter = NULL;
  1102. while (hwndShutDown = FindWindowEx(NULL, hwndAfter, s_arryClsNames[i], NULL))
  1103. {
  1104. pq.uQueryVal = (UINT)SendMessage(hwndShutDown, PUI_OFFICE_COMMAND, PLUGUI_CMD_QUERY, 0);
  1105. if (pq.uQueryVal)
  1106. {
  1107. if(pq.PlugUIInfo.uMajorVersion == OFFICE_VERSION_9)
  1108. {
  1109. PostMessage(hwndShutDown, PUI_OFFICE_COMMAND, (WPARAM)PLUGUI_CMD_SHUTDOWN, 0);
  1110. // store the information about the process which this window belongs to
  1111. // we only need to remember non OLE processes here for re-starting.
  1112. if (!pq.PlugUIInfo.uOleServer)
  1113. {
  1114. AddToProcList(hwndShutDown);
  1115. nProcToShutDown ++;
  1116. }
  1117. }
  1118. }
  1119. hwndAfter = hwndShutDown;
  1120. }
  1121. }
  1122. if (!nProcToShutDown)
  1123. hr = S_FALSE;
  1124. if (pnProcess)
  1125. *pnProcess = nProcToShutDown;
  1126. return hr;
  1127. }
  1128. const TCHAR c_szRegAppPaths[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\");
  1129. HRESULT CShutDownProcInfo::GetRestartAppPath(LPTSTR szPath, int cchPath, int iProc)
  1130. {
  1131. HRESULT hr = S_OK;
  1132. TCHAR szAppPath[MAX_PATH];
  1133. TCHAR szRegKey[MAX_PATH];
  1134. ASSERT(szPath && cchPath > 0);
  1135. if (iProc < _iProcList)
  1136. {
  1137. _tcscpy(szRegKey, c_szRegAppPaths);
  1138. _tcscat(szRegKey, _pProcList[iProc].szExeName);
  1139. DWORD cb = sizeof(szAppPath);
  1140. if (ERROR_SUCCESS != SHGetValue(HKEY_LOCAL_MACHINE, szRegKey, NULL, NULL, szAppPath, &cb))
  1141. {
  1142. szPath[0] = TEXT('0');
  1143. hr = E_FAIL;
  1144. }
  1145. else
  1146. _tcsncpy(szPath, szAppPath, cchPath);
  1147. }
  1148. return hr;
  1149. }
  1150. HRESULT CShutDownProcInfo::RestartFolks()
  1151. {
  1152. PROCESS_INFORMATION pi;
  1153. for (int i = 0; i < _iProcList; i++)
  1154. {
  1155. STARTUPINFO si = {0};
  1156. si.cb = sizeof(si);
  1157. if (_pProcList[i].State == PS_SHUTDOWN_OK)
  1158. {
  1159. TCHAR szAppPath[MAX_PATH];
  1160. HRESULT hr = GetRestartAppPath(szAppPath, ARRAYSIZE(szAppPath), i);
  1161. if (hr == S_OK)
  1162. {
  1163. BOOL fLaunchedOK =
  1164. CreateProcess (szAppPath, // name of app to launch
  1165. NULL, // lpCmdLine
  1166. NULL, // lpProcessAttributes
  1167. NULL, // lpThreadAttributes
  1168. TRUE, // bInheritHandles
  1169. NORMAL_PRIORITY_CLASS, // dwCreationFlags
  1170. NULL, // lpEnvironment
  1171. NULL, // lpCurrentDirectory
  1172. &si, // lpStartupInfo
  1173. &pi); // lpProcessInformation
  1174. if (fLaunchedOK)
  1175. {
  1176. DWORD dwRet = WaitForInputIdle (pi.hProcess,
  1177. RELAUNCH_TIMEOUT);
  1178. CloseHandle(pi.hProcess);
  1179. CloseHandle(pi.hThread);
  1180. }
  1181. }
  1182. }
  1183. }
  1184. return S_OK;
  1185. }
  1186. //
  1187. // CShutDownProcInfo::ShutDownThreadProc
  1188. //
  1189. // synopsis: launched from changelang dialog so the dialog
  1190. // wouldn't get blocked when we're waiting for our apps
  1191. // to shutdown/restart. this is a static proc
  1192. // so we should be able to delete the class instance
  1193. // in this proc.
  1194. //
  1195. DWORD CALLBACK CShutDownProcInfo::ShutDownThreadProc(void *pv)
  1196. {
  1197. CShutDownProcInfo *pspi = (CShutDownProcInfo *)pv;
  1198. if (pspi)
  1199. {
  1200. HRESULT hr;
  1201. int nToShutDown;
  1202. // send PUI_OFFICE_COMMAND to corresponding folks...
  1203. hr = pspi->NotifyShutDownToFolks(&nToShutDown);
  1204. // and wait until all processes shutdown
  1205. if (SUCCEEDED(hr) && nToShutDown > 0)
  1206. {
  1207. hr = pspi->WaitForFolksShutDown();
  1208. // then restart here
  1209. if (SUCCEEDED(hr))
  1210. pspi->RestartFolks();
  1211. }
  1212. // now the parent dialog should go away
  1213. int iret = (nToShutDown > 0) ?
  1214. RETURN_SETLANG_ENDLANGDIALOG: RETURN_SETLANG_CLOSEDNORMAL;
  1215. EndDialog(pspi->_hdlgParent, iret);
  1216. // delete this class instance
  1217. delete pspi;
  1218. }
  1219. return 0;
  1220. }
  1221. void OpenSatelliteDownloadUrl(HWND hDlg)
  1222. {
  1223. // get the default Url from registry
  1224. TCHAR szSatelliteUrl[INTERNET_MAX_URL_LENGTH];
  1225. // reg api needs size in byte
  1226. DWORD dwType, dwcbData = sizeof(szSatelliteUrl);
  1227. DWORD dwRet = SHGetValue(HKEY_LOCAL_MACHINE, REGSTR_PATH_INTERNATIONAL,
  1228. NULL, &dwType, (void *)szSatelliteUrl, &dwcbData);
  1229. if (dwRet != ERROR_SUCCESS || !szSatelliteUrl[0])
  1230. {
  1231. // use the hard coded Url instead
  1232. _tcscpy(szSatelliteUrl, s_szUrlSPK);
  1233. }
  1234. if(!hOLE32)
  1235. {
  1236. if(!_StartOLE32())
  1237. {
  1238. ASSERT(FALSE);
  1239. return;
  1240. }
  1241. }
  1242. HRESULT hr = pCoInitialize(NULL);
  1243. if (SUCCEEDED(hr))
  1244. {
  1245. NavToUrlUsingIE(szSatelliteUrl, TRUE);
  1246. pCoUninitialize();
  1247. }
  1248. }
  1249. INT_PTR CALLBACK LangMsgDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1250. {
  1251. switch (uMsg)
  1252. {
  1253. case WM_COMMAND:
  1254. {
  1255. switch (GET_WM_COMMAND_ID(wParam, lParam))
  1256. {
  1257. case IDYES:
  1258. case IDNO:
  1259. case IDOK:
  1260. case IDCANCEL:
  1261. EndDialog(hDlg, GET_WM_COMMAND_ID(wParam, lParam));
  1262. break;
  1263. }
  1264. return TRUE;
  1265. }
  1266. case WM_HELP: // F1
  1267. ResWinHelp( (HWND)((LPHELPINFO)lParam)->hItemHandle, IDS_HELPFILE,
  1268. HELP_WM_HELP, (DWORD_PTR)(LPSTR)mapIDCsToIDHs);
  1269. break;
  1270. case WM_CONTEXTMENU: // right mouse click
  1271. ResWinHelp( (HWND) wParam, IDS_HELPFILE,
  1272. HELP_CONTEXTMENU, (DWORD_PTR)(LPSTR)mapIDCsToIDHs);
  1273. break;
  1274. }
  1275. return FALSE;
  1276. }
  1277. BOOL ChangeLanguage(IN HWND hDlg, CUILangList *pLangList)
  1278. {
  1279. HWND hwndCombo = GetDlgItem(hDlg, IDC_COMBO_UILANG);
  1280. int iSel = ComboBox_GetCurSel(hwndCombo);
  1281. INT_PTR idxSel = 0;
  1282. int idxCur;
  1283. if (iSel != CB_ERR)
  1284. idxSel = ComboBox_GetItemData(hwndCombo, iSel);
  1285. if ( idxSel != CB_ERR
  1286. && idxSel < pLangList->GetListSize())
  1287. {
  1288. idxCur = pLangList->GetCurrentLangIdx();
  1289. if (idxCur != idxSel)
  1290. {
  1291. INT_PTR iRet = DialogBox(MLGetHinst(), MAKEINTRESOURCE(IDD_LANG_WARNING), hDlg, LangMsgDlgProc);
  1292. if (IDCANCEL != iRet)
  1293. {
  1294. pLangList->SetCurrentLangIdx((int)idxSel);
  1295. if (IDYES == iRet)
  1296. {
  1297. CShutDownProcInfo *pspi = new CShutDownProcInfo(hDlg);
  1298. if (!SHCreateThread(pspi->ShutDownThreadProc, (void *)pspi, 0, NULL))
  1299. delete pspi;
  1300. // returning TRUE to indicate that we do shutdown/restart
  1301. return TRUE;
  1302. }
  1303. else
  1304. {
  1305. DialogBox(MLGetHinst(), MAKEINTRESOURCE(IDD_LANG_INFO), hDlg, LangMsgDlgProc);
  1306. }
  1307. }
  1308. }
  1309. }
  1310. // returning FALSE to indicate that we haven't changed the language
  1311. return FALSE;
  1312. }
  1313. //
  1314. // LangChangeDlgProc()
  1315. //
  1316. // Message handler for the "Change Language" subdialog.
  1317. //
  1318. INT_PTR CALLBACK LangChangeDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1319. {
  1320. CUILangList *pLangList;
  1321. switch (uMsg)
  1322. {
  1323. case WM_INITDIALOG:
  1324. CUILangList::GetLangList(GetParent(hDlg), &pLangList);
  1325. return FillUILangListBox(hDlg, pLangList);
  1326. case WM_DESTROY:
  1327. break;
  1328. case WM_COMMAND:
  1329. switch(GET_WM_COMMAND_ID(wParam, lParam))
  1330. {
  1331. case IDC_LANG_ADDSPK:
  1332. // open url from resource
  1333. OpenSatelliteDownloadUrl(hDlg);
  1334. EndDialog(hDlg, RETURN_SETLANG_ENDLANGDIALOG);
  1335. break;
  1336. case IDOK:
  1337. if(!SUCCEEDED(CUILangList::GetLangList(GetParent(hDlg), &pLangList))
  1338. || !ChangeLanguage(hDlg, pLangList))
  1339. EndDialog(hDlg, 0);
  1340. // EndDialog() is called in separate thread
  1341. // when shutdown/restart is done
  1342. //
  1343. break;
  1344. case IDCANCEL:
  1345. EndDialog(hDlg, 0);
  1346. break;
  1347. }
  1348. break;
  1349. case WM_HELP: // F1
  1350. ResWinHelp( (HWND)((LPHELPINFO)lParam)->hItemHandle, IDS_HELPFILE,
  1351. HELP_WM_HELP, (DWORD_PTR)(LPSTR)mapIDCsToIDHs);
  1352. break;
  1353. case WM_CONTEXTMENU: // right mouse click
  1354. ResWinHelp( (HWND) wParam, IDS_HELPFILE,
  1355. HELP_CONTEXTMENU, (DWORD_PTR)(LPSTR)mapIDCsToIDHs);
  1356. break;
  1357. default:
  1358. return FALSE;
  1359. }
  1360. return TRUE;
  1361. }
  1362. //
  1363. // LangAddDlgProc()
  1364. //
  1365. // Message handler for the "Add Language" subdialog.
  1366. //
  1367. INT_PTR CALLBACK LangAddDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1368. {
  1369. switch (uMsg)
  1370. {
  1371. case WM_INITDIALOG:
  1372. return FillLanguageListBox(hDlg);
  1373. case WM_DESTROY:
  1374. break;
  1375. case WM_COMMAND:
  1376. switch(GET_WM_COMMAND_ID(wParam, lParam))
  1377. {
  1378. case IDOK:
  1379. AddLanguage(hDlg);
  1380. EndDialog(hDlg, 0);
  1381. break;
  1382. case IDCANCEL:
  1383. EndDialog(hDlg, 0);
  1384. break;
  1385. }
  1386. break;
  1387. case WM_HELP: // F1
  1388. ResWinHelp( (HWND)((LPHELPINFO)lParam)->hItemHandle, IDS_HELPFILE,
  1389. HELP_WM_HELP, (DWORD_PTR)(LPSTR)mapIDCsToIDHs);
  1390. break;
  1391. case WM_CONTEXTMENU: // right mouse click
  1392. ResWinHelp( (HWND) wParam, IDS_HELPFILE,
  1393. HELP_CONTEXTMENU, (DWORD_PTR)(LPSTR)mapIDCsToIDHs);
  1394. break;
  1395. default:
  1396. return FALSE;
  1397. }
  1398. return TRUE;
  1399. }
  1400. // put any cleanup procedures for language dialog here
  1401. void LangDlgCleanup(HWND hDlg)
  1402. {
  1403. // also delete and remove the instance of
  1404. // UI language list from window prop
  1405. CUILangList::RemoveLangList(hDlg);
  1406. }
  1407. //
  1408. // LanguageDlgProc()
  1409. //
  1410. // Message handler for the "Language Preference" subdialog.
  1411. //
  1412. INT_PTR CALLBACK LanguageDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1413. {
  1414. CUILangList *pLangList;
  1415. switch (uMsg)
  1416. {
  1417. case WM_INITDIALOG:
  1418. return LanguageDlgInit(hDlg);
  1419. case WM_DESTROY:
  1420. LangDlgCleanup(hDlg);
  1421. break;
  1422. case WM_COMMAND:
  1423. switch(GET_WM_COMMAND_ID(wParam, lParam))
  1424. {
  1425. HWND hwndList;
  1426. int iIndex, iNumItems;
  1427. INT_PTR iret;
  1428. case IDOK:
  1429. SaveLanguageData(hDlg);
  1430. EndDialog(hDlg, 0);
  1431. break;
  1432. case IDCANCEL:
  1433. EndDialog(hDlg, 0);
  1434. break;
  1435. case IDC_LANG_ADD_BUTTON:
  1436. DialogBox(MLGetHinst(), MAKEINTRESOURCE(IDD_LANG_ADD), hDlg, LangAddDlgProc);
  1437. break;
  1438. case IDC_LANG_UI_PREF:
  1439. CUILangList::GetLangList(hDlg, &pLangList);
  1440. iret = KickSetLang(hDlg, pLangList);
  1441. if (iret == RETURN_SETLANG_ENDLANGDIALOG)
  1442. {
  1443. // we're outa job
  1444. EndDialog(hDlg, 0);
  1445. }
  1446. else
  1447. {
  1448. InitCurrentUILang(hDlg);
  1449. }
  1450. break;
  1451. case IDC_LANG_REMOVE_BUTTON:
  1452. hwndList = GetDlgItem(hDlg, IDC_LANG_ACCEPT_LIST);
  1453. iIndex = ListBox_GetCurSel(hwndList);
  1454. ListBox_DeleteString(hwndList, iIndex);
  1455. iNumItems = ListBox_GetCount(hwndList);
  1456. if (iNumItems == iIndex)
  1457. iIndex--;
  1458. ListBox_SetCurSel(hwndList, iIndex);
  1459. EnableWindow(GetDlgItem(hDlg, IDC_LANG_REMOVE_BUTTON), (iNumItems > 0) && !g_restrict.fInternational);
  1460. EnableWindow(GetDlgItem(hDlg, IDC_LANG_MOVE_UP_BUTTON), (iIndex > 0) && !g_restrict.fInternational);
  1461. EnableWindow(GetDlgItem(hDlg, IDC_LANG_MOVE_DOWN_BUTTON), (iIndex < iNumItems - 1) && !g_restrict.fInternational);
  1462. if (NULL == GetFocus()) // This prevent keyboard access disable
  1463. SetFocus(hwndList);
  1464. break;
  1465. case IDC_LANG_ACCEPT_LIST:
  1466. hwndList = GetDlgItem(hDlg, IDC_LANG_ACCEPT_LIST);
  1467. iIndex = ListBox_GetCurSel(hwndList);
  1468. if (0 <= iIndex)
  1469. {
  1470. iNumItems = ListBox_GetCount(hwndList);
  1471. EnableWindow(GetDlgItem(hDlg, IDC_LANG_REMOVE_BUTTON), (iNumItems > 0) && !g_restrict.fInternational);
  1472. EnableWindow(GetDlgItem(hDlg, IDC_LANG_MOVE_UP_BUTTON), (iIndex > 0) && !g_restrict.fInternational);
  1473. EnableWindow(GetDlgItem(hDlg, IDC_LANG_MOVE_DOWN_BUTTON), (iIndex < iNumItems - 1) && !g_restrict.fInternational);
  1474. }
  1475. break;
  1476. case IDC_LANG_MOVE_UP_BUTTON:
  1477. MoveUpDownListItem(hDlg, GetDlgItem(hDlg, IDC_LANG_ACCEPT_LIST), TRUE);
  1478. break;
  1479. case IDC_LANG_MOVE_DOWN_BUTTON:
  1480. MoveUpDownListItem(hDlg, GetDlgItem(hDlg, IDC_LANG_ACCEPT_LIST), FALSE);
  1481. break;
  1482. }
  1483. break;
  1484. case WM_HELP: // F1
  1485. ResWinHelp( (HWND)((LPHELPINFO)lParam)->hItemHandle, IDS_HELPFILE,
  1486. HELP_WM_HELP, (DWORD_PTR)(LPSTR)mapIDCsToIDHs);
  1487. break;
  1488. case WM_CONTEXTMENU: // right mouse click
  1489. ResWinHelp( (HWND) wParam, IDS_HELPFILE,
  1490. HELP_CONTEXTMENU, (DWORD_PTR)(LPSTR)mapIDCsToIDHs);
  1491. break;
  1492. default:
  1493. return FALSE;
  1494. }
  1495. return TRUE;
  1496. }
  1497. //
  1498. // KickLanguageDialog
  1499. //
  1500. // synopsis : used for launching Language Preference sub dialog.
  1501. // we need to launch the dialogbox as a separate process if inetcpl is
  1502. // invoked from Tools->Internet options.
  1503. // The reason: we shutdown every browser instances on desktop
  1504. // user chooses different UI language than the current,
  1505. // including the browser that launched inetcpl.
  1506. //
  1507. static const TCHAR s_szRunDll32[] = TEXT("RunDll32.exe");
  1508. static const TCHAR s_szKickLangDialog[] = TEXT(" inetcpl.cpl,OpenLanguageDialog");
  1509. void KickLanguageDialog(HWND hDlg)
  1510. {
  1511. // 1: here we want to check to see if inetcpl was launched
  1512. // as a rundll32 process already, which would happen if user
  1513. // clicks on it at control panel folder
  1514. //
  1515. //
  1516. BOOL fLaunchedOnBrowser = FALSE;
  1517. // this tells me whether we got invoked from Tools->Internet Options...
  1518. if (g_szCurrentURL[0])
  1519. {
  1520. fLaunchedOnBrowser = TRUE;
  1521. }
  1522. if (fLaunchedOnBrowser)
  1523. {
  1524. TCHAR szCommandLine[MAX_PATH];
  1525. TCHAR szTitle[MAX_PATH];
  1526. HWND hwndParent = GetParent(hDlg);
  1527. StrCpy(szCommandLine, s_szRunDll32);
  1528. StrCat(szCommandLine, s_szKickLangDialog);
  1529. if (GetWindowText(hwndParent, szTitle, ARRAYSIZE(szTitle)) > 0)
  1530. {
  1531. StrCat(szCommandLine, TEXT(" "));
  1532. StrCat(szCommandLine, szTitle);
  1533. }
  1534. #ifdef USE_CREATE_PROCESS
  1535. PROCESS_INFORMATION pi;
  1536. STARTUPINFO si = {0};
  1537. si.cb = sizeof(si);
  1538. BOOL fLaunchedOK =
  1539. CreateProcess (szCommandLine, // name of app to launch
  1540. NULL, // lpCmdLine
  1541. NULL, // lpProcessAttributes
  1542. NULL, // lpThreadAttributes
  1543. TRUE, // bInheritHandles
  1544. NORMAL_PRIORITY_CLASS, // dwCreationFlags
  1545. NULL, // lpEnvironment
  1546. NULL, // lpCurrentDirectory
  1547. &si, // lpStartupInfo
  1548. &pi); // lpProcessInformation
  1549. #else
  1550. char szAnsiPath[MAX_PATH];
  1551. SHUnicodeToAnsi(szCommandLine, szAnsiPath, ARRAYSIZE(szAnsiPath));
  1552. WinExec(szAnsiPath, SW_SHOWNORMAL);
  1553. #endif
  1554. }
  1555. else
  1556. {
  1557. DialogBoxParam(MLGetHinst(), MAKEINTRESOURCE(IDD_LANG), hDlg, LanguageDlgProc, NULL);
  1558. }
  1559. }
  1560. //
  1561. // KickSetLang
  1562. //
  1563. // synopsis : tries to find setlang.exe of Office9 first, if found it'll be kicked
  1564. // if not, it uses our own setlang dialog.
  1565. //
  1566. //
  1567. static const TCHAR s_szOfficeInstallRoot[] = TEXT("Software\\Microsoft\\Office\\9.0\\Common\\InstallRoot");
  1568. static const TCHAR s_szOffice10InstallRoot[] = TEXT("Software\\Microsoft\\Shared");
  1569. static const TCHAR s_szPath[] = TEXT("Path");
  1570. static const TCHAR s_szOffice10Path[] = TEXT("OfficeSetLangInstallLocation");
  1571. static const TCHAR s_szSetLangExe[] = TEXT("setlang.exe");
  1572. INT_PTR KickSetLang(HWND hDlg, CUILangList *pLangList)
  1573. {
  1574. BOOL fOfficeSetLangInstalled = FALSE;
  1575. INT_PTR iret;
  1576. TCHAR szSetLangPath[MAX_PATH];
  1577. // deleting the key this way makes the key invalid for this process
  1578. // this way the inetcpl doesnt get bogus cached values
  1579. SHDeleteKey(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Windows\\ShellNoRoam\\MUICache"));
  1580. // try to get Office's setlang path
  1581. if(pLangList && pLangList->IsOffice9Installed())
  1582. {
  1583. DWORD cb = sizeof(szSetLangPath);
  1584. DWORD dwRet = SHGetValue(HKEY_LOCAL_MACHINE, s_szOffice10InstallRoot, s_szOffice10Path, NULL, szSetLangPath, &cb);
  1585. // fall back to Office9 langpack setting if Office10 langpack setting isn't there
  1586. if (ERROR_SUCCESS != dwRet)
  1587. {
  1588. cb = sizeof(szSetLangPath);
  1589. dwRet = SHGetValue(HKEY_LOCAL_MACHINE, s_szOfficeInstallRoot, s_szPath, NULL, szSetLangPath, &cb);
  1590. }
  1591. if (ERROR_SUCCESS == dwRet)
  1592. {
  1593. // If last character is a backslash
  1594. if (szSetLangPath[lstrlen(szSetLangPath)-1] == TEXT('\\'))
  1595. {
  1596. // Then concatenate the exe name
  1597. //
  1598. StrCat(szSetLangPath, s_szSetLangExe);
  1599. }
  1600. if (PathFileExists(szSetLangPath) == TRUE)
  1601. fOfficeSetLangInstalled = TRUE;
  1602. }
  1603. }
  1604. if (fOfficeSetLangInstalled)
  1605. {
  1606. PROCESS_INFORMATION pi;
  1607. STARTUPINFO si = {0};
  1608. si.cb = sizeof(si);
  1609. BOOL fLaunchedOK = CreateProcess(
  1610. szSetLangPath, // name of app to launch
  1611. NULL, // lpCmdLine
  1612. NULL, // lpProcessAttributes
  1613. NULL, // lpThreadAttributes
  1614. TRUE, // bInheritHandles
  1615. NORMAL_PRIORITY_CLASS, // dwCreationFlags
  1616. NULL, // lpEnvironment
  1617. NULL, // lpCurrentDirectory
  1618. &si, // lpStartupInfo
  1619. &pi); // lpProcessInformation
  1620. // just wait a while
  1621. if (fLaunchedOK)
  1622. {
  1623. WaitForInputIdle (pi.hProcess, RELAUNCH_TIMEOUT);
  1624. CloseHandle(pi.hProcess);
  1625. CloseHandle(pi.hThread);
  1626. }
  1627. iret = RETURN_SETLANG_ENDLANGDIALOG;
  1628. }
  1629. else
  1630. {
  1631. iret = DialogBoxParam(MLGetHinst(), MAKEINTRESOURCE(IDD_LANG_CHANGE), hDlg, LangChangeDlgProc, NULL);
  1632. }
  1633. return iret;
  1634. }
  1635. //
  1636. // entry point for rundll32
  1637. // NOTE: the following function was written intentionally as non-Unicode
  1638. // mainly because we don't have Wide wrapper mechanism for rundll32
  1639. // function on win95
  1640. //
  1641. extern void GetRestrictFlags(RESTRICT_FLAGS *pRestrict);
  1642. void CALLBACK OpenLanguageDialog(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
  1643. {
  1644. // hinst is ignored because we set it at our LibMain()
  1645. INITCOMMONCONTROLSEX icex;
  1646. GetRestrictFlags(&g_restrict);
  1647. icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
  1648. icex.dwICC = ICC_USEREX_CLASSES|ICC_NATIVEFNTCTL_CLASS;
  1649. InitCommonControlsEx(&icex);
  1650. if (lpszCmdLine && *lpszCmdLine)
  1651. {
  1652. HWND hwndParent = FindWindowA(NULL, lpszCmdLine);
  1653. if (hwndParent)
  1654. hwnd = hwndParent;
  1655. }
  1656. DialogBoxParam(MLGetHinst(), MAKEINTRESOURCE(IDD_LANG), hwnd, LanguageDlgProc, NULL);
  1657. }
  1658. // MLGetUILanguage in shlwapi returns current MUI language regardless version.
  1659. // MUI architecture doesn't display string correctly when main dll and satellite
  1660. // pack versions are mismatched.
  1661. // A good example is IE version upgrade without upgrading satellite.
  1662. // So here is more clever way to get the MUI language.
  1663. //
  1664. // 1. Get MLGetUILangauge from shlwapi
  1665. // 2. Compare it with current installed language.
  1666. // 3. if those are different, try to get resource dll.
  1667. // 4. if the resource dll is not in correct path just return current installed
  1668. // language.
  1669. // 5. Or return the langid of MLGetUILanguage.
  1670. LANGID INETCPL_GetUILanguage()
  1671. {
  1672. HINSTANCE hMLInst;
  1673. TCHAR szPath[MAX_PATH], szMUI[16];
  1674. LANGID lidUI = MLGetUILanguage();
  1675. if (IsOS(OS_WIN2000ORGREATER))
  1676. return lidUI;
  1677. if (lidUI != GetInstallLanguage())
  1678. {
  1679. hMLInst = MLGetHinst();
  1680. if (GetModuleFileName(hMLInst, szPath, ARRAYSIZE(szPath)))
  1681. {
  1682. IntToHex(szMUI, 4, lidUI);
  1683. if (StrStrI(szPath, szMUI) == NULL)
  1684. lidUI = GetInstallLanguage();
  1685. }
  1686. }
  1687. return lidUI;
  1688. }