VB6 控制IE弹出模式窗口

最近一个小项目,开发一个插件,需要对一个第三方系统的网页内容进行操作.操作的内容还比较复杂.自然选择用BHO做.

做到一半卡住了,原因在于这个网站有一个showmodal的模式窗口,需要对这个弹出的模式窗口也进行控制.

但是找遍了DOM和IE的各个接口也没找到能控制或捕获弹出窗口内容的东西.

虽然可以重写弹出窗口的代码,改用window.open方式弹出,再进行捕获,但因为那网站的弹出窗口还带了复杂的参数,不方便转换,所以保持不能改他的代码.

既然从IE方向无法下手,就只能改变方向,从Windows窗口方向下手.因为弹出窗口也是窗口,可以进行捕获弹出窗口句柄,然后遍历出Webbrowser控制句柄,再转换成Document对象.得到Document对象就可以对网页进行随意控制了.

关键代码如下:

'BHO类中下勾子
hWndRetProcHook = SetWindowsHookEx(HookType.WH_CALLWNDPROCRET, AddressOf modCallback.CallWndRetProc, 0, App.ThreadID)
'再手工弹出模式窗口.
htmlDOM.parentWindow.execScript "btnReNewCard()", "JScript"

此时标准模块中的CallWndRetProc开始工作了,代码如下(省略部门代码的声名):

