2012-06-27 44 views
4

我想檢查我的應用程序中的用戶不活動。我做了一些研究,並使用GetLastInputInfo和Environment.TickCount,因爲它看起來很簡單。不幸的是,它變得有點棘手。GetLastInputInfo的整數環繞問題

GetLastInputInfo返回一個LASTINPUTINFO結構,它具有最後一個「TickCount」值作爲DWORD(即UInt32)。理論上,我想從Environment.TickCount中減去這個值,這給了我多少毫秒的用戶一直處於非活動狀態。

Environment.TickCount返回一個Int32。兩者都會在達到最大值時迴繞,這對於Int32和UInt32是不同的。我處理這個問題有點不舒服,特別是因爲代碼基本上不能被測試(Environment.TickCount在24.9天后環繞並且該功能在此之前到期)。

這是我到目前爲止已經完成:

[DllImport("user32.dll")] 
static extern bool GetLastInputInfo(out LastInputInfo plii); 
struct LastInputInfo 
{ 
    public uint cbSize; 
    public uint dwTime; 
} 

//(...) 
var lastInputInfo = new LastInputInfo(); 
lastInputInfo.cbSize = (uint)Marshal.SizeOf(lastInputInfo); 
if (GetLastInputInfo(out lastInputInfo)) 
{ 
    // The next line obviously will not work when either of the terms has wrapped around 
    var idleTime = Environment.TickCount - lastInputInfo.dwTime; 
    if (idleTime > mTimeOut) 
    { 
    // user is inactive! 
    } 
} 

有一個很簡單的方法來處理這兩種迴繞或者我應該使用其他方法來共檢測用戶閒置?此外,如何在25天內無需專用計算機的情況下對此進行任何建議,我們都非常感謝。

+0

請記住,這種方法只能檢測用戶閒置時間模〜50天。 –

+0

@HristoIliev感謝您的提醒,但該功能的使用情況是5分鐘到1小時不活動,所以這不是問題。 – Asik

回答

7

由於不活動時間比滴答櫃的容量要小得多,所以根本不是問題。

如果其中一個計數器纏繞而不是另一個,則減法中的結果也會環繞並給出正確的結果。你只需要以使具有相同的數據類型強制轉換的值:

int idleTime = Environment.TickCount - (int)lastInputInfo.dwTime; 

例如,如果Environment.TickCount已經纏到-2147483612和lastInputInfo.dwTime是2147483624,則-2147483612 - 2147483624 = 60

您甚至可以將兩個值都轉換爲較小的數據類型(如Int16),只要空閒時間符合數據類型,減法後您仍然會得到正確的結果。

+0

看起來是正確的,我在F#interactive中做了一些測試來驗證。 :P謝謝! – Asik

+0

只需確認一下,假設您使用Win32 GetTickCount()返回一個uint,那麼結果是正確的? – Ravenheart

3

這只是Guffa答案的補充。

這是「最佳實踐」,依靠整數溢出來始終使用unchecked關鍵字。有兩個原因:

  1. 它讓讀者知道你是故意的溢出
  2. 依託雖然未檢查是在C#中默認情況下,可以在編譯器的命令行來改變。

Checked and Unchecked (C# Reference)

int idleTime = unchecked(Environment.TickCount - (int)lastInputInfo.dwTime); 
+0

+1是的,這使得代碼更具信息性,而且不依賴於特定的編譯器設置更健壯。 – Guffa