我正在研究需要檢測登錄到單臺計算機上的所有用戶的用戶狀態的服務。具體來說,我想檢查屏幕保護程序是否處於活動狀態,以及他們的會話是否被鎖定。服務需要檢測工作站是否鎖定,並且屏幕保護程序處於活動狀態
此代碼將在系統級服務下運行,並且沒有可見的用戶界面,因此可以排除幾個選項(捕獲WM消息等)。
除了正常的工作站,我希望這可以在有多個用戶登錄到它的終端服務器上工作。由於這些要求,我想知道是否需要涉及幾個Win32 API。
任何想法從哪裏開始?
我正在研究需要檢測登錄到單臺計算機上的所有用戶的用戶狀態的服務。具體來說,我想檢查屏幕保護程序是否處於活動狀態,以及他們的會話是否被鎖定。服務需要檢測工作站是否鎖定,並且屏幕保護程序處於活動狀態
此代碼將在系統級服務下運行,並且沒有可見的用戶界面,因此可以排除幾個選項(捕獲WM消息等)。
除了正常的工作站,我希望這可以在有多個用戶登錄到它的終端服務器上工作。由於這些要求,我想知道是否需要涉及幾個Win32 API。
任何想法從哪裏開始?
最直接的方法是在每個用戶的會話中運行一個小應用程序。此應用程序的每個實例都可以與服務的主要實例進行通信。
Windows非常難以保持登錄會話分開 - 在服務和交互式桌面之間以及在單獨的終端服務會話之間 - 所以訪問有關用戶會話的這類信息非常棘手,除非您的應用程序是在該會話中運行以開始。
屏保應該有擴展名.scr的,你可以查詢正在運行的進程......
一個簡單的辦法是使用Cassia,它包裝的各種TS的API,以檢查用戶有多久空閒:
using Cassia;
foreach (ITerminalServicesSession session in new TerminalServicesManager().GetSessions())
{
if ((session.CurrentTime - session.LastInputTime > TimeSpan.FromMinutes(10)) &&
(!string.IsNullOrEmpty(session.UserName)))
{
Console.WriteLine("Session {0} (User {1}) is idle", session.SessionId, session.UserName);
}
}
作爲一個服務,您可以使用事件OnSessionChange來捕獲所有相關的時刻。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceProcess;
using System.Diagnostics;
namespace MyCode
{
class MyService : ServiceBase
{
public MyService()
{
this.CanHandleSessionChangeEvent = true;
}
protected override void OnSessionChange(SessionChangeDescription changeDescription)
{
switch (changeDescription.Reason)
{
case SessionChangeReason.SessionLogon:
Debug.WriteLine(changeDescription.SessionId + " logon");
break;
case SessionChangeReason.SessionLogoff:
Debug.WriteLine(changeDescription.SessionId + " logoff");
break;
case SessionChangeReason.SessionLock:
Debug.WriteLine(changeDescription.SessionId + " lock");
break;
case SessionChangeReason.SessionUnlock:
Debug.WriteLine(changeDescription.SessionId + " unlock");
break;
}
base.OnSessionChange(changeDescription);
}
}
}
我確定可以根據changeDescription.SessionId來識別用戶。但此刻我不知道如何...
編輯:這應該是一個possibilty
public static WindowsIdentity GetUserName(int sessionId)
{
foreach (Process p in Process.GetProcesses())
{
if(p.SessionId == sessionId) {
return new WindowsIdentity(p.Handle);
}
}
return null;
}
MSDN鏈接
GetUserName代碼不適用於我(引發異常)。不過,我在這裏找到了代碼,它需要執行以下操作:http://msmvps.com/blogs/siva/archive/2006/10/02/Getting-Windows-Process-Owner-Name.aspx – Kramii 2011-06-08 10:03:44
謝謝,我會放棄這一點。也許一個簡單的套接字將是最好的方式來做到這一點。 – 2008-10-29 20:53:38