请帮助我检查为什么代码(由FWN在此topic编写)以使用远程桌面服务API检索终端服务上的用户登录时间无法正常工作 - 每次 wtsinfo.LogonTime 返回不同的 Int64 值。 以下是修订后的代码:
RDPInfo.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
namespace RDP
{
public enum WTS_INFO_CLASS
{
WTSInitialProgram,
WTSApplicationName,
WTSWorkingDirectory,
WTSOEMId,
WTSSessionId,
WTSUserName,
WTSWinStationName,
WTSDomainName,
WTSConnectState,
WTSClientBuildNumber,
WTSClientName,
WTSClientDirectory,
WTSClientProductId,
WTSClientHardwareId,
WTSClientAddress,
WTSClientDisplay,
WTSSessionInfo,
WTSClientProtocolType,
}
public enum WTS_CONNECTSTATE_CLASS
{
WTSActive,
WTSConnected,
WTSConnectQuery,
WTSShadow,
WTSDisconnected,
WTSIdle,
WTSListen,
WTSReset,
WTSDown,
WTSInit,
}
public class RDPInfo
{
[DllImport("wtsapi32.dll")]
static extern IntPtr WTSOpenServer([MarshalAs(UnmanagedType.LPStr)] String pServerName);
[DllImport("wtsapi32.dll")]
static extern void WTSCloseServer(IntPtr hServer);
[DllImport("wtsapi32.dll")]
static extern Int32 WTSEnumerateSessions(
IntPtr hServer,
[MarshalAs(UnmanagedType.U4)] Int32 Reserved,
[MarshalAs(UnmanagedType.U4)] Int32 Version,
ref IntPtr ppSessionInfo,
[MarshalAs(UnmanagedType.U4)] ref Int32 pCount);
[DllImport("wtsapi32.dll")]
static extern void WTSFreeMemory(IntPtr pMemory);
[DllImport("Wtsapi32.dll")]
static extern bool WTSQuerySessionInformation(System.IntPtr hServer, int sessionId, WTS_INFO_CLASS wtsInfoClass, out System.IntPtr ppBuffer, out uint pBytesReturned);
[StructLayout(LayoutKind.Sequential)]
private struct WTS_SESSION_INFO
{
public Int32 SessionID;
[MarshalAs(UnmanagedType.LPStr)]
public String pWinStationName;
public WTS_CONNECTSTATE_CLASS State;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct WTSINFO
{
[MarshalAs(UnmanagedType.I8)]
public Int64 LogonTime;
}
public static IntPtr OpenServer(String Name)
{
IntPtr server = WTSOpenServer(Name);
return server;
}
public static void CloseServer(IntPtr ServerHandle)
{
WTSCloseServer(ServerHandle);
}
public static List<RDPSession> ListUsers(String ServerName)
{
List<RDPSession> List = new List<RDPSession>();
WTSINFO wtsinfo = new WTSINFO();
IntPtr serverHandle = IntPtr.Zero;
List<String> resultList = new List<string>();
serverHandle = OpenServer(ServerName);
IntPtr SessionInfoPtr = IntPtr.Zero;
IntPtr userPtr = IntPtr.Zero;
IntPtr domainPtr = IntPtr.Zero;
IntPtr clientNamePtr = IntPtr.Zero;
IntPtr wtsinfoPtr = IntPtr.Zero;
IntPtr clientDisplayPtr = IntPtr.Zero;
try
{
Int32 sessionCount = 0;
Int32 retVal = WTSEnumerateSessions(serverHandle, 0, 1, ref SessionInfoPtr, ref sessionCount);
Int32 dataSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO));
Int32 currentSession = (int)SessionInfoPtr;
uint bytes = 0;
if (retVal != 0)
{
for (int i = 0; i < sessionCount; i++)
{
WTS_SESSION_INFO si = (WTS_SESSION_INFO)Marshal.PtrToStructure((System.IntPtr)currentSession, typeof(WTS_SESSION_INFO));
currentSession += dataSize;
WTSQuerySessionInformation(serverHandle, si.SessionID, WTS_INFO_CLASS.WTSUserName, out userPtr, out bytes);
WTSQuerySessionInformation(serverHandle, si.SessionID, WTS_INFO_CLASS.WTSDomainName, out domainPtr, out bytes);
WTSQuerySessionInformation(serverHandle, si.SessionID, WTS_INFO_CLASS.WTSClientName, out clientNamePtr, out bytes);
WTSQuerySessionInformation(serverHandle, si.SessionID, WTS_INFO_CLASS.WTSSessionInfo, out wtsinfoPtr, out bytes);
RDPSession temp = new RDPSession();
temp.Client = Marshal.PtrToStringAnsi(clientNamePtr);
temp.Server = ServerName;
temp.UserName = Marshal.PtrToStringAnsi(userPtr);
temp.Domain = Marshal.PtrToStringAnsi(domainPtr);
temp.ConnectionState = si.State;
temp.SessionId = si.SessionID;
//WTSINFO dt = (WTSINFO)Marshal.PtrToStructure((System.IntPtr)currentSession, typeof(WTSINFO));
//DateTime date = new DateTime(dt.LogonTime);
//temp.sessionInfo = date;
wtsinfo = (WTSINFO)Marshal.PtrToStructure(wtsinfoPtr, typeof(WTSINFO));
temp.sessionInfo = wtsinfo.LogonTime;
List.Add(temp);
WTSFreeMemory(clientNamePtr);
WTSFreeMemory(userPtr);
WTSFreeMemory(domainPtr);
WTSFreeMemory(wtsinfoPtr);
}
WTSFreeMemory(SessionInfoPtr);
}
}
catch (Exception ex)
{
Console.WriteLine("Exception: " + ex.Message);
}
finally
{
Marshal.Release(SessionInfoPtr);
Marshal.Release(userPtr);
Marshal.Release(domainPtr);
Marshal.Release(clientNamePtr);
//Marshal.Release(wtsinfoPtr);
CloseServer(serverHandle);
}
return List;
}
}
public class RDPSession
{
public string UserName;
public string Domain;
public int SessionId;
public string Client;
public string Server;
public WTS_CONNECTSTATE_CLASS ConnectionState;
//public RDP.RDPInfo.WTSINFO sessionInfo;
public Int64 sessionInfo;
}
}
Program.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RDP
{
class Program
{
static void Main(string[] args)
{
List<RDPSession> ServerList = new List<RDPSession>();
ServerList = RDPInfo.ListUsers("SERVERNAME");
foreach (RDPSession item in ServerList)
{
Console.WriteLine("{0,-15} {1,-15} {2,-35} {3,-40}", item.UserName, item.ConnectionState, item.Client, item.sessionInfo);
}
}
P.S。我认为我需要在此article
中从WTSINFO获取LogonTimeP.S.S。我已从WTSINFO structure添加了WTS_CLIENT_DISPLAY structure 和WTS_INFO_CLASS enumeration。 WTS_CLIENT_DISPLAY得到正确答案。但WTSINFO每次返回不同的 Int64 值。你能帮帮我吗?如何将其转换为 DateTime ?感谢。
答案 0 :(得分:1)
Chris Lewis [MSFT]在此thread中回答。 这是代码:
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
namespace WTSInfoExample
{
public enum WTS_INFO_CLASS:int
{
WTSInitialProgram = 0,
WTSApplicationName = 1,
WTSWorkingDirectory = 2,
WTSOEMId = 3,
WTSSessionId = 4,
WTSUserName = 5,
WTSWinStationName = 6,
WTSDomainName = 7,
WTSConnectState = 8,
WTSClientBuildNumber = 9,
WTSClientName = 10,
WTSClientDirectory = 11,
WTSClientProductId = 12,
WTSClientHardwareId = 13,
WTSClientAddress = 14,
WTSClientDisplay = 15,
WTSClientProtocolType = 16,
WTSIdleTime = 17,
WTSLogonTime = 18,
WTSIncomingBytes = 19,
WTSOutgoingBytes = 20,
WTSIncomingFrames = 21,
WTSOutgoingFrames = 22,
WTSClientInfo = 23,
WTSSessionInfo = 24,
WTSSessionInfoEx = 25,
WTSConfigInfo = 26,
WTSValidationInfo = 27,
WTSSessionAddressV4 = 28,
WTSIsRemoteSession = 29
}
public enum WTS_CONNECTSTATE_CLASS:int
{
WTSActive,
WTSConnected,
WTSConnectQuery,
WTSShadow,
WTSDisconnected,
WTSIdle,
WTSListen,
WTSReset,
WTSDown,
WTSInit,
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct WTSINFOA
{
public const int WINSTATIONNAME_LENGTH = 32;
public const int DOMAIN_LENGTH = 17;
public const int USERNAME_LENGTH = 20;
public WTS_CONNECTSTATE_CLASS State;
public int SessionId;
public int IncomingBytes;
public int OutgoingBytes;
public int IncomingFrames;
public int OutgoingFrames;
public int IncomingCompressedBytes;
public int OutgoingCompressedBytes;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = WINSTATIONNAME_LENGTH)]
public byte[] WinStationNameRaw;
public string WinStationName
{
get
{
return Encoding.ASCII.GetString(WinStationNameRaw);
}
}
[MarshalAs(UnmanagedType.ByValArray, SizeConst = DOMAIN_LENGTH)]
public byte[] DomainRaw;
public string Domain
{
get
{
return Encoding.ASCII.GetString(DomainRaw);
}
}
[MarshalAs(UnmanagedType.ByValArray, SizeConst = USERNAME_LENGTH + 1)]
public byte[] UserNameRaw;
public string UserName
{
get
{
return Encoding.ASCII.GetString(UserNameRaw);
}
}
public long ConnectTimeUTC;
public DateTime ConnectTime
{
get
{
return DateTime.FromFileTimeUtc(ConnectTimeUTC);
}
}
public long DisconnectTimeUTC;
public DateTime DisconnectTime
{
get
{
return DateTime.FromFileTimeUtc(DisconnectTimeUTC);
}
}
public long LastInputTimeUTC;
public DateTime LastInputTime
{
get
{
return DateTime.FromFileTimeUtc(LastInputTimeUTC);
}
}
public long LogonTimeUTC;
public DateTime LogonTime
{
get
{
return DateTime.FromFileTimeUtc(LogonTimeUTC);
}
}
public long CurrentTimeUTC;
public DateTime CurrentTime
{
get
{
return DateTime.FromFileTimeUtc(CurrentTimeUTC);
}
}
}
public class RDPInfo
{
[DllImport("wtsapi32.dll")]
static extern IntPtr WTSOpenServer([MarshalAs(UnmanagedType.LPStr)] String pServerName);
[DllImport("wtsapi32.dll")]
static extern void WTSCloseServer(IntPtr hServer);
[DllImport("wtsapi32.dll")]
static extern Int32 WTSEnumerateSessions(
IntPtr hServer,
[MarshalAs(UnmanagedType.U4)] Int32 Reserved,
[MarshalAs(UnmanagedType.U4)] Int32 Version,
ref IntPtr ppSessionInfo,
[MarshalAs(UnmanagedType.U4)] ref Int32 pCount);
[DllImport("wtsapi32.dll")]
static extern void WTSFreeMemory(IntPtr pMemory);
[DllImport("Wtsapi32.dll")]
static extern bool WTSQuerySessionInformation(System.IntPtr hServer, int sessionId, WTS_INFO_CLASS wtsInfoClass, out System.IntPtr ppBuffer, out uint pBytesReturned);
[StructLayout(LayoutKind.Sequential)]
private struct WTS_SESSION_INFO
{
public Int32 SessionID;
[MarshalAs(UnmanagedType.LPStr)]
public String pWinStationName;
public WTS_CONNECTSTATE_CLASS State;
}
public static IntPtr OpenServer(String Name)
{
IntPtr server = WTSOpenServer(Name);
return server;
}
public static void CloseServer(IntPtr ServerHandle)
{
WTSCloseServer(ServerHandle);
}
public static List<RDPSession> ListUsers(String ServerName)
{
List<RDPSession> List = new List<RDPSession>();
IntPtr serverHandle = IntPtr.Zero;
List<String> resultList = new List<string>();
serverHandle = OpenServer(ServerName);
IntPtr SessionInfoPtr = IntPtr.Zero;
IntPtr clientNamePtr = IntPtr.Zero;
IntPtr wtsinfoPtr = IntPtr.Zero;
IntPtr clientDisplayPtr = IntPtr.Zero;
try
{
Int32 sessionCount = 0;
Int32 retVal = WTSEnumerateSessions(serverHandle, 0, 1, ref SessionInfoPtr, ref sessionCount);
Int32 dataSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO));
Int32 currentSession = (int)SessionInfoPtr;
uint bytes = 0;
if (retVal != 0)
{
for (int i = 0; i < sessionCount; i++)
{
WTS_SESSION_INFO si = (WTS_SESSION_INFO)Marshal.PtrToStructure((System.IntPtr)currentSession, typeof(WTS_SESSION_INFO));
currentSession += dataSize;
WTSQuerySessionInformation(serverHandle, si.SessionID, WTS_INFO_CLASS.WTSClientName, out clientNamePtr, out bytes);
WTSQuerySessionInformation(serverHandle, si.SessionID, WTS_INFO_CLASS.WTSSessionInfo, out wtsinfoPtr, out bytes);
var wtsinfo = (WTSINFOA)Marshal.PtrToStructure(wtsinfoPtr, typeof(WTSINFOA));
RDPSession temp = new RDPSession();
temp.Client = Marshal.PtrToStringAnsi(clientNamePtr);
temp.Server = ServerName;
temp.UserName = wtsinfo.UserName;
temp.Domain = wtsinfo.Domain;
temp.ConnectionState = si.State;
temp.SessionId = si.SessionID;
temp.sessionInfo = wtsinfo;
List.Add(temp);
WTSFreeMemory(clientNamePtr);
WTSFreeMemory(wtsinfoPtr);
}
WTSFreeMemory(SessionInfoPtr);
}
}
catch (Exception ex)
{
Console.WriteLine("Exception: " + ex.Message);
}
finally
{
CloseServer(serverHandle);
}
return List;
}
}
public class RDPSession
{
public string UserName;
public string Domain;
public int SessionId;
public string Client;
public string Server;
public WTS_CONNECTSTATE_CLASS ConnectionState;
public WTSINFOA sessionInfo;
}
class Program
{
static void Main(string[] args)
{
List<RDPSession> ServerList = new List<RDPSession>();
ServerList = RDPInfo.ListUsers("SERVERNAME");
foreach (RDPSession item in ServerList)
{
Console.WriteLine("{0,-15} {1,-15} {2,-35} {3,-40}", item.UserName, item.ConnectionState, item.Client, item.sessionInfo.LogonTime);
}
}
}
}