正在读取数据,请稍侯
正在读取数据,请稍侯
 
 VC计时器的一个使用心得
□ clever101 发表于 2008-2-24 0:05:00

                            朱金灿

 

最近使用VC的计时器。计时器一般是先设置一个Timer,然后响应WM_TIMER消息,然后销毁计时器。但是我发现在哪里设置计时器和销毁计时器是有讲究的。

 

开始我的代码是这样的:

CMain::CMain()

{

       // TODO: add member initialization code here

       SetTimer(1, 5000, 0);

}

// WM_TIMER消息响应函数

void CMain::OnTimer(UINT nIDEvent)

{

       // TODO: Add your message handler code here and/or call default

       AfxMessageBox("Hello World!");

       CWnd::OnTimer(nIDEvent);

}

 

CMain::~CMain()

{

       KillTimer(1);

}

 

编译结果是,debug模式编译下出现Assertion Fauled

 调试时发现出错是在BOOL CTestTimerApp::InitInstance()函数中的一句:

       if (!ProcessShellCommand(cmdInfo))

              return FALSE;

发生的。

 

但是在release模式编译成功。想来是因为release模式忽略Assert宏的缘故,但是运行程序却没有Hello World!的对话框弹出。

 

     后来我想莫非是SetTimer(1, 5000, 0);函数放置的地方不对的缘故。后来我把它

框架类的OnCreate函数。

int CMain::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

       if (CWnd::OnCreate(lpCreateStruct) == -1)

              return -1;

      

       if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP

              | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||

              !m_wndToolBar.LoadToolBar(IDR_MAIN))

       {

              TRACE0("Failed to create toolbar\n");

              return -1;      // fail to create

       }

 

       if (!m_wndStatusBar.Create(this) ||

              !m_wndStatusBar.SetIndicators(indicators,

                sizeof(indicators)/sizeof(UINT)))

       {

              TRACE0("Failed to create status bar\n");

              return -1;      // fail to create

       }

 

       // TODO: Delete these three lines if you don't want the toolbar to

       //  be dockable

       m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);

       EnableDocking(CBRS_ALIGN_ANY);

       DockControlBar(&m_wndToolBar);

    SetTimer(1, 5000, 0); // 在这里设置计时器

       return 0;

}

 

这样编译debugm通过, Hello World!的对话框也出来了。但是在程序退出时检测到有内存泄露:Detected memory leaks!

 

我估计在销毁计时器的代码有问题。于是我把放到响应WM_DESTROY消息的函数里。

void CMain::OnDestroy()

{

       CWnd::OnDestroy();

      

       // TODO: Add your message handler code here

       KillTimer(1);

}

      为什么设置计时起不能放在窗口类构造函数,销毁计时器不能放在窗口类的析构函数里?让我们看看MFC的源码:

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

 

果然有一个ASSERT宏。而且这个宏很明确地告诉我们必须在窗口句柄有效的时候才能设置计时器。同样道理,在销毁计时器时也必须确保窗口句柄是有效的。

 

阅读全文 | 回复(2) | 引用通告 | 编辑

  • 标签:VC计时器 
  •  Re:VC计时器的一个使用心得
    lucyli发表评论于2008-5-6 20:18:00
    lucyli那这么说是在析构里窗口的句柄就没有了吗?
    是void CMain::OnDestroy() 在析构之前将句柄销毁了吗?
    一直在关注
    个人主页 | 引用 | 返回 | 删除 | 回复

     Re:VC计时器的一个使用心得
    zhangming发表评论于2008-3-20 16:23:00
    zhangming了解了,谢谢。
    个人主页 | 引用 | 返回 | 删除 | 回复

    发表评论:
    正在读取数据,请稍侯
    正在读取数据,请稍侯
    正在读取数据,请稍侯
    正在读取数据,请稍侯
    正在读取数据,请稍侯

    正在读取数据,请稍侯