Search
Module:
Directory

   Desktop Functions:

   Smart Device Functions:


Show Recent Changes
Subscribe (RSS)
Misc. Pages
Comments
FAQ
Helpful Tools
Playground
Suggested Reading
Website TODO List
Download Visual Studio Add-In

WTSEnumerateSessions (wtsapi32)
 
.
Summary
This Terminal Services API call lists all local and remote sessions for a given server, including their state (e.g. connected, disconnected) and type (local, RDP). It is the basis for the output of qwinsta.exe.

C# Signature:

[DllImport("wtsapi32.dll", SetLastError=true)]
static extern int WTSEnumerateSessions(
                System.IntPtr hServer,
                int Reserved,
                int Version,
                ref System.IntPtr ppSessionInfo,
                ref int pCount);

[DllImport("wtsapi32.dll", SetLastError=true)]
static extern void WTSEnumerateSessions(
                System.IntPtr hServer,
                ref System.IntPtr ppSessionInfo,
                ref int pCount)
{
    WTSEnumerateSessions(hServer,0,1,ppSessionInfo,pCount);
}

Powershell Signature:

$wtsenumsig = @'
[DllImport("wtsapi32.dll", SetLastError=true)]
public static extern int WTSEnumerateSessions(
        System.IntPtr hServer,
        int Reserved,
        int Version,
        ref System.IntPtr ppSessionInfo,
        ref int pCount);
'@

C# Example

// Note the VB example will give you the first entry of the array n times where n is the size of the array
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace TerminalServices
{
    class TSManager
    {
    [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", SetLastError=true)]
    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));

        Int64 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;
    }
    }
}

Powershell Example

$server = "vmtermsrv"
$messageTitle = "FooBar"
$message = "This is a test...  This is only a test"
$timeout = 60;

$wtssig = @'
namespace mystruct {
using System;
using System.Runtime.InteropServices;
     [StructLayout(LayoutKind.Sequential)]
     public 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
     }
     }
'@


add-type  $wtssig

$wtsenumsig = @'
[DllImport("wtsapi32.dll", SetLastError=true)]
public static extern int WTSEnumerateSessions(
         System.IntPtr hServer,
         int Reserved,
         int Version,
         ref System.IntPtr ppSessionInfo,
         ref int pCount);
'@

$wtsopensig = @'
[DllImport("wtsapi32.dll", SetLastError=true)]
public static extern IntPtr WTSOpenServer(string pServerName);
'@

$wtsSendMessagesig = @'
[DllImport("wtsapi32.dll", SetLastError = true)]
     public static extern bool WTSSendMessage(
     IntPtr hServer,
     [MarshalAs(UnmanagedType.I4)] int SessionId,
     String pTitle,
     [MarshalAs(UnmanagedType.U4)] int TitleLength,
     String pMessage,
     [MarshalAs(UnmanagedType.U4)] int MessageLength,
     [MarshalAs(UnmanagedType.U4)] int Style,
     [MarshalAs(UnmanagedType.U4)] int Timeout,
     [MarshalAs(UnmanagedType.U4)] out int pResponse,
     bool bWait);
'@

$wtsenum = add-type -MemberDefinition $wtsenumsig -Name PSWTSEnumerateSessions -Namespace GetLoggedOnUsers -PassThru
$wtsOpen = add-type -MemberDefinition $wtsopensig -name PSWTSOpenServer -Namespace GetLoggedOnUsers -PassThru
$wtsmessage = Add-Type -MemberDefinition $wtsSendMessagesig -name PSWTSSendMessage -Namespace GetLoggedOnUsers -PassThru



[long]$count = 0
[long]$ppSessionInfo = 0

