using System; using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; using System.Net; using System.Windows.Forms; using System.Data; using log4net; namespace AnywhereTS { public class TSManager { // Imports [DllImport("wtsapi32.dll")] static extern IntPtr WTSOpenServer([MarshalAs(UnmanagedType.LPStr)] String pServerName); [DllImport("wtsapi32.dll")] public static extern void WTSCloseServer(IntPtr hServer); [DllImport("wtsapi32.dll")] public 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", EntryPoint = "WTSQuerySessionInformation", CallingConvention = CallingConvention.Cdecl)] public static extern bool WTSQuerySessionInformation( System.IntPtr hServer, uint sessionId, WTSInfoClass wtsInfoClass, out System.IntPtr ppBuffer, out uint pBytesReturned); [DllImport("wtsapi32.dll")] static extern void WTSFreeMemory(IntPtr pMemory); // For Lookup of MAC address [DllImport("iphlpapi.dll", ExactSpelling = true)] public static extern int SendARP(int DestIP, int SrcIP, [Out] byte[] pMacAddr, ref int PhyAddrLen); // Consts public const uint WTS_CURRENT_SESSION = 4294967295; // = -1 // Type definitions [StructLayout(LayoutKind.Sequential)] private struct WTS_SESSION_INFO { public uint SessionID; [MarshalAs(UnmanagedType.LPStr)] public String pWinStationName; public WTS_CONNECTSTATE_CLASS State; } public enum WTS_CONNECTSTATE_CLASS { WTSActive, // User logged on to WinStation WTSConnected, // WinStation connected to client WTSConnectQuery, // In the process of connecting to client WTSShadow, // Shadowing another WinStation WTSDisconnected, // WinStation logged on without client WTSIdle, // Waiting for client to connect WTSListen, // WinStation is listening for connection WTSReset, // WinStation is being reset WTSDown, // WinStation is down due to error WTSInit, // WinStation in initialization }; public enum WTSInfoClass { WTSInitialProgram, WTSApplicationName, WTSWorkingDirectory, WTSOEMId, WTSSessionId, WTSUserName, WTSWinStationName, WTSDomainName, WTSConnectState, WTSClientBuildNumber, WTSClientName, WTSClientDirectory, WTSClientProductId, WTSClientHardwareId, WTSClientAddress, WTSClientDisplay, WTSClientProtocolType, } ; public struct WTS_CLIENT_ADDRESS { public uint AddressFamily; // AF_INET, AF_IPX, AF_NETBIOS, AF_UNSPEC public Byte[] Address; }; public struct WTS_CLIENT_DISPLAY { public uint HorizontalResolution; // horizontal dimensions, in pixels public uint VerticalResolution; // vertical dimensions, in pixels public uint ColorDepth; // 1=16, 2=256, 4=64K, 8=16M }; // Selected info for terminal server sessions public struct TS_SESSION_INFO { public uint sessionID; public string ipAddress; // The IP address of the client public string macAddress; // The MAC address of the client public string name; // The (netbios) name of the client public string username; // User logged in to the session, if any. public WTS_CONNECTSTATE_CLASS state; // The state of the session public int HorizontalResolution; // Vertical screen res for the session public int VerticalResolution; // Horiz screen res for the session public int ColorDepth; // Screen color depth for the session }; public static IntPtr OpenServer(String Name) { IntPtr server = WTSOpenServer(Name); return server; } public static void CloseServer(IntPtr ServerHandle) { WTSCloseServer(ServerHandle); } // Return address for a terminal server session. // WTSClientAddress gives a pointer to a WTS_CLIENT_ADDRESS structure containing // the network type and network address of the client. If the function is called // from the Terminal Services console, ppBuffer returns a NULL pointer. // Note that the first byte of the IP address returned in the ppBuffer // parameter will be located at an offset of two bytes from the first location // of the buffer. private static string GetTSClientAddress(uint sessionID, IntPtr server) { System.IntPtr ppBuffer = System.IntPtr.Zero; uint pBytesReturned = 0; StringBuilder builder = new StringBuilder(); // Interface avec API WTS_CLIENT_ADDRESS wtsAdr = new WTS_CLIENT_ADDRESS(); if (WTSQuerySessionInformation( server, sessionID, WTSInfoClass.WTSClientAddress, out ppBuffer, out pBytesReturned)) { wtsAdr.Address = new Byte[pBytesReturned - 1]; int run = (int)ppBuffer; // pointeur sur les données Type t = typeof(Byte); Type t1 = typeof(uint); int uintSize = Marshal.SizeOf(t1); int byteSize = Marshal.SizeOf(t); wtsAdr.AddressFamily = (uint)Marshal.ReadInt32((System.IntPtr)run); // Address family can be only: // AF_UNSPEC = 0 (unspecified) // AF_INET = 2 (internetwork: UDP, TCP, etc.) // AF_IPX = AF_NS = 6 (IPX protocols: IPX, SPX, etc.) // AF_NETBIOS = 17 (NetBios-style addresses) //run+=uintSize; //run+=dataSize; /*switch(wtsAdr.AddressFamily) { case 0:builder.Append("AF_UNSPEC"); break; case 1:builder.Append("AF_INET"); break; case 2:builder.Append("AF_IPX"); break; case 3:builder.Append("AF_NETBIOS"); break; }*/ for (int i = 0; i < pBytesReturned - 1; i++) { wtsAdr.Address[i] = Marshal.ReadByte((System.IntPtr)run); run += byteSize; // TO GET and to SEE ALL the DATA //builder.Append(wtsAdr.Address[i].ToString()+"-"); } //builder.Append("-"); // The IP address is located in bytes 2, 3, 4, and 5. The other bytes are not used. // If AddressFamily returns AF_UNSPEC, the first byte in Address // is initialized to zero. // Check if the returned address is an IP address if (wtsAdr.AddressFamily == 2) { // It is an IP address builder.Append((wtsAdr.Address[4 + 2]).ToString()); builder.Append("."); builder.Append((wtsAdr.Address[4 + 3]).ToString()); builder.Append("."); builder.Append((wtsAdr.Address[4 + 4]).ToString()); builder.Append("."); builder.Append((wtsAdr.Address[4 + 5]).ToString()); } } WTSFreeMemory(ppBuffer); return builder.ToString(); } // Get display parameters for a user session on a terminal server // In: SessionID = identifier for the session // In: server = server handle for the server that the session resides on. private static void GetTSClientDisplay(uint sessionID, IntPtr server, out int horizontalResolution, out int verticalResolution, out int colorDepth) { horizontalResolution = 0; verticalResolution = 0; colorDepth = 0; System.IntPtr ppBuffer = System.IntPtr.Zero; uint pBytesReturned = 0; StringBuilder sDisplay = new StringBuilder(); WTS_CLIENT_DISPLAY clientDisplay = new WTS_CLIENT_DISPLAY(); clientDisplay.HorizontalResolution = 0; clientDisplay.VerticalResolution = 0; clientDisplay.ColorDepth = 0; Type dataType = typeof(WTS_CLIENT_DISPLAY); if (WTSQuerySessionInformation( server, sessionID, WTSInfoClass.WTSClientDisplay, out ppBuffer, out pBytesReturned)) { clientDisplay = (WTS_CLIENT_DISPLAY)Marshal.PtrToStructure(ppBuffer, dataType); horizontalResolution = (int)(clientDisplay.HorizontalResolution); verticalResolution = (int)(clientDisplay.VerticalResolution); colorDepth = (int)(clientDisplay.ColorDepth); } WTSFreeMemory(ppBuffer); } // Get Mac from IP, using ARP private static string GetMACFromIP(string ipString) { IPAddress ip = IPAddress.Parse(ipString); // Actual IP int rv; string macStr; byte[] mac = new byte[6]; int maclen = mac.Length; rv = SendARP(BitConverter.ToInt32(ip.GetAddressBytes(), 0), 0, mac, ref maclen); if (rv == 0) // If not 0, error { // macStr = BitConverter.ToString(mac, 0, 6); macStr = BitConverter.ToString(mac, 0, 1)+BitConverter.ToString(mac, 1, 1)+BitConverter.ToString(mac, 2, 1) +BitConverter.ToString(mac, 3, 1)+BitConverter.ToString(mac, 4, 1)+BitConverter.ToString(mac, 5, 1); } else { macStr = ""; } return macStr; } private static string GetTSUserName(uint sessionID, IntPtr server) { System.IntPtr ppBuffer = System.IntPtr.Zero; uint pBytesReturned = 0; string currentUserName = ""; if (WTSQuerySessionInformation( server, sessionID, WTSInfoClass.WTSUserName, out ppBuffer, out pBytesReturned)) { currentUserName = Marshal.PtrToStringAnsi(ppBuffer); } WTSFreeMemory(ppBuffer); return currentUserName; } public static string GetTSClientName(uint sessionID, IntPtr server) { System.IntPtr ppBuffer = System.IntPtr.Zero; int adrBuffer; uint pBytesReturned = 0; string clientName = ""; if (WTSQuerySessionInformation( server, sessionID, WTSInfoClass.WTSClientName, out ppBuffer, out pBytesReturned)) { adrBuffer = (int)ppBuffer; clientName = Marshal.PtrToStringAnsi((System.IntPtr)adrBuffer); } WTSFreeMemory(ppBuffer); return clientName; } // List all sessions on all registered terminal servers and return in a list with selected data for each session. public static List ListSessions() { List ret = new List(); if (ATSGlobals.terminalServerConfig == 0) // This server is a terminal server { ListSessions(ret, "localhost"); // Add sessions from local server } // Add sessions from other terminal servers atsDataSet.TerminalServerDataTable datatableTerminalServer; datatableTerminalServer = new atsDataSet.TerminalServerDataTable(); ProSupport.terminalServerTableAdapter.Fill(datatableTerminalServer); foreach (DataRow row in datatableTerminalServer.Rows) { string strError = ""; try { strError = ListSessions(ret, row["Path"].ToString()); } catch { //MessageBox.Show("Error: Could not retrieve session data from server '" + row["Path"].ToString() + "'. Error 39092."); } if (strError.Length != 0) { //MessageBox.Show("Warning: " + strError, "AnywhereTS"); } } return ret; } // List all sessions on the terminal server and return in a list with selected data for each session. public static List ListSessions(String serverName) { IntPtr server = IntPtr.Zero; List ret = new List(); 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; TS_SESSION_INFO CurrentClientInfo; if (retval != 0) { for (int i = 0; i < count; i++) // Iterate through all sessions on the server { WTS_SESSION_INFO si = (WTS_SESSION_INFO)Marshal.PtrToStructure((System.IntPtr)current, typeof(WTS_SESSION_INFO)); current += dataSize; CurrentClientInfo.sessionID = si.SessionID; CurrentClientInfo.ipAddress = GetTSClientAddress(si.SessionID, server); CurrentClientInfo.name = GetTSClientName(si.SessionID, server); CurrentClientInfo.username = GetTSUserName(si.SessionID, server); CurrentClientInfo.state = si.State; if (CurrentClientInfo.name != "") { CurrentClientInfo.macAddress = ProSupport.GetMacAddressFromNameAndDatabase(CurrentClientInfo.name); } else { CurrentClientInfo.macAddress = ""; } GetTSClientDisplay( si.SessionID, server, out CurrentClientInfo.HorizontalResolution, out CurrentClientInfo.VerticalResolution, out CurrentClientInfo.ColorDepth); ret.Add(CurrentClientInfo); } WTSFreeMemory(ppSessionInfo); } } finally { try { CloseServer(server); } catch (Exception e) { MessageBox.Show("Error could not close terminal server connection (63210)"); using (log4net.NDC.Push(string.Format("SqlException: MESSAGE={0}{1}Diagnostics:{1}{2}", e.Message, System.Environment.NewLine, e.ToString()))) { Logging.ATSAdminLog.Error("Error could not close terminal server connection (63210)"); } } } return ret; } // List all sessions on the terminal server and return in a list with selected data for each session. public static List ListTSsessions(String serverName) { IntPtr server = IntPtr.Zero; List ret = new List(); 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; AtsSession CurrentSession = new AtsSession(); if (retval != 0) { for (int i = 0; i < count; i++) // Iterate through all sessions on the server { WTS_SESSION_INFO si = (WTS_SESSION_INFO)Marshal.PtrToStructure((System.IntPtr)current, typeof(WTS_SESSION_INFO)); current += dataSize; CurrentSession.sessionID = si.SessionID; CurrentSession.ipAddress = GetTSClientAddress(si.SessionID, server); CurrentSession.name = GetTSClientName(si.SessionID, server); CurrentSession.username = GetTSUserName(si.SessionID, server); CurrentSession.state = si.State; if (CurrentSession.name != "") { CurrentSession.macAddress = ProSupport.GetMacAddressFromNameAndDatabase(CurrentSession.name); } else { CurrentSession.macAddress = ""; } GetTSClientDisplay( si.SessionID, server, out CurrentSession.HorizontalResolution, out CurrentSession.VerticalResolution, out CurrentSession.ColorDepth); ret.Add(CurrentSession); } WTSFreeMemory(ppSessionInfo); } } finally { try { CloseServer(server); } catch(Exception e) { MessageBox.Show("Error could not close terminal server connection (63210)"); using (log4net.NDC.Push(string.Format("SqlException: MESSAGE={0}{1}Diagnostics:{1}{2}", e.Message, System.Environment.NewLine, e.ToString()))) { Logging.ATSAdminLog.Error("Error could not close terminal server connection (63210)"); } } } return ret; } // List all sessions on the terminal server and adds them to list with selected data for each session. // Returns error message or "" if everything went ok. public static string ListSessions(List SessionInfo, String serverName) { IntPtr server = IntPtr.Zero; server = OpenServer(serverName); string strError = "Could not retrieve session data from server '" + serverName + "'"; // Assume something went wrong if (server != IntPtr.Zero) { 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; TS_SESSION_INFO CurrentClientInfo; 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; CurrentClientInfo.sessionID = si.SessionID; CurrentClientInfo.ipAddress = GetTSClientAddress(si.SessionID, server); CurrentClientInfo.name = GetTSClientName(si.SessionID, server); CurrentClientInfo.username = GetTSUserName(si.SessionID, server); CurrentClientInfo.state = si.State; if (CurrentClientInfo.name != "") { CurrentClientInfo.macAddress = ProSupport.GetMacAddressFromNameAndDatabase(CurrentClientInfo.name); } else { CurrentClientInfo.macAddress = ""; } GetTSClientDisplay( si.SessionID, server, out CurrentClientInfo.HorizontalResolution, out CurrentClientInfo.VerticalResolution, out CurrentClientInfo.ColorDepth); SessionInfo.Add(CurrentClientInfo); } WTSFreeMemory(ppSessionInfo); } } finally { try { CloseServer(server); } finally { // Catch exeception } } strError = ""; // Everything went ok } // end if (server != null) return strError; } // List all sessions on the terminal server and adds them to list with selected data for each session. // Returns error message or "" if everything went ok. public static string ListSessions(List SessionInfo, String serverName) { IntPtr server = IntPtr.Zero; server = OpenServer(serverName); string strError = "Could not retrieve session data from server '" + serverName + "'"; // Assume something went wrong if (server != IntPtr.Zero) { 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++) { AtsSession currentSession = new AtsSession(); WTS_SESSION_INFO si = (WTS_SESSION_INFO)Marshal.PtrToStructure((System.IntPtr)current, typeof(WTS_SESSION_INFO)); current += dataSize; currentSession.TerminalServerName = serverName; currentSession.sessionID = si.SessionID; currentSession.ipAddress = GetTSClientAddress(si.SessionID, server); currentSession.name = GetTSClientName(si.SessionID, server); currentSession.username = GetTSUserName(si.SessionID, server); currentSession.state = si.State; if (currentSession.name != "") { currentSession.macAddress = ProSupport.GetMacAddressFromNameAndDatabase(currentSession.name); } else { currentSession.macAddress = ""; } GetTSClientDisplay( si.SessionID, server, out currentSession.HorizontalResolution, out currentSession.VerticalResolution, out currentSession.ColorDepth); SessionInfo.Add(currentSession); } WTSFreeMemory(ppSessionInfo); } } finally { try { CloseServer(server); } finally { // Catch exeception } } strError = ""; // Everything went ok } // end if (server != null) return strError; } // Return matching session for a macAddress, or null, if the mac address is not used in any session. // Called when a child node selected in the tree view public static AtsSession GetSession(string macAddress) { foreach (AtsTerminalServer ts in AtsEnvironment.TerminalServers) { foreach (AtsSession session in ts.Session) { // Try to find the MAC adress for the selected client in any of the sessions. if (session.macAddress == macAddress) { return session; } } } // Session not found, return null. return null; } // Convert session state to string public static string StateToString(WTS_CONNECTSTATE_CLASS state) { switch (state) { case WTS_CONNECTSTATE_CLASS.WTSActive: return "User logged on"; case WTS_CONNECTSTATE_CLASS.WTSConnected: return "Connected to client"; case WTS_CONNECTSTATE_CLASS.WTSConnectQuery: return "Connecting to client"; case WTS_CONNECTSTATE_CLASS.WTSShadow: return "Shadowing"; case WTS_CONNECTSTATE_CLASS.WTSDisconnected: return "Logged on without client"; case WTS_CONNECTSTATE_CLASS.WTSIdle: return "Waiting for client to connect"; case WTS_CONNECTSTATE_CLASS.WTSListen: return "Listening for connection"; case WTS_CONNECTSTATE_CLASS.WTSReset: return "Being reset"; case WTS_CONNECTSTATE_CLASS.WTSDown: return "Down due to error"; case WTS_CONNECTSTATE_CLASS.WTSInit: return "In initialization"; default: return "Unknown state (error!)"; } } public static string GetMyName() { return GetTSClientName(WTS_CURRENT_SESSION, System.IntPtr.Zero); } } // Class TSManager } // Namespace TerminalServices