在 CDHtmlDialog 类中如何使用 OnBeforeNavigate2 方法

http://hi.baidu.com/alee201/blog/item/6196d38130a33fd19023d9ef.html

在 CDHtmlDialog 类中如何使用 OnBeforeNavigate2 方法
2008-08-03 16:30

!本文为本站原创,欢迎转载,请保留原站链接

最近在一个 CDHtmlDialog 中需要用到用户提交的 Post 数据,可是 CDHtmlDialog 并没有实现 CHtmlView 中的虚函数 OnBeforeNavigate2 , 只有 OnBeforeNavigate 。   而 OnBeforeNavigate 仅传入两个参数 LPDISPATCH pDisp 和 LPCTSTR szUrl,这 显然不够用, 查了很多资料 还是没有结果。

通常的处理办法是: 在 CDialog 中 使用一个 Html 控件(CHtmlCtrl) 。

但是我不想放弃 CDHtmlDialog ,至少想先尝试一下 。

在 VC 调试状态 的 调用堆栈中, 发现 我们重载的 CDHtmlDialog::OnBeforeNavigate 虚函数 是在 CDHtmlDialog::_OnBeforeNavigate2 中被调用的, 而 这个 _OnBeforeNavigate2 的参数内容 与 CHtmlView 类的 OnBeforeNavigate2 虚函数 完全一致(不过数据类型不同)。这正是我所需要的!!

可是这个 _OnBeforeNavigate2 并不是虚函数, 我是不是可以直接重载它呢?

立刻尝试 在自己的 HtmlDialog派生类中 重载   _OnBeforeNavig 。 结果行不通。 重载的 _OnBeforeNavigate2 没用被调用, 原生的 _OnBeforeNavig 仍然被执行 。

那 会不会是 因为 _OnBeforeNavigate2 是被一个 CDHtmlDialog指针调用的 , 因为 _OnBeforeNavigate2 事件由 MFC 负责调用, MFC 当然不知道 我定义的 CDHtmlDialog派生类类型, 所以一定使用 CDHtmlDialog 类型的指针 来 调用 _OnBeforeNavigate2 , 结果 我重载的 _OnBeforeNavigate2 不会被执行 。

想到这里, 便随手 做了一个 大胆的 试验(只是做一下实验而已 ^_^!)。 在 afxdhtml.h 文件中 _OnBeforeNavigate2 的声明前面 加了一个 “virtual” ,将它强行 改成 一个虚函数:

virtual void _OnBeforeNavigate2(LPDISPATCH pDisp, VARIANT FAR* URL, VARIANT FAR* Flags, VARIANT FAR* TargetFrameName, VARIANT FAR* PostData, VARIANT FAR* Headers, BOOL FAR* Cancel);

在自己的 重载版本 前 也加上了 virtual 。 按 F5 试验, 结果很遗憾, 还是行不通 。

于是仔细研究 调用堆栈 , 原来 CDHtmlDialog::_OnBeforeNavigate2 并不是如我所猜测 由某个CDHtmlDialog类型的指针调用, 调用来自于 CCmdTarget::OnEvent 。

虽然不太懂 这个函数的工作原理和方式, 可是 看到 Event ,立刻就想到了 Mapping (直觉而已^_^! 也可说是误打误撞)。 OnEvent 可能是根据 某种 映射机制 来决定调用哪一个 事件函数 ,就像消息映射 来 决定 窗口事件函数一样。

这只是 猜想, 用 event 和 mapping 作为 关键词 到 msdn 查找 , 立刻就找到了 BEGIN_EVENTSINK_MAP 和 END_EVENTSINK_MAP 这一对宏  。 至于如何使用,CDHtmlDialog::_OnBeforeNavigate2 既然能够响应事件, 必然用到了这个宏, 所以 在 afxdhtml.h 中找到了对应的用法 。 参考 CDHtmlDialog 中的用法,将下面的代码 拷贝到 自己派生的 CDHtmlDialog Cpp 文件里:

BEGIN_EVENTSINK_MAP(CMyDlg, CDialog)
ON_EVENT(CMyDlg, AFX_IDC_BROWSER, 250 /* BeforeNavigate2 */, _OnBeforeNavigate2, VTS_DISPATCH VTS_PVARIANT VTS_PVARIANT VTS_PVARIANT VTS_PVARIANT VTS_PVARIANT VTS_PBOOL)
END_EVENTSINK_MAP()

按 F5 调试, 发现编译有错, 原来 和消息映射一样, 也要在 头文件中 先声明。将下面的 宏放在头文件里:

DECLARE_EVENTSINK_MAP()

编译通过! 按 F5 执行, 自己重载的 _OnBeforeNavigate2 被执行了 。 大功告成 :)

当然,你可以直接命名成 OnBeforeNavigate2 ,毕竟 以下划线 起头,习惯上 是给 私有函数 命名的。

你可能感兴趣的:(html,工作,url,mfc,browser)