【问题标题】:How to automate response to msgbox如何自动响应 msgbox
【发布时间】:2010-04-17 19:31:33
【问题描述】:

我正在开发一个 C# 应用程序来自动运行调用多个 VB6 .exe 文件的旧版 VBScript(vbs) 文件。 .exe 文件具有我需要“响应”的消息框弹出窗口,以允许 VBScript 进程在无人值守的情况下运行。响应需要是 Enter 键。我没有 .exe 文件的来源,也不知道它们的确切用途。 我将不胜感激任何帮助...

【问题讨论】:

    标签: c# vb6 vbscript msgbox


    【解决方案1】:

    您可能会发现AutoIt 很有帮助。

    AutoIt v3 是一款类似 BASIC 的免费软件 脚本语言专为 自动化 Windows GUI 和一般 脚本。它使用了一个组合 模拟击键,鼠标移动 和窗口/控件操作 为了以某种方式自动化任务 可能或可靠与其他 语言(例如 VBScript 和 发送密钥)。

    您可以仅使用 AutoIt 编程语言开发一些东西,也可以从您自己的应用程序中驱动它。我的团队正在使用它,并取得了很好的成功。

    【讨论】:

    • 看起来可行,但不幸的是,我不能在没有经过企业 IT 审批流程的情况下在此客户端引入任何第三方应用程序...
    【解决方案2】:

    您可以使用 wsh SendKeys() 函数。但是,由于您需要确保消息框已激活,因此您还需要在 SendKeys 调用之前立即调用 AppActivate()。

    即使这有问题,但我已经编写了几个脚本来执行此操作,只要您可以预测消息框何时出现,您就可以发送 [Enter] 键来响应它。

    【讨论】:

      【解决方案3】:

      您可以在 C# 中执行此操作,而无需一些外部实用程序。诀窍是搜索消息框对话框并单击其确定按钮。多次执行此操作需要一个计时器,该计时器不断搜索此类对话框并单击它。向您的项目添加一个新类并粘贴此代码:

      using System;
      using System.Text;
      using System.Windows.Forms;
      using System.Runtime.InteropServices;
      
      class MessageBoxClicker : IDisposable {
        private Timer mTimer;
      
        public MessageBoxClicker() {
          mTimer = new Timer();
          mTimer.Interval = 50;
          mTimer.Enabled = true;
          mTimer.Tick += new EventHandler(findDialog);
        }
      
        private void findDialog(object sender, EventArgs e) {
          // Enumerate windows to find the message box
          EnumThreadWndProc callback = new EnumThreadWndProc(checkWindow);
          EnumThreadWindows(GetCurrentThreadId(), callback, IntPtr.Zero);
          GC.KeepAlive(callback);
        }
      
        private bool checkWindow(IntPtr hWnd, IntPtr lp) {
          // Checks if <hWnd> is a dialog
          StringBuilder sb = new StringBuilder(260);
          GetClassName(hWnd, sb, sb.Capacity);
          if (sb.ToString() != "#32770") return true;
          // Got it, send the BN_CLICKED message for the OK button
          SendMessage(hWnd, WM_COMMAND, (IntPtr)IDC_OK, IntPtr.Zero);
          // Done
          return false;
        }
      
        public void Dispose() {
          mTimer.Enabled = false;
        }
      
        // P/Invoke declarations
        private const int WM_COMMAND = 0x111;
        private const int IDC_OK = 2;
        private delegate bool EnumThreadWndProc(IntPtr hWnd, IntPtr lp);
        [DllImport("user32.dll")]
        private static extern bool EnumThreadWindows(int tid, EnumThreadWndProc callback, IntPtr lp);
        [DllImport("kernel32.dll")]
        private static extern int GetCurrentThreadId();
        [DllImport("user32.dll")]
        private static extern int GetClassName(IntPtr hWnd, StringBuilder buffer, int buflen);
        [DllImport("user32.dll")]
        private static extern IntPtr GetDlgItem(IntPtr hWnd, int item);
        [DllImport("user32.dll")]
        private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
      }
      

      示例用法:

      private void button1_Click(object sender, EventArgs e) {
        using (new MessageBoxClicker()) {
          MessageBox.Show("gonzo");
        }
      }
      

      【讨论】:

      • 这是我试图做的事情,但当消息框由另一个进程生成时,我无法让它工作。
      • 对,对其他EXE无效。除非你能得到那个EXE的主线程ID,Process.Threads和ProcessThread.Id
      【解决方案4】:

      可能想看看使用,

      SetWinEventHook PInvoke
      

      检测何时创建对话框。您可以将挂钩指定为全局或特定进程。您可以设置WINEVENT_OUTOFCONTEXT 标志以确保您的代码实际上并未在您要挂接的进程中运行。您要查找的事件应该是EVENT_SYSTEM_DIALOGSTART。

      一旦获得对话框的 hwnd(来自事件挂钩),您可以使用 SendMesssage 和 WM_COMMAND 或 WM_SYSCOMMAND 来摆脱它。

      【讨论】:

        【解决方案5】:

        在过去 2 天试图让这个工作正常后,我最终放弃并决定采用另一种方法。我正在询问发送到外部进程的数据并筛选导致消息框弹出的条件。 感谢所有回答问题的人!

        【讨论】:

        • 这可能是一种更好、更健壮的方法。
        【解决方案6】:

        使用 sendkey 方法,传递键盘键值并继续执行。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-09-24
          相关资源
          最近更新 更多