$server = $wtsOpen::WTSOpenServer($server)
[long]$retval = $wtsenum::WTSEnumerateSessions($server,0,1,[ref]$ppSessionInfo,[ref]$count)
$datasize = [system.runtime.interopservices.marshal]::SizeOf([System.Type][mystruct.WTS_SESSION_INFO])
$Responses = @()
if ($retval -ne 0){
     for ($i = 0; $i -lt $count; $i++){
     $element =  [system.runtime.interopservices.marshal]::PtrToStructure($ppSessionInfo + ($datasize * $i),[System.type][mystruct.WTS_SESSION_INFO])
     $element
     $resp = ""
     $wtsmessage::WTSSendMessage($server, $element.SessionID,$messageTitle,$messageTitle.Length,$message,$message.Length,0,$timeout,[ref]$resp,$true)
     $responses += $resp;
     }

}
$responses

VB Signature:

    <DllImport("wtsapi32.dll", _
    bestfitmapping:=True, _
    CallingConvention:=CallingConvention.StdCall, _
    CharSet:=CharSet.Auto, _
    EntryPoint:="WTSEnumerateSessions", _
    setlasterror:=True, _
    ThrowOnUnmappableChar:=True)> _
    Private Shared Function WTSEnumerateSessions( _
    ByVal hServer As IntPtr, _
    <MarshalAs(UnmanagedType.U4)> _
    ByVal Reserved As Int32, _
    <MarshalAs(UnmanagedType.U4)> _
    ByVal Version As Int32, _
    ByRef ppSessionInfo As IntPtr, _
    <MarshalAs(UnmanagedType.U4)> _
    ByRef pCount As Int32) As Int32
    End Function

User-Defined Types:

    Private Enum WTS_CONNECTSTATE_CLASS
    WTSActive
    WTSConnected
    WTSConnectQuery
    WTSShadow
    WTSDisconnected
    WTSIdle
    WTSListen
    WTSReset
    WTSDown
    WTSInit
    End Enum

    <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> _
    Private Structure WTS_SESSION_INFO
    Dim SessionID As Int32 'DWORD integer
    Dim pWinStationName As String ' integer LPTSTR - Pointer to a null-terminated string containing the name of the WinStation for this session
    Dim State As WTS_CONNECTSTATE_CLASS
    End Structure

Notes:

None.

Tips & Tricks:

Please add some!

Sample Code:

Option Explicit On
Option Strict On

Imports System.Runtime.InteropServices

Public Class ManagedWTSAPI

    Private Enum WTS_CONNECTSTATE_CLASS
    WTSActive
    WTSConnected
    WTSConnectQuery
    WTSShadow
    WTSDisconnected
    WTSIdle
    WTSListen
    WTSReset
    WTSDown
    WTSInit
    End Enum

    <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> _
    Private Structure WTS_SESSION_INFO
    Dim SessionID As Int32 'DWORD integer
    Dim pWinStationName As String ' integer LPTSTR - Pointer to a null-terminated string containing the name of the WinStation for this session
    Dim State As WTS_CONNECTSTATE_CLASS
    End Structure

    Friend Structure strSessionsInfo
    Dim SessionID As Integer
    Dim StationName As String
    Dim ConnectionState As String
    End Structure

    <DllImport("wtsapi32.dll", _
    bestfitmapping:=True, _
    CallingConvention:=CallingConvention.StdCall, _
    CharSet:=CharSet.Auto, _
    EntryPoint:="WTSEnumerateSessions", _
    setlasterror:=True, _
    ThrowOnUnmappableChar:=True)> _
    Private Shared Function WTSEnumerateSessions( _
    ByVal hServer As IntPtr, _
    <MarshalAs(UnmanagedType.U4)> _
    ByVal Reserved As Int32, _
    <MarshalAs(UnmanagedType.U4)> _
    ByVal Vesrion As Int32, _
    ByRef ppSessionInfo As IntPtr, _
    <MarshalAs(UnmanagedType.U4)> _
    ByRef pCount As Int32) As Int32
    End Function

    <DllImport("wtsapi32.dll")> _
    Private Shared Sub WTSFreeMemory(ByVal pMemory As IntPtr)
    End Sub

    <DllImport("wtsapi32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
     Private Shared Function WTSOpenServer(ByVal pServerName As String) As IntPtr
    End Function

    <DllImport("wtsapi32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
     Private Shared Sub WTSCloseServer(ByVal hServer As IntPtr)
    End Sub

    Friend Function GetSessions(ByVal ServerName As String) As strSessionsInfo()
    Dim ptrOpenedServer As IntPtr
    Dim RetVal As strSessionsInfo()
    Try
        ptrOpenedServer = WTSOpenServer(ServerName)
        Dim FRetVal As Int32
        Dim ppSessionInfo As IntPtr = IntPtr.Zero
        Dim Count As Int32 = 0
        Try
        FRetVal = WTSEnumerateSessions(ptrOpenedServer, 0, 1, ppSessionInfo, Count)
        If FRetVal <> 0 Then
            Dim sessionInfo() As WTS_SESSION_INFO = New WTS_SESSION_INFO(Count) {}
            Dim i As Integer
            Dim DataSize = Marshal.SizeOf(New WTS_SESSION_INFO)
            Dim current As Int64
            current = ppSessionInfo.ToInt64
            For i = 0 To Count - 1 ' Step i + 1
            sessionInfo(i) = CType(Marshal.PtrToStructure(New IntPtr(current), GetType(WTS_SESSION_INFO)), WTS_SESSION_INFO)
            current = current + DataSize
            Next
            WTSFreeMemory(ppSessionInfo)
            Dim tmpArr(sessionInfo.GetUpperBound(0)) As strSessionsInfo
            For i = 0 To tmpArr.GetUpperBound(0)
            tmpArr(i).SessionID = sessionInfo(i).SessionID
            tmpArr(i).StationName = sessionInfo(i).pWinStationName
            tmpArr(i).ConnectionState = GetConnectionState(sessionInfo(i).State)
            Next
            ReDim sessionInfo(-1)
            RetVal = tmpArr
        Else
            Throw New ApplicationException("No data retruned")
        End If
        Catch ex As Exception
        Throw New Exception(ex.Message & vbCrLf & System.Runtime.InteropServices.Marshal.GetLastWin32Error)
        End Try
    Catch ex As Exception
        Throw New Exception(ex.Message)
        Exit Function
    Finally
        WTSCloseServer(ptrOpenedServer)
    End Try

    Return RetVal
    End Function

    Private Function GetConnectionState(ByVal State As WTS_CONNECTSTATE_CLASS) As String
    Dim RetVal As String
    Select Case State
        Case WTS_CONNECTSTATE_CLASS.WTSActive
        RetVal = "Active"
        Case WTS_CONNECTSTATE_CLASS.WTSConnected
        RetVal = "Connected"
        Case WTS_CONNECTSTATE_CLASS.WTSConnectQuery
        RetVal = "Query"
        Case WTS_CONNECTSTATE_CLASS.WTSDisconnected
        RetVal = "Disconnected"
        Case WTS_CONNECTSTATE_CLASS.WTSDown
        RetVal = "Down"
        Case WTS_CONNECTSTATE_CLASS.WTSIdle
        RetVal = "Idle"
        Case WTS_CONNECTSTATE_CLASS.WTSInit
        RetVal = "Initializing."
        Case WTS_CONNECTSTATE_CLASS.WTSListen
        RetVal = "Listen"
        Case WTS_CONNECTSTATE_CLASS.WTSReset
        RetVal = "reset"
        Case WTS_CONNECTSTATE_CLASS.WTSShadow
        RetVal = "Shadowing"
        Case Else
        RetVal = "Unknown connect state"
    End Select
    Return RetVal
    End Function

End Class

Alternative Managed API:

Cassia on google code: https://code.google.com/p/cassia/

Documentation

Please edit this page!

Do you have...

  • helpful tips or sample code to share for using this API in managed code?
  • corrections to the existing content?
  • variations of the signature you want to share?
  • additional languages you want to include?

Select "Edit This Page" on the right hand toolbar and edit it! Or add new pages containing supporting types needed for this API (structures, delegates, and more).

 
Access PInvoke.net directly from VS:
Terms of Use
Edit This Page
Find References
Show Printable Version
Revisions