简体   繁体   English

使用VB.Net在Internet Explorer中捕获Javascript警报

[英]Capturing Javascript Alert in Internet Explorer using VB.Net

I found a similar thread here but answer is not shared by the inquirer. 我在这里找到了一个类似的帖子但询问者不会回答这个问题。

I'm using SHDocVw.InternetExplorer APIs in my Vb.Net WinForms application to record user actions from Internet Explorer in my application. 我在我的Vb.Net WinForms应用程序中使用SHDocVw.InternetExplorer API来记录我的应用程序中来自Internet Explorer的用户操作。

  1. How do I know that a javascript alert is opened in the Internet Explorer? 我怎么知道在Internet Explorer中打开了javascript警报?
  2. How to get the text of that alert box? 如何获取该警报框的文本?

I don't want to inject any javascript. 我不想注入任何JavaScript。 Is there any way by which I can directly know about the alert opening and some way of hooking it to get its text? 有什么方法可以让我直接了解警报开放以及某种方式来获取它的文本吗?

EDIT 1: 编辑1:

WindowStateChanged event is fired when a javascript alert is opened in Internet Explorer but this event is fired in many other cases also such as opening of modal dialog window, minimize Internet Explorer etc.. 在Internet Explorer中打开javascript警报时会触发WindowStateChanged事件,但在许多其他情况下也会触发此事件,例如打开模式对话框窗口,最小化Internet Explorer等。

With below code you can auto close JavaScript alert windows, get message text or send click message to buttons on alert window. 使用以下代码,您可以自动关闭JavaScript警报窗口,获取消息文本或向警报窗口上的按钮发送单击消息。

WindowStateChanged event does not fire on JavaScript alert show (on my environment). WindowStateChanged事件不会在JavaScript警报show(在我的环境中)上触发。 if it fires, below code can be used. 如果它触发,可以使用下面的代码。

<DllImport("user32.dll", SetLastError:=True)> _
Private Shared Function GetForegroundWindow() As IntPtr
End Function

Private Sub aaxWebBrowser1_WindowStateChanged(sender As Object, e As AxSHDocVw.DWebBrowserEvents2_WindowStateChangedEvent)
    HandleJavascriptAlertwindows(GetForegroundWindow(), False)
End Sub 

or you can use ForeGroundWindowWatcher class to catch JavaScript alert windows. 或者您可以使用ForeGroundWindowWatcher类来捕获JavaScript警报窗口。 if AxWebbrowser on a form you should change Me.ParentForm.Handle to Me.Handle 如果表单上有AxWebbrowser,则应将Me.ParentForm.Handle更改为Me.Handle

Private ForeGroundWindowWatcher_ As ForeGroundWindowWatcher

Private Sub StartForeGroundWatcher()
    ForeGroundWindowWatcher_ = New ForeGroundWindowWatcher
    AddHandler ForeGroundWindowWatcher_.ForegroundWindowHasChanged, AddressOf ForeGroundWindowWatcher_ForegroundWindowHasChanged
    ForeGroundWindowWatcher_.Startt()
End Sub

Private Sub StopForeGroundWatcher()
    If ForeGroundWindowWatcher_ IsNot Nothing Then
        RemoveHandler ForeGroundWindowWatcher_.ForegroundWindowHasChanged, AddressOf ForeGroundWindowWatcher_ForegroundWindowHasChanged
        ForeGroundWindowWatcher_.Stopp()
    End If
End Sub

Private Sub btnStartForeGroundWatcher_Click(sender As System.Object, e As System.EventArgs) Handles btnStartForeGroundWatcher.Click
    'Should be called inside form_load event
    StartForeGroundWatcher()
End Sub

Private Sub btnStopForeGroundWatcher_Click(sender As System.Object, e As System.EventArgs) Handles btnStopForeGroundWatcher.Click
    'Should be called inside form_Closing event
    StopForeGroundWatcher()
End Sub

Private Sub ForeGroundWindowWatcher_ForegroundWindowHasChanged(sender As Object, ForeGroundWindowHandle As IntPtr)
    HandleJavascriptAlertwindows(ForeGroundWindowHandle, False)
End Sub

Private LastForeGroundWindowHandle As IntPtr = IntPtr.Zero

