从登录和注销获取通知 [英] Get notified from logon and logoff

查看:310
本文介绍了从登录和注销获取通知的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我必须开发一个在本地PC上作为服务运行的程序,将一系列用户状态提供给服务器。最初我必须检测用户登录注销

I have to develop a program which runs on a local pc as a service an deliver couple of user status to a server. At the beginning I have to detect the user logon and logoff.

我的想法是使用 ManagementEventWatcher 类,并查询 Win32_LogonSession ,以便在有变化的情况下收到通知。

My idea was to use the ManagementEventWatcher class and to query the Win32_LogonSession to be notified if something changed.

我的第一个测试运行良好,这里是代码部分(这将作为一个服务的线程执行)

My first test works well, here is the code part (This would executed as a thread from a service):

private readonly static WqlEventQuery qLgi = new WqlEventQuery("__InstanceCreationEvent", new TimeSpan(0, 0, 1), "TargetInstance ISA \"Win32_LogonSession\"");

public EventWatcherUser() {
}

public void DoWork() {
    ManagementEventWatcher eLgiWatcher = new ManagementEventWatcher(EventWatcherUser.qLgi);
    eLgiWatcher.EventArrived += new EventArrivedEventHandler(HandleEvent);
    eLgiWatcher.Start();
}

private void HandleEvent(object sender, EventArrivedEventArgs e)
{
    ManagementBaseObject f = (ManagementBaseObject)e.NewEvent["TargetInstance"];
    using (StreamWriter fs = new StreamWriter("C:\\status.log", true))
    {
        fs.WriteLine(f.Properties["LogonId"].Value);
    }
}

但我有一些理解问题,我不是如果这是解决这个任务的常用方法。

But I have some understanding problems and I’m not sure if this is the common way to solve that task.


  1. 如果我查询 Win32_LogonSession 我收到与同一用户关联的
    的几个记录。例如,我得到这个ID 7580798和
    7580829,如果我查询

  1. If I query Win32_LogonSession I get several records which are associated to the same user. For example I get this IDs 7580798 and 7580829 and if I query

ASSOCIATORS OF {Win32_LogonSession.LogonId = X}
WHERE ResultClass = Win32_UserAccount

ASSOCIATORS OF {Win32_LogonSession.LogonId=X} WHERE ResultClass=Win32_UserAccount

我为不同的ID获得相同的记录。
(Win32_UserAccount.Domain =PC-Name,Name =User1)

I get the same record for different IDs. (Win32_UserAccount.Domain="PC-Name",Name="User1")

为什么同一用户有几个登录会话?什么是
常用的方式来获取当前登录的用户?或者更好的如何通过用户的登录正确获得通知

Why are there several logon session with the same user? What is the common way to get the current signed in user? Or better how to get notified correctly by the login of a user?

我以为我可以使用相同的方式与 __ InstanceDeletionEvent
确定用户是否注销。但是我猜,如果事件被提出,我可以在$ code> Win32_UserAccount 之后找到该用户名。我是对的?

I thought I could use the same way with __InstanceDeletionEvent to determine if a user is log off. But I guess if the event is raised, I cant query Win32_UserAccount for the username after that. I’m right?

我是正确的方向还是有更好的方法?如果您能帮助我,这将是非常棒的!

I’m at the right direction or are there better ways? It would be awesome if you could help me!

编辑 WTSRegisterSessionNotification类是否正确?我不知道是否可能,因为在一个服务中我没有窗口处理程序。

Edit Is the WTSRegisterSessionNotification class the correct way? I don't know if it's possible, because in a service I haven't a window handler.

推荐答案

我使用 ServiceBase.OnSessionChange to捕获不同的用户事件,然后加载必要的信息。

I use ServiceBase.OnSessionChange to catch the different user events and load the necessary information afterwards.

protected override void OnSessionChange(SessionChangeDescription desc)
{
    var user = Session.Get(desc.SessionId);
}

要加载会话信息,我使用 WTS_INFO_CLASS 。请参阅下面的示例:

To load the session information I use the WTS_INFO_CLASS. See my example below:

internal static class NativeMethods
{
    public enum WTS_INFO_CLASS
    {
        WTSInitialProgram,
        WTSApplicationName,
        WTSWorkingDirectory,
        WTSOEMId,
        WTSSessionId,
        WTSUserName,
        WTSWinStationName,
        WTSDomainName,
        WTSConnectState,
        WTSClientBuildNumber,
        WTSClientName,
        WTSClientDirectory,
        WTSClientProductId,
        WTSClientHardwareId,
        WTSClientAddress,
        WTSClientDisplay,
        WTSClientProtocolType,
        WTSIdleTime,
        WTSLogonTime,
        WTSIncomingBytes,
        WTSOutgoingBytes,
        WTSIncomingFrames,
        WTSOutgoingFrames,
        WTSClientInfo,
        WTSSessionInfo
    }

