CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 2 of 3 FirstFirst 123 LastLast
Results 16 to 30 of 38
  1. #16
    Join Date
    Oct 2003
    Location
    Iran
    Posts
    79
    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!

  2. #17
    Join Date
    Jan 2004
    Posts
    206
    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.

  3. #18
    Join Date
    Apr 2003
    Location
    UK
    Posts
    83
    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;
    	}
    }

  4. #19
    Join Date
    Oct 2003
    Location
    Iran
    Posts
    79
    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

  5. #20
    Join Date
    May 1999
    Location
    Southern California
    Posts
    12,266
    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.
    "Signature":
    My web site is Simple Samples.
    C# Corner Editor

  6. #21
    Join Date
    Jan 2004
    Posts
    206
    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.

  7. #22
    Join Date
    May 1999
    Location
    Southern California
    Posts
    12,266
    Originally posted by Wombat
    although the application is supposed to be in idle state, it is still doing background processing
    What background processing?
    "Signature":
    My web site is Simple Samples.
    C# Corner Editor

  8. #23
    Join Date
    May 1999
    Location
    Southern California
    Posts
    12,266
    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.
    "Signature":
    My web site is Simple Samples.
    C# Corner Editor

  9. #24
    Join Date
    Oct 2003
    Location
    Iran
    Posts
    79
    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

  10. #25
    Join Date
    Jan 2004
    Posts
    206
    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.

  11. #26
    Join Date
    May 1999
    Location
    Southern California
    Posts
    12,266
    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.
    "Signature":
    My web site is Simple Samples.
    C# Corner Editor

  12. #27
    Join Date
    Oct 2003
    Location
    Iran
    Posts
    79

    Question

    Time out works fine in debug mode but it doesn't work at all in release mode!

    Could you plzzzz help me?

  13. #28
    Join Date
    Apr 2003
    Location
    UK
    Posts
    83
    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.

  14. #29
    Join Date
    May 2000
    Location
    KY, USA
    Posts
    18,652
    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...

  15. #30
    Join Date
    Oct 2003
    Location
    Iran
    Posts
    79
    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!

Page 2 of 3 FirstFirst 123 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured