如何获取嵌入式IE浏览器的COM对象?

发布于 2024-07-18 04:56:27 字数 5151 浏览 7 评论 0原文

如何将此函数从 AutoIt 的 IE.au3 UDF 转换为 Ruby? 目的是将 Watir 与 Internet Explorer 浏览器(嵌入到另一个应用程序中)一起使用。

AutoIt 函数工作正常,但我更喜欢 Watir(这是 Ruby)。 我可以使用 ControlGetHandle() 获取嵌入式浏览器的句柄,但 AutoIt dll 无法提供该句柄。

下面是要翻译的函数(还有另外两个我不需要的函数)。

;===============================================================================
;
; Function Name:    __IEControlGetObjFromHWND()
; Description:      Returns a COM Object Window reference to an embebedded Webbrowser control
; Parameter(s):     $hWin       - HWND of a Internet Explorer_Server1 control obtained for example:
;                   $hwnd = ControlGetHandle("MyApp","","Internet Explorer_Server1")
; Requirement(s):   Windows XP, Windows 2003 or higher.
;                   Windows 2000; Windows 98; Windows ME; Windows NT may install the
;                   Microsoft Active Accessibility 2.0 Redistributable:
;                   http://www.microsoft.com/downloads/details.aspx?FamilyId=9B14F6E1-888A-4F1D-B1A1-DA08EE4077DF&displaylang=en
; Return Value(s):  On Success  - Returns DOM Window object
;                   On Failure  - 0  and sets @ERROR = 1
; Author(s):        Larry with thanks to Valik
;
;===============================================================================

Func __IEControlGetObjFromHWND(ByRef $hWin)
    DllCall("ole32.dll", "int", "CoInitialize", "ptr", 0)
    Local Const $WM_HTML_GETOBJECT = __IERegisterWindowMessage("WM_HTML_GETOBJECT")
    Local Const $SMTO_ABORTIFHUNG = 0x0002
    Local $lResult, $typUUID, $aRet, $oIE
MsgBox(0, "msg", $WM_HTML_GETOBJECT)


    __IESendMessageTimeout($hWin, $WM_HTML_GETOBJECT, 0, 0, $SMTO_ABORTIFHUNG, 1000, $lResult)

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


    MsgBox(0, "lResult", $lResult)


    $aRet = DllCall("oleacc.dll", "long", "ObjectFromLresult", "lresult", $lResult, "ptr", DllStructGetPtr($typUUID), _
            "wparam", 0, "idispatch*", 0)
MsgBox(0, "aRet4", $aRet[4])
    If IsObj($aRet[4]) Then
        $oIE = $aRet[4] .Script()
        ; $oIE is now a valid IDispatch object
        Return $oIE.Document.parentwindow
    Else
        SetError(1)
        Return 0
    EndIf
EndFunc   ;==>__IEControlGetObjFromHWND
;===============================================================================
; Function Name:    __IERegisterWindowMessage()
; Description:      Required by __IEControlGetObjFromHWND()
; Author(s):        Larry with thanks to Valik
;===============================================================================
Func __IERegisterWindowMessage($sMsg)
    Local $aRet = DllCall("user32.dll", "int", "RegisterWindowMessage", "str", $sMsg)
    If @error Then Return SetError(@error, @extended, 0)
    Return $aRet[0]
EndFunc   ;==>__IERegisterWindowMessage

;===============================================================================
; Function Name:    __IESendMessageTimeout()
; Description:      Required by __IEControlGetObjFromHWND()
; Author(s):        Larry with thanks to Valik
;===============================================================================
Func __IESendMessageTimeout($hWnd, $msg, $wParam, $lParam, $nFlags, $nTimeout, ByRef $vOut, $r = 0, $t1 = "int", $t2 = "int")
    Local $aRet
    $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   ;==>__IESendMessageTimeout

到目前为止我的代码:

