this-is-me Posted May 13, 2005 Posted May 13, 2005 (edited) I am looking to duplicate a Visual Basic 6.0 script in autoit and am confused as to how this might be possible: Dim doc As IHTMLDocument2 I need a method to access the document object model of an existing webpage and be able to interact with it. I already have experience with javascript, so as long as I can "connect" with the DOM, I will be OK. Does anyone know of a way to do this with the current beta version? Edited May 13, 2005 by this-is-me Who else would I be?
MSLx Fanboy Posted May 13, 2005 Posted May 13, 2005 Dim $doc = ObjCreate("IHTMLDocument2") That *should* work. Don't hold me, I'm learning COM right now as well. Writing AutoIt scripts since _DateAdd("d", -2, _NowCalcDate())
this-is-me Posted May 13, 2005 Author Posted May 13, 2005 OK, well that makes sense. I will try it and see if it performs as I would wish. Who else would I be?
this-is-me Posted May 13, 2005 Author Posted May 13, 2005 (edited) Com gurus to the rescue here. I have the following, but it doesn't look right: #cs Type UUID Data1 As Long Data2 As Integer Data3 As Integer Data4(0 To 7) As Byte End Type #ce $UUID = DllStructCreate("long,int,int,byte,byte,byte,byte,byte,byte,byte,byte") Is it right after all? Edited May 13, 2005 by this-is-me Who else would I be?
this-is-me Posted May 13, 2005 Author Posted May 13, 2005 Thanks a lot larry. If all goes well I will be creating a simple wrapper for webpage access. Who else would I be?
this-is-me Posted May 13, 2005 Author Posted May 13, 2005 Another one: Dim IID_IHTMLDocument As UUID This completely confuses me. I know I don't do $IID_IHTMLDocument = ObjCreate($UUID) but what _do_ I do? Who else would I be?
this-is-me Posted May 13, 2005 Author Posted May 13, 2005 (edited) I must say I got completely confused again at the bottom, but I think I am close. I am posting the original VB6 Code first, and my "converted" autoit code second, and maybe someone can tell me if I went wrong anywhere: expandcollapse popupAttribute VB_Name = "basGetIEInfo" Option Explicit ' ' Requires: reference to "Microsoft HTML Object Library" ' Author: James Johnston (jjohnston@email4life.com) ' Type UUID Data1 As Long Data2 As Integer Data3 As Integer Data4(0 To 7) As Byte End Type Public Declare Function GetClassName Lib "user32" _ Alias "GetClassNameA" ( _ ByVal hWnd As Long, _ ByVal lpClassName As String, _ ByVal nMaxCount As Long) As Long Public Declare Function EnumChildWindows Lib "user32" ( _ ByVal hWndParent As Long, _ ByVal lpEnumFunc As Long, _ lParam As Long) As Long Public Declare Function RegisterWindowMessage Lib "user32" _ Alias "RegisterWindowMessageA" ( _ ByVal lpString As String) As Long Public Declare Function SendMessageTimeout Lib "user32" _ Alias "SendMessageTimeoutA" ( _ ByVal hWnd As Long, _ ByVal msg As Long, _ ByVal wParam As Long, _ lParam As Any, _ ByVal fuFlags As Long, _ ByVal uTimeout As Long, _ lpdwResult As Long) As Long Public Const SMTO_ABORTIFHUNG = &H2 Public Declare Function ObjectFromLresult Lib "oleacc" ( _ ByVal lResult As Long, _ riid As UUID, _ ByVal wParam As Long, _ ppvObject As Any) As Long Public Declare Function FindWindow Lib "user32" _ Alias "FindWindowA" ( _ ByVal lpClassName As String, _ ByVal lpWindowName As String) As Long ' ' GetIEText ' ' Returns the Text from an Internet Explorer window ' ' hWnd - Window handle of the IE window ' ' Function GetIEText(ByVal hWnd As Long) As String Dim doc As IHTMLDocument2 Dim col As IHTMLElementCollection2 Dim EL As IHTMLElement Dim l As Long, v1 As Variant, v2 As Variant Set doc = IEDOMFromhWnd(hWnd) GetIEText = doc.body.innerText End Function ' ' GetIEHTML ' ' Returns the HTML from an Internet Explorer window ' ' hWnd - Window handle of the IE window ' ' Function GetIEHTML(ByVal hWnd As Long) As String Dim doc As IHTMLDocument2 Dim col As IHTMLElementCollection2 Dim EL As IHTMLElement Dim l As Long, v1 As Variant, v2 As Variant Set doc = IEDOMFromhWnd(hWnd) GetIEHTML = doc.body.innerHTML End Function ' ' IEDOMFromhWnd ' ' Returns the IHTMLDocument interface from a WebBrowser window ' ' hWnd - Window handle of the control ' ' Function IEDOMFromhWnd(ByVal hWnd As Long) As IHTMLDocument Dim IID_IHTMLDocument As UUID Dim hWndChild As Long Dim spDoc As IUnknown Dim lRes As Long Dim lMsg As Long Dim hr As Long If hWnd <> 0 Then If Not IsIEServerWindow(hWnd) Then ' Get 1st child IE server window EnumChildWindows hWnd, AddressOf EnumChildProc, hWnd End If If hWnd <> 0 Then ' Register the message lMsg = RegisterWindowMessage("WM_HTML_GETOBJECT") ' Get the object Call SendMessageTimeout(hWnd, lMsg, 0, 0, _ SMTO_ABORTIFHUNG, 1000, lRes) If lRes Then ' Initialize the interface ID With IID_IHTMLDocument .Data1 = &H626FC520 .Data2 = &HA41E .Data3 = &H11CF .Data4(0) = &HA7 .Data4(1) = &H31 .Data4(2) = &H0 .Data4(3) = &HA0 .Data4(4) = &HC9 .Data4(5) = &H8 .Data4(6) = &H26 .Data4(7) = &H37 End With ' Get the object from lRes hr = ObjectFromLresult(lRes, IID_IHTMLDocument, 0, IEDOMFromhWnd) End If End If End If End Function Function EnumChildProc(ByVal hWnd As Long, lParam As Long) As Long If IsIEServerWindow(hWnd) Then lParam = hWnd Else EnumChildProc = 1 End If End Function Function IsIEServerWindow(ByVal hWnd As Long) As Boolean Dim lRes As Long Dim sClassName As String ' Initialize the buffer sClassName = String$(100, 0) ' Get the window class name lRes = GetClassName(hWnd, sClassName, Len(sClassName)) sClassName = Left$(sClassName, lRes) IsIEServerWindow = StrComp(sClassName, _ "Internet Explorer_Server", _ vbTextCompare) = 0 End Function Converted: expandcollapse popupOpt("WinTitleMatchMode", 4) ;Public Const SMTO_ABORTIFHUNG = &H2 $SMTO_ABORTIFHUNG = 0x2 #cs Type UUID Data1 As Long Data2 As Integer Data3 As Integer Data4(0 To 7) As Byte End Type #ce $UUID = "long;int;int;byte[8]" ;Dim doc As IHTMLDocument2 $doc = ObjCreate("IHTMLDocument2") ;Dim col As IHTMLElementCollection2 $col = ObjCreate("IHTMLElementCollection2") ;Dim EL As IHTMLElement $EL = ObjCreate("IHTMLElement") ;Set doc = IEDOMFromhWnd(hWnd) ;Dim IID_IHTMLDocument As UUID $IID_IHTMLDocument = DLLStructCreate($UUID) $hndl = ControlGetHandle("classname=IEFrame", "", "Internet Explorer_Server1") ;lMsg = RegisterWindowMessage("WM_HTML_GETOBJECT") $lMsg = DllCall("user32.dll", "int", "RegisterWindowMessage", "str", "WM_HTML_GETOBJECT") #cs Public Declare Function SendMessageTimeout Lib "user32" _ Alias "SendMessageTimeoutA" ( _ ByVal hWnd As Long, _ ByVal msg As Long, _ ByVal wParam As Long, _ lParam As Any, _ ByVal fuFlags As Long, _ ByVal uTimeout As Long, _ lpdwResult As Long) As Long #ce ;Dim lRes As Long dim $lRes ;SendMessageTimeout(hWnd, lMsg, 0, 0, SMTO_ABORTIFHUNG, 1000, lRes) DllCall("user32.dll", "long", "SendMessageTimeout", "long", $hndl, "long", $lMsg, "long", 0, "long", 0, "long", $SMTO_ABORTIFHUNG, "long", 1000, "long", $lRes) #cs With IID_IHTMLDocument .Data1 = &H626FC520 .Data2 = &HA41E .Data3 = &H11CF .Data4(0) = &HA7 .Data4(1) = &H31 .Data4(2) = &H0 .Data4(3) = &HA0 .Data4(4) = &HC9 .Data4(5) = &H8 .Data4(6) = &H26 .Data4(7) = &H37 End With #ce DllStructSet($IID_IHTMLDocument, 1, 0x626FC520) DllStructSet($IID_IHTMLDocument, 2, 0xA41E) DllStructSet($IID_IHTMLDocument, 3, 0x11CF) DllStructSet($IID_IHTMLDocument, 4, 0xA7) DllStructSet($IID_IHTMLDocument, 4, 0x31, 1) DllStructSet($IID_IHTMLDocument, 4, 0x0, 2) DllStructSet($IID_IHTMLDocument, 4, 0xA0, 3) DllStructSet($IID_IHTMLDocument, 4, 0xC9, 4) DllStructSet($IID_IHTMLDocument, 4, 0x8, 5) DllStructSet($IID_IHTMLDocument, 4, 0x26, 6) DllStructSet($IID_IHTMLDocument, 4, 0x37, 7) #cs Public Declare Function ObjectFromLresult Lib "oleacc" ( _ ByVal lResult As Long, _ riid As UUID, _ ByVal wParam As Long, _ ppvObject As Any) As Long #ce ;hr = ObjectFromLresult(lRes, IID_IHTMLDocument, 0, IEDOMFromhWnd) $hr = DllCall("oleacc.dll", "long", "ObjectFromLresult", "long", $lRes, "ptr" , DllStructPtr($IID_IHTMLDocument), "long", 0, "ptr", $doc) EDIT: I also see that $doc = ObjCreate("IHTMLDocument2") is not getting me anywhere. an IsObj on the result is saying that nothing was created. Edited May 13, 2005 by this-is-me Who else would I be?
this-is-me Posted May 13, 2005 Author Posted May 13, 2005 I know I am bumping this a litttle prematurely, but I need to get this running as soon as I can. Does anyone have any ideas for dim doc as IHTMLDocument2 ? Who else would I be?
this-is-me Posted May 15, 2005 Author Posted May 15, 2005 (edited) Just to let everyone know, I did find a way to interact with any current Internet Explorer window, and it was much easier than any of the above would have led me to believe. Here is some simple code to illustrate the new code: $ShellApp = ObjCreate("Shell.Application") for $win in $ShellApp.Windows MsgBox(0, "", $win.document.documentElement.innerHTML) next NOTE: This also gives listings of any open "windows explorer" window, so the above code does not work correctly if you have any folder windows open at the time. Edited May 15, 2005 by this-is-me Who else would I be?
this-is-me Posted May 15, 2005 Author Posted May 15, 2005 Here is some more fun with a webbrowser. I plan on putting this in the bug reports, though, because there are a few things here that can cause autoit as a whole to crash: expandcollapse popupHotKeySet("{F1}", "testit") ObjEvent("AutoIt.Error","au3error") #cs $test = ObjCreate("Shell.Application") for $win in $test.Windows ;msgbox(0, "", $win.document.documentElement.innerHTML) if isobj($win) Then MsgBox(0, "", $win.FullName) EndIf next #ce $test = ObjCreate("InternetExplorer.Application") $test.visible = true $test.Navigate2("http://windowsupdate.microsoft.com") While 1 Sleep(1000) WEnd Func testit() $evl = InputBox("", "") if $evl <> "" Then Eval($evl) EndIf EndFunc ;msgbox(0,"",$test.frames[0]) Func au3error() $HexNumber=hex($oMyError.number,8) Msgbox(0,"","We intercepted a COM Error !" & @CRLF & _ "Number is: " & $HexNumber & @CRLF & _ "Windescription is: " & $oMyError.windescription & @CRLF & _ "description is: " & $oMyError.description) SetError(1); something to check for when this function returns Endfunc You can execute any scripting in the open browser window by typing F1 and using $test as a launchpad. Try typing msgbox(0,"",$test.document.documentElement.innerHTML) Who else would I be?
Ejoc Posted May 15, 2005 Posted May 15, 2005 (edited) Should be: .Data4(0) = &HA7 .Data4(1) = &H31 .Data4(2) = &H0 .Data4(3) = &HA0 .Data4(4) = &HC9 .Data4(5) = &H8 .Data4(6) = &H26 .Data4(7) = &H37 DllStructSet($IID_IHTMLDocument, 4, 0xA7, 1) DllStructSet($IID_IHTMLDocument, 4, 0x31, 2) DllStructSet($IID_IHTMLDocument, 4, 0x0, 3) DllStructSet($IID_IHTMLDocument, 4, 0xA0, 4) DllStructSet($IID_IHTMLDocument, 4, 0xC9, 5) DllStructSet($IID_IHTMLDocument, 4, 0x8, 6) DllStructSet($IID_IHTMLDocument, 4, 0x26, 7) DllStructSet($IID_IHTMLDocument, 4, 0x37, 8) Arrays in DllStruct start at 1 not 0 I dont see DllStructDelete($IID_IHTMLDocument) Edited May 15, 2005 by Ejoc Start -> Programs -> AutoIt v3 -> AutoIt Help File -> Index -> (The Function you are asking about)----- Links -----DllStruct UDFsRSA Crypto UDFs
this-is-me Posted May 15, 2005 Author Posted May 15, 2005 That's because I didn't get far enough to tell if it would work. Do you see any other reasons it wouldn't work correctly? Who else would I be?
Ejoc Posted May 15, 2005 Posted May 15, 2005 $lMsg = DllCall("user32.dll", "int", "RegisterWindowMessage", "str", "WM_HTML_GETOBJECT") $lMsg will be an array, where $lMsg[0] = the return from RegisterWindowMessage you could do $lMsg = $lMsg[0] Start -> Programs -> AutoIt v3 -> AutoIt Help File -> Index -> (The Function you are asking about)----- Links -----DllStruct UDFsRSA Crypto UDFs
SvenP Posted May 15, 2005 Posted May 15, 2005 Anyone?<{POST_SNAPBACK}>this-is-me,I know you have found an easier way to do this job, but I just wanted you to explain this COM issue.The IHTMLDocument and IHTMLDocument2 are NOT objects. These are 'interfaces' to an Object. (in simple human terms, let's say I am an Object and you can talk to me by 'speaking' or by 'writing' me). So you just can't just CREATE 'speaking', you have to meet the person first and find out in what ways you can communicate with him.Since AutoIt script is 'datatypeless' you don't have to 'declare' a variable type. They are all of type 'Variant' and get their contents on assignment. (And no, Arrays are no exception. On a DIM you don't really declare them, you merely reserve space for the containing variants). Also when a function returns a value through one of it's arguments (like in some UDF's), you use a DIM line to 'define' a name for the variable that will act as the placeholder for the data.Same way with objects, you don't have to declare them. When some function want to give it a value, do a "DIM $col" or just give it an empty value, like "$col=0" (same as a dim).However, your attempts with DLLCall will never work, because DLLCall does not yet understand return types of type 'Object'. I know that Valik did some attempts using 'dispatch' pointers in DLLCall, but that requires a specific format on the DLL-side. It has never been documented however.If it would work, then it would look like:$hr = DllCall("oleacc.dll", "long", "ObjectFromLresult", "long", $lRes, "ptr" , DllStructPtr($IID_IHTMLDocument), "long", 0, "idispatch_ptr", "") $doc=hr[4] ; This will put the HTMLDocument interface in $docBut as I said, it has never been tested with windows DLL's and I doubt if it will work.Regards,-Sven
this-is-me Posted May 15, 2005 Author Posted May 15, 2005 I kinda figured that out when I did the research on how c++ handles creation of IHTMLDocument2, but I didn't know if there was another way to create an interface with au3 without delving into the sourcecode. Thanks for an exact explanation of what was going on. Who else would I be?
wliebkem Posted September 18, 2005 Posted September 18, 2005 (edited) Just to let everyone know, I did find a way to interact with any current Internet Explorer window, and it was much easier than any of the above would have led me to believe. Here is some simple code to illustrate the new code:$ShellApp = ObjCreate("Shell.Application") for $win in $ShellApp.Windows MsgBox(0, "", $win.document.documentElement.innerHTML) nextNOTE: This also gives listings of any open "windows explorer" window, so the above code does not work correctly if you have any folder windows open at the time.Rats, I seized on the same C++ and VB code to try and get a DOM of a WebBrowser from a hWnd. The Shell.Application method is limited in that it will not control modal and modeless web page dialogs. The just don't show up as windows under Shell.Application, thus they can't be accessed this way. I still haven't fully tried to enumerate all child windows but in the particular application that I am using, the web page dialog is black-box launched. Sounds like a dead end for now though. I may just do this in VB.Thanks,Walt L. Edited September 18, 2005 by wliebkem
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now