双语或多语种成品软件的编制 .吕维 只用一套源代码就可以方便地支持多种文字和多个地域,那么这个软件就可以方便地被翻译成本地版本,这个过程叫做地域化(Localization)。怎样才能不修改任何源代码就使之能动态地转换到不同的地域资源上呢?那就是使用Windows的程序特性之一-- 资源。把在软件中用到的可见资源维系在一个资源DLL(Dynamic Link Library动态链接库)中,就能使地域化很容易地被实现,因为它把具体的文字组件单独提取放在一个文 件中,所以,一个可执行文件就可以装载几种不同的语言文字,并且选择用子程序来装 载适合的文字DLL。创建一个CString对象的实例,并用该字串的资源标识符(string ID) 调用LoadString,即可避免繁琐的字串编码工作。 在大多数情况下,资源包含在应用程序的单元中,如果调用AfxSetResource Handle,可以指向另一个不同的单元,示例StateDemo程序就是这样处理的。调用AfxSetResourceHandle,从DLL资源中采集软件所需资源,通过替换掉不同语种的DLL资源,程序便可以使用一套完全不同的资源(如String字串、Dialogue对话框、Bmp位图、Menu菜单等)。 初始情况下,作为主执行体的StateDemo不含任何资源。首先,创建一个包含所有英 文资源的DLL,在使用这个资源DLL时,应用程序就会以英文形式出现,即软件为英文版 ;然后,创建中文DLL,再次运行StateDemo程序,程序就以中文形式出现(即使应用程 序未被重新编译)。 一.应用程序的创建与编译 1.创建StateDemo.EXE文件(1)创建StateDemo工作区 在Microsoft Visual C++ 5.0开发环境下,单击File | New选项,在创建类型选择 框New 中选择MFC AppWizard(exe)、Projectname:StateDemo,创建新项目StateDemo工作区, 应用 程序类型选择Multiple Documents,单击Finish完成工作区的建立。 (2)添加字串资源 这步实际上是在为英文资源DLL添加字串资源,因为后面将把英文资源StateDemo.rc 从项目中移走,并把它拷贝到英文资源的项目中,而不是刚建立的StateDemo.EXE文件 项目,执行体exe文件会引用这个资源,而字串就在资源DLL中。选择StateDemo项目资源 中的String Table,在StringTable中单击右键选择New String,添加如下代码,然后选 择菜单中File | Save All选项即完成。 ID:IDS_MINE=300 //主框架IDS_MINE定义为300,即ID的值为300 Caption(标题):Hi! it's my demo vc5 program of English version. //这是英文版软件中字串的演示 (3)添加CStateDemo类的数据成员 本程序要动态地装入包含所有资源的DLL,所以必须保存DLL的Handle(句柄),在 后面会释放Handle,并在CStateDemoApp类中添加私有数据成员(代码如下)。 private: HINSTANCE m_hDemoDLL;//资源DLL handle句柄 可以在MS-VC5的DevelopStudio位于左方的Workspace窗口中选择ClassView标签,单 击CstateDemoApp类,单击鼠标右键选择Add Member Variable,然后输入Type与 Declarition,并选择私有类型。 (4)修改CStateDemoApp::InitInstance函数 应用程序需装入包含所有资源的DLL,在本例程序中,英文资源DLL都命名为Resource.dll。 把下面的代码加入初始化函数InitInstance的顶部。 BOOL CStateDemoApp::InitInstance() { AfxEnableControlContainer(); //Standard initialization //If you are not using these features and wish to reduce the size //of your final executable, you should remove from the following //the specific initialization routines you do not need. //调入StateDemo资源DLL. m_hDemoDLL=AfxLoadLibrary (_T("Resource.dll")); if(!m_hDemoDLL) //如果Resource.dll文件Handle不存在 { AfxMessageBox(_T("I can't load the resource DLL !")); return FALSE; } //告诉应用程序设置资源句柄m_hDemoDLL; AfxSetResourceHandle(m_hDemoDLL); } (5)使用WizardBar处理CStateDemoApp的ExitInstance函数 在此需要释放前面用AfxLoadLibrary装入的DLL,将下面的代码添加到函数ExitInstance 中就可达到此目的。选择菜单View | Class Wizard,在Message Maps的Classname Edit 窗口中选择CstateDemoApp,然后在Messages下找到ExitInstance,选择Edit Code并加入以下 代码。 int CStateDemoApp::ExitInstance() { //TODO: Add your specialized code here and/or call the base class if(m_hDemoDLL) AfxFreeLibrary(m_hDemoDLL);//释放DLL资源; retrun CWinApp::ExitInstance(); } (6)修改CStateDemoView::OnDraw 在Multiple-Document类型中显示不同语种字串和icon等各种资源,在函数中加入下 列代码。 void CStateDemoView::OnDraw(CDC*pDC) { CStateDemoDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); pDC->DrawIcon(10,10,AfxGetApp()->LoadIcon(IDR_MAINFRAME)); //从资源DLL中调入图标(ID为IDR_MAINFRAME)并在窗口10,10位置绘制; CString strMessage;//定义strMessage为Cstring字串类型; //从resource DLL中显示字串; strMessage.LoadString(IDS_DEMO); pDC->TextOut(60,65,strMessage); }
只用一套源代码就可以方便地支持多种文字和多个地域,那么这个软件就可以方便地被翻译成本地版本,这个过程叫做地域化(Localization)。怎样才能不修改任何源代码就使之能动态地转换到不同的地域资源上呢?那就是使用Windows的程序特性之一-- 资源。把在软件中用到的可见资源维系在一个资源DLL(Dynamic Link Library动态链接库)中,就能使地域化很容易地被实现,因为它把具体的文字组件单独提取放在一个文 件中,所以,一个可执行文件就可以装载几种不同的语言文字,并且选择用子程序来装 载适合的文字DLL。创建一个CString对象的实例,并用该字串的资源标识符(string ID)
调用LoadString,即可避免繁琐的字串编码工作。 在大多数情况下,资源包含在应用程序的单元中,如果调用AfxSetResource Handle,可以指向另一个不同的单元,示例StateDemo程序就是这样处理的。调用AfxSetResourceHandle,从DLL资源中采集软件所需资源,通过替换掉不同语种的DLL资源,程序便可以使用一套完全不同的资源(如String字串、Dialogue对话框、Bmp位图、Menu菜单等)。
初始情况下,作为主执行体的StateDemo不含任何资源。首先,创建一个包含所有英 文资源的DLL,在使用这个资源DLL时,应用程序就会以英文形式出现,即软件为英文版 ;然后,创建中文DLL,再次运行StateDemo程序,程序就以中文形式出现(即使应用程 序未被重新编译)。
一.应用程序的创建与编译
1.创建StateDemo.EXE文件(1)创建StateDemo工作区 在Microsoft Visual C++ 5.0开发环境下,单击File | New选项,在创建类型选择 框New 中选择MFC AppWizard(exe)、Projectname:StateDemo,创建新项目StateDemo工作区, 应用 程序类型选择Multiple Documents,单击Finish完成工作区的建立。
(2)添加字串资源 这步实际上是在为英文资源DLL添加字串资源,因为后面将把英文资源StateDemo.rc
从项目中移走,并把它拷贝到英文资源的项目中,而不是刚建立的StateDemo.EXE文件 项目,执行体exe文件会引用这个资源,而字串就在资源DLL中。选择StateDemo项目资源 中的String Table,在StringTable中单击右键选择New String,添加如下代码,然后选 择菜单中File | Save All选项即完成。
ID:IDS_MINE=300 //主框架IDS_MINE定义为300,即ID的值为300 Caption(标题):Hi! it's my demo vc5 program of English version. //这是英文版软件中字串的演示
(3)添加CStateDemo类的数据成员 本程序要动态地装入包含所有资源的DLL,所以必须保存DLL的Handle(句柄),在 后面会释放Handle,并在CStateDemoApp类中添加私有数据成员(代码如下)。
private: HINSTANCE m_hDemoDLL;//资源DLL handle句柄 可以在MS-VC5的DevelopStudio位于左方的Workspace窗口中选择ClassView标签,单 击CstateDemoApp类,单击鼠标右键选择Add Member Variable,然后输入Type与 Declarition,并选择私有类型。
(4)修改CStateDemoApp::InitInstance函数 应用程序需装入包含所有资源的DLL,在本例程序中,英文资源DLL都命名为Resource.dll。 把下面的代码加入初始化函数InitInstance的顶部。
BOOL CStateDemoApp::InitInstance() { AfxEnableControlContainer(); //Standard initialization //If you are not using these features and wish to reduce the size //of your final executable, you should remove from the following //the specific initialization routines you do not need. //调入StateDemo资源DLL. m_hDemoDLL=AfxLoadLibrary (_T("Resource.dll")); if(!m_hDemoDLL) //如果Resource.dll文件Handle不存在 { AfxMessageBox(_T("I can't load the resource DLL !")); return FALSE; } //告诉应用程序设置资源句柄m_hDemoDLL; AfxSetResourceHandle(m_hDemoDLL); } (5)使用WizardBar处理CStateDemoApp的ExitInstance函数 在此需要释放前面用AfxLoadLibrary装入的DLL,将下面的代码添加到函数ExitInstance
中就可达到此目的。选择菜单View | Class Wizard,在Message Maps的Classname Edit
窗口中选择CstateDemoApp,然后在Messages下找到ExitInstance,选择Edit Code并加入以下 代码。 int CStateDemoApp::ExitInstance() { //TODO: Add your specialized code here and/or call the base class if(m_hDemoDLL) AfxFreeLibrary(m_hDemoDLL);//释放DLL资源; retrun CWinApp::ExitInstance(); }
(6)修改CStateDemoView::OnDraw 在Multiple-Document类型中显示不同语种字串和icon等各种资源,在函数中加入下 列代码。 void CStateDemoView::OnDraw(CDC*pDC) { CStateDemoDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); pDC->DrawIcon(10,10,AfxGetApp()->LoadIcon(IDR_MAINFRAME)); //从资源DLL中调入图标(ID为IDR_MAINFRAME)并在窗口10,10位置绘制; CString strMessage;//定义strMessage为Cstring字串类型; //从resource DLL中显示字串; strMessage.LoadString(IDS_DEMO); pDC->TextOut(60,65,strMessage); }
具体操作如下:选择Workspace下的FileView,单击StateDemo.rc,按键盘上Delete键删除,
此时所有资源就不在项目中了。
(8)编译StateDemo项目 开始编译项目,单击菜单Build | Execute StateDemo.exe选项,由于此时项目中没 有资源,因此会弹出报错消息框"I can't load the resource DLL !",单击OK,不予理会。 现在,StateDemo项目的执行体StateDemo.exe就建成了,它不包含任何资源,而是 依靠动态链接库DLL来提供所有资源。 下面来创建中、英文资源DLL,在这个DLL建立之后,把资源DLL拷回到本项目的Debug
或Release目录中,就可运行该应用程序了。 2.创建英文资源Resource.dll
(1)创建英文新项目区 在创建类型选择框New中选择MFC AppWizard(dll),创建一个英文新项目区,在Location下
为工作区选择目录...\StateDemo\即...\StateDemo\English作为该项目区目录,单击OK,
在Step1中选择Regular DLL using MFC DLL,单击OK即可。
(2)删除项目中所有文件 刚才建立的DLL已包含了一些资源,但它的各种文件都不需要,所以在Workspace FileView
中选中所有文件,按Delete删除所有文件。
(3)从StateDemo项目中复制英文资源文件 现在要用刚才从StateDemo中移出的英文资源,前面曾把一个资源字串加入到StateDemo.rc文件中,
在此,资源字串就起作用了。将...\StateDemo目录下的StateDemo.rc和Resource.h拷贝到
..\Statedemo\English目录下。目的是把...\StateDemo\res下的所有资源转移到..\StateDemo\English\res
目录下。下面列出需从项目StateDemo中拷贝到项目英文中的所有文件及其注释。
需要拷贝的文件 注释 StateDemo.rc 资源文件 resource.h 资源头文件 res\StateDemo.ico 主程序的图标 res\StateDemo.rc2 用户资源描述文件 res\StateDoc.ico 文挡图标 res\Toolbar.bmp 工具条位图
(4)将资源文件添加到英文项目中去,使图标变为英文资源式样 把StateDemo.rc加入到英文项目中去,你可以在VC5 Develop Studio的Workspace窗 口的File View选项卡中选择"English"。单击右键选择Add project to workspace选项,
把文件加入项目中。在此,你可以从Resource View选项卡中看到,在最开始的StateDemo
项目中加入的字串IDS_DEMO("It's my demo...")现在已被移到了英文项目中,并将成为Resource.dll的一员。 既然这个英文项目是英文资源DLL,并命名为Resource.dll(与后面建立的中文Resource.dll同名,
这样才能使EXE执行程序存取双语或多语种DLL),所以要修改图标来演示StateDemo.exe被调入时是英文版的。
把IDR_MAINFRAME图标修改为英文文化特征的,或在Resource View选项卡的图标一栏
单击右键选择Import来导入你想要的图标,它可以是16*16,也可以是32*32,本演示程序
是使用英国国旗作为IDR_MAINFRAME,以示是英文版的。你可以按自己的需要和风格任意修改在Resource View中的其他资源。
(5)修改链接目标程序中的设置 建立英文资源DLL的任务已经基本完成,还需修改DLL程序在Link前的设置。选择Workspace选项卡,
选择Project | Settings选项,在窗口中选择Link标签,改变一些Link设置,将输出的文件名改为Resource.dll,
也就是中英文资源同名的那个英文资源DLL,在链接命令Project Options中加入\NOENTRY,它的功能是
告诉链接器这是一个含有唯一资源的DLL,不包括入口点。注意必须把/NOENTRY选项加进公用项编译控件中。 至此,英文资源DLL就创建成功了。运行它时,Resource.DLL就在...\StateDemo\English\Debug目录下了。
如需运行英文版演示程序,则把它拷贝到StateDemo\Debug目录下,然后运行StateDemo.exe文件,现在就
是英文资源起作用了,它显示英文和英国国旗。 3.创建中文资源Resource.dll
(1)创建中文新项目区并删除中文项目中所有文件 在创建类型选择框New中选择MFC AppWizard(dll),创建一个中文新项目区,在Location下为工作区
选择目录...\StateDemo\即...\StateDemo\Chinese作为该项目区目录,单击OK。其他选项如上面创建英文项目区所述。 刚建立的DLL已包含了一些资源,但它的各种文件在此都不需要。所以,在Workspace FileView中选中所有文件,
按Delete删除所有文件。
(2)拷贝资源文件 仍然使用前面从StateDemo中移出的英文资源,同样将目录..\StateDemo\下StateDemo.rc和Resource.h
拷贝到刚建立的中文资源项目目录Chinese下,将..\StateDemo目录下的StateDemo.rc和Resource.h拷贝
到...\Statedemo\Chinese目录下。目的是把..\StateDemo\res下的所有资源转移到...\StateDemo\Chinese\res目录下,
需从项目StateDemo拷贝到项目Chinese的所有文件和注释也如上述表1所示。
(3)把资源文件添加到中文项目中使图标变为中文资源式样 把StateDemo.rc加入到Chinese项目中去,你可以在VC5 Develop Studio的Workspace窗口的File View选项卡中
选择"Chinese",单击右键选择Add project to workspace选项把文件加入到项目中。在此,StateDemo项目中
的字串IDS_DEMO("it's my demo...")已经移到中文项目中,并将成为中文Resource.dll的一员。现在的
Resource.dll是中文资源DLL(与前面建立的英文Resource.dll同名),把IDS_DEMO改为中文字串,代码如 下:
IDS_DEMO=300, Caption(标题):"你好!这是MS VC5中文演示程序!"
字串修改完成后,需要对菜单进行地域化处理,即把菜单项改为中文。打开Resource View标签,双击Menu项,
在右边工作区所显示的MFC标准菜单中把英文翻译成中文;也可以添加菜单项,按软件所需作完全个性化的设计。
本演示程序使用中国国旗做IDR_MAINFRAME,以表示是中文版。你还可以按自己的需要和风格任意修改Resource View中
的其他资源。
(4)修改中文DLL链接目标程序和资源组件中的设置 中文资源DLL也需要修改DLL程序在Link前的设置,其方法与英文的相同:依次选择 Workspace选项卡、Project | Settings菜单、Link选项卡,改变一些Link设置,将输出 的文件名改为Resource.dll,在链接命令Project Options中加入\NOENTRY。修改资源组件
中的设置,在Project | Settings菜单中的Resource选项卡中,将缺省的文字改为中文
(如果是中文Windows,则此处就已经是中文了),接下来删除预处理定义_AFXDLL,
最后在Directory中输入Visual C++ 5.0安装目录1.chs的路径,这个目录下装的是中文特定资源。
还有其他资源如\1.fra法语、\1.ita意大利语、\1.kor韩文等,都可以在需要时选择使用。 删除预处理定义_AFXDLL并输入资源的路径的目的是要包含通用的资源,如果没有这样做,
则应用程序会从系统安装的MFC中收集通用的资源。应用程序特定资源会被地域化,通用的MFC资源
(诸如光标、打印预览和通用属性页)则不需要。所修改的设置如图6所示。
(5)链接并运行中文资源DLL 按热键F7进行链接,中文资源Resource.DLL就在...\StateDemo\Chinese\Debug目录 下了。要看中文,就把它拷贝到StateDemo\Debug目录下,然后再运行StateDemo.exe文 件,这时显示的就是中文版了。所有资源都中文化了,如中国国旗、中文菜单等,起作 用的就是刚建立的中文资源Resource.dll,运行结果如图7所示。要注意的是,由于中文 资源DLL包含了所有通用的MFC资源,所以它比英文要大一些。
至此,两种资源的DLL都建立好了。在本演示程序中,资源全部被从可执行文件中移 走并被放入一个DLL中。在MFC类引用任何资源时(比如CString::LoadString),都可以 使用当前的资源句柄。通常情况下,当前资源句柄和应用程序的资源句柄是一样的,但 本演示程序通过AfxSetResourceHandle改变了这种情况,该函数通过传给AfxSetResour ceHandle的句柄使MFC提取所有的资源。当英文的DLL被中文的DLL所取代时,资源ID就访 问定位在中文DLL的资源。由于DLL是从初始的DLL拷贝翻译过来的,所以,所有的资源应 是完整的,只不过是被翻译成中文罢了。Windows应用程序的资源一般维系在执行程序上 ,当需要时才被装入。当你的应用程序需要某种资源时,需要给Windows提供两件东西: 应用程序的实例句柄和资源的标识符。