Internet Explorer 编程简述(十)响应来自HTML Element的事件通知——几个好用的类

原创 2006年03月11日 20:52:00

关键字:HTML Element, Sink

 
1、概述
实现了对Webbrowser的resuing之后我们便会发现有时候我们还需要处理浏览器中的元素(HTML Element)。这种处理包括主动和被动两个方面,像《FAQ:如何访问WebBrowser的滚动条、《FAQ:操纵下拉列表、《FAQ:两种方法访问多层嵌套的frame等文章所演示的就是主动的处理。通常我们从Webbrowser获得一个Web文档接口(IHTMLDocumentx),从它出发便可访问到浏览器所包含的一切HTML元素。而被动的处理则是在COM技术中称为Sink的技术,我更喜欢的说法是事件通知。当文档的下载进度发生变化时,我们可以获得ProgressChange通知,当Webbrowser下载完HTML文档时,我们可以获得DocumentComplete的通知,而当链接被点击,或图片被拖动时,我们如何获得通知呢?本文希望能够给出部分的答案。
 
2、HtmlObj Template
如何Sink一个HTML Element并不是本文的重点,其理论我不是太了解,也懒得去搞透彻,所以使用现成的库来实现。CodeProject上的一篇文章《CHtmlObj Template》给出的一个模板类CHtmlObj就非常好用。下面的例子是针对Html Anchor Element的一个实例化。
 
#include "HtmlObj.h"
 
class CHtmlAnchorElement : public CHtmlObj<IHTMLAnchorElement,
&DIID_HTMLAnchorEvents> 
{
public:
CHtmlAnchorElement(CHtmlDocument2* pParentDoc2);
virtual ~CHtmlAnchorElement();
 
virtual HRESULT OnInvoke(DISPID dispidMember,REFIID riid,
LCID lcid, WORD wFlags,
DISPPARAMS * pdispparams, VARIANT * pvarResult,
EXCEPINFO * pexcepinfo,
UINT * puArgErr);
};

HRESULT CHtmlAnchorElement::OnInvoke(DISPID dispidMember,
REFIID riid, LCID lcid, WORD wFlags,
DISPPARAMS * pdispparams, VARIANT * pvarResult,
EXCEPINFO * pexcepinfo,
UINT * puArgErr)
{
HRESULT hr = E_NOTIMPL;
switch(dispidMember)
{
case DISPID_HTMLELEMENTEVENTS_ONMOUSEOVER :
{//当鼠标经过链接时,我们在这里获得通知
hr = S_OK;
      // TODO: add code to handle on mouse over events
break;
}
case DISPID_HTMLELEMENTEVENTS_ONMOUSEOUT :
{//当鼠标从链接上移开时,我们在这里获得通知,其它的Dispatch ID可根据需要添加
hr = S_OK;
      // TODO: add code to handle on mouse out events
break;
}
default:
{
break;
}
}
 
return hr;
}
 
当我们得到某个链接的HTML接口指针,便可调用CHtmlAnchorElement继承自CHtmlObj的SetSite(IUnknown *pUnkSite)成员函数传入该接口指针。在CHtmlObj类内部用一个智能指针m_spHtmlObj来保存相应的HTML Element接口指针,所以当上面的ONMOUSEHOVER和ONMOUSEOUT两个事件通知到达时,从m_spHtmlObj就可以访问IHTMLAnchorElement的所有成员,如从href获得链接的Url等,此处不再赘述。
 
3、CHtmlElements类
有了CHtmlObj之后我们又会发现实践中常常会需要多个相同类型的CHtmlObj。比如包含Frame的网页中每个Frame的HTML Document都需要一个CHtmlObj来Sink其事件。所以我们还需要有效地管理这些相同类型的CHtmlObj。下面是我写的一个简单的模板类CHtmlElements,它通过CMap来管理多个CHtmlObj对象。
 
template<class THtmlElement> class CHtmlElements
{
typedef CMap<LPDISPATCH, LPDISPATCH, THtmlElement*, THtmlElement*> CMapDispToHtmlElement;
CMapDispToHtmlElement m_htmlElements;
BOOL IsSiteConnected( LPDISPATCH pDisp )
{
THtmlElement *pElement;
return m_htmlElements.Lookup( pDisp, pElement );
}
public:
CHtmlElements(void)
{
}
~CHtmlElements(void)
{
}
public:
void SetSite( LPDISPATCH pDisp )
{
if ( IsSiteConnected( pDisp ) ) //检查以避免多余的Sink
{
return;
}
THtmlElement *pElement = new THtmlElement; //通过模板类型创建相应的类的实例进行连接
pElement->SetSite( pDisp );
m_htmlElements.SetAt( pDisp, pElement );
}
 

//在合适的地方调用Clear释放所管理的内存

void Clear(void)

{

POSITION pos = m_htmlElements.GetStartPosition();

THtmlElement *pElement = NULL;

LPDISPATCH pDisp = NULL;

while (pos != NULL)

{

m_htmlElements.GetNextAssoc( pos, pDisp, pElement );

m_htmlElements.RemoveKey( pDisp );

delete pElement;

}

}

};
 
假设我们有一个象CHtmlAnchorElement那样派生自CHtmlObj的类CHtmlDocument2,使用CHtmlElements时这样声明:
 
typedef CHtmlElements<CHtmlDocument2> CHtmlDocuments;
typedef CHtmlElements<CHtmlAnchorElement> CHtmlAnchors;
 
