Sign in to follow this  
Followers 0
wisheu

Problem with event BeforeNavigate2 of Shell.Explorer.2

9 posts in this topic

Hi,

I'm trying to catch the BeforeNavigate2 event of the Shell.Explorer.2 control. I've managed to catch other events of this control, but when I try to catch this one, then the script crashes, when I try to navigate.

The Shell.Explorer.2 control is very similiar to the InternetExplorer.Application control, but has the abillity to embed this control in an AutoIt GUI. (Which works very good... ;-))

This is the code for creating the control in the GUI and to catch events: (Works!)

; Function for creation of an embeded Shell.Explorer.2 object within a GUI
; $oIE must be a declared global variable
; $X, $Y, $Width; $Height are the position and size of the control
Func GUICtrlCreateIE (ByRef $oIE, $X, $Y, $Width, $Height)
    Local $GUIIE
    
    If IsObj ($oIE) Then
    ; Variable is already an object! -> error!
        SetError (1); Error
        Return 0    ; Error     
    EndIf
; Create Shell.Explorer.2 object
    $oIE = ObjCreate ("Shell.Explorer")
    If @Error = 1 Then
    ; Failure while creating the Shell.Explorer.2 object
        $oIE = 0
        SetError (1); Error
        Return 0    ; Error             
    EndIf
; Objectcreation was successful -> Create the GUI control
    $GUIIE = GUICtrlCreateObj ($oIE, $X, $Y , $Width , $Height)
    If $GUIIE = 0 Then 
    ; Failure while creating the GUI control
        $oIE = 0    ; Destroys the Shell.Explorer.2 object
        $GUIIE = 0
        SetError (1); Error
        Return 0    ; Error             
    EndIf
    
    $oIE.silent = 0 ; Get Error Messages
    $oIEEvents = ObjEvent ($oIE,"IEEvent","DWebBrowserEvents2") ; Assign events to functions starting with IEEvent
    IENavigate ($oIE, $GUIIE, "about:blank"); Display blank page    
    Return $GUIIE   ; Success!  
EndFunc

And here is a event handler which works:

; Event: Will be called when the progress of a download changes
Func IEEventProgressChange ($IEProg, $IEProgMax)
    If $IEProg < 0 Then $IEProg = 0
    If $IEProgMax <= 0 Then 
        $IEProgress = 0
    Else
        $IEProgress = ($IEProg * 100) / $IEProgMax
    EndIf
EndFunc

And here is the BeforeNavigate2 event handler and I have no clue why it raises a crash:

; Event: Will be called before a navigation starts
Func IEEventBeforeNavigate2 ($IEpDisp, $IEURL, $IEFlags, $IETargetFrameName, $IEPostData, $IEHeaders, ByRef $IECancel)
    $IECancel = False   ; Dummy - Until I add other code
EndFunc

A detailed reference of these events will you find under:

http://msdn.microsoft.com/library/default...._node_entry.asp

Perhaps somebody could help me with this problem...

Thanks in advance

Michael

PS: Here is my complete code... It's still in development... so don't wonder if you see something "unfinished"... and, of course, the described error is comented out, so that this code will work...

; Shell.Explorer.2 ActiveX control - Test for the latest Beta of AutoIt
; for a reference see: 'http://msdn.microsoft.com/library/default.asp?url=/workshop/browser/webbrowser/browser_control_node_entry.asp'

; Needed for the GUI
#include <GUIConstants.au3>

Global $oIE = 0         ; Objectvariable for Shell.Explorer.2 object                                
Global $oIEEvents = 0   ; Objectvariable for Events object
Global $IEProgress = 0  ; Integer variable for the actual progress value in percent
Global $GUIIE = 0       ; controlID for Shell.Explorer.2 control

; Install custom error handler
$oMyError = ObjEvent ("AutoIt.Error","MyError") 

; A simple error handler
Func MyError () 
    Local $HexNumber = hex ($oMyError.number, 8) 
    MsgBox (4096, "COM Error", "COM Error: " & $HexNumber & ", Source: " & $oMyError.source & ", Description: " & $oMyError.description & ", Line: " & $oMyError.scriptline)    
    SetError(1) ; For @Error... This is needed for several functions of the Shell.Explorer.2 library!
