jbc1

Explain this function to me?

10 posts in this topic

#1 ·  Posted (edited)

Hi all,

I have a collection of AutoIT scripts which I use to run build sanity checks on my builds. The dialogs I am testing are basically HTML code contained within a custom HTML container.

I find the IE functions very useful as I can click buttons, wait for certain elements to appear etc. For each dialog I am testing, I get the HTML source on the fly like this:

(All the HTML is within an 'Internet Explorer_Server' Object)

#include <ie.au3>
#include "functions.au3"

$WindowTitle = "My App Window Title"
$Win_hWnd = WinGetHandle($WindowTitle) ;
WinActivate($Win_hWnd)

$IE_hWnd = ControlGetHandle($Win_hWnd,"","[Class:Internet Explorer_Server;Instance:1]")

$o_IE = _ObjGetFromHWND($IE_hWnd)

If IsObj($o_IE) Then
     $ieHTML = _IEDocReadHTML($o_IE)
Else
     MsgBos(1, "ERROR", "o_IE is not an Object"
EndIf

The attached file, 'functions.au3' contains the functions I use to get the HTML source, I did not write these, but got them on this forum a while back.

My problem is that now my code does not work on new builds, so I need to troubleshoot, but I don't know how these functions work, especially, '_ObjGetFromHWND'. I keep getting the "o_IE is not an Object" message.

Can anybody explain how these functions work, and if I may need to change anything in them in order for my code to work ?

I especially don't understand this section of '_ObjGetFromHWND'

$typUUID = DLLStructCreate("int;short;short;byte[8]")
    DLLStructSetData($typUUID,1,0x626FC520)
    DLLStructSetData($typUUID,2,0xA41E)
    DLLStructSetData($typUUID,3,0x11CF)
    DLLStructSetData($typUUID,4,0xA7,1)
    DLLStructSetData($typUUID,4,0x31,2)
    DLLStructSetData($typUUID,4,0x0,3)
    DLLStructSetData($typUUID,4,0xA0,4)
    DLLStructSetData($typUUID,4,0xC9,5)
    DLLStructSetData($typUUID,4,0x8,6)
    DLLStructSetData($typUUID,4,0x26,7)
    DLLStructSetData($typUUID,4,0x37,8)

Thanks.

jbc1

functions.au3

Edited by jbc1

Share this post


Link to post
Share on other sites



I think that this GUID is hust the IID_Accessible GUID. Try to change this line in the _ObjGetFromHWND() function:

$aRet = DllCall("oleacc.dll", "int", "ObjectFromLresult", "int", $lResult, _
            "ptr", DLLStructGetPtr($typUUID), "int", 0, "idispatch_ptr", "")

to:

$aRet = DllCall("oleacc.dll", "int", "ObjectFromLresult", "int", $lResult, _
            "ptr", DLLStructGetPtr($typUUID), "int", 0, "idispatch*", "")

You can search the example forum, trancexx have posted a nice topic with samples about the subject. >_<

Share this post


Link to post
Share on other sites

I think that this GUID is hust the IID_Accessible GUID. Try to change this line in the _ObjGetFromHWND() function:

$aRet = DllCall("oleacc.dll", "int", "ObjectFromLresult", "int", $lResult, _
            "ptr", DLLStructGetPtr($typUUID), "int", 0, "idispatch_ptr", "")

to:

$aRet = DllCall("oleacc.dll", "int", "ObjectFromLresult", "int", $lResult, _
            "ptr", DLLStructGetPtr($typUUID), "int", 0, "idispatch*", "")

You can search the example forum, trancexx have posted a nice topic with samples about the subject. >_<

This made no differance, and I must say I actually lost faith in the search on this forum a while back!!

Thanks for your response!

Share this post


Link to post
Share on other sites

Too bad because it took me less than a minute to find it: Link

Share this post


Link to post
Share on other sites

Too bad because it took me less than a minute to find it: Link

It's easy when you know how I suppose >_<

I think this may be different to what I am looking for. To re-iterate, I need to get the text behind an "Internet Explore_Server" Object. My code worked before, but now it doesn't, I was just wondering if the section I mentioned in my first post from '_ObjGetFromHWND' has something specific to do with the window.

Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

Heh, I hope it'll work for you. The problem was with SendMessageTimeOut and the unknown type idispatch_ptr which should be idispatch*.

functions.au3:

#include <WinAPI.au3>

Func _RegisterWindowMessage($sMsg)
    Local $aRet = DllCall("user32.dll", "int", "RegisterWindowMessage", "str", $sMsg)
    If @error Then Return SetError(@error, @extended, 0)
    Return $aRet[0]
EndFunc

Func _SendMessageTimeout($hWnd, $msg, $wParam, $lParam, $nFlags, $nTimeout, ByRef $vOut, $r = 0, $t1 = "int", $t2 = "int")
    Local $aRet = DllCall("user32.dll", "long", "SendMessageTimeout", "hwnd", $hWnd, "int", $msg, $t1, $wParam, $t2, $lParam, "int", $nFlags, "int", $nTimeout, "int*", "")
    If @error Then
        $vOut = 0
        Return SetError(@error, @extended, 0)
    EndIf
    $vOut = $aRet[7]
    If $r >= 0 And $r <= 4 Then Return $aRet[$r]
    Return $aRet
EndFunc

Func _ObjGetFromHWND(ByRef $hWin)
    DLLCall("ole32.dll","int","CoInitialize","ptr",0)
    If @error Then Return SetError(@error,@extended,0)

    Local Const $WM_HTML_GETOBJECT = _RegisterWindowMessage("WM_HTML_GETOBJECT")
    
    If @error Then Return SetError(@error,@extended,0)
    
    Local Const $SMTO_ABORTIFHUNG = 0x0002
    Local $lResult, $typUUID, $aRet, $oIE

    _SendMessageTimeout($hWin, $WM_HTML_GETOBJECT, 0, 0, $SMTO_ABORTIFHUNG, 1000, $lResult)
    If @error Then Return SetError(@error,@extended,0)

    $typUUID = _WinAPI_GUIDFromString('{626FC520-A41E-11cf-A731-00A0C9082637}')
    $aRet = DllCall("oleacc.dll", "int", "ObjectFromLresult", "int", $lResult, _
            "ptr", DLLStructGetPtr($typUUID), "int", 0, "idispatch*", "")
    If @error Then Return SetError(@error,@extended,0)
   ; If Not IsObj($aRet[4]) Then Return SetError(1,@extended,0)
    $oIE = $aRet[4].Script()
; $oIE is now a valid IDispatch object
;Return $oIE.document.parentwindow
    Return $oIE
EndFunc

test.au3:

#include "functions.au3"

ShellExecute('iexplore.exe', 'www.google.com')
WinWaitActive('[CLASS:IEFrame]')
$hWnd = WinGetHandle('[CLASS:IEFrame]')

$IE_hWnd = 0
Do
    $IE_hWnd = ControlGetHandle($hWnd, '', 'Internet Explorer_Server1')
    Sleep(200)
Until $IE_hWnd

Sleep(2000)
$oIE = _ObjGetFromHWND($IE_hWnd)
$oIE.navigate('http://www.autoitscript.com')

Edit: By the way, the GUID is of IID_IHTMLDocument GUID.

Edited by Authenticity

Share this post


Link to post
Share on other sites

Unfortuntely when I try to adapt this to the application I need to get the source of, I get the error message:

'The requested action with this Object has failed'

$typUUID = _WinAPI_GUIDFromString('{626FC520-A41E-11cf-A731-00A0C9082637}')

Is the above libe specifc to the application I am testing?

Share this post


Link to post
Share on other sites

Well, it's working when tested so I guess that one of the parameters or hwnd's is not correct. You can revert to the initial functions.au3 but the two things you need to change are as followed:

Change in _SendMessageTimeOut:

; From:
Local $aRet = DllCall("user32.dll", "long", "SendMessageTimeout", "hwnd", $hWnd, "int", $msg, $t1, $wParam, $t2, $lParam, "int", $nFlags, "int", $nTimeout, "int_ptr", "")

; To:
Local $aRet = DllCall("user32.dll", "long", "SendMessageTimeout", "hwnd", $hWnd, "int", $msg, $t1, $wParam, $t2, $lParam, "int", $nFlags, "int", $nTimeout, "int*", "")

and in _ObjGetFromHWND:

; From:
$aRet = DllCall("oleacc.dll", "int", "ObjectFromLresult", "int", $lResult, _
            "ptr", DLLStructGetPtr($typUUID), "int", 0, "idispatch_ptr", "")

; To:
$aRet = DllCall("oleacc.dll", "int", "ObjectFromLresult", "int", $lResult, _
            "ptr", DLLStructGetPtr($typUUID), "int", 0, "idispatch*", "")

The rest of the code don't use any of the WinAPI.au3 library functions so it can be removed.

Can you post the relevant code that is not succeeding. Before you can spot the faulting parameter(s) you should check if all the window handles are correct and contain a valid handle value, it can be one of the problem that the function fails.

Share this post


Link to post
Share on other sites

#9 ·  Posted (edited)

I'm not MVP but...

When working with "idispatch" type I encountered this function (_IEControlGetObjFromHWND), and actually dismantled it completely (it's called abstraction). At the end it lead me to the conclusion that the function could be written differently.

I did manage to find the source of that function - yes it's Microsoft's suggestion. Of course that doesn't mean that it can't be done better.

I think that function should look like this:

Func _IEControlGetObjFromHWND($hWin)

    Local $aCall = DllCall("user32.dll", "dword", "RegisterWindowMessageW", "wstr", "WM_HTML_GETOBJECT")

    If @error Or Not $aCall[0] Then
        Return SetError(1, 0, "")
    EndIf

    Local Const $WM_HTML_GETOBJECT = $aCall[0]

    $aCall = DllCall("user32.dll", "lresult", "SendMessageW", _
            "hwnd", $hWin, _
            "dword", $WM_HTML_GETOBJECT, _
            "wparam", 0, _
            "lparam", 0)

    Local $lResult = $aCall[0]

    Local $tUUID = _WinAPI_GUIDFromString("{626FC520-A41E-11CF-A731-00A0C9082637}") ; IID_IHTMLDocument

    DllCall("ole32.dll", "int", "CoInitializeEx", "ptr", 0, "dword", 2) ;COINIT_APARTMENTTHREADED

    $aCall = DllCall("oleacc.dll", "dword", "ObjectFromLresult", _
            "lresult", $lResult, _
            "ptr", DllStructGetPtr($tUUID), _
            "wparam", 0, _
            "idispatch*", 0)


    If IsObj($aCall[4]) Then
        Local $oIE = $aCall[4].Script()
        ; $oIE is now a valid IDispatch object
        Return $oIE.document.parentwindow
    Else
        Return SetError(1, 0, 0)
    EndIf

EndFunc   ;==>IEControlGetObjFromHWND

Focus is important and error checking is generally essential, if that means anything to anyone.

edit: s

Edited by trancexx

♡♡♡

.

eMyvnE

Share this post


Link to post
Share on other sites

I'm trying to adapt this code to make it work (i.e. return the object by handle) for a MSFlexGrid object.

For now I tried to change it to:

#include
Global $oError = ObjEvent("AutoIt.Error", "_ErrFunc")

; Here goes your code

; User's COM error function. Will be called if COM error occurs
Func _ErrFunc()
; Do anything here.
ConsoleWrite("err.number is: " & @TAB & $oError.number & @CRLF & _
"err.windescription:" & @TAB & $oError.windescription & @CRLF & _
"err.description is: " & @TAB & $oError.description & @CRLF & _
"err.source is: " & @TAB & $oError.source & @CRLF & _
"err.helpfile is: " & @TAB & $oError.helpfile & @CRLF & _
"err.helpcontext is: " & @TAB & $oError.helpcontext & @CRLF & _
"err.lastdllerror is: " & @TAB & $oError.lastdllerror & @CRLF & _
"err.scriptline is: " & @TAB & $oError.scriptline & @CRLF & _
"err.retcode is: " & @TAB & $oError.retcode & @CRLF & @CRLF)
EndFunc ;==>_ErrFunc

Func _RegisterWindowMessage($sMsg)
Local $aRet = DllCall("user32.dll", "int", "RegisterWindowMessage", "str", $sMsg)
If @error Then Return SetError(@error, @extended, 0)
Return $aRet[0]
EndFunc

Func _SendMessageTimeout($hWnd, $msg, $wParam, $lParam, $nFlags, $nTimeout, ByRef $vOut, $r = 0, $t1 = "int", $t2 = "int")
Local $aRet = DllCall("user32.dll", "long", "SendMessageTimeout", "hwnd", $hWnd, "int", $msg, $t1, $wParam, $t2, $lParam, "int", $nFlags, "int", $nTimeout, "int*", "")
If @error Then
$vOut = 0
Return SetError(@error, @extended, 0)
EndIf
$vOut = $aRet[7]
If $r >= 0 And $r <= 4 Then Return $aRet[$r]
Return $aRet
EndFunc

Func _ObjGetFromHWND(ByRef $hWin)
DLLCall("ole32.dll","int","CoInitialize","ptr",0)
If @error Then Return SetError(@error,@extended,0)
;changed from
;Local Const $WM_HTML_GETOBJECT = _RegisterWindowMessage("WM_HTML_GETOBJECT")
;...to
Local Const $WM_HTML_GETOBJECT = _RegisterWindowMessage("WM_GETOBJECT")

If @error Then Return SetError(@error,@extended,0)

Local Const $SMTO_ABORTIFHUNG = 0x0002
Local $lResult, $typUUID, $aRet, $oIE

_SendMessageTimeout($hWin, $WM_HTML_GETOBJECT, 0, 0, $SMTO_ABORTIFHUNG, 1000, $lResult)
If @error Then Return SetError(@error,@extended,0)

;changed from
;$typUUID = _WinAPI_GUIDFromString('{626FC520-A41E-11cf-A731-00A0C9082637}')
;...to
$typUUID = _WinAPI_GUIDFromString('{5F4DF280-531B-11CF-91F6-C2863C385E30}')
$aRet = DllCall("oleacc.dll", "int", "ObjectFromLresult", "int", $lResult, _
"ptr", DLLStructGetPtr($typUUID), "int", 0, "idispatch*", "")
If @error Then Return SetError(@error,@extended,0)
; If Not IsObj($aRet[4]) Then Return SetError(1,@extended,0)
;this fails with the error below - Script() is obviously wrong but have no clue what to put instead
$oIE = $aRet[4].Script()
; $oIE is now a valid IDispatch object
;Return $oIE.document.parentwindow
Return $oIE
EndFunc

err.number is: 2

err.windescription: Not an Object type

err.description is:

err.source is:

err.helpfile is:

err.helpcontext is: 0

err.lastdllerror is: 127

err.scriptline is: 56

err.retcode is: 0

Can anyone help?

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