CHtmlView的通信机制_chtmlview 自动-程序员宅基地

技术标签: 文档  多线程  WIN32界面编程  socket  windows  microsoft  user  

IWebBrowser2是microsoft提供的web浏览器控件, 它也是IE使用的内核,功能非常强大。在http客户端程序中,使用IWebBrowser2可以简化对http通信过程的处理,并将html文档解析成一个对象结构。IWebBrowser2是一个ActiveX控件和COM接口,直接使用比较复杂。CHtmlView是MFC对IWebBrowser2的封装,提供了更为简化的编程模型。尽管如此,程序员必须对底层的通信机制有基本的理解,才能正确地使用CHtmlView。
我们可以把http客户端与服务端的通信过程看成一个发送接收序列:

Send(1), Receive(1), Send(2),Receive(2) ….

客户端在每次发送和接收的时候都必须清楚当前的状态,才能逐步完成一个功能,比如为了上传一个文件,应该先登录一个账号,再获取上传页面,然后提交要上传的文件,整个过程是有序的。当客户端响应用户请求时,也必须清楚当前的通信状态,比如账号已经登录时,就不再响应登录请求。

在CHtmlView中有两个主要的方法:Navigate2()用来打开一个URL,OnDocumentComplete()在文档接收完时调用。Navigate2()执行以后程序不必等待,而是可以做其它事情,文档接收完成时OnDocumentComplete()自动被调用。感觉上这样的模型是很合理的,为了编写程序,还必须对它有确切的理解。主要的一个问题是,存不存在多线程,特别是,Navigate2()和OnDocumentComplete()是否在一个线程中执行? 因为对单线程的情况,有一种简单的方法来跟踪通信状态:用一个全局变量,在发送接收序列的第一步将其初始化,以后每一步将其加1,它的值就反映了状态。而多线程时,事情会变复杂。此外,这个模型涉及到一些基本概念和重要的机制,也非常值得了解。

追究IwebBrowser2的通信进制涉及到若干技术主题: Berkley socket通信模型,异步通信模型, COM连接点机制,ActiveX控件和包容器的通信,Windows程序模型。虽然没有源代码和官方的文档,无法确定IwebBrowser2的具体实现方式。但通过查阅有关的资料,可以整理出大体的概念,初步结果如下:

1.       Berkley socket通信模型,异步通信模型

传统的Berkley socket使用的是同步模型,用recv()接收数据时,如果没有数据,调用会阻塞,可以用select()检查socket状态,避免阻塞,但又必须忙等待,这都不符合CHtmlView的通信模型。recv()和select()的说明可以参考MSDN文档。

一种可能的实现方式是使用Windows提供的扩展socket API,WSAAsyncSelect()将socket和调用后立即返回,当数据到达时,以Windows消息的方式通知线程。可以参考MSDN中关于WSAAsyncSelect()的文档。

