Pergunta

Aqui está o cenário:

Você tem um servidor Windows que os usuários se conectar remotamente a via RDP. Você quer que seu programa (que funciona como um serviço) para saber quem está conectado no momento. Isto pode ou não pode incluir uma sessão de console interativo.

Por favor note que este é o não o mesmo que apenas recuperar o usuário interativo atual.

Eu estou supondo que há algum tipo de acesso à API para serviços de terminal para obter esta informação?

Foi útil?

Solução

Aqui está a minha opinião sobre o assunto:

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(Environment.MachineName);
    }

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

    }

  }
}

Outras dicas

Outra opção, se você não quer lidar com o P / Invoca mesmo, seria usar o Cassia biblioteca:

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

Ok, uma solução para a minha própria pergunta.

Você pode usar o WMI para recuperar uma lista de processos em execução. Você também pode olhar para os proprietários desses processos. Se você olhar para os proprietários de "explorer.exe" (e remover as duplicatas) você deve acabar com uma lista de usuários logados.

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;
    }
    }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top