Public Function CallWndRetProc(ByVal code As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    On Error GoTo ErrorLine
    Dim hwnd As Long
    Dim script As MSHTML.HTMLScriptElement
    If code <> 0 Then
      CallWndRetProc = CallNextHookEx(hWndRetProcHook, code, wParam, lParam)
      Exit Function
    End If
    CopyMemory hCWPRETSTRUCT, ByVal lParam, LenB(hCWPRETSTRUCT)
    If hCWPRETSTRUCT.Message = WM_PARENTNOTIFY Then
        Debug.Print hCWPRETSTRUCT.wParam, hCWPRETSTRUCT.hwnd
        If hCWPRETSTRUCT.wParam = WM_CREATE Then
            EnumChildWindows hCWPRETSTRUCT.hwnd, AddressOf EnumChildProc, hwnd
'注意到以下代码都是注释的,实际项目中已经删除了,这里留下只为演示,后面解释为什么要注释掉.
'            If hwnd = 0 Then
'                MsgBox "获取浏览器信息失败,请重试.", vbExclamation
'                Exit Function
'            End If
'	Set NewhtmlDOM = IEDOMFromhWnd(hwnd)
'        If Not (NewhtmlDOM Is Nothing) Then
'            Set script = NewhtmlDOM.createElement("Script")
'            script.Text = "var getCardScript = function(){" & vbCrLf & _
'                      "            getScrapCardScript();" & vbCrLf & _
'                      "          }" & vbCrLf & _
'                      "  var refreshCard =function(){" & vbCrLf & _
'                      "              if(hasErrMsg()) {" & vbCrLf & _
'                      "                  return;" & vbCrLf & _
'                      "              }" & vbCrLf & _
'                      "          writeFlag=true;" & vbCrLf & _
'                      "              var noticeInfo={};" & vbCrLf & _
'                      "              // Comments 字段在下发时设置具体的错误信息" & vbCrLf & _
'                      "              if(writeFlag==true){" & vbCrLf & _
'                      "                noticeInfo.Result=""1"";" & vbCrLf & _
'                      "                //noticeInfo.Comments=""成功"";" & vbCrLf & _
'                      "              }" & vbCrLf & _
'                      "              else{" & vbCrLf & _
'                      "                noticeInfo.Result=""2"";" & vbCrLf & _
'                      "                noticeInfo.ErrorCode=writeFlag;" & vbCrLf & _
'                      "                //noticeInfo.Comments=""失败"";" & vbCrLf & _
'                      "              }" & vbCrLf & _
'                      "              addBizState(""noticeInfo"",noticeInfo);" & vbCrLf & _
'                      "              scrapCardReturnNotice();" & vbCrLf & _
'                      "          }"
'            script.language = "Javascript"
'                'Debug.Print InStr(0, "authKey", htmlDOM.scripts(5).Text, vbTextCompare)
'            While NewhtmlDOM.ReadyState <> "complete"
'                DoEvents
'            Wend
'            NewhtmlDOM.body.appendChild script
'        Else
'            MsgBox "获取浏览对象失败.", vbExclamation
'        End If
            'UnhookWindowsHookEx hWndRetProcHook
        End If
    End If
    CallWndRetProc = CallNextHookEx(hWndRetProcHook, code, wParam, lParam)
    Exit Function
ErrorLine:
    MsgBox "发生异常." & Err.Description, vbCritical
    CallWndRetProc = CallNextHookEx(hWndRetProcHook, code, wParam, lParam)
End Function
因为IE的ShowModal方法弹出窗口会产生WM_PARENTNOTIFY消息和WM_Create消息,所以只对这两个消息进行监控.监控到弹出窗口后,就用EnumChildWindows遍历弹出窗口的所有子窗口,以得到Webbrowser的句柄.在上面的代码中看到,EnumChildWindows后有大片的注释代码.

我的原意是想用EnumChildWindows的最后一个参数来输出EnumWindowProc子程查找到的Webbrowser句柄,我将这个参数声名为byref.这段代码在我Win7下运行正常,并且输出了Webbrowser句柄.但是当项目完成后移到WindowsXP测试时,居然无法输出遍历得到的句柄了.MSDN中没说这个参数只能输入不能输出啊!而且我在Win7下运行相当正确啊,百思不得其解.

一开始以为是user32.dll版本问题,将WIN7的这个文件复制到XP的DLL和IE根目录下,问题依旧存在,所以无奈,只能取消用EnumChildWindows返回句柄的方式,改在EnumWindowProc子程中处理,于是注释上上面那段代码.

另外有注意到,上面代码中,取消Hook的代码是单独一行注释的,我的本意是,在获得完Webbrowser控件后就unhook,这句代码在WIN7运行的也是相当好,但是转到XP就不行了,所以也注释了这行代码,改到后面unhook.

下面是EnumWindowProc子程.

Function EnumChildProc(ByVal hwnd As Long, ByRef lParam As Long) As Long
    Dim script As MSHTML.HTMLScriptElement
    If IsIEServerWindow(hwnd) Then
        lParam = hwnd
	'找到句柄后,将句柄转换成Document对象.
        Set NewhtmlDOM = IEDOMFromhWnd(hwnd)
        If Not (NewhtmlDOM Is Nothing) Then
            Set script = NewhtmlDOM.createElement("Script")
	'下面重写网页中的代码.
            script.Text = "var getCardScript = function(){" & vbCrLf & _
                      "            getScrapCardScript();" & vbCrLf & _
                      "          }" & vbCrLf & _
                      "  var refreshCard =function(){" & vbCrLf & _
                      "              if(hasErrMsg()) {" & vbCrLf & _
                      "                  return;" & vbCrLf & _
                      "              }" & vbCrLf & _
                      "          writeFlag=true;" & vbCrLf & _
                      "              var noticeInfo={};" & vbCrLf & _
                      "              // Comments 字段在下发时设置具体的错误信息" & vbCrLf & _
                      "              if(writeFlag==true){" & vbCrLf & _
                      "                noticeInfo.Result=""1"";" & vbCrLf & _
                      "                //noticeInfo.Comments=""成功"";" & vbCrLf & _
                      "              }" & vbCrLf & _
                      "              else{" & vbCrLf & _
                      "                noticeInfo.Result=""2"";" & vbCrLf & _
                      "                noticeInfo.ErrorCode=writeFlag;" & vbCrLf & _
                      "                //noticeInfo.Comments=""失败"";" & vbCrLf & _
                      "              }" & vbCrLf & _
                      "              addBizState(""noticeInfo"",noticeInfo);" & vbCrLf & _
                      "              scrapCardReturnNotice();" & vbCrLf & _
                      "          }"
            script.language = "Javascript"
                'Debug.Print InStr(0, "authKey", htmlDOM.scripts(5).Text, vbTextCompare)
	'下面这段必不可少.因为获得句柄和Document对象是相当短暂的,网页根本未加载完全,无法重写代码的,所以必须等待网页加载完成,再重写页面代码.
            While NewhtmlDOM.ReadyState <> "complete"
                DoEvents
            Wend
            NewhtmlDOM.body.appendChild script
        Else
            MsgBox "获取浏览对象失败.", vbExclamation
        End If
        EnumChildProc = 0
    Else
        EnumChildProc = 1
    End If
End Function
下面贴出句柄转换成Document对象的方法

'判断是否浏览器控件
Function IsIEServerWindow(ByVal hwnd As Long) As Boolean
    '判断是否是浏览器控件
    Dim lRes As Long
    Dim sClassName As String
    sClassName = String(100, 0)
    lRes = GetClassName(hwnd, sClassName, Len(sClassName))
    sClassName = Left(sClassName, lRes)
    IsIEServerWindow = StrComp(sClassName, "Internet Explorer_Server", vbTextCompare) = 0
End Function


Function IEDOMFromhWnd(ByRef hwnd As Long) As IHTMLDocument
'通过句柄得到DOM对象
Dim IID_IHTMLDocument As olelib.UUID
 
Dim hWndChild As Long
Dim lRes As Long
Dim lMsg As Long
Dim hr As Long
Set IEDOMFromhWnd = Nothing
If hwnd <> 0 Then
    'If Not IsIEServerWindow(hwnd) Then
    '    EnumChildWindows hwnd, AddressOf EnumChildProc, hwnd
    'End If
    If IsIEServerWindow(hwnd) Then
        '注册消息
        lMsg = RegisterWindowMessage("WM_HTML_GETOBJECT")
        '发送消息
        SendMessageTimeout hwnd, lMsg, 0, 0, SMTO_ABORTIFHUNG, 1000, lRes
        'MsgBox "lRes" & lRes
        If lRes Then
            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
            hr = ObjectFromLresult(lRes, IID_IHTMLDocument, 0, IEDOMFromhWnd)
            'MsgBox "HR:" & hr
        End If
    End If
End If
End Function
这里利用Active Accessibility组件获取的Document对象.

通过上面的代码就完成了对IE弹出模块窗口的控制.其中WIN7和XP下调用API的一些差别让我走了不少弯路,现在还不明白这些差异是如何产生的,希望了解真相的人士指点一二.

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
源代码推荐——VB实现IE下载管理器扩展 ------ 摘要 这个例子演示了如何实现一个自定义IE下载管理器,当IE下载一个文件,VBWebDownloader.exe就会启动来下载它。 (这个项目支持断点续传,而且代码相对简单) 注意:一些第三方的IE下载扩展可能会和这个例子程序冲突,所以在尝试这个例子之前最好临时屏蔽它们。 安装/卸载 A. 安装 对于32bit系统,或者32bit IE运行在54bit系统,安装 VBIEDownloadManagerSetup(x86) 项目输出的VBIEDownloadManagerSetup(x86).msi。对于 64bit IE安装 VBIEDownloadManagerSetup(x64) 项目输出的 VBIEDownloadManagerSetup(x64).msi。 B. 卸载 运行安装时候所用的那个安装程序,并且选择卸载。 演示:(不翻译了,自己看吧) Step1. Open this project in VS2010 and set the platform of the solution to x86. Make sure that the projects VBIEDownloadManagerSetup, VBWebDownloader and VBIEDownloadManagerSetup(x86) are selected to build in Configuration Manager. NOTE: If you want to run this sample in 64bit IE, set the platform to x64 and select VBIEDownloadManagerSetup, VBWebDownloader and VBIEDownloadManagerSetup(x64) to build. Step2. 生成解决方案 Step3. Right click the project VBIEDownloadManagerSetup(x86) in Solution Explorer, and choose "Install". Step4. Open 32bit IE and visit the the download link of Microsoft .NET Framework 4 http://www.microsoft.com/downloads/en/details.aspx?displaylang=en&FamilyID=0a391abd-25c1-4fc0-919f-b21f31ab88b7. Click the "Download" button on this page, and then VBWebDownloader.exe will be launched. In VBWebDownloader.exe, you will find that the url is http://download.microsoft.com/download/9/5/A/95A9616B-7A37-4AF6-BC36-D6EA96C8DAAE/dotNetFx40_Full_x86_x64.exe and the local path is D:\dotNetFx40_Full_x86_x64.exe Step5. Click the button "Download" in VBWebDownloader.exe, it will start to download the file, and after a few minutes, you will find a file D:\dotNetFx40_Full_x86_x64.exe in Windows Explorer. 下载: http://code.msdn.microsoft.com/VBIEDownloadManager-3287b087

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值