开发者论坛

 找回密码
 注册 (请使用非IE浏览器)
查看: 7032|回复: 4

[教程] 动态改变MessageBox的按钮文本的语言

[复制链接]

0

精华

5099

贡献

5340

赞扬

管理员

帖子
1155
软币
21089
在线时间
4330 小时
注册时间
2013-6-7

黄马甲

发表于 2013-6-10 23:29:38 | 显示全部楼层 |阅读模式
通过设置CultureUIInfo无法改变MessageBox的按钮的文本语言,因为这个文本是根据你所安装的操作系统的语言决定的:你装的英文操作系统,
那么就是"Yes""No";你装的中文操作系统,那么就是“是”“否”。
所以对于可以改变语言版本的应用程序,就会遇到英文版应用程序下的MessageBox的按钮显示“是”“否”(中文操作系统);中文版应用程序下的
MessageBox的按钮显示"Yes""No"。傻呼呼。
想达到目的,还是可以的,只是比较麻烦,要不择手段。要使用win-API函数,以及Hook技术
下面是我参照着C++代码写的C#代码

一、首先声明Hook的类型
  1.    public enum HookType
  2.         {
  3.             Keyboard = 2,//键盘操作
  4.             CBT = 5,//窗口操作
  5.             Mouse = 7, //鼠标操作
  6.         };
复制代码
二、声明API函数
  1.         [DllImport("kernel32.dll")]
  2.         static extern int GetCurrentThreadId();//得到当前的线程ID
  3.         [DllImport("user32.dll")]
  4.         static extern int GetDlgItem(IntPtr hDlg, int nIDDlgItem);//得到Dialog窗口的子项
  5.         [DllImport("user32", EntryPoint = "SetDlgItemText")]
  6.         static extern int SetDlgItemTextA(IntPtr hDlg, int nIDDlgItem, string lpString);//设置Dialog窗口子项的文本
  7.         [DllImport("user32.dll")]
  8.         static extern void UnhookWindowsHookEx(IntPtr handle);//解掉挂钩
  9.         [DllImport("user32.dll")]
  10.         static extern IntPtr SetWindowsHookEx(int idHook, [MarshalAs(UnmanagedType.FunctionPtr)] HookProc lpfn, IntPtr
  11. hInstance, int threadID);//设置挂钩
  12.         [DllImport("user32.dll")]
  13.         static extern IntPtr CallNextHookEx(IntPtr handle, int code, IntPtr wparam, IntPtr lparam);//进行下一个挂钩,如果有的话
复制代码
三、定义局部变量
  1.         static IntPtr _nextHookPtr;
  2.         static HookProc myProc = new HookProc(MyHookProc);//must be global, or it will be Collected by GC, then no callback
  3. func can be used for the Hook
  4. delegate IntPtr HookProc(int code, IntPtr wparam, IntPtr lparam);
复制代码
四、自定义HookProck逻辑,这是最关键的部分,如何劫持人质,如何勒索人质,如何释放人质
  1. static IntPtr MyHookProc(int code, IntPtr wparam, IntPtr lparam)
  2.           {
  3.             IntPtr hChildWnd;// msgbox is "child"
  4.             // notification that a window is about to be activated
  5.             // window handle is wParam
  6.             if (code == 5)//HCBT_ACTIVATE = 5
  7.             {
  8.                 // set window handles of messagebox
  9.                 hChildWnd = wparam;
  10.                 //to get the text of yes button
  11.                 int result;
  12.                 if (GetDlgItem(hChildWnd, 6) != 0)//IDYES = 6
  13.                 {
  14.                     result = SetDlgItemTextA(hChildWnd, 6, Properties.Resources.YES);//在Project.Resources里自定义文本
  15.                 }
  16.                 if (GetDlgItem(hChildWnd, 7) != 0)//IDNO = 7
  17.                 {
  18.                     result = SetDlgItemTextA(hChildWnd, 7, Properties.Resources.NO);
  19.                 }
  20.             }
  21.             else
  22.             {
  23.                 CallNextHookEx(_nextHookPtr, code, wparam, lparam);// otherwise, continue with any possible chained hooks
  24.             }
  25.             //return (IntPtr)1; //直接返回了,该消息就处理结束了
  26.             return IntPtr.Zero;//返回,让后面的程序处理该消息
  27.         }
复制代码
五、提供给外部调用的Hook方法,如在Form_Load时SetHook,Form_Closing时UnHook.
  1.   public static void SetHook()
  2.         {
  3.             if (_nextHookPtr != IntPtr.Zero)//Hooked already
  4.             {
  5.                 return;
  6.             }
  7.             _nextHookPtr = SetWindowsHookEx((int)HookType.CBT, myProc, IntPtr.Zero, GetCurrentThreadId());
  8.         }
复制代码
上面的代码可以放在一个独立文件如APIHelper.cs,供User使用。
目的达到了,看代码就知道,这样不仅可以让button的文本可以根据语言改变,文本的内容也可以自定义。
事实证明抢劫的收获是诱人的,但是风险成本也是很高的

1.对于挂钩Hook技术,我们还不是很熟悉,比如什么死后SetHook(),什么时候UnHook()就是值得考虑的一个问题,你也可以在程序启动就
SetHook,也可以在进行某项操作后就SetHook,但是一定不要忘了UnHook,否则你的Hook会造成你意想不到的范围的影响。

2.回调函数要判断消息号,所有的Form在Activate的时候都是code = 5,但是我们只有在弹出MessageBox的时候设置Button的文本。所以如果我
们在启动程序的时候就SetHook(),必然会让每次消息处理多走了几段代码,虽然肉眼无法识别这些差别,但是的确不必要。
如果SetHook和UnHook的成本不高,我们可以考虑在MessageBox.Show()的地方进行挂钩和解钩。假如这样,那么如果你的程序里面散布着
MessageBox.show(),你就哭吧;TMS真是英明,把MessageBox.Show()的功能都抽取到了一个全局静态类里面,我只要改这个全局方法就可以了。
可见抽取共用逻辑还是很重要的!

结论:就让我们的程序傻傻的,傻傻要比傻B强得多。至少我们知道了,这个问题有解决方案。

回复

使用道具 举报

0

精华

940

贡献

167

赞扬

正版授权组

Rank: 14Rank: 14Rank: 14Rank: 14

帖子
237
软币
2692
在线时间
264 小时
注册时间
2013-6-17
发表于 2013-6-18 10:11:41 | 显示全部楼层
好东西,收藏了
回复

使用道具 举报

0

精华

0

贡献

15

赞扬

帖子
8
软币
223
在线时间
16 小时
注册时间
2013-6-12
发表于 2013-6-23 05:00:00 | 显示全部楼层
labor health
回复

使用道具 举报

0

精华

63

贡献

47

赞扬

帖子
101
软币
1134
在线时间
230 小时
注册时间
2013-8-27
发表于 2013-10-16 10:28:23 | 显示全部楼层
好东西...谢谢
回复

使用道具 举报

Archiver|手机版|小黑屋|开发者网 ( 苏ICP备08004430号-2 )
版权所有:南京韵文教育信息咨询有限公司

GMT+8, 2024-5-10 12:10

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表