Jump to content

All-Purpose IE Event Handler


lod3n
 Share

Recommended Posts

If you struggle to capture IE events dynamically, and then want to get a particular DOM object when your events fire, you should immediately see the value in this demo. I've written this as a stopgap in lieu of probably never being able to use window.external in AutoIt.

What it does is create a simple html file, and a button which calls a js function, Au3Callback, passing in as parameters the button itself as an object, and a string. The demo then loads this document into an IE wrapper GUI, and installs the Au3Callback function in the document's header (this is so that it can be changed easily for customization). It then attaches a handler to the IE window's onpropertychange event. When one occurs due to Au3Callback changing the documentElement's property "params", the handler function retrieves the object stored in "params", which contains the parameters that the javascript function set. As you'll see, it gets the button's object from the parameters pulled into the function, not via a DOM search, or element collection enumeration!

If this sort of thing is up your alley, please take a look and let me know what you think. BTW, the reason I have it connected to document.parentwindow.document.documentElement is so that it will work with frameset children too. I'm sure DaleHohm could improve this vastly, but the way it is, it solves a few major problems for me personally right now.

#include <GUIConstants.au3>

$sFilename = @scriptDir&"\Lod3n_Event_Demo.htm"
;NONE OF THIS WILL WORK without a doctype declaration. Dunno why.
$sHTML = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">'
$sHTML &= "<HTML><HEAD></HEAD><body>"
$sHTML &= "<button onclick=""Au3Callback(this,'Notify it, baby!')"">Do it!</button>"
$sHTML &= "</body></HTML>"
FileDelete($sFilename)
FileWrite($sFilename,$sHTML)

$oIE = ObjCreate("Shell.Explorer.2")
GUICreate ( "Embedded Web control Test", 640, 480,-1, -1 , $WS_OVERLAPPEDWINDOW + $WS_VISIBLE + $WS_CLIPSIBLINGS)
$GUIActiveX = GUICtrlCreateObj($oIE, 0, 0 , 640 , 480 )
GUISetState(@SW_SHOW)

$oIE.Navigate($sFilename)
installCallback($oIE)
$targetObj = $oIE.document.parentwindow.document.documentElement
$targetObj.setAttribute("params",1)
$handler = ObjEvent($targetObj,"IeEvent_")

While 1
    $msg = GUIGetMsg()
    if $msg = $GUI_EVENT_CLOSE then ExitLoop
Wend

func installCallback($o_object)
    Local $scriptCode = "function Au3Callback(obj,msg){ "
    $scriptCode &= "var targetObj = top.document.parentwindow.document.documentElement;"
    $scriptCode &= " targetObj.params = new function(){this.obj=obj;this.msg=msg;}"
    $scriptCode &= " }"
    Local $o_head = $o_object.document.all.tags ("HEAD").Item(0)
    Local $o_script = $o_object.document.createElement ("script")
    With $o_script
        .defer = True
        .language = "jscript"
        .type = "text/javascript"
        .text = $scriptCode
    EndWith
    $o_head.appendChild ($o_script)
EndFunc

func IeEvent_onpropertychange()
    $oElement = @COM_EventObj
    if isobj($oElement.params) then
        
        $oElement.params.obj.style.background="red"
        Msgbox(64,"Message from js event!",$oElement.params.msg & @crlf)
        
        $oElement.params = 1 ; just in case anything else triggers onpropertychange
    EndIf
EndFunc

[font="Fixedsys"][list][*]All of my AutoIt Example Scripts[*]http://saneasylum.com[/list][/font]

Link to comment
Share on other sites

I am not so quick as gesller; it will take me some tome to better understand and test.

But thank you for your lead here lod3n.

As you might guess from my history of posts this is a "flashy" issue for me.

Currently I go through the flash player using an earlier example of yours.

I will let you know how it goes.

gsb

"Did you ever stop to think? ...and forget to restart!"
Link to comment
Share on other sites

Very interesting approach, using attributes on the documentElement. I'm guessing that the need for the !DOCTYPE (forcing the W3C DOM) probably affects whether attribute change generates an event or not (I say this because IE does not report a new attribute as part of the attribute collection unless it matches a named property - at least through IE5.5, not sure after that).

I'd love to get a generalized procedure created for this that could be included in IE.au3... your thoughts would be appreciated - I'll have to do some study.

Dale

Free Internet Tools: DebugBar, AutoIt IE Builder, HTTP UDF, MODIV2, IE Developer Toolbar, IEDocMon, Fiddler, HTML Validator, WGet, curl

MSDN docs: InternetExplorer Object, Document Object, Overviews and Tutorials, DHTML Objects, DHTML Events, WinHttpRequest, XmlHttpRequest, Cross-Frame Scripting, Office object model

