Jump to content

Dim variable as object with com


Recommended Posts

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 by this-is-me
Who else would I be?
Link to comment
Share on other sites

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 by this-is-me
Who else would I be?
Link to comment
Share on other sites

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:

Attribute 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:

Opt("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 by this-is-me
Who else would I be?
Link to comment
Share on other sites

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 by this-is-me
Who else would I be?
Link to comment
Share on other sites

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:

HotKeySet("{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?
Link to comment
Share on other sites

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 by Ejoc
Start -> Programs -> AutoIt v3 -> AutoIt Help File -> Index -> (The Function you are asking about)----- Links -----DllStruct UDFsRSA Crypto UDFs
Link to comment
Share on other sites

$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
Link to comment
Share on other sites

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 $doc

But as I said, it has never been tested with windows DLL's and I doubt if it will work.

Regards,

-Sven

Link to comment
Share on other sites

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?
Link to comment
Share on other sites

  • 4 months later...

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.

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 by wliebkem
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...