只用一套源代码就可以方便地支持多种文字和多个地域,那么这个软件就可以方便地被翻译成本地版本,这个过程叫做地域化(localization)。怎样才能不修改任何源代码就使之能动态地转换到不同的地域资源上呢?那就是使用windows的程序特性之一--资源。把在软件中用到的可见资源维系在一个资源dll(dynamic link library动态链接库)中,就能使地域化很容易地被实现,因为它把具体的文字组件单独提取放在一个文件中,所以,一个可执行文件就可以装载几种不同的语言文字,并且选择用子程序来装载适合的文字dll。创建一个cstring对象的实例,并用该字串的资源标识符(string id)调用loadstring,即可避免繁琐的字串编码工作。 在大多数情况下,资源包含在应用程序的单元中,如果调用afxsetresource handle,就可以指向另一个不同的单元,我下面给出的statedemo程序就是这样处理的。调用afxsetresource handle,从dll资源中采集软件所需资源,通过替换掉不同语种的dll资源,程序便可以使用一套完全不同的资源(如string字串、dialogue对话框、bmp位图、menu菜单等)。 初始情况下,作为主执行体的statedemo不含任何资源。首先,创建一个包含所有英文资源的dll,在使用这个资源dll时,应用程序就会以英文形式出现,即软件为英文版;然后,创建中文dll,再次运行statedemo程序,程序就以中文形式出现(即使应用程序未被重新编译)。
i. 应用程序的创建与编译
(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 !")); //没有找到resource.dll文件时,弹出消息框发出警告:i can't load the resource dll !; //警告消息框如图2所示 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); } (7)从statedemo project中移走statedemo.rc 因需要程序中不含有任何资源,只在resource.dll中含有资源,所以,要在此项目中移走所有资源,并把它们放进resource.dll中,但不是删除,这就是使用mfc的灵活性。具体操作如下:选择workspace下的fileview,单击statedemo.rc,按键盘上delete键删除,此时所有资源就不在项目中了。 (8)编译statedemo项目 开始编译项目,单击菜单build | execute statedemo.exe选项,由于此时项目中没有资源,因此会弹出报错消息框"i can't load the resource dll !",如图2所示,单击ok,不予理会。 现在,statedemo项目的执行体statedemo.exe就建成了,它不包含任何资源,而是依靠动态链接库dll来提供所有资源。 下面来创建中、英文资源dll,在这个dll建立之后,把资源dll拷回到本项目的debug或release目录中,就可运行该应用程序了。