2010-01-16 26 views
1

我正在使用C#.NET 2005編寫Windows服務。我如何確定當前登錄的用戶是誰(如果有的話)?當用戶登錄時還有一種通知方式嗎?如何從Windows服務中確定當前的Windows用戶?

或者,有沒有辦法知道誰最近使用過機器?

我需要知道當前登錄的用戶,所以我可以緩存該用戶的一些數據。在公司環境中運行時,有成千上萬的潛在用戶,但只有爲使用該機器的用戶緩存數據纔有意義。

UPDATE:

This solution效果很好。另請參閱this pinvoke.net example,它使用擴展結構來檢索域名。

與此組合,我使用SystemEvents類在用戶登錄到機器時收到通知。請參閱example 2 here一個很好的示例 - 請注意,您需要使用服務中的隱藏表單才能使用服務中的SystemEvents。

回答

3

您可以使用P/Invoke調用NetWkstaUserEnum,它將枚舉當前登錄的用戶。請記住,如果有終端服務器會話,可能會有多個用戶,並且並非所有用戶都返回了「真實」用戶。如文檔所述:

「此列表包括交互式, 服務和批處理登錄。」

這裏是在C#中如何調用NetWkstaUserEnum一個完整的工作代碼示例:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Runtime.InteropServices; 

namespace EnumerateUsers 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var ue = new UserEnumerator(); 
      foreach(string userName in ue.GetLoggedOnUsers(null)) 
      { 
       Console.WriteLine(userName); 
      } 
     } 

    } 

    class UserEnumerator 
    { 
     public IEnumerable<string> GetLoggedOnUsers(string host) 
     { 
      int entriesRead, totalEntries, resumeHandle = 0; 
      IntPtr pBuffer = IntPtr.Zero; 
      try 
      { 
       int result = NetWkstaUserEnum(host, 0, out pBuffer, MAX_PREFERRED_LENGTH, out entriesRead, out totalEntries, ref resumeHandle); 
       if (result != NERR_Success) 
        throw new ApplicationException(String.Format("Failed to enumerate users, error code {0}", result)); 

       return GetUsersFromStruct(pBuffer, entriesRead).ToList(); 
      } 
      finally 
      { 
       if (pBuffer != IntPtr.Zero) 
        NetApiBufferFree(pBuffer); 
       } 

     } 

     private IEnumerable<string> GetUsersFromStruct(IntPtr pBuffer, int count) 
     { 
      for (int i = 0; i < count; i++) 
      { 
       var user = (WKSTA_USER_INFO_0)Marshal.PtrToStructure(pBuffer, typeof(WKSTA_USER_INFO_0)); 
       yield return user.username; 
       pBuffer = IntPtr.Add(pBuffer, user.username.Length * 2);     
      } 
     } 
     [DllImport("netapi32.dll")] 
     private static extern int NetWkstaUserEnum(string host, int level, out IntPtr pBuffer, int prefMaxLength, out int entriesRead, 
            out int totalEntries, ref int resumeHandle); 

     [DllImport("netapi32.dll")] 
     private static extern int NetApiBufferFree(IntPtr buffer); 

     private const int MAX_PREFERRED_LENGTH = -1; 

     private const int NERR_Success = 0; 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    struct WKSTA_USER_INFO_0 
    { 
     [MarshalAs(UnmanagedType.LPTStr)] 
     internal string username; 
    } 
} 
+0

謝謝,這太棒了。我注意到它可以返回兩次相同的用戶,所以如果需要唯一值,我會添加一個去重複步驟。 – Rory

0

如你所知,有可能不是當前登錄的Windows服務中的用戶。爲什麼不在計算機上的啓動登錄過程中添加一個小的實用程序,只要有人登錄就會運行該程序,該程序將執行調用服務中的數據高速緩存功能的方法。這樣,該實用程序就可以訪問登錄用戶的Windows原則身份。

+0

儘管構建起來可能更簡單,但這意味着解決方案會有更多的部署和運行時依賴關係,因此會出現更多問題:例如,如果某人更改了啓動登錄進程以禁用實用程序,該怎麼辦?如果有一個標準的程序化解決方案會更好。 – Rory

+0

@Rory,我猜這是一個服務器,在這種情況下問題不大......除了極少數情況外,唯一登錄的用戶使用遠程桌面遠程登錄。另外,通過將登錄過程中的功能,意味着您不必處理多個併發登錄。但是任何一種方法都可行 –

相關問題