首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使.NET检测登录、注销和切换用户事件?

如何使.NET检测登录、注销和切换用户事件?
EN

Stack Overflow用户
提问于 2011-03-18 14:01:01
回答 5查看 25.9K关注 0票数 14

我需要跟踪Windows SP3上用户(使用控制台的用户)的当前情况。

我尝试了以下几点:

  • Microsoft.Win32.SystemEvents.SessionSwitch:适用于单个登录/注销事件,但未能检测到交换机用户。 如果发生下列情况:
代码语言:javascript
复制
1. userA log in
2. userA switch user
3. userB login
4. userB logout
5. userA restore session

事件3和事件4未被SystemEvents.SessionSwitch检测到

  • 监视“安全”EventLog:事件不一致,到达不正常。例如,如果上面的列表被重播,我将收到一个事件id 528 (登录),在他恢复会话后为userA接收两个538 (注销)。检查event.TimeGenerated没有帮助。如果在SecPol.msc上禁用审核,则此方法也不起作用。
  • P/调用WTSRegisterSessionNotification:工作正常。我必须创建一个隐藏表单,重写它的WndProc来处理WM_WTSSESSION_CHANGE消息,然后调用WTSQuerySessionInformation获取与事件关联的用户名。这个方法看起来太复杂了,有更简单的方法吗?

编辑:

  • 每n毫秒调用一次WTSGetActiveConsoleSessionId也有效,但我正在寻找一种基于事件的方法。
EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2011-03-18 14:18:07

如果您正在创建一个服务,那么您的类是从ServiceBase派生的。考虑调查OnSessionChange方法。重写此方法以检测不同类型的会话更改。它提供了会话更改的原因和新的会话标识符。确保在构造函数中将CanHandleSessionChangeEvent设置为true,否则将不会调用您的覆盖。

票数 28
EN

Stack Overflow用户

发布于 2016-08-12 17:19:02

在最后一部分中,我使用它来查询会话更改事件:

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Linq;
using System.Windows.Forms;
using Rdp.Interfaces;
using Microsoft.Win32;
using System.ServiceProcess;
using System.Diagnostics;
using System.Threading;
using Balzers.Misc.Helpers;


namespace Rdp.Service {

/// <summary>
///     <para> Terminal session info provider has 2 main functions:</para>
///     <list type="number">
///         <item>
///             <description>Provide all current terminal session information: <see cref="M:Oerlikon.Balzers.Rdp.Service.RdpSessionInfo.ListSessions(System.Boolean)"/></description>
///         </item>
///         <item>
///             <description>Observer terminal session changes: <see cref="E:Oerlikon.Balzers.Rdp.Service.RdpSessionInfo.SessionChanged"/></description>
///         </item>
///     </list>
/// </summary>
public class RdpSessionInfo : IDisposable {

    /************************************************************************************************/
    /*                                  DllImports                                                  */
    /************************************************************************************************/
    #region DllImports
    [DllImport("wtsapi32.dll", SetLastError = true)]
    static extern IntPtr WTSOpenServer([MarshalAs(UnmanagedType.LPStr)] String pServerName);

    [DllImport("wtsapi32.dll")]
    static extern void WTSCloseServer(IntPtr hServer);

    [DllImport("wtsapi32.dll")]
    static extern int WTSEnumerateSessions(
        IntPtr pServer,
        [MarshalAs(UnmanagedType.U4)] int iReserved,
        [MarshalAs(UnmanagedType.U4)] int iVersion,
        ref IntPtr pSessionInfo,
        [MarshalAs(UnmanagedType.U4)] ref int iCount);

    [DllImport("Wtsapi32.dll")]
    static extern bool WTSQuerySessionInformation(
        System.IntPtr pServer,
        int iSessionID,
        WTS_INFO_CLASS oInfoClass,
        out System.IntPtr pBuffer,
        out uint iBytesReturned);

    [DllImport("Wtsapi32.dll")]
    public static extern bool WTSWaitSystemEvent(
        IntPtr hServer,
        UInt32 EventMask,
        out IntPtr pEventFlags);

    [DllImport("wtsapi32.dll")]
    static extern void WTSFreeMemory(IntPtr pMemory);

    [DllImport("user32.dll")]
    public static extern int ExitWindowsEx(int uFlags, int dwReason);

    [DllImport("WtsApi32.dll")]
    private static extern bool WTSRegisterSessionNotification(IntPtr hWnd, [MarshalAs(UnmanagedType.U4)]int dwFlags);

    [DllImport("WtsApi32.dll")]
    private static extern bool WTSUnRegisterSessionNotification(IntPtr hWnd);

    public delegate int ServiceControlHandlerEx(int control, int eventType, IntPtr eventData, IntPtr context);

    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern IntPtr RegisterServiceCtrlHandlerEx(string lpServiceName, ServiceControlHandlerEx cbex, IntPtr context);

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern bool CloseHandle(IntPtr hObject);

    [DllImport("user32.dll")]
    static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
    #endregion

    #region Constants
    public const int SERVICE_CONTROL_STOP = 1;
    public const int SERVICE_CONTROL_DEVICEEVENT = 11;
    public const int SERVICE_CONTROL_SHUTDOWN = 5;
    public const int SERVICE_CONTROL_SESSIONCHANGE = 0x0000000E;       
    // WTSWaitSystemEvent local server handle
    public const int WTS_CURRENT_SERVER_HANDLE = 0;
    public const int WTS_CURRENT_SESSION     =  0;
    [Flags]
    public enum WaitSystemEventFlags {
        /* ===================================================================== 
         == EVENT - Event flags for WTSWaitSystemEvent
         ===================================================================== */

