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...