Automate input type=file (Related)

Alternative to _IECreateEmbedded? better: _IECreatePseudoEmbedded  Better Better?

IE.au3 issues with Vista - Workarounds

SciTe Debug mode - it's magic: #AutoIt3Wrapper_run_debug_mode=Y

Doesn't work needs to be ripped out of the troubleshooting lexicon. It means that what you tried did not produce the results you expected. It begs the questions 1) what did you try?, 2) what did you expect? and 3) what happened instead?

Reproducer: a small (the smallest?) piece of stand-alone code that demonstrates your trouble

Link to comment
Share on other sites

As far as working up a generalized procedure, I'm not sure how to go about that. A few problems present themselves.

1) The event handler "loses focus" if the page changes. I've played around with trying to detect page load events, and reattaching the events, but this is unreliable, and if you try and reattach the event while the page is loading, I've managed to crash AutoIt. A good compromise, as far as a purely internal html based application goes is to dynamically create the DOM as needed, instead of navigating to multiple pages, and to use framesets (which was the actual goal in this case.) That way you only set up the event handler once. What I'm trying to say is that this method is not really applicable for messing around with sites that you don't have direct control of - though I'd love to develop a workaround, I just don't have any good theories on how to do so.

2) In theory you should be able to read document.doctype (though not in IE?), but that value is read only. Again, if you come across a page you don't control which doesn't have a doctype set, you're screwed.

Some things I experimented with was creating a javascript object which looked promising. Like this:

<script>
window.au3Obj = new AutoItObj();
function AutoItObj(){
this.obj = 0;
this.msg = 0;
}
</script>

I could get the object in AutoIt, and even read/set the properties. The problem was that I could not attach events to the object, and I'm not interested in dealing with it through polling. So that was a dealbreaker.

It would be great if I could just set up events on the $oIE object, and have events percolate up through somehow, but I don't think that's possible. Let me know if you have any ideas.

Edited by lod3n

[font="Fixedsys"][list][*]All of my AutoIt Example Scripts[*]http://saneasylum.com[/list][/font]

Link to comment
Share on other sites

You know, in reading over my own comment, a potential partial solution appears: load the target websites in an Iframe, and call the installCallback() on any loaded pages within it. But that doesn't solve the potential null doctype issue though. And oh yeah, that's cross site scripting, so it won't work anyway... Never mind.

[font="Fixedsys"][list][*]All of my AutoIt Example Scripts[*]http://saneasylum.com[/list][/font]

Link to comment
Share on other sites

Yes lod3n!

This is perfect... well better than my kluge.

Redefining the js function to the _fsCommand and a few simple changes it allows flash to directly call an au3 function.

Thank you for this short cut.

Now to just do a call back directly to flash.

But I think I know a way. ...testing later perhaps.

The wife is getting pushy just now. :whistle:

gsb

"Did you ever stop to think? ...and forget to restart!"
Link to comment
Share on other sites

  • 3 months later...

I haven't yet used it extensively, so I couldn't tell you. It might be optimized by switching it to Event mode instead of Message mode, but I haven't tried it with this model. It's also single threaded, whereas Flash and Javascript can have several things going on at once.

Are you finding that it's inefficient? Could you elaborate?

[font="Fixedsys"][list][*]All of my AutoIt Example Scripts[*]http://saneasylum.com[/list][/font]

Link to comment
Share on other sites

