Click here to Skip to main content
Click here to Skip to main content

Auto Click Button on HTML Popup Window

, 11 Feb 2013
Rate this:
Please Sign up or sign in to vote.
This article provides a practical solution to clicking the button on a popup window.

Introduction

Do you have a process that watches an HTML page? Are you writing a test harness? Do you sometimes get a popup which brings your process to a halt? If so then this article will hopefully provide you a way of automatically clicking the button on the popup dialog box.

Background

I'm writing a test harness for work to test some old Classic ASP pages. Yes, I know there are testing frameworks out there but I have some very specific requirements and I kept running into problem after problem. I created a hack test project to identify problems and find solutions. While doing that, I found that I had a problem automatically clicking a popup button.  After Googling for awhile, I found that others were having the same problem when using the WPF WebBrowser and no solution was available. So, I posted a question to the Microsoft WPF Forum for help with the WebBrowser control.

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.

Within a few hours, the forum admin responded with

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.

No, I frankly don't understand how a HTML page was rendered is relevant to making a WPF WebBrowser control work.

Off Googling again I go. I found an obscure posting by someone saying maybe you can get the handle of the window and do something. In case "getting the handle of a window" doesn't mean anything to you, you're in for a treat, P/Invoke. This article is not going to describe P/Invoke as it is a topic unto itself, but rather provide you with a working example of how to click the button using the P/Invoke methodology.

A site that contains good information on P/Invoke is PINVOKE .NET

Using the code

The following class is at the heart of the solution. The sample project included has some additional classes to make the implementation a little easier.

This class will find a window by its title. This doesn't necessarily mean a JavaScript or VBScript window. It could be used to find an instance of NotePad.exe running but would have to be modified to be of use. There are better ways to get to a running application and as executables fall outside of the scope of this article, I will limit the remainder of the article to the HTML script languages.

In the SearchForWindow method you will see code for FindWindow and FindWindowByCaption. They are basically the same thing. Using either method will work.

If your requirements mandate that you find specific text on the popup, you will have to look for other P/Invoke options to make that work.

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();
      }
   }
}

One thing to note is that this code will have to be run on another thread. You ask...Why? Because, once the script window is popped up, the UI Thread is blocking until the button is pushed which kind of defeats the purpose of this class. So, make sure you are on another thread.

As a final note, the sample application is setup to allow the popup to be displayed for a period of time (5 seconds) before the button is clicked. You will want to fix this when using the code in your project. See the note in the constructor of ClickButtonTask.

Running the sample application

Compile and start the application. It will start the application and load a sample HTML page. If you get the security banner shown below, you will have to click the "Allow Blocked Content..." option. If you don't then JavaScript and VB Script will not run. After that security nag, you get another one asking if you are sure... Click "Yes".

To test, click on one of the WPF buttons at the top of the screen (red box). This will create a task that will look for a popup. Next click on the corresponding HTML button below (blue box) to create the popup window. You will note that the window goes away once the button is "pushed" from the code running in the task.

The HTML confirm button will pop up another window. You will have to manually click the button for the box to go away. I did this to show that the script will continue after the button is pushed.

History

None.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Dave Elliott
Software Developer (Senior) Webbert Solutions
United States United States
Dave is an independent consultant working in a variety of industries utilizing Microsoft .NET technologies.

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Mobile
Web03 | 2.8.140721.1 | Last Updated 11 Feb 2013
Article Copyright 2013 by Dave Elliott
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid