现在的位置: 首页 > 综合 > 正文

ATL 开发ActiveX控件之定时器使用(改进,含源码)

2013年10月04日 ⁄ 综合 ⁄ 共 6583字 ⁄ 字号 评论关闭

原定时器设计:http://blog.csdn.net/strmagic/archive/2007/10/23/1840365.aspx (如不能访问请看本文最后的原文附录)

原定时器缺点1:使用继承方式无法实现一个类具有多个定时器

原因:采用继承方式

改进思路:将继承方式给成聚合,将定时器作为类的成员变量,这样便可以定义多个定时器

具体方案:1.增加public的成员变量 T* m_cls和 UINT m_nTimerID;     

2.将TimerOn函数中的第1条语句修改为Derived* pDerived = ((Derived*)m_cls);(m_cls指需要使用定时器的类的对象.原设计方案采用继承方式,因此使用this,而改进方案作为m_cls的成员变量,因此不能在使用this)

3.修改OnTimer函数,增加一个参数UINT m_nTimerID.(m_nTimerID是定时器ID,用于识别多个定时器)     

4.在需要使用定时器的类(本例为自定义的类Catl)中定义两个定时器(可以定义任意个,这里以两个为例).         

CTimer m_timerForRFID;//读取标签的定时器         

CTimer m_timerForCountTime;//计算剩余时间的定时器

5.定义为定时器定义两个标识符,作为定时器ID         

#define TIMERID_RFID 100         

#define TIMERID_COUNTTIME 200

6.在Catl的构造函数中增加:         

m_timerForRFID.m_cls=this;        

m_timerForRFID.m_nTimerID=TIMERID_RFID;        

m_timerForCountTime.m_cls=this;        

m_timerForCountTime.m_nTimerID=TIMERID_COUNTTIME;

7.使用 打开定时器:m_timerForCountTime.TimerOn(m_dwTimerInterval);m_timerForRFID.TimerOn(m_dwTimerInterval); 关闭定时器:m_timerForRFID.TimerOff();m_timerForCountTime.TimerOff();

处理函数:使用switch case 根据不同的定时器ID进行处理.

 

原定时器缺点2:不能在需要使用定时器的OnTimer函数中关闭定时器

原因:原定时器使用线程模拟定时器的关键代码是Apartment函数中的while循环,在循环中增加sleep达到定时功能.其结束的条件是m_bTimerOn=FALSE.由于m_bTimerOn是关键成员变量,不易对外公开,因此在OnTimer函数中不能访问m_bTimerOn来结束,而TimerOff必须由需要使用定时器的线程来调用才能结束定时器线程,而不能定时器线程自己调用TimerOff来结束自身(线程结束自身的最佳办法是线程函数退出)

改进思路:OnTimer增加BOOL* b_isOver参数,其中b_isOver和m_bTimerOn共同作为Apartment函数中的while循环结束条件

具体方案:

1.修改Apartment函数的while循环如下:     

      

 

2.在OnTimer中设置b_isOver,如果需要结束,可在OnTimer中将b_isOver=TRUE.

 

附改进后源代码:

头文件:

 

附原文:

在Window编程中,我们经常要依靠定时器来定时触发某些代码的执行。但在ATL 的ActiveX 编程中,定时器的使用受到了一定限制,下面,我就根据开发经验谈谈如何在ATL 的 ActiveX编程中使用定时器这一资源。
  首先,为了优化的性能,当前ActiveX  控件 分两种有窗口和无窗口控件。
在有窗口控件中你所获得的编程资源几乎和普通的Windows编程没有两样,而定时器的使用也一样。在ATL中你只要在控件的构造函数中指定控件基类CComControlBase 的成员m_bWindowOnly 为 true 就可以创建一个有窗口的ActiveX控件。示例如下:
   myControl : myControl(){
   m_bWindowOnly = true;
   }
  这样就可以在程序中用 SetTimer/KillTimer 和 响应 WM_TIMER消息来设置并使用定时器。
  当作为一个ATL程序员,我们当然不会放弃每一个优化程序性能的机会,下面我就来介绍一下在ATL中的无窗口ActiveX控件中使用定时器的几种方法:
  第一种:使用回调函数。在VC中,由于MFC和ATL了包装,我们可以忽略窗口句柄参数,直接创建一个和窗口关联的定时器。当无窗口控件由于没有窗口句柄,直接调用CWindow的SetTimer函数会给你抛出一个ASSERT对话框来。这时候我们只好回到API来寻求帮助, 由于 API SetTimer在创建一个定时器时除了窗口句柄,还为我们提供了通过回调函数来响应定时事件,这样,我们就可以绕过无窗口控件的约束使用定时器了。
  首先,定义一个定时器的回调函数:
  VOID CALLBACK TimerProc(
    HWND hwnd,        // 定时器消息的窗口句柄
    UINT message,     // WM_TIMER 消息
    UINT idTimer,     // 定时器标志
    DWORD dwTime)     // 当前系统启动计时
  {
     //这里添加你的定时器处理代码
  }
  接下来,就可以使用SetTimer来使用定时器了
  uResult = SetTimer(NULL,      // handle to main window
             ID_TIMER,          // 定时器标识
             1000,              // 1 秒间隔
             (TIMERPROC)TimerProc); // 回调函数
  
  第二种:通常我们在使用定时器时,往往希望在定时事件出发时可以通知自己的ActiveX 控件,虽然上面方法可以,但在参数的传递上有些不便,这里我使用多线程来模拟实习之,作为ATL中的编程风格,在向实现类添加某些功能,通常使用模板基类来扩充,故首先定义如下基类: 
   
  从基类中可以看到,在线程函数中定时调用子类的OnTimer接口函数。这样我们只要从CTimer 中派生,并在子类接口中定义OnTimer接口,并实现该接口函数,就可以获得定时的调用,而TimerOn则用来开始并指定定时间隔,而TimerOff则用来关闭定时器。子类的代码如下:
 

声明:方法二参考了MSDN中相关资料。
  
  后记:实际上,在无窗口ActiveX控件中使用定时器的方法是很多,在这里只概述了两种。原本想就ATL中使用定时器这一功能进行比较详细描述,但由于中间工作原因间断,现在思源枯竭,只能写这些勒,如果这篇文章对于初次接触 ATL ActiveX 控件编程朋友有所参考,那在下就很感激了。

抱歉!评论已关闭.