分享
 
 
 

windows mobile 下用资源DLL实现多语言支持的方法

王朝system·作者佚名  2007-01-12
窄屏简体版  字體: |||超大  

这几天一直在研究这个东东,总算小有所成,中间走了不少弯路,摔了不少跟头,也学到了不少知识。

之所以把这点东西写出来,是为了让和我曾经一样迷茫的兄弟们找到一点方向,不要像我一样浪费那么多时间在一些无谓的事情上。

实现软件国际化目前有两种方式:

第一种是像FLASHGET那样将菜单文本等按资源ID写入一个TXT文件,需要时提取文本,刷新窗体,这种方式的弊端就是语言选择菜单内的语言种类是固定的,想要添加/删除一种语言要修改主程序,而且不方便管理,甚至会造成资源无法完全本地的问题。

第二种是用资源DLL实现软件的国际化,是MS推荐的方式,也是比较好管理的方式,这种方式可以动态的添加和删除附属语言DLL而不用更改主程序的代码,效率高,管理方便。

下面我就说说我在windows moblie下是如何实现第2种方法的。

1。建立一个win32应用程序MUL_LAN 作为主程序,并且添加rc档作为默认的菜单

//

// Menu

//

IDR_MENU MENU

BEGIN

POPUP "menu"

BEGIN

MENUITEM "文件", ID_MENU_FILE

MENUITEM "语言", IDM_LANG//选择语言的菜单按键

MENUITEM "关于", IDM_ABOUT

END

END

// Dialog

//

IDD_ABOUTBOX DIALOG 0, 0, 156, 129

STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION

EXSTYLE 0x80000000L

CAPTION "关于 MUL_LAN"

FONT 9, "MS Shell Dlg"

BEGIN

ICON IDI_MUL_LAN,IDC_STATIC_1,12,12,20,20,SS_REALSIZEIMAGE

LTEXT "MUL_LAN 1.0 版",IDC_STATIC_2,12,36,70,8,SS_NOPREFIX

LTEXT "版权所有 (C) 2006",IDC_STATIC_3,12,48,66,8

END

IDD_ABOUTBOX_WIDE DIALOG 0, 0, 210, 129

STYLE DS_SETFONT | WS_POPUP | WS_CAPTION

EXSTYLE 0x80000000L

CAPTION "关于 MUL_LAN"

FONT 9, "MS Shell Dlg"

BEGIN

ICON IDI_MUL_LAN,IDC_STATIC_1,12,12,21,20,SS_REALSIZEIMAGE

LTEXT "MUL_LAN 1.0 版",IDC_STATIC_2,48,12,66,8,SS_NOPREFIX

LTEXT "版权所有 (C) 2006",IDC_STATIC_3,48,24,66,8

END

IDD_COMBOBOX DIALOG 0, 0, 186, 95

STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU

CAPTION "Dialog"

FONT 8, "MS Shell Dlg"

BEGIN

DEFPUSHBUTTON "确定",IDOK,129,7,50,14

PUSHBUTTON "取消",IDCANCEL,129,24,50,14

LTEXT "请选择语言",IDC_STATIC,7,7,41,8

COMBOBOX IDC_COMBO1,7,22,111,131,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL |

END

//选择语言的DialogBox,上面有一个combobox用来动态列出可以使用的附属语言。

2。建立对应的附属语言DLL项目,添加资源档,其他可以不动,打开属性面板在链接器-〉高级-〉将“无入口点”属性改为“/NOENTRY”,以表明此项目的输出是纯资源DLL。

