<!-- /* Font Definitions */ @font-face {font-family:"MS 明朝"; panose-1:2 2 6 9 4 2 5 8 3 4; mso-font-alt:"MS Mincho"; mso-font-charset:128; mso-generic-font-family:roman; mso-font-pitch:fixed; mso-font-signature:-1610612033 1757936891 16 0 131231 0;} @font-face {font-family:SimSun; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-alt:宋体; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} @font-face {font-family:Century; panose-1:2 4 6 3 5 7 5 2 3 3; mso-font-alt:"Times New Roman"; mso-font-charset:0; mso-generic-font-family:roman; mso-font-format:other; mso-font-pitch:variable; mso-font-signature:3 0 0 0 1 0;} @font-face {font-family:"/@MS 明朝"; panose-1:2 2 6 9 4 2 5 8 3 4; mso-font-charset:128; mso-generic-font-family:roman; mso-font-pitch:fixed; mso-font-signature:-1610612033 1757936891 16 0 131231 0;} @font-face {font-family:"/@SimSun"; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-parent:""; margin:0mm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; mso-pagination:none; font-size:10.5pt; mso-bidi-font-size:12.0pt; font-family:Century; mso-fareast-font-family:"MS 明朝"; mso-bidi-font-family:"Times New Roman"; mso-font-kerning:1.0pt;} /* Page Definitions */ @page {mso-page-border-surround-header:no; mso-page-border-surround-footer:no;} @page Section1 {size:595.3pt 841.9pt; margin:99.25pt 30.0mm 30.0mm 30.0mm; mso-header-margin:42.55pt; mso-footer-margin:49.6pt; mso-paper-source:0; layout-grid:18.0pt;} div.Section1 {page:Section1;} -->
要包含的
头
文件
#include "stdafx.h"
#import <mshtml.tlb> // Internet Explorer 5
#import <shdocvw.dll>
#include "Shlwapi.h"
#pragma comment(lib,"Shlwapi.lib")
//--------------------
#include <mshtml.h>
#include <atlbase.h>
#include <oleacc.h>
//---------------------
下面是代
码
,
我是用
webbrowser
控件做和
浏览
器
,CHTMLVIEW
其他也是可以的
实现
的功能是根据内容插入表
单
,
保存也是一
样
的道理
.
注
释
因
为
会乱
码
,
所以没加上
,
如果看不懂
,
可以看下面我从我博客上
复
制来的一篇文章
void CHelpDlg::OnButtonSubmit()
{
// TODO: Add your control notification handler code here
HWND hWnd = AfxGetMainWnd()->m_hWnd;
CoInitialize(NULL); //
初始化
COM
SHDocVw::IShellWindowsPtr m_spSHWinds;
if(m_spSHWinds.CreateInstance(__uuidof(SHDocVw::ShellWindows)) == S_OK)
{
IDispatchPtr spDisp;
long nCount = m_spSHWinds->GetCount();
for(long i =0;i<nCount;i++)
{
_variant_t va(i, VT_I4);
spDisp = m_spSHWinds->Item(va);
SHDocVw::IWebBrowser2Ptr spBrowser(spDisp);
if (spBrowser != NULL)
{
IDispatchPtr spDisp;
if(spBrowser->get_Document(&spDisp) == S_OK && spDisp!= 0 )
{
MSHTML::IHTMLDocument2Ptr spHtmlDocument(spDisp);
MSHTML::IHTMLElementPtr spHtmlElement;
if(spHtmlDocument==NULL)
continue;
spHtmlDocument->get_body(&spHtmlElement);
if(spHtmlDocument==NULL)
continue;
HRESULT hr;
MSHTML::IHTMLElementCollection* pColl=NULL;
hr=spHtmlDocument->get_all(&pColl);
if(pColl!=NULL&&SUCCEEDED(hr))
{
long lcount = 0;
pColl->get_length(&lcount);
for(int i=0;i<lcount;i++)
{
_variant_t index;
index.vt=VT_I4;
index.intVal=i;
IDispatchPtr disp;
disp=pColl->item(index,index);
if(disp==NULL)
hr=E_FAIL;
else
{
MSHTML::IHTMLInputElementPtr pInput(disp);
if(pInput)
{
BSTR bstrtype;
pInput->get_type(&bstrtype);
//printf(_bstr_t(bstrtype));
if(StrCmpW(bstrtype,L"text")==0)
{
MSHTML::IHTMLElementPtr e(pInput);//
以下是
关
于表
单
的
,
上面已
经
可以得到整个网
页
的内容了
,
把下面的表
单
部份改成你自已要
实现
的功能就可以了
// }
}
SysFreeString(bstrtype);
}
}
}
pColl->Release();
}
}
}
}
}
else
{
printf("Shell Windows interface is not avilable/n");
}
CoUninitialize();
}
下面是
讲
解
实现
和
IE
浏览
器交互的几
种
方法的介
绍
---- 1
.引言
----
如何
实现对
IE
浏览
器中
对
象的操作是一个很有
实际
意
义问题
,通
过
和
IE
绑
定的
DLL
我
们
可以
记录
IE
浏览过
的网
页
的
顺
序,分析用
户
的使用行
为
和模式。我
们
可以
对
网
页
的内容
进
行
过滤
和翻
译
,可以自
动
填写网
页
中
经
常需要用
户
填写的
Form
内容等等
,
我
们
所有的例子代
码
都是通
过
VC
来表示的,采用的原理是通
过
和
IE
对
象的接口的交互来
实现对
IE
的
访问
。
实际
上是采用
COM
的技
术
,我
们
知道
COM
是和
语
言无
关
的一
种
二
进
制
对
象交互的模式,所以
实际
上我
们
下面所描述
的内容都可以用其他的
语
言来
实现
,比如
VB
,
DELPHI
,
C++ Builder
等等。
---- 2
.
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
的
实
例,如果
这
些
页
面都是很好的
话
,我
们
可能想保存在硬
盘
上,
这样
,我
们
需要
对每
一个
实
例
进
行保存,而如果
我
们
采用上面的
原理,我
们
可以得到
每
一个
IE
的
实
例及其网
页对
象的接口,
这样
就可以通
过
一个
简单
的程序来批量的保存当前的所有打
开
的网
页
。采用上面介
绍
的
方法
实现
了
对
当前
IE
实
例的遍
历
,但是我
们
希望得到
每
一个
IE
实
例所
产
生的事件,
这
就需要通
过
DLL
的机制来
实现
。
---- 3
.和
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, &IID_IWebBrowser2 > m_myWebBrowser2;
----
我
们
就可以在方法
SetSite
中把
这
个
传进
来的接口指
针赋给
m_myWebBrowser2
。
2
.
在我
们
得到了指向
IE COM
对
象的接口后,我
们
需要把自己的
DLL
和
IE
实
例所
发
生的事件相
关连
,
为
了
实现这
个目的,需要介
绍
两个接口:
----
(
1
)
IConnectionPointContainer
。
这
里使用
这
个接口的目的是用来根据它得到的
IID
来建立和
DLL
的一个特定的
连
接。比如我
们
可以
进
行如下的定
义
:
CComQIPtr< IConnectionPointContainer,
&IID_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(
DIID_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,REFIID
riid, LCID lcid, WORD wFlags,
DISPPARAMS * pdispparams, VARIANT * pvarResult,
EXCEPINFO * pexcepinfo, UINT * puArgErr);
-- --
其中,
DISPID
是一个
长
整数,它
标识
的是一个函数。
对
于
IDispatch
的某一个特定的
实现
,
DISPID
都是唯一的。
IDispatch
的
每
一个
实现
都有其自己的
IID,
这
里
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
实
例所
发
生的事件
,我
们
可以把
这
些数据放到文件中
进
行事后的分析,也可以放到一个列表框中
实时
的
显
示。
---- 4
.微
软
的
HTML
文档
对
象模型和
应
用分析
----
下面我
们
来看如何得到网
页
文档的接口:网
页
文档的接口
为
IHTMLDocument2
,可以通
过调
用
IE COM
对
象的
get_Document
方法来得到网
页
的接口。使用如下的
语
句:
hr = m_spWebBrowser2- >get_Document(&spDisp);
CComQIPtr< IHTMLDocument2,
&IID_IHTMLDocument2 > spHTML;
spHTML = spDisp;
----
这样
我
们
就得到了网
页对
象的接口,然后我
们
就可以
对
网
页进
行分析,比如通
过
IHTMLDocument2
提供的方法
get_URL
我
们
可以得到和
该
网
页
相
关
的
URL
的地址
值
,通
过
get_forms
方法可以
该
网
页
中所有的
Form
对
象的集合。
实际
上
W3C
组织
已
经
制定了一个
DOM
(
Document Objec
Model
)
标
准,当然
这
个
标
准不
仅仅
是
针对
HTML
,同
时还
是
针对
XML
制定的。
W3C
组织
只是定
义
了网
页对
象的接口,不同的公司可以采用不同的
语
言和
方法
进
行具体的
实现
。按照
W3C
组织
定
义
的网
页对
象被
认为
是
动态
的,即用
户
可以
动态
的
对
网
页对
象里面所包含的
每
一个
对
象
进
行操作。
这
里的
对
象可以是指一个
输
入框,也可以是
图
象和声音等
对
象。同
时
按照
W3C
的正式文档的
说
明,网
页对
象是可以
动态
增加和
删
除的。事
实
上,很少有厂商
实现
了
DOM
定
义
的所有功能。
微
软对
网
页对
象的定
义
也基本上是按照
这
个
标
准
实现
的。但是当前的接口
还
不支持
动态
的增加和
删
除元素,但是可以
对
网
页
中的基本元素
进
行属性的修改。比如
IHTMLElementCollection
表示网
页
中一些基本的元素的集合,
IHTMLElement
表示网
页
中的一个基本的元素。而象
IHTMLOptionElement
接口就表示一个特定的元素
Option
。基本的元素都有
setAttribute
和
geAttribute
方法来
动
态
的
设
置和得到元素的名称和
值
。
----
较为
常
见
的一个
应
用是我
们
能
够
分析网
页
中是否有需要填写的
Forms
,如果
这
个网址的
Forms
以前已
经
填写
过
而且数据我
们
已
经
保存下来的
话
,我
们
就可以
把数据自
动
放到和
该
URL
下的
Forms
的相
关
的位置中去。另外,我
们
可以
总结
网
页
上需要填写的
Form
的数据
项
,先
对这
些数据
项进
行
赋值
,以后碰到有相
同的数据
项
的
时
候就自
动
把我
们赋值
的内容填写
进
去。
实际
上
Form
是
对
象,
Form
中包含的元素,比如
INPUT
,
OPTION
,
SELECT
等
类
型的
输
入元素都是
对
象。
----
另外一个可以想到的
应
用是自
动对
网
页
中的文本
进
行翻
译
,因
为
我
们
可以修改网
页
中任何
对
象的属性,所以我
们
可以把里面不属于本国
语
言的部分自
动
翻
译
成本国
语
言,当然真正的
实现还
要靠自然
语
言理解方面技
术
的突破,但是
IE
浏览
器的接口和
对
象的形式使我
们
能
够
灵活的控制整个
IE
,无
论
是从事件
对
象
还
是到网
页对
象。
---- 5
.小
结
----
上面我
们
分析了如何得到所有
IE
的
实
例,同
时
介
绍
了和
IE
实
例相捆
绑
的
DLL
的
详细
的
实现
机制,同
时对
网
页
的
对
象化
进
行了分析。并且介
绍
了几个相
关
的
应
用
和
实现
的方法及存在的技
术问题
。
IE
是一个
组
件化的以
COM
为
基
础
的
浏览
器,它具有
强
大的功能,同
时为应
用
开发
者留下了广
阔
的空
间
,当然它也存在体
积
比
较
大,速度相
对
比
较
慢的缺点。但是它的体系
结
构代表了微
软
先
进
的
创
新的技
术
,因此具有
强
大的生命力
。