I'm using SetTimer and TimerProc functions to set a timer interval in MFC application.
Could you let me know how I can reset the timer?
Printable View
I'm using SetTimer and TimerProc functions to set a timer interval in MFC application.
Could you let me know how I can reset the timer?
What do you mean by 'reset'? As soon as you start a timer, you will be periodically triggered until you stop the timer by a call to 'KillTimer()'...
I'm using KillTimer but when calling TimerProc again, it immedialtely returns and doesnt wait for the time to be elapsed!
What do you mean it immediately returns? 'TimerProc()' will be called every time a WM_TIMER message is sent to your message queue. It does not wait...so I honestly do not understand the question here... :confused:
I think your last statement shows the problem. You should not call the Timerproc! All you have to do is to set the timer. Then the Timerproc gets called after the given time from the framework. AFAIK there is no "ResetTimer" function. But it can't be difficult: As you know which timer to reset, you know which timer to kill and restart.
Good luck!
Marc
To reset a timer you can use SetTimer with the same timer ID:
quote from MSDN
Quote:
nIDEvent
[in] Specifies a nonzero timer identifier. If the hWnd parameter is NULL, this parameter is ignored. If the hWnd parameter is not NULL and the window specified by hWnd already has a timer with the value nIDEvent, then the existing timer is replaced by the new timer. When SetTimer replaces a timer, the timer is reset. Therefore, a message will be sent after the current time-out value elapses, but the previously set time-out value is ignored.
Thanks all for your immediate reply and sorry for my ambiguous question.
Actually, I'm using SetTimer in OnIdle function to log out the application when it's idle for a specified time and it works properely and logs out the user when the time is expired but when the user logs in again it logs her out immeditely :(
Here's my code:
BOOL CxxApp::OnIdle(long lCount)
{
BOOL bRet = CWinApp::OnIdle (lCount);
if(lCount == 0)
{
KillTimer(NULL, m_IDTimer);
}
else
{
m_IDTimer = SetTimer(NULL,NULL,m_lSecProjectTimeOut*1000,(TIMERPROC)TimerProc);
if (m_bTimeOutFinished)
{
m_bTimeOutFinished = FALSE;
LogOff();
bRet = FALSE;
KillTimer(NULL, m_IDTimer);
}
}
return bRet;
}
I do not understand what you are doing there. But maybe my comments are nevertheless useful.
I would expect your function to set the timer again and again, always after an action is performed. So this should happen in OnIdle. I do not see the need of a recursion in that.
But it would be the job of the timer to logoff your user. So I would expect that function in your timerproc!
In the moment it seems to me that you are using the timer like wait(xxx). But the setTimer-command returns immediately!
All put together I would expect a stucture like this:
OnIdle()
{
SetTimer(..)
}
OnTimer()
{
LogOff()
}
regards,
Marc
I'd overridden OnIdle function as below, but I noticed that it uses CPU 100%. So I desided to use Timer functions but the code that I've written logs out user even if the application is not idle. So far as I know I cannot use OnTimer in SDI application.
Do you have any suggestion?
BOOL CxxxApp::OnIdle(long lCount)
{
BOOL bRet = CWinApp::OnIdle (lCount);
static COleDateTime Time;
COleDateTime now;
if (lCount == 0)
Time = COleDateTime::GetCurrentTime();
now = COleDateTime::GetCurrentTime();
COleDateTimeSpan sp;
sp = now - Time;
UINT sec = sp.GetTotalSeconds();
if (sec >= m_lSecProjectTimeOut)
{
Logoff();
bRet = FALSE;
}
else
{
bRet = TRUE;
}
}
Thanks & Regards
You couldn't be more wrong. It's not true.Quote:
So far as I know I cannot use OnTimer in SDI application.
What I think is that you are trying to do something without knowing exaclty what it is that you want to do.
This implementation is correct, except that it uses a lot of CPU time cos OnIdle gets called again and again.Quote:
Originally posted by mfc_oracle
I'd overridden OnIdle function as below, but I noticed that it uses CPU 100%. So I desided to use Timer functions but the code that I've written logs out user even if the application is not idle. So far as I know I cannot use OnTimer in SDI application.
Do you have any suggestion?
BOOL CxxxApp::OnIdle(long lCount)
{
BOOL bRet = CWinApp::OnIdle (lCount);
static COleDateTime Time;
COleDateTime now;
if (lCount == 0)
Time = COleDateTime::GetCurrentTime();
now = COleDateTime::GetCurrentTime();
COleDateTimeSpan sp;
sp = now - Time;
UINT sec = sp.GetTotalSeconds();
if (sec >= m_lSecProjectTimeOut)
{
Logoff();
bRet = FALSE;
}
else
{
bRet = TRUE;
}
}
Thanks & Regards
But back to the previous code that uses Timer, I think we still needs more info. Where and how is m_bTimeOutFinished updated? How about post up your TimerProc ?
mfc_oracle, I think your problems arise because you step into different traps. Your opinion, that a timer is not possible might come from a basic misunderstanding:
Your application, whatever it is (SDI, MDI, Dialog..) is typically mainly based on Event-Handlers. This means, that you can initiate and react on events. As long as your program is already doing something, it is typically not able to do any additional job. Those events might be qeued outside your appl.
So your application should consist of many short parts, each one will provide a reaction of your program. You should make sure, that those event-handlers stop, once they have done their job. This will enable the qeued events to be handled.
If one event-handler is never ending, the other events will never be called.
So a timer is surely working, but when your application ist doing other things all time, it will just endless wait until it gets called.
Just try to understand that your appl. consists of many small and more or less independent parts.
regards
Marc
m_bTimeOutFinished is updated in TimerProc:
VOID CALLBACK TimerProc(
HWND hwnd, // handle to window
UINT uMsg, // WM_TIMER message
UINT_PTR idEvent, // timer identifier
DWORD dwTime // current system time
)
{
m_bTimeOutFinished = TRUE;
}
Thank you all for your patience I'm not very experienced in MFC and I need your help indeed :)
BTW, I'm still thinking and investigating about your comments, Marc.
Regards
Hi mfc_quote,Quote:
Originally posted by mfc_oracle
m_bTimeOutFinished is updated in TimerProc:
VOID CALLBACK TimerProc(
HWND hwnd, // handle to window
UINT uMsg, // WM_TIMER message
UINT_PTR idEvent, // timer identifier
DWORD dwTime // current system time
)
{
m_bTimeOutFinished = TRUE;
}
Thank you all for your patience I'm not very experienced in MFC and I need your help indeed :)
BTW, I'm still thinking and investigating about your comments, Marc.
Regards
I think I more or less understand what you want to achieve by now. It is good to know that you have tried different approaches in solving the problems.
Let's talk about the first approach, which is the CTime approach.
This approach has achieved your objective, but the problem is the great amount of CPU time it "utilized". The application is busy performing tasks when it is supposed to idle, which is a bit cruel to your CPU :D .
The other approach using timer, looks a bit strange to me. I can help you visualize how this approach does not work well in the following scenario:
At time t1, there is no messages in the queue, so OnIdle() is being called, and a timer is set, say to invoke 10s later.
After t1, there are a series of user activities resulting the message queue being non-empty at all times.
Then at some time t10, which is 10s after t1, the timer invoked and the flag m_bTimeOutFinished is set to TRUE.
And finally after some time, when the message queue is empty again, OnIdle() will be invoked again and becos m_bTimeOutFinished is being set TRUE at an earlier stage, it just log off the user.
That is why the user experience a log off even when he is not idle.
:)
I suggest maybe you can do it this way:
**************************************************
BOOL CTestOnIdleApp::OnIdle(LONG lCount)
{
if(CWinApp::OnIdle(lCount))
return TRUE;
if(m_FirstTimeIdle)
{
m_PreviousIdleTime = m_CurrentIdleTime = CTime::GetCurrentTime();
m_FirstTimeIdle = FALSE;
}
else
{
m_CurrentIdleTime = CTime::GetCurrentTime();
m_TimeSpan = m_CurrentIdleTime - m_PreviousIdleTime;
if(m_TimeSpan.GetTotalSeconds() > 20)
{
AfxMessageBox("LogOff");
}
m_PreviousIdleTime = m_CurrentIdleTime;
}
return FALSE;
}
**********************************************
The flag m_FirstTimeIdle is set to TRUE at the constructor of CTestOnIdleApp().
m_CurrentIdleTime and m_PreviousIdleTime are instances of CTime.
m_TimeSpan is an instance of CTimeSpan.
It is similar to your first approach, only that OnIdle() is not constantly being called. You can try that out and tell me the outcome. :)