        None = 0x00000000, // return no event
        CreatedWinstation = 0x00000001, // new WinStation created
        DeletedWinstation = 0x00000002, // existing WinStation deleted
        RenamedWinstation = 0x00000004, // existing WinStation renamed
        ConnectedWinstation = 0x00000008, // WinStation connect to client
        DisconnectedWinstation = 0x00000010, // WinStation logged on without client           
        LogonUser = 0x00000020, // user logged on to existing WinStation
        LogoffUser = 0x00000040, // user logged off from existing WinStation
        WinstationStateChange = 0x00000080, // WinStation state change
        LicenseChange = 0x00000100, // license state change
        AllEvents = 0x7fffffff, // wait for all event types
        // Unfortunately cannot express this as an unsigned long...
        //FlushEvent = 0x80000000 // unblock all waiters
    }
    public const UInt32 FlushEvent = 0x80000000;
    #endregion

    /************************************************************************************************/
    /*                                  Private members                                             */
    /************************************************************************************************/
    #region Private members
    private String m_ServerName = Environment.MachineName;
    private bool m_unregistered = false;
    private ServiceControlHandlerEx myCallback;
    private bool tsObserverRunning = false;
    private Thread tsObserverThread;
    IntPtr hServ;        
    #endregion

    /************************************************************************************************/
    /*                                  Constructors                                                */
    /************************************************************************************************/
    #region Constructors
    /// <summary>
    /// Initializes a new instance of the <see cref="T:Oerlikon.Balzers.Rdp.Service.RdpSessionInfo">RdpSessionInfo</see> class. 
    /// </summary>
    /// <remarks></remarks>
    public RdpSessionInfo() : this(Environment.MachineName) { }

    /// <summary>
    /// Initializes a new instance of the <see cref="T:Oerlikon.Balzers.Rdp.Service.RdpSessionInfo"/> class.
    /// </summary>
    /// <param name="ServerName"></param>
    public RdpSessionInfo(String ServerName) : base() {
        this.m_ServerName = ServerName;
        this.hServ = WTSOpenServer(this.m_ServerName);
        tsObserverThread = new Thread(StartTerminalSessionObservation);
        tsObserverThread.Start(hServ);          
    }     

    ~RdpSessionInfo() {
    }
    #endregion Constructors

    /************************************************************************************************/
    /*                                  Methods                                                     */
    /************************************************************************************************/
    #region Public methods

    public void StartTerminalSessionObservation(object hServ) {                       
        string msg;
        IntPtr pEvents = IntPtr.Zero;
        IntPtr hServer = (IntPtr)hServ;
        List<TerminalSessionInfo> oldSessions, newSessions;
        TerminalSessionInfo tsi;
        WM_WTSSESSION_CHANGE_TYPE changeType;

        // initial read actual sessions
        oldSessions = ListSessions(false);
        newSessions = new List<TerminalSessionInfo>(oldSessions.ToArray());            
        tsObserverRunning = true;
        while(this.tsObserverRunning) {
            if(WTSWaitSystemEvent(hServer, (UInt32)WaitSystemEventFlags.AllEvents, out pEvents)) {

                WaitSystemEventFlags eventType = GetSystemEventType(pEvents);

                switch(eventType) {
                    case WaitSystemEventFlags.ConnectedWinstation:
                    case WaitSystemEventFlags.CreatedWinstation:
                    case WaitSystemEventFlags.LogonUser:                           
                        newSessions = ListSessions(false);
                        tsi = GetChangedTerminalSession(oldSessions, newSessions, out changeType);
                        oldSessions.Clear();
                        oldSessions.AddRange(newSessions.ToArray());
                        if(tsi != null && tsi.SessionInfo.iSessionID != 0)
                            OnSessionChanged(new TerminalSessionChangedEventArgs(changeType, tsi.SessionInfo.iSessionID, tsi));
                        break;
                    case WaitSystemEventFlags.DeletedWinstation:                      
                    case WaitSystemEventFlags.DisconnectedWinstation:
                    case WaitSystemEventFlags.LogoffUser:
                    case WaitSystemEventFlags.WinstationStateChange:                          
                        newSessions = ListSessions(false);
                        tsi = GetChangedTerminalSession(oldSessions, newSessions, out changeType);                           
                        oldSessions.Clear();
                        oldSessions.AddRange(newSessions.ToArray());
                        if(tsi != null && tsi.SessionInfo.iSessionID != 0)
                            OnSessionChanged(new TerminalSessionChangedEventArgs(changeType, tsi.SessionInfo.iSessionID, tsi));
                        break;                                                                                           
                    default:
                        break;
                }
            }
            else {
                uint winErrorCode = Win32Sec.GetLastError();
                msg = new System.ComponentModel.Win32Exception((int)winErrorCode).Message;
                WindowsEventLogHelper.WriteEventLog(msg, EventLogEntryType.Error);
                WindowsEventLogHelper.WriteEventLog(RdpControl.SVC_NAME + " " + System.Reflection.MethodInfo.GetCurrentMethod().Name + " - methode failed: " + msg, EventLogEntryType.Error);
            }
           Thread.Sleep(100);
        }
        WTSCloseServer(hServer);
    }

    public void StopTerminalSessionObservation(object hServ) {
        this.tsObserverRunning = false;
        IntPtr pEvents = IntPtr.Zero;            
        // unlock the waiter
        WTSWaitSystemEvent((IntPtr)hServ, FlushEvent, out pEvents);
        tsObserverThread.Join(200);
    }

    public static IntPtr OpenServer(String Name) {
        IntPtr server = WTSOpenServer(Name);
        return server;
    }
    public static void CloseServer(IntPtr ServerHandle) {
        WTSCloseServer(ServerHandle);
    }

