http://hi.baidu.com/alee201/blog/item/6196d38130a33fd19023d9ef.html
!本文为本站原创,欢迎转载,请保留原站链接 最近在一个 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) 按 F5 调试, 发现编译有错, 原来 和消息映射一样, 也要在 头文件中 先声明。将下面的 宏放在头文件里: DECLARE_EVENTSINK_MAP() 编译通过! 按 F5 执行, 自己重载的 _OnBeforeNavigate2 被执行了 。 大功告成 :) 当然,你可以直接命名成 OnBeforeNavigate2 ,毕竟 以下划线 起头,习惯上 是给 私有函数 命名的。 |