Private Sub HandleJavascriptAlertwindows(ForeGroundWindowHandle As IntPtr, preventFromShowing As Boolean)
    Try
        'source http://www.vbforums.com/showthread.php?761005-WebBrowser-Control-how-to-handle-Javascript-generated-alert-window-%28onbeforeunload%29

        'Dim hwnd = FindWindow("#32770", "Windows Internet Explorer")' this finds windows from its title.
        Dim hwnd = ForeGroundWindowHandle 'GetForegroundWindow() 'get the foreground window
        If hwnd = IntPtr.Zero Then Return

        'Get forgroundwindow cvlassname. Classname of JavaScript alert windows is "#32770"
        Dim ForeGroundWindowClassName As String = ForeGroundWindowHelper.GetClassNameFromHandle(hwnd)
        Dim MeHandle As IntPtr = Me.ParentForm.Handle 'use Me.Handle if ME is a form. 
        'Debug.WriteLine(WindowClassName)

        Dim AlertMessage As String = ""

        Debug.WriteLine("ForeGroundWindowHandle: " + ForeGroundWindowHandle.ToString)
        Debug.WriteLine("MeHandle: " + MeHandle.ToString)
        Debug.WriteLine("ForeGroundWindowClassName: " + ForeGroundWindowClassName)

        If String.CompareOrdinal("#32770", ForeGroundWindowClassName) = 0 Then

            If LastForeGroundWindowHandle <> IntPtr.Zero AndAlso LastForeGroundWindowHandle <> MeHandle Then
                'Alert might be shown another webbrowser.
                Return
            End If

            For Each ch As ForeGroundWindowHelper.WindowChildInfo In ForeGroundWindowHelper.GetChildWindows(hwnd)
                Debug.WriteLine("Text: " + ch.Text)
                Debug.WriteLine("ClassName: " + ch.ClassName)
                If ch.ClassName.ToLower = "static" Then
                    AlertMessage = ch.Text
                End If

                If preventFromShowing Then

                    'close alert by sending ESC
                    SendKeys.Send("{ESC}")

                    'or

                    ''send click event to specific button
                    'If ch.ClassName = "Button" AndAlso ch.Text = "OK" Then
                    '    ForeGroundWindowHelper.SendClickEvet2Button(ch.hWnd)
                    '    Exit For
                    'End If
                End If

            Next
        End If

        Debug.WriteLine("AlertMessage: " + AlertMessage)
        LastForeGroundWindowHandle = ForeGroundWindowHandle

    Catch ex As Exception
        Debug.WriteLine(ex.Message)
    End Try
End Sub

original source Detect active window changed using C# without polling 原始源检测活动窗口使用C#更改而不进行轮询

Imports System.Runtime.InteropServices
Imports System.Text

Public Class ForeGroundWindowWatcher
    'original source https://stackoverflow.com/questions/4372055/detect-active-window-changed-using-c-sharp-without-polling
    'Stephen Lee Parker

    Public Event ForeGroundWindowHasChanged(sender As Object, ForeGroundWindowHandle As IntPtr)
    Private dele As WinEventDelegate = Nothing

    Private Const WINEVENT_OUTOFCONTEXT As UInteger = 0
    Private Const EVENT_SYSTEM_FOREGROUND As UInteger = 3
    Private m_hhook As IntPtr = IntPtr.Zero

    Public Sub Startt()

        If m_hhook <> IntPtr.Zero Then
            Return
        End If

        dele = New WinEventDelegate(AddressOf WinEventProc)
        m_hhook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, dele, 0, 0, WINEVENT_OUTOFCONTEXT)

        If m_hhook = IntPtr.Zero Then
            Throw New Exception("SetWinEventHook failed")
        End If

    End Sub

    Public Sub Stopp()
        If m_hhook <> IntPtr.Zero Then
            UnhookWinEvent(m_hhook)
        End If
    End Sub

    Private Delegate Sub WinEventDelegate(hWinEventHook As IntPtr,
                                          eventType As UInteger,
                                          hwnd As IntPtr,
                                          idObject As Integer,
                                          idChild As Integer,
                                          dwEventThread As UInteger,
                                          dwmsEventTime As UInteger)

    <DllImport("user32.dll")> _
    Private Shared Function SetWinEventHook(eventMin As UInteger,
                                            eventMax As UInteger,
                                            hmodWinEventProc As IntPtr,
                                            lpfnWinEventProc As WinEventDelegate,
                                            idProcess As UInteger,
                                            idThread As UInteger,
                                            dwFlags As UInteger) As IntPtr
    End Function

    <DllImport("user32.dll")> _
    Private Shared Function UnhookWinEvent(hWinEventHook As IntPtr) As Boolean
    End Function

    Public Sub WinEventProc(hWinEventHook As IntPtr,
                            eventType As UInteger,
                            hwnd As IntPtr,
                            idObject As Integer,
                            idChild As Integer,
                            dwEventThread As UInteger,
                            dwmsEventTime As UInteger)

        RaiseEvent ForeGroundWindowHasChanged(Me, hwnd)

    End Sub

End Class