    /// <summary>
    /// Read all session info running on the system.
    /// </summary>
    /// <param name="RdpOnly">If set to <see langword="true"/>, then only Rdp sessions
    /// will be listed; otherwise, all session types <see cref="T:Oerlikon.Balzers.Rdp.Interfaces.WTS_CLIENT_PROTOCOL_TYPE"/> .</param>
    public List<TerminalSessionInfo> ListSessions(bool RdpOnly) {
        IntPtr server = IntPtr.Zero;
        List<TerminalSessionInfo> ret = new List<TerminalSessionInfo>();
        //server = OpenServer(this.m_ServerName);

        try {
            IntPtr ppSessionInfo = IntPtr.Zero;
            Int32 count = 0;
            Int32 retval = WTSEnumerateSessions(this.hServ, 0, 1, ref ppSessionInfo, ref count);
            Int32 dataSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO));
            Int64 current = (int)ppSessionInfo;

            if(retval != 0) {
                for(int i = 0; i < count; i++) {
                    TerminalSessionInfo tsi = GetSessionInfo(this.hServ, (System.IntPtr)current);                      
                    current += dataSize;
                    if(tsi.ProtocolType == WTS_CLIENT_PROTOCOL_TYPE.RDP || !RdpOnly)
                        ret.Add(tsi);
                }

                WTSFreeMemory(ppSessionInfo);
            }
        }
        finally {
            //CloseServer(server);
        }
        return ret;
    }

    #endregion Public methods

    #region Private methods
    private TerminalSessionInfo GetChangedTerminalSession(List<TerminalSessionInfo> oldSessions, List<TerminalSessionInfo> newSessions, out WM_WTSSESSION_CHANGE_TYPE sessionChangeType) {
        TerminalSessionInfo retval = new TerminalSessionInfo(0);
        sessionChangeType = (WM_WTSSESSION_CHANGE_TYPE)0;

        // session added
        if(newSessions.Count > oldSessions.Count) {
            retval = newSessions.Where(s => oldSessions.Where(old => old.SessionInfo.iSessionID == s.SessionInfo.iSessionID).ToList().Count == 0).FirstOrDefault();
            if(retval.SessionInfo.oState == WTS_CONNECTSTATE_CLASS.WTSConnected
                || retval.SessionInfo.oState == WTS_CONNECTSTATE_CLASS.WTSActive
                || retval.SessionInfo.oState == WTS_CONNECTSTATE_CLASS.WTSConnectQuery)
                sessionChangeType = (retval.ProtocolType == WTS_CLIENT_PROTOCOL_TYPE.RDP) ? WM_WTSSESSION_CHANGE_TYPE.WTS_REMOTE_CONNECT : WM_WTSSESSION_CHANGE_TYPE.WTS_CONSOLE_CONNECT;
        }
        else if(newSessions.Count < oldSessions.Count) {
            retval = oldSessions.Where(s => newSessions.Where(old => old.SessionInfo.iSessionID == s.SessionInfo.iSessionID).ToList().Count == 0).FirstOrDefault();
            retval.SessionInfo.oState = WTS_CONNECTSTATE_CLASS.WTSDisconnected;
            retval.WtsInfo.State = WTS_CONNECTSTATE_CLASS.WTSDisconnected;  
            sessionChangeType = (retval.ProtocolType == WTS_CLIENT_PROTOCOL_TYPE.RDP) ? WM_WTSSESSION_CHANGE_TYPE.WTS_REMOTE_DISCONNECT : WM_WTSSESSION_CHANGE_TYPE.WTS_CONSOLE_DISCONNECT;
        }
        else {
            retval = newSessions.Where(s => oldSessions.Where(old => old.SessionInfo.iSessionID == s.SessionInfo.iSessionID && old.SessionInfo.oState != s.SessionInfo.oState).ToList().Count > 0 && s.SessionInfo.iSessionID != 0).FirstOrDefault();
            if(retval.SessionInfo.oState == WTS_CONNECTSTATE_CLASS.WTSConnected
               || retval.SessionInfo.oState == WTS_CONNECTSTATE_CLASS.WTSActive
               || retval.SessionInfo.oState == WTS_CONNECTSTATE_CLASS.WTSConnectQuery)
                sessionChangeType = (retval.ProtocolType == WTS_CLIENT_PROTOCOL_TYPE.RDP) ? WM_WTSSESSION_CHANGE_TYPE.WTS_REMOTE_CONNECT : WM_WTSSESSION_CHANGE_TYPE.WTS_CONSOLE_CONNECT;
            else if(retval.SessionInfo.oState == WTS_CONNECTSTATE_CLASS.WTSDisconnected
                || retval.SessionInfo.oState == WTS_CONNECTSTATE_CLASS.WTSDown
                || retval.SessionInfo.oState == WTS_CONNECTSTATE_CLASS.WTSIdle
                || retval.SessionInfo.oState == WTS_CONNECTSTATE_CLASS.WTSListen
                || retval.SessionInfo.oState == WTS_CONNECTSTATE_CLASS.WTSReset
                || retval.SessionInfo.oState == WTS_CONNECTSTATE_CLASS.WTSShadow)
                sessionChangeType = (retval.ProtocolType == WTS_CLIENT_PROTOCOL_TYPE.RDP) ? WM_WTSSESSION_CHANGE_TYPE.WTS_REMOTE_DISCONNECT : WM_WTSSESSION_CHANGE_TYPE.WTS_CONSOLE_DISCONNECT;
        }
        return retval;
    }

    private WaitSystemEventFlags GetSystemEventType(IntPtr pEvents) {
        if(((int)pEvents & (int)WaitSystemEventFlags.ConnectedWinstation) == (int)WaitSystemEventFlags.ConnectedWinstation)
            return WaitSystemEventFlags.ConnectedWinstation;
        else if(((int)pEvents & (int)WaitSystemEventFlags.CreatedWinstation) == (int)WaitSystemEventFlags.CreatedWinstation)
            return WaitSystemEventFlags.CreatedWinstation;         
        else if(((int)pEvents & (int)WaitSystemEventFlags.DisconnectedWinstation) == (int)WaitSystemEventFlags.DisconnectedWinstation)
            return WaitSystemEventFlags.DisconnectedWinstation;
        else if(((int)pEvents & (int)WaitSystemEventFlags.LicenseChange) == (int)WaitSystemEventFlags.LicenseChange)
            return WaitSystemEventFlags.LicenseChange;
        else if(((int)pEvents & (int)WaitSystemEventFlags.LogoffUser) == (int)WaitSystemEventFlags.LogoffUser)
            return WaitSystemEventFlags.LogoffUser;
        else if(((int)pEvents & (int)WaitSystemEventFlags.LogonUser) == (int)WaitSystemEventFlags.LogonUser)
            return WaitSystemEventFlags.LogonUser;
        else if(((int)pEvents & (int)WaitSystemEventFlags.RenamedWinstation) == (int)WaitSystemEventFlags.RenamedWinstation)
            return WaitSystemEventFlags.RenamedWinstation;
        else if(((int)pEvents & (int)WaitSystemEventFlags.WinstationStateChange) == (int)WaitSystemEventFlags.WinstationStateChange)
            return WaitSystemEventFlags.WinstationStateChange;
        else return WaitSystemEventFlags.None;


    }     

    /// <param name="pServer"></param>
    /// <param name="pSessionInfo"></param>
    private TerminalSessionInfo GetSessionInfo(IntPtr pServer, IntPtr pSessionInfo) {
        int iCurrent = (int)pSessionInfo;
        uint iReturned = 0;
        WTS_CLIENT_ADDRESS oClientAddres = new WTS_CLIENT_ADDRESS();
        WTS_CLIENT_DISPLAY oClientDisplay = new WTS_CLIENT_DISPLAY();
        WTS_CLIENT_PROTOCOL_TYPE oClientProtocol = WTS_CLIENT_PROTOCOL_TYPE.UNKNOWN;
        WTS_CLIENT_INFO oClientInfo = new WTS_CLIENT_INFO();
        WTSINFO oWtsInfo = new WTSINFO();
        string sIPAddress = string.Empty;
        string sUserName = string.Empty, sClientName = string.Empty;
        string sDomain = string.Empty;
        string sClientApplicationDirectory = string.Empty;
        TerminalSessionInfo retval = new TerminalSessionInfo(0);

        // Get session info structure
        WTS_SESSION_INFO oSessionInfo = (WTS_SESSION_INFO)Marshal.PtrToStructure((System.IntPtr)iCurrent, typeof(WTS_SESSION_INFO));

        //Get the IP address of the Terminal Services User
        IntPtr pAddress = IntPtr.Zero;
        if(WTSQuerySessionInformation(pServer, oSessionInfo.iSessionID, WTS_INFO_CLASS.WTSClientAddress, out pAddress, out iReturned) == true) {
            oClientAddres = (WTS_CLIENT_ADDRESS)Marshal.PtrToStructure(pAddress, oClientAddres.GetType());
            sIPAddress = oClientAddres.bAddress[2] + "." + oClientAddres.bAddress[3] + "." + oClientAddres.bAddress[4] + "." + oClientAddres.bAddress[5];
        }

        //Get the User Name of the Terminal Services User
        if(WTSQuerySessionInformation(pServer, oSessionInfo.iSessionID, WTS_INFO_CLASS.WTSUserName, out pAddress, out iReturned) == true) {
            sUserName = Marshal.PtrToStringAnsi(pAddress);
        }

        //Get the Client Name of the Terminal Services User
        if(WTSQuerySessionInformation(pServer, oSessionInfo.iSessionID, WTS_INFO_CLASS.WTSClientName, out pAddress, out iReturned) == true) {
            sClientName = Marshal.PtrToStringAnsi(pAddress);
        }

        //Get the Domain Name of the Terminal Services User
        if(WTSQuerySessionInformation(pServer, oSessionInfo.iSessionID, WTS_INFO_CLASS.WTSDomainName, out pAddress, out iReturned) == true) {
            sDomain = Marshal.PtrToStringAnsi(pAddress);
        }

        //Get the Display Information  of the Terminal Services User
        if(WTSQuerySessionInformation(pServer, oSessionInfo.iSessionID, WTS_INFO_CLASS.WTSClientDisplay, out pAddress, out iReturned) == true) {
            oClientDisplay = (WTS_CLIENT_DISPLAY)Marshal.PtrToStructure(pAddress, oClientDisplay.GetType());
        }

        //Get the Application Directory of the Terminal Services User
        if(WTSQuerySessionInformation(pServer, oSessionInfo.iSessionID, WTS_INFO_CLASS.WTSClientDirectory, out pAddress, out iReturned) == true) {
            sClientApplicationDirectory = Marshal.PtrToStringAnsi(pAddress);
        }

        //Get protocol type
        if(WTSQuerySessionInformation(pServer, oSessionInfo.iSessionID, WTS_INFO_CLASS.WTSClientProtocolType, out pAddress, out iReturned) == true) {
            oClientProtocol = (WTS_CLIENT_PROTOCOL_TYPE)Marshal.ReadInt16(pAddress);               
        }

        //Get client info
        if(WTSQuerySessionInformation(pServer, oSessionInfo.iSessionID, WTS_INFO_CLASS.WTSClientInfo, out pAddress, out iReturned) == true) {
            oClientInfo = (WTS_CLIENT_INFO)Marshal.PtrToStructure(pAddress, oClientInfo.GetType());
            //sUserName = String.IsNullOrEmpty(sUserName) ? oClientInfo.UserName : sUserName;             
        }

        //Get WTS info
        if(WTSQuerySessionInformation(pServer, oSessionInfo.iSessionID, WTS_INFO_CLASS.WTSSessionInfo, out pAddress, out iReturned) == true) {
            oWtsInfo = (WTSINFO)Marshal.PtrToStructure(pAddress, oWtsInfo.GetType());
        }

        // fill result
        retval.SessionInfo = oSessionInfo;
        //retval.SessionInfo.oState = oSessionInfo.oState;
        //retval.SessionInfo.sWinsWorkstationName = oSessionInfo.sWinsWorkstationName == null ? "" : oSessionInfo.sWinsWorkstationName;
        retval.UserName = sUserName == null ? "" : sUserName;
        retval.ClientMachineName = sClientName == null ? "" : sClientName;
        retval.ClientIPAddress = sIPAddress == null ? "" : sIPAddress;
        retval.Domain = sDomain == null ? "" : sDomain;
        retval.ProtocolType = oClientProtocol;
        retval.ClientInfo = oClientInfo;
        retval.WtsInfo = oWtsInfo;                   
        return retval;
    }

    #endregion Private methods

    #region Handlers   
    private event TerminalSessionChangedEventHandler mSessionChangedEventHandler;

    /// <summary>
    /// Occurs when a terminal session has changed.
    /// </summary>
    /// <remarks>
    /// Following change types will be observed: <see cref="T:Oerlikon.Balzers.Rdp.Interfaces.WM_WTSSESSION_CHANGE"/> and <see cref="F:Oerlikon.Balzers.Rdp.Interfaces.WM_WTSSESSION_CHANGE.WM_WTSSESSION_CHANGE"/>
    /// </remarks>
    /// <seealso href="http://pinvoke.net/default.aspx/wtsapi32/WTSRegisterSessionNotification.html">WTSRegisterSessionNotification</seealso>
    public event TerminalSessionChangedEventHandler SessionChanged {
        add {
            if(mSessionChangedEventHandler == null || !mSessionChangedEventHandler.GetInvocationList().Contains(value))
                mSessionChangedEventHandler += value;
        }
        remove {
            mSessionChangedEventHandler -= value;
        }
    }

    public void OnSessionChanged(TerminalSessionChangedEventArgs SessionChangedEventArg) {
        if(mSessionChangedEventHandler != null) {
            TerminalSessionChangedSaveInvoker.SafeInvokeEvent(mSessionChangedEventHandler, SessionChangedEventArg);
        }
    }

    #endregion Handlers


    #region IDisposable Members

    public void Dispose() {
        if(!m_unregistered) {
            StopTerminalSessionObservation(this.hServ);                
            m_unregistered = true;
        }
    }

    #endregion
}
}

