65.9K
CodeProject 正在变化。 阅读更多。
Home

自动单击 HTML 弹出窗口中的按钮

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (4投票s)

2013年2月11日

CPOL

4分钟阅读

viewsIcon

34770

downloadIcon

781

本文提供了一种实用的解决方案,用于点击弹出窗口上的按钮。

引言

你是否有一个监控 HTML 页面的进程?你是否正在编写一个测试工具?你是否偶尔会遇到一个弹出窗口,导致你的进程停止?如果是这样,那么本文希望能为你提供一种自动点击弹出对话框上的按钮的方法。

背景

我正在为工作编写一个测试工具,以测试一些旧的 Classic ASP 页面。是的,我知道有很多测试框架,但我有一些非常具体的要求,并且我一直遇到一个又一个问题。我创建了一个 hack 测试项目来识别问题并找到解决方案。在这样做的时候,我发现我有一个问题,即自动点击一个弹出按钮。在 Google 上搜索了一段时间后,我发现其他人在使用 WPF WebBrowser 时也遇到了同样的问题,并且没有可用的解决方案。所以,我在 Microsoft WPF 论坛上发帖,寻求关于 WebBrowser 控件的帮助。

Title: WebBrowser - How to click button on javascript confirm popup 

I'm writing a test harness for an older classic ASP application that we have. 
Some of the pages have JavaScript confirm dialog boxes like the following 
    var answer = confirm('Are you sure you want to delete the record.\n\nOK – proceed with delete Cancel – no change');
I would like to be able to click on the "OK" or "Cancel" button from my C# test harness application if possible. 
This will allow for the rest of the code to be tested. 
Any thoughts on how to fix this problem is appreciated and no I can't rewrite the classic ASP application.

在几个小时内,论坛管理员回复说

Classic ASP application is a very old product which is out of the support scope of this forum.
We will move this thread to Off-topic forum. Thank you for your understanding.

坦率地说,我不明白 HTML 页面是如何呈现的与使 WPF WebBrowser 控件工作有什么关系。

我再次开始了 Google 搜索。我发现有人发表了一篇晦涩的帖子,说也许你可以获得窗口的句柄并做一些事情。万一“获取窗口的句柄”对你来说没有任何意义,那么你将会得到惊喜,P/Invoke。本文不会描述 P/Invoke,因为它本身就是一个主题,而是为你提供一个使用 P/Invoke 方法点击按钮的工作示例。

一个包含 P/Invoke 良好信息的网站是 PINVOKE .NET

使用代码

以下类是解决方案的核心。包含的示例项目有一些额外的类,使实现更容易一些。

这个类将通过标题找到一个窗口。这不一定意味着 JavaScript 或 VBScript 窗口。它可以用来查找 NotePad.exe 的运行实例,但必须进行修改才能使用。有更好的方法来访问正在运行的应用程序,并且由于可执行文件不在本文的范围内,我将把本文的其余部分限制在 HTML 脚本语言上。

SearchForWindow 方法中,你将看到 FindWindowFindWindowByCaption 的代码。它们基本上是同一件事。使用任何一种方法都可以。

如果你的要求规定你必须找到弹出窗口上的特定文本,你将不得不寻找其他 P/Invoke 选项来实现这一点。

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace AutoClickPopup
{
   public class Popup
   {
      #region Constants

      const int BM_CLICK = 0x00F5;

      #endregion

      #region P/Invoke Methods

      // Example: FindWindow((string)null, windowName)
      [DllImport("user32.dll", SetLastError = true)]
      static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

      // You must pass IntPtr.Zero as the first parameter.
      [DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
      static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);

      // Use to find controls on the popup window
      [DllImport("user32.dll", SetLastError = true)]
      static extern IntPtr FindWindowEx(IntPtr parentHandle, 
        IntPtr childAfter, string className, string windowTitle);

      // Send a Message to a control
      [DllImport("user32.dll", CharSet = CharSet.Auto)]
      static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);

      #endregion

      private readonly string _windowTitle;
      private IntPtr _window;

      /// <summary />
      /// 
      /// </summary />
      /// <param name="windowTitle" /></param />
      public Popup(string windowTitle)
      {
         _windowTitle = windowTitle;
      }

      /// <summary />
      /// Indicates if the windows was successfully found and is usable
      /// </summary />
      public bool IsFound { get { return _window != IntPtr.Zero; } }


      /// <summary />
      /// Try and find the window by the window title
      /// </summary />
      /// <returns />If the window was found</returns />
      public bool SearchForWindow()
      {
         try
         {
            _window = FindWindow(null, _windowTitle);
            //_window = FindWindowByCaption(IntPtr.Zero, _windowTitle);
         }
         catch
         {
            // Ignore Exceptions
         }

         return IsFound;
      }


      /// <summary />
      /// Click a button on the windows
      /// </summary />
      /// <param name="buttonText" />Text of the button</param />
      public void ClickButton(string buttonText)
      {
         try
         {
            IntPtr btn = FindWindowEx(_window, IntPtr.Zero, "Button", buttonText);
            if (btn != IntPtr.Zero)
            {
               IntPtr rc = SendMessage(btn, BM_CLICK, IntPtr.Zero, IntPtr.Zero);
               BreakOnError(rc);
            }
         }
         catch
         {
            // Ignore Exceptions
         }
      }

      [Conditional("DEBUG")]
      public void BreakOnError(IntPtr code)
      {
         if (code != IntPtr.Zero)
            Debugger.Break();
      }
   }
}

需要注意的一点是,这段代码必须在另一个线程上运行。你可能会问...为什么?因为,一旦脚本窗口弹出,UI 线程就会阻塞,直到按钮被按下,这有点违背了这个类的目的。所以,确保你在另一个线程上。

最后,示例应用程序被设置为允许弹出窗口显示一段时间(5 秒),然后才点击按钮。在使用你项目中的代码时,你会想要修复这个问题。请参阅 ClickButtonTask 构造函数中的注释。

运行示例应用程序

编译并启动应用程序。它将启动应用程序并加载一个示例 HTML 页面。如果你看到下面显示的安全横幅,你将必须点击“允许阻止的内容...”选项。如果你不这样做,JavaScript 和 VB Script 将不会运行。在那个安全提示之后,你还会收到另一个提示,询问你是否确定...点击“是”。

要进行测试,请点击屏幕顶部的其中一个 WPF 按钮(红色框)。这将创建一个任务,该任务将查找一个弹出窗口。接下来,点击下面对应的 HTML 按钮(蓝色框)来创建弹出窗口。你会注意到,一旦按钮被任务中运行的代码“按下”,窗口就会消失。

HTML 确认按钮将弹出另一个窗口。你必须手动点击按钮才能使该框消失。我这样做是为了表明在按钮被按下后,脚本将继续运行。

历史

无。

© . All rights reserved.