以非管理员身份捕获本地计算机上的登录事件.有没有接口

本文关键字:登录 事件 接口 有没有 计算机 管理员 身份 | 更新日期: 2023-09-27 18:32:04

作为非管理员用户,我想在其他用户登录时检测事件。我无法使用系统事件通知服务 (SensLogon2),因为它要求用户是管理员组的一部分。是否有其他 API,或者我可以向当前用户授予某些权限/特权?

我们需要检测通过 RDP 登录到终端的另一个用户,以便我们可以更改当前用户所处的应用程序状态。

以非管理员身份捕获本地计算机上的登录事件.有没有接口

您可以执行后续步骤来获取有关会话更改的信息:

  1. 在表单上NOTIFY_FOR_ALL_SESSIONS调用WTSRegisterSessionNotification以接收WM_WTSSESSION_CHANGE消息
  2. 覆盖表单的无效 WndProc(ref 消息 m) 并按WM_WTSSESSION_CHANGE过滤 (0x2b1)
  3. 从 LPARAM 中提取会话 ID 并从 WPARAM 中提取会话状态更改事件
  4. 使用会话ID调用WTSQuerySessionInformation以获取用户名

这是使用pInvoke的工作示例。我的项目中有 Form1 (WinForm)。是的:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace MessageLoop
{
    public partial class Form1 : Form
    {
        /// <summary>
        ///  WM_WTSSESSION_CHANGE message number for filtering in WndProc
        /// </summary>
        private const int WM_WTSSESSION_CHANGE = 0x2b1;
        public Form1()
        {
            InitializeComponent();
            NativeWrapper.WTSRegisterSessionNotification(this, SessionNotificationType.NOTIFY_FOR_ALL_SESSIONS);
        }
        protected override void OnClosing(CancelEventArgs e)
        {
            NativeWrapper.WTSUnRegisterSessionNotification(this);
            base.OnClosing(e);
        }
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == WM_WTSSESSION_CHANGE)
            {
                int eventType = m.WParam.ToInt32();
                int sessionId = m.LParam.ToInt32();
                WtsSessionChange reason = (WtsSessionChange)eventType;
                Trace.WriteLine(string.Format("SessionId: {0}, Username: {1}, EventType: {2}", 
                    sessionId, NativeWrapper.GetUsernameBySessionId(sessionId), reason));
            }
            base.WndProc(ref m);
        }
    }
}

这是NativeWrapper.cs:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace MessageLoop
{
    public enum WtsSessionChange
    {
        WTS_CONSOLE_CONNECT = 1,
        WTS_CONSOLE_DISCONNECT = 2,
        WTS_REMOTE_CONNECT = 3,
        WTS_REMOTE_DISCONNECT = 4,
        WTS_SESSION_LOGON = 5,
        WTS_SESSION_LOGOFF = 6,
        WTS_SESSION_LOCK = 7,
        WTS_SESSION_UNLOCK = 8,
        WTS_SESSION_REMOTE_CONTROL = 9,
        WTS_SESSION_CREATE = 0xA,
        WTS_SESSION_TERMINATE = 0xB
    }
    public enum SessionNotificationType
    {
        NOTIFY_FOR_THIS_SESSION = 0,
        NOTIFY_FOR_ALL_SESSIONS = 1
    }
    public static class NativeWrapper
    {
        public static void WTSRegisterSessionNotification(Control control, SessionNotificationType sessionNotificationType)
        {
            if (!Native.WTSRegisterSessionNotification(control.Handle, (int)sessionNotificationType))
                throw new Win32Exception(Marshal.GetLastWin32Error()); 
        }
        public static void WTSUnRegisterSessionNotification(Control control)
        {
            if (!Native.WTSUnRegisterSessionNotification(control.Handle))
                throw new Win32Exception(Marshal.GetLastWin32Error());
        }
        public static string GetUsernameBySessionId(int sessionId)
        {           
            IntPtr buffer;
            int strLen;
            var username = "SYSTEM"; // assume SYSTEM as this will return "'0" below
            if (Native.WTSQuerySessionInformation(IntPtr.Zero, sessionId, Native.WTS_INFO_CLASS.WTSUserName, out buffer, out strLen) && strLen > 1)
            {
                username = Marshal.PtrToStringAnsi(buffer); // don't need length as these are null terminated strings
                Native.WTSFreeMemory(buffer);
                if (Native.WTSQuerySessionInformation(IntPtr.Zero, sessionId, Native.WTS_INFO_CLASS.WTSDomainName, out buffer, out strLen) && strLen > 1)
                {
                    username = Marshal.PtrToStringAnsi(buffer) + "''" + username; // prepend domain name
                    Native.WTSFreeMemory(buffer);
                }
            }
            return username;
        }
    }
}

最后一个文件是本机文件.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace MessageLoop
{
    public static class Native
    {
        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("wtsapi32.dll", SetLastError = true)]
        internal static extern bool WTSRegisterSessionNotification(IntPtr hWnd, [MarshalAs(UnmanagedType.U4)] int dwFlags);
        [DllImport("wtsapi32.dll", SetLastError = true)]
        internal static extern bool WTSUnRegisterSessionNotification(IntPtr hWnd);
        [DllImport("Wtsapi32.dll")]
        internal static extern bool WTSQuerySessionInformation(IntPtr hServer, int sessionId, WTS_INFO_CLASS wtsInfoClass, out IntPtr ppBuffer, out int pBytesReturned);
        [DllImport("Wtsapi32.dll")]
        internal static extern void WTSFreeMemory(IntPtr pointer);
    }
}