|
|
///////////////////////////////////////////////////////////////////////
// Microsoft Windows //
// Copyright(c) Microsoft Corp., 1995 //
///////////////////////////////////////////////////////////////////////
//
// LANG.CPP - "Language" property page for InetCpl
//
// HISTORY:
//
// 1/10/97 beomoh created
//
#include "inetcplp.h"
#include <tchar.h>
#include <mlang.h>
#include "psapi.h"
#include "tlhelp32.h"
#include "process.h"
#include <mluisupp.h>
#include <shdocvw.h>
#define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
#define FORMAT_STR TEXT("%s [%s]")
#define MAX_LIST_STRING_LEN MAX_LOCALE_NAME + MAX_RFC1766_NAME + 3
#define MAX_ACCEPT_LANG_LEN 2048
#define CP_THAI 874
#define CP_ARABIC 1256
#define CP_HEBREW 1255
// used as the return value from setlang dialog
#define RETURN_SETLANG_ENDLANGDIALOG 2
#define RETURN_SETLANG_CLOSEDNORMAL 1
#define RETURN_SETLANG_CANCELED 0
typedef HRESULT (* PCOINIT) (LPVOID); typedef VOID (* PCOUNINIT) (VOID); typedef VOID (* PCOMEMFREE) (LPVOID); typedef HRESULT (* PCOCREINST) (REFCLSID, LPUNKNOWN, DWORD, REFIID, LPVOID * );
extern HMODULE hOLE32; extern PCOINIT pCoInitialize; extern PCOUNINIT pCoUninitialize; extern PCOMEMFREE pCoTaskMemFree; extern PCOCREINST pCoCreateInstance;
extern BOOL _StartOLE32();
class CUILangList; INT_PTR KickSetLang(HWND hDlg, CUILangList * pLangList);
static const TCHAR s_szResourceLocale[] = TEXT("ResourceLocale"); // HKLM\Software\Microsoft\Internet Explorer\International used for url string
static const TCHAR s_szUrlSPK[] = TEXT("http://www.microsoft.com/isapi/redir.dll?prd=ie&pver=6&ar=plugui&sba=install"); static const TCHAR c_szInstall[] = TEXT("Software\\Microsoft\\Active Setup\\Installed Components\\{89820200-ECBD-11CF-8B85-00AA005B4383}"); static const TCHAR c_szLocale[] = TEXT("Locale"); static const TCHAR s_szLangPackPath[] = TEXT("Software\\Microsoft\\Internet Explorer"); static const TCHAR s_szVersion[] = TEXT("LPKInstalled");
typedef struct { WORD wlangid; BOOL fValid; TCHAR szName[MAX_LOCALE_NAME]; } LANGLIST;
static LANGLIST s_arryLangList[] = { {0x0409, FALSE, {0}}, {0x0407, FALSE, {0}}, {0x0411, FALSE, {0}}, {0x0412, FALSE, {0}}, {0x0404, FALSE, {0}}, {0x0804, FALSE, {0}}, {0x040c, FALSE, {0}}, {0x0c0a, FALSE, {0}}, {0x0416, FALSE, {0}}, {0x0410, FALSE, {0}}, {0x0413, FALSE, {0}}, {0x041d, FALSE, {0}}, {0x0406, FALSE, {0}}, {0x040b, FALSE, {0}}, {0x040e, FALSE, {0}}, {0x0414, FALSE, {0}}, {0x0408, FALSE, {0}}, {0x0415, FALSE, {0}}, {0x0419, FALSE, {0}}, {0x0405, FALSE, {0}}, {0x0816, FALSE, {0}}, {0x041f, FALSE, {0}}, {0x041b, FALSE, {0}}, {0x0424, FALSE, {0}}, {0x0401, FALSE, {0}}, {0x040d, FALSE, {0}}, {0x042d, FALSE, {0}}, {0x040f, FALSE, {0}}, };
//
// ISO639 ID table
//
typedef struct tagISO639 { LPCTSTR ISO639; LANGID LangID; } ISO639, *LPISO639;
const ISO639 c_ISO639[] = { { TEXT("EN"), 0x0409 }, { TEXT("DE"), 0x0407 }, { TEXT("JA"), 0x0411 }, { TEXT("KO"), 0x0412 }, { TEXT("TW"), 0x0404 }, { TEXT("CN"), 0x0804 }, { TEXT("FR"), 0x040C }, { TEXT("ES"), 0x0C0A }, { TEXT("BR"), 0x0416 }, { TEXT("IT"), 0x0410 }, { TEXT("NL"), 0x0413 }, { TEXT("SV"), 0x041D }, { TEXT("DA"), 0x0406 }, { TEXT("FI"), 0x040B }, { TEXT("HU"), 0x040E }, { TEXT("NO"), 0x0414 }, { TEXT("EL"), 0x0408 }, { TEXT("PL"), 0x0415 }, { TEXT("RU"), 0x0419 }, { TEXT("CS"), 0x0405 }, { TEXT("PT"), 0x0816 }, { TEXT("TR"), 0x041F }, { TEXT("SK"), 0x041B }, { TEXT("SL"), 0x0424 }, { TEXT("AR"), 0x0401 }, { TEXT("HE"), 0x040D }, { TEXT("EU"), 0x042D }, { TEXT("IS"), 0x040F }, };
// GetInstallLanguage
//
// synopsis - borrowed this function from shlwapi. we can remove this
// once we have it exported from shlwapi.dll
//
LANGID GetInstallLanguage(void) { static LANGID LangID = 0; TCHAR szISO639[3]; DWORD cb;
if (0 == LangID) { cb = sizeof(szISO639); if (ERROR_SUCCESS == SHGetValue(HKEY_LOCAL_MACHINE, c_szInstall, c_szLocale, NULL, szISO639, &cb)) { int i;
for (i = 0; i < ARRAYSIZE(c_ISO639); i++) { if (!StrCmpNI(szISO639, c_ISO639[i].ISO639, ARRAYSIZE(szISO639))) { LangID = c_ISO639[i].LangID; break; } } } } return LangID; }
// CUILangList
//
// maintains the list of UI languages for user to choose
//
class CUILangList { public: CUILangList() {_iLangIdx = -1; lang = s_arryLangList; _nLangList = ARRAYSIZE(s_arryLangList); _fOffice9Installed = -1;}; void ValidateLangList(); BOOL IsValidLang(int idx) { return (idx < _nLangList) ? lang[idx].fValid: FALSE; }; int GetCurrentLangIdx(); void SetCurrentLangIdx(int idx); LPCTSTR GetCurrentLangName(); LPCTSTR GetLangNameOfIdx(int idx); WORD GetLangIdOfIdx(int idx) { return (idx < _nLangList) ? lang[idx].wlangid:0; }; UINT GetIds(int idx); int GetListSize() {return _nLangList;}; BOOL IsOffice9Installed(); static HRESULT GetLangList(HWND hdlg, CUILangList ** ppLangList); static HRESULT RemoveLangList(HWND hdlg); private: int _iLangIdx; int _nLangList; int _fOffice9Installed; LANGLIST *lang; };
// CShutDownProcInfo
//
// manages information about processes we want
// to shutdown/restart.
//
typedef enum { PS_UNKNOWN=0, PS_CANDIDATE, PS_TO_BE_SHUTDOWN, PS_IGNORE, PS_SHUTDOWN_OK, PS_WAITING, PS_TO_BE_SHUTDOWN_WITH_NO_RELAUNCH, PS_SHUTDOWN_OK_NO_RELAUNCH_NEEDED, } PROCSTATE;
class CShutDownProcInfo : public CProcessInfo { public: CShutDownProcInfo(HWND hdlgParent); ~CShutDownProcInfo(); HRESULT EnsureProcList(); HRESULT IncreaseProcList(); HRESULT NotifyShutDownToFolks(int *nProccess); HRESULT AddToProcList(HWND hwndShutDown); HRESULT WaitForOneProcess(int iProc); HRESULT WaitForFolksShutDown(); HRESULT GetRestartAppPath(LPTSTR szPath, int cchPath, int iProc); HRESULT RestartFolks(); static DWORD CALLBACK ShutDownThreadProc(void *pv); protected: typedef struct { DWORD dwPID; TCHAR szExeName[32]; PROCSTATE State; } PROCLIST; PROCLIST *_pProcList; int _nAlloced; int _iProcList; HWND _hdlgParent; BOOL _fAllShutDown; }; // this always fills '0' to empty digits
// caller has to make sure sz has cdigit+1 of buffer
void IntToHex(OUT LPTSTR sz, IN int cdigit, IN int value) { int i, idigit;
if (sz && value > 0 && cdigit > 0) { // nul terminate the buffer
sz[cdigit] = TEXT('\0'); for (i = cdigit-1; i >= 0; i--, value /= 16) { idigit = value%16; if (idigit < 10) sz[i] = (TCHAR)idigit + TEXT('0'); else sz[i] = (TCHAR)idigit - 10 + TEXT('A'); } } }
// set valid flags for the lang list
// very expensive so expects to be called only once in a session
// from CUILangList::GetLangList
//
#define MAX_SATELLITEPACKS 30 // 30 must be a practical number for satellite packs
void CUILangList::ValidateLangList() { HKEY hKey; HRESULT hr; TCHAR szValueName[32]; WORD aryValidLang[MAX_SATELLITEPACKS +1+1] = {0}; // +1 for install lang,
// +1 for terminator
int nMaxValidLang = ARRAYSIZE(aryValidLang)-1; // -1 for terminator
WORD *pwValid = aryValidLang; // make the install language always valid
*pwValid = GetInstallLanguage(); if (*pwValid != 0) { *(pwValid+1) = 0; // terminator
pwValid++; nMaxValidLang--; }
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_INTERNATIONAL, NULL, KEY_READ, &hKey)) { int i = 0; do { // see if the value has a match in the list
DWORD dwType; DWORD cb = ARRAYSIZE(szValueName)-2;
hr = SHEnumValue(hKey, i++, szValueName+2, &cb, &dwType, NULL, NULL); if (SUCCEEDED(hr) && dwType == REG_SZ) { UINT uiInstalled ;
szValueName[0] = TEXT('0'); szValueName[1] = TEXT('x'); StrToIntEx(szValueName, STIF_SUPPORT_HEX, (LPINT)&uiInstalled); if (uiInstalled > 0) { *pwValid = (unsigned short) uiInstalled; *(pwValid+1) = 0; // terminator
pwValid++; } } } while(hr == ERROR_SUCCESS && i < nMaxValidLang); RegCloseKey(hKey); }
// this assumes we can use StrChrW to search a value in
// a word array, it also assumes we never have 0 as a langid
//
Assert(sizeof(WORD) == sizeof(WCHAR)); // unix?
int nValidLang = (int)(pwValid-aryValidLang); for(int idx = 0; idx < GetListSize(); idx++ ) { // abusing the string function but this is a fast way
if (StrChrW((WCHAR *)aryValidLang, (WCHAR)lang[idx].wlangid)) { lang[idx].fValid = TRUE; if(--nValidLang <= 0) break; } } }
static const TCHAR s_szPropLangList[] = TEXT("langlist"); HRESULT CUILangList::GetLangList(HWND hdlg, CUILangList ** ppLangList) { HRESULT hr=S_OK; CUILangList *pLangList = (CUILangList *)GetProp(hdlg, s_szPropLangList); if (!pLangList) { pLangList = new CUILangList(); if (pLangList) { pLangList->ValidateLangList(); SetProp(hdlg, s_szPropLangList, (HANDLE)pLangList); } else hr = E_FAIL; } ASSERT(ppLangList); if (ppLangList) *ppLangList = pLangList; return hr; }
HRESULT CUILangList::RemoveLangList(HWND hdlg) { HRESULT hr = S_OK; CUILangList *pLangList = (CUILangList *)GetProp(hdlg, s_szPropLangList);
if (pLangList) { delete pLangList; RemoveProp(hdlg, s_szPropLangList); } else hr = S_FALSE;
return hr; }
void CUILangList::SetCurrentLangIdx(int idx) { TCHAR sz[4+1]; if (idx != _iLangIdx) { // the resource id is always 4 digit
IntToHex(sz, 4, lang[idx].wlangid); SHSetValue(HKEY_CURRENT_USER, REGSTR_PATH_INTERNATIONAL, s_szResourceLocale, REG_SZ, (void *)sz, sizeof(sz)); _iLangIdx = idx; } } // returns idx to the lang array
int CUILangList::GetCurrentLangIdx() { // show the current selection
TCHAR sz[64]; DWORD dwType; int isel; // see if it's cached already
if (_iLangIdx == -1) { // We basically wants what we've set in the registry,
// but if Office9 is installed we'll show whatever
// Office sets, and we can't change the Office setting anyway
// MLGetUILanguage returns Office's setting if its there
// Also I suppose we want to show NT5's UI language here
//
if (IsOffice9Installed() || IsOS(OS_WIN2000ORGREATER)) isel = INETCPL_GetUILanguage(); else { DWORD dwcbData = sizeof(sz);
HRESULT hr = SHGetValue(HKEY_CURRENT_USER, REGSTR_PATH_INTERNATIONAL, s_szResourceLocale, &dwType, (void *)&sz[2], &dwcbData); if (hr == ERROR_SUCCESS && dwType == REG_SZ) { sz[0] = TEXT('0'); sz[1] = TEXT('x'); StrToIntEx(sz, STIF_SUPPORT_HEX, (LPINT)&isel); } else { isel = GetInstallLanguage(); } } for(int i = 0; i < GetListSize(); i++ ) { if (isel == lang[i].wlangid) { _iLangIdx = i; break; } } // english for error case
if (_iLangIdx < 0) _iLangIdx = 0; } return _iLangIdx; }
LPCTSTR CUILangList::GetLangNameOfIdx(int idx) { LPCTSTR pszRet = NULL; IMultiLanguage2 *pML2; HRESULT hr; RFC1766INFO Rfc1766Info={0};
if(!hOLE32) { if(!_StartOLE32()) { ASSERT(FALSE); return NULL; } } hr = pCoInitialize(NULL);
if (FAILED(hr)) return NULL;
hr = pCoCreateInstance(CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER, IID_IMultiLanguage2, (LPVOID *) &pML2);
if (SUCCEEDED(hr)) { if (idx >= 0) { if (!lang[idx].szName[0]) { pML2->GetRfc1766Info(lang[idx].wlangid, INETCPL_GetUILanguage(), &Rfc1766Info); StrCpyNW(lang[idx].szName, Rfc1766Info.wszLocaleName, ARRAYSIZE(lang[0].szName)); } pszRet = lang[idx].szName; } pML2->Release(); }
pCoUninitialize(); return pszRet; } LPCTSTR CUILangList::GetCurrentLangName() { int idx = GetCurrentLangIdx(); return GetLangNameOfIdx(idx); }
BOOL CUILangList::IsOffice9Installed() { DWORD dwVersion; DWORD cb = sizeof(dwVersion); if (_fOffice9Installed < 0) { _fOffice9Installed ++; if (ERROR_SUCCESS == SHGetValue(HKEY_LOCAL_MACHINE, s_szLangPackPath, s_szVersion, NULL, &dwVersion, &cb) && dwVersion > 0) // magic number - christw tells me so
_fOffice9Installed ++; } return (BOOL)_fOffice9Installed; }
void InitCurrentUILang(HWND hDlg) { BOOL fChanged = FALSE; CUILangList *pLangList; LPCTSTR pszLangSel = NULL; HRESULT hr; hr = CUILangList::GetLangList(hDlg, &pLangList); if (SUCCEEDED(hr)) pszLangSel = pLangList->GetCurrentLangName(); if (pszLangSel) { TCHAR szBig[1024], szSmall[256];
GetDlgItemText(hDlg, IDC_LANG_CURSEL, szBig, ARRAYSIZE(szBig)); if (szBig[0]) fChanged = (StrStr(szBig, pszLangSel) == NULL);
if (MLLoadString((fChanged)? IDS_LANG_FUTUREUSE: IDS_LANG_CURRENTUSE, szSmall, ARRAYSIZE(szSmall)) > 0) { wnsprintf(szBig, ARRAYSIZE(szBig), szSmall, pszLangSel); Static_SetText(GetDlgItem(hDlg, IDC_LANG_CURSEL), szBig); } } }
//
// FillAcceptListBox()
//
// Fills the accept language listbox with names of selected language
//
void FillAcceptListBox(IN HWND hDlg) { IMultiLanguage2 *pML2; HRESULT hr; HKEY hKey; DWORD cb; TCHAR sz[MAX_LIST_STRING_LEN], szBuf[MAX_ACCEPT_LANG_LEN], *p1, *p2, *p3; HWND hwndList = GetDlgItem(hDlg, IDC_LANG_ACCEPT_LIST);
if(!hOLE32) { if(!_StartOLE32()) { ASSERT(FALSE); return; } } hr = pCoInitialize(NULL); if (FAILED(hr)) return;
hr = pCoCreateInstance(CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER, IID_IMultiLanguage2, (LPVOID *) &pML2); if (SUCCEEDED(hr)) { if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_CURRENT_USER, REGSTR_PATH_INTERNATIONAL, NULL, NULL, NULL, KEY_SET_VALUE|KEY_READ, NULL, &hKey, NULL)) { LCID lcid; RFC1766INFO Rfc1766Info; TCHAR sz1[MAX_LIST_STRING_LEN], sz2[MAX_RFC1766_NAME];
cb = sizeof(szBuf); if (ERROR_SUCCESS == RegQueryValueEx(hKey, REGSTR_VAL_ACCEPT_LANGUAGE, NULL, NULL, (LPBYTE)szBuf, &cb)) { p1 = p2 = szBuf; while (NULL != *p1) { WCHAR wsz[MAX_LIST_STRING_LEN]; BOOL bEnd = FALSE;
while (TEXT(',') != *p2 && NULL != *p2) p2 = CharNext(p2); if (NULL != *p2) *p2 = NULL; else bEnd = TRUE; p3 = p1; while (TEXT(';') != *p3 && NULL != *p3) p3 = CharNext(p3); if (NULL != *p3) *p3 = NULL; #ifdef UNICODE
StrCpyN(wsz, p1, ARRAYSIZE(wsz)); #else
MultiByteToWideChar(CP_ACP, 0, p1, -1, wsz, MAX_RFC1766_NAME); #endif
hr = pML2->GetLcidFromRfc1766(&lcid, wsz); if (SUCCEEDED(hr)) { hr = pML2->GetRfc1766Info(lcid, INETCPL_GetUILanguage(), &Rfc1766Info); if (SUCCEEDED(hr)) { #ifdef UNICODE
StrCpyN(sz1, Rfc1766Info.wszLocaleName, ARRAYSIZE(sz1)); #else
WideCharToMultiByte(CP_ACP, 0, Rfc1766Info.wszLocaleName, -1, sz1, MAX_LIST_STRING_LEN, NULL, NULL); #endif
wnsprintf(sz, ARRAYSIZE(sz), FORMAT_STR, sz1, p1); } } else { MLLoadString(IDS_USER_DEFINED, sz1, ARRAYSIZE(sz1)); wnsprintf(sz, ARRAYSIZE(sz), FORMAT_STR, sz1, p1); } ListBox_AddString(hwndList, sz); if (TRUE == bEnd) p1 = p2; else p1 = p2 = p2 + 1; } } else { lcid = GetUserDefaultLCID();
hr = pML2->GetRfc1766Info(lcid, INETCPL_GetUILanguage(), &Rfc1766Info); if (SUCCEEDED(hr)) { #ifdef UNICODE
StrCpyN(sz1, Rfc1766Info.wszLocaleName, ARRAYSIZE(sz1)); StrCpyN(sz2, Rfc1766Info.wszRfc1766, ARRAYSIZE(sz2)); #else
WideCharToMultiByte(CP_ACP, 0, Rfc1766Info.wszLocaleName, -1, sz1, MAX_LIST_STRING_LEN, NULL, NULL); WideCharToMultiByte(CP_ACP, 0, Rfc1766Info.wszRfc1766, -1, sz2, MAX_RFC1766_NAME, NULL, NULL); #endif
wnsprintf(sz, ARRAYSIZE(sz), FORMAT_STR, sz1, sz2); ListBox_AddString(hwndList, sz); } } RegCloseKey(hKey); } pML2->Release(); } pCoUninitialize(); }
//
// LanguageDlgInit()
//
// Initializes the Language dialog.
//
BOOL LanguageDlgInit(IN HWND hDlg) { if (!hDlg) return FALSE; // nothing to initialize
FillAcceptListBox(hDlg);
EnableWindow(GetDlgItem(hDlg, IDC_LANG_REMOVE_BUTTON), FALSE); EnableWindow(GetDlgItem(hDlg, IDC_LANG_MOVE_UP_BUTTON), FALSE); EnableWindow(GetDlgItem(hDlg, IDC_LANG_MOVE_DOWN_BUTTON), FALSE); EnableWindow(GetDlgItem(hDlg, IDC_LANG_ADD_BUTTON), !g_restrict.fInternational); // On NT5, we use NT5's MUI feature instead of IE5 plugui
if (IsOS(OS_WIN2000ORGREATER)) ShowWindow(GetDlgItem(hDlg, IDC_LANG_UI_PREF), SW_HIDE); else { UINT uiACP = GetACP();
// We don't support PlugUI on these platforms
if (uiACP == CP_ARABIC || uiACP == CP_HEBREW || uiACP == CP_THAI) ShowWindow(GetDlgItem(hDlg, IDC_LANG_UI_PREF), SW_HIDE); else EnableWindow(GetDlgItem(hDlg, IDC_LANG_UI_PREF), !g_restrict.fInternational); }
// show the current UI lang
InitCurrentUILang(hDlg); // everything ok
return TRUE; }
//
// SaveLanguageData()
//
// Save the new language settings into regestry
//
void SaveLanguageData(IN HWND hDlg) { HKEY hKey; DWORD dw; int i, iNumItems, iQ, n; TCHAR szBuf[MAX_ACCEPT_LANG_LEN];
if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_CURRENT_USER, REGSTR_PATH_INTERNATIONAL, NULL, NULL, NULL, KEY_WRITE, NULL, &hKey, &dw )) { HWND hwndList = GetDlgItem(hDlg, IDC_LANG_ACCEPT_LIST);
iNumItems = ListBox_GetCount(hwndList);
for (n = 1, iQ = 10; iQ < iNumItems; iQ *= 10, n++) ;
szBuf[0] = NULL; for (i = 0; i < iNumItems; i++) { TCHAR sz[MAX_LIST_STRING_LEN], *p1, *p2;
ListBox_GetText(hwndList, i, sz); p1 = sz; // We can assume safely there is '[' and ']' in this string.
while (TEXT('[') != *p1) p1 = CharNext(p1); p1 = p2 = p1 + 1; while (TEXT(']') != *p2) p2 = CharNext(p2); *p2 = NULL; if (0 == i) StrCpyN(szBuf, p1, ARRAYSIZE(szBuf)); else { TCHAR szF[MAX_ACCEPT_LANG_LEN], szQ[MAX_ACCEPT_LANG_LEN];
int len = lstrlen(szBuf); StrCpyN(szBuf + len, TEXT(","), ARRAYSIZE(szBuf) - len); len++; StrCpyN(szBuf + len, p1, ARRAYSIZE(szBuf) - len); wnsprintf(szF, ARRAYSIZE(szF), TEXT(";q=0.%%0%dd"), n); wnsprintf(szQ, ARRAYSIZE(szQ), szF, ((iNumItems - i) * iQ + (iNumItems / 2)) / iNumItems); len = lstrlen(szBuf); StrCpyN(szBuf + len , szQ, ARRAYSIZE(szBuf) - len); } } RegSetValueEx(hKey, REGSTR_VAL_ACCEPT_LANGUAGE, NULL, REG_SZ, (LPBYTE)szBuf, (lstrlen(szBuf)+1)*sizeof(TCHAR)); RegCloseKey(hKey); } }
// MoveUpDownListItem()
//
// Move selected list item up or down
//
void MoveUpDownListItem(HWND hDlg, HWND hwndList, BOOL bUp) { int i, iNumItems; TCHAR sz[MAX_LIST_STRING_LEN];
i = ListBox_GetCurSel(hwndList); iNumItems = ListBox_GetCount(hwndList); ListBox_GetText(hwndList, i, sz); ListBox_DeleteString(hwndList, i);
i += (bUp)? -1: 1; if (i < 0) i = 0; else if (i >= iNumItems) i = iNumItems - 1; ListBox_InsertString(hwndList, i, sz); ListBox_SetSel(hwndList, TRUE, i); ListBox_SetCurSel(hwndList, i);
EnableWindow(GetDlgItem(hDlg, IDC_LANG_MOVE_UP_BUTTON), i != 0); EnableWindow(GetDlgItem(hDlg, IDC_LANG_MOVE_DOWN_BUTTON), i < iNumItems - 1);
if (NULL == GetFocus()) // This prevent keyboard access disable
SetFocus(hwndList); }
//
// FillLanguageListBox()
//
// Fills the language listbox with the names of available languages
//
BOOL FillLanguageListBox(IN HWND hDlg) { IMultiLanguage2 *pML2; HRESULT hr; TCHAR sz[MAX_LIST_STRING_LEN], sz1[MAX_LOCALE_NAME], sz2[MAX_RFC1766_NAME]; HWND hwndEdit = GetDlgItem(hDlg, IDC_LANG_USER_DEFINED_EDIT); HWND hwndList = GetDlgItem(hDlg, IDC_LANG_AVAILABLE_LIST); HWND hwndAccept = GetDlgItem(GetParent(hDlg), IDC_LANG_ACCEPT_LIST); SendMessage(hwndEdit, EM_SETLIMITTEXT, 16, 0L); // Set Limit text as 16 characters
if(!hOLE32) { if(!_StartOLE32()) { ASSERT(FALSE); return FALSE; } } hr = pCoInitialize(NULL); if (FAILED(hr)) return FALSE;
hr = pCoCreateInstance(CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER, IID_IMultiLanguage2, (LPVOID *) &pML2); if (SUCCEEDED(hr)) { IEnumRfc1766 *pEnumRfc1766; RFC1766INFO Rfc1766Info;
if (SUCCEEDED(pML2->EnumRfc1766(INETCPL_GetUILanguage(), &pEnumRfc1766))) { while (S_OK == pEnumRfc1766->Next(1, &Rfc1766Info, NULL)) { #ifdef UNICODE
StrCpyN(sz1, Rfc1766Info.wszLocaleName, ARRAYSIZE(sz1)); StrCpyN(sz2, Rfc1766Info.wszRfc1766, ARRAYSIZE(sz2)); #else
WideCharToMultiByte(CP_ACP, 0, Rfc1766Info.wszLocaleName, -1, sz1, MAX_LOCALE_NAME, NULL, NULL); WideCharToMultiByte(CP_ACP, 0, Rfc1766Info.wszRfc1766, -1, sz2, MAX_RFC1766_NAME, NULL, NULL); #endif
wnsprintf(sz, ARRAYSIZE(sz), FORMAT_STR, sz1, sz2); if (LB_ERR == ListBox_FindStringExact(hwndAccept, -1, sz)) ListBox_AddString(hwndList, sz); } pEnumRfc1766->Release(); } pML2->Release(); } pCoUninitialize(); // everything ok
return TRUE; }
//
// AddLanguage()
//
// Add selected language to accept language listbox.
//
void AddLanguage(IN HWND hDlg) { int i, j, *pItems, iNumItems, iIndex; TCHAR sz[MAX_LIST_STRING_LEN]; HWND hdlgParent = GetParent(hDlg); HWND hwndFrom = GetDlgItem(hDlg, IDC_LANG_AVAILABLE_LIST); HWND hwndTo = GetDlgItem(hdlgParent, IDC_LANG_ACCEPT_LIST);
i = ListBox_GetSelCount(hwndFrom); if (0 < i && (pItems = (PINT)LocalAlloc(LPTR, sizeof(int)*i))) { ListBox_GetSelItems(hwndFrom, i, pItems); for (j = 0; j < i; j++) { ListBox_GetText(hwndFrom, pItems[j], sz); ListBox_AddString(hwndTo, sz); } LocalFree(pItems); } if (GetWindowTextLength(GetDlgItem(hDlg, IDC_LANG_USER_DEFINED_EDIT))) { TCHAR *p, sz1[MAX_LIST_STRING_LEN], sz2[MAX_LIST_STRING_LEN]; BOOL fValid = TRUE;
GetWindowText(GetDlgItem(hDlg, IDC_LANG_USER_DEFINED_EDIT), sz2, ARRAYSIZE(sz2)); p = sz2; while (NULL != *p && TRUE == fValid) { switch (*p) { // Invalid characters for user-defined string
case TEXT(','): case TEXT(';'): case TEXT('['): case TEXT(']'): case TEXT('='): fValid = FALSE; break;
default: p = CharNext(p); } } if (FALSE == fValid) { TCHAR szTitle[256], szErr[1024];
MLLoadShellLangString(IDS_USER_DEFINED_ERR, szErr, ARRAYSIZE(szErr)); GetWindowText(hDlg, szTitle, ARRAYSIZE(szTitle)); MessageBox(hDlg, szErr, szTitle, MB_OK | MB_ICONHAND); } else { MLLoadString(IDS_USER_DEFINED, sz1, ARRAYSIZE(sz1)); wnsprintf(sz, ARRAYSIZE(sz), FORMAT_STR, sz1, sz2); ListBox_AddString(hwndTo, sz); } } iIndex = ListBox_GetCurSel(hwndTo); if (LB_ERR != iIndex) { iNumItems = ListBox_GetCount(hwndTo); EnableWindow(GetDlgItem(hdlgParent, IDC_LANG_REMOVE_BUTTON), iNumItems > 0); EnableWindow(GetDlgItem(hdlgParent, IDC_LANG_MOVE_UP_BUTTON), iIndex > 0); EnableWindow(GetDlgItem(hdlgParent, IDC_LANG_MOVE_DOWN_BUTTON), iIndex < iNumItems - 1); } }
int ComboBoxEx_AddString(IN HWND hwndCtl, IN LPCTSTR sz) { COMBOBOXEXITEM cbexItem = {0}; int csz = _tcslen(sz);
cbexItem.mask = CBEIF_TEXT; cbexItem.pszText = (LPTSTR)sz; cbexItem.cchTextMax = csz; // sort the string based on the current locale
// we don't bother to use binary search because
// the list is up to 25 item
TCHAR szItem[MAX_LOCALE_NAME]; int i, itemCount = ComboBox_GetCount(hwndCtl); for (i = 0; i < itemCount; i++) { ComboBox_GetLBText(hwndCtl, i, szItem); if (CompareString(INETCPL_GetUILanguage(), 0, sz, csz, szItem, ARRAYSIZE(szItem)) == CSTR_LESS_THAN) { break; } } cbexItem.iItem = i; SendMessage(hwndCtl, CBEM_INSERTITEM, (WPARAM)0, (LPARAM)(LPVOID)&cbexItem); return i; }
BOOL FillUILangListBox(IN HWND hDlg, CUILangList *pLangList) { HWND hwndCombo = GetDlgItem(hDlg, IDC_COMBO_UILANG); BOOL bNT5 = IsOS(OS_WIN2000ORGREATER); DWORD dwAcp = GetACP(); LPCTSTR pszLangName; if (!pLangList) return FALSE;
// fill the list up.
for (int i = 0; i < pLangList->GetListSize(); i++) { if (!pLangList->IsValidLang(i)) continue;
if (!bNT5) { LANGID lid = pLangList->GetLangIdOfIdx(i);
if (dwAcp == CP_THAI || dwAcp == CP_ARABIC || dwAcp == CP_HEBREW) { // do not support cross codepage PlugUI
// on Thai or Middle East platform(Arabic/Hebrew)
static DWORD dwDefCP = 0;
if (dwDefCP == 0) { TCHAR szLcData[6+1]; // +2 for '0x' +1 for terminator
GetLocaleInfo( MAKELCID(lid, SUBLANG_NEUTRAL), LOCALE_IDEFAULTANSICODEPAGE, szLcData, ARRAYSIZE(szLcData)); dwDefCP = StrToInt(szLcData); } if (dwDefCP != dwAcp && lid != 0x0409 && lid != GetInstallLanguage()) continue; } else { // skip Arabic and Hebrew on non-supporting platform
if (lid == 0x401 || lid == 0x40d) continue; } }
pszLangName = pLangList->GetLangNameOfIdx(i);
// ComboBox_FindStringExact has problems to handle DBCS Unicode characters
if (pszLangName) { int ipos = ComboBoxEx_AddString(hwndCombo, pszLangName); if (ipos >= 0) { ComboBox_SetItemData(hwndCombo, ipos, i); } } }
// show the current selection
int iLangIdx = pLangList->GetCurrentLangIdx(); if (iLangIdx >= 0) { int iCBPos; int iCBSize = ComboBox_GetCount(hwndCombo); for (iCBPos = 0; iCBPos < iCBSize; iCBPos++) { if (iLangIdx == ComboBox_GetItemData(hwndCombo, iCBPos)) break; }
if (iCBPos < iCBSize) ComboBox_SetCurSel(hwndCombo, iCBPos); } return TRUE; }
//
// Shutdown/reboot procedures implementation
//
// synopsis: CShutDownInfo class implements the method and the process list
// which handle the sequence.
// s_arryClsNames[] holds the list of target application
// ChangeLanguage() (global) triggers the sequence being called from
// LangChangeDlgProc().
//
static const LPTSTR s_arryClsNames[] = { TEXT("IEFrame"), // browser instance
TEXT("ThorBrowserWndClass"), // OE
TEXT("HH Parent"), // Html Help
TEXT("MPWClass"), //
TEXT("Outlook Express Browser Class"), // OE
TEXT("ATH_Note"), // OE?
TEXT("WABBrowseView"), // WAB
TEXT("Afx:400000:8:10008:0:900d6"), TEXT("Media Player 2"), TEXT("FrontPageExpressWindow"), TEXT("MSBLUIManager"), // Messenger
};
//
// CShutDownInfo
// class methods implementation
//
#define SHUTDOWN_TIMEOUT 2000 // 2 sec
#define RELAUNCH_TIMEOUT 1000 // 1 sec
CShutDownProcInfo::CShutDownProcInfo(HWND hDlg) { _pProcList = NULL; _nAlloced = 0; _iProcList = 0; _hdlgParent = hDlg; _fAllShutDown = FALSE; }
CShutDownProcInfo::~CShutDownProcInfo() { if (_pProcList) LocalFree(_pProcList); }
HRESULT CShutDownProcInfo::EnsureProcList() { HRESULT hr = S_OK; if (!_pProcList) { // alloc mem for practical # of processes
_nAlloced = ARRAYSIZE(s_arryClsNames); _pProcList = (PROCLIST *)LocalAlloc(LPTR, sizeof(PROCLIST)*_nAlloced); } if (!_pProcList) { _nAlloced = 0; hr = E_FAIL; }
return hr; } HRESULT CShutDownProcInfo::IncreaseProcList() { HRESULT hr = S_OK; PROCLIST * pl = NULL; // realloc mem every so often
if (_iProcList+1 > _nAlloced) { pl = (PROCLIST *)LocalReAlloc(_pProcList, sizeof(PROCLIST)*(ARRAYSIZE(s_arryClsNames)+_nAlloced), LMEM_MOVEABLE | LMEM_ZEROINIT); if (pl) { _nAlloced += ARRAYSIZE(s_arryClsNames); _pProcList = pl; } else hr = E_FAIL; }
if (hr == S_OK) _iProcList++;
return hr; } // CShutDownProcInfo::AddToProcList()
//
// synopsis: Get process info from given window handle
// store it for shutdown procedure
//
//
//
HRESULT CShutDownProcInfo::AddToProcList(HWND hwnd) { HRESULT hr = S_OK;
hr = EnsureProcList(); if (SUCCEEDED(hr) && hwnd) { DWORD dwPID; BOOL fFoundDup = FALSE;
GetWindowThreadProcessId(hwnd, &dwPID); // check to see if we already have the PID in the list
for (int i=0; i < _iProcList; i++) { if (_pProcList[i].dwPID == dwPID) { fFoundDup = TRUE; break; } }
// add proccess info only if we don't have it already
if (!fFoundDup) { hr = IncreaseProcList(); if (SUCCEEDED(hr)) { int iCur = _iProcList-1;
GetExeNameFromPID(dwPID, _pProcList[iCur].szExeName, ARRAYSIZE(_pProcList[iCur].szExeName));
_pProcList[iCur].dwPID = dwPID; _pProcList[iCur].State = PS_UNKNOWN; } } } return hr; }
// CShutDownProcInfo::WaitForOneProcess
//
// synopsis: ensures the given process
// has terminated
//
//
HRESULT CShutDownProcInfo::WaitForOneProcess(int iProc) { HRESULT hr = S_OK; if (iProc < _iProcList && _pProcList[iProc].State != PS_SHUTDOWN_OK) { DWORD dwProcessFlags = PROCESS_ALL_ACCESS | (_fNT ? SYNCHRONIZE : 0 );
HANDLE hProc = OpenProcess(dwProcessFlags, FALSE, _pProcList[iProc].dwPID);
// pressume it has terminated, get it marked so
_pProcList[iProc].State = PS_SHUTDOWN_OK;
if (hProc) { // if the proccess in query is still alive,
// we'll wait with time out here
//
DWORD dwRet = WaitForSingleObject (hProc, SHUTDOWN_TIMEOUT); if (dwRet == WAIT_TIMEOUT) { _pProcList[iProc].State = PS_WAITING; } CloseHandle(hProc); } } return hr; }
// CShutDownProcInfo::WaitForFolksShutDown
//
// synopsis: ensure the nominated processes terminate. If anyone
// doesn't want to terminate, wait for her retrying a couple of
// times and note her name so we can show it to the user.
//
//
#define MAXSHUTDOWNTRY 10
HRESULT CShutDownProcInfo::WaitForFolksShutDown() { HRESULT hr = S_OK; int iTry = 0; do { // pressume all will be fine
_fAllShutDown = TRUE; // waiting loop
for (int i = 0; i < _iProcList; i++) { WaitForOneProcess(i); if (_pProcList[i].State != PS_SHUTDOWN_OK) _fAllShutDown = FALSE; } } while( !_fAllShutDown && iTry++ < MAXSHUTDOWNTRY ); // FEATURE: here we should put up a dialog
// to ask user if they want to wait
// for the apps
return hr; }
// CShutDownProcInfo::NotifyShutDownToFolks
//
// synopsis: send POI_OFFICE_COMMAND to possible candidates on the desktop
// if a candidate replies with valid value, save the proccess
// information for the later restart procedure.
//
HRESULT CShutDownProcInfo::NotifyShutDownToFolks(int *pnProcess) { HWND hwndShutDown, hwndAfter; PLUGUI_QUERY pq; HRESULT hr = S_OK; int nProcToShutDown = 0;
for (int i = 0; i < ARRAYSIZE(s_arryClsNames); i++) { hwndAfter = NULL; while (hwndShutDown = FindWindowEx(NULL, hwndAfter, s_arryClsNames[i], NULL)) { pq.uQueryVal = (UINT)SendMessage(hwndShutDown, PUI_OFFICE_COMMAND, PLUGUI_CMD_QUERY, 0); if (pq.uQueryVal) { if(pq.PlugUIInfo.uMajorVersion == OFFICE_VERSION_9) { PostMessage(hwndShutDown, PUI_OFFICE_COMMAND, (WPARAM)PLUGUI_CMD_SHUTDOWN, 0);
// store the information about the process which this window belongs to
// we only need to remember non OLE processes here for re-starting.
if (!pq.PlugUIInfo.uOleServer) { AddToProcList(hwndShutDown); nProcToShutDown ++; } } } hwndAfter = hwndShutDown; } } if (!nProcToShutDown) hr = S_FALSE;
if (pnProcess) *pnProcess = nProcToShutDown;
return hr; }
const TCHAR c_szRegAppPaths[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\"); HRESULT CShutDownProcInfo::GetRestartAppPath(LPTSTR szPath, int cchPath, int iProc) { HRESULT hr = S_OK; TCHAR szAppPath[MAX_PATH]; TCHAR szRegKey[MAX_PATH];
ASSERT(szPath && cchPath > 0);
if (iProc < _iProcList) { _tcscpy(szRegKey, c_szRegAppPaths); _tcscat(szRegKey, _pProcList[iProc].szExeName); DWORD cb = sizeof(szAppPath); if (ERROR_SUCCESS != SHGetValue(HKEY_LOCAL_MACHINE, szRegKey, NULL, NULL, szAppPath, &cb)) { szPath[0] = TEXT('0'); hr = E_FAIL; } else _tcsncpy(szPath, szAppPath, cchPath); } return hr; }
HRESULT CShutDownProcInfo::RestartFolks() { PROCESS_INFORMATION pi; for (int i = 0; i < _iProcList; i++) { STARTUPINFO si = {0}; si.cb = sizeof(si); if (_pProcList[i].State == PS_SHUTDOWN_OK) { TCHAR szAppPath[MAX_PATH]; HRESULT hr = GetRestartAppPath(szAppPath, ARRAYSIZE(szAppPath), i); if (hr == S_OK) { BOOL fLaunchedOK = CreateProcess (szAppPath, // name of app to launch
NULL, // lpCmdLine
NULL, // lpProcessAttributes
NULL, // lpThreadAttributes
TRUE, // bInheritHandles
NORMAL_PRIORITY_CLASS, // dwCreationFlags
NULL, // lpEnvironment
NULL, // lpCurrentDirectory
&si, // lpStartupInfo
&pi); // lpProcessInformation
if (fLaunchedOK) { DWORD dwRet = WaitForInputIdle (pi.hProcess, RELAUNCH_TIMEOUT); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } } } } return S_OK; }
//
// CShutDownProcInfo::ShutDownThreadProc
//
// synopsis: launched from changelang dialog so the dialog
// wouldn't get blocked when we're waiting for our apps
// to shutdown/restart. this is a static proc
// so we should be able to delete the class instance
// in this proc.
//
DWORD CALLBACK CShutDownProcInfo::ShutDownThreadProc(void *pv) { CShutDownProcInfo *pspi = (CShutDownProcInfo *)pv; if (pspi) { HRESULT hr; int nToShutDown; // send PUI_OFFICE_COMMAND to corresponding folks...
hr = pspi->NotifyShutDownToFolks(&nToShutDown);
// and wait until all processes shutdown
if (SUCCEEDED(hr) && nToShutDown > 0) { hr = pspi->WaitForFolksShutDown();
// then restart here
if (SUCCEEDED(hr)) pspi->RestartFolks(); } // now the parent dialog should go away
int iret = (nToShutDown > 0) ? RETURN_SETLANG_ENDLANGDIALOG: RETURN_SETLANG_CLOSEDNORMAL; EndDialog(pspi->_hdlgParent, iret); // delete this class instance
delete pspi; } return 0; }
void OpenSatelliteDownloadUrl(HWND hDlg) { // get the default Url from registry
TCHAR szSatelliteUrl[INTERNET_MAX_URL_LENGTH];
// reg api needs size in byte
DWORD dwType, dwcbData = sizeof(szSatelliteUrl); DWORD dwRet = SHGetValue(HKEY_LOCAL_MACHINE, REGSTR_PATH_INTERNATIONAL, NULL, &dwType, (void *)szSatelliteUrl, &dwcbData); if (dwRet != ERROR_SUCCESS || !szSatelliteUrl[0]) { // use the hard coded Url instead
_tcscpy(szSatelliteUrl, s_szUrlSPK); }
if(!hOLE32) { if(!_StartOLE32()) { ASSERT(FALSE); return; } }
HRESULT hr = pCoInitialize(NULL); if (SUCCEEDED(hr)) { NavToUrlUsingIE(szSatelliteUrl, TRUE); pCoUninitialize(); } }
INT_PTR CALLBACK LangMsgDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_COMMAND: { switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDYES: case IDNO: case IDOK: case IDCANCEL: EndDialog(hDlg, GET_WM_COMMAND_ID(wParam, lParam)); break; } return TRUE; }
case WM_HELP: // F1
ResWinHelp( (HWND)((LPHELPINFO)lParam)->hItemHandle, IDS_HELPFILE, HELP_WM_HELP, (DWORD_PTR)(LPSTR)mapIDCsToIDHs); break;
case WM_CONTEXTMENU: // right mouse click
ResWinHelp( (HWND) wParam, IDS_HELPFILE, HELP_CONTEXTMENU, (DWORD_PTR)(LPSTR)mapIDCsToIDHs); break; } return FALSE; }
BOOL ChangeLanguage(IN HWND hDlg, CUILangList *pLangList) { HWND hwndCombo = GetDlgItem(hDlg, IDC_COMBO_UILANG); int iSel = ComboBox_GetCurSel(hwndCombo); INT_PTR idxSel = 0; int idxCur; if (iSel != CB_ERR) idxSel = ComboBox_GetItemData(hwndCombo, iSel);
if ( idxSel != CB_ERR && idxSel < pLangList->GetListSize()) { idxCur = pLangList->GetCurrentLangIdx();
if (idxCur != idxSel) { INT_PTR iRet = DialogBox(MLGetHinst(), MAKEINTRESOURCE(IDD_LANG_WARNING), hDlg, LangMsgDlgProc);
if (IDCANCEL != iRet) { pLangList->SetCurrentLangIdx((int)idxSel);
if (IDYES == iRet) { CShutDownProcInfo *pspi = new CShutDownProcInfo(hDlg); if (!SHCreateThread(pspi->ShutDownThreadProc, (void *)pspi, 0, NULL)) delete pspi;
// returning TRUE to indicate that we do shutdown/restart
return TRUE; } else { DialogBox(MLGetHinst(), MAKEINTRESOURCE(IDD_LANG_INFO), hDlg, LangMsgDlgProc); } } } } // returning FALSE to indicate that we haven't changed the language
return FALSE; }
//
// LangChangeDlgProc()
//
// Message handler for the "Change Language" subdialog.
//
INT_PTR CALLBACK LangChangeDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { CUILangList *pLangList; switch (uMsg) { case WM_INITDIALOG: CUILangList::GetLangList(GetParent(hDlg), &pLangList); return FillUILangListBox(hDlg, pLangList); case WM_DESTROY: break;
case WM_COMMAND: switch(GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_LANG_ADDSPK: // open url from resource
OpenSatelliteDownloadUrl(hDlg); EndDialog(hDlg, RETURN_SETLANG_ENDLANGDIALOG); break; case IDOK: if(!SUCCEEDED(CUILangList::GetLangList(GetParent(hDlg), &pLangList)) || !ChangeLanguage(hDlg, pLangList)) EndDialog(hDlg, 0);
// EndDialog() is called in separate thread
// when shutdown/restart is done
//
break;
case IDCANCEL: EndDialog(hDlg, 0); break; } break;
case WM_HELP: // F1
ResWinHelp( (HWND)((LPHELPINFO)lParam)->hItemHandle, IDS_HELPFILE, HELP_WM_HELP, (DWORD_PTR)(LPSTR)mapIDCsToIDHs); break;
case WM_CONTEXTMENU: // right mouse click
ResWinHelp( (HWND) wParam, IDS_HELPFILE, HELP_CONTEXTMENU, (DWORD_PTR)(LPSTR)mapIDCsToIDHs); break;
default: return FALSE; } return TRUE; }
//
// LangAddDlgProc()
//
// Message handler for the "Add Language" subdialog.
//
INT_PTR CALLBACK LangAddDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_INITDIALOG: return FillLanguageListBox(hDlg); case WM_DESTROY: break;
case WM_COMMAND: switch(GET_WM_COMMAND_ID(wParam, lParam)) { case IDOK: AddLanguage(hDlg); EndDialog(hDlg, 0); break;
case IDCANCEL: EndDialog(hDlg, 0); break; } break;
case WM_HELP: // F1
ResWinHelp( (HWND)((LPHELPINFO)lParam)->hItemHandle, IDS_HELPFILE, HELP_WM_HELP, (DWORD_PTR)(LPSTR)mapIDCsToIDHs); break;
case WM_CONTEXTMENU: // right mouse click
ResWinHelp( (HWND) wParam, IDS_HELPFILE, HELP_CONTEXTMENU, (DWORD_PTR)(LPSTR)mapIDCsToIDHs); break;
default: return FALSE; } return TRUE; }
// put any cleanup procedures for language dialog here
void LangDlgCleanup(HWND hDlg) { // also delete and remove the instance of
// UI language list from window prop
CUILangList::RemoveLangList(hDlg); } //
// LanguageDlgProc()
//
// Message handler for the "Language Preference" subdialog.
//
INT_PTR CALLBACK LanguageDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { CUILangList *pLangList; switch (uMsg) { case WM_INITDIALOG: return LanguageDlgInit(hDlg); case WM_DESTROY: LangDlgCleanup(hDlg); break;
case WM_COMMAND: switch(GET_WM_COMMAND_ID(wParam, lParam)) { HWND hwndList; int iIndex, iNumItems; INT_PTR iret;
case IDOK: SaveLanguageData(hDlg); EndDialog(hDlg, 0); break;
case IDCANCEL: EndDialog(hDlg, 0); break;
case IDC_LANG_ADD_BUTTON: DialogBox(MLGetHinst(), MAKEINTRESOURCE(IDD_LANG_ADD), hDlg, LangAddDlgProc); break;
case IDC_LANG_UI_PREF: CUILangList::GetLangList(hDlg, &pLangList); iret = KickSetLang(hDlg, pLangList); if (iret == RETURN_SETLANG_ENDLANGDIALOG) { // we're outa job
EndDialog(hDlg, 0); } else { InitCurrentUILang(hDlg); } break;
case IDC_LANG_REMOVE_BUTTON: hwndList = GetDlgItem(hDlg, IDC_LANG_ACCEPT_LIST); iIndex = ListBox_GetCurSel(hwndList); ListBox_DeleteString(hwndList, iIndex); iNumItems = ListBox_GetCount(hwndList); if (iNumItems == iIndex) iIndex--; ListBox_SetCurSel(hwndList, iIndex); EnableWindow(GetDlgItem(hDlg, IDC_LANG_REMOVE_BUTTON), (iNumItems > 0) && !g_restrict.fInternational); EnableWindow(GetDlgItem(hDlg, IDC_LANG_MOVE_UP_BUTTON), (iIndex > 0) && !g_restrict.fInternational); EnableWindow(GetDlgItem(hDlg, IDC_LANG_MOVE_DOWN_BUTTON), (iIndex < iNumItems - 1) && !g_restrict.fInternational);
if (NULL == GetFocus()) // This prevent keyboard access disable
SetFocus(hwndList); break;
case IDC_LANG_ACCEPT_LIST: hwndList = GetDlgItem(hDlg, IDC_LANG_ACCEPT_LIST); iIndex = ListBox_GetCurSel(hwndList); if (0 <= iIndex) { iNumItems = ListBox_GetCount(hwndList); EnableWindow(GetDlgItem(hDlg, IDC_LANG_REMOVE_BUTTON), (iNumItems > 0) && !g_restrict.fInternational); EnableWindow(GetDlgItem(hDlg, IDC_LANG_MOVE_UP_BUTTON), (iIndex > 0) && !g_restrict.fInternational); EnableWindow(GetDlgItem(hDlg, IDC_LANG_MOVE_DOWN_BUTTON), (iIndex < iNumItems - 1) && !g_restrict.fInternational); } break;
case IDC_LANG_MOVE_UP_BUTTON: MoveUpDownListItem(hDlg, GetDlgItem(hDlg, IDC_LANG_ACCEPT_LIST), TRUE); break;
case IDC_LANG_MOVE_DOWN_BUTTON: MoveUpDownListItem(hDlg, GetDlgItem(hDlg, IDC_LANG_ACCEPT_LIST), FALSE); break; } break;
case WM_HELP: // F1
ResWinHelp( (HWND)((LPHELPINFO)lParam)->hItemHandle, IDS_HELPFILE, HELP_WM_HELP, (DWORD_PTR)(LPSTR)mapIDCsToIDHs); break;
case WM_CONTEXTMENU: // right mouse click
ResWinHelp( (HWND) wParam, IDS_HELPFILE, HELP_CONTEXTMENU, (DWORD_PTR)(LPSTR)mapIDCsToIDHs); break;
default: return FALSE; } return TRUE; }
//
// KickLanguageDialog
//
// synopsis : used for launching Language Preference sub dialog.
// we need to launch the dialogbox as a separate process if inetcpl is
// invoked from Tools->Internet options.
// The reason: we shutdown every browser instances on desktop
// user chooses different UI language than the current,
// including the browser that launched inetcpl.
//
static const TCHAR s_szRunDll32[] = TEXT("RunDll32.exe"); static const TCHAR s_szKickLangDialog[] = TEXT(" inetcpl.cpl,OpenLanguageDialog"); void KickLanguageDialog(HWND hDlg) { // 1: here we want to check to see if inetcpl was launched
// as a rundll32 process already, which would happen if user
// clicks on it at control panel folder
//
//
BOOL fLaunchedOnBrowser = FALSE; // this tells me whether we got invoked from Tools->Internet Options...
if (g_szCurrentURL[0]) { fLaunchedOnBrowser = TRUE; } if (fLaunchedOnBrowser) { TCHAR szCommandLine[MAX_PATH]; TCHAR szTitle[MAX_PATH];
HWND hwndParent = GetParent(hDlg); StrCpy(szCommandLine, s_szRunDll32); StrCat(szCommandLine, s_szKickLangDialog); if (GetWindowText(hwndParent, szTitle, ARRAYSIZE(szTitle)) > 0) { StrCat(szCommandLine, TEXT(" ")); StrCat(szCommandLine, szTitle); } #ifdef USE_CREATE_PROCESS
PROCESS_INFORMATION pi; STARTUPINFO si = {0};
si.cb = sizeof(si); BOOL fLaunchedOK = CreateProcess (szCommandLine, // name of app to launch
NULL, // lpCmdLine
NULL, // lpProcessAttributes
NULL, // lpThreadAttributes
TRUE, // bInheritHandles
NORMAL_PRIORITY_CLASS, // dwCreationFlags
NULL, // lpEnvironment
NULL, // lpCurrentDirectory
&si, // lpStartupInfo
&pi); // lpProcessInformation
#else
char szAnsiPath[MAX_PATH]; SHUnicodeToAnsi(szCommandLine, szAnsiPath, ARRAYSIZE(szAnsiPath)); WinExec(szAnsiPath, SW_SHOWNORMAL); #endif
} else { DialogBoxParam(MLGetHinst(), MAKEINTRESOURCE(IDD_LANG), hDlg, LanguageDlgProc, NULL); } }
//
// KickSetLang
//
// synopsis : tries to find setlang.exe of Office9 first, if found it'll be kicked
// if not, it uses our own setlang dialog.
//
//
static const TCHAR s_szOfficeInstallRoot[] = TEXT("Software\\Microsoft\\Office\\9.0\\Common\\InstallRoot"); static const TCHAR s_szOffice10InstallRoot[] = TEXT("Software\\Microsoft\\Shared"); static const TCHAR s_szPath[] = TEXT("Path"); static const TCHAR s_szOffice10Path[] = TEXT("OfficeSetLangInstallLocation"); static const TCHAR s_szSetLangExe[] = TEXT("setlang.exe");
INT_PTR KickSetLang(HWND hDlg, CUILangList *pLangList) { BOOL fOfficeSetLangInstalled = FALSE; INT_PTR iret; TCHAR szSetLangPath[MAX_PATH]; // deleting the key this way makes the key invalid for this process
// this way the inetcpl doesnt get bogus cached values
SHDeleteKey(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Windows\\ShellNoRoam\\MUICache"));
// try to get Office's setlang path
if(pLangList && pLangList->IsOffice9Installed()) { DWORD cb = sizeof(szSetLangPath); DWORD dwRet = SHGetValue(HKEY_LOCAL_MACHINE, s_szOffice10InstallRoot, s_szOffice10Path, NULL, szSetLangPath, &cb);
// fall back to Office9 langpack setting if Office10 langpack setting isn't there
if (ERROR_SUCCESS != dwRet) { cb = sizeof(szSetLangPath); dwRet = SHGetValue(HKEY_LOCAL_MACHINE, s_szOfficeInstallRoot, s_szPath, NULL, szSetLangPath, &cb); }
if (ERROR_SUCCESS == dwRet) { // If last character is a backslash
if (szSetLangPath[lstrlen(szSetLangPath)-1] == TEXT('\\')) { // Then concatenate the exe name
//
StrCat(szSetLangPath, s_szSetLangExe); } if (PathFileExists(szSetLangPath) == TRUE) fOfficeSetLangInstalled = TRUE; } } if (fOfficeSetLangInstalled) { PROCESS_INFORMATION pi; STARTUPINFO si = {0};
si.cb = sizeof(si); BOOL fLaunchedOK = CreateProcess( szSetLangPath, // name of app to launch
NULL, // lpCmdLine
NULL, // lpProcessAttributes
NULL, // lpThreadAttributes
TRUE, // bInheritHandles
NORMAL_PRIORITY_CLASS, // dwCreationFlags
NULL, // lpEnvironment
NULL, // lpCurrentDirectory
&si, // lpStartupInfo
&pi); // lpProcessInformation
// just wait a while
if (fLaunchedOK) { WaitForInputIdle (pi.hProcess, RELAUNCH_TIMEOUT); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } iret = RETURN_SETLANG_ENDLANGDIALOG; } else { iret = DialogBoxParam(MLGetHinst(), MAKEINTRESOURCE(IDD_LANG_CHANGE), hDlg, LangChangeDlgProc, NULL); }
return iret; }
//
// entry point for rundll32
// NOTE: the following function was written intentionally as non-Unicode
// mainly because we don't have Wide wrapper mechanism for rundll32
// function on win95
//
extern void GetRestrictFlags(RESTRICT_FLAGS *pRestrict); void CALLBACK OpenLanguageDialog(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) { // hinst is ignored because we set it at our LibMain()
INITCOMMONCONTROLSEX icex;
GetRestrictFlags(&g_restrict); icex.dwSize = sizeof(INITCOMMONCONTROLSEX); icex.dwICC = ICC_USEREX_CLASSES|ICC_NATIVEFNTCTL_CLASS; InitCommonControlsEx(&icex); if (lpszCmdLine && *lpszCmdLine) { HWND hwndParent = FindWindowA(NULL, lpszCmdLine); if (hwndParent) hwnd = hwndParent; } DialogBoxParam(MLGetHinst(), MAKEINTRESOURCE(IDD_LANG), hwnd, LanguageDlgProc, NULL); }
// MLGetUILanguage in shlwapi returns current MUI language regardless version.
// MUI architecture doesn't display string correctly when main dll and satellite
// pack versions are mismatched.
// A good example is IE version upgrade without upgrading satellite.
// So here is more clever way to get the MUI language.
//
// 1. Get MLGetUILangauge from shlwapi
// 2. Compare it with current installed language.
// 3. if those are different, try to get resource dll.
// 4. if the resource dll is not in correct path just return current installed
// language.
// 5. Or return the langid of MLGetUILanguage.
LANGID INETCPL_GetUILanguage() { HINSTANCE hMLInst; TCHAR szPath[MAX_PATH], szMUI[16]; LANGID lidUI = MLGetUILanguage();
if (IsOS(OS_WIN2000ORGREATER)) return lidUI;
if (lidUI != GetInstallLanguage()) { hMLInst = MLGetHinst(); if (GetModuleFileName(hMLInst, szPath, ARRAYSIZE(szPath))) { IntToHex(szMUI, 4, lidUI); if (StrStrI(szPath, szMUI) == NULL) lidUI = GetInstallLanguage(); } }
return lidUI; }
|