你是否曾经想过如何过滤IE中的Flash,或者如何在网页中嵌入的电子邮件病毒?或者实现类似Netants和Flashget那样的下载监视功能?看到这些问题,你可能会觉得很简单:“只需要监视IE的下载,发现后缀是'.swf'的文件就不进行下载。这样就可以过滤掉Flash。同样地,发现后缀是'.eml'的文件也做同样的处理......”然而,问题的关键在于如何彻底监视IE的下载。你不会为了这个目的去编写一个驱动程序吧?
如果你熟悉IE编程,你会马上意识到可以使用BHO(Browser Helper Object)。但是,仅仅使用BHO是不够的。BHO类似于钩子(hook),它钩住的是IE的事件。如果你还不熟悉BHO,可以访问MSDN网站查看相关文章:http://www.microsoft.com/Mind/0598/browhelp.htm。通过阅读这篇文章,你会发现BHO可以“hook”到IE的所有事件,如Navigate->NavigateComplete->DownloadBegin->DownloadComplete->DocumentComplete等。但是,它无法hook到IE的整个下载事件,例如:www.csdn.net首页里包含了大量的gif文件,BHO面对这些文件就变得无能为力了。
首先,我们需要了解一下IInternetProtocolRoot接口的Start方法:
```cpp
HRESULT Start(
LPCWSTR szUrl,//
IInternetProtocolSink *pOIProtSink,
IInternetBindInfo *pOIBindInfo,
DWORD grfPI,
HANDLE_PTR dwReserved
);
```
只要实现了IE的这个IinternetProtocolRoot接口,并在其Start方法中检查szUrl,就可以实现对IE下载的监视。那么,如何过滤呢?我们再来看看IinternetProtocolSink接口的ReportResult方法:
```cpp
HRESULT ReportResult(
HRESULT hrResult,
DWORD dwError,
LPCWSTR szResult
);
```
通过在ReportResult方法中检查hrResult和dwError参数,以及szResult参数的内容,我们可以实现对IE下载内容的过滤。
以下是重构后的代码,并保持了段落结构:
在Start方法中调用pOIProtSink的ReportResult方法实现过滤。实际上就是在IE下载文件之前欺骗IE说文件已经下载完毕了。比方说我们要过滤IE中的gif文件,那么只需要实现以下代码:
```cpp
STDMETHODIMP CQUrl::Start(LPCWSTR szUrl, IInternetProtocolSink *pIProtSink, IInternetBindInfo *pIBindInfo, DWORD grfSTI, DWORD dwReserved)
{
USES_CONVERSION;
char *str = OLE2A(szUrl);
if (strlen(str) > 4)
{
str = str + strlen(str) - 4; //取资源的最后四个字符,用来比较文件后缀
if (_strnicmp(str, L".gif", 4) == 0) //后缀是gif
{
pIProtSink->ReportResult(S_OK, 0, 0); //告诉IE:下载已经结束了! return S_OK; //返回,如果你返回INET_E_DOWNLOAD_FAILURE将看到另外一幅景象......
}
}
return INET_E_USE_DEFAULT_PROTOCOLHANDLER;
}
```
熟悉了监视过滤的一般方法后,下面开始深入到IE之中。以MIND杂志的iehelper实例为例。我们在IEHelper的基础上添加一个ATL对象,继承IinternetProtocol并实现IinternetProtocolRoot的Start方法即可。剩下的工作仅仅是在IEHelper的构造函数中实现上面添加的atl对象。在IEHelper类里加入两个接口指针:IInternetSession和IClassFactory。然后创建对象:
```cpp
CIEHlprObj()
{
// ... 其他初始化操作 ...
m_pProtocol = new CMyInternetProtocolRoot(); //创建CMyInternetProtocolRoot对象,并赋值给m_pProtocol指针
m_pProtocol->AddRef(); //增加引用计数,确保对象不被提前析构
}
```
请根据提供的内容完成内容重构,并保持段落结构:
```cpp
HRESULT hr = CoGetClassObject(CLSID_FiltUrl, CLSCTX_SERVER, NULL, IID_IClassFactory, (void**)&m_pFactory);
if(hr==S_OK)
{
if(CoInternetGetSession(0, &m_pSession, 0)==S_OK)
m_pSession->RegisterNameSpace(m_pFactory, CLSID_FiltUrl, L"http", 0, NULL, 0); //监视HTTP服务
}
```
如果必要的话,析构函数如下:
```cpp
CIEHlprObj::~CIEHlprObj()
{
if(m_pSession!=NULL)
{
m_pSession->UnregisterNameSpace(m_pFactory, L"http");
m_pSession->Release();
m_pSession = NULL;
}
if(m_pFactory!=NULL)
{
m_pFactory->Release();
m_pFactory = NULL;
}
}
```