一、背景
在函数中需要大量调到其他模块的函数,而这些被调用的函数有些会弹出MessageBox框,这些框的标题是不一样的,而且最麻烦的是代码执行了以后需要反反复复点“确定”按钮,是否有一种方法可以自动去点这些“确定”按钮呢?这样不仅把我的手解放了,而且把我的人也解放了,我可以去干其他的事情,让程序自己点按钮去吧!
二、实现
MessageBox一旦弹出,程序会中断执行,只有点了“确定”之后程序才会继续执行,因此不能在我调用完被调函数后再关MessageBox,因为没有关闭MessageBox被调函数压根就执行不完。因此需要另外起一个线程,在弹出MessageBox后,新起的线程把它关掉。
这里使用了定时器的方法,和前人总结的差不多,下面的代码已经经过验证,可以拷贝直接使用(当然还需要加上using之类)
[DllImport("user32.dll", EntryPoint = "FindWindow", CharSet = CharSet.Auto)]
public extern static IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int PostMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
public const int WM_CLOSE = 0x10;
public static void StartKiller(string MessageBoxTitle, int TimeInterval)
{
System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
timer.Interval = TimeInterval; //延时时间
timer.Tag = MessageBoxTitle;
timer.Tick += new EventHandler(Timer_Tick);
timer.Start();
}
private static void Timer_Tick(object sender, EventArgs e)
{
KillMessageBox((string)((System.Windows.Forms.Timer)sender).Tag);
//停止计时器
((System.Windows.Forms.Timer)sender).Stop();
}
private static void KillMessageBox(string MessageBoxTitle)
{
//根据标题查找MessageBox的弹出窗口
IntPtr ptr = FindWindow(null, MessageBoxTitle);
if (ptr != IntPtr.Zero)
{
//查找到窗口则关闭
PostMessage(ptr, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
}
}
在调用的地方只需要 StartKiller("提示", 1000); 这一句话即可,其中“提示”是MessageBox的标题,1000是定时器的时长,表示1秒。
举例:
假如我想要调用的函数是:
formType.InvokeMember("BtnSave_Click", flagsInvoke, null, Obj, new object[] { a, e });
在这个函数中会弹出MessageBox框,那么我的代码需要写成这样:
StartKiller("提示", 1000);
formType.InvokeMember("BtnSave_Click", flagsInvoke, null, Obj, new object[] { a, e });
这样就完全可以了,若有可能会弹出好几个框,只需多写几句StartKiller即可,很简单吧
formType.InvokeMember("toolStripBtnSave_Click", flagsInvoke, null, formObj, new object[] { a, e });
formType.InvokeMember("toolStripBtnSave_Click", flagsInvoke, null, formObj, new object[] { a, e });
三、存在的问题
这种实现方法只能对已知的MessageBox进行关闭,若MessageBox的标题未知或没有标题是没法处理的。