从 VC7 的 CHtmlView 不能正常退出谈 CComPtr 使用中的一个误区

分享一下CHtmlView指定IE内核版本崩溃问题及解决办法 相关环境: Win7 64位 MFC工程 UNICODE字符类型 相关技术点: 为进程指定用到的IE版本   http://blog.youkuaiyun.com/yanghongche/article/details/19481761 问题引出: 最近做一个类似浏览器的应用,加载网页地址url。我是自己写的一个类,继承自CHtmlView,然后做一些处理。 其中涉及到了必须得指定 阅读详情
一、错误再现
 
在 VC7 中新建一个 MDI 的 MFC Application,命名为MyHtml, 选择使用 CHtmlView。
 
建立两个 html 文件:
 
home.htm
<head>
<frameset rows="*,30">
   <frame src="test.htm">
   <frame src="about:blank">
</frameset>
</html>


test.htm
<html>
<head>
<script language="JavaScript"><!--
function FreshNew()
{
    window.alert("I'am here.");
    setTimeout('FreshNew();',2000);
}

setTimeout('FreshNew();',2000);
// --></script>
</head>
</html>

修改 CMyHtmlView 的 OnInitialUpdate()

void CMyHtmlView::OnInitialUpdate()
{
   CHtmlView::OnInitialUpdate();
   Navigate2(_T( http://www.openeim.com/));
}

编译并运行这个程序,在子窗口打开后将其关闭。你会发现浏览器控件还在运行。
 
二、错误分析
 
在 VC7 中,MFC 在很大程度上使用了 ATL,CHtmlView 也不例外,在 CHtmlView 中,访问 COM 指针的代码被修改为使用 ATL 的 CComPtr。CComPtr 是一个对 COM 指针进行包装的 ATL 模版,它实现了引用时自动 AddRef 和退出时自动 Release 这些以前很烦琐的操作。而由其发展出来的 CComQIPtr 则更将 QueryInterface 包装成 "=" 运算符,更加方便使用。对于这两个模版的详细介绍,不在本文的探讨范围,我只能假设您已经基本了解并已经用过这两个模版。
 
我们再来看看 VC7 的 CHtmlView 对 CComPtr 的使用方法。在函数 OnFilePrint 中,CHtmlView 的代码是这样的:
 
void CHtmlView::OnFilePrint()
{
  // get the HTMLDocument
  if (m_pBrowserApp != NULL)
 {
   CComPtr<IDispatch> spDisp = GetHtmlDocument();
   if (spDisp != NULL)
  {
   // the control will handle all printing UI
   CComQIPtr<IOleCommandTarget> spTarget = spDisp;
    if (spTarget != NULL)
    spTarget->Exec(NULL, OLECMDID_PRINT, 0, NULL, NULL);
  }
 }
}
在我所标记的一行中我们看到这样的代码:
CComPtr<IDispatch> spDisp = GetHtmlDocument();
 
而 GetHtmlDocument 的实现是什么样的呢?我们再来看看:
 
LPDISPATCH CHtmlView::GetHtmlDocument() const
{
 ASSERT(m_pBrowserApp != NULL);
 LPDISPATCH result;
  m_pBrowserApp->get_Document(&result);
  return result;
}
可以知道,GetHtmlDocument 返回的是 get_Document 所输出的一个接口指针,而我们知道,对于 COM 指针的一个使用原则是输出参数时进行引用计数,也就是说我们所获得的这个 result 在 get_Document 内部已经对其进行了 AddRef 调用,函数的调用者在不再需要这个指针的时候必须自行对指针进行 Release。
 
继续,我们再回头看 OnFilePrint 的代码,在代码中使用了 CComPtr 重载过的 "=" 运算符将函数的返回指针赋值给 spDisp。我们已经知道 CComPtr 在函数退出的时候会自动对其所包装的指针进行 Release,一切看起来都是正常而且天体无缝的。
 
那么到底错在哪里呢?恰恰就错在了这个 "=" 上面。
 
依照 COM 指针的引用时计数的原则,CComPtr 在实现的时候实现了自动化的引用计数。即在任何 "=" 操作的时候 AddRef,而在无效时 Release。我们来看看 "=" 运算符的具体实现代码是什么样的:
 
ATLINLINE ATLAPI_(IUnknown*) AtlComPtrAssign(IUnknown** pp, IUnknown* lp)
{
  if (lp != NULL)
   lp->AddRef();
  if (*pp)
  (*pp)->Release();
 *pp = lp;
  return lp;
}
从这段代码可以知道,CComPtr 在拿到指针后,并不是直接将其保存到自己的指针里面,而是先对拿到的指针进行 AddRef,保证引用计数,而后才执行 *pp = lp。
 
这样以来,我们将三部分代码合并起来就成了这样:
 
void CHtmlView::OnFilePrint()
{
 LPDISPATCH result; // 函数 GetHtmlDocument
 m_pBrowserApp->get_Document(&result); // 函数 GetHtmlDocument
 IDispatch* spDisp;
 
 result->AddRef(); // CComPtr 自动完成
 spDisp = result; // CComPtr 自动完成
 
 .......
 
 spDisp->Release(); // CComPtr 自动完成
}
 
能够看出其中的问题吗?对了,result 并没有被释放。问题出在函数输出的并不是一个引用计数完整的 COM 指针,而 CComPtr 并不知道,从而导致了这个指针最终被丢失。而 COM 对象也因为引用计数并没有回归为零而不敢清除自己,最终导致了 CHtmlView 不能正常退出。
 
三、修改
 
通过对上面代码的分析,我们已经清楚了解了 CHtmlView 错误的原因,下面我们就来试图对 CHtmlView 进行修正。
 
1.将 PROGRAM FILES\MICROSOFT VISUAL STUDIO .NET\Vc7\atlmfc\src\mfc 目录中的 viewhtml.cpp 复制到你自己的项目目录,并将其加入到自己的项目中。
2.打开 viewhtml.cpp, 寻找 GetHtmlDocument。
3.将所有的直接将 GetHtmlDocument 函数返回赋值给 CComPtr 指针的语句修改为使用 CComPtr 的 Attach。以 OnFilePrint 为例,代码将修改为下面的样子:
 
void CHtmlView::OnFilePrint()
{
  // get the HTMLDocument
  if (m_pBrowserApp != NULL)
 {
   CComPtr<IDispatch> spDisp;
 
  spDisp.Attach(GetHtmlDocument());
   if (spDisp != NULL)
  {
   // the control will handle all printing UI
   CComQIPtr<IOleCommandTarget> spTarget = spDisp;
    if (spTarget != NULL)
    spTarget->Exec(NULL, OLECMDID_PRINT, 0, NULL, NULL);
  }
 }
}
 
重新编译你的程序,再用最开始我提到的 html 进行测试,你会发现一切都正常了。看起来麻烦一些,但是是正确的。
 
四、结论
 
通过上面分析纠错,我们可以知道,CComPtr 并不是一把万能钥匙,而对 COM 指针的使用也远没有因为 ATL 的出现而变得通俗起来。如果具体到这个例子,我们可以得到一个结论:
 
任何时候不要将函数的返回指针赋值给一个 CComPtr。
excel 利用SUBTOTAL函数计算筛选后数列总和、均值、最大、最小值 表里有三个人,咱们需要筛选出三个人,并分别计算他们的总和值。 先看一下数据范围(A1:B27) 通过筛选找张三。 按照上图所示输入函数,选择9,求和。 然后按照函数输入即可。 就能计算出结果。 筛选项选择王五,就会自动计算王五的总和。 筛选到李四就会自动计算李四的总和。 如果把9改成1,就是自动计算筛选出来的均值结果,如下图所示。 如果改成4就是取筛选项的最大值,选择5就是取最小值。 ... 阅读详情

相关推荐

envi5.3处理高分二号影像数据详细过程记录

全文根据此篇文章进行数据处理: tm影像辐射定标_高分二号影像数据预处理及裁剪过程 其他参考: 学习笔记---遥感影像辐射定标与大气校正 利用ENVI自带全球DEM数据计算区域平均高程 高分二号数据处理流程(有高分二号的数据信息) GF2有多光谱和全色两个数据,MSS是多光谱的,PAN是全色的,多光谱的分辨率低,全色的高,需要把这两个数据融合,融合之前需要做定标等处理,获取经纬度。 一、多光谱影像处理 1. 辐射定标 以这个为例: 其他路径\2022.4.2...

ligous的博客 5万+

CHtmlView,点击网页中的按钮

有如下HTML,如何用程序触发点击按钮呢?HTML> HEAD>  TITLE> New Document TITLE>  META NAME="Generator" CONTENT="EditPlus">  META NAME="Author" CONTENT="">  META NAME="Keywords" CONTENT="">  META NAME="

++ の 博客 5051

华为交换机与思科/华三设备LACP对接实战:手把手教你配置链路聚合

本文详细解析了华为交换机与思科、华三设备间的LACP链路聚合配置实战,涵盖核心原理、配置步骤及排错技巧。通过对比不同厂商的实现差异,提供可落地的跨厂商对接方案,助力企业网络工程师高效部署高可靠性链路聚合。

weixin_30836759的博客 425

CHtmlView中如何禁用HTML页面的上下文菜单

1.添加"MyIEWnd.h"// MyIEWnd.h: interface for the CMyIEWnd class. // ////////////////////////////////////////////////////////////////////// #if !defined(AFX_MYIEWND_H__348AB709_5BCD_4815_BE

Jinhill's Blog 1481

用C#和MQTTnet在WinForm里做个简易物联网监控后台(附完整源码)

本文详细介绍了如何使用C#和MQTTnet库在WinForm中构建一个简易物联网监控后台。通过实战案例,包括环境配置、MQTT服务端实现、客户端监控功能及高级优化技巧,帮助开发者快速搭建高效的物联网监控系统,适用于工业自动化和智能家居场景。

weixin_29540599的博客 393

希捷硬盘卡死修复实战:U盘启动盘制作与低格清零全流程

机械硬盘使用多年后常出现卡顿、假死、坏道等问题,很多用户在网上搜索“希捷硬盘低格工具”或“U盘硬盘复活器”,却发现要么工具不明,要么操作不当造成二次损伤。其实所谓修复工具,本质是U盘启动环境配合硬盘检测与清零软件,低格并非修复物理坏道,而是通过全盘写零触发主控重映射,隔离不稳定扇区。懂原理后,用官方SeaTools、Ventoy/U盘启动盘、Victoria或Linux dd等组合工具,即可对可抢救的硬盘做清零修复。这一技术适用于逻辑坏道、SMART警告、扇区不稳定等场景,但需先备份数据并判断盘体是否有异响

weixin_30431445的博客 218

MFC界面--利用CHtmlView和HTML制作新风格的界面(包括CView和Dialog)

一、文档视图形式,以一个视图cview(chtmlview)作为首页界面 转自:http://liuxiang031130.blog.163.com/blog/static/1176665520111117914849/ 用过 Outlook Express 的很多人都对其第一页的 HTML 界面感到新奇,很明显这是使用 DHTML 技术,加入了一些 Java Script 的一个网页,但它能

Wait的专栏 1万+

Lossless-Claw 插件实战:告别上下文截断,让 OpenClaw 永不遗忘

本文介绍了OpenClaw的Lossless-Claw插件,这是一个基于LCM论文的DAG摘要系统,能有效解决上下文截断问题。文章包含10个部分,从插件原理到实操指南: 核心原理:通过DAG结构持久化存储所有原始消息,将旧消息分块摘要并形成层级结构,保持上下文在模型Token限制内。 性能优势:在OOLONG基准测试中得分74.8,优于Claude Code的70.3,尤其在长上下文场景表现更佳。 功能特点: 提供lcm_grep、lcm_describe等工具主动回忆历史 摘要始终链接回原文,实现真正无损

u014798858的博客 2619

[转载]从 VC7 的 CHtmlView 不能正常退出谈 CComPtr 使用中的一个误区

 从 VC7 的 CHtmlView 不能正常退出谈 CComPtr 使用中的一个误区响马lion@public1.ptt.js.cn> 一、错误再现 在 VC7 中新建一个 MDI 的 MFC Application,命名为MyHtml, 选择使用 CHtmlView。 建立两个 html 文件: home.htm      test.htmfunction Fr

hixixi的专栏 1135

基于MATLAB的井筒多相流模拟

井筒多相流的模拟可以基于不同的数学模型和计算方法。其中,最常用的模型之一是多相流模型,它基于质量守恒、动量守恒和能量守恒等原理,描述了流体在井筒中的流动行为。对于井筒多相流的模拟和分析可以帮助我们理解和优化油气田开发过程中的流体行为,从而提高产量和效率。在本文中,我们将介绍如何使用MATLAB进行井筒多相流的模拟,并提供相应的源代码。需要注意的是,以上示例是一个简化的模拟,仅用于演示如何使用MATLAB进行井筒多相流模拟。实际应用中,我们需要考虑更多的物理过程和参数,并使用更复杂的数值方法和模型进行模拟。

AtdiHtml的博客 706

Debian Buster 软件源失效问题

摘要:基于Debian Buster的ARM64设备因系统版本结束支持(EOL)导致apt update报错404。解决方案包括:1)改用Debian官方存档源(需禁用安全检查);2)升级至受支持的Debian 11/12版本(推荐);3)临时使用第三方镜像源(不推荐)。操作步骤涉及修改sources.list、处理NTP同步问题及清理残留配置。建议优先采用版本升级方案以获得持续安全更新,避免使用过时系统带来的安全隐患。文中提供了完整命令示例和操作记录供参考。

