【问题标题】:How to get the window handle for a VBA MsgBox?如何获取 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 按钮?

【问题讨论】:

    标签: c# vba excel windows-7


    【解决方案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 脚本来解决它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-22
    • 2011-02-26
    • 1970-01-01
    • 2020-10-22
    • 2014-01-28
    • 1970-01-01
    • 2010-11-19
    相关资源
    最近更新 更多