Excel Interop 禁用 Msgbox 而不禁用所有 VBA

Excel Interop disable Msgbox without disabling all VBA

我正在尝试自动执行其中包含 VBA 的 excel 文件。此 VBA 受保护,因此我无法访问它。

这是我需要自动脚本执行的操作。

  1. 打开工作簿
  2. 单击/关闭任何 Msgbox 的(卡住部分)
  3. 输入一个单元格,然后让工作簿的 vba 执行此操作

所以我发现我可以使用以下方式打开这本书而不弹出窗口:

var app = new Excel.Application();
app.DisplayAlerts = false;
app.Visible = false;
app.EnableEvents = false;
app.Workbooks.Open(@"path...");

但是书中的 VBA 也被禁用了,所以我无法执行上面的第 3 步。

我怎样才能禁用所有消息框,然后在最后重新启用它们?

可以使用的技巧是:

  1. 运行 另一个线程上函数中的 Excel 代码。这是因为 Excel 可以设置很多东西来阻止执行,例如来自 Excel 的 Msgboxes 和其他对话框,如果您不控制 Excel 代码隐藏,那么您应该希望在超时的基础上中止该任务。

  2. 在您的主线程中,只需检查任务是否完成,并添加一个超时。

  3. 我将 WindowHandler 作为一个单独的 class 使用来自 user32.dll 的 winAPI 函数等来自这里的示例:Close window via SendMessage AND here: FindWindow Function Codes

    class WindowHandler {
     [DllImport("user32.dll", SetLastError = true)]
     static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
    
     // Find window by Caption only. Note you must pass IntPtr.Zero as the first parameter.
     [DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
     static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);
    
     [DllImport("user32.dll", CharSet = CharSet.Auto)]
     private static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
    
     private const UInt32 WM_CLOSE = 0x0010;
    
     public static void CloseWindow(IntPtr hwnd) {
         SendMessage(hwnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
     }
     public static IntPtr FindWindow(string windowName) {
         var hWnd = FindWindowByCaption(IntPtr.Zero, windowName);
         return hWnd;
     }
     public static void CloseMsgBox() {
         CloseWindow(FindWindow("Microsoft Excel"));
     }
    } 
    

所以现在代码执行大致如下:

// The OpenExcel Action would actually be all the Excel code encapsulated into one function to run in a separate thread
Task t = Task.Run(OpenExcel); 
// Be aware that Excel can have many different popups or VBA issues which may cause execution to stall.
TimeSpan timeLimit = new TimeSpan(0, 0, 10);  // 10 secs or acceptable time limit for Excel
DateTime startTime = DateTime.Now;
while (!t.IsCompleted) {
    if (DateTime.Now - startTime > timeLimit)
        break;  //or do other exception routine, if Excel execution is taking an unacceptable amount of time!
    WindowHandler.CloseMsgBox(); //close any Msgboxes
    Thread.Sleep(200);
}