在传统socket基础上实现异步通信模型需要使用多线程,大体说就是在主线程中启动发送过程,随即返回进行其它处理,另一个线程负责跟踪,当数据接收完成时通知主线程,跟踪线程是可以阻塞的。MSDN文档《using an asyncronous client socket》(http://msdn.microsoft.com/en-us/library/bbx2eya8.aspx)讲解了DotNet框架中的异步socket模型。

2.       COM连接点机制,ActiveX控件和包容器的通信

在IWebBrowser实现了异步通信的基础上,它还必须通知控件的调用者,这里使用了COM的连接点机制,我们知道COM组件提供接口给客户调用,但这是单向的,通过在调用方实现COM组件支持的出接口,调用方可以收到COM组件的通知,进一步内容可以参考潘爱明的《COM原理和应用》第6和12章。这里需要知道COM组件是在调用方线程中执行,除非它执行时又创建了新的线程。

3.       Windows消息模型

Windows程序是基于消息的,简单说,它有一个消息循环不断从消息队列中取消息,发给窗口过程来响应,执行响应过程中,某些系统调用可能会产生不进队消息,这些消息立即被处理,只要窗口过程是可重入的。不管怎么说,这是一个单线程模型,线程入口函数中包含了消息循环,所有的代码都必须通过消息执行。关于Windows程序模型,可以参考Petzold的《Windows程序设计》第1章。

现在我们考虑为了实现CHtmlView的通信模型,以上三种机制如何协作。

首先,需要确定Navigate2()和OnDocumentComplete()是否在同一线程中执行。如果在OoDocumentComplete()加入一个消息框,而在调用Navigate2()之后执行一个无限循环,则无论等多久,该消息框都不会弹出。这说明OnDocumentComplete()不是在另外一个线程中执行的。

然后,通过CHtmlView的源代码容易知道OnDocumentComplete()是通过COM连接点机制被调用的,从而IWebBrowser2中负责调用的代码也是在同一线程中执行的。我们可以想到,在IWebBrowser2中还有一个线程负责跟踪http通信,或者IWebBrowser2没有创建新线程,但是用WSAAsyncSelect()为socket注册了消息,Windows会以消息形式通知线程。如果存在跟踪线程,它怎样和主线程通信呢,若干线程通信手段,如事件,信号量,都需要等待一方阻塞,这不符合CHtmlView的使用模型,唯一的可能是跟踪线程向主线程发消息。

用CHtmlView编写一个浏览器程序,在OnDocumentComplete()中打断点,如下是调用栈。

 

CHtmlView_tView::OnDocumentComplete(const char * 0x003864cc) line 105

CHtmlView::DocumentComplete(IDispatch * 0x0015cee0, tagVARIANT * 0x0012f560 {"http://www.google.cn/" VT_BSTR}) line 680

_AfxDispatchCall(void (void)* 0x5f599c20, void (void)* 0x5f599c20, void (void)* 0x5f599c20) line 43

CCmdTarget::OnEvent(unsigned int 59648, AFX_EVENT * 0x0012f330, AFX_CMDHANDLERINFO * 0x00000000) line 95 + 58 bytes

COccManager::OnEvent(CCmdTarget * 0x003850f0 {CHtmlView_tView}, unsigned int 59648, AFX_EVENT * 0x0012f330, AFX_CMDHANDLERINFO * 0x00000000) line 138

CCmdTarget::OnCmdMsg(unsigned int 59648, int -2, void * 0x0012f330, AFX_CMDHANDLERINFO * 0x00000000) line 208 + 41 bytes

CView::OnCmdMsg(unsigned int 59648, int -2, void * 0x0012f330, AFX_CMDHANDLERINFO * 0x00000000) line 162 + 24 bytes

COleControlSite::OnEvent(AFX_EVENT * 0x0012f330) line 944

COleControlSite::XEventSink::Invoke(COleControlSite::XEventSink * const 0x00385428, long 259, const _GUID & {00000000-0000-0000-0000-000000000000}, const _GUID & {00000000-0000-0000-0000-000000000000}, unsigned short 1, tagDISPPARAMS * 0x0012f510, tagVARIANT * 0x00000000 {???}, tagEXCEPINFO * 0x00000000, unsigned int * 0x00000000) line 1952

SHLWAPI! 77f62559()

SHLWAPI! 77f55e62()

SHLWAPI! 77f55dd6()

SHLWAPI! 77f55fcc()

SHDOCVW! 7e56804b()

SHDOCVW! 7e575951()

SHDOCVW! 7e578cb3()

MSHTML! 7e2a229e()

MSHTML! 7e2a30cc()

MSHTML! 7e2a2f1a()

MSHTML! 7e27ea9c()

MSHTML! 7e27e7a5()

MSHTML! 7e27cb3b()

MSHTML! 7e278937()

USER32! 77d18734()

USER32! 77d18816()

USER32! 77d2a013()

USER32! 77d2a998()

_AfxActivationWndProc(HWND__ * 0x000202f4, unsigned int 32770, unsigned int 0, long 0) line 439 + 26 bytes

USER32! 77d18734()

USER32! 77d18816()

USER32! 77d189cd()

USER32! 77d196c7()

CWinThread::PumpMessage() line 853

CWinThread::Run() line 487 + 11 bytes

CWinApp::Run() line 400

AfxWinMain(HINSTANCE__ * 0x00400000, HINSTANCE__ * 0x00000000, char * 0x00141f09, int 1) line 49 + 11 bytes

WinMain(HINSTANCE__ * 0x00400000, HINSTANCE__ * 0x00000000, char * 0x00141f09, int 1) line 30

WinMainCRTStartup() line 330 + 54 bytes

KERNEL32! 7c817067()

 
 

 

SHDOCVW是IWebBrowser2所在的DLL,CWinThread::PumpMessage()是MFC封装的消息循环。从上面的调用栈可以看出,当OnDocumentComplete()被调用时,确实是主线程先收到消息,再由IWebBrowser2控件处理,由IWebBrowser2最后调用到CHtmlView::DocumentComplete()。

 

本文来自程序员宅基地,转载请标明出处:http://blog.csdn.net/zliner/archive/2008/10/19/3100668.aspx

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/zhuzhubin/article/details/4298956

智能推荐

全新好用的窗口置顶工具WindowTop-程序员宅基地

文章浏览阅读3.5k次。全局快捷键功能可以配置窗口置顶,透明,穿透,画中画,截图等功能,而鼠标快捷键操作可以配置在对应窗口连续点击执行置顶窗口,窗口移动,最大化,最小化等操作。打开WindowTop软件,所有已打开的窗口都会在左上角出现一个置顶栏,点击置顶栏的置顶复选框即可置顶窗口或取消窗口。输入法提示功能可以在置顶栏实时显示输入法的状态,又或者以独立的小窗口显示。屏幕截图,窗口截图,支持自由编辑画图,并能将截图以贴图的方式贴在屏幕上。可改变置顶栏的外观,还可以自由拖动置顶栏到想要的位置。_windowtop

felx的使用_felx: 0 0 0-程序员宅基地

文章浏览阅读246次。flex的使用Flex 布局是什么?Flex 是 Flexible Box 的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性。任何一个容器都可以指定为 Flex 布局。.box{ display: flex;}行内元素也可以使用 Flex 布局。.box{ display: inline-flex;}Webkit 内核的浏览器,必须加上-webkit前缀。.box{ display: -webkit-flex; /* Safari */ display: f_felx: 0 0 0

Junit单元测试_timed out after 500 milliseconds-程序员宅基地

文章浏览阅读353次。Junit是干什么的我在这里就不讲解了。直接开始正题。常用的注解Junit中的注解很多,我们首先来看一下最常用的一些注解 - @Test:把一个方法标记未测试方法 - excepted:用来测试异常的,方法抛出该异常说明测试成功 - timeout:用来测试性能的,在规定的时间内完成,说明成功。注意单位是毫秒 - @Before:每个测试方法执行前自动调用一次_timed out after 500 milliseconds

python和c十十区别_C语言和python的区别-程序员宅基地

文章浏览阅读464次。Python可以说是目前最火的语言之一了,人工智能的兴起让Python一夜之间变得家喻户晓,Python号称目前最最简单易学的语言,现在有不少高校开始将Python作为大一新生的入门语言。本萌新也刚开始接触Python,发现Python与其他语言确实有很大的区别。Python是由C语言实现的,因此想把Python与C语言做一个简单的比较。一、C语言是编译型语言,经过编译后,生成机器码,然后再运行,..._c十十pathyon

appium+python自动化43-微信公众号webview操作-程序员宅基地

文章浏览阅读271次。前言上一篇已经解决切换到微信公众号的webview上了,但是定位webview上元素的时候一直提示找不到,打印page_source也找不到页面上的元素,这个问题困扰了一整天,还好最后找到了原因,此处埋了一个深坑,需要再次切换handle切换到webview1.上一篇已经详细介绍如何切换到微信公众号的webview上,这里就不重复说了,贴下代码:# 切换到webviewtime.sle..._自动化测试公众微信号python

2019.3.20 RecyclerView的依赖_recyclerview依赖地-程序员宅基地

文章浏览阅读1.1k次,点赞3次,收藏2次。2019.3.20 RecyclerView的依赖andriod studio更新到最新版本打开.xml文件点击Design点击下载按钮 等待下载完成在这里插入图片描述大功告成。_recyclerview依赖地

随便推点

HTML---今天学了有序列表<ol>和无序列表<ul>,自我总结一下_无序列表和有序列表的标签分别是-程序员宅基地

文章浏览阅读245次。分享有序列表和无序列表的使用和常用属性_无序列表和有序列表的标签分别是

java/php/net/pythont电影票订票系统设计_电影购票系统er图-程序员宅基地

文章浏览阅读4.1k次。本系统带文档lw万字以上+答辩PPT+查重 如果这个题目不合适,可以去我上传的资源里面找题目,找不到的话,评论留下题目,或者站内私信我,有时间看到机会给您发系统体系结构电影票订票系统的结构图4-1所示: 图4-1 系统结构登录系统结构图,如图4-2所示: 图4-2 登录结构图管理员结构图,如_电影购票系统er图

Python字符串及正则表达式(一)_python 字符串 表达式-程序员宅基地

文章浏览阅读847次。1.6.1字符串常用操作1.6.1.1拼接字符串使用”+”运算符可以完成对多个字符串的拼接,”+”元素安抚可以连接多个字符串并产生一个字符串对象示例代码:teacher ="Will"content="主要负责Python自动化"结果:Will主要负责Python自动化字符串不允许直接与其他类型的数据拼接。示例代码:name="李二狗"course="语文成绩是"score=97 #(int类型)print(name+course+score)结果:Traceback _python 字符串 表达式

【本人秃顶程序员】Spring Boot 最流行的 16 条实践解读!_bom专员的最佳实践-程序员宅基地

文章浏览阅读171次。←←←←←←←←←←←← 快!点关注Spring Boot是最流行的用于开发微服务的Java框架。在本文中,我将与你分享自2016年以来我在专业开发中使用Spring Boot所采用的最佳实践。这些内容是基于我的个人经验和一些熟知的Spring Boot专家的文章。在本文中,我将重点介绍Spring Boot特有的实践(大多数时候,也适用于Spring项目)。以下依次列出了最佳实践,排名不分先..._bom专员的最佳实践

3090 pytorch编译记录_ms/iter-程序员宅基地

文章浏览阅读337次。一、环境配置编译的本地环境如下:gpu : RTX 3090ubuntu 20.04gcc 9.3.0driver : 460.56CUDA : 11.2CUDNN : 8.1.0python :3.6.12pytorch : 1.7.1torchvision : 0.8.2torchtext : 0.8.1pytorch、torchtext、torchvision 需要在同一个环境编译,编译顺序为: pytorch > torchvision > torcht_ms/iter

关于微信小程序不同机型导致的布局不统一的问题_小程序在不同手机上页面不一样-程序员宅基地

文章浏览阅读1.7k次。解决小程序不同机型出现布局差异问题_小程序在不同手机上页面不一样

推荐文章

热门文章

相关标签