class CMyView : public CHtmlView
{
private:
CHtmlDocuments m_htmlDocs;
CHtmlAnchors m_htmlAnchors;
}
 
在DocumentComplete时就可以这样连接到浏览器的文档对象:
void CMyView ::OnDocumentComplete(LPDISPATCH pDisp, LPCTSTR lpszURL)
{
m_htmlDocs.SetSite(pDisp);
}
 
如果想一次性连接上文档中所有的Anchor Element,可以通过IHTMLDocument2::get_anchors获得包含所有IHTMLAnchorElement接口指针的IHTMLElementCollection,再遍历其中的每个元素,分别调用m_htmlAnchors.SetSite即可。当然,一次性的Sink全部链接可能并不是个好注意,我更愿意在CHtmlDocument2中响应事件再通过其它手段来访问当前位置的HTML Element。
 
4、结论
响应HTML Element的事件通知对于浏览器编程来说是一个非常强大的手段,它可以更深入细化地控制浏览器中的文档及其HTML元素,实现更为高级的功能,比如所谓的“超级拖放”(许多多窗口浏览器都提供了该功能,但实际上没有哪个浏览器完美地实现了对URL、文字及图片的拖放)。
 
5、参考资料
 

Internet Explorer 编程简述(十)响应来自HTML Element的事件通知——几个好用的类

关键字:HTML Element, Sink   1、概述 实现了对Webbrowser的resuing之后我们便会发现有时候我们还需要处理浏览器中的元素(HTML Element)。这种处理包...
  • delphi99
  • delphi99
  • 2011年09月22日 16:15
  • 356

Internet Explorer 编程简述(十)响应来自HTML Element的事件通知——几个好用的类

1、概述实现了对Webbrowser的resuing之后我们便会发现有时候我们还需要处理浏览器中的元素(HTML Element)。这种处理包括主动和被动两个方面,像《FAQ:如何访问WebBrows...
  • zshwlw
  • zshwlw
  • 2008年01月13日 20:15
  • 511

Internet Explorer无法下载 *** (来自 ***)。Internet Explorer无法打开该Internet站点。请求的站点不可用,或找不到。请以后再试。”

Internet Explorer无法下载 *** (来自 ***)。Internet Explorer无法打开该Internet站点。请求的站点不可用,或找不到。请以后再试。” http:...
  • jackpk
  • jackpk
  • 2014年07月28日 17:58
  • 15117

【原】解决php 下 ie 无法下载 来自 无法打开该internet 站点 的问题

由于某度众所周知的举动,让我搬离写了5年的渣度空间,准备把技术性的文章定在CSDN了。这些都是文章备份。勿怪。。 鉴于最近有些抓取机器和抄袭者,把标题的【原】字都复制,我不得不声明:本文为 yuko...
  • yukon12345
  • yukon12345
  • 2011年09月28日 20:37
  • 5907

Windows Server 2008 IE弹出 Internet Explorer增强安全设置正在阻止来自下列网站的此应用程序中的内容

Internet Explorer 增强的安全配置是个好东西,也是保护系统不被钓鱼和拦截的好帮手。但讲课、测试、练习,尤其是内部网络OA等应用实在是让人挠头,问我的非IT行业的朋友和同事也比较多。以上...
  • Eric_K1m
  • Eric_K1m
  • 2013年09月25日 16:15
  • 3074

Internet Explorer编程简述(二)

  Internet Explorer 编程简述(二)在IE中编辑OLE嵌入文档  除了打开Internet上的网页,Internet Explorer还能够浏览本地文件夹及文件。如果浏览的是PDF文...
  • donetk
  • donetk
  • 2008年05月03日 17:53
  • 161

Internet Explorer 编程简述(繁体版)

Internet Explorer 程式設計簡述(一)Internet Explorer 程式設計簡述(二)Internet Explorer 程式設計簡述(三)Internet Explorer 程...
  • CathyEagle
  • CathyEagle
  • 2004年10月02日 14:59
  • 4575

该网页脚本造成Internet Explorer运行速度减慢!若继续运行会更慢,至无法响应!

访问者所使用的浏览器不能完全支持页面里的脚本,形成“脚本错误”。遇到“脚本错误”时一般会弹出一个非常难看的脚本运行错误警告窗口,而事实上,脚本错误并不会影响网站浏览,因此这一警告可谓多此一举。要关闭警...
  • zhongguomao
  • zhongguomao
  • 2016年05月11日 14:17
  • 845

Internet Explorer 编程简述(序)

一直对Microsoft Internet Explorer编程非常感兴趣,曾花了不少时间琢磨,也与众多网友讨论过问题,2000年将心得写成一篇《TWebBrowser编程简述》,发表在自己的个人主页...
  • delphi99
  • delphi99
  • 2011年09月22日 16:04
  • 213

Internet Explorer编程简述(六)

1、概述Internet Explorer提供了非常开发的接口,使开发人员不仅可以把其浏览器核心嵌入应用程序,还可以通过各种接口以实现更深层的控制。本文就将介绍对浏览器进行高级控制的话题之一——自定义...
  • donetk
  • donetk
  • 2008年05月03日 17:53
  • 209
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章: Internet Explorer 编程简述(十)响应来自HTML Element的事件通知——几个好用的类
举报原因:
原因补充:

(最多只允许输入30个字)