VB6 控制IE弹出模式窗口

前端之家收集整理的这篇文章主要介绍了VB6 控制IE弹出模式窗口前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

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

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

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

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

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

关键代码如下:

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

此时标准模块中的CallWndRetProc开始工作了,代码如下(省略部门代码的声名):
  1. Public Function CallWndRetProc(ByVal code As Long,ByVal wParam As Long,ByVal lParam As Long) As Long
  2. On Error GoTo ErrorLine
  3. Dim hwnd As Long
  4. Dim script As MSHTML.HTMLScriptElement
  5. If code <> 0 Then
  6. CallWndRetProc = CallNextHookEx(hWndRetProcHook,code,wParam,lParam)
  7. Exit Function
  8. End If
  9. CopyMemory hCWPRETSTRUCT,ByVal lParam,LenB(hCWPRETSTRUCT)
  1. If hCWPRETSTRUCT.Message = WM_PARENTNOTIFY Then
  2. Debug.Print hCWPRETSTRUCT.wParam,hCWPRETSTRUCT.hwnd
  3. If hCWPRETSTRUCT.wParam = WM_CREATE Then
  4. EnumChildWindows hCWPRETSTRUCT.hwnd,AddressOf EnumChildProc,hwnd
  1. '注意到以下代码都是注释的,实际项目中已经删除了,这里留下只为演示,后面解释为什么要注释掉.
  2. ' If hwnd = 0 Then
  3. ' MsgBox "获取浏览器信息失败,请重试.",vbExclamation
  4. ' Exit Function
  5. ' End If
  1. ' Set NewhtmlDOM = IEDOMFromhWnd(hwnd)
  2. ' If Not (NewhtmlDOM Is Nothing) Then
  3. ' Set script = NewhtmlDOM.createElement("Script")
  4. ' script.Text = "var getCardScript = function(){" & vbCrLf & _
  5. ' " getScrapCardScript();" & vbCrLf & _
  6. ' " }" & vbCrLf & _
  7. ' " var refreshCard =function(){" & vbCrLf & _
  8. ' " if(hasErrMsg()) {" & vbCrLf & _
  9. ' " return;" & vbCrLf & _
  10. ' " }" & vbCrLf & _
  11. ' " writeFlag=true;" & vbCrLf & _
  12. ' " var noticeInfo={};" & vbCrLf & _
  13. ' " // Comments 字段在下发时设置具体的错误信息" & vbCrLf & _
  14. ' " if(writeFlag==true){" & vbCrLf & _
  15. ' " noticeInfo.Result=""1"";" & vbCrLf & _
  16. ' " //noticeInfo.Comments=""成功"";" & vbCrLf & _
  17. ' " }" & vbCrLf & _
  18. ' " else{" & vbCrLf & _
  19. ' " noticeInfo.Result=""2"";" & vbCrLf & _
  20. ' " noticeInfo.ErrorCode=writeFlag;" & vbCrLf & _
  21. ' " //noticeInfo.Comments=""失败"";" & vbCrLf & _
  22. ' " }" & vbCrLf & _
  23. ' " addBizState(""noticeInfo"",noticeInfo);" & vbCrLf & _
  24. ' " scrapCardReturnNotice();" & vbCrLf & _
  25. ' " }"
  26. ' script.language = "Javascript"
  27. ' 'Debug.Print InStr(0,"authKey",htmlDOM.scripts(5).Text,vbTextCompare)
  28. ' While NewhtmlDOM.ReadyState <> "complete"
  29. ' DoEvents
  30. ' Wend
  31. ' NewhtmlDOM.body.appendChild script
  32. ' Else
  33. ' MsgBox "获取浏览对象失败.",vbExclamation
  34. ' End If
  35. 'UnhookWindowsHookEx hWndRetProcHook
  36. End If
  37. End If
  38. CallWndRetProc = CallNextHookEx(hWndRetProcHook,lParam)
  39. Exit Function
  40. ErrorLine:
  41. MsgBox "发生异常." & Err.Description,vbCritical
  42. CallWndRetProc = CallNextHookEx(hWndRetProcHook,lParam)
  43. 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子程.

  1. Function EnumChildProc(ByVal hwnd As Long,ByRef lParam As Long) As Long
  2. Dim script As MSHTML.HTMLScriptElement
  3. If IsIEServerWindow(hwnd) Then
  4. lParam = hwnd
  1. '找到句柄后,将句柄转换成Document对象.
  2. Set NewhtmlDOM = IEDOMFromhWnd(hwnd)
  3. If Not (NewhtmlDOM Is Nothing) Then
  4. Set script = NewhtmlDOM.createElement("Script")
  1. '下面重写网页中的代码.
  1. script.Text = "var getCardScript = function(){" & vbCrLf & _
  2. " getScrapCardScript();" & vbCrLf & _
  3. " }" & vbCrLf & _
  4. " var refreshCard =function(){" & vbCrLf & _
  5. " if(hasErrMsg()) {" & vbCrLf & _
  6. " return;" & vbCrLf & _
  7. " }" & vbCrLf & _
  8. " writeFlag=true;" & vbCrLf & _
  9. " var noticeInfo={};" & vbCrLf & _
  10. " // Comments 字段在下发时设置具体的错误信息" & vbCrLf & _
  11. " if(writeFlag==true){" & vbCrLf & _
  12. " noticeInfo.Result=""1"";" & vbCrLf & _
  13. " //noticeInfo.Comments=""成功"";" & vbCrLf & _
  14. " }" & vbCrLf & _
  15. " else{" & vbCrLf & _
  16. " noticeInfo.Result=""2"";" & vbCrLf & _
  17. " noticeInfo.ErrorCode=writeFlag;" & vbCrLf & _
  18. " //noticeInfo.Comments=""失败"";" & vbCrLf & _
  19. " }" & vbCrLf & _
  20. " addBizState(""noticeInfo"",noticeInfo);" & vbCrLf & _
  21. " scrapCardReturnNotice();" & vbCrLf & _
  22. " }"
  23. script.language = "Javascript"
  24. 'Debug.Print InStr(0,vbTextCompare)
  1. '下面这段必不可少.因为获得句柄和Document对象是相当短暂的,网页根本未加载完全,无法重写代码的,所以必须等待网页加载完成,再重写页面代码.
  2. While NewhtmlDOM.ReadyState <> "complete"
  3. DoEvents
  4. Wend
  5. NewhtmlDOM.body.appendChild script
  6. Else
  7. MsgBox "获取浏览对象失败.",vbExclamation
  8. End If
  9. EnumChildProc = 0
  10. Else
  11. EnumChildProc = 1
  12. End If
  13. End Function
