本文转自: http://whatsthematrix.spaces.live.com/blog/cns!52A6BFE11C08D828!158.entry
通过设置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());
}
public static void UnHook()
{
if (_nextHookPtr != IntPtr.Zero)
{
UnhookWindowsHookEx(_nextHookPtr);
_nextHookPtr = IntPtr.Zero;
}
}
上面的代码可以放在一个独立文件如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强得多。
至少我们知道了,这个问题有解决方案。