你是否曾经想过如何过滤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;

}

}

```