VB.NET WebBrowser dialog popup automatic handling

A recent site visitor had a fairly simple requirement which involved crawling a specific web page and clicking a button. Pretty basic stuff. And then it happened… clicking that button produced a javascript “confirm()” dialog with OK and Cancel buttons. “Well this won’t be easy” I thought to myself. Just to ensure there wouldn’t be any other surprises, I continued along through the entire “manual” version of the process, and lo and behold, ANOTHER javascript dialog box, this time with “Yes” & “No” buttons! Not wanting to let my visitor down (and more so not to be defeated by javascript!), I set to work…

Now, I’m no fan of re-inventing the wheel, nor am I a fan of using “3rd party code”, but knowing that the solution would involve a lot of API work, I knew someone has probably come up with something that could save me some time with this. I found various pieces of code online that used some of the API’s that would be needed. I have consolidated this work into a reusable Class that can be used in any project where automatic handling of WebBrowser dialog popups is needed.

The DialogHandler Class:

Imports System.Runtime.InteropServices

Public Class DialogHandler
    'API CONSTANTS
    Const WM_GETTEXT As Long = &HD
    Const WM_GETTEXTLENGTH As Long = &HE
    Const GW_ENABLEDPOPUP As Long = 6
    Const BM_CLICK As Long = &HF5&
    Const GW_CHILD As Long = 5
    Const GW_HWNDNEXT As Long = 2

    'FINDS CHILD WINDOWS
    Private Declare Auto Function GetWindow Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal uCmd As Integer) As IntPtr

    'SEND MESSAGES TO THE BUTTON
    Private Declare Auto Function SendMessage Lib "user32.dll" Alias "SendMessage" (ByVal hWnd As IntPtr, ByVal Msg As Integer, _
    ByVal wParam As Integer, ByRef lParam As IntPtr) As IntPtr

    'GETS WINDOW TEXT
    Private Declare Auto Function SendMessageA Lib "user32.dll" Alias "SendMessageA" (ByVal hWnd As IntPtr, ByVal Msg As Integer, _
    ByVal wParam As IntPtr, ByRef lParam As IntPtr) As IntPtr
    <DllImport("User32.dll", CharSet:=CharSet.Auto, Entrypoint:="SendMessage")> Public Shared Function SendMessageString(ByVal hwnd As IntPtr, _
    ByVal wMsg As Integer, ByVal wparam As Integer, ByVal lparam As System.Text.StringBuilder) As IntPtr
    End Function

    Private Function GetChildWindowHandles(ByVal ParentWindowHandle As IntPtr) As ArrayList

        Dim ptrChild As IntPtr
        Dim clsRet As New ArrayList

        'GET FIRST CHILD HANDLE
        ptrChild = GetChildWindowHandle(ParentWindowHandle)

        Do Until ptrChild.Equals(IntPtr.Zero)
            'ADD TO COLLECTION OF HANDLES
            clsRet.Add(ptrChild)
            'GET NEXT CHILD
            ptrChild = GetNextWindowHandle(ptrChild)
        Loop

        Return clsRet

    End Function

    Private Function GetChildWindowHandle(ByVal ParentWindowHandle As IntPtr) As IntPtr
        Return GetWindow(ParentWindowHandle, GW_CHILD)
    End Function

    Private Function GetNextWindowHandle(ByVal CurrentWindowhandle As IntPtr) As IntPtr
        Return GetWindow(CurrentWindowhandle, GW_HWNDNEXT)
    End Function

    'RETURNS TEXT OF THE WINDOW FOR CONFIRMATION OF CORRECT DIALOG
    Private Function GetWindowText(ByVal WindowHandle As IntPtr) As String

        Dim ptrRet As IntPtr
        Dim ptrLength As IntPtr

        'LENGTH OF BUFFER
        ptrLength = SendMessageA(WindowHandle, WM_GETTEXTLENGTH, IntPtr.Zero, IntPtr.Zero)

        'BUFFER NEEDED FOR RETURN VALUE
        Dim sb As New System.Text.StringBuilder(ptrLength.ToInt32 + 1)

        'WINDOW TEXT
        ptrRet = SendMessageString(WindowHandle, WM_GETTEXT, ptrLength.ToInt32 + 1, sb)

        Return sb.ToString

    End Function

    'SEND A 'CLICK' TO THE BUTTON ("WINDOW")
    Private Sub PerformClick(ByVal WindowHandle As IntPtr)
        SendMessage(WindowHandle, BM_CLICK, 0, IntPtr.Zero)
    End Sub

    Public Sub LookForAndCloseIEPopup(ByVal whichButton As String)

        'GET HANDLE OF ANY POPUP WINDOW ASSOCIATED WITH MAIN FORM
        Dim ptrDialogWindow As IntPtr = GetWindow(Process.GetCurrentProcess.MainWindowHandle, GW_ENABLEDPOPUP)

        'IF IT'S A BROWSER POPUP, HANDLE IT
        If GetWindowText(ptrDialogWindow) = "Microsoft Internet Explorer" Or GetWindowText(ptrDialogWindow) = "Message from webpage" Or GetWindowText(ptrDialogWindow) = "Windows Internet Explorer" Then
            ClosePopup(ptrDialogWindow, whichButton)
        End If

    End Sub

    Private Sub ClosePopup(ByVal WindowHandle As IntPtr, ByVal whichButton As String)

        Dim clsChildHandles As ArrayList = GetChildWindowHandles(WindowHandle)

        For Each ptrHandle As IntPtr In clsChildHandles
            'IF IT FINDS A BUTTON WITH THE TEXT SPECIFIED, CLICK IT
            If GetWindowText(ptrHandle).Contains(whichButton) Then PerformClick(ptrHandle) : Exit For
        Next

    End Sub