Endfunc

; Function for creation of an embeded Shell.Explorer.2 object within a GUI
; $oIE must be a declared global variable
; $X, $Y, $Width; $Height are the position and size of the control
Func GUICtrlCreateIE (ByRef $oIE, $X, $Y, $Width, $Height)
    Local $GUIIE
    
    If IsObj ($oIE) Then
    ; Variable is already an object! -> error!
        SetError (1); Error
        Return 0    ; Error     
    EndIf
; Create Shell.Explorer.2 object
    $oIE = ObjCreate ("Shell.Explorer")
    If @Error = 1 Then
    ; Failure while creating the Shell.Explorer.2 object
        $oIE = 0
        SetError (1); Error
        Return 0    ; Error             
    EndIf
; Objectcreation was successful -> Create the GUI control
    $GUIIE = GUICtrlCreateObj ($oIE, $X, $Y , $Width , $Height)
    If $GUIIE = 0 Then 
    ; Failure while creating the GUI control
        $oIE = 0    ; Destroys the Shell.Explorer.2 object
        $GUIIE = 0
        SetError (1); Error
        Return 0    ; Error             
    EndIf
    
    $oIE.silent = 0 ; Get Error Messages
    $oIEEvents = ObjEvent ($oIE,"IEEvent","DWebBrowserEvents2") ; Assign events to functions starting with IEEvent
    IENavigate ($oIE, $GUIIE, "about:blank"); Display blank page    
    Return $GUIIE   ; Success!  
EndFunc

; Function for deletion of an embeded Shell.Explorer.2 object within a GUI
; $oIE must be a declared global variable
; $GUIIE must be a declared global variable
Func GUICtrlDeleteIE (ByRef $oIE, ByRef $GUIIE)
    Local $RV = 0; Return value
    
; Check if $oIE is an object...
    If Not IsObj ($oIE) Then
    ; Variable isn't an object! -> error!
        SetError (1); Error
        Return 0    ; Error     
    EndIf
    
; Disable event calls
    $oIEEvents = 0; Perhaps someone knows a better way...
    
; Destroy Shell.Explorer.2 object
    $oIE = 0; Perhaps someone knows a DestroyObj function or anything else... This is the only way I know!
    
; Delete GUI control
    $RV = GUICtrlDelete ($GUIIE)
    If $RV <> 1 Then 
    ; Unknown Error
        SetError (1); Error
        Return 0    ; Error             
    EndIf
; Zero the controlID 
    $GUIIE = 0
    
; Success!
    Return 1
EndFunc

; Funktion for navigating to websites
; $oIE is the objectvariable of the Shell.Explorer.2 object (set with GUICtrlCreateIE)
; $GUIIE is the controlID of the Shell.Explorer.2 GUI control (set with GUICtrlCreateIE)
; $URL is the URL to navigate to (String with beginning 'http://' or equivalent)
; $Wait states if Shell.Explorer.2 should wait until the site is completly loaded
Func IENavigate ($oIE, $GUIIE, $URL, $Wait = 1)
    Local $HTML = "" ; String for HTML code
    
    If IsObj ($oIE) Then
        $oIE.navigate ($URL)
    ; When an error handler is installed, this will raise this query when a 'SetError = 1' is at the end of the error handler... This is highly prefered!
        If @Error = 1 Then
            IENavigate ($oIE, $GUIIE, "about:blank", 0) ; Navigate to 'about:blank'... without this Shell.Explorer.2 could raise an exception on quit!
            SetError (1)
            Return 0
        EndIf
       ; Navigation successful
        If ($Wait = 1) Then 
            IELoadWait ($oIE)       ; Wait until page is loaded
            $HTML = IEReadHTML ($oIE); Get HTML code and check if error page is displayed
            If @Error = 1 Then
            ; Error reading HTML code -> Page can't be displayed right!
                SetError (1); Error
                Return 0    ; Error
            EndIf
            If StringInStr ($HTML, "res://shdoclc.dll/pagerror.gif") <> 0 Then 
            ; Error page is displayed
                SetError (1); Error
                Return 0    ; Error
            EndIf
        EndIf   
        GUICtrlSetState ($GUIIE, $GUI_Focus)
        Return 1            ; Success       
    Else
       ; $oIE is no Object
        SetError (1)        ; Error
        Return 0            ; Error
    EndIf   