下面贴出句柄转换成Document对象的方法
  1. '判断是否浏览器控件
  1. Function IsIEServerWindow(ByVal hwnd As Long) As Boolean
  2. '判断是否是浏览器控件
  3. Dim lRes As Long
  4. Dim sClassName As String
  5. sClassName = String(100,0)
  6. lRes = GetClassName(hwnd,sClassName,Len(sClassName))
  7. sClassName = Left(sClassName,lRes)
  8. IsIEServerWindow = StrComp(sClassName,"Internet Explorer_Server",vbTextCompare) = 0
  9. End Function
  10.  
  11.  
  12. Function IEDOMFromhWnd(ByRef hwnd As Long) As IHTMLDocument
  13. '通过句柄得到DOM对象
  14. Dim IID_IHTMLDocument As olelib.UUID
  15. Dim hWndChild As Long
  16. Dim lRes As Long
  17. Dim lMsg As Long
  18. Dim hr As Long
  19. Set IEDOMFromhWnd = Nothing
  20. If hwnd <> 0 Then
  21. 'If Not IsIEServerWindow(hwnd) Then
  22. ' EnumChildWindows hwnd,hwnd
  23. 'End If
  24. If IsIEServerWindow(hwnd) Then
  25. '注册消息
  26. lMsg = RegisterWindowMessage("WM_HTML_GETOBJECT")
  27. '发送消息
  28. SendMessageTimeout hwnd,lMsg,SMTO_ABORTIFHUNG,1000,lRes
  29. 'MsgBox "lRes" & lRes
  30. If lRes Then
  31. With IID_IHTMLDocument
  32. .Data1 = &H626FC520 '编码
  33. .Data2 = &HA41E
  34. .Data3 = &H11CF
  35. .Data4(0) = &HA7
  36. .Data4(1) = &H31
  37. .Data4(2) = &H0
  38. .Data4(3) = &HA0
  39. .Data4(4) = &HC9
  40. .Data4(5) = &H8
  41. .Data4(6) = &H26
  42. .Data4(7) = &H37
  43. End With
  1. hr = ObjectFromLresult(lRes,IID_IHTMLDocument,IEDOMFromhWnd)
  2. 'MsgBox "HR:" & hr
  3. End If
  4. End If
  5. End If
  6. End Function
这里利用Active Accessibility组件获取的Document对象.

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

猜你在找的VB相关文章