字符串表资源和本地化

本文详细解析了字符串表资源STRINGTABLE在程序本地化中的二进制结构,展示了如何通过多语言字符串表资源文件进行本地化操作,并提供了编写的更新子程序实例。涉及关键步骤包括资源文件编写、本地化更新函数和实际应用示例,适用于多语言软件开发。
摘要由CSDN通过智能技术生成

字符串表资源(STRINGTABLE)和程序本地化

在多语言编程中,使用UpdateResource函数可实现资源本地化,如对话框、菜单、版本等资源的本地化。然字符串表的本地化需要进行特别的处理,这就需要对字符串表资源的二进制数据结构有所了解。

1. 字符串表资源的二进制数据结构

字符串表资源使用STRINGTABLE语句定义,但串表设有名称或ID。

FindResourceEx函数对字符串资源的内存格式描述为: 字符串资源存储在每个组最多16个字符串的组中。每个组中字符串都以Unicode格式存储为字符串长度和字符串值(不一定以NULL结尾)。LoadString函数将从其对应的部分提取字符串资源。

根据对字符串资源的内存格式分析,为了提高字符串的检索效率,字符串资源以分组方式存贮,如果用FindResourceEx函数来搜索字符串,则只能搜索字符串组(这与搜索RT_GROUP_CURSOR和RT_GROUP_ICON类资源有点类似),然后再使用列遍的方法在搜索到的组内搜索对应ID的字符串。

字符串组的二进制数据结构如下:

    第1组: 
    dw ?    ;ID=00h的字符串的长度(WORD单位,以下同)
    dw .... ;字符串值(Unicode格式)。如果字符串的长度=0,则无该内容(以下同理)。
    dw ?    ;ID=01h的字符串的长度
    dw .... ;字符串值。
    ......
    dw ?    ;ID=0fh的字符串的长度
    dw .... ;字符串值

    如果资源中未定义ID=0-0fh的字符串,则没有该组的内容(以下同理)。

    第2组: 
    dw ?    ;ID=10h的字符串的长度
    dw .... ;字符串值
    dw ?    ;ID=11h的字符串的长度
    dw .... ;字符串值
    ......
    dw ?    ;ID=1fh的字符串的长度
    dw .... ;字符串值

   第3组: 
   ......

例: 如果RC资源文件中定义以下的字符串表:

    STRINGTABLE
    BEGIN
      0                    "A000000000"
      1                    "B000000001"
      3                    "C000000003"
      4                    "D000000004"
      35                   "E000000035"
      38                   "F000000038"
    END

则字符串资源内存格式如下:

   第1组: 
   dw 0ah          ;ID=00h的字符串的长度
   dw "A000000000" ;串值(这不是合法的语句,只表示它是一个Unicode串,下同)
   dw 0ah          ;ID=01h的字符串的长度
   dw "B000000001"
   dw  00          ;ID=02h的字符串的长度
   dw 0ah          ;ID=03h的字符串的长度
   dw  "C000000003"
   dw 0ah          ;ID=04h的字符串的长度
   dw "D000000004"
   dw 00h          ;ID=05h的字符串的长度
   dw 00h          ;ID=06h的字符串的长度
   dw 00h          ;ID=07h的字符串的长度
   dw 00h          ;ID=08h的字符串的长度
   dw 00h          ;ID=09h的字符串的长度
   dw 00h          ;ID=0ah的字符串的长度
   dw 00h          ;ID=0bh的字符串的长度
   dw 00h          ;ID=0ch的字符串的长度
   dw 00h          ;ID=0dh的字符串的长度
   dw 00h          ;ID=0e0h的字符串的长度
   dw 00h          ;ID=0fh的字符串的长度

   第2组: 无该组内容。因为未定义10h-1fh的字符串。
 

   第3组:
   dw 00h          ;ID=20h的字符串的长度
   dw 00h          ;ID=21h的字符串的长度
   dw 00h          ;ID=22h的字符串的长度
   dw 0ah          ;ID=23h(35)的字符串的长度
   dw "E000000035"
   dw 00h          ;ID=24h的字符串的长度
   dw 00h          ;ID=25h的字符串的长度
   dw 0ah          ;ID=26h(38)的字符串的长度
   dw "F000000038"
   dw 00h          ;ID=27h的字符串的长度
   dw 00h          ;ID=28h的字符串的长度
   dw 00h          ;ID=29h的字符串的长度
   dw 00h          ;ID=2ah的字符串的长度
   dw 00h          ;ID=2bh的字符串的长度
   dw 00h          ;ID=2ch的字符串的长度
   dw 00h          ;ID=2dh的字符串的长度
   dw 00h          ;ID=2eh的字符串的长度
   dw 00h          ;ID=2fh的字符串的长度

