科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件用VisualStudio2005生成浏览器帮助对象

用VisualStudio2005生成浏览器帮助对象

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

用VisualStudio2005生成浏览器帮助对象

作者:Tony Schreiner,John Sudds 来源:微软 2007年10月16日

关键字:

  • 评论
  • 分享微博
  • 分享邮件
进行试用

  为了进行快速测试,请在 SetSite 中设置一个断点,然后按 F5 启动调试程序。当出现“调试会话的可执行文件”对话框时,选择“默认的 Web 浏览器”,然后单击“确定”。如果 Internet Explorer 不是您的默认浏览器,则可以浏览查找可执行文件。

  注意 在 Windows Vista 上,Internet Explorer 的“保护模式”功能将启动另一个进程,然后退出,这样会给调试带来一点难度。您可以通过以下两种方式轻松关闭当前会话的“保护模式”:从管理进程(例如 Visual Studio)启动浏览器,或者创建一个本地 HTML 文件并将其指定为 Internet Explorer 的命令行参数。

  浏览器启动时,将加载 BHO 的 DLL。命中断点时,请注意是否设置了 pUnkSite 参数。再次按 F5 以继续加载主页。

  关闭浏览器以验证是否通过 NULL 再次调用了 SetSite。

  对事件做出响应

  既然已经确认了 Internet Explorer 可以加载和运行 BHO,那就让我们在所举示例的基础上再深入一些,将 BHO 扩展到响应浏览器事件。在本部分中,我们介绍如何使用 ATL 为 DocumentComplete(在页面加载后显示一个消息框)实现一个事件处理程序。

  为接到事件通知,BHO 建立一个与浏览器之间的连接点;为响应这些事件,它将实现 IDispatch。根据 DocumentComplete 的文档,该事件有两个参数:pDisp(IDispatch 的指针)和 pUrl。这些参数将作为事件的一部分传递给 IDispatch::Invoke;但手动析取这些事件参数并非一项简单的任务,并且易于出错。幸好 ATL 提供了一个默认实现,可以帮助简化这个事件处理逻辑。

  HelloWorldBHO.h

  首先通过包含 exdispid.h(为浏览器事件定义调度 ID)处理 HelloWorldBHO.h。

  #include // DISPID_DOCUMENTCOMPLETE 等。

  接下来,从 IDispEventImpl 基类进行派生,该基类为处理事件提供了除 Invoke 之外的另一个简单安全的替代方法。IDispEventImpl 与事件汇映射配合工作,以将事件路由到相应的处理程序函数。我们明确说明,想要使用以下类定义(突出显示)处理由 DWebBrowserEvents2 接口定义的事件。

以下是引用片段:
  class ATL_NO_VTABLE CHelloWorldBHO :
  public CComObjectRootEx,
  public CComCoClass,
  public IObjectWithSiteImpl,
  public IDispatchImpl,
  public IDispEventImpl<1, CHelloWorldBHO, &DIID_DWebBrowserEvents2, &LIBID_SHDocVw, 1, 1>

  接下来,添加将事件路由到新的 OnDocumentComplete 事件处理程序方法的 ATL 宏,该事件处理程序方法采用的是 DocumentComplete 事件所定义的相同参数和顺序。将以下代码放置到该类的公共部分。

以下是引用片段:
  BEGIN_SINK_MAP(CHelloWorldBHO)
  SINK_ENTRY_EX(1, DIID_DWebBrowserEvents2, DISPID_DOCUMENTCOMPLETE, OnDocumentComplete)
  END_SINK_MAP()
  // DWebBrowserEvents2
  void STDMETHODCALLTYPE OnDocumentComplete(IDispatch *pDisp, VARIANT *pvarURL);

  提供给 SINK_ENTRY_EX 宏 (1) 的数字指的是 IDispEventImpl 类定义的第一个参数,在必要时用于区分来自不同接口的事件。另请注意,不能从该事件处理程序返回值;这是因为 Internet Explorer 无论怎样都会忽略从 Invoke 返回的值。

  最后,添加一个专用成员变量,以跟踪各对象是否已建立了与浏览器的连接。

以下是引用片段:
  private:
  BOOL m_fAdvised;
  HelloWorldBHO.cpp

  要通过事件映射将事件处理程序连接到浏览器,可在处理 SetSite 期间调用 DispEventAdvise。同样,使用 DispEventUnadvise 断开连接。

  以下是 SetSite 的新实现:

以下是引用片段:
  STDMETHODIMP CHelloWorldBHO::SetSite(IUnknown* pUnkSite)
  {
  if (pUnkSite != NULL)
  {
  // 缓存指向 IWebBrowser2 的指针。
  HRESULT hr = pUnkSite->QueryInterface(IID_IWebBrowser2, (void **)&m_spWebBrowser);
  if (SUCCEEDED(hr))
  {
  // 注册以从 DWebBrowserEvents2 中汇集事件。
  hr = DispEventAdvise(m_spWebBrowser);
  if (SUCCEEDED(hr))
  {
  m_fAdvised = TRUE;
  }
  }
  }
  else
  {
  // 取消注册事件汇。
  if (m_fAdvised)
  {
  DispEventUnadvise(m_spWebBrowser);
  m_fAdvised = FALSE;
  }
  // 在此释放缓存的指针和其他资源。
  m_spWebBrowser.Release();
  }
  // 调用基类实现。
  return IObjectWithSiteImpl::SetSite(pUnkSite);
  }

  最后,添加一个简单的 OnDocumentComplete 事件处理程序。

以下是引用片段:
  void STDMETHODCALLTYPE CHelloWorldBHO::OnDocumentComplete(IDispatch *pDisp, VARIANT *pvarURL)
  {
  // 从站点检索顶级窗口。
  HWND hwnd;
  HRESULT hr = m_spWebBrowser->get_HWND((LONG_PTR*)&hwnd);
  if (SUCCEEDED(hr))
  {
  // 加载页面时输出消息框。
  MessageBox(hwnd, L"大家好!", L"BHO", MB_OK);
  }
  }

  请注意,消息框会将站点的顶层窗口用作其父窗口,而不仅仅是通过该参数传递 NULL。在 Internet Explorer 6 中,NULL 父窗口并不阻止应用程序,也就是说,在消息框等待用户输入时用户可以继续与浏览器交互。在某些情况下,这会导致浏览器挂起或崩溃。在 BHO 需要显示 UI 的这种少见情况下,应始终通过指定指向父窗口的句柄来确保该对话框为应用程序模态。

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章