- 积分
- 6059
- 在线时间
- 4467 小时
- 主题
- 281
- 注册时间
- 2013-6-7
- 帖子
- 1176
- 最后登录
- 2024-12-21
管理员
- 帖子
- 1176
- 软币
- 22629
- 在线时间
- 4467 小时
- 注册时间
- 2013-6-7
|
通过设置CultureUIInfo无法改变MessageBox的按钮的文本语言,因为这个文本是根据你所安装的操作系统的语言决定的:你装的英文操作系统,
那么就是"Yes""No";你装的中文操作系统,那么就是“是”“否”。
所以对于可以改变语言版本的应用程序,就会遇到英文版应用程序下的MessageBox的按钮显示“是”“否”(中文操作系统);中文版应用程序下的
MessageBox的按钮显示"Yes""No"。傻呼呼。
想达到目的,还是可以的,只是比较麻烦,要不择手段。要使用win-API函数,以及Hook技术
下面是我参照着C++代码写的C#代码
一、首先声明Hook的类型- public enum HookType
- {
- Keyboard = 2,//键盘操作
- CBT = 5,//窗口操作
- Mouse = 7, //鼠标操作
- };
复制代码 二、声明API函数- [DllImport("kernel32.dll")]
- static extern int GetCurrentThreadId();//得到当前的线程ID
- [DllImport("user32.dll")]
- static extern int GetDlgItem(IntPtr hDlg, int nIDDlgItem);//得到Dialog窗口的子项
- [DllImport("user32", EntryPoint = "SetDlgItemText")]
- static extern int SetDlgItemTextA(IntPtr hDlg, int nIDDlgItem, string lpString);//设置Dialog窗口子项的文本
- [DllImport("user32.dll")]
- static extern void UnhookWindowsHookEx(IntPtr handle);//解掉挂钩
- [DllImport("user32.dll")]
- static extern IntPtr SetWindowsHookEx(int idHook, [MarshalAs(UnmanagedType.FunctionPtr)] HookProc lpfn, IntPtr
- hInstance, int threadID);//设置挂钩
- [DllImport("user32.dll")]
- static extern IntPtr CallNextHookEx(IntPtr handle, int code, IntPtr wparam, IntPtr lparam);//进行下一个挂钩,如果有的话
复制代码 三、定义局部变量- static IntPtr _nextHookPtr;
- static HookProc myProc = new HookProc(MyHookProc);//must be global, or it will be Collected by GC, then no callback
- func can be used for the Hook
- delegate IntPtr HookProc(int code, IntPtr wparam, IntPtr lparam);
复制代码 四、自定义HookProck逻辑,这是最关键的部分,如何劫持人质,如何勒索人质,如何释放人质- static IntPtr MyHookProc(int code, IntPtr wparam, IntPtr lparam)
- {
- IntPtr hChildWnd;// msgbox is "child"
- // notification that a window is about to be activated
- // window handle is wParam
- if (code == 5)//HCBT_ACTIVATE = 5
- {
- // set window handles of messagebox
- hChildWnd = wparam;
- //to get the text of yes button
- int result;
- if (GetDlgItem(hChildWnd, 6) != 0)//IDYES = 6
- {
- result = SetDlgItemTextA(hChildWnd, 6, Properties.Resources.YES);//在Project.Resources里自定义文本
- }
- if (GetDlgItem(hChildWnd, 7) != 0)//IDNO = 7
- {
- result = SetDlgItemTextA(hChildWnd, 7, Properties.Resources.NO);
- }
- }
- else
- {
- CallNextHookEx(_nextHookPtr, code, wparam, lparam);// otherwise, continue with any possible chained hooks
- }
- //return (IntPtr)1; //直接返回了,该消息就处理结束了
- return IntPtr.Zero;//返回,让后面的程序处理该消息
- }
复制代码 五、提供给外部调用的Hook方法,如在Form_Load时SetHook,Form_Closing时UnHook.- public static void SetHook()
- {
- if (_nextHookPtr != IntPtr.Zero)//Hooked already
- {
- return;
- }
- _nextHookPtr = SetWindowsHookEx((int)HookType.CBT, myProc, IntPtr.Zero, GetCurrentThreadId());
- }
复制代码 上面的代码可以放在一个独立文件如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强得多。至少我们知道了,这个问题有解决方案。
|
|