2. 字符串表本地化例子

2.1 多语言字符串表资源

写一个多语言字符串表资源文件,文件名假定的mui.rc,该资源文件包含以下3种语言的字符串表资源。并使用该资源创建一个简单的DLL,假定该DLL文件名为mui.dll。该DLL没有导出函数,只包含多语言资源,供本地化使用。

 #define IDS_FILE      1000
 #define IDS_EXIT      9001
 #define IDS_UNDO      1002
 #define IDS_CUT       1003
 #define IDS_COPY      1004
 #define IDS_PASTE     1005
 #define IDS_FONT      1015
 #define IDS_COLOR     1016

// 英文
LANGUAGE 9,1  //0x409
STRINGTABLE
BEGIN
  IDS_FILE       "File"
  IDS_EXIT       "Exit"
  IDS_UNDO       "Undo"
  IDS_CUT        "Cut"
  IDS_COPY       "Copy"
  IDS_PASTE      "Paste"
  IDS_FONT       "Font"
  IDS_COLOR      "Color"
END
// 简体中文
LANGUAGE 4,2  //0x804
STRINGTABLE
BEGIN
  IDS_FILE       "文 件"
  IDS_EXIT       "退 出"
  IDS_UNDO       "撤 消"
  IDS_CUT        "剪 切"
  IDS_COPY       "复 制"
  IDS_PASTE      "粘 贴"
  IDS_FONT       "字 体"
  IDS_COLOR      "颜 色"
END
// 繁体中文
LANGUAGE 4,1  //0x404
STRINGTABLE
BEGIN
  IDS_FILE       "文 件"
  IDS_EXIT       "退 出"
  IDS_UNDO       "撤 消"
  IDS_CUT        "剪 切"
  IDS_COPY       "復 製"
  IDS_PASTE      "粘 貼"
  IDS_FONT       "字 體"
  IDS_COLOR      "顏 色"
END

2.2 编写一个串表更新子程序

根据FindResourceEx函数的描述,字符串是以组为单位进行搜索和装载的,如果要对字符串表实现本地化,则也应以组为单位进行本地化。

以下的子程序用于对指定的字符串资源进行更新,以实现本地化。

;==========================================================
;更新指定的字符串表资源---用于字符串资源的本地化
;入: hUpdate=目标文件的更新句柄(BeginUpdateResource函数返回)
;    wMinId=要更新的最小字符串资源ID
;    wMaxId=要更新的最大字符串资源ID
;    hInst=源资源模块句柄
;    ulang=源模块资源中用于更新的资源语言
;出: NO
;注: 如果字符串资源ID的间隔值较大,则可分段更新
;=========================================================
Update_StringTable proc hUpdate:QWORD,wMinId:QWORD,\
                       wMaxId:QWORD,hInst:QWORD,\
                       ulang:DWORD
 LOCAL ss_size:DWORD
 LOCAL ss_hRes:QWORD
;---将字符串ID转换为组序号---
 mov rax,wMinId
 shr rax,4    ;/16
 inc rax
 mov wMinId,rax   ;组号
 mov rax,wMaxId
 shr rax,4    ;/16
 inc rax
 mov wMaxId,rax   ;组号
;---在源资源模块中搜索资源---
ss_lp1:
 invoke FindResourceEx,hInst,RT_STRING,wMinId,ulang
 test rax,rax
 jz ss_nt
 mov ss_hRes,rax
 invoke SizeofResource,hInst,ss_hRes
 mov ss_size,eax ;资源尺寸
 invoke LoadResource,hInst, ss_hRes
 test rax,rax
 jz ss_nt
 invoke LockResource,rax
 test rax,rax
 jz ss_nt
;---复制资源---
 mov r10,rax
 invoke UpdateResource,hUpdate,RT_STRING,wMinId,0,r10,ss_size
ss_nt:
 inc wMinId
 mov rax,wMinId
 cmp rax,wMaxId
 jbe ss_lp1 ;搜索下一个组
 ret
Update_StringTable endp

