2016-04-05 12 views
4

C#Winformsアプリケーションが一定期間アイドル状態になっているかどうかを検出する最も良い方法は何ですか?Winformsアプリケーションを検出する方法は一定の時間アイドル状態になっています

ユーザーがALT + TABを選択してMicrosoft Wordなどで30分間何か作業を行う場合、私たちのアプリケーションを使用しないままにしておくと、私たちのアプリケーションは自己終了します。

これは、同様の質問に対する受け入れ答えている: Check if an application is idle for a time period and lock it

はしかし、答えはない、特定のアプリケーションのWindowsは、しばらくの間アイドル状態であることに関係します。私は、アプリケーションが30分で使われていなければ、アプリケーションを終了させたいと思っています。

私はこれを見て:私はこれが私たちのアプリは1となっているマルチスレッドアプリケーション、機能しないことをコメントで読んしかし

http://www.codeproject.com/Articles/13756/Detecting-Application-Idleness

私たちのアプリは、それが動作するかどうグリッドを埋めるために非同期待つを使用し、モーダルとモードレスフォームを生成しますメインフォーム、など

は、その後、私はわからない、は、SetWindowsHookExを見ています。

きっと誰かが(うまくいけば、.NET 4.5との互換性)ソリューションを持っている:)

TIA

+1

Winform onfocus lostは、タイマと組み合わせて使用​​できます。 – schultz

+0

パフォーマンスカウンターでそれを測定し、アプリケーションがアイドル状態であると見なす数字に応じて決定する必要があります – Zinov

+0

アプリケーションが自己終了するのを見た場合、クラッシュしていると思います。それがあなたが望む行動だと確信していますか? –

答えて

3

これを実行する方法はたくさんありますが、回答は必要なものによって多少異なります。あなたは、あなたが必要とするものについて明確かつ具体的です。以下は私の開発したもので、おそらくあなたの要求に合っています。それが何をしているのは、アプリケーションがメッセージの処理を終了した後、タイマーを設定し、アプリケーションのすべてのメッセージをフィルタリング(リッスン)するために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; 
     } 
    } 
} 
0

あなたは手段を "アイドル" かを決定する必要があります。私はマウスやキー入力が必要な時間内にアプリケーションによって受信されないと仮定します。

アプリケーション全体のすべてのWindowsメッセージを表示するメッセージフィルタを追加できます。 Application.AddMessageFilterを参照してください。キーダウンとマウスダウンのメッセージコードを確認し、発生した最後の時刻を記録しますが、falseを返して、すべてのメッセージがランタイムによって正常に処理されるようにします。おそらくコードは次のとおりです。

WM_LBUTTONDOWN = 513 
RBUTTONDOWN = 516 
WM_KEYDOWN = 256 

その後、別のタイマーで最後のイベントは、30分以上前であるとき、他の場所で確認してください。

アプリケーションの「終了」にも潜在的な問題があります。アプリケーションがモーダルフォームを開いている場合は、突然殺すのに特に安全な状態ではないかのように聞こえます。

+0

IIRC - メッセージフィルタがスレッド固有であるという点で問題が発生する可能性があります。彼はマルチスレッドアプリケーションで動作するようなものが必要であると具体的に述べているので、OPのためにはうまくいきません。 – AgapwIesu

+0

OPは他のスレッドでバックグラウンドタスクを実行していますが、私の理解では、Windowsメッセージは元のスレッドにまだ到着するでしょう。 –

+0

サンプルを提供しました。それを試してみるのは簡単でしょう。ほとんどのスレッドにUIはありません(メッセージループ)。おそらくメッセージフィルタは、独自のUI(メッセージループ)を持つ他のすべてのスレッドで使用する必要があります。 UIアクティビティではないスレッドに**関連する**アクティビティがある場合は、それを別々に検出する必要があります。 – user34660

関連する問題