有一些镇流器和未使用的废物在其中,但你可以挑选必需品。这也应该作为windows服务在桌面会话中工作。

票数 1
EN

Stack Overflow用户

发布于 2016-08-12 17:11:32

好的,WTSRegisterSessionNotification -解决方案只与您手中的控件或窗体一起工作,但是在windows服务环境中运行的控制台应用程序或类如何,并且没有ServiceBase对象,因为它是基于插件的体系结构。

以下是一些结构定义:

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Linq;
using System.Windows.Forms;
using System.Reflection;

namespace Rdp.Interfaces {

    /************************************************************************************************/
    /*                                  struct  members                                             */
    /************************************************************************************************/
    /// <summary>
    /// Terminal Session Info data holder struct.
    /// </summary>
    /// <remarks>
    /// Structures, interfaces, p-invoke members for Terminal Service Session
    /// </remarks>
    [Serializable]
    public struct TerminalSessionInfo {
        /// <summary>
        ///  Remote Desktop Services API Structure member
        /// </summary>
        /// <seealso cref="T:Oerlikon.Balzers.Rdp.Interfaces.WTS_SESSION_INFO"/>
        public WTS_SESSION_INFO SessionInfo;
        /// <summary>
        ///  Remote Desktop Services API Structure member
        /// </summary>
        /// <seealso cref="T:Oerlikon.Balzers.Rdp.Interfaces.WTS_CLIENT_PROTOCOL_TYPE"/>
        public WTS_CLIENT_PROTOCOL_TYPE ProtocolType;
        /// <summary>
        ///  Remote Desktop Services API Structure member
        /// </summary>
        /// <seealso cref="T:Oerlikon.Balzers.Rdp.Interfaces.WTS_CLIENT_INFO"/>
        public WTS_CLIENT_INFO ClientInfo;
        /// <summary>
        ///  Remote Desktop Services API Structure member
        /// </summary>
        /// <seealso cref="T:Oerlikon.Balzers.Rdp.Interfaces.WTSINFO"/>
        public WTSINFO WtsInfo;
        /// <summary>
        ///  The client user name.
        /// </summary>
        public string UserName;
        /// <summary>
        ///  The domain name of the client computer.
        /// </summary>
        public string Domain;
        /// <summary>
        /// The client network address.
        /// </summary>
        public string ClientIPAddress;
        /// <summary>
        /// The machine name of the client computer.
        /// </summary>
        public string ClientMachineName;

        /// <summary>
        /// Initializes a new instance of the <see cref="T:Oerlikon.Balzers.Rdp.Interfaces.TerminalSessionInfo"/> structure.
        /// </summary>
        /// <param name="SessionId">Only used to force an initialization of members.</param>
        public TerminalSessionInfo(int SessionId) {
            this.SessionInfo = new WTS_SESSION_INFO();
            this.SessionInfo.iSessionID = SessionId;
            this.SessionInfo.sWinsWorkstationName = String.Empty;
            this.UserName = String.Empty;
            this.Domain = String.Empty;
            this.ClientIPAddress = String.Empty;
            this.ProtocolType = WTS_CLIENT_PROTOCOL_TYPE.UNKNOWN;
            this.ClientMachineName = String.Empty;
            this.ClientInfo = new WTS_CLIENT_INFO();
            this.ClientInfo.ClientMachineName = String.Empty;
            this.ClientInfo.Domain = String.Empty;
            this.ClientInfo.UserName = String.Empty;
            this.ClientInfo.WorkDirectory = String.Empty;
            this.ClientInfo.InitialProgram = String.Empty;
            this.ClientInfo.ClientDirectory = String.Empty;
            this.ClientInfo.DeviceId = String.Empty;
            this.WtsInfo = new WTSINFO();
            this.WtsInfo.Domain = String.Empty;
            this.WtsInfo.UserName = String.Empty;
            this.WtsInfo.WinStationName = String.Empty;
        }

