在上一篇”C++ 實現多語言程序開發研究與Xtreme ToolkitPro的使用(二)”在MultiLanguageDemo程序中添加語言資源的定義,這裏繼續開始介紹如何使用在程序中動態添加語言資源DLL文件。
回到在Xtreme ToolkitPro源碼中兩個關於多語言的例子:ScribbleMultiLang(Xtreme ToolkitPro v15.2.1\Samples\CommandBars\ScribbleMultiLang\)和MultiLanguage(Xtreme ToolkitPro v15.2.1\Samples\ToolkitPro\MultiLanguage)。可以在MultiLanguage中看到一個管理語言資源的類CLanguageManger,類中有幾個比較關鍵的函數:
BOOL CLanguageManger::InitLanguageDlls()
{
TCHAR szBuff[_MAX_PATH];
::GetModuleFileName(NULL, szBuff, _countof(szBuff));
TCHAR *p = _tcsrchr(szBuff, _T('\\'));
if (p != NULL) {
*p = _T('\0');
}
CString strDllPath;
if (!DIRECTORYEXISTS_S(CString(szBuff) + _T("\\Translations")) &&
DIRECTORYEXISTS_S(CString(szBuff) + _T("\\..\\..\\Utils\\Translations")))
{
strDllPath.Format(_T("%s\\..\\..\\Utils\\Translations\\*.dll"), szBuff);
}
else
{
strDllPath.Format(_T("%s\\Translations\\*.dll"), szBuff);
}
return InitLanguageDlls(strDllPath);
}
這個函數是查找Translations目錄(路徑可以根據實際情況做修改)下所有的語言資源DLL並加載後其語言ID並保存:
WORD CLanguageManger::GetLangID(HMODULE hResDll) const
{
typedef WORD (CALLBACK* PGETLANGID)();
if (hResDll != NULL)
{
PGETLANGID pfnGetLangID = (PGETLANGID)::GetProcAddress(
hResDll, "GetLangID");
if (pfnGetLangID)
return (*pfnGetLangID)();
WORD wLanguage = 0;
DWORD Zero;
UINT cbTranslate;
TCHAR pszPath[MAX_PATH];
struct LANGANDCODEPAGE
{
WORD wLanguage;
WORD wCodePage;
} *lpTranslate;
GetModuleFileName(hResDll, pszPath, MAX_PATH);
DWORD dwDataLen = ::GetFileVersionInfoSize(pszPath, &Zero);
if (dwDataLen == 0)
{
EnumResourceTypes(hResDll, &CLanguageManger::EnumResTypeProc, (LONG_PTR)&wLanguage);
return wLanguage;
}
LPVOID pData = new BYTE[dwDataLen];
if (::GetFileVersionInfo((TCHAR*)pszPath, NULL, dwDataLen, pData))
{
::VerQueryValue(pData, _T("\\VarFileInfo\\Translation"), (LPVOID*)&lpTranslate, &cbTranslate);
if (cbTranslate >= 4)
{
wLanguage = lpTranslate->wLanguage;
}
}
delete [] pData;
return wLanguage;
}
return 0;
}
這樣,就很方便地在CMainFrame中操作語言資源了,加入的主要操作函數是:
void OnInitCommandsPopup(CXTPPopupBar* pCommandBar);
void ResetCommandBars(); // 重置命令欄
// 語言更新函數
afx_msg BOOL OnLangaugeFile(UINT nID);
afx_msg void OnUpdateLangaugeFile(CCmdUI* pCmdUI);
在CMainFrame::OnCreate函數中添加工具條: // 2017-08-25
// Create Language ToolBar
CXTPToolBar* pLangBar = (CXTPToolBar*)
pCommandBars->Add(_T("Language"), xtpBarTop);
if (!pLangBar || !pLangBar->LoadToolBar(IDR_LANGBAR))
{
TRACE0("Failed to create toolbar\n");
return -1;
}
然後初始化之前選擇的語言:
// Load previously selected language.
OnLangaugeFile(m_langManager.GetCmdID(m_langManager.GetLangID()));
更新操作:
// 重置命令欄
void CMainFrame::ResetCommandBars()
{
m_bInRecalcLayout = TRUE;
CXTPCommandBars* pCommandBars = GetCommandBars();
for (int i = 0; i < pCommandBars->GetCount(); i++)
{
CXTPToolBar* pToolBar = pCommandBars->GetAt(i);
if (pToolBar->IsBuiltIn())
{
if (pToolBar->GetType() != xtpBarTypeMenuBar)
{
pToolBar->LoadToolBar(pToolBar->GetBarID(), FALSE);
}
else
{
CMenu menu;
menu.LoadMenu(IDR_MultiLanguageDeTYPE);
pToolBar->LoadMenu(&menu);
pToolBar->GetControls()->CreateOriginalControls();
((CXTPMenuBar*)pToolBar)->RefreshMenu();
}
}
// 隱藏未加載的語言
if (pToolBar->GetBarID() == IDR_LANGBAR)
{
CXTPControls* pCommandList = pToolBar->GetControls();
for (int iIndex = pCommandList->GetCount()-1; iIndex >= 0; --iIndex)
{
CXTPControl* pButton = pCommandList->GetAt(iIndex);
if (pButton)
{
WORD wLangID = m_langManager.GetLangID(pButton->GetID());
pButton->SetCaption(m_langManager.GetDescription(wLangID));
LANGUAGE_DLL langDll;
if (!m_langManager.GetDllInfo(wLangID, langDll))
pCommandList->Remove(iIndex);
}
}
}
}
m_bInRecalcLayout = FALSE;
RecalcLayout();
AfxGetApp()->OnIdle(0);
RedrawWindow(NULL, NULL,
RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE | RDW_ALLCHILDREN);
}
// 語言更新函數
BOOL CMainFrame::OnLangaugeFile(UINT nID)
{
LANGUAGE_DLL langDll;
if (m_langManager.GetDllInfo(m_langManager.GetLangID(nID), langDll))
{
if (m_langManager.LoadLanguageDll(langDll.strDllPath))
{
::SetThreadLocale(MAKELCID(m_langManager.GetLangID(nID), SORT_DEFAULT));
BOOL bRTLLayout = ((::GetWindowLong(m_hWnd, GWL_EXSTYLE)
& WS_EX_LAYOUTRTL) == WS_EX_LAYOUTRTL);
if (bRTLLayout != m_langManager.IsRTL())
{
m_langManager.SetRTLLayout(this, m_langManager.IsRTL());
XTPImageManager()->DrawReverted(m_langManager.IsRTL());
}
ResetCommandBars();
return TRUE;
}
}
return FALSE;
}
其他的函數比較簡單,參考下Xtreme ToolkitPro中的例子很容易實現。最終,完成的MultiLanguageDemo如下:提供完整的工程下載:MultiLanguageDemo