热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

源码下载:ActiveX-Clock-OCX参照孙鑫的中第18章自定义ActiveX中的Clock例子(到18.3节之前),完成了O

源码下载:ActiveX-Clock-OCX

 

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

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

 

 

 

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

看来是优化的问题吧&#xff0c;详情未知&#xff0c;猜测而已&#xff01;

 

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

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

 于是我将代码改成下面的样子&#xff1a;

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


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

先来看下Plateform SDK中的SetTimer()原型吧&#xff1a;

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


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

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

_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); }


因此&#xff0c;我认为解决的办法有3种&#xff1a;

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

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

void CClockCtrl::OnIntervalChanged()
{
if(m_nInterval <0 || m_nInterval > 6000)
m_nInterval &#61; 1000;
else
m_nInterval &#61; 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();
}


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

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

 

void CClockCtrl::OnIntervalChanged()
{
if(m_nInterval <0 || m_nInterval > 6000)
m_nInterval &#61; 1000;
else
m_nInterval &#61; 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();
}


如果各位有什么不同的看法&#xff0c;欢迎提出来探讨&#xff01;


推荐阅读
  • 利用Visual Basic开发SAP接口程序初探的方法与原理
    本文介绍了利用Visual Basic开发SAP接口程序的方法与原理,以及SAP R/3系统的特点和二次开发平台ABAP的使用。通过程序接口自动读取SAP R/3的数据表或视图,在外部进行处理和利用水晶报表等工具生成符合中国人习惯的报表样式。具体介绍了RFC调用的原理和模型,并强调本文主要不讨论SAP R/3函数的开发,而是针对使用SAP的公司的非ABAP开发人员提供了初步的接口程序开发指导。 ... [详细]
  • 拥抱Android Design Support Library新变化(导航视图、悬浮ActionBar)
    转载请注明明桑AndroidAndroid5.0Loollipop作为Android最重要的版本之一,为我们带来了全新的界面风格和设计语言。看起来很受欢迎࿰ ... [详细]
  • 如何搭建Java开发环境并开发WinCE项目
    本文介绍了如何搭建Java开发环境并开发WinCE项目,包括搭建开发环境的步骤和获取SDK的几种方式。同时还解答了一些关于WinCE开发的常见问题。通过阅读本文,您将了解如何使用Java进行嵌入式开发,并能够顺利开发WinCE应用程序。 ... [详细]
  • ShiftLeft:将静态防护与运行时防护结合的持续性安全防护解决方案
    ShiftLeft公司是一家致力于将应用的静态防护和运行时防护与应用开发自动化工作流相结合以提升软件开发生命周期中的安全性的公司。传统的安全防护方式存在误报率高、人工成本高、耗时长等问题,而ShiftLeft提供的持续性安全防护解决方案能够解决这些问题。通过将下一代静态代码分析与应用开发自动化工作流中涉及的安全工具相结合,ShiftLeft帮助企业实现DevSecOps的安全部分,提供高效、准确的安全能力。 ... [详细]
  • 微软头条实习生分享深度学习自学指南
    本文介绍了一位微软头条实习生自学深度学习的经验分享,包括学习资源推荐、重要基础知识的学习要点等。作者强调了学好Python和数学基础的重要性,并提供了一些建议。 ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • [译]技术公司十年经验的职场生涯回顾
    本文是一位在技术公司工作十年的职场人士对自己职业生涯的总结回顾。她的职业规划与众不同,令人深思又有趣。其中涉及到的内容有机器学习、创新创业以及引用了女性主义者在TED演讲中的部分讲义。文章表达了对职业生涯的愿望和希望,认为人类有能力不断改善自己。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • 本文介绍了游标的使用方法,并以一个水果供应商数据库为例进行了说明。首先创建了一个名为fruits的表,包含了水果的id、供应商id、名称和价格等字段。然后使用游标查询了水果的名称和价格,并将结果输出。最后对游标进行了关闭操作。通过本文可以了解到游标在数据库操作中的应用。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • Imtryingtofigureoutawaytogeneratetorrentfilesfromabucket,usingtheAWSSDKforGo.我正 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • 本文介绍了在Ubuntu 11.10 x64环境下安装Android开发环境的步骤,并提供了解决常见问题的方法。其中包括安装Eclipse的ADT插件、解决缺少GEF插件的问题以及解决无法找到'userdata.img'文件的问题。此外,还提供了相关插件和系统镜像的下载链接。 ... [详细]
  • 本文介绍了某点评网的搜索策略,包括名称和地址的匹配策略,模糊匹配的方法以及不同口音和拼音的近似发音。同时提供了一些例子来说明这些策略的应用。 ... [详细]
author-avatar
苦蔷薇1988
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有