如何获取 VBA MsgBox 的 window 句柄?
How to get the window handle for a VBA MsgBox?
我是 运行 大量 Excel 工作簿的 C# 脚本,涉及在每个工作簿中调用宏;由于错误处理程序,宏有时会生成一个 MsgBox,这会暂停脚本的执行,直到我在 MsgBox 中单击 "OK"。
MsgBox的标题文字为"Error in processSub",正文为"Error (Type Mismatch)"。
我想也许我可以有一个并发线程来查找所有当前打开的 windows,如果找到 MsgBox,则单击 "OK"。我正在尝试使用类似这样的方法找到 window:
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 window,而没有找到它的 VBA 的任何 child windows代码产生。有没有办法找到 MsgBox 并单击它的“确定”按钮?
您可以使用 winapi 函数 FindWindow 通过标题和 class 检索 window 的句柄。将以下代码添加到您的程序中:
[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
}
如果默认按钮不是 "OK",请在 ENTER 之前向 select 发送一些 TAB 键。
不要忘记为 DllImport
.
输入 using System.Runtime.InteropServices;
编辑:
对于远程桌面,试试这个本机方法:
[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
我是 运行 大量 Excel 工作簿的 C# 脚本,涉及在每个工作簿中调用宏;由于错误处理程序,宏有时会生成一个 MsgBox,这会暂停脚本的执行,直到我在 MsgBox 中单击 "OK"。
MsgBox的标题文字为"Error in processSub",正文为"Error (Type Mismatch)"。
我想也许我可以有一个并发线程来查找所有当前打开的 windows,如果找到 MsgBox,则单击 "OK"。我正在尝试使用类似这样的方法找到 window:
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 window,而没有找到它的 VBA 的任何 child windows代码产生。有没有办法找到 MsgBox 并单击它的“确定”按钮?
您可以使用 winapi 函数 FindWindow 通过标题和 class 检索 window 的句柄。将以下代码添加到您的程序中:
[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
}
如果默认按钮不是 "OK",请在 ENTER 之前向 select 发送一些 TAB 键。
不要忘记为 DllImport
.
using System.Runtime.InteropServices;
编辑: 对于远程桌面,试试这个本机方法:
[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