3。在主程序的MUL_LAN.cpp当中的主窗体消息处理函数

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)当中添加对“IDM_LANG”的处理

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{

switch (message)

{

……

case IDM_LANG:

DialogBox(g_hInst,(LPCTSTR)IDD_COMBOBOX,hWnd,(DLGPROC)Language);

break;

……

}

3。加载被选择语言对应DLL的函数

LRESULT CALLBACK Language(HWND hDlg,UINT message,WPARAM wParam,LPARAM)

{

int index;

LRESULT NewUILanguage;

HWND hwndCombo = GetDlgItem(hDlg,IDC_COMBO1);

HWND hMainWindow = GetParent(hDlg);

HMENU hNewMenu;

HMENU g_hMenu;

DWORD error;

switch (message)

{

case WM_INITDIALOG:

PopulateLanguages(hwndCombo);//寻找DLL目录并填充语言选择下拉cai

return TRUE;

case WM_COMMAND:

switch (LOWORD(wParam)) {

case IDOK:

index = SendMessage(hwndCombo, CB_GETCURSEL, 0, 0);

if( index != CB_ERR ) {

NewUILanguage = SendMessage(hwndCombo, CB_GETITEMDATA, index, 0);

if( NewUILanguage != CB_ERR && NewUILanguage != UILanguage ) {

UILanguage = (LANGID)NewUILanguage;

hSatDLL=LoadSatelliteDLL(UILanguage);

if( hSatDLL == NULL ) {

hSatDLL = g_hInst;

}

SetLastError(0);

hNewMenu=LoadMenu(hSatDLL,MAKEINTRESOURCE(IDR_MENU));

error=GetLastError();

SHMENUBARINFO mbi;//创建新的菜单栏

memset(&mbi, 0, sizeof(SHMENUBARINFO));

mbi.cbSize = sizeof(SHMENUBARINFO);

mbi.hwndParent = hMainWindow;

mbi.nToolBarId =IDR_MENU ;

mbi.hInstRes =hSatDLL;

if (!SHCreateMenuBar(&mbi))

{

error=GetLastError();

g_hWndMenuBar = NULL;

}

else

{

g_hWndMenuBar = mbi.hwndMB;

}

}

}

case IDCANCEL:

EndDialog(hDlg, LOWORD(wParam));

return TRUE;

}

break;

}

return FALSE;

}

// 填充选择对话框中的语言列表

// 根据用十进制 LCID 命名的子目录

int PopulateLanguages(HWND hwndCombo) {

TCHAR CurrentDirectory[MAX_PATH];

TCHAR CurrentFile[MAX_PATH];

int AvailableLangID;

TCHAR AvailableLangName[MAX_LANGNAME];

wchar_t *prt;

int PathLength;

HANDLE hDir;

int i = 0;

int j;

// 检索当前目录名

GetModuleFileName(NULL,CurrentFile,sizeof(CurrentFile)/sizeof(TCHAR));//当前文件

prt=wcsrchr(CurrentFile,TEXT('\\'));

PathLength=prt-CurrentFile;

wcsncpy_s(CurrentDirectory,sizeof(CurrentDirectory)/sizeof(TCHAR),CurrentFile,PathLength);

wcscat_s(CurrentDirectory,sizeof(CurrentDirectory)/sizeof(TCHAR),_T("\\*.*"));

// 循环访问所有目录并填充语言选择的

// 下拉列表

hDir = FindFirstFile(CurrentDirectory, &FindFileData);

if( hDir == INVALID_HANDLE_VALUE ) {

FindClose(hDir);

SendMessage(hwndCombo,CB_ADDSTRING,0,(LPARAM)CurrentDirectory);

return 0;

}

SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);

do {

if( FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {

AvailableLangID = _ttoi(FindFileData.cFileName);

if( AvailableLangID ) {

if( GetLocaleInfo(AvailableLangID,LOCALE_SNATIVELANGNAME,AvailableLangName,MAX_LANGNAME)) {

CurrentIndex = SendMessage(hwndCombo, CB_INSERTSTRING , 0, (LPARAM)AvailableLangName);

SendMessage(hwndCombo, CB_SETITEMDATA, (WPARAM)CurrentIndex, (LPARAM)AvailableLangID);

i++;

}

}

}

}while ( FindNextFile(hDir, &FindFileData) );

FindClose(hDir);

// 为了设置当前选择,我们必须循环访问组合框

// 因为添加操作按字母顺序排序组合框

for(j=0 ; j<=i ; j++) {

if( UILanguage == SendMessage(hwndCombo, CB_GETITEMDATA, j, 0) )

SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM)j, 0);

}

return i;

}

//加载选定语言DLL

