如何获取 VBA MsgBox 的窗口句柄?
Posted
技术标签:
【中文标题】如何获取 VBA MsgBox 的窗口句柄?【英文标题】:How to get the window handle for a VBA MsgBox? 【发布时间】:2016-02-27 23:01:49 【问题描述】:我在大量 Excel 工作簿上运行 C# 脚本,其中涉及在每个工作簿中调用宏;由于错误处理程序,宏有时会产生一个 MsgBox,并且会暂停脚本的执行,直到我在 MsgBox 中单击“确定”。
MsgBox 的标题文本为“Error in processSub”,正文为“Error (Type Mismatch)”。
我想也许我可以有一个并发线程来查找所有当前打开的窗口,如果找到 MsgBox,请单击“确定”。我正在尝试使用以下方式查找窗口:
using System.Diagnostics;
public Process getErrorWindow()
Process[] processList = Process.GetProcesses();
foreach (Process process in processList)
if (process.MainWindowTitle=="Error in processSub")
return process;
但这并没有找到任何东西。当我查看processList[]
时,它似乎只找到了主 Excel 窗口,而不是其 VBA 代码生成的任何子窗口。有没有办法找到 MsgBox 并点击它的 OK 按钮?
【问题讨论】:
【参考方案1】:您可以使用 winapi 函数FindWindow 通过标题和类检索窗口句柄。将以下代码添加到您的程序中:
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetForegroundWindow(IntPtr hWnd);
public static IntPtr FindExcelErrorPopup()
return FindWindow(null, "Error in processSub");
点击按钮:
IntPtr hwnd = FindExcelErrorPopup();
if (hwnd != IntPtr.Zero)
SetForegroundWindow(hwnd); // activates the window
SendKeys.SendWait("ENTER"); // send ENTER key
如果默认按钮不是“确定”,请在 ENTER 之前发送一些 TAB 笔划以选择它。
不要忘记将using System.Runtime.InteropServices;
放入DllImport
。
编辑: 对于远程桌面,试试这个原生方法:
[DllImport("user32.dll")]
private static extern void keybd_event(Keys bVk, byte bScan, uint dwFlags, UIntPtr dwExtraInfo);
private const uint KEYEVENTF_EXTENDEDKEY = 0x0001;
private const uint KEYEVENTF_KEYUP = 0x0002;
const uint KEYEVENTF_EXTENDEDKEY = 0x0001;
const uint KEYEVENTF_KEYUP = 0x0002;
然后像这样举起钥匙:
keybd_event(Keys.Enter, 0x45, KEYEVENTF_EXTENDEDKEY, UIntPtr.Zero); // key down
keybd_event(Keys.Enter, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, UIntPtr.Zero); // key up
【讨论】:
这可以成功,但是当我在远程桌面上运行它时,SendKeys.SendInput()
会抛出一个System.ComponentModel.Win32Exception: Access is denied
。关于如何解决此问题的任何想法,因为我将在远程桌面上运行脚本,以便即使我关闭笔记本电脑也可以继续该过程?
你不能添加一个 try/catch 来捕获该错误并在不让窗口弹出任何消息框的情况下处理它吗?
如果你仍然在做整个 FindWindow 舞蹈,只需找到默认按钮并按下它。跳过注入键盘事件的困难。 (如果你坚持这样做,你应该完全使用 SendInput,而不是 keybd_event。)
我最终通过在远程机器上运行 AutoIt 脚本来解决它。以上是关于如何获取 VBA MsgBox 的窗口句柄?的主要内容,如果未能解决你的问题,请参考以下文章