IE里的探索之定制浏览器好助手(中)
(作者:青苹果工作室编译 2001年02月08日 14:00)
检测调用者
像前面提到的,如果你运行的外壳版本不低于471,BHO 就既能被Internet Explorer又能被Windows Explorer引用。在这个例子里,我们要是涉及一个专对 HTML 页面起作用的助手对象,所以它应该对 Windows Explorer 不起任何作用。一个不想被特定的调用者加载的 DLL 可以在它发现谁是调用者后,简单地在它的 DllMain() 函数中返回 False。当你将 NULL 作为 API 函数 GetModuleFileName() 的第一个参数调用它时,它返回调用 DLL 的模块名。这个参数是你想知道名字的模块的句柄。NULL 表示你想知道调用 DLL 的进程的名字。
if (dwReason == DLL_PROCESS_ATTACH)
{
TCHAR pszLoader[MAX_PATH];
GetModuleFileName(NULL, pszLoader, MAX_PATH);
_tcslwr(pszLoader);
if (_tCSStr(pszLoader, _T("explorer.exe")))
return FALSE;
}
你知道了进程的名字,你就能在它是 Windows Explorer 时退出加载过程。注意采取更严格的淘汰是很危险的。实际上,其它进程可能视为一个正常的原因调用它但被拒绝。第一个受害者是 regsvr32.exe,这个程序用来自动注册对象。如果 你是用不同的测试条件,比如说,只允许 Internet Explorer 可以执行:
if (!_tCSStr(pszLoader, _T("iexplore.exe")))
你就不能注册 DLL 了。实际上,当 regsvr32.exe 试图加载 DLL 以调用DllRegisterServer() 函数时,调用被拒绝。
同 WebBrowser 建立联系
SetSite() 方法是 BHO 进行初始化以及所有只进行一次任务的地方。当你用 Internet Explorer 浏览 URL 时,你需要等待一对事件以确保所需的文档被完全下载并被初始化。只有在这一位置上你能通过可能存在的对象模型安全地访问它的 内容。这表示你需要获得一对指针。第一个是指向 IWebBrowser2 的,它是处理 WebBrowser 对象的接口。第二个指针和事件有关。这个模块必须注册为浏览器的事件监听者,以便能够接收关于下载和文档相关事件的通知。通过使用 ATL 的灵巧指针:
CComQIPtr<IWebBrowser2, &IID_IWebBrowser2> m_spWebBrowser2;
CComQIPtr<IConnectionPointContainer,
&IID_IConnectionPointContainer> m_spCPC;
源代码类似于:
HRESULT CViewSource::SetSite(IUnknown *pUnkSite)
{
// 获得并保存 IWebBrowser2 指针
m_spWebBrowser2 = pUnkSite;
if (m_spWebBrowser2 == NULL)
return E_INVALIDARG;
// 获得并保存 IConnectionPointerContainer 指针
m_spCPC = m_spWebBrowser2;
if (m_spCPC == NULL)
return E_POINTER;
// 获得并保存浏览器的 HWND。另外为以后的使用安装键盘挂钩。
RetrieveBrowserWindow();
// 连接到容器以接受事件通知
return Connect();
}
要获得指向 IWebBrowser2 接口的指针,你只需要简单地查询。对事件处理的第一个步骤,获得 IConnectionPointContainer 的指针,也用同样的办法。SetSite() 的代码也查询浏览器的 HWND 并在当前线程上安装键盘挂钩。HWND 以后会被用以移动 Internet Explorer 窗口并改变它的尺寸。那个挂钩,被用以提供一个热键,以方便用户显示或隐藏 HTML 代码窗口。