C++ – OnTimer method not working in MFC

cmessage-queuemfctimervisual studio 2010

I created an MFC dialog based app in VS2010, and wanted to add timer to update a picture controller every 3 seconds. But the OnTimer method never worked.

I have used Class Wizard to add WM_TIMER into the message queue, which turned out to be as following:

BEGIN_MESSAGE_MAP(CxxxxDlg, CDialogEx)
    ON_WM_PAINT()
    ON_BN_CLICKED(IDOK, &CxxxxDlg::OnBnClickedOK)
    ON_WM_TIMER()
END_MESSAGE_MAP()

In xxxxDlg.cpp, I put SetTimer method in OnInitDialog:

BOOL CxxxxDlg::OnInitDialog()
{
    CDialog::OnInitDialog();
    SetIcon(m_hIcon, TRUE);
    SetIcon(m_hIcon, TRUE);

    _imageCounter = 1;
    _isMale = 3;
    _testNum = 0;

    SetTimer(123, 2000, NULL);

    bFullScreen = false;
    OnFullShow();
    updateImages();
    UpdateData();

    return TRUE;
}

The OnTimer method was declard in xxxxdlv.h:

public:
    afx_msg void OnTimer(UINT_PTR nIDEvent);

When I run the app, the SetTimer returned 123. So everything should be all right here. But the program never reached the breakpoint I set in the 1st line of OnTimer method!

Then I wrote another hello world project only to test the timer. I set the timer in exactly the same way and it worked well.

So I thought the OnFullShow() method may be the problem. This method was used to change the window into full screen mode. I comment this line , but still OnTimer never worked.

I have check the questions here. But it doesn't help.

Does anyone know where the problem comes from? Thanks!

PS. I did receive some warnings of memory leaks. Did this matter?

Best Answer

Thanks to @IInspectable. I found a tech support here. It fully explains the cause and tells one solution:

// Rewrite PreTranslateMessage method
BOOL CMyApp::PreTranslateMessage( MSG *pMsg )
{
   // If this is a timer callback message let it pass on through to the
   // DispatchMessage call.
   if( (pMsg->message==WM_TIMER) && (pMsg->hwnd==NULL) )
       return FALSE;
   ...
   // The rest of your PreTranslateMessage goes here.
   ...

   return CWinApp::PreTranslateMessage(pMsg);
}

This solution does not solve my problem but gives me a hint. PreTranslateMessage method should be rewritten to let WM_TIMER pass on through to the DispatchMessage call. But if you are using PreTranslateMessage to deal with other messages, WM_KEYDOWN for example, the solution above may not work. It seems to be a problem about priority. In the end, I solve it using switch instead of if:

// Rewrite PreTranslateMessage method
BOOL CMyApp::PreTranslateMessage( MSG *pMsg )
{
   // If this is a timer callback message let it pass on through to the
   // DispatchMessage call.
   switch(pMsg->message)
   {
    case WM_KEYDOWN: // your codes
    case WM_TIMER: return false;
    ...
   }
   ...
   // The rest of your PreTranslateMessage goes here.
   ...

   return CWinApp::PreTranslateMessage(pMsg);
}

I hope this will help anyone who has similar problem.

PS. pMsg->hwnd==NULL is removed in switch and I am not sure if it is safe.

Related Topic