def get_control_from_hwnd(hnd)  
    Win32API.new("ole32", "CoInitialize", ['P'] , 'I').call(0)

    reg_msg = Win32API.new("user32", "RegisterWindowMessage", ['P'] ,'I').call("WM_HTML_GETOBJECT")
    puts "msg: " + reg_msg.to_s
    result=" "*16 
    aInt = [0xA7, 0x31, 0x0, 0xA0, 0xC9, 0x8, 0x26, 0x37].pack 'I*'
    a = [0x626FC520, 0xA41E, 0x11CF, aInt].pack 'IIIP'

    sendMessagetimeout = Win32API.new("user32", "SendMessageTimeout", ['L','I','I','I','I','I','P'] , 'L')
    sendMessagetimeout.call(hnd.hex, reg_msg, 0, 0, SMTO_ABORTIFHUNG, 1000, result)

    puts "result unpacked: " + result.unpack("L").to_s  #i can confirm this is the same as the lResult from the autoit functioin

    idisp=0 
    #the problem is likely either here or the next line afterwards
    oIE = Win32API.new("oleacc", "ObjectFromLresult", ['P','P','I','P'] , 'L')

    oIE.call(result, a, 0, idisp)
    puts "idisp: " + idisp.to_s
    # returning zero
    puts idisp.unpack("L")  

end

How to translate this function from AutoIt's IE.au3 UDF to Ruby? Intention is to use Watir with an Internet Explorer browser (embedded in another application).

The AutoIt function works fine but I prefer Watir (which is Ruby). I can get the handle of the embedded browser using ControlGetHandle(), which is not available from the AutoIt dll.