original source WebBrowser Control how to handle Javascript generated alert window 原始源WebBrowser控件如何处理Javascript生成的警报窗口

Imports System.Runtime.InteropServices
Imports System.Text

Public Class ForeGroundWindowHelper
    'source http://www.vbforums.com/showthread.php?761005-WebBrowser-Control-how-to-handle-Javascript-generated-alert-window-%28onbeforeunload%29
    'by AgustinTRC

    Public Class WindowChildInfo
        Public hWnd As IntPtr
        Public ClassName As String
        Public Text As String
        Public Sub New(hwnd As IntPtr, clsname As String, text As String)
            Me.hWnd = hwnd
            Me.ClassName = clsname
            Me.Text = text
        End Sub
    End Class

    Private Const BM_CLICK As Integer = &HF5
    Private Const WM_ACTIVATE As Integer = &H6
    Private Const WA_ACTIVE As Integer = 1

    <DllImport("user32.dll", CharSet:=CharSet.Auto, EntryPoint:="FindWindow")> _
    Private Shared Function FindWindow(ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr
    End Function

    <DllImport("user32.dll", EntryPoint:="SendMessage")> _
    Private Shared Function SendMessage(hwnd As IntPtr, wMsg As Integer, wParam As Integer, lParam As Integer) As IntPtr
    End Function

    ' private...
    <DllImport("user32.dll", CharSet:=CharSet.Auto)> _
    Private Shared Sub GetClassName(ByVal hWnd As System.IntPtr, ByVal lpClassName As StringBuilder, ByVal nMaxCount As Integer)
    End Sub

    <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
    Private Shared Function GetWindowText(ByVal hwnd As IntPtr, ByVal lpString As StringBuilder, ByVal cch As Integer) As Integer
    End Function

    <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
    Private Shared Function GetWindowTextLength(ByVal hwnd As IntPtr) As Integer
    End Function


    Private Delegate Function EnumCallBackDelegate(ByVal hwnd As IntPtr, ByVal lParam As IntPtr) As Integer
    Private Declare Function EnumChildWindows Lib "user32" (ByVal hWndParent As IntPtr, ByVal lpEnumFunc As EnumCallBackDelegate, ByVal lParam As IntPtr) As IntPtr


    Private Shared children As List(Of WindowChildInfo)
    Public Shared Function GetChildWindows(ByVal hwnd As IntPtr) As List(Of WindowChildInfo)
        children = New List(Of WindowChildInfo)
        EnumChildWindows(hwnd, AddressOf EnumProc, Nothing)
        Return children
    End Function

    Private Shared Function EnumProc(ByVal hwnd As IntPtr, ByVal lParam As IntPtr) As Int32
        If hwnd <> IntPtr.Zero Then
            children.Add(New WindowChildInfo(hwnd, GetClassNameFromHandle(hwnd), GetText(hwnd)))
        End If
        Return 1
    End Function

    Public Shared Function GetClassNameFromHandle(ByVal hWnd As IntPtr) As String
        Dim sbClassName As New StringBuilder("", 256)
        Call GetClassName(hWnd, sbClassName, 256)
        Return sbClassName.ToString
    End Function

    Private Shared Function GetText(ByVal hWnd As IntPtr) As String
        Dim length As Integer = GetWindowTextLength(hWnd)
        If length = 0 Then Return ""
        Dim sb As New StringBuilder("", length + 1)
        GetWindowText(hWnd, sb, sb.Capacity)
        Return sb.ToString()
    End Function

    Public Shared Sub SendClickEvet2Button(ByVal hWnd As IntPtr)
        ' activate the button
        SendMessage(hWnd, WM_ACTIVATE, WA_ACTIVE, 0)
        ' send button a click message
        SendMessage(hWnd, BM_CLICK, 0, 0)
    End Sub

End Class

inject javascript. 注入javascript。

(function(w){
  w.____oldAlert = w.alert;
  w.alert = function(msg){
    console.log("alert(", msg, ");");
    var result = w.____oldAlert(msg);
    console.log("returned ", result);
    return result;
  };
})(window);

similar code can be applied to confirm and prompt so you do not have to depend on many hacks, can possibly read return values. 类似的代码可以应用于confirmprompt因此您不必依赖许多黑客,可能会读取返回值。 If one day IE decides to change the way it shows the dialogs like Chrome did, your code will still be working 如果有一天IE决定改变它显示像Chrome这样的对话框的方式,那么你的代码仍然有效

I think that if you look at the top answer to this question , you will find what you are looking for. 我想如果你看看这个问题的最佳答案,你会发现你在寻找什么。 The code there is in C, but the responder indicates that all of the necessary information is there. 代码存在于C中,但响应者指出所有必要的信息都在那里。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM