Reputation: 721
I am currently making a C++ MFC application, and I need a timer to call a function called OnTimer every 30 seconds or so. Right now, I have a class that looks like this:
class CMyApp : public CWinApp
{
// Do some stuff...
DECLARE_MESSAGE_MAP()
BOOL InitInstance()
{
// m_pMainWnd is an object in CWinApp that allows me to render a window
m_pMainWnd->ShowWindow(SW_SHOWMAXIMIZED);
// Do some stuff with this window
::SetTimer(NULL, 0, 30000, 0);
}
afx_msg void OnTimer(WPARAM wParam, LPARAM lParam)
{
// I want this function to execute every 30 seconds
// This function manipulates the window
}
}
BEGIN_MESSAGE_MAP(CMyApp, CWinApp)
ON_THREAD_MESSAGE(WM_TIMER, OnTimer)
END_MESSAGE_MAP()
CMyApp theApp;
This method does get OnTimer to be called, but not every 30 seconds. In fact, OnTimer seems to get called hundreds of times a minute now. My question is: how do I set my class's timer?
Things I've tried
I've tried changing the user extension from ON_THREAD_MESSAGE to ON_WM_TIMER, to ON_COMMAND, and to ON_MESSAGE. For anything that isn't ON_THREAD_MESSAGE, I get the error
error C2440: 'static_cast' : cannot convert from 'void (__thiscall CMyApp::* )(WPARAM,LPARAM)' to 'LRESULT (__thiscall CWnd::* )(WPARAM,LPARAM)'
I'm not sure, but I think SetTimer may be manipulating some CWinApp specific function, while the CWnd SetTimer is not being manipulated, and is set to some default value. I'm pretty much in the dark here though, any help would be appreciated.
Upvotes: 0
Views: 1117
Reputation: 31619
ON_THREAD_MESSAGE
is for user defined messages, not WM_TIMER
According to SetTimer documentation, the window handle must be valid, and the timer identifier must be non-zero to create a new timer. Example:
::SetTimer(m_pMainWnd->m_hWnd, 1, 30000, NULL);
or
m_pMainWnd->SetTimer(1, 30000, NULL);
The message can be handled in main GUI Window. For example CMainFrame
, CMyCMDIFrameWnd
, or whatever m_pMainWnd
points to.
BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd)
ON_WM_TIMER()
...
END_MESSAGE_MAP()
void CMainFrame::OnTimer(UINT id)
{
TRACE("OnTimer(%d)\n", id);
}
Alternatively you can use NULL
for window handle in ::SetTimer
but you must supply a call back function:
VOID CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
{
TRACE("TimerProc\n");
}
::SetTimer(NULL, 2, 30000, TimerProc);
Upvotes: 3