这里是场景:如何在.NET中检索登录/连接用户列表?
你有一个Windows服务器,用户通过RDP远程连接到。您希望您的程序(作为服务运行)知道当前连接的人员。这可能包括也可能不包括交互式控制台会话。
请注意,这是而不是就像检索当前的交互式用户一样。
我猜测有终端服务的某种API访问来获取此信息?
这里是场景:如何在.NET中检索登录/连接用户列表?
你有一个Windows服务器,用户通过RDP远程连接到。您希望您的程序(作为服务运行)知道当前连接的人员。这可能包括也可能不包括交互式控制台会话。
请注意,这是而不是就像检索当前的交互式用户一样。
我猜测有终端服务的某种API访问来获取此信息?
这里是我就此问题:
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace EnumerateRDUsers
{
class Program
{
[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 enum WTS_INFO_CLASS
{
WTSInitialProgram,
WTSApplicationName,
WTSWorkingDirectory,
WTSOEMId,
WTSSessionId,
WTSUserName,
WTSWinStationName,
WTSDomainName,
WTSConnectState,
WTSClientBuildNumber,
WTSClientName,
WTSClientDirectory,
WTSClientProductId,
WTSClientHardwareId,
WTSClientAddress,
WTSClientDisplay,
WTSClientProtocolType
}
public enum WTS_CONNECTSTATE_CLASS
{
WTSActive,
WTSConnected,
WTSConnectQuery,
WTSShadow,
WTSDisconnected,
WTSIdle,
WTSListen,
WTSReset,
WTSDown,
WTSInit
}
static void Main(string[] args)
{
ListUsers("<INSERT SERVERNAME HERE>");
}
public static IntPtr OpenServer(String Name)
{
IntPtr server = WTSOpenServer(Name);
return server;
}
public static void CloseServer(IntPtr ServerHandle)
{
WTSCloseServer(ServerHandle);
}
public static void ListUsers(String ServerName)
{
IntPtr serverHandle = IntPtr.Zero;
List<String> resultList = new List<string>();
serverHandle = OpenServer(ServerName);
try
{
IntPtr SessionInfoPtr = IntPtr.Zero;
IntPtr userPtr = IntPtr.Zero;
IntPtr domainPtr = IntPtr.Zero;
Int32 sessionCount = 0;
Int32 retVal = WTSEnumerateSessions(serverHandle, 0, 1, ref SessionInfoPtr, ref sessionCount);
Int32 dataSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO));
IntPtr currentSession = 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);
Console.WriteLine("Domain and User: " + Marshal.PtrToStringAnsi(domainPtr) + "\\" + Marshal.PtrToStringAnsi(userPtr));
WTSFreeMemory(userPtr);
WTSFreeMemory(domainPtr);
}
WTSFreeMemory(SessionInfoPtr);
}
}
finally
{
CloseServer(serverHandle);
}
}
}
}
好吧,我自己的问题的一个解决方案。
您可以使用WMI来检索正在运行的进程的列表。你也可以看看这些过程的所有者。如果你看看“explorer.exe”的所有者(并删除重复项),你最终应该得到一个登录用户列表。
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace TerminalServices
{
class TSManager
{
[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);
[StructLayout(LayoutKind.Sequential)]
private struct WTS_SESSION_INFO
{
public Int32 SessionID;
[MarshalAs(UnmanagedType.LPStr)]
public String pWinStationName;
public WTS_CONNECTSTATE_CLASS State;
}
public enum WTS_CONNECTSTATE_CLASS
{
WTSActive,
WTSConnected,
WTSConnectQuery,
WTSShadow,
WTSDisconnected,
WTSIdle,
WTSListen,
WTSReset,
WTSDown,
WTSInit
}
public static IntPtr OpenServer(String Name)
{
IntPtr server = WTSOpenServer(Name);
return server;
}
public static void CloseServer(IntPtr ServerHandle)
{
WTSCloseServer(ServerHandle);
}
public static List<String> ListSessions(String ServerName)
{
IntPtr server = IntPtr.Zero;
List<String> ret = new List<string>();
server = OpenServer(ServerName);
try
{
IntPtr ppSessionInfo = IntPtr.Zero;
Int32 count = 0;
Int32 retval = WTSEnumerateSessions(server, 0, 1, ref ppSessionInfo, ref count);
Int32 dataSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO));
Int32 current = (int)ppSessionInfo;
if (retval != 0)
{
for (int i = 0; i < count; i++)
{
WTS_SESSION_INFO si = (WTS_SESSION_INFO)Marshal.PtrToStructure((System.IntPtr)current, typeof(WTS_SESSION_INFO));
current += dataSize;
ret.Add(si.SessionID + " " + si.State + " " + si.pWinStationName);
}
WTSFreeMemory(ppSessionInfo);
}
}
finally
{
CloseServer(server);
}
return ret;
}
}
}
另一种选择,如果你不想处理P /调用自己,会使用Cassia库:
using System;
using System.Security.Principal;
using Cassia;
namespace CassiaSample
{
public static class Program
{
public static void Main(string[] args)
{
ITerminalServicesManager manager = new TerminalServicesManager();
using (ITerminalServer server = manager.GetRemoteServer("your-server-name"))
{
server.Open();
foreach (ITerminalServicesSession session in server.GetSessions())
{
NTAccount account = session.UserAccount;
if (account != null)
{
Console.WriteLine(account);
}
}
}
}
}
}
我知道这是一个线索necomancy位,但如果任何人使用这有一个记忆韭菜。 add`WTSFreeMemory(userPtr); WTSFreeMemory(domainPtr);`在Console.Writeline`后修复它。 – 2010-04-20 21:49:22