[转]动态改变MessageBox的按钮文本的语言
2010-11-24 10:05
246 查看
本文转自: 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强得多。
至少我们知道了,这个问题有解决方案。
通过设置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强得多。
至少我们知道了,这个问题有解决方案。
相关文章推荐
- 动态改变MessageBox的按钮文本的语言
- 杂记之使用代码动态的改变文本、按钮的颜色
- DataGridViewButtonColumn的使用 — 动态改变按钮的文本
- C# DataGridViewButtonColumn的使用—动态改变按钮的文本
- 动态改变工具栏按钮图标及工具提示文本
- DataGridViewButtonColumn的使用 — 动态改变按钮的文本
- 动态改变富文本字体的颜色
- dskinlite(uieasy mfc界面库)使用记录2:绘制动态元素(按钮控件绘制元素动态控制,改变图片和文字)
- android 文本输入框文字改变监听-输入值显示,没有值删除按钮消失
- 5.4 蓝图可以改变吗? ——动态语言
- 易语言单击按钮后向编辑框中加入指定文本的方法
- 点击按钮动态的显示适当的文本
- flash中怎么制作一个按钮,当鼠标移上去就会显示文字(动态文本)?
- Javascript动态改变按钮样式
- JS动态改变文本中光标位置
- (原创)代码动态改变某些textview文本颜色及其大小的方式
- 如何使STATIC控件的背景透明以及动态改变控件文本内容时闪烁的问题
- 根据文本动态改变labelframe
- ABAP 根据按钮动态显示/改变屏幕
- 通过javascript动态改变按钮的值