EndFunc 

; Funktion for waiting while Shell.Explorer.2 is busy
; $oIE is the objectvariable of the Shell.Explorer.2 object (set with GUICtrlCreateIE)
Func IELoadWait ($oIE)
    If IsObj ($oIE) Then
        While $oIE.Busy ; While Shell.Explorer.2 is busy thru loading a website
            Sleep (30)          
        WEnd
        SetError (0)
        Return 1
    Else
       ; $oIE is no Object
        SetError (1); Error
        Return 0    ; Error
    EndIf
EndFunc

; Function for reading of the HTML code which is actually displayed in the control
; $oIE is the objectvariable of the Shell.Explorer.2 object (set with GUICtrlCreateIE)
Func IEReadHTML($oIE)
    Local $HTML = ""; String for HTMl code
        
    If IsObj($oIE) Then
        $HTML = $oIE.document.body.innerHTML    ; Return value is the HTML code
        If @Error = 1 Then
        ; Error while retriefing the HTML code
            SetError(1)
            Return 0
        EndIf
        Return $HTML    ; Success!
    Else
        SetError(1)
        Return 0
    EndIf
EndFunc

; Function for writing HTML code which will be displayed in the control
; $oIE is the objectvariable of the Shell.Explorer.2 object (set with GUICtrlCreateIE)
; $HTML is a String with the HTMl code to display
Func IEWriteHTML($oIE, $HTML)
    If IsObj($oIE) Then
        $oIE.document.body.innerHTML = $HTML
        If @Error = 1 Then
        ; Error while writing the HTML code
            SetError(1); Error
            Return 0; Error
        EndIf
        Return 1    ; Success!
    Else
        SetError(1) ; Error
        Return 0    ; Error
    EndIf
EndFunc

; Event: Will be called when the progress of a download changes
Func IEEventProgressChange ($IEProg, $IEProgMax)
    If $IEProg < 0 Then $IEProg = 0
    If $IEProgMax <= 0 Then 
        $IEProgress = 0
    Else
        $IEProgress = ($IEProg * 100) / $IEProgMax
    EndIf
EndFunc

; Event: Will be called before a navigation starts
;Func IEEventBeforeNavigate2 ($IEpDisp, $IEURL, $IEFlags, $IETargetFrameName, $IEPostData, $IEHeaders, ByRef $IECancel)
;   $IECancel = False   ; Dummy - Until I add other code
;EndFunc
    
; Event: Will be called when a new window (popup) will be opended -> will be canceled
Func IEEventNewWindows2 (ByRef $IEIDipatch, ByRef $IECancel)
    $IECancel = True
EndFunc

; Create a simple GUI for our browser
$GUI = GUICreate ("Embedded IE-Webbrowser", 830, 500,(@DesktopWidth-1000)/2, (@DesktopHeight-600)/2 , $WS_OVERLAPPEDWINDOW + $WS_VISIBLE + $WS_CLIPSIBLINGS)
$GUIIE = GUICtrlCreateIE ($oIE, 1, 21 , 829 , 498 )
$GUILabel = GUICtrlCreatelabel ("", 1, 1, 100, 18)

; Show GUI
GUISetState (@SW_Show, $GUI)

; Navigate to ...
IENavigate ($oIE, $GUIIE, "www.monstersgame.de", 0)

; Waiting for user to close the window
While 1
    $msg = GUIGetMsg ($GUI)
    Select
        Case $msg = $GUI_EVENT_CLOSE
            GUICtrlDeleteIE ($oIE, $GUIIE)  ; destroys Shell.Explorer.2; must be destroyed before the GUI will be destroyed and before an 'Exit' command
            GUIDelete ($GUI)                ; destroys GUI
            ExitLoop        
    EndSelect
    GUICtrlSetData ($GUILabel, $IEProgress)
    Sleep (10)  
Wend

; End of main programm
Exit

Share this post


Link to post
Share on other sites



Well your script was to big to look deeply into but I can provide you with an example on how to fire up the BeforeNavigate event...

