Click here to Skip to main content
15,905,785 members
Articles / Programming Languages / C#

Grabbing Information of a Terminal Services Session Programmatically

Rate me:
Please Sign up or sign in to vote.
4.91/5 (9 votes)
6 Oct 2010CPOL1 min read 60K   21   6
Grabbing Information of a Terminal Services Session Programmatically

Like me, when I created this application, you might be wondering how you can 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 services.

Well without a Terminal Services Session, getting this information will be really easy like getting an IP from the application as an example:

C#
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:

C#
using System.Drawing;
using System.Windows.Forms;
Console.WriteLine(SystemInformation.PrimaryMonitorSize.ToString());

As you can see, it's really easy as there are .NET References for it but doing it in a Terminal Service Session will give you a different story 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 provides additional functionality which is related to a Remote Desktop Environment. To get started, I will give you a sample down below on how would we import this DLL to our application as well as how to consume the methods it exposes.

C#
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:

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Technical Lead
New Zealand New Zealand
http://nz.linkedin.com/in/macaalay
http://macaalay.com/

Comments and Discussions

 
QuestionHow to get Hardware id of client machine who is logged in Pin
Member 1469200716-Dec-19 21:36
Member 1469200716-Dec-19 21:36 
PraiseVery useful Pin
tshepo nnene22-Oct-18 22:09
tshepo nnene22-Oct-18 22:09 
GeneralRe: Very useful Pin
citizendc4-Feb-19 21:24
citizendc4-Feb-19 21:24 
Hi Tshepo,

Can you share your updated version of the code ?
PraiseUseful article Pin
Michael_A19-Aug-18 8:07
Michael_A19-Aug-18 8:07 
GeneralMy vote of 3 Pin
i0029-Jan-14 11:46
i0029-Jan-14 11:46 
GeneralRe: My vote of 3 Pin
citizendc4-Feb-19 21:21
citizendc4-Feb-19 21:21 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.