2010-01-16 3 views
1

J'écris un service Windows en utilisant C# .NET 2005. Comment puis-je déterminer qui est l'utilisateur actuellement connecté (le cas échéant)? Est-il également possible d'être averti lorsqu'un utilisateur se connecte?Comment déterminer l'utilisateur Windows actuel à partir d'un service Windows?

Sinon, existe-t-il un moyen de savoir qui a récemment utilisé la machine?

J'ai besoin de connaître l'utilisateur actuellement connecté afin que je puisse mettre en cache des données pour cet utilisateur. Dans un environnement d'entreprise, il existe des milliers d'utilisateurs potentiels, mais il est logique de mettre en cache des données pour quelqu'un qui utilise cette machine.

MISE À JOUR:

This solution fonctionne bien. Voir aussi this pinvoke.net example qui utilise la structure étendue pour récupérer également le nom de domaine. En combinaison avec ceci, j'utilise la classe SystemEvents pour être averti lorsqu'un utilisateur ouvre une session sur la machine. Voir example 2 here pour un bon exemple - notez que vous devez utiliser un formulaire caché d'un service afin de pouvoir utiliser SystemEvents à partir d'un service.

Répondre

3

Vous pouvez utiliser P/Invoke pour appeler le NetWkstaUserEnum, qui énumérera les utilisateurs actuellement connectés. Gardez à l'esprit qu'il peut y avoir plus d'un utilisateur dans le cas où il y a des sessions Terminal Server, et que tous les utilisateurs retournés ne sont pas des utilisateurs "réels". Comme la documentation indique:

"Cette liste comprend interactive, logons de service et par lots."

Voici un exemple de code de travail complet en C# sur la façon d'appeler 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

Merci, c'est génial. J'ai remarqué qu'il peut retourner deux fois le même utilisateur, donc j'ajouterais une étape de-dup si des valeurs uniques sont désirées. – Rory

0

Comme vous le savez, il ne peut pas être un utilisateur actuellement connecté dans un service Windows. Pourquoi ne pas ajouter un petit programme utilitaire au processus d'ouverture de session sur la machine, qui s'exécutera à chaque connexion, qui exécutera une méthode qui appelle la fonctionnalité de mise en cache des données dans le service. De cette façon, cet utilitaire aura accès au connecté sur le principe des fenêtres des utilisateurs Identité.

+0

Bien que cela soit probablement plus simple à construire, cela signifie qu'il y a plus de dépendances de déploiement et d'exécution à la solution et donc plus de problèmes: si quelqu'un change les processus d'ouverture de session pour que l'utilitaire soit désactivé, par exemple. S'il existe une solution programmatique standard, ce serait mieux. – Rory

+0

@Rory, je devinais qu'il s'agit d'un serveur, où ces préoccupations sont moins un problème .... à savoir, sauf rares cas, les seules personnes qui se connectent se connectent à distance en utilisant le bureau à distance .. En outre, en mettant le fonctionnalité dans le processus d'ouverture de session, signifie que vous n'avez pas à gérer plusieurs journaux simultanés. Mais chaque approche va fonctionner ... –

Questions connexes