Thanks lod3n and no, I have not found it inefficient. Frankly, I am not sure how I would measure such at this point. It is just that I was thinking about generalizing it some for my flash interface (BTW: http://www.autoitscript.com/forum/index.ph...t&p=362234) where it would be more extensively used.

So was wondering since it is:

Flash ==> javascript ==> DOM ==> [event] ==> AutoIt ==> Flash

Seemed like a bit of a trip and was wondering how extensively it could be used w/o issue.

On a related subject is the final step: a callback to Flash. This is doable based on the object passed via IE's _onpropertychange event:

Local $oElement = @COM_EventObj
If IsObj($oElement.param) Then
    $flash = $oElement.param.obj
    $flash.SetVariable ("/:myFlashVariable", "some au3 string")
EndIf

This works fine. Here the exposed function 'SetVariable' is hard-coded.

I would like to make the exposed function variable, say the text string "SetVariable" but have had no luck in AutoIt.

Do you know of any way to do that in AutoIt? ...something like:

$flash["SetVariable"] ("/:myFlashVariable", "some au3 string")

Simple enough in other languages but an AutoIt solution eludes me yet.

gsb

"Did you ever stop to think? ...and forget to restart!"
Link to comment
Share on other sites

The Execute function is your friend...

Here is an example of how I use it in IE.au3:

Dale

Free Internet Tools: DebugBar, AutoIt IE Builder, HTTP UDF, MODIV2, IE Developer Toolbar, IEDocMon, Fiddler, HTML Validator, WGet, curl

MSDN docs: InternetExplorer Object, Document Object, Overviews and Tutorials, DHTML Objects, DHTML Events, WinHttpRequest, XmlHttpRequest, Cross-Frame Scripting, Office object model

Automate input type=file (Related)

Alternative to _IECreateEmbedded? better: _IECreatePseudoEmbedded  Better Better?

IE.au3 issues with Vista - Workarounds

SciTe Debug mode - it's magic: #AutoIt3Wrapper_run_debug_mode=Y

Doesn't work needs to be ripped out of the troubleshooting lexicon. It means that what you tried did not produce the results you expected. It begs the questions 1) what did you try?, 2) what did you expect? and 3) what happened instead?

Reproducer: a small (the smallest?) piece of stand-alone code that demonstrates your trouble

Link to comment
Share on other sites

Thank you Dale.

But I thought I had tried that with some return arguments and found no success.

I must have mistyped it and will try again.

How about another way:

Func _SomeFunc( $funcRef, $moreArguments ) {
  ...
  $funcRef("some results")
EndFunc

This would too solve my problem if there is some way to pass the function reference as an argument.

Thanks for your time.

I will go back and see why my Execute test failed.

BTW: Any comments on efficiency and adding such into IE.au3... as you mentioned above?

gsb

"Did you ever stop to think? ...and forget to restart!"
Link to comment
Share on other sites

Thanks Dale.

This seems to work.

Local $flash, $oElement = @COM_EventObj
If IsObj($oElement.param) Then
    $flash = $oElement.param.obj
   ;; $flash.SetVariable ("/:myFlashVariable", "some au3 string") << mimick this
    _SomeFunc( "SetVariable", "some au3 string")
EndIf


Func _SomeFunc( $funcRefString, $data ) {
  ...
  rv = Execute( "$flash." & $funcRefString & "('/:myFlashVariable','" & $data & "')" );
EndFunc

This allows me to execute an exposed Flash function from within AutoIt.

In this case, it is simply setting a variables value.

The problem of getting the data back to Flash is solved.

Thanks again for your help.

gsb

"Did you ever stop to think? ...and forget to restart!"
Link to comment
Share on other sites

That has some interesting implications. It might be possible to speed up some operations in AutoIt (especially big math) by using a compiled flash object to do the heavy lifting... Time to start learning ActionScript. :rolleyes:

[font="Fixedsys"][list][*]All of my AutoIt Example Scripts[*]http://saneasylum.com[/list][/font]

Link to comment
Share on other sites

Actually lod3n. For that all you would need is a ObjCreate("ShockwaveFlash.ShockwaveFlash.1") control to load you swf into instead of the whole browser thing I am using. Remember, the IE setup is solely for the "visual" side of the control and it's bad behavior in an AutoIt GUI.

gsb

"Did you ever stop to think? ...and forget to restart!"
Link to comment
Share on other sites

BTW: Any comments on efficiency and adding such into IE.au3... as you mentioned above?

The way this is handled here really is quite "efficient" as it is all event-driven. As far as being "responsive" - that's a slightly different issue. Since AutoIt COM does not handle COM events synchronously, there can easily be some delay built in to the transactions. I don't expect it to be much of an issue in most cases, but that would depend on your application and expectations.

As far as a generalized implementation of this, I'm not keen on enforcing a specific document namespace, so I'd like to find a more flexible implementation before doing more with it.

Dale

Free Internet Tools: DebugBar, AutoIt IE Builder, HTTP UDF, MODIV2, IE Developer Toolbar, IEDocMon, Fiddler, HTML Validator, WGet, curl

MSDN docs: InternetExplorer Object, Document Object, Overviews and Tutorials, DHTML Objects, DHTML Events, WinHttpRequest, XmlHttpRequest, Cross-Frame Scripting, Office object model

Automate input type=file (Related)

Alternative to _IECreateEmbedded? better: _IECreatePseudoEmbedded  Better Better?

IE.au3 issues with Vista - Workarounds

SciTe Debug mode - it's magic: #AutoIt3Wrapper_run_debug_mode=Y

Doesn't work needs to be ripped out of the troubleshooting lexicon. It means that what you tried did not produce the results you expected. It begs the questions 1) what did you try?, 2) what did you expect? and 3) what happened instead?

Reproducer: a small (the smallest?) piece of stand-alone code that demonstrates your trouble

Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...