; Author:   Kåre Johansson
; AutoIt Version: 3.1.1.86
; Description: Very Simple example: Embedding Shell Browser object with BeforeNavigate event
; Date: 5 nov 2005

#include <GUIConstants.au3>
;#include <Word.au3>

$oIE = ObjCreate("Shell.Explorer.2"); open the com openject
$oEvt = ObjEvent($oIE,"IEEvent_","DWebBrowserEvents"); attach the DWebBrowserEvents where 'BeforeNavigate' is part of
GUICreate(@ScriptName, 400, 400, 100, 100, BitOR($WS_OVERLAPPEDWINDOW, $WS_CLIPSIBLINGS))
GUICtrlCreateObj($oIE, 0, 0, 400, 400); make the com object visible
GUISetState()

With $oIE; make a object pool
    .RegisterAsBrowser = True
    .RegisterAsDropTarget = True
    .TheaterMode = True
    .Resizable = False
    .navigate("http://www.google.com")
EndWith

While 1
    $msg = GUIGetMsg()
    Select
      Case $msg = $GUI_EVENT_CLOSE
         ExitLoop
    EndSelect
WEnd
Exits()

; ==================================================================
; BeforeNavigate - Fires the BeforeNavigate event from IEEvent
; arguments:
#cs
void BeforeNavigate(          IDispatch *pDisp,
    VARIANT *&url,
    VARIANT *&Flags,
    VARIANT *&TargetFrameName,
    VARIANT *&PostData,
    VARIANT *&Headers,
    VARIANT_BOOL *&Cancel
)

Parameters

url: [in] Pointer to a VARIANT structure of type VT_BSTR that contains the URL to be navigated to. 
Flags: [in] Reserved. Must be set to NULL. 
TargetFrameName:[in] Pointer to a VARIANT structure of type VT_BSTR that contains the name of the frame in which to display the resource, 
    or NULL if no named frame is targeted for the resource. 
PostData: [in] Pointer to a VARIANT structure of type VT_BYREF|VT_VARIANT that contains the data to send to the server if the HTTP POST 
    transaction is being used. 
Headers: [in] Pointer to a VARIANT structure of type VT_BSTR that contains additional HTTP headers to send to the server (HTTP URLs only). 
    The headers can specify things such as the action required of the server, the type of data being passed to the server, or a status code. 
Cancel: [in, out] Pointer to a VARIANT structure of type VARIANT_BOOL that contains the cancel flag. An application can set this parameter to 
    VARIANT_TRUE to cancel the navigation operation, or to VARIANT_FALSE to allow it to proceed. 
; ==================================================================
#ce
Func IEEvent_BeforeNavigate($url,$Flags,$TargetFrameName,$PostData,$Headers,$Cancel)
    _say('before Navigate Event notified')
    _say($url)
    _say($Flags)
    _say($TargetFrameName)
    _say($PostData)
    _say($Headers)
    _say($Cancel)
EndFunc

; ==================================================================
; Exits - Exit window and close com object and event handle
; arguments no / returns no
; ==================================================================
Func Exits()
    GUIDelete()
    $oEvt = 0
    $oIE = 0
Exit
EndFunc

Func _Say($tx)
    ConsoleWrite($tx & @CR)
EndFunc

Hope this can help you on...

kjactive B)

Share this post


Link to post
Share on other sites

Hi Kåre Johansson,

I know that the BeforeNavigate event of DWebBrowserEvents works. But on the MSDN page is noticed that this events are obsolete...

This interface is obsolete; use the DWebBrowserEvents2 interface instead. The DWebBrowserEvents2 interface provides more control over the WebBrowser control than the DWebBrowserEvents interface.

I've tried to implement the mentioned DWebBrowserEvents2 events and many worked but the BeforNavigate2 event causes a crash and I have no idea why... When I implement this event without a ByRef for $IECancel then it works... But I need $IECancel as ByRef because - when you run my example code again and click on the link news - it will simply crash on requests for a new window and I want to prevent these naviagtions...

I would simply implement the BeforeNavigate event instead of the BeforeNavigate2 event when I could be sure that my script works after the release of IE 7. But I can't because these events are obsolete and nobody could say, that these events are present in IE 7!

Best regards

Michael