为了本地化的完整性,另写一个子程序,以下子程序用于更新普通的资源。

;==========================================================
;更新指定的资源
;入: hUpdate=目标文件的更新句柄(BeginUpdateResource函数返回)
; rType=要更新的资源类型
; wId=要更新的资源ID
; hInst=源资源模块句柄
; uId=源模块资源中用于更新的资源ID
; ulang=源模块资源中用于更新的资源语言
;出: RAX=TRUE: 成功
; =FALSE: 失败
;=========================================================
Update_Rsrc proc hUpdate:QWORD,rType:QWORD,wId:QWORD,
hInst:QWORD,uId:QWORD,ulang:DWORD
LOCAL ss_size:DWORD
LOCAL ss_hRes:QWORD
;—在源资源模块中搜索资源—
invoke FindResourceEx,hInst,rType,uId,ulang
test rax,rax
jz ss_0
mov ss_hRes,rax
invoke SizeofResource,hInst,ss_hRes
mov ss_size,eax
invoke LoadResource,hInst, ss_hRes
test rax,rax
jz ss_0
invoke LockResource,rax
test rax,rax
jz ss_0
;—复制资源—
mov r10,rax
invoke UpdateResource,hUpdate,rType,wId,0,r10,ss_size
ss_0:
ret
Update_Rsrc endp

2.3 本地化操作

软件的本地化一般是在安装时完成的,假如你需要本地化的程序文件名为test.exe,则安装包中应包含用于本地化的mui.dll文件和安装程序install.exe。

安装程序install.exe中包含以下子程序,根据用户所选择的应用语言环境,更新test.exe程序中的资源。更新完成后,mui.dll文件和安装程序install.exe不再需要,可以删除。

;=======================================
;本地化示例子程序
;入: wlang=test.exe程序的应用环境语言:
;        409h--美国英语
;        804h--简体中文
;        404h--繁体中文
;=======================================
App_Local proc wlang:DWORD
 LOCAL ss_hInst:QWORD
 LOCAL ss_hUpdate:QWORD
;---装载源DLL文件,其中包含要复制的资源---
 invoke LoadLibrary,"mui.dll"
 mov ss_hInst,rax
 test rax,rax
 jz ss_0
;---打开目标文件的更新句柄---
 invoke BeginUpdateResource,"test.exe", FALSE
 test rax,rax
 jz ss_out
 mov ss_hUpdate,rax
;---更新字符串表资源(最小ID=IDS_FILE,最大ID=IDS_EXIT)---
 invoke Update_StringTable,ss_hUpdate,IDS_FILE,IDS_EXIT,ss_hInst,wlang
;-------------------------------------------------
; 如果mui.dll文件中还包含消息表、菜单、版本等资源,
; 则调用Update_Rsrc函数进行更新
;-------------------------------------------------
;---更新版本资源---
 invoke Update_Rsrc,ss_hUpdate,RT_VERSION,VS_VERSION_INFO,\
                     ss_hInst,VS_VERSION_INFO,wlang
;---更新菜单资源---
 invoke Update_Rsrc,ss_hUpdate,RT_MENU,IDM_MAIN,\
                    ss_hInst,IDM_MAIN,wlang
;---更新消息表资源---
 invoke Update_Rsrc,ss_hUpdate,RT_MESSAGETABLE,1,ss_hInst,1,wlang
;---完成更新---
 invoke EndUpdateResource,ss_hUpdate,FALSE
ss_out:
 invoke FreeLibrary,ss_hInst
ss_0:
 ret
App_Local endp

2.4 其他说明

如果你的Windows系统中有LoadMUILibrary函数,则可以使用.mui文件来包含多语言资源,而不使用DLL文件。用rc.exe编译mui.rc资源文件,来获取.mui文件,用LoadMUILibrary装载.mui文件,并用FreeMUILibrary释放。其他本地化操作与上述类似。

;—完成更新—
invoke EndUpdateResource,ss_hUpdate,FALSE
ss_out:
invoke FreeLibrary,ss_hInst
ss_0:
ret
App_Local endp

## 2.4 其他说明

如果你的Windows系统中有LoadMUILibrary函数,则可以使用.mui文件来包含多语言资源,而不使用DLL文件。用rc.exe编译mui.rc资源文件,来获取.mui文件,用LoadMUILibrary装载.mui文件,并用FreeMUILibrary释放。其他本地化操作与上述类似。














  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值