    [DllImport("Kernel32.dll")]
    public static extern uint WTSGetActiveConsoleSessionId();

    [DllImport("Wtsapi32.dll")]
    public static extern bool WTSQuerySessionInformation(IntPtr hServer, Int32 sessionId, WTS_INFO_CLASS wtsInfoClass, out IntPtr ppBuffer, out Int32 pBytesReturned);

    [DllImport("Wtsapi32.dll")]
    public static extern void WTSFreeMemory(IntPtr pointer);
}

public static class Status
{
    public static Byte Online
    {
        get { return 0x0; }
    }

    public static Byte Offline
    {
        get { return 0x1; }
    }

    public static Byte SignedIn
    {
        get { return 0x2; }
    }

    public static Byte SignedOff
    {
        get { return 0x3; }
    }
}

public static class Session
{
    private static readonly Dictionary<Int32, User> User = new Dictionary<Int32, User>();

    public static bool Add(Int32 sessionId)
    {
        IntPtr buffer;
        int length;

        var name = String.Empty;
        var domain = String.Empty;

        if (NativeMethods.WTSQuerySessionInformation(IntPtr.Zero, sessionId, NativeMethods.WTS_INFO_CLASS.WTSUserName, out buffer, out length) && length > 1)
        {
            name = Marshal.PtrToStringAnsi(buffer);
            NativeMethods.WTSFreeMemory(buffer);
            if (NativeMethods.WTSQuerySessionInformation(IntPtr.Zero, sessionId, NativeMethods.WTS_INFO_CLASS.WTSDomainName, out buffer, out length) && length > 1)
            {
                domain = Marshal.PtrToStringAnsi(buffer);
                NativeMethods.WTSFreeMemory(buffer);
            }
        }

        if (name == null || name.Length <= 0)
        {
            return false;
        }

        User.Add(sessionId, new User(name, domain));

        return true;
    }

    public static bool Remove(Int32 sessionId)
    {
        return User.Remove(sessionId);
    }

    public static User Get(Int32 sessionId)
    {
        if (User.ContainsKey(sessionId))
        {
            return User[sessionId];
        }

        return Add(sessionId) ? Get(sessionId) : null;
    }

    public static UInt32 GetActiveConsoleSessionId()
    {
        return NativeMethods.WTSGetActiveConsoleSessionId();
    }
}

public class AvailabilityChangedEventArgs : EventArgs
{
    public bool Available { get; set; }

    public AvailabilityChangedEventArgs(bool isAvailable)
    {
        Available = isAvailable;
    }
}

public class User
{
    private readonly String _name;

    private readonly String _domain;

    private readonly bool _isDomainUser;

    private bool _signedIn;

    public static EventHandler<AvailabilityChangedEventArgs> AvailabilityChanged;

    public User(String name, String domain)
    {
        _name = name;
        _domain = domain;

        if (domain.Equals("EXAMPLE.COM"))
        {
            _isDomainUser = true;
        }
        else
        {
            _isDomainUser = false;
        }
    }

    public String Name
    {
        get { return _name; }
    }

    public String Domain
    {
        get { return _domain; }
    }

    public bool IsDomainUser
    {
        get { return _isDomainUser; }
    }

    public bool IsSignedIn
    {
        get { return _signedIn; }
        set
        {
            if (_signedIn == value) return;

            _signedIn = value;

            OnAvailabilityChanged(this, new AvailabilityChangedEventArgs(IsSignedIn));
        }
    }

    protected void OnAvailabilityChanged(object sender, AvailabilityChangedEventArgs e)
    {
        if (AvailabilityChanged != null)
        {
            AvailabilityChanged(this, e);
        }
    }
}

以下代码使用静态 AvailabilityChanged 来自用户的事件,一旦会话状态更改,它将被触发。

The following code use the static AvailabilityChanged event from User, which gets fired as soon as the session state changes. The arg e contains the specific user.

public Main()
{
  User.AvailabilityChanged += UserAvailabilityChanged;
}

private static void UserAvailabilityChanged(object sender, AvailabilityChangedEventArgs e)
{
  var user = sender as User;

  if (user == null) return;

  System.Diagnostics.Debug.WriteLine(user.IsSignedIn);
}

这篇关于从登录和注销获取通知的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