自定义ActiveX组件在设计阶段,切换属性页后出现异常

源码下载:ActiveX-Clock-OCX

 

参照孙鑫的<<VC++深入详解>>中第18章自定义ActiveX中的Clock例子(到18.3节之前),完成了OCX控件的制作,而且也编译(Debug模式)、注册成功了!于是又创建了一个MFC基于对话框的测试程序,在对话框中放入了这个Clock控件,界面如下:

接下来右击Clock控件,选择“属性”,切换到“设置时间间隔面板”,更改时间后,切换到其他一个属性页,这时就出现assert宏异常了,看图:

 

 

 

真是奇怪,孙鑫的教程里也没提到有这个问题。后来试了下在Release模式下编译成功的OCX,发现在切换属性页时却没有这样的问题,一切都是正常的。

看来是优化的问题吧,详情未知,猜测而已!

 

看到第18章的总结(Page708)才发现,原来孙鑫老师还是提到了这个问题的。

他说出现这种错误的原因是:当将Clock控件放到VB的Form上时,该控件的窗口已经创建,也就是说,CClockCtrl类的OnCreate()方法被执行了,这样就设置了定时器。而在VC的对话框上插入Clock控件时,却没有调用CClockCtrl类的OnCreate()方法,当修改Interval属性时,会调用CClockCtrl类的OnIntervalChanged()方法,在这个方法中,调用了KillTimer(1),因为定时器根本没有创建,因此就出现了非法操作。解决办法是:用一个变量保存定时器的返回值,然后在OnIntervalChanged()方法中对返回值进行判断。

 于是我将代码改成下面的样子:

void CClockCtrl::OnIntervalChanged() 
{
if(m_nInterval < 0 || m_nInterval > 6000)
m_nInterval = 1000;
else
m_nInterval = m_nInterval / 1000 * 1000;
//if(timer_flag != 0)
{
MessageBox("OnIntervalChanged: going to do KillTimer()");
//KillTimer(1);
timer_flag = 0;
}
MessageBox("OnIntervalChanged: going to do SetTimer()");
//timer_flag = SetTimer(1, m_nInterval, NULL);
SetTimer(1, m_nInterval, NULL);
char message[100] = {0};
sprintf(message, "timer_flag = %d", timer_flag);
MessageBox(message);
SetModifiedFlag();
}


再经过测试,发现在切换属性页时,弹出窗口输出了“OnIntervalChanged: going to do SetTimer()”后就出现了ASSERT()宏异常,可见这个异常是出现在SetTimer()内部的。我们都知道,ASSERT()宏只有在Debug模式下才会起作用,在Release下是不会起作用的,这就是为什么使用Release时生成的ocx时不会弹出ASSERT()宏异常窗口的原因了。可是为什么SetTimer()会失败呢???

先来看下Plateform SDK中的SetTimer()原型吧:

UINT_PTR SetTimer(
HWND hWnd,              // handle to window
UINT_PTR nIDEvent,      // timer identifier
UINT uElapse,           // time-out value
TIMERPROC lpTimerFunc   // timer procedure
);


看到第一个参数hWnd了吗,这是与窗口的句柄相关联的,但是孙鑫老师也说了“将Clock控件放到VB的Form上时,该控件的窗口已经创建”,但是“在VC的对话框上插入Clock控件时,却没有调用CClockCtrl类的OnCreate()方法 ”,这里的关键不是指“OnCreate()中的SetTimer()”,而是指“窗口没有创建”,所以“窗口对应的句柄又将是多少”呢?正是因为控件窗口没有创建,所以“CClockCtrl::OnIntervalChanged() ”中的“SetTimer()”和“KillTimer()”都将会失败,而且失败的主要原因是在其函数内部对“窗口句柄”的ASSERT()判断。因此,我认为孙鑫老师说的“解决办法”是行不通的,除非不调用KillTimer()和SetTimer(),但是这样的话,就达不到控制多少秒触发一次OnDraw()的效果了!

经过调试,终于在“D:\Program Files\Microsoft Visual Studio\VC98\MFC\Include\AFXWIN2.INL文件中的第166-171行”找到了SetTimer()和KillTimer()的具体实现:

