参考http://www.cnblogs.com/xianyunhe/archive/2011/09/02/2163842.html
最近在开发一个测试工具,因交付的使用对象是攻城狮,为使气质与之匹配,故而选用了MFC开发框架。
收尾阶段,boss希望能添加上中英文切换的功能,为不至于貂尾续狗,故而考虑直接使用MFC所支持的多语言资源。
基本思路是提供子菜单项,响应点击执行相关切换。因为窗口在初始化之初就根据当前语言环境加载了默认的资源文件,因而切换时必须重启应用才有效,为此考虑添加警示弹框,以免攻城狮在测试的过程中切换语言导致不必要的公司财产损失及人员伤残。
正传不多说,言归废话。
添加菜单项
插入一份英文资源副本
设置线程语言并保存至配置文件,以在重启时读入并配置
以下是切换成中文的部分响应代码:
BOOL bXPLaterOS=isVistaOrLaterVersion(); //判断系统版本
CID lcidNew;
if(bXPLaterOS)
lcidNew = GetThreadUILanguage();
else
lcidNew = GetThreadLocale();
if(LANG_CHINESE == PRIMARYLANGID(LANGIDFROMLCID(lcidNew)))
{
return;
}
INT_PTR nRes;
nRes = MessageBoxEx(NULL,L"此操作将重启应用,是否继续?",L"警告",MB_YESNO,MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED));
if(nRes == IDYES)
{
//do nothing
}
else if(nRes == IDCANCEL || nRes == IDNO)
{
return;
}
if(bXPLaterOS)
lcidNew = MAKELANGID(LANG_CHINESE,SUBLANG_CHINESE_SIMPLIFIED);
else
lcidNew = MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT);
// 写入配置文件
CFile file;
file.Open(_T("Language.ini"), CFile::modeWrite | CFile::modeCreate | CFile::typeBinary);
file.Write(&lcidNew, sizeof(lcidNew));
file.Close();
// 关闭窗口
m_bRestartFlag = TRUE;
PostMessage(WM_CLOSE, 0, 0);
OnClose()中添加相应重启代码
//...
if (m_bRestartFlag)
{
CString strFileName = _T("");
GetModuleFileName(NULL, strFileName.GetBuffer(MAX_PATH), MAX_PATH);
ShellExecute(NULL, _T(""), strFileName, NULL, NULL, SW_SHOWNORMAL);
strFileName.ReleaseBuffer();
}
//...
重启应用,载入资源之前设置线程语言(程序的语言选择跟操作系统语言(System Locale)、用户设置语言(User Locale)和线程语言(Thread Locale)有关。程序运行时,是根据线程语言来选择资源的。如果程序中未对线程语言进行设置,线程语言默认采用用户设置语言):
//以下代码添加在了BOOL C*App::InitInstance()中的
//CWinAppEx::InitInstance()语句之前
CString strFileName = _T("Language.ini");
if (PathFileExists(strFileName))
{
LCID lcidThread = 0;
CFile file;
file.Open(strFileName, CFile::modeRead | CFile::typeBinary);
file.Read(&lcidThread, sizeof(LCID));
file.Close();
if(bXPLaterOS)
SetThreadUILanguage(lcidThread);
}
注:之所以使用isVistaOrLaterVersion()对系统版本进行判断是因为上述代码清单使用到的个别函数的兼容问题
function Minimum supported client GetThreadUILanguage Windows Vista [desktop apps only] GetThreadLocale Windows 2000 Professional [desktop apps only] SetThreadUILanguage Windows XP [desktop apps only] SetThreadLocale Windows 2000 Professional [desktop apps only]
另:Windows 2000/XP: Do not use SetThreadLocale to select a user interface language. To select the resource that is defined in the .rc file with a LANGUAGE statement, the application must use the Win32 FindResourceEx function.
大牛反汇编了下Kernel32.dll里面的LoadString,XP系统下的LoadString内部调用了FindResourceEx。SetTreadLocale会影响LoadString和FindResource,而不会影响FindResourceEx。因而,调用SetThreadLocale设置线程语言很可能无效。(经测试win7调用无效)
考虑下图中的数据,使用SetThreadUILanguage()设置线程语言;至于获取,判断当前Windows版本,XP使用GetThreadLocale(),Vista或以上使用GetThreadUILanguage()。
用着用着在XP中突然开始报错: “无法定位程序输入点 GetThreadUiLanguage 于动态链接库 KERNEL32.dll 上”。 没有一点点防备,也没有一丝顾虑,它就这样出现…于是使用最笨的方法判断当前是否需要切换语言:获取某个资源的窗口字符串判断其为何种语言。
看到有大牛推荐使用dll的方式支持多语言
???偶尔切换不成功是什么鬼