        /// <summary>
        /// Returns the fully qualified type name of this instance.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.String"/> containing a fully qualified type name.
        /// </returns>
        /// <filterpriority>2</filterpriority>
        public override string ToString() {
            string retval = "SessionID: " + this.SessionInfo.iSessionID.ToString();
            retval += String.IsNullOrEmpty(this.Domain) ? "" : Environment.NewLine + "Domain: " + this.Domain;
            retval += String.IsNullOrEmpty(this.UserName) ? "" : Environment.NewLine + "UserName: " + this.UserName;
            retval += String.IsNullOrEmpty(this.ClientMachineName) ? "" : Environment.NewLine + "ClientMachineName: " + this.ClientMachineName;
            retval += String.IsNullOrEmpty(this.ClientIPAddress) ? "" : Environment.NewLine + "ClientIPAddress: " + this.ClientIPAddress;
            retval += String.IsNullOrEmpty(this.SessionInfo.sWinsWorkstationName) ? "" : Environment.NewLine + "WinsWorkstationName: " + this.SessionInfo.sWinsWorkstationName;
            retval += this.ProtocolType == WTS_CLIENT_PROTOCOL_TYPE.UNKNOWN ? "" : Environment.NewLine + "ProtocolType: " + this.ProtocolType.ToString();
            retval += String.IsNullOrEmpty(this.SessionInfo.oState.ToString()) ? "" : Environment.NewLine + "State: " + this.SessionInfo.oState.ToString();
            retval += String.IsNullOrEmpty(this.ClientInfo.ClientMachineName) ? "" : Environment.NewLine + "ClientInfoMachineName: " + this.ClientInfo.ClientMachineName;
            retval += String.IsNullOrEmpty(this.ClientInfo.Domain) ? "" : Environment.NewLine + "ClientInfoDomain: " + this.ClientInfo.Domain;
            retval += String.IsNullOrEmpty(this.ClientInfo.UserName) ? "" : Environment.NewLine + "ClientInfoUserName: " + this.ClientInfo.UserName;
            retval += String.IsNullOrEmpty(this.ClientInfo.WorkDirectory) ? "" : Environment.NewLine + "ClientInfoWorkDirectory: " + this.ClientInfo.WorkDirectory;
            retval += String.IsNullOrEmpty(this.ClientInfo.ClientDirectory) ? "" : Environment.NewLine + "ClientInfoDirectory: " + this.ClientInfo.ClientDirectory;
            retval += String.IsNullOrEmpty(this.ClientInfo.DeviceId) ? "" : Environment.NewLine + "ClientInfoDeviceId: " + this.ClientInfo.DeviceId;
            retval += this.ClientInfo.ClientBuildNumber == 0 ? "" : Environment.NewLine + "ClientInfoBuildNumber: " + this.ClientInfo.ClientBuildNumber.ToString();
            retval += this.ClientInfo.ClientHardwareId == 0 ? "" : Environment.NewLine + "ClientInfoHardwareId: " + this.ClientInfo.ClientHardwareId.ToString();
            retval += this.ClientInfo.ClientProductId == 0 ? "" : Environment.NewLine + "ClientInfoProductId: " + this.ClientInfo.ClientProductId.ToString();
            retval += String.IsNullOrEmpty(this.WtsInfo.Domain) ? "" : Environment.NewLine + "WtsInfoDomain: " + this.WtsInfo.Domain;
            retval += String.IsNullOrEmpty(this.WtsInfo.UserName) ? "" : Environment.NewLine + "WtsInfoUserName: " + this.WtsInfo.UserName;
            retval += String.IsNullOrEmpty(this.WtsInfo.WinStationName) ? "" : Environment.NewLine + "WtsInfoWinStationName: " + this.WtsInfo.WinStationName;
            retval += this.WtsInfo.ConnectTime == 0 ? "" : Environment.NewLine + "WtsInfoConnectTime: " + ToCSharpTime(this.WtsInfo.ConnectTime, true).ToString();
            retval += this.WtsInfo.CurrentTime == 0 ? "" : Environment.NewLine + "WtsInfoCurrentTime: " + ToCSharpTime(this.WtsInfo.CurrentTime, true).ToString();
            retval += this.WtsInfo.DisconnectTime == 0 ? "" : Environment.NewLine + "WtsInfoDisconnectTime: " + ToCSharpTime(this.WtsInfo.DisconnectTime, true).ToString();
            retval += this.WtsInfo.LogonTime == 0 ? "" : Environment.NewLine + "WtsInfoLogonTime: " + ToCSharpTime(this.WtsInfo.LogonTime, true).ToString();
            retval += this.WtsInfo.LastInputTime == 0 ? "" : Environment.NewLine + "WtsInfoLogonTime: " + ToCSharpTime(this.WtsInfo.LastInputTime, true).ToString();
            retval += this.WtsInfo.IncomingBytes == 0 ? "" : Environment.NewLine + "WtsInfoIncomingBytes: " + this.WtsInfo.IncomingBytes.ToString();
            retval += this.WtsInfo.OutgoingBytes == 0 ? "" : Environment.NewLine + "WtsInfoOutgoingBytes: " + this.WtsInfo.OutgoingBytes.ToString();
            return retval;
        }

