-
January 15th, 2004, 03:57 AM
#16
Thank you so much Wombat
Your code was life saving (or better saying CPU saving )
But there's a small problem!
When the time expires, the user isn't logged out unless mouse is moved!
-
January 15th, 2004, 04:12 AM
#17
That's a slight change of design concept from your original request. Instead of constantly checking the idling status and use up cpu time, I just check the time elapsed when the application came "alive" again and log off the user accordingly.
I guess this is still acceptable for your application, while retaining your original design to a certain extent. Do let me know if it poses serious problem.
-
January 15th, 2004, 09:32 AM
#18
This is the approach I've taken to this problem in the past, and it works very well.
In your app's InitInstance, hook into the Windows mouse and keyboard hooks:
Code:
m_lpfnKeyboardHook = (HOOKPROC)KeyboardHookProc;
m_hKeyboardHook = ::SetWindowsHookEx(
WH_KEYBOARD,
m_lpfnKeyboardHook,
NULL,
(DWORD)GetCurrentThreadId());
m_lpfnMouseHook = (HOOKPROC)MouseHookProc;
m_hMouseHook = ::SetWindowsHookEx(
WH_MOUSE,
m_lpfnMouseHook,
NULL,
(DWORD)GetCurrentThreadId());
The hook functions look like this:
Code:
extern "C"
{
DWORD CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
return theApp.HookProc(theApp.m_hKeyboardHook, nCode, wParam, lParam);
}
}
extern "C"
{
DWORD CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
return theApp.HookProc(theApp.m_hMouseHook, nCode, wParam, lParam);
}
}
They call a member function in the app, which stops and restarts the timer (in the MainFrame window). Thus, every time the user uses mouse or keyboard, the timer is reset.
Code:
LRESULT CMyApp::HookProc(HHOOK hHook, int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode >= 0)
{
m_nTimeOutMinsElapsed = 0;
m_nTimeOutCount = 0;
((CMainFrame*)theApp.m_pMainWnd)->StopTimeOutTimer();
((CMainFrame*)theApp.m_pMainWnd)->StartTimeOutTimer();
}
return ::CallNextHookEx(hHook, nCode, wParam, lParam);
}
You will need to free the hook procedures in ExitInstance:
Code:
if (m_hKeyboardHook)
{
::UnhookWindowsHookEx(m_hKeyboardHook);
m_hKeyboardHook = NULL;
}
if (m_lpfnKeyboardHook)
{
m_lpfnKeyboardHook = NULL;
}
if (m_hMouseHook)
{
::UnhookWindowsHookEx(m_hMouseHook);
m_hMouseHook = NULL;
}
if (m_lpfnMouseHook)
{
m_lpfnMouseHook = NULL;
}
Declare the app's members like this:
Code:
private:
HOOKPROC m_lpfnKeyboardHook; // keyboard hook function
HOOKPROC m_lpfnMouseHook; // mouse hook function
public:
UINT m_nTimeOutMins; // time out
UINT m_nTimeOutMinsElapsed; // time out minutes elapsed
UINT m_nTimeOutCount; // time out count
HHOOK m_hKeyboardHook; // keyboard hook
HHOOK m_hMouseHook; // mouse hook
public:
LRESULT HookProc(HHOOK hHook, int nCode, WPARAM wParam, LPARAM lParam);
The MainFrame message handlers are simple:
Code:
void CMainFrame::StopTimeOutTimer(void)
{
KillTimer(m_nHookTimer);
}
void CMainFrame::StartTimeOutTimer(void)
{
if ((m_nHookTimer = SetTimer(ID_EVENT_HOOK, 10000, NULL)) == NULL)
{
TRACE("Failed to set time out timer\n");
ASSERT(FALSE);
}
}
void CMainFrame::OnTimer(UINT nIDEvent)
{
static BOOL bInTimer = FALSE;
if (!bInTimer && nIDEvent == m_nHookTimer)
{
bInTimer = TRUE;
if (theApp.m_nTimeOutCount == 5)
{
// 60 seconds have passed (theApp.m_nTimeOutCount == 5)
theApp.m_nTimeOutCount = 0;
if (++theApp.m_nTimeOutMinsElapsed >= theApp.m_nTimeOutMins)
{
// not currently processing previous timer message
KillTimer(m_nHookTimer);
theApp.m_nTimeOutMinsElapsed = 0;
// forces exit from application
PostMessage(WM_QUIT);
}
}
else
{
theApp.m_nTimeOutCount++;
}
bInTimer = FALSE;
}
}
-
January 18th, 2004, 12:40 AM
#19
Well.......you're right Wombat ......but this is a problem for my application
I wonder how I can keep my application alive while CPU usage is not much. I'd prefer this code to using a thread and changing all design.
Do you have any suggession?
Besides, I'm considering your suggession as well, Astanley.
Thanks & Regards
-
January 18th, 2004, 04:10 PM
#20
Try something such as:
Code:
BOOL CMyApp::OnIdle(LONG lCount) {
if (m_bTimerGoing && lCount == 0) {
m_bTimerGoing = FALSE;
KillTimer(NULL, m_IDTimer);
}
if (CWinApp::OnIdle(lCount)) // MFC have more work?
return 1; // Give MFC a chance to finish first
if (!m_bTimerGoing) {
m_bTimerGoing = TRUE;
m_IDTimer = SetTimer(NULL, NULL, m_lSecProjectTimeOut*1000,
(TIMERPROC)TimerProc);
}
return 1;
}
Be sure to initialize m_bTimerGoing to FALSE. Then in TimerProc:
Code:
m_bTimerGoing = FALSE;
KillTimer(NULL, m_IDTimer);
LogOff();
I am not sure if always return non-zero from OnIdle makes much difference, but it might.
-
January 18th, 2004, 11:12 PM
#21
Originally posted by Sam Hobbs
I am not sure if always return non-zero from OnIdle makes much difference, but it might.
Yes, it does make a difference. If OnIdle returns non-zero and there is no message in the thread message queue, the framework will continue invoke OnIdle while incrementing the lCount every loop. In this case, although the application is supposed to be in idle state, it is still doing background processing and using up cpu time. This is what mfc_oracle encountered in his first approach.
-
January 18th, 2004, 11:43 PM
#22
Originally posted by Wombat
although the application is supposed to be in idle state, it is still doing background processing
What background processing?
-
January 19th, 2004, 12:02 AM
#23
Yes, by returning a non-zero value, the processor remains busy; but I think it is just because the idle processing is continually being executed. Therefore it probably has no impact on the system. However it probably does not solve the problem either, since there are too many miscelaneous messages that will reset the idle count to zero even when there has not been any activity we care about. Probably the only way to solve the problem is to use something that determines inactivity more directly; that is, by detecting keyboard and mouse messages.
An important design criteria is whether it is application inactivity or system inactivity that determines whether to logoff the application.
-
January 19th, 2004, 04:44 AM
#24
Thanks all for your useful comments!
Your code was perfect, Wombat but I have to log out user at the specified time. So, I tried Astanely's code and it works as I'd like.
All the best!
Kindly Regards,
mfc_oracle
-
January 19th, 2004, 07:04 AM
#25
Originally posted by Sam Hobbs
Probably the only way to solve the problem is to use something that determines inactivity more directly; that is, by detecting keyboard and mouse messages.
I agreed. And this is what astanley has suggested, using a hook procedure to monitor keyboard and mouse events.
Originally posted by Sam Hobbs
An important design criteria is whether it is application inactivity or system inactivity that determines whether to logoff the application.
Agreed. The hook procedure can be associated with all existing threads or just the identified thread.
-
January 19th, 2004, 10:11 AM
#26
It is probably not necessary to use a hook if it is just the applicaton's idleness that determines when to logoff. Also, I am not sure whether there are any Windows functions that can help to determine if the system has been idle for a specified legth of time, but if I knew that such a thing could help then if it were me trying to solve this problem I would sure try to find anything that can do that. I think I have seen something that is new for Windows 2000 that might help. If it is just the application that will determine idle time and if a hook is used, then an application-specific hook would certainly be less complicated; no DLL is needed; the hook can exist in the exe.
-
March 1st, 2004, 01:55 AM
#27
Time out works fine in debug mode but it doesn't work at all in release mode!
Could you plzzzz help me?
-
March 1st, 2004, 04:13 AM
#28
There is no reason why the time out code should not work in a release build, so a bug must have been introduced some where. You need to debug the release build to find this bug.
Project->Settings->Win32 Release, C/C++ tab, General Category, Debug info - set to Program Database. Link tab, Debug Category, tick Debug info, set Both formats. Rebuild All. You will now be able to debug the release build (set breakpoints, watch variables, etc).
Because of code optimisation in the release build, you may see some funny things whilst debugging (e.g., code lines where you can't set a breakpoint, variables with strange values), but it should be good enough so you can find the bug.
-
March 1st, 2004, 05:11 AM
#29
Originally posted by mfc_oracle
Time out works fine in debug mode but it doesn't work at all in release mode!
Take a look at the following FAQ...
-
March 1st, 2004, 05:26 AM
#30
Actually, I've turned off optimization and teh problem still exists. I've debugged it in release mode as well; all variables have proper values!
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|