如何访问IE的数据?

feelinn 2001-05-20 05:53:00
实现和IE浏览器交互的几种方法

浙江大学计算机系 (310027) 胡朝晖 陈奇 俞瑞钊

一 实现IE实例遍历
首先我们来看系统是如何知道当前有多少个IE的实例在运行。
在Windows体系结构下,一个应用程序可以通过操作系统的运行对象表来和这些应用的实例进行交互。但是IE当前的实现机制是不在运行对象表中进行注册,所以需要采用其他的方法。可以通过ShellWindows集合来代表属于shell的当前打开的窗口的集合,而IE就是属于shell的一个应用程序。
下面描述一下用VC实现对当前IE实例进行遍历的方法。IShellWindows是关于系统shell的一个接口,可以定义一个如下的接口变量:
SHDocVw::IShellWindowsPtr m_spSHWinds;
然后创建变量的实例:
m_spSHWinds.CreateInstance(__uuidof(SHDocVw::ShellWindows));
通过IShellWindows接口的方法GetCount可以得到当前实例的数目:
long nCount = m_spSHWinds->GetCount();
通过IShellWindows接口的方法Item可以得到每一个实例对象:
IDispatchPtr spDisp;
_variant_t va(i, VT_I4);
spDisp = m_spSHWinds->Item(va);
然后可以判断实例对象是不是属于IE浏览器对象,通过下面的语句实现:
SHDocVw::IWebBrowser2Ptr spBrowser(spDisp);
assert(spBrowser != NULL)
在得到了IE浏览器对象以后,可以调用IWebBrowser2Ptr接口的方法来得到当前的文档对象的指针: MSHTML::IHTMLDocument2Ptr spDoc(spBrowser->GetDocument());
然后就可以通过这个接口对这个文档对象进行操作,比如通过Gettitle得到文档的标题。
二 实现和IE相绑定的DLL
介绍一下如何建立和IE进行绑定的DLL的实现的过程。为了和IE的运行实例进行绑定,需要建立一个能够和每一个IE实例进行绑定的DLL。IE的启动过程是这样的,当每一个IE的实例启动的时候,它都会在注册表中去寻找一个CLSID,具体的注册表的键位置为:
HKEY_LOCALL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects
当在这个键位置下存在CLSIDs的时候,IE会通过使用CoCreateInstance()方法来创建列在该键位置下的每一个对象的实例。注意对象的CLSIDs必须用子键而非名字值的形式表现,比如{DD41D66E-CE4F-11D2-8DA9-00A0249EABF4}就是一个有效的子键。
使用DLL的形式而非EXE的形式的原因是因为DLL和IE实例运行在同一个进程空间里面。每一个这种形式的DLL必须实现接口IObjectWithSite,其中方法SetSite必须被实现。通过这个方法,我们自己的DLL就可以得到一个指向IE COM对象的IUnknown的指针,实际上通过这个指针就可以通过COM对象中的方法QueryInterface来遍历所有可以得到的接口,这是COM的基本的机制。当然需要的只是IWebBrowser2这个接口。
实际上建立的是一个COM对象,DLL只不过是COM对象的一种表现形式。COM对象需要建立和实现的方法有:
1. 实现IOleObjectWithSite接口的方法SetSite。
实际上IE实例通过这个方法向COM对象传递一个接口的指针。假设有一个接口指针的变量,不妨设为:
CComQIPtr<IWebBrowser2, &ⅡD_IWebBrowser2> m_myWebBrowser2;
就可以在方法SetSite中把这个传进来的接口的指针赋给m_myWebBrowser2。
2. 在得到了指向IE COM对象的接口后,需要把自己的DLL和IE实例所发生的事件相关联。
为了实现这个目的,需要介绍两个接口:
(1) IConnectionPointContainer。这里使用这个接口的目的是根据它得到的ⅡD来建立和DLL的一个特定的连接。比如可以进行如下的定义:
CComQIPtr<IConnectionPointContainer,
&ⅡD_IConnectionPointContainer>
spCPContainer(m_myWebBrowser2);
然后,需要把所有IE中发生的事件和DLL进行通信,可以使用IConnectPoint。
(2) IConnectPoint。通过这个接口,客户可以对连接的对象开始或者是终止一个advisory循环。IConnectPoint有两个主要的方法,一个为Advice,另一个为Unadvise。对于我们的应用来说,Advise是用来在每一个IE发生的事件和DLL之间建立一个通道。而Unadvise就是用来终止以前用Advise建立的通知关系,比如可以定义IConnectPoint接口如下
CComPtr<IConnectionPoint> spConnectionPoint;
然后,要使所有在IE实例中发生的事件和我们的DLL相关,可以使用如下的方法: hr =spCPContainer->FindConnectionPoint(DⅡD_DWebBrowserEvents2, &spConnectionPoint);
然后通过IConnectPoint接口的方法Advice使每当IE有一个新的事件发生的时候,都能够让DLL知道。可以用如下的语句实现:
hr = spConnectionPoint->Advise((IDispatch*)this, &m_dwIDCode);
在把IE实例中的事件和我们的DLL之间建立联系以后,我们可以通过IDispatch接口的Invoke()方法来处理所有的IE的事件。
3. IDispatch接口的Invoke()方法。
IDispatch是从IUnknown中继承的一个接口的类型,通过COM接口提供的任何服务都可以通过IDispatch接口来实现。IDispatch::Invoke的工作方式同vtbl幕后的工作方式是类似的,Invoke将实现一组按索引来访问的函数,我们可以对Invoke方法进行动态的定制以提供不同的服务。Invoke方法的表示如下:
STDMETHOD(Invoke)(DISPID dispidMember,REFⅡD riid, LCID lcid, WORD wFlags,DISPPARAMS * pdispparams, VARIANT * pvarResult,EXCEPINFO * pexcepinfo, UINT * puArgErr);
其中,DISPID是一个长整数,它标识的是一个函数。对于IDispatch的某一个特定的实现,DISPID都是唯一的。IDispatch的每一个实现都有其自己的ⅡD,这里dispidMemeber实际上是可以认为是和IE实例所发生的每一个事件相关的方法,比如:DISPID_BEFORENAVIGATE2,DISPID_NAVIGATECOMPLETE2等等。
这个方法中另外一个比较重要的参数是DISPPARAMS,它的结构如下:
typedef struct tagDISPPARAMS
{
VARIANTARG* rgvarg; //VARIANTARG是同VARAIANT相同的,可以在OAIDL.IDL中找到。所以实际上rgvarg是一个参数数组
DISPID* rgdispidNameArgs; //命名参数的DISPID
unsigned int cArgs;//表示数组中元素的个数
unsigned int CnameArgs; //命名元素的个数
}DISPPARAMS
要注意的是每一个参数的类型都是VARIANTARG,所以在IE和我们DLL之间可以传递的参数类型的数目是有限的。只有那些能够被放到VARIANTARG结构中的类型才可以通过调度接口进行传递。
比如对于事件DISPID_NAVIGATECOMPLETE2来说:第一个参数表示IE在访问的URL的值,类型是VT_BYREF|VT_VARIANT。注意DISPID_NAVIGATECOMPLETE2等DISPID已经在VC中被定义,我们可以直接进行使用。
如上所述,我们在方法Invoke中可以得到所有IE实例所发生的事件,我们可以把这些数据放到文件中进行事后的分析,也可以放到一个列表框中实时显示。


节选自别人的文档,但我用代理类却不行?有谁知道更具体一点的方法?谢谢.

...全文
74 回复 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

16,548

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • AIGC Browser
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