如何获取 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