Mi sembra ieri che mi sono affacciato al "blogging", con un timido chi sono consapevole che l'onere che mi stavo assumendo era comunque sottovalutato, ed oggi, a distanza di alcuni mesi, 4 per l'esattezza, mi ritrovo a festeggiare il 100esimo post. Lo so, spesso e volentieri vi ho tediato con i miei sfoghi radicali, ma guardando ora nella console dello spendido tool che ci ha regalato l'ugi, mi rendo conto che comunque la maggioranza dei miei post sono dedicati a .NET.

Perciò, per festeggiare il numero 100, ho deciso di trovare qualcosa di succulento, che spero vi faccia piacere. Per tutta la giornata ho rinuciato a postare, per riservare questo numero a qualcosa che fosse un po' più che banale. E infine, spero di esserci riuscito, e vi ho preparato una classe che fa qualcosa di speciale, almeno a giudicare la fatica che ho dovuto fare a trovare la soluzione nella rete.

Dovete sapere che sto lavorando ad un software gestionale nel settore della sanità, che verrà utilizzato per mezzo di Terminal Server. Questo gestionale, oltre a profilare l'utente, necessita anche di riconoscere il terminale che è connesso, per adattare ad esso le proprie funzionalità. Il problema è che se provate a fare un po' di googling per cercare come si fa a conoscere anche solo l'indirizzo ip del client, presto vi renderete conto che se la soluzione esiste, di certo non sono in molti a conoscerla.

La classe che qui ho linkato ottiene questo risultato, per mezzo delle API esposte da wts32api.dll. Ho tentato in vari modi di ottenere quello che stavo cercando, (WMI è uno di questi) perfino qualche pazzoide suggeriva di usare netstat per conoscere l'ip della macchina collegata alla porta 3389, dimenticando che comunque non si sarebbe riusciti a sapere esattamente come fare corrispondere gli ip trovati alle varie sessioni... ed ecco il metodo che compie la magia:

private object GetSessionData( WtsInfoClass infoClass, Type type )
{
   // puntatore al buffer
   IntPtr ppBuffer = IntPtr.Zero;
   // numero di byte restituiti
   uint
pBytesReturned = 0;
   // eseguo la query
   if
( WTSQuerySessionInformation( IntPtr.Zero,
      unchecked( (uint
)WTS_CURRENT_SESSION ),
      infoClass,
      out
ppBuffer,
      out
pBytesReturned ) != 0 )
   {
      // converto il valore al tipo richiesto
      if ( type == typeof( string
) )
         return
Marshal.PtrToStringAuto( ppBuffer );
      else
         return
Marshal.PtrToStructure( ppBuffer, type );
   }
   // null se non trovo nulla
   return null
;
}

Si tratta di un metodo generico che richiede in input il dato che si deridera cercare. Tra quelli disponibili segnalo WTSClientName, WTSSessionId e WTSClientAddress. Questi tre vengono usati nella mia classe TerminalServerClient per ottenere rispettivamente il nome del client, l'id della sessione e l'indirizzo ip (tra i tre è questo il più difficile da trovare).

Se vi interessa, la classe completa la trovate qui. Si tratta di un singleton, perciò per usarla dovete fare così:

[STAThread]
static void Main(string
[] args)
{
   Console.WriteLine( TerminalServerClient.Current.SessionId );
   Console.WriteLine( TerminalServerClient.Current.Name );
   Console.WriteLine( TerminalServerClient.Current.IPAddress );
}

Infine una curiosità. se quello di cui avete bisogno è il nome della macchina, e tutto il resto non vi importa, allora basta una sola riga di codice per ottenerlo:

Console.WriteLine( Environment.GetEnvironmentVariable( "CLIENTNAME" ) );

Spero apprezziate il regalo di compleblog...