HMODULE LoadSatelliteDLL(LANGID DesiredLanguage) {

TCHAR CurrentFile[MAX_PATH];

TCHAR CurrentDirectory[MAX_PATH];

TCHAR SatellitePath[MAX_PATH];

TCHAR buffer[100];

HMODULE hDLL;

int PathLength;

wchar_t* prt;

DWORD error;

// WIN32_FIND_DATA FindFileData;

//wchar_t* DLLname;

GetModuleFileName(NULL,CurrentFile,sizeof(CurrentFile)/sizeof(TCHAR));//当前文件

prt=wcsrchr(CurrentFile,TEXT('\\'));

PathLength=prt-CurrentFile+1;

wcsncpy_s(CurrentDirectory,sizeof(CurrentDirectory)/sizeof(TCHAR),CurrentFile,PathLength);

// // 先尝试加载具有完全指定语言的库

wcscpy_s(SatellitePath,sizeof(SatellitePath)/sizeof(TCHAR),CurrentDirectory);

_itot_s(DesiredLanguage,buffer, sizeof(buffer)/sizeof(TCHAR), 10);

wcscat_s(SatellitePath,sizeof(SatellitePath)/sizeof(TCHAR),buffer);

wcscat_s(SatellitePath,sizeof(SatellitePath)/sizeof(TCHAR),_T("\LANG.dll"));

hDLL=LoadLibrary( SatellitePath);

if( hDLL )

return hDLL;

else { // 尝试主语言 ID

_tcscpy_s(SatellitePath, sizeof(SatellitePath)/sizeof(TCHAR), CurrentDirectory);

DesiredLanguage = PRIMARYLANGID(DesiredLanguage);

_itot_s(DesiredLanguage,buffer,sizeof(buffer)/sizeof(TCHAR),10);

wcscat_s(SatellitePath,sizeof(SatellitePath)/sizeof(TCHAR),buffer);

wcscat_s(SatellitePath,sizeof(SatellitePath)/sizeof(TCHAR),_T("\1233.dll"));

hDLL = LoadLibraryEx(SatellitePath,NULL,DONT_RESOLVE_DLL_REFERENCES);

if( hDLL )

return hDLL;

else

return NULL;

}

}

就是这么简单,这个程序参考了MSDN的例程,但是关键部分都是自己重写的。

其中遇到的各种问题我也总结一下:

1.WINCE当中没有currentdirectory这个概念,如果想要加载DLL必须要使用绝对路径,问题是怎么找到DLL的绝对路径呢?方法是调用GetModuleFileName()函数,原形可以查MSND得到,该函数的第一个参数如果为NULL,则返回最后一个发出WM_CREAT 消息的文件的绝对路径,根据这个路径就可以找到DLL的路径。

2. WINCE当中使用的是UNICODE,对应的操作其实不难,只要记住:将char声明改称TCHAR,将CHAR* 改成wchar_t*,字符串引用都用TEXT宏包起来,搞定!

对应的还有几个字符串操作的函数,UNICODE的版本都是WCS开头的,比如wcscat_s(是wcscat的安全版本)是unicode版的字符串追加宏,强烈建议使用加_s而不是没有的的版本。原因不多说了,安全嘛呵呵,尤其是在拼路径的时候。

3.这个问题是浪费我时间的第2大罪魁祸首,他就是GetLastError();

此函数相当无聊,在我调用LoadLibrary的时候他不停的抱错,比如说代码6号,invalid module handle,再比如说126号 module handle could not found, 无知的我努力的寻找错误的根源,最终发现,众里寻她千百度。。。

强烈建议各位朋友在LoadLibrary 有返回值得时候别去管GetlastError给出的错误,完全是SHIT~

顺便提一下,我的LoadLibrary返回值unused是负数,如果你也返回了类似的数不要慌,转换成16进制看看~

4.第一大罪魁 模拟器 他加载了主程序的模块,但是不加载DLL模块。所以生成新菜单总是失败,害得我几乎把程序重写一遍都找不到错误。奉劝和我一样的新手们,一定要设备调试。。。。

就是这样啦,这是我完成的WINCE上的第一个任务,一路跌跌撞撞,总算是完成了,写出来和菜鸟们共同学习,希望你们不要跟我一样为了这些回头想想非常搞笑的问题浪费时间甚至暴跳如雷。

老鸟们可以扔鸡蛋了,谢谢~~

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有