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.
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);
Related
I'm fairly new to MFC and the Message handling context.
I've a DLL Consumer application, which has a CFrameWndEx derived class,CMainFrame. Now this calls a DLL, which puts a CDialog etc. into this MainFrame window.
I wish to receive certain messages into my application.
So what I have done is, declared the expected messages in the Message Map, of the DLL Consumer application, and defined the appropriate message handlers.
Now, even though I can see that the application is being sent those registered messages, I'm not able to receive / handle them in the Consumer Window, i.e., nothing happens when those messages are broadcast.
Mainfrm.h
class CMainFrame : public CFrameWndEx
{
public:
CMainFrame();
protected:
DECLARE_DYNAMIC(CMainFrame)
public:
void OnFileDialogdisplay(void);
afx_msg LRESULT OnLogonChanged(WPARAM,LPARAM);
afx_msg LRESULT OnLanguageChanged(WPARAM,LPARAM);
afx_msg LRESULT OnShutdownRequested(WPARAM,LPARAM);
afx_msg LRESULT OnReconnectServer(WPARAM,LPARAM);
afx_msg LRESULT OnChangeRole(WPARAM,LPARAM);
}
Mainfrm.cpp
<some header files>
static UINT UWM_LOGON_CHANGED = ::RegisterWindowMessage(UWM_LOGON_CHANGE);
static UINT UWM_LANGUAGE_CHANGED = ::RegisterWindowMessage(UWM_LANGUAGE_CHANGE);
static UINT UWM_RECONNECT = ::RegisterWindowMessage(UWM_RECONNECT_SERVER);
static UINT UWM_SHUTDOWN_REQUESTED = ::RegisterWindowMessage(UWM_REQUEST_SHUTDOWN);
static UINT UWM_ROLE = ::RegisterWindowMessage(UWM_ROLE_CHANGE);
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWndEx)
ON_WM_CREATE()
ON_WM_SETFOCUS()
ON_COMMAND(ID_VIEW_CUSTOMIZE, &CMainFrame::OnViewCustomize)
ON_REGISTERED_MESSAGE(AFX_WM_CREATETOOLBAR, &CMainFrame::OnToolbarCreateNew)
ON_COMMAND(ID_FILE_DIALOGDISPLAY, &CMainFrame::OnFileDialogdisplay)
ON_REGISTERED_MESSAGE(UWM_LOGON_CHANGED, OnLogonChanged)
ON_REGISTERED_MESSAGE(UWM_LANGUAGE_CHANGED, OnLanguageChanged)
ON_REGISTERED_MESSAGE(UWM_SHUTDOWN_REQUESTED, OnShutdownRequested)
ON_REGISTERED_MESSAGE(UWM_RECONNECT, OnReconnectServer)
ON_REGISTERED_MESSAGE(UWM_ROLE, OnChangeRole)
//ON_WM_NCCALCSIZE()
END_MESSAGE_MAP()
//code to register to Main server application to be able to receive messages
void manageregistration(CMainFrame* pFrame, bool flag)
{
if (flag)
{ // registration
HWND MyHandle = (HWND)pFrame->GetActiveWindow();
RegisterApmsClientPgm(_T("AAUserInterface"), MyHandle);
}
}
//Handlers
LRESULT CMainFrame::OnShutdownRequested(WPARAM,LPARAM lp)
{
AfxMessageBox(_T("Error"),MB_ICONERROR | MB_OK);
testProgram();
return 0;
}
LRESULT CMainFrame::OnChangeRole(WPARAM,LPARAM lp)
{
AfxMessageBox(_T("Error"),MB_ICONERROR | MB_OK);
testProgram();
return 0;
}
// etc etc.etc.
So, after all this, I can see that the Consumer application, is registered to receive these messages from another application which broadcasts them.
However, upon creating the condition where the messages are being broadcast, and they are as I can verify from other applications which receive them, no such message is being caught in my application.
I am not sure where the problem could be. The window is always on top, albeit with another CDialog derived DLL inside it.
Try using pFrame->m_hWnd. You can't assume that the Mainframe window is always active.
I have a custom class derived from CWnd that I would like to post a message to from a worker thread. I am using the PostMessage function to achieve this. The first argument to PostMessage is the HWND type handle to my class, and the next is the message I would like handled. For the first parameter, I generate the handle to my class using GetSafeHwnd() function, and for the second parameter, I use WM_USER+3. Also, I declare a message map inside my class header file, and add an entry for the message handler inside the BEGIN_MESSAGE_MAP and END_MESSAGE_MAP block. However, my handler is not getting called. I have also checked the return value of PostMessage function, it is 1, that means success.
Here is my code :
Inside MyClass.h
class CMyClass : CWnd
{
....
....
public:
void InitHandle();
protected:
afx_msg LRESULT OnMessageReceived(WPARAM wParam, LPARAM lParam);
DECLARE_MESSAGE_MAP()
}
Inside MyClass.cpp
#define WM_MY_MESSAGE WM_USER+3
HWND handleToMyClassWindow;
BEGIN_MESSAGE_MAP(CMyClass, CWnd)
ON_MESSAGE(WM_MY_MESSAGE, OnMessageReceived)
END_MESSAGE_MAP()
LRESULT CMyClass::OnMessageReceived(WPARAM wParam, LPARAM lParam)
{ .... }
void CMyClass::InitHandle()
{
handleToMyClassWindow = GetSafeHwnd();
}
Inside Worker thread
UINT WorkerThreadFunction(LPVOID pParam )
{
....
PostMessage(handleToMyClassWindow, WM_MY_MESSAGE, NULL, NULL);
....
}
My question is, what are the possible reasons for the OnMessageReceived handler to not be called.
P.S.
I take care that the calling object calls the InitHandle() function.
I tried the same technique with the View class (derived from CView) of my program, and it works there, but fails here.
You cannot post to a window if it has not been created. GetSafeHwnd() will return NULL if you have not actually created a window using your class.
I need timer to start function every 1 second.
I have tried SetTimer, my code:
const UINT_PTR TIMER_ID = 1000;
DWORD DownloadThread()
{
SetTimer(NULL, TIMER_ID, 1000, (TIMERPROC)DownloadSpeedCounter);
/*some stuff*/
}
void DownloadSpeedCounter()
{
/*some stuff*/
}
I cannot compile this code and get error C2440: 'type cast' : cannot convert from 'overloaded-function' to 'TIMERPROC'
Also it is class member method.
This is because you are trying to use a normal function as an application-defined callback function. What you are probably looking for is this application-defined callback function which could look like this:
VOID CALLBACK DownloadSpeedCounter(
HWND hwnd, // handle to window for timer messages
UINT message, // WM_TIMER message
UINT idTimer, // timer identifier
DWORD dwTime) {
/* some stuff */
}
For additional information on using callback functions for timers see this article.
One of the problems is that TIMERPROC functions should look like this: typedef VOID (CALLBACK* TIMERPROC)(HWND, UINT, UINT_PTR, DWORD); So your method definition should look like this:
VOID CALLBACK DownloadSpeedCounter(HWND, UINT, UINT_PTR, DWORD);
Also, as this is a method, not just a function, it must be static. So it is calling like static but to access private non-static data may be used this technique.
Though I've had plenty of software experience I've not done a great deal of Windows programming. I'm trying to post a WM_USER message from a thread so that it gets picked up in the main UI thread but I'm having some trouble. This is in C++ using VS2010 and MFC.
I've created a message map thus,
#define WM_MYMSG (WM_USER + 77)
BEGIN_MESSAGE_MAP(CMyApp, CWinApp)
ON_MESSAGE(WM_MYMSG, DoSomething)
END_MESSAGE_MAP()
Declared the handler function as follows,
afx_msg LRESULT DoSomething(WPARAM wParam, LPARAM lParam);
And written the function body as,
LRESULT CMyApp::DoSomething( WPARAM wParam, LPARAM lParam )
{
UNREFERENCED_PARAMETER(wParam);
UNREFERENCED_PARAMETER(lParam);
CallSomeFunction();
return 0L;
}
As far as I can see this is all in line with what MSDN says as stated here.
http://msdn.microsoft.com/en-gb/library/k35k2bfs(v=vs.100).aspx
However I'm getting an
error C2440: 'static_cast' : cannot convert from 'LRESULT (__cdecl CMyApp::*)(WPARAM,LPARAM)' to 'LRESULT (__cdecl CWnd::* )(WPARAM,LPARAM)'
relating to the line
ON_MESSAGE(WM_AVATAR_SCALE_MSG, DoSomething)
Can anyone let me know what the problem is?
Thanks for reading.
Paul
CMyApp inherits from CWinApp, which inherits from CWinThread. CWinThread user-defined messages take a special macro in their message map for what you want to do:
Change this:
ON_MESSAGE(WM_AVATAR_SCALE_MSG, DoSomething)
To this:
ON_THREAD_MESSAGE(WM_AVATAR_SCALE_MSG, DoSomething)
Assuming DoSomething() is a member of your CMyApp class.
See the documentation on ON_THREAD_MESSAGE() for more information.
THe problem is that the message map expects a function on a CWnd, whereas your class clearly is not a CWnd, either by virtue of actually being such or inheriting from CWnd.
The function expects you to pass a method of CWnd that takes a WPARAM and an LPARAM, but you're passing in a function of CMyApp.
Make the CMyApp class extend off of the CWnd class:
class CMyApp : public CWnd {
// members here
};
edit
If this isn't possible, then you're going to have to find a way to pass in a function of CWnd or any other function of a class that extends off of CWnd with the right parameters and return type.
I'm trying to make a timer in c++. I'm new to c++. I found this code snippet
UINT_PTR SetTimer(HWND hWnd, UINT_PTR nIDEvent, UINT uElapse, TIMERPROC lpTimerFunc);
I put it in my global variables and it tells me
Error 1 error C2373: 'SetTimer' : redefinition; different type modifiers
I'm not sure what this means. Is there a more proper way to define a timer?
I'm not using mfc / afx
Thanks
You should call it like this:
void CALLBACK TimerProc(
HWND hwnd,
UINT uMsg,
UINT idEvent,
DWORD dwTime
)
{
//do something
}
SetTimer(NULL, NULL, 1000, TimerProc);
This would set a timer for 1 second and will call TimerProc when it expires. Read TimerProc MSDN here: http://msdn.microsoft.com/en-us/library/ms644907%28VS.85%29.aspx
That's not a function call -- that's a function declaration, which you are probably already #including from somewhere. What you need is the actual SetTimer call from your code.
Can you post your code where you're trying to set up the timer, and the function you want it to call when it triggers?