检测C#Winforms应用程序是否已空闲一段时间的最佳方法是什么?
如果用户决定使用ALT + TAB并使用Microsoft Word或其他任何工作30分钟,我们的应用程序未使用,我希望我们的应用能够自行终止。
这是类似问题的公认答案: Check if an application is idle for a time period and lock it
但是,答案与Windows闲置一段时间相关,不特定应用程序。我希望我们的申请终止,如果它没有被用于说,30分钟。
我看了看这个:
http://www.codeproject.com/Articles/13756/Detecting-Application-Idleness
但是我在评论中读到这对多线程应用程序不起作用,我们的应用程序就是其中之一。 我们的应用程序有一个主窗体,它产生模态和无模式窗体,使用Async Await来填充网格等。
然后我查看了SetWindowsHookEx,不确定这是否有用。
当然有人有解决方案(希望与.NET 4.5兼容):)
TIA
答案 0 :(得分:10)
有很多方法可以做到,答案在某种程度上取决于你需要做什么。您清楚明确地了解自己的需求。以下是我开发的可能符合您要求的内容。它正在做的是使用Application.Idle来确定应用程序何时完成处理消息然后它设置一个计时器并过滤(监听)应用程序的所有消息,如果收到相关消息(如鼠标或键盘),那么它重置计时器。它忽略鼠标移动,因为可以在不使用应用程序的情况下将鼠标移动到应用程序上。我写这篇文章已经有一段时间了,所以我不确定细节,但如果有必要,我可以弄明白。请注意,这是一个控制台程序,可以使示例更容易尝试,但代码适用于表单应用程序。
using System;
using System.Security.Permissions;
using System.Windows.Forms;
namespace _121414
{
static class Program
{
public static Timer IdleTimer = new Timer();
const int MinuteMicroseconds = 60000;
static Form1 f = null;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
LeaveIdleMessageFilter limf = new LeaveIdleMessageFilter();
Application.AddMessageFilter(limf);
Application.Idle += new EventHandler(Application_Idle);
IdleTimer.Interval = MinuteMicroseconds; // One minute; change as needed
IdleTimer.Tick += TimeDone;
IdleTimer.Start();
f = new Form1();
Application.Run(f);
Application.Idle -= new EventHandler(Application_Idle);
}
static private void Application_Idle(Object sender, EventArgs e)
{
if (!IdleTimer.Enabled) // not yet idling?
IdleTimer.Start();
}
static private void TimeDone(object sender, EventArgs e)
{
IdleTimer.Stop(); // not really necessary
MessageBox.Show("Auto logoff");
f.Close();
}
}
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public class LeaveIdleMessageFilter : IMessageFilter
{
const int WM_NCLBUTTONDOWN = 0x00A1;
const int WM_NCLBUTTONUP = 0x00A2;
const int WM_NCRBUTTONDOWN = 0x00A4;
const int WM_NCRBUTTONUP = 0x00A5;
const int WM_NCMBUTTONDOWN = 0x00A7;
const int WM_NCMBUTTONUP = 0x00A8;
const int WM_NCXBUTTONDOWN = 0x00AB;
const int WM_NCXBUTTONUP = 0x00AC;
const int WM_KEYDOWN = 0x0100;
const int WM_KEYUP = 0x0101;
const int WM_MOUSEMOVE = 0x0200;
const int WM_LBUTTONDOWN = 0x0201;
const int WM_LBUTTONUP = 0x0202;
const int WM_RBUTTONDOWN = 0x0204;
const int WM_RBUTTONUP = 0x0205;
const int WM_MBUTTONDOWN = 0x0207;
const int WM_MBUTTONUP = 0x0208;
const int WM_XBUTTONDOWN = 0x020B;
const int WM_XBUTTONUP = 0x020C;
// The Messages array must be sorted due to use of Array.BinarySearch
static int[] Messages = new int[] {WM_NCLBUTTONDOWN,
WM_NCLBUTTONUP, WM_NCRBUTTONDOWN, WM_NCRBUTTONUP, WM_NCMBUTTONDOWN,
WM_NCMBUTTONUP, WM_NCXBUTTONDOWN, WM_NCXBUTTONUP, WM_KEYDOWN, WM_KEYUP,
WM_LBUTTONDOWN, WM_LBUTTONUP, WM_RBUTTONDOWN, WM_RBUTTONUP,
WM_MBUTTONDOWN, WM_MBUTTONUP, WM_XBUTTONDOWN, WM_XBUTTONUP};
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == WM_MOUSEMOVE) // mouse move is high volume
return false;
if (!Program.IdleTimer.Enabled) // idling?
return false; // No
if (Array.BinarySearch(Messages, m.Msg) >= 0)
Program.IdleTimer.Stop();
return false;
}
}
}
答案 1 :(得分:0)
你需要决定什么&#34;空闲&#34;手段。我假设应用程序在所需的时间内没有收到任何鼠标或键输入。
您可以添加一个消息过滤器,该过滤器将查看所有应用程序范围的Windows消息。见Application.AddMessageFilter。检查按键和鼠标按下的消息代码,并记录上次发生的消息代码,但返回false,以便运行时正常处理所有消息。可能的代码是:
WM_LBUTTONDOWN = 513
RBUTTONDOWN = 516
WM_KEYDOWN = 256
然后在别处的另一个计时器中检查最后一个事件是否超过30分钟。
还有潜在的问题&#34;终止&#34;应用程序。如果应用程序打开了模态窗体,听起来好像它可能没有特别安全的状态突然杀死。