在VC工程中新增多語言支援 (資源DLL)
隨著貿易國際化,在軟體開發過程中,常會碰到需在現有中文版軟體加入多語言支援的情況。由於不同語言版本間的差別通常僅是軟體操作介面的不同,為實現多語言支援,使用純資源DLL是一個不錯的解決之道。所謂純資源DLL是指只包含資源的DLL,譬如:快捷鍵、對話方塊、字串、選單、工具條、點陣圖、圖示、版本資訊等等。
具體做法是:利用VC視覺化編輯環境為每種語言製作一套資源ID一一對應的資源集並編譯生成DLL檔案。應用程式初始化時按預設的語言設定選擇合適的資源DLL調入,使用資源時依據資源ID進行訪問,這樣即可實現軟體的多語言支援。當然了,應用程式退出前,注意將動態調入的DLL檔案佔用的資源釋放。
現有一個心電圖檢視程式,工程名為DispECG,語言為中文,現需加入英文支援。下面根據這個具體例項來說明在VC中加入多語言支援的具體實施方法。
(一)建立純資源DLL
a)開啟DispECG工程,在當前工作區中新增一個工程。方法:使用選單File\New…
b)從彈出的對話方塊中選擇“Projects”頁面,選擇“Win32 Dynamic-Link Library”,工程名設定為“DispECG_ENG”,DispECG工程的工作目錄為D:\MyProject\DispECG,DispECG_ENG工程的工作目錄為D:\MyProject\DispECG\DispECG_ENG。選擇新增到當前工作區(注意Dependency of前的框不選),然後按OK。
c)建立一個簡單的DLL工程
選擇“A simple DLL project”,然後按“Finish”。此時新建的DispECG_ENG工程中會建立如下幾個檔案:DispECG_ENG.cpp,StdAfx.cpp,StdAfx.h以及ReadMe.txt。注意沒有後綴為*.RC的資原始檔。
其中DispECG_ENG.cpp中檔案內容如下:
// DispECG_ENG.cpp : Defines the entry point for the DLL application.
//
#include "stdafx.h"
BOOL APIENTRY DllMain( HANDLE hModule,DWORD ul_reason_for_call,
LPVOID lpReserved)
{
return TRUE;
}
(二)為DispECG_ENG加入資源並編輯
a)使用Windows資源管理器將DispECG工程下的resource.h和DispECG.rc拷貝到DispECG_ENG工程下,將DispECG工程下的res子目錄拷貝到DispECG工程下;
b)使用Windows資源管理器將DispECG_ENG工程下的DispECG.rc改名為DispECG_ENG.rc,將DispECG_ENG\res下的DispECG.rc2改名為DispECG_ENG.rc2;
c)回到VC編輯環境。選擇工作區中的檔案視(FileView),選擇“DispECG_ENG files”,單擊右鍵,選擇“Add Files to Project…”將DispECG_ENG工程下的resource.h和DispECG_ENG.rc加入到DispECG_ENG工程。
資原始檔DispECG_ENG.rc及資源ID定義檔案resource.h加入工程後:
d)修改編輯resource.h和DispECG_ENG.rc
d.1)將檔案頭的註釋“Used by DispECG_ENG.rc”修改為“Used by DispECG_ENG.rc”
d.2)修改資原始檔DispECG_ENG.rc,將
"#include ""res\\DispECG.rc2"" // non-Microsoft Visual C++ edited resources\r\n"
"#include ""l.chs\\afxres.rc"" // Standard components\r\n"
"#include "" l.chs\\afxprint.rc"" // printing/print preview resources\r\n"
修改為
"#include ""res\\DispECG_ENG.rc2"" // non-Microsoft Visual C++ edited resources\r\n"
"#include ""afxres.rc"" // Standard components\r\n"
"#include ""afxprint.rc"" // printing/print preview resources\r\n"
需要說明的是:MFC中含有一些預定義好的資源,不同的語言版本儲存在不同的目錄下,英文版儲存在MFC\Include下,其它語言的版本則儲存在Include的子目錄中,譬如中文版對應的目錄為l.chs,日文版對應l.jpn,韓文版對應l.kor,等等。
e)使用視覺化編輯環境編輯對話方塊、選單、字串、版本等語言依賴性資源,將中文版翻譯為英文版。當然,如果對資原始檔的結構非常瞭解,可使用文字編輯器對資原始檔直接編輯。方法是:使用“File\Open…”開啟檔案對化框,找到“DispECG_ENG.rc”,注意開啟方式選擇“Text”。
完成文字的翻譯是一項費時耗力的體力活兒,請耐心地仔細地一一做完。
f)修改工程設定,調整編譯後DLL檔案的存放位置。
由於按照預設的工程設定,DispECG_ENG.DLL的Release版自動生成在D:\My Project\DispECG\DispECG_ENG\Release下,Debug版自動生成在D:\My Project\DispECG\DispECG_ENG\Debug下。為了程式的處理方便,資源DLL最好和應用程式的可執行檔案存放在同一目錄。為做到這一點,請修改工程配置。
方法:操作選單“Project\Project Settings…”
在“Project Settings”中選擇“DispECG_ENG”工程,再選擇“Link”頁面,將輸出檔名由“Release/DispECG_ENG.dll”修改為“../Release/DispECG_ENG.dll”,這樣編譯後生成的DLL檔案將儲存在D:\My Project\DispECG\Release下。
除錯版也作類似的修改,使得編譯後生成的DLL檔案將儲存在D:\My Project\DispECG\Debug下。
g)編譯DispECG_ENG工程,生成發行版和除錯版的DispECG_ENG.DLL。
在編譯資源DLL時別忘了在連線時加上/NOENTRY選項以告訴聯結器這是一個唯一資源的DLL,不包含程式執行的入口點。
(三)在程式中新增多語言支援程式
a) 定義資源名稱
在DispECG工程中的StdAfx.h中新增:
#define CHINESE 0
#define ENGLISH 1
b)定義兩個全域性變數,一個表示當前的語言選擇,另一個為資源控制代碼。
UINT nLanguage = ENGLISH;
HINSTANCE hResourceHandle = NULL;
c)新增資源DLL載入程式
在完成應用程式初始化的BOOL CDispECGApp::InitInstance()中新增依據語言選擇資源DLL的程式程式碼。
nLanguage = GetProfileInt("SETTINGS","LANGUAGE",ENGLISH);
if (nLanguage != CHINESE)
{
CString strFile;
strFile = "NewDispECG_ENG.dll";
hResourceHandle = AfxLoadLibrary(strFile);
ASSERT(hResourceHandle);
if (hResourceHandle)
{
AfxSetResourceHandle(hResourceHandle);
}
else
{
CString strText;
strText.Format("%s not found!",strFile);
::MessageBox(NULL,strText,"Error",MB_OK|MB_ICONERROR);
return FALSE;
}
}
d)新增資源DLL解除安裝程式
CDispECGApp::~CDispECGApp()
{
if (hResourceHandle)
AfxFreeLibrary(hResourceHandle);
}
e) 新增語言選擇選單和命令實現程式碼。
同步更新各種版本的資源,編輯選單加入語言選擇選單項。注意同一選單項不同語言版本的命令ID保持一致。
使用類嚮導新增命令響應:
void CDispECGApp::OnSwitchVersion()
{
WriteProfileInt("SETTINGS","LANGUAGE",1-nLanguage);
AfxMessageBox(ID_SWITCH_VERSION);
TRACE("%s\n%s\n%d\n
%s\n",m_pszAppName,m_lpCmdLine,m_nCmdShow,m_pszExeName);
}
(四)修改程式程式碼,根據資源ID呼叫資源
如果原先的程式未考慮到多語言支援,在顯示提示資訊時可能使用如下的語句:
AfxMessageBox("檔案無法開啟!");
此時應該將諸如"檔案無法開啟!"此類的字串新增到字串資源中,其它語言版本同步更新。同樣,注意字串ID的彼此一致。一個好的習慣是,各版本的資源同步更新後,使用VC開發環境自帶的WinDiff.exe對各個版本下的resource.h進行檔案內容比較,以確保各語言的資源ID彼此完全一致。
修改完畢後,改用根據資源ID進行資源訪問的函式。在實際程式設計中,最常用到的是對字串資源的訪問以及提示資訊的顯示,所以下面這些函式在需多語言支援的應用程式中會常被使用:
int AFXAPI AfxMessageBox( UINT nIDPrompt, UINT nType = MB_OK, UINT nIDHelp = (UINT) -1 );
BOOL LoadString( UINT nID );
void Format( UINT nFormatID, ... );
void FormatMessage( UINT nFormatID, ... );
...
至於其它資源,比如對話方塊、選單等,通常由系統自動完成載入,無需程式設計師在軟體中進行特別處理。