Share this post


Link to post
Share on other sites

Hi Kåre Johansson,

in addition it seems that DWebBrowserEvents2 is responsible for the crash of my script when I click on the mentioned link... This is so strange... When I use DWebBrowserEvents then I could click on the mentioned link and I could use every event... Whats going on here?

Best regards

Michael

Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

Please don't answer anymore to this topic. Please see http://www.autoitscript.com/forum/index.php?showtopic=17685 for further details on my problem...

Thanks

Michael

PS: If you are an admin: Please close this thread. Thanks.

Maybe its better to open one thread and stick with it ? B)

Edited by JdeB

Visit the SciTE4AutoIt3 Download page for the latest versions        Beta files                                                          Forum Rules
 
Live for the present,
Dream of the future,
Learn from the past.
  :)

Share this post


Link to post
Share on other sites

Maybe its better to open one thread and stick with it ? B)

Man you're right but it seems that this is no longer a problem with simply catching a event... My problem is that I can't give a parameter back to the control which has raised the event... and so I've created a thread in the developer section... I've discused this problem with Dale Holm (creator of the IE Automation Library), too and we have no solution for this problem... And perhaps with this new topic it is clearer what I mean...

So please excuse it... ;-)

Best regards

Michael

Share this post


Link to post
Share on other sites

#8 ·  Posted (edited)

Hi Kåre Johansson,

in addition it seems that DWebBrowserEvents2 is responsible for the crash of my script when I click on the mentioned link... This is so strange... When I use DWebBrowserEvents then I could click on the mentioned link and I could use every event... Whats going on here?

Best regards

Michael

Well I do remember somewhere back in time that I read something about 'DWebBrowserEvents2' is only available to the InternetExplorer.Application.1 com object but I lost track on this one - but with all the browsers around, not every events is available to all and the Shell.Explorer.2 is one of the oldest and basic ones around BUT...

With an com object you could find that an object shows up and works basicly but events is non functional as this particulare language is not in the target area ( basic, C++, net or HTML ) and I don't know what SvenP did target his functions with but it shure looks like basic interface BUT still how he did interface com objects to something as these object always has an target area, he has to answer to that one when he come home from 'south of china', a second com object is needed to interface or simply that the object functions is not available to this particulare object when used in this manner - sniff around the INet is my adwise simple as that...

ActiveX object interface is one of the hardest thing to interface and SvenP did a ereal great job - hope he returns...

kjactive B)

Edited by kjactive

Share this post


Link to post
Share on other sites

Hi kjactive,

Well I do remember somewhere back in time that I read something about 'DWebBrowserEvents2' is only available to the InternetExplorer.Application.1 com object but I lost track on this one - but with all the browsers around, not every events is available to all and the Shell.Explorer.2 is one of the oldest and basic ones around BUT...

Relying on the documentation of MSDN Shell.Explorer.2 also supports the BeforeNavigate2 event and as long as I didn't try to give a parameter back to the control it works perfect. But in order to get the full functionallity of BeforeNavigate2 I must give the Cancel Parameter back to the control. I've tried this by adding ByRef to the Parameter but when I do that and the event happens AutoIt crashes. It seems that this is a circumstance which is not implementet in AutoIt and so I'll raise a crash.

With an com object you could find that an object shows up and works basicly but events is non functional as this particulare language is not in the target area ( basic, C++, net or HTML ) and I don't know what SvenP did target his functions with but it shure looks like basic interface BUT still how he did interface com objects to something as these object always has an target area, he has to answer to that one when he come home from 'south of china', a second com object is needed to interface or simply that the object functions is not available to this particulare object when used in this manner - sniff around the INet is my adwise simple as that...

I've "sniffed" around the INet and the forum a lot... But I haven't found a solution. But the Webbrowser control is well documentated at MSDN and there is noticed that the Cancel parameter is designed as pointer and to be readable and writeable. I simply have no idea how this could be done with AutoIt and tested the ByRef keyword with my event hanlder. And this ByRef raises a crash. It simply seems that noone had this before. Should I ask SvenP directly?

ActiveX object interface is one of the hardest thing to interface and SvenP did a ereal great job - hope he returns...

I completly belief this!

Best regards

Michael

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0