        /// <summary>
        /// Help method to find C++ corresponding long value of C# DateTime (starting at 01
        /// / 01 / 1970 00:00:00).
        /// </summary>
        /// <param name="date">.NET object</param>
        /// <param name="localTime">If set to <see langword="true"/>, then date will be
        /// assummed as local time and converted to UTC - time; otherwise, UTC will be
        /// assumed.</param>
        /// <returns>
        /// C++ corresponding long value
        /// </returns>
        public static long ToUnixtime(DateTime date, bool localTime) {
            DateTime unixStartTime = new DateTime(1970, 1, 1, 0, 0, 0, 0);
            //DateTime unixStartTime = DateTime.MinValue;
            if(localTime) date = date.ToUniversalTime();
            TimeSpan timeSpan = date - unixStartTime;
            return Convert.ToInt64(timeSpan.TotalMilliseconds);
        }

        /// <summary>
        ///  Help method to find C# DateTime from C++ corresponding long value.
        /// </summary>
        /// <param name="unixTime">Unix value of date time starting at 01 / 01 / 1970
        /// 00:00:00</param>
        /// <param name="localTime">If set to <see langword="true"/>, then ; otherwise,
        /// .</param>
        public static DateTime ToCSharpTime(long unixTime, bool localTime) {
            DateTime unixStartTime = new DateTime(1970, 1, 1, 0, 0, 0, 0);
            //DateTime unixStartTime = DateTime.MinValue;           
            if(localTime) return unixStartTime.AddTicks(unixTime).ToLocalTime();
            return unixStartTime.AddTicks(unixTime);
        }

        #region IComparable Members

        /// <summary>
        /// Overriding Operator ==
        /// </summary>
        /// <param name="a">Object to compare</param>
        /// <param name="b">Object to compare</param>
        /// <returns>Return true if the segment start / end values match.</returns>
        public static bool operator ==(TerminalSessionInfo a, TerminalSessionInfo b) {
            return Equals(a, b);
        }

        /// <summary>
        /// Overriding Operator !=
        /// </summary>
        /// <param name="a">Object to compare</param>
        /// <param name="b">Object to compare</param>
        /// <returns>Return true if the segment start / end values match.</returns>
        public static bool operator !=(TerminalSessionInfo a, TerminalSessionInfo b) {
            return !Equals(a, b);
        }

        /// <summary>
        /// Overriding Equals
        /// </summary>
        /// <param name="obj">Object to compare with own instance.</param>
        /// <returns>Return true if the segment start / end values match.</returns>
        public override bool Equals(object obj) {
            // If parameter is null return false.
            if(obj == null) {
                return false;
            }
            // If parameter cannot be cast to Point return false.
            TerminalSessionInfo p = (TerminalSessionInfo)obj;
            if((System.Object)p == null) {
                return false;
            }

            // Return true if the segment start / end values match: 
            return Equals(this, p);
        }


        /// <summary>
        /// Memberwise comparison
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        public static bool Equals(TerminalSessionInfo a, TerminalSessionInfo b) {
            bool retval = false;
            if(((System.Object)a == null) && (System.Object)b == null) {
                return false;
            }
            if(((System.Object)a == null) ^ (System.Object)b == null) {
                return false;
            }

            // check property members         
            string[] properties = new string[] { 
                "UserName", 
                "Domain",
                "ClientIPAddress",
                "ClientMachineName",
                "SessionInfo.iSessionID",
                "SessionInfo.sWinsWorkstationName",
                "SessionInfo.oState",
                "ProtocolType",
                "ClientInfo.ClientMachineName",
                "ClientInfo.Domain",
                "ClientInfo.UserName",
                "ClientInfo.WorkDirectory",
                "ClientInfo.InitialProgram",
                "ClientInfo.EncryptionLevel",
                "ClientInfo.ClientAddressFamily",
                "ClientInfo.ClientAddress",
                "ClientInfo.HRes",
                "ClientInfo.VRes",
                "ClientInfo.ColorDepth",
                "ClientInfo.ClientDirectory",
                "ClientInfo.ClientBuildNumber",
                "ClientInfo.ClientHardwareId",
                "ClientInfo.ClientProductId",
                "ClientInfo.DeviceId",
                "WtsInfo.State",
                "WtsInfo.SessionId",
                "WtsInfo.WinStationName",
                "WtsInfo.Domain",
                "WtsInfo.UserName",
                "WtsInfo.ConnectTime",
                "WtsInfo.DisconnectTime",
                "WtsInfo.LogonTime" };

            retval = true;
            object vala, valb;
            foreach(string prop in properties) {
                try {
                    vala = GetFieldItem(a, prop);
                    valb = GetFieldItem(b, prop);
                    if(((System.Object)vala == null) && (System.Object)valb == null)
                        continue;                  
                    if(((System.Object)vala == null) ^ (System.Object)valb == null) 
                        return false;

                    if(!Object.Equals(vala, valb))
                        return false;
                }
                catch(Exception ex) {
                    retval = false;
                }

            }
            return retval;
        }

