如何获取VBA MsgBox的窗口句柄?

时间:2016-02-27 23:01:50

标签: c# vba excel-vba windows-7 excel

我在大量的Excel工作簿上运行C#脚本,涉及在每个工作簿中调用一个宏;由于错误处理程序,宏有时会生成一个MsgBox,并暂停执行脚本,直到我点击" OK"在MsgBox中。

MsgBox的标题文本是" processSub"中的错误,主文本是"错误(类型不匹配)"。

我想也许我可以找到一个找到所有当前打开的窗口的并发线程,如果找到了MsgBox,点击" OK"。我试图用这样的东西找到窗口:

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并单击其确定按钮?

1 个答案:

答案 0 :(得分:2)

您可以使用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
}

如果默认按钮不是“OK”,请发送一些TAB笔划以在ENTER之前选择它。 不要忘记为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