End Class

To use the Class in your application, simply use:

Dim dh As New DialogHandler
dh.LookForAndCloseIEPopup("OK") 'This single parameter is the text of the button you want to click (case insensitive)

This should handle any dialog popups that should appear during the course of any scraping/automating you may encounter. In my visitor’s case, I simply added that call to a Timer that was started on Form Load. This timer periodically “checked” for dialog popups and handled them accordingly. No user intervention required!

So, if you find yourself faced with nagging WebBrowser dialog popups and need a way to automate clicking the OK, Cancel, Yes, or No nuttons, you can use the DialogHandler Class above to take care of it.

Comments Welcome.

Download DialogHandler Class Download DialogHandler Class
Like it? Share it:

25 thoughts on “VB.NET WebBrowser dialog popup automatic handling

  1. Steve Post author

    I’m sure it could with some tweaking. What tweaks are needed, I’m not sure as I didn’t do much with VB6, but I believe there are VB6 -> .NET converters online. Or, a good place to post for help in the conversion is http://www.vbforums.com.

    Thanks
    Steve

    Reply
  2. Fp

    I can not get the popup message handeled by the class you gave.

    i have added a timer and set its intreval to 100.

    i get a popup “Are you sure you want to exit this page” and it has two options Leave this page and Stay on the page

    Can you please help me for this?

    Reply
  3. Steve Post author

    Hi Fp, you’d have to post the code you’re using in order for me to assist. I have to see how you’re using it. Also, an interval of “100″ is pretty low. Also, is this with a WebBrowser Control on your form or are you automating an open Browser external to your application?

    Reply
  4. Rit Man

    the way i used to deal with aol popups was to use a window spy program to get the class of the popup(not in your program, get it ahead of time), then use the api call findwindowbyclass to get the handle of that window and send a wm_close message through the sendmessage api call.

    vb comes with some tools for spying on windows, i THINK its called spy++. i reread steves post and you might need to send a close message to the ok button, or if the bm_click is not working, try sending a left button click to the button handle.

    the interval on the timer is 1000 = 1 second, so you probably dont want to be running that code 10 times per second unless you get trapped in a pron popup frenzy

    Reply
  5. Fp

    Hi,

    I have a WebBrowser Control on my form, i navigate it to a website, but that website has some code which verifies that are you sure you want to leave this page or stay on the page.

    So other are two buttons on the popup, i copied your code and made a class of same name, initialized a new instance dh of that class.

    And then in timmer i used the code to call it after 100 ms
    dh.LookForAndCloseIEPopup(“Leave this page”)

    I am also uploading the error
    http://img189.imageshack.us/img189/7716/20111001173922.png

    Hope you have some solution for this.

    Thanks

    Reply
  6. Steve Post author

    Hey Fp,
    I can’t get the imageshack link to load. Where are you enabling the timer? If you’re able to post a large amount of the code, specifically the enabling of the timer and the documentCompleted event of the browser, it would help.

    Rit,
    That is what I call the “old school” way of doing it. While it definitely works, it’s not dynamic enough for my liking. This class will handle ANY popups, regardless of count, which is sometimes needed when scraping as you may not always know the “course of events” ahead of time or at runtime they may change.

    Thanks for reading.

    Reply
  7. Fp

    So you mean, i should execute the code when i assume the popup would be there, and how can i make sure if the code is working or not?

    Thanks

    Reply
  8. Steve Post author

    What I do is enable the timer in my Form’s load event that way I know it’s always running (I don’t always know when a popup will occur). You could also start your timer directly before your WebBrowser1.Navigate() lines so that it’s already checking before it navigates. To know if the code is working, you should see the popup for a split second and then it should disappear. If you really wanted to see it working, you could modify the Class to put a “Stop” on this line:

    ClosePopup(ptrDialogWindow, whichButton)

    If it stops on that line, that means it’s attempting to close a popup and you can then Step through to the next line with F8.

    If you DON’T see a stop on that line and you’re staring at a popup, ensure it’s meeting one of these criteria:

    If GetWindowText(ptrDialogWindow) = “Microsoft Internet Explorer” Or GetWindowText(ptrDialogWindow) = “Message from webpage” Or GetWindowText(ptrDialogWindow) = “Windows Internet Explorer”

    Reply
  9. Fp

    I applied stop on the line
    If GetWindowText(ptrDialogWindow) = “Microsoft Internet Explorer” Or GetWindowText(ptrDialogWindow) = “Message from webpage” Or GetWindowText(ptrDialogWindow) = “Windows Internet Explorer”

    but when i saw its value it shows 0, where as the title of the window is Windows Internet Explorer

    any clues?

    Reply
  10. Steve Post author

    If you put a stop directly on that line, it may not show the value until you step through at least one line after.

    Also you could add an “Else” clause to that If condition that says:

    If GetWindowText(ptrDialogWindow) = “Microsoft Internet Explorer” Or GetWindowText(ptrDialogWindow) = “Message from webpage” Or GetWindowText(ptrDialogWindow) = “Windows Internet Explorer”
    ‘Close Popup
    Else
    MsgBox(GetWindowText(ptrDialogWindow))
    End if

    That will show you what the Window Title says at the time of the test. You might even try changing the condition statement to:

    If GetWindowText(ptrDialogWindow).ToString.Contains(“Microsoft Internet Explorer”) Or GetWindowText(ptrDialogWindow).ToString.Contains(“Message from webpage”) Or GetWindowText(ptrDialogWindow).ToString.Contains(“Windows Internet Explorer”)

    Reply
  11. Steve Post author

    Do you get multiple Message boxes? What is the interval of your timer?

    If you put a stop on the line after:
    Dim ptrDialogWindow As IntPtr = GetWindow(Process.GetCurrentProcess.MainWindowHandle, GW_ENABLEDPOPUP)

    What is the “ptrDialogWindow” value?

    Reply
  12. Fp

    Interval is 10 sec, yes i get multiple windows after every 10 sec, all of them are blank

    I put the stop on If GetWindowText(ptrDialogWindow) = “Microsoft Internet Explorer” Or GetWindowText(ptrDialogWindow) = “Message from webpage” Or GetWindowText(ptrDialogWindow) = “Windows Internet Explorer” Then

    which is after the line you mentioned, and there the value is ptrDialogWindow 0 System.IntPtr

    Reply
  13. Steve Post author

    Is it possible for you to send me your project? I’ve been swamped lately with other projects and this one is a bit difficult to help with without seeing it running. To me, it sounds like it’s not meeting any of the conditons (the window text) so the value is staying at 0. You might try adding a condition that says:

    If GetWindowText(ptrDialogWindow) = “Microsoft Internet Explorer” Or GetWindowText(ptrDialogWindow) = “Message from webpage” Or GetWindowText(ptrDialogWindow) = “Windows Internet Explorer” Or GetWindowText(ptrDialogWindow) = “”

    Reply
  14. ESSOO

    thanx for this wonderful class it works like a charm for me but i had to change this
    p.handle TO p.MainWindowHandle And it’s not Case insensitive i had to change “ok” To “OK”

    thnx a lot

    Reply
  15. siteper

    Hi,
    thank you for your help and tutorial.
    I’m a nobby and I tried your code but in visual basic 2008 it give me errors on this strings
    = &HD
    = &HE
    = &HF5&
    How can I write them on corret form?
    thank you

    Reply
    1. Allen

      the (ampersand) is probably getting changed to (ampersand)amp; when you copy it off this website.
      delete the “amp;” portion from the problmatic lines and you should be OK.

      Reply
    2. Allen

      Or, you can just click the “Download DialogHandler Class” button instead of trying to copy/paste the code off the website. That should avoid the & issue completely.

      (I copied and pasterd the code, and after i fixed the ampersands, it worked great!)

      Reply
      1. Steve Post author

        Appreciate the feedback! Glad it’s working for you. Great catch on the ampersand thing as well. Definitely want to download the Class file as opposed to copy/paste. Bad mojo could happen with odd stuff like that.

        Reply
  16. Rit Man

    i always re-read this thread when a new msg comes in(to clarify my context)… heres 2 more cents: first the popup window could have extra text so you might check the text of the window title by doing: if windowText = left(popupWindowHandle, numCharsOfSearchText) – i was winging it there so just try to get the concept and code it correctly… or I was thinking that ANY other window is unwanted so send a WM_CLOSE window message to the ptrDialogWindow handle. dont forget to declare the constant for WM_CLOSE. happy botting to all :)

    Reply
  17. Sandy

    I tried you code but it is not working. Please let me know how can I get this working. I also have the same case like Fp. When I debug the code I found that

    Dim ptrDialogWindow As IntPtr = GetWindow(p.Handle, GW_ENABLEDPOPUP)

    After this file value of ptrDialogWindow was 0 and I think this where it is going wrong. Please check and let me know if you can help me in this.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Notify me of follow-up comments via e-mail. You can also subscribe without commenting.