Below is the function to translate (also 2 others which I don't need).

;===============================================================================
;
; Function Name:    __IEControlGetObjFromHWND()
; Description:      Returns a COM Object Window reference to an embebedded Webbrowser control
; Parameter(s):     $hWin       - HWND of a Internet Explorer_Server1 control obtained for example:
;                   $hwnd = ControlGetHandle("MyApp","","Internet Explorer_Server1")
; Requirement(s):   Windows XP, Windows 2003 or higher.
;                   Windows 2000; Windows 98; Windows ME; Windows NT may install the
;                   Microsoft Active Accessibility 2.0 Redistributable:
;                   http://www.microsoft.com/downloads/details.aspx?FamilyId=9B14F6E1-888A-4F1D-B1A1-DA08EE4077DF&displaylang=en
; Return Value(s):  On Success  - Returns DOM Window object
;                   On Failure  - 0  and sets @ERROR = 1
; Author(s):        Larry with thanks to Valik
;
;===============================================================================

Func __IEControlGetObjFromHWND(ByRef $hWin)
    DllCall("ole32.dll", "int", "CoInitialize", "ptr", 0)
    Local Const $WM_HTML_GETOBJECT = __IERegisterWindowMessage("WM_HTML_GETOBJECT")
    Local Const $SMTO_ABORTIFHUNG = 0x0002
    Local $lResult, $typUUID, $aRet, $oIE
MsgBox(0, "msg", $WM_HTML_GETOBJECT)


    __IESendMessageTimeout($hWin, $WM_HTML_GETOBJECT, 0, 0, $SMTO_ABORTIFHUNG, 1000, $lResult)

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


    MsgBox(0, "lResult", $lResult)


    $aRet = DllCall("oleacc.dll", "long", "ObjectFromLresult", "lresult", $lResult, "ptr", DllStructGetPtr($typUUID), _
            "wparam", 0, "idispatch*", 0)
MsgBox(0, "aRet4", $aRet[4])
    If IsObj($aRet[4]) Then
        $oIE = $aRet[4] .Script()
        ; $oIE is now a valid IDispatch object
        Return $oIE.Document.parentwindow
    Else
        SetError(1)
        Return 0
    EndIf
EndFunc   ;==>__IEControlGetObjFromHWND
;===============================================================================
; Function Name:    __IERegisterWindowMessage()
; Description:      Required by __IEControlGetObjFromHWND()
; Author(s):        Larry with thanks to Valik
;===============================================================================
Func __IERegisterWindowMessage($sMsg)
    Local $aRet = DllCall("user32.dll", "int", "RegisterWindowMessage", "str", $sMsg)
    If @error Then Return SetError(@error, @extended, 0)
    Return $aRet[0]
EndFunc   ;==>__IERegisterWindowMessage

;===============================================================================
; Function Name:    __IESendMessageTimeout()
; Description:      Required by __IEControlGetObjFromHWND()
; Author(s):        Larry with thanks to Valik
;===============================================================================
Func __IESendMessageTimeout($hWnd, $msg, $wParam, $lParam, $nFlags, $nTimeout, ByRef $vOut, $r = 0, $t1 = "int", $t2 = "int")
    Local $aRet
    $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   ;==>__IESendMessageTimeout

My code so far:

def get_control_from_hwnd(hnd)  
    Win32API.new("ole32", "CoInitialize", ['P'] , 'I').call(0)

    reg_msg = Win32API.new("user32", "RegisterWindowMessage", ['P'] ,'I').call("WM_HTML_GETOBJECT")
    puts "msg: " + reg_msg.to_s
    result=" "*16 
    aInt = [0xA7, 0x31, 0x0, 0xA0, 0xC9, 0x8, 0x26, 0x37].pack 'I*'
    a = [0x626FC520, 0xA41E, 0x11CF, aInt].pack 'IIIP'

    sendMessagetimeout = Win32API.new("user32", "SendMessageTimeout", ['L','I','I','I','I','I','P'] , 'L')
    sendMessagetimeout.call(hnd.hex, reg_msg, 0, 0, SMTO_ABORTIFHUNG, 1000, result)

    puts "result unpacked: " + result.unpack("L").to_s  #i can confirm this is the same as the lResult from the autoit functioin

    idisp=0 
    #the problem is likely either here or the next line afterwards
    oIE = Win32API.new("oleacc", "ObjectFromLresult", ['P','P','I','P'] , 'L')

    oIE.call(result, a, 0, idisp)
    puts "idisp: " + idisp.to_s
    # returning zero
    puts idisp.unpack("L")  

end

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

似梦非梦 2024-07-25 04:56:27

不敢相信我们正在做同样的事情,尽管我正在尝试用 Perl 来做。 我不知道 Ruby,但看看脚本,它看起来几乎与 Perl 类似。 看看 autoIt 上的这个帖子,我仍在尝试解决这个问题 http://www.autoitscript.com/forum/index.php?showtopic=104894。 但我想我可能已经得到了idisp。 两个变化:

1)我打包结构的方式有点不同。 我的 $iid 看起来像这样:
包('LSSC8',0x626FC520,0xA41E,0x11CF,0xA7,0x31,0x00,0xA0,0xC9,0x08,0x26,0x37)。 所以在Ruby中我猜它是[0x626FC520,0xA41E,0x11CF,0xA7,0x31,0x00,0xA0,0xC9,0x08,0x26,0x37].pack'LSSC8'? 我不知道正确的语法,但你明白了。
2)我从SendMessageTimeout & 中解压“结果”; 然后将其传递给 ObjectFromLresult。 如果我直接传递结果,我会得到 0,就像你得到的一样。

但我目前就到此为止了。

Can't believe we are doing the same, albeit I'm trying to do it in Perl. I dunno Ruby but looking at the script, it almost looks like similar to Perl. Take a look at this thread at autoIt, where I am still trying to tackle the issue http://www.autoitscript.com/forum/index.php?showtopic=104894. But I think I might have gotten the idisp though. Two changes:

1) The way I am packing the struct is a bit different. My $iid looks like this:
pack('LSSC8',0x626FC520,0xA41E,0x11CF,0xA7,0x31,0x00,0xA0,0xC9,0x08,0x26,0x37). So in Ruby I guess it'd be [0x626FC520,0xA41E,0x11CF,0xA7,0x31,0x00,0xA0,0xC9,0x08,0x26,0x37].pack 'LSSC8'? I dunno the right syntax, but you get the idea.
2) I unpack the "result" from SendMessageTimeout & then pass it to ObjectFromLresult. If I pass the result directly, I get 0 as you were getting it.

But that is as far as I've gone.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文