1915 lines
57 KiB
C++
1915 lines
57 KiB
C++
|
///////////////////////////////////////////////////////////////////////
|
||
|
// 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;
|
||
|
}
|