CWinApp::OnIdle virtual BOOL OnIdle( LONG lCount );Return ValueNonzero to receive more idle processing time; 0 if no more idle time is needed.ParameterslCountA counter incremented each time OnIdle is called when the application’s message queue is empty. This count is reset to 0 each time a new message is processed. You can use the lCount parameter to determine the relative length of time the application has been idle without processing a message.ResOverride this member function to perform idle-time processing. OnIdle is called in the default message loop when the application’s message queue is empty. Use your override to call your own background idle-handler tasks.OnIdle should return 0 to indicate that no idle processing time is required. The lCount parameter is incremented each time OnIdle is called when the message queue is empty and resets to 0 each time a new message is processed. You can call your different idle routines based on this count.The following summarizes idle loop processing: If the message loop in the Microsoft Foundation Class Library checks the message queue and finds no pending messages, it calls OnIdle for the application object and supplies 0 as the lCount argument. OnIdle performs some processing and returns a nonzero value to indicate it should be called again to do further processing. The message loop checks the message queue again. If no messages are pending, it calls OnIdle again, incrementing the lCount argument. Eventually, OnIdle finishes processing all its idle tasks and returns 0. This tells the message loop to stop calling OnIdle until the next message is received from the message queue, at which point the idle cycle restarts with the argument set to 0. Do not perform lengthy tasks during OnIdle because your application cannot process user input until OnIdle returns.Note The default implementation of OnIdle updates command user-interface objects such as menu items and toolbar buttons, and it performs internal data structure cleanup. Therefore, if you override OnIdle, you must call CWinApp::OnIdle with the lCount in your overridden version. First call all base-class idle processing (that is, until the base class OnIdle returns 0). If you need to perform work before the base-class processing completes, review the base-class implementation to select the proper lCount during which to do your work.ExampleThe following two examples show how to use OnIdle. The first example processes two idle tasks using the lCount argument to prioritize the tasks. The first task is high priority, and you should do it whenever possible. The second task is less important and should be done only when there is a long pause in user input. Note the call to the base-class version of OnIdle. The second example manages a group of idle tasks with different priorities.BOOL CMyApp::OnIdle(LONG lCount) { BOOL bMore = CWinApp::OnIdle(lCount); if (lCount == 0) { TRACE("App idle for short period of time\n"); bMore = TRUE; } else if (lCount == 10) { TRACE("App idle for longer amount of time\n"); bMore = TRUE; } else if (lCount == 100) { TRACE("App idle for even longer amount of time\n"); bMore = TRUE; } else if (lCount == 1000) { TRACE("App idle for quite a long period of time\n"); // bMore is not set to TRUE, no longer need idle // IMPORTANT: bMore is not set to FALSE since CWinApp::OnIdle may // have more idle tasks to complete. } return bMore; // return TRUE as long as there is any more idle tasks }Second Example// In this example, four idle loop tasks are given various // opportunities to run: // Task1 is always given a chance to run during idle time, provided // that no message has queued up while the framework was processing // its own idle loop tasks (at lCount levels 0 and 1). // Task2 is given a chance to run only if Task1 has already run, // provided that no message has queued up while Task1 was running. // Task3 and Task4 are given a chance to run only if both Task1 and // Task2 have already run, and no message has queued up in the mean // time. If Task3 gets its chance to run, then Task4 always gets // a chance to run immediately after Task3.BOOL CMyApp::OnIdle(LONG lCount) { // In this example, as in most applications, you should let the // base class CWinApp::OnIdle complete its processing before you // attempt any additional idle loop processing. if (CWinApp::OnIdle(lCount)) return TRUE; // The base class CWinApp::OnIdle reserves the lCount values 0 // and 1 for the framework's own idle processing. If you wish to // share idle processing time at a peer level with the framework, // then replace the above if-statement with a straight call to // CWinApp::OnIdle; and then add a case statement for lCount value // 0 and/or 1. Study the base class implementation first to // understand how your idle loop tasks will compete with the // framework's idle loop processing. switch (lCount) { case 2: Task1(); return TRUE; // next time give Task2 a chance case 3: Task2(); return TRUE; // next time give Task3 and Task4 a chance case 4: Task3(); Task4(); return FALSE; // cycle through the idle loop tasks again } return FALSE; }
virtual BOOL OnIdle( LONG lCount );Return ValueNonzero to receive more idle processing time; 0 if no more idle time is needed.ParameterslCountA counter incremented each time OnIdle is called when the application’s message queue is empty. This count is reset to 0 each time a new message is processed. You can use the lCount parameter to determine the relative length of time the application has been idle without processing a message.ResOverride this member function to perform idle-time processing. OnIdle is called in the default message loop when the application’s message queue is empty. Use your override to call your own background idle-handler tasks.OnIdle should return 0 to indicate that no idle processing time is required. The lCount parameter is incremented each time OnIdle is called when the message queue is empty and resets to 0 each time a new message is processed. You can call your different idle routines based on this count.The following summarizes idle loop processing: If the message loop in the Microsoft Foundation Class Library checks the message queue and finds no pending messages, it calls OnIdle for the application object and supplies 0 as the lCount argument.
OnIdle performs some processing and returns a nonzero value to indicate it should be called again to do further processing.
The message loop checks the message queue again. If no messages are pending, it calls OnIdle again, incrementing the lCount argument.
Eventually, OnIdle finishes processing all its idle tasks and returns 0. This tells the message loop to stop calling OnIdle until the next message is received from the message queue, at which point the idle cycle restarts with the argument set to 0.
Do not perform lengthy tasks during OnIdle because your application cannot process user input until OnIdle returns.Note The default implementation of OnIdle updates command user-interface objects such as menu items and toolbar buttons, and it performs internal data structure cleanup. Therefore, if you override OnIdle, you must call CWinApp::OnIdle with the lCount in your overridden version. First call all base-class idle processing (that is, until the base class OnIdle returns 0). If you need to perform work before the base-class processing completes, review the base-class implementation to select the proper lCount during which to do your work.ExampleThe following two examples show how to use OnIdle. The first example processes two idle tasks using the lCount argument to prioritize the tasks. The first task is high priority, and you should do it whenever possible. The second task is less important and should be done only when there is a long pause in user input. Note the call to the base-class version of OnIdle. The second example manages a group of idle tasks with different priorities.BOOL CMyApp::OnIdle(LONG lCount)
{
BOOL bMore = CWinApp::OnIdle(lCount); if (lCount == 0)
{
TRACE("App idle for short period of time\n");
bMore = TRUE;
}
else if (lCount == 10)
{
TRACE("App idle for longer amount of time\n");
bMore = TRUE;
}
else if (lCount == 100)
{
TRACE("App idle for even longer amount of time\n");
bMore = TRUE;
}
else if (lCount == 1000)
{
TRACE("App idle for quite a long period of time\n");
// bMore is not set to TRUE, no longer need idle
// IMPORTANT: bMore is not set to FALSE since CWinApp::OnIdle may
// have more idle tasks to complete.
} return bMore;
// return TRUE as long as there is any more idle tasks
}Second Example// In this example, four idle loop tasks are given various
// opportunities to run:
// Task1 is always given a chance to run during idle time, provided
// that no message has queued up while the framework was processing
// its own idle loop tasks (at lCount levels 0 and 1).
// Task2 is given a chance to run only if Task1 has already run,
// provided that no message has queued up while Task1 was running.
// Task3 and Task4 are given a chance to run only if both Task1 and
// Task2 have already run, and no message has queued up in the mean
// time. If Task3 gets its chance to run, then Task4 always gets
// a chance to run immediately after Task3.BOOL CMyApp::OnIdle(LONG lCount)
{
// In this example, as in most applications, you should let the
// base class CWinApp::OnIdle complete its processing before you
// attempt any additional idle loop processing.
if (CWinApp::OnIdle(lCount))
return TRUE; // The base class CWinApp::OnIdle reserves the lCount values 0
// and 1 for the framework's own idle processing. If you wish to
// share idle processing time at a peer level with the framework,
// then replace the above if-statement with a straight call to
// CWinApp::OnIdle; and then add a case statement for lCount value
// 0 and/or 1. Study the base class implementation first to
// understand how your idle loop tasks will compete with the
// framework's idle loop processing. switch (lCount)
{
case 2:
Task1();
return TRUE; // next time give Task2 a chance
case 3:
Task2();
return TRUE; // next time give Task3 and Task4 a chance
case 4:
Task3();
Task4();
return FALSE; // cycle through the idle loop tasks again
}
return FALSE;
}
clock_t lastTaskTimestamp;
void task1()
{
g_btaskrunning=true;
//process task here/g_btaskrunning=false;
lastTaskTimestamp=clock();}然后可以使用timer或waitabletimer定时检查当前时间与lastTaskTimestamp的间隔。如果你的task是多线程处理的,需要有同步手段。应该没什么问题
因此,应该检测用户输入(mouse+keyboard)的空闲时间.在win2000/xp下有API,9x下可能得写hook自己统计.
lpi.cbSize = sizeof(lpi);
GetLastInputInfo(&lpi);调用函数GetLastInputInfo()以后, 结构成员lpi.dwTime 中的值便是自上次输入事件发生以后的毫秒数。这个值也就是键盘、鼠标处于空闲状态的时间。9x下面要通过钩子来实现。
引用:HHOOK g_hHookKbd = NULL;
HHOOK g_hHookMouse = NULL;在Windows中,一个系统(相对于一个特定进程而言)钩子必须用一个动态链接库(DLL)来实现。不妨将这个动态链接库命名为IdleUI.dll。 这个动态链接库在Windows 9x和Windows NT4.0中实现了GetLastInputInfo()的功能。IdleUI.dll中有三个函数:BOOL IdleUIInit()
void IdleUITerm();
DWORD IdleUIGetLastInputTime();IdleUIInit()是环境初始化函数,IdleUITerm()是环境清理函数,分别在MFC应用程序的InitInstance() 和 ExitInstance()中调用它们。当用IdleUIInit()做完初始化后,就可以调用第三个函数IdleUIGetLastInputTime()来获取最后一次输入事件后的时钟。从而实现与GetLastInputInfo()一样的功能。程序TestIdleUI.exe是用来测试IdleUI动态库的,程序中调用了IdleUIInit 和 IdleUITerm,同时在程序的客户区中间显示键盘、鼠标空闲的秒数。void CMainFrame::OnPaint()
{
CPaintDC dc(this);
CString s;
DWORD nsec = (GetTickCount() - IdleUIGetLastInputTime())/1000;
s.Format( "鼠标或键盘空闲 %d 秒。",nsec);
CRect rc;
GetClientRect(&rc);
dc.DrawText(s, &rc, DT_CENTER|DT_VCENTER|DT_SINGLELINE);
}为了连续的显示,TestIdleUI设置刷新定时器间隔为一秒。void CMainFrame::OnTimer(UINT)
{
Invalidate();
UpdateWindow();
}运行TestIdleUI,当键盘和鼠标什么也不做时,可以看到计时器跳动,当移动鼠标或按键时,计时器又恢复到零,这样就实现了对输入设备空闲状态的监控。实现细节请看下面对IdleUI.dll工作原理的描述:首先调用IdleUIInit ()进行初始化,安装两个钩子:一个用于监控鼠标输入,一个用于监控键盘输入。HHOOK g_hHookKbd;
HHOOK g_hHookMouse;
g_hHookKbd = SetWindowsHookEx(WH_KEYBOARD,
MyKbdHook,
hInst, 0);
g_hHookMouse = SetWindowsHookEx(WH_MOUSE,
MyMouseHook,
hInst, 0);当用户移动鼠标或按下键盘键时,Windows调用其中的一个钩子并且钩子函数开始记录时间: LRESULT CALLBACK MyMouseHook(int code,
WPARAM wp,
LPARAM lp)
{
if (code==HC_ACTION) {
// note the tick count
g_dwLastInputTick = GetTickCount();
}
return ::CallNextHookEx(g_hHookMouse,
code, wp, lp);
}如法炮制MyKbdHook。IdleUIGetLastInputTime 返回结果g_dwLastInputTick, 并且IdleUITerm 卸载两个钩子。这个程序中有一个细节使用了一些技巧:通常,建立一个动态链接库时,链接器将静态数据标记为非共享,也就是说,每一个调用DLL的进程都获得自己的数据拷贝------在本程序中是g_hHookKbd、g_hHookMouse和g_dwLastInputTick。当在整个进程空间中需要且只需要一个这些数据的实例时,这样的静态数据标记就不适合了,为了解决这个问题,必须实现数据共享。为此得把数据放入一个特定的段地址中,然后将它们标记为共享。实现代码如下:#pragma data_seg (".IdleUI") // 可以取任何别的名字
HHOOK g_hHookKbd = NULL;
HHOOK g_hHookMouse = NULL;
DWORD g_dwLastInputTick = 0;
#pragma data_seg ()这段代码告诉链接器将三个变量放到叫“.IdleUI”的数据段中。然后在模块定义文件.DEF中加入下面的代码来共享这个数据段:SECTIONS .IdleUI READ WRITE SHARED // in IdleUI.def
当然,我没有写过一个VC++的软件。