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