yy_xzz的博客 2179

基于VC++的WEB浏览器的实现

id=15148在要求的功能之上,对 Web 浏览器的功能进行了扩充,能实现网页保存、打印网页、在网页上查找、选中全部内容、标签式多窗口浏览、关闭浏览器提示、页面缩放、网页加载进度显示、浏览器状态以及界面样式更换等功能。本次毕业设计所实现的 Web 浏览器首先要实现设计要求中的功能,要有友好的界面,能正常的浏览网页,能实现后退、前进、刷新等基本功能。设计题目:基于VC++的WEB浏览器的实现设计要求:①能实现浏览器外观界面的设计。②能实现网页的浏览、后退、前进、刷新等基本功能。

毕业作品网站 2463

RockChip Android14 修改LCD背光最大值

在调试LCD屏时时长会出现硬件不匹配,导致电流过大,屏幕发热严重。在不调整硬件的情况下,我们可以通过修改软件,降低LCD背光最大值来实现适配。我们都知道LCD屏背光是靠pwm来控制,一般来说最大值可以设置为255,针对上述问题,我们可以通过软件来降低该值,比如200,100等等。

qq_34968572的博客 631

CHtmlView在vs2010/vs2017中崩溃问题的解决

定义MFC类CHtmlViewExt,继承CHtmlView。 1、在vs2010中,用CHtmlViewExt作为doc视图类,关闭文档时会导致程序崩溃。 解决方法:覆盖 PostNcDestroy、OnDestroy两个函数。 (1)覆盖PostNcDestroy() void CHtmlViewExt::PostNcDestroy() { //CHtmlView::PostNcDestroy();//注释掉自动生成的代码,防止CView 销毁自己导致关闭程序时崩溃 } (2)覆盖O...

atp069121的博客 434

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

MFC程序退出错误原因

自己在修改一个五子棋时,遇到了MFC程序

samdyli先生的专栏-wx:lisamdy 3803

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

MFC中使用CHtmlView时的问题

使用CHtmlView时的问题 参考:https://blog.youkuaiyun.com/xiaolongwang2010/article/details/11100923 CRuntimeClass* prc = RUNTIME_CLASS(CHtmlView); m_pHtmlView = DYNAMIC_DOWNCAST(CHtmlView, prc->CreateObject()); m_pHtmlView->Create(NULL, _T(""), WS_CHILD | WS_VISIBLE,

htj10的博客 537

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

MFC中手动create窗口退出程序报错的解决方法

问题产生自一个需要添加列表(CListView)的工程

猪哥的白驼山 4073

关于 COM 指针·3则

最近在玩 MSHTML 和 MSXML,被一堆 COM 接口搞的晕头转向。以前也玩过一些,但基本都是照抄别人的代码,也没注意到 IDispatch * 和 IDispatchPtr 有啥区别,就模糊的认为可能是同一个东东的两种写法罢……这次趁机仔细研究了一番,转载3篇 COM 智能指针的详细的介绍,以备不时之需 ATL智能指针类 ATL中包含的智能指针包括:CAutoPtr、CAu

Perry 的专栏 2467

IHTMLDocument2接口访问Dom,完成自动搜索

首先感叹下:冬至了,别人都去聚餐言欢,我去孤独写这些文字 之所以写这个东西,是一个网管朋友出50元大洋让我写的,有了这个东东,在网吧可以很轻松的做网吧增值广告了.当时是星期天,想着又没有事做,就答应了,虽知星期天的事情还真多,知道昨天晚上才搞定. 我们来看下这位朋友的要求: 1、网站址:http://www.v232.com/?username,后面的username最好能在配置...

weixin_30852419的博客 333

CComPtr用法

CComPtr用法 COM接口指针很危险,因为使用过程中需要每一个使用者都要严格并且正确的AddRef和Release,一旦出现问题,就会造成对象不能被正常释放,或者对象被重复删除,造成程序崩溃。所以使用COM接口,必须小心翼翼才行。 但是,即使所有的代码中,都正确...

aimang9690的博客 588

关于 IDispatch 接口的 LPDispatch 属性的实现

文章概要:在我们自己写的自动化组件中,当然你可以把所有的方法都用唯一的一个自动化接口表现出来,但是这样好吗?所有的方法都处于一个层次上,没有适当的分类,显然不是个优秀的组件。好了,下面看看我们如何实现分层次的自动化组件吧。 好象是绕口令一样的标题。呵呵,看看下面的这个例子,我想大家就知道是什么意思了吧。 在脚本语言中,我们经常看到类似这样的语句:obj.Document.Write(...

smallfish6的专栏 1350

IDispatch接口原理与应用

IDispatch接口原理与应用目录:IDispatch接口原理与应用... 1目录:... 1前言:... 1IDispatch接口的定义:... 1创建支持IDispatch接口的COM对象:... 4标准方式调用IDispatch接口的方法:... 5采用ATL智能指针类调用IDispatch接口的方法:... 7使用类COleDispatchDriver调用IDispatch的方...

612
上一篇: 调整的飞秋官网幅度还非常的大
下一篇: 改變HTML中的光標問題
普通网友
博客等级 码龄22年 1万+粉丝 3156原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值