        /* Ein Property TopDown suchen. Wir graben uns durch die Hierarchiestufen einer Klasse nach unten,
        // Bis wir das erste mal auf das Property "name" stossen. Dieses wird dann zurückgemolden
        // Bei überladenen Properties wird dann erst das überladene gefunden.
        // Über den normalen Type.GetProperty(name) würde sonst ein ambigous error erzeugt.*/
        /// <summary>
        /// Gets property with path <see paramref="name"/> from <see paramref="obj"/>.
        /// Using System.Type.GetProperty(name) throws an exception if a property is overloaded. This method
        /// does not throw an ambigous exception instead it returns the overloaded property value.
        /// </summary>
        /// <param name="obj">Object with properties.</param>
        /// <param name="name">Path to property (e.g.: TimeOfDay.Hours or Ticks)</param>
        /// <returns></returns>
        static public System.Reflection.PropertyInfo GetPropertyTopDown(System.Object obj, System.String name) {
            System.Type trs = obj.GetType();
            for(trs = obj.GetType(); trs != null; trs = trs.BaseType) {
                // Nur Properties, die in dieser Hierarchiestufe der Klasse deklariert wurden
                System.Reflection.PropertyInfo[] pis = trs.GetProperties(
                    System.Reflection.BindingFlags.Public
                    | System.Reflection.BindingFlags.Instance
                    | System.Reflection.BindingFlags.DeclaredOnly
                    | System.Reflection.BindingFlags.NonPublic
                    | System.Reflection.BindingFlags.Static);

                foreach(System.Reflection.PropertyInfo pi in pis) {
                    System.Diagnostics.Debug.Assert(trs == pi.DeclaringType);
                    if(pi.Name == name) {
                        //System.Diagnostics.Debug.WriteLine(pi.DeclaringType + " -> " + pi.Name);
                        return pi;
                    }
                }
            }
            return null;
        }

        /* Ein Property TopDown suchen. Wir graben uns durch die Hierarchiestufen einer Klasse nach unten,
      // Bis wir das erste mal auf das Property "name" stossen. Dieses wird dann zurückgemolden
      // Bei überladenen Properties wird dann erst das überladene gefunden.
      // Über den normalen Type.GetProperty(name) würde sonst ein ambigous error erzeugt.*/
        /// <summary>
        /// Gets property with path <see cref=""/> from <see cref=""/>. Using
        /// System.Type.GetField(name) throws an exception if a property is overloaded. This
        /// method does not throw an ambigous exception instead it returns the overloaded
        /// property value.
        /// </summary>
        /// <param name="obj">Object with properties.</param>
        /// <param name="name">Path to property (e.g.: TimeOfDay.Hours or Ticks)</param>
        static public System.Reflection.FieldInfo GetFieldTopDown(System.Object obj, System.String name) {
            System.Type trs = obj.GetType();
            for(trs = obj.GetType(); trs != null; trs = trs.BaseType) {
                // Nur Properties, die in dieser Hierarchiestufe der Klasse deklariert wurden
                System.Reflection.FieldInfo[] pis = trs.GetFields(
                    System.Reflection.BindingFlags.Public
                    | System.Reflection.BindingFlags.Instance
                    | System.Reflection.BindingFlags.DeclaredOnly
                    | System.Reflection.BindingFlags.NonPublic
                    | System.Reflection.BindingFlags.Static);

                foreach(System.Reflection.FieldInfo fi in pis) {
                    System.Diagnostics.Debug.Assert(trs == fi.DeclaringType);
                    if(fi.Name == name) {
                        //System.Diagnostics.Debug.WriteLine(pi.DeclaringType + " -> " + pi.Name);
                        return fi;
                    }
                }
            }
            return null;
        }

        /// <summary>
        /// Gets value of property with path <paramref name="name"/>.
        /// </summary>
        /// <param name="obj">Object with properties.</param>
        /// <param name="name">Property path.</param>
        /// <example>
        ///     <code><![CDATA[
        /// System.DateTime date = new System.DateTime();
        /// int hours = (int)Balzers.Misc.ReflectionHelper.GetItem(date, "TimeOfDay.Hours");
        /// long ticks = (long)Balzers.Misc.ReflectionHelper.GetItem(date, "Ticks");
        /// ]]></code>
        /// </example>
        static public System.Object GetFieldItem(System.Object obj, System.String name) {
            System.Reflection.FieldInfo fi = null;
            System.String[] s = name.Split(new char[] { '.' }, 2);
            while(s.Length > 1) {
                //pi = Balzers.Misc.ReflectionHelper.GetPropertyTopDown(obj, name);
                //System.Diagnostics.Debug.Assert(pi != null, "GetItem(obj, " + name + ")");
                fi = GetFieldTopDown(obj, s[0]);
                System.Diagnostics.Debug.Assert(fi != null, "GetFieldItem(obj, " + name + ")");
                obj = fi.GetValue(obj);
                //obj = obj.GetType().GetProperty(s[0]).GetValue(obj, null);
                s = s[1].Split(new char[] { '.' }, 2);
            }

            //pi = Balzers.Misc.ReflectionHelper.GetPropertyTopDown(obj, name);
            //System.Diagnostics.Debug.Assert(pi != null, "GetItem(obj, " + name + ")");
            fi = GetFieldTopDown(obj, s[0]);
            System.Diagnostics.Debug.Assert(fi != null, "GetFieldItem(obj, " + s[0] + ")");
            System.Object value = fi.GetValue(obj);
            return value;
            //return obj.GetType().GetProperty(s[0]).GetValue(obj, null);
        }

        #endregion
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5353066

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档