_AFXWIN_INLINE UINT CWnd::SetTimer(UINT nIDEvent, UINT nElapse,
void (CALLBACK* lpfnTimer)(HWND, UINT, UINT, DWORD))
{ ASSERT(::IsWindow(m_hWnd)); return ::SetTimer(m_hWnd, nIDEvent, nElapse,
(TIMERPROC)lpfnTimer); }
_AFXWIN_INLINE BOOL CWnd::KillTimer(int nIDEvent)
{ ASSERT(::IsWindow(m_hWnd)); return ::KillTimer(m_hWnd, nIDEvent); }


因此,我认为解决的办法有3种

1. 使用“Release方式生成的OCX”

2. 越过KillTimer()和SetTimer()中“ASSERT(::IsWindow(m_hWnd)); ”,即将CClockCtrl::OnIntervalChanged() 中的内容修改如下:

void CClockCtrl::OnIntervalChanged() 
{
if(m_nInterval < 0 || m_nInterval > 6000)
m_nInterval = 1000;
else
m_nInterval = m_nInterval / 1000 * 1000;
//KillTimer(1);					// 为了越过KillTimer()中的ASSERT(::IsWindow(m_hWnd)); 
::KillTimer(m_hWnd, 1);
::SetTimer(m_hWnd, 1, m_nInterval, NULL);
//SetTimer(1, m_nInterval, NULL);
SetModifiedFlag();
}


这时,在切换属性页时虽然也会执行::KillTimer和::SetTimer(),而且其中的m_hWnd可能为一个非法的值,但是起码不会弹出ASSERT()宏异常窗口,大不了就是这两个函数调用失败而已,所以也解决了这个问题。

3. 判断控件当前状态是否为运行状态,如果是才调用SetTimer()和KillTimer(),即修改CClockCtrl::OnIntervalChanged()的内容如下:

 

void CClockCtrl::OnIntervalChanged() 
{
if(m_nInterval < 0 || m_nInterval > 6000)
m_nInterval = 1000;
else
m_nInterval = m_nInterval / 1000 * 1000;
if(AmbientUserMode())
{
KillTimer(1);					// 为了越过KillTimer()中的ASSERT(::IsWindow(m_hWnd)); 
//::KillTimer(m_hWnd, 1);
//::SetTimer(m_hWnd, 1, m_nInterval, NULL);
SetTimer(1, m_nInterval, NULL);
}
SetModifiedFlag();
}


如果各位有什么不同的看法,欢迎提出来探讨!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/407140.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#正则表达式整理备忘

转载于&#xff1a;http://www.cnblogs.com/KissKnife/archive/2008/03/23/1118423.html有一段时间&#xff0c;正则表达式学习很火热很潮流&#xff0c;当时在CSDN一天就能看到好几个正则表达式的帖子&#xff0c;那段时间借助论坛以及Wrox Press出版的《C#字符串和正则表达式…

vue.js 引用背景图 background 无效的3种解决办法

&#xff03;vue.js项目中&#xff0c;出现css调用background背景图无效&#xff1f;如何解决&#xff1f; 或者调用<img>标签&#xff0c;也无效果&#xff1f; 直接上代码&#xff0c;自行对比查找一下&#xff1a; 效果图预览 1. 正确的代码&#xff0c;示例如下&…

RETSful 的真正含义

Representational State Transfer "表现层状态转化"。 三个概念&#xff1a; 1、资源&#xff08;Resources&#xff09;&#xff1a;"表现层"其实指的是"资源"的"表现层"。 所谓"资源"&#xff0c;就是网络上的一个实体&a…

CSS之Responsive网页设计的三个特性

Responsive网页设计无疑是网页设计中的一个热门话题。某种程度上&#xff0c;他将是一个最受欢迎的网页设计概念&#xff0c;因为随着网站用户日渐多样化的访问方法&#xff0c;比如说“iPad”、“iPhone”、“Android移动设备”、“平板电脑”、“台式机”以及“ 笔记本”等不…

什么是awk?

你可能对UNIX比较熟悉&#xff0c;但你可能对awk很陌生&#xff0c;这一点也不奇怪&#xff0c;的确&#xff0c;与其优秀的功能相比&#xff0c;awk还远没达到它应有的知名度。awk是什么&#xff1f;与其它大多数UNIX命令不同的是&#xff0c;从名字上看&#xff0c;我们不可能…

linux中mv命令使用详解

mv命令是move的缩写&#xff0c;可以用来移动文件或者将文件改名&#xff08;move (rename) files&#xff09;&#xff0c;是Linux系统下常用的命令&#xff0c;经常用来备份文件或者目录。 1&#xff0e;命令格式&#xff1a; mv [选项] 源文件或目录 目标文件或目录 2&…

CSS之不使用Media Queries的自适应CSS

虽然标题说不用Media Queries&#xff0c;但我还是要在开头讲清楚&#xff0c;本文并不是要大家丢掉Media Queries&#xff0c;也不是要抨击Media Queries。Media Queries实际上非常有用&#xff0c;我在各种地方都会用到。但Media Queries并不能解决所有的自适应的设计问题 本…

Taro+react开发(32) Please use the ‘new‘ operator, this DOM object constructor cannot be called as a fu

2.Failed to construct Image: Please use the new operator, this DOM object constructor cannot be called as a function 像上面这种错误都是使用了元素&#xff0c;但没有import到文件导致。

0920

今天的亚洲区网络赛我们学校第一次把工大和工程干掉了 有一种慕名奇妙的自豪感 转载于:https://www.cnblogs.com/zhanzhao/p/3983866.html

Linux下的文件系统与目录系统简介

Linux下的文件系统与目录系统简介一. 文件系统 LINUX有四种基本文件系统类型&#xff1a;普通文件、目录文件、连接文件和特殊文件&#xff0c;可用file命令来识别。 普通文件&#xff1a;如文本文件、C语言元代码、SHELL脚本、二进制的可执行文件等&#xff0c;可用cat、less、…

修改DOS窗口编码格式

1、打开CMD.exe命令行窗口 2、通过 chcp命令改变代码页&#xff0c;UTF-8的代码页为65001 F:\trash> chcp 65001执行该操作后&#xff0c;代码页就被变成UTF-8了。但是&#xff0c;在窗口中仍旧不能正确显示UTF-8字符。 3、修改窗口属性&#xff0c;改变字体 在命令行标题栏…

CSS3属性之text-indent文本缩进使用详解

1、定义&#xff1a;text-indent 属性规定文本块中首行文本的缩进。 2、使用&#xff1a; 将段落的第一行缩进2em&#xff1a; div{text-indent:2em;} 注意: 1em等于一个汉字的大小 3、注意事项&#xff1a; 3-1、允许使用负值。如果使用负值&#xff0c;那么首行会被缩进…

Linux嵌入式入门

虚拟机Linux系统网络配置&#xff1a; 1、Vmware网络设置 虚拟机设置->网路适配器->网络连接 桥接模式&#xff1a;能提供独立的IP地址的情况下使用NAT模式&#xff1a;一台计算机只能使用一个IP&#xff0c;主机与虚拟机共享IP&#xff0c;外部网络无法发现虚拟机&#…

CSS之Responsive设计和CSS3 Media Queries的结合

随着高科技的发展&#xff0c;现在我们浏览网页不在局限于PC机上了&#xff0c;用户可使用上网的设备是越来越多的品种&#xff1a;手机、小笔记本、iPad、Playbook&#xff0c;以及PC机&#xff0c;而且PC机的显展大小各不一致。这样一来不同的屏幕分辨率范围就产生了&#xf…

服务器性能测试典型工具介绍

服务器性能测试典型工具介绍 众所周知&#xff0c;服务器是整个网络系统和计算平台的核心&#xff0c;许多重要的数据都保存在服务器上&#xff0c;很多网络服务都在服务器上运行&#xff0c;因此服务器性能的好坏决定了整个应用系统的性能。现在市面上不同品牌、不同种类的服务…

select count(*) into 也会报 NO_DATA_FOUND 异常?!

From: http://www.cnblogs.com/howelei/archive/2006/12/21/599268.html 我们知道NO_DATA_FOUND异常情况仅仅被SELECT..INTO语句触发&#xff0c;当该WHERE子句没有找到任何行的时候就会触发它。 解决的方法通常有两种&#xff1a; 一种是我们将查询语句写成游标&#xff0c;这…

setInterval 和setTimeout 清空定时器,返回值,赋值为null的区别

说到定时器&#xff0c;很多人都不陌生&#xff0c;觉得这个有什么说的&#xff0c;很简单的了&#xff0c;其实你真正的理解了它了吗&#xff1f; 定时器的返回值是什么&#xff1f;clearInterval和 null有什么区别&#xff0c;可能有些干了几年的都不知道&#xff0c;下面我以…