Like me when I created this application you might be wondering how can you grab information about a terminal services session programatically might be because you have an application that checks the Users IP to do some additional configuration on the application surface / environment or you might have an application that you need to render differently depending on the clients resolution on the terminal serices.
Well without a Terminal Services Session getting this information will be really easy take getting an IP from the application as an example
System.Net.IPAddress[] YourIPs = System.Net.Dns.GetHostAddresses(System.Net.Dns.GetHostName()); for (int i = 0; i < YourIPs.Length; i++) { Console.WriteLine("IP Address {0}: {1} ", i, YourIPs[i].ToString()); }
or Getting a resolution
using System.Drawing; using System.Windows.Forms; Console.WriteLine(SystemInformation.PrimaryMonitorSize.ToString());
as you can see its really easy as there are .Net References for it but doing it in a Terminal Service Session will give you a differenstory as you will get the server environment results. Also you have to consider that there are no .Net references for Terminal Services Session and we have to import Wtsapi32.dll to achieve the results you want.
So what is Wtsapi32.dll? It is a Remote Desktop Services API that provide additional functionality which are related to a Remote Desktop Environment. To get starting I will give you a sample dwon below on how would we import this dll to our application as well as how to consume the methods it exposes.
using System; using System.Diagnostics; using System.Runtime.InteropServices; class Program { #region Constants public const int WTS_CURRENT_SESSION = -1; #endregion #region Dll Imports [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")] public static extern bool WTSQuerySessionInformation( System.IntPtr pServer, int iSessionID, WTS_INFO_CLASS oInfoClass, out System.IntPtr pBuffer, out uint iBytesReturned); [DllImport("wtsapi32.dll")] static extern void WTSFreeMemory( IntPtr pMemory); #endregion #region Structures //Structure for Terminal Service Client IP Address [StructLayout(LayoutKind.Sequential)] private struct WTS_CLIENT_ADDRESS { public int iAddressFamily; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] public byte[] bAddress; } //Structure for Terminal Service Session Info [StructLayout(LayoutKind.Sequential)] private struct WTS_SESSION_INFO { public int iSessionID; [MarshalAs(UnmanagedType.LPStr)] public string sWinsWorkstationName; public WTS_CONNECTSTATE_CLASS oState; } //Structure for Terminal Service Session Client Display [StructLayout(LayoutKind.Sequential)] private struct WTS_CLIENT_DISPLAY { public int iHorizontalResolution; public int iVerticalResolution; //1 = The display uses 4 bits per pixel for a maximum of 16 colors. //2 = The display uses 8 bits per pixel for a maximum of 256 colors. //4 = The display uses 16 bits per pixel for a maximum of 2^16 colors. //8 = The display uses 3-byte RGB values for a maximum of 2^24 colors. //16 = The display uses 15 bits per pixel for a maximum of 2^15 colors. public int iColorDepth; } #endregion #region Enumurations public enum WTS_CONNECTSTATE_CLASS { WTSActive, WTSConnected, WTSConnectQuery, WTSShadow, WTSDisconnected, WTSIdle, WTSListen, WTSReset, WTSDown, WTSInit } 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, WTSConfigInfo, WTSValidationInfo, WTSSessionAddressV4, WTSIsRemoteSession } #endregion static void Main(string[] args) { IntPtr pServer = IntPtr.Zero; string sUserName = string.Empty; string sDomain = string.Empty; string sClientApplicationDirectory = string.Empty; string sIPAddress = string.Empty; WTS_CLIENT_ADDRESS oClientAddres = new WTS_CLIENT_ADDRESS(); WTS_CLIENT_DISPLAY oClientDisplay = new WTS_CLIENT_DISPLAY(); IntPtr pSessionInfo = IntPtr.Zero; int iCount = 0; int iReturnValue = WTSEnumerateSessions(pServer, 0, 1, ref pSessionInfo, ref iCount); int iDataSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO)); int iCurrent = (int)pSessionInfo; if (iReturnValue != 0) { //Go to all sessions for (int i = 0; i < iCount; i++) { WTS_SESSION_INFO oSessionInfo = (WTS_SESSION_INFO)Marshal.PtrToStructure((System.IntPtr)iCurrent, typeof(WTS_SESSION_INFO)); iCurrent += iDataSize; uint iReturned = 0; //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 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); } Console.WriteLine("Session ID : " + oSessionInfo.iSessionID); Console.WriteLine("Session State : " + oSessionInfo.oState); Console.WriteLine("Workstation Name : " + oSessionInfo.sWinsWorkstationName); Console.WriteLine("IP Address : " + sIPAddress); Console.WriteLine("User Name : " + sDomain + @"" + sUserName); Console.WriteLine("Client Display Resolution: " + oClientDisplay.iHorizontalResolution + " x " + oClientDisplay.iVerticalResolution); Console.WriteLine("Client Display Colour Depth: " + oClientDisplay.iColorDepth); Console.WriteLine("Client Application Directory: " + sClientApplicationDirectory); Console.WriteLine("-----------------------"); } WTSFreeMemory(pSessionInfo); } } }
And here is the result
If you’d rather not deal with the P/Invokes, you might be interested to learn about Cassia, a .NET library which wraps the WTS API and provides access to all of the session information you mentioned.
Looks interesting will have a look at this library, thanks for sharing
What about pulling out incoming bytes and frams, outgoing bytes and frames as well as idle time and log on time? I was able to get the rest of the information you provided working but for some reason when i use the WTSQuerySessionInformation for the 5 values listed above it always comes back as false.
pServer is Zero means,how can get the remote machine sessions..i could not get info for remote domain…help me regarding this
This is just what I’m looking for but I have only ever used vb.net. My skills aren’t good enough to convert myself – I don’t suppose anyone has a vb.net version they could share?
You can try this, it should work http://www.developerfusion.com/tools/convert/csharp-to-vb/
Imports System
Imports System.Diagnostics
Imports System.Runtime.InteropServices
Imports log4net
Public Class TerminalServer
#Region “Constants”
Private Const WTS_CURRENT_SESSION As Integer = -1
#End Region
#Region “Dll Imports”
‘ _
‘Private Shared Function WTSEnumerateSessions(ByVal hwnd As IntPtr, ByVal lpString As StringBuilder, ByVal cch As Integer) As Integer
‘ End Function
_
Private Shared Function WTSEnumerateSessions( _
ByVal hServer As IntPtr, _
_
ByVal Reserved As Int32, _
_
ByVal Version As Int32, _
ByRef ppSessionInfo As IntPtr, _
_
ByRef pCount As Int32) As Int32
End Function
‘[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”)]
‘public static extern bool WTSQuerySessionInformation(
‘ System.IntPtr pServer,
‘ int iSessionID,
‘ WTS_INFO_CLASS oInfoClass,
‘ out System.IntPtr pBuffer,
‘ out uint iBytesReturned);
Private Declare Auto Function WTSQuerySessionInformation Lib “wtsapi32.dll” ( _
ByVal hServer As System.IntPtr, _
ByVal SessionId As Int32, _
ByVal InfoClass As WTS_INFO_CLASS, _
ByRef ppBuffer As IntPtr, _
ByRef pCount As UInt32) As Boolean
‘[DllImport(“wtsapi32.dll”)]
‘static extern void WTSFreeMemory(
‘ IntPtr pMemory);
_
Private Shared Sub WTSFreeMemory(ByVal pMemory As IntPtr)
End Sub
#End Region
#Region “Structures”
‘Structure for Terminal Service Client IP Address
_
Private Structure WTS_CLIENT_ADDRESS
Public iAddressFamily As Integer ‘AF_INET, (AF_INET6), AF_IPX, AF_NETBIOS, AF_UNSPEC
_
Public bAddress() As Byte
End Structure
‘Structure for Terminal Service Session Info
_
Private Structure WTS_SESSION_INFO
Public iSessionID As Integer
_
Public sWinsWorkstationName As String
Public oState As WTS_CONNECTSTATE_CLASS
End Structure
‘Structure for Terminal Service Session Client Display
_
Private Structure WTS_CLIENT_DISPLAY
Public iHorizontalResolution As Integer
Public iVerticalResolution As Integer
‘1 = The display uses 4 bits per pixel for a maximum of 16 colors.
‘2 = The display uses 8 bits per pixel for a maximum of 256 colors.
‘4 = The display uses 16 bits per pixel for a maximum of 2^16 colors.
‘8 = The display uses 3-byte RGB values for a maximum of 2^24 colors.
’16 = The display uses 15 bits per pixel for a maximum of 2^15 colors.
Public iColorDepth As Integer
End Structure
#End Region
#Region “Enumurations”
Private Enum WTS_CONNECTSTATE_CLASS
WTSActive
WTSConnected
WTSConnectQuery
WTSShadow
WTSDisconnected
WTSIdle
WTSListen
WTSReset
WTSDown
WTSInit
End Enum
Private 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
WTSConfigInfo
WTSValidationInfo
WTSSessionAddressV4
WTSIsRemoteSession
End Enum
#End Region
‘fonte: http://www.codeproject.com/Articles/111430/Grabbing-Information-of-a-Terminal-Services-Sessio
‘Public Sub Test()
‘ Dim pServer As IntPtr = IntPtr.Zero
‘ Dim sUserName As String = String.Empty
‘ Dim sDomain As String = String.Empty
‘ Dim sClientName As String = String.Empty
‘ Dim sSessionId As String = String.Empty
‘ Dim sClientApplicationDirectory As String = String.Empty
‘ Dim sIPAddress As String = String.Empty
‘ Dim oClientAddres As WTS_CLIENT_ADDRESS = New WTS_CLIENT_ADDRESS()
‘ Dim oClientDisplay As WTS_CLIENT_DISPLAY = New WTS_CLIENT_DISPLAY()
‘ Dim pSessionInfo As IntPtr = IntPtr.Zero
‘ Dim iCount As Integer = 0
‘ Dim iReturnValue As Integer = WTSEnumerateSessions(pServer, 0, 1, pSessionInfo, iCount)
‘ ‘dim iDataSize as Integer = Marshal.SizeOf(typeof(WTS_SESSION_INFO))
‘ Dim iDataSize As Integer = Marshal.SizeOf(GetType(WTS_SESSION_INFO))
‘ Dim iCurrent As Integer = pSessionInfo.ToInt32
‘ Dim _Message As String = String.Empty
‘ Dim _ThisProcess As Process = Process.GetCurrentProcess()
‘ Dim _SessionId As Integer = _ThisProcess.SessionId
‘ _Message += “Session ID:” + _SessionId.ToString
‘ If (iReturnValue 0) Then
‘ ‘Go to all sessions
‘ For i As Integer = 0 To iCount – 1
‘ _Message += ” ” + i.ToString
‘ Dim oSessionInfo As WTS_SESSION_INFO = _
‘ CType(Marshal.PtrToStructure(New IntPtr(iCurrent), _
‘ GetType(WTS_SESSION_INFO)), WTS_SESSION_INFO)
‘ iCurrent += iDataSize
‘ Dim iReturned As UInteger = 0
‘ ‘Get the IP address of the Terminal Services User
‘ Dim pAddress As IntPtr = IntPtr.Zero
‘ If (WTSQuerySessionInformation(pServer, _
‘ oSessionInfo.iSessionID, WTS_INFO_CLASS.WTSClientAddress, _
‘ pAddress, iReturned) = True) Then
‘ oClientAddres = DirectCast(Marshal.PtrToStructure _
‘ (pAddress, oClientAddres.GetType()), WTS_CLIENT_ADDRESS)
‘ sIPAddress = oClientAddres.bAddress(2).ToString() + “.” + _
‘ oClientAddres.bAddress(3).ToString() + “.” + oClientAddres.bAddress(4).ToString() _
‘ + “.” + oClientAddres.bAddress(5).ToString()
‘ _Message += ” IPAddress:” + sIPAddress
‘ End If
‘ ‘Get the User Name of the Terminal Services User
‘ If (WTSQuerySessionInformation(pServer, _
‘ oSessionInfo.iSessionID, WTS_INFO_CLASS.WTSUserName, _
‘ pAddress, iReturned) = True) Then
‘ ‘sUserName = Marshal.PtrToStringAnsi(pAddress) ‘, CType(iReturned, Integer))
‘ sUserName = Marshal.PtrToStringUni(pAddress)
‘ _Message += ” UserName:” + sUserName
‘ End If
‘ ‘Get the Domain Name of the Terminal Services User
‘ If (WTSQuerySessionInformation(pServer, _
‘ oSessionInfo.iSessionID, WTS_INFO_CLASS.WTSDomainName, _
‘ pAddress, iReturned) = True) Then
‘ ‘sDomain = Marshal.PtrToStringAnsi(pAddress, CType(iReturned, Integer))
‘ sDomain = Marshal.PtrToStringUni(pAddress)
‘ _Message += ” Domain:” + sDomain
‘ End If
‘ ‘Get the User Name of the Terminal Services User
‘ If (WTSQuerySessionInformation(pServer, _
‘ oSessionInfo.iSessionID, WTS_INFO_CLASS.WTSClientName, _
‘ pAddress, iReturned) = True) Then
‘ ‘sUserName = Marshal.PtrToStringAnsi(pAddress) ‘, CType(iReturned, Integer))
‘ sClientName = Marshal.PtrToStringUni(pAddress)
‘ _Message += ” ClientName:” + sClientName
‘ End If
‘ ‘Get the Domain Name of the Terminal Services User
‘ If (WTSQuerySessionInformation(pServer, _
‘ oSessionInfo.iSessionID, WTS_INFO_CLASS.WTSSessionId, _
‘ pAddress, iReturned) = True) Then
‘ ‘sDomain = Marshal.PtrToStringAnsi(pAddress, CType(iReturned, Integer))
‘ sSessionId = Marshal.PtrToStringUni(pAddress)
‘ _Message += ” SessionId:” + sSessionId
‘ End If
‘ ”Get the Display Information of the Terminal Services User
‘ ‘If (WTSQuerySessionInformation(pServer, _
‘ ‘ oSessionInfo.iSessionID, WTS_INFO_CLASS.WTSClientDisplay, _
‘ ‘ pAddress, iReturned) = True) Then
‘ ‘ oClientDisplay = CType(Marshal.PtrToStructure _
‘ ‘ (pAddress, oClientDisplay.GetType()), WTS_CLIENT_DISPLAY)
‘ ‘End If
‘ ”Get the Application Directory of the Terminal Services User
‘ ‘If (WTSQuerySessionInformation(pServer, oSessionInfo.iSessionID, _
‘ ‘ WTS_INFO_CLASS.WTSClientDirectory, pAddress, iReturned) = True) Then
‘ ‘ ‘sClientApplicationDirectory = Marshal.PtrToStringAnsi(pAddress)
‘ ‘ sClientApplicationDirectory = Marshal.PtrToStringUni(pAddress)
‘ ‘End If
‘ Next
‘ WTSFreeMemory(pSessionInfo)
‘ End If
‘ Dim _logger As ILog = LogManager.GetLogger(“IDE”)
‘ _logger.Debug(_Message)
‘End Sub
Public Function ClientName(ByVal p_LocalName As String) As String
Dim pServer As IntPtr = IntPtr.Zero
Dim sClientName As String = p_LocalName
Dim pSessionInfo As IntPtr = IntPtr.Zero
Dim iCount As Integer = 0
Dim iReturnValue As Integer = WTSEnumerateSessions(pServer, 0, 1, pSessionInfo, iCount)
‘dim iDataSize as Integer = Marshal.SizeOf(typeof(WTS_SESSION_INFO))
Dim iDataSize As Integer = Marshal.SizeOf(GetType(WTS_SESSION_INFO))
Dim iCurrent As Integer = pSessionInfo.ToInt32
Dim oSessionInfo As WTS_SESSION_INFO
If (iReturnValue 0) Then
Dim _ThisProcess As Process = Process.GetCurrentProcess()
Dim _SessionId As Integer = _ThisProcess.SessionId
If _SessionId 0 Then
sClientName = _Name
End If
End If
End If
WTSFreeMemory(pSessionInfo)
End If
Return sClientName
End Function
End Class