Home | Chi sono | Contattami
 

Progr. lineare

Delphi
 
Componenti
  Database
 
Miei articoli

Windows

Miei articoli 

 

Le API dei Terminal Services


In questo articolo ho raccolto una serie di esempi di utilizzo delle api di Windows dedicate ai servizi terminal per la realizzazione di uno strumento analogo a "gestione servizi terminal". Anzitutto bisogna munirsi di una Unit che contenga la traduzione in Delphi dell' header che contiene la dichiarazione delle api di Windows in questione: la soluzione il sito www.delphi-jedi.org dove possibile scaricare tutte le unit Delphi che contengono le dichiarazioni di tutte le api di Windows. Click sul link

JEDI API Library (package JEDI API Windows Headers (JWAPI))
 

ed il gioco fatto. Scompattiamo il tutto in una cartella locale a piacimento ed aggiungiamo tale cartella al Library Path (Tools -> Environment Options -> Library). La unit che fa al caso nostro JwaWtsApi32.

1. Dato un nome di dominio enumerare tutti i server con attivo il "servizio terminal"

Per enumerare i server terminal nel contesto di un dominio si usa l' API win32 WTSEnumerateServers

function WTSEnumerateServers( pDomainName: pChar; //nome del dominio Reserved: cardinal; //deve essere settata a 0 Version: cardinal; //deve essere settata a 1 var ppServerInfo: PWTS_SERVER_INFOA; //informazioni sul server var pCount: cardinal //numero di server terminal //presenti nel dominio in questione ): Boolean; stdcall;

PWtsServerInfo un tipo puntatore al record

_WTS_SERVER_INFOA = record pServerName: pChar; // Nome NETBIOS del server end;

procedure ElencoServer(NomeDominio: string); var pServerInfo: PWtsServerInfo; //caratteristiche del server CountServers: Cardinal; //numero di server nel dominio NomeDominio //su cui attivo il servizio terminal i, j: integer; hServer: Cardinal; //identificativo univoco del server ServerName: PChar; //nome NETBIOS del server begin WTSEnumerateServers(NomeDominio, 0, 1, pServerInfo, CountServers); for i := 0 to CountServers - 1 do begin ServerName := (PWtsServerInfo(pChar(pServerInfo) + i * sizeof(TWtsServerInfo)))^.pServerName; ShowMessage(ServerName); end; WTSFreeMemory(pServerInfo); end;

2. Dato un nome di server enumerare tutte le sessioni sul quel server

Per enumerare le sessioni nel contesto di un server terminal si usa l' API win32 WTSEnumerateSessions

function WTSEnumerateSessions( hServer: Cardinal; //handle del server terminal //(ottenuto con WTSOpenServer(pChar(NomeServer))) Reserved: Cardinal; //deve essere settato a 0 Version: Cardinal; //deve essere settato a 1 var ppSessionInfo: PWTS_SESSION_INFOA; //informazioni sulla sessione var pCount: Cardinal //numero di sessioni ): Boolean; stdcall;

PWTS_SESSION_INFOA un tipo puntatore al record

_WTS_SESSION_INFOA = record SessionId: cardinal; // identificativo univoco della sessione nel contesto del server pWinStationName: pChar; // puntatore ad una stringa che identifica il nome //della sessione terminal (RDP-Tcp#) State: WTS_CONNECTSTATE_CLASS; // stato della connessione end;

  • sessionId: l' identificativo di sessione: un intero che identifica univocamente la sessione nel contesto di un server
  • pWinstationName: nome della WinStation a cui connessa questa sessione: assume valori del tipo RDP-Tcp#<numero> dove il valore di <numero> non ha nulla a che vedere con l' Id di sessione. Facciamo un esempio: supponiamo che ci siano varie sessioni terminal aperte su un server: tra queste ne consideriamo 2, una aperta dall' utente Carlo e l' altra dall' utente Chiara. La prima ha un nome di Winstation pari a RDP-Tcp#156 mentre la seconda ha un nome di Winstation pari a RDP-Tcp#187. Supponiamo che Carlo sia un utente con l' autorizzazione Connetti e sia quindi in grado di connettersi ad altre sessioni: apre "gestioni servizi terminal", seleziona la sessione RDP-Tcp#187 (quella aperta dall' utente Chiara), pulsante destro, Connetti. A questo punto la sessione aperta in origine da Carlo viene disconnessa e la sessione in origine aperta da Chiara assume nome di Winstation pari a RDP-Tcp#156
  • State: stato della connessione (Connessa, Disconnessa, Pausa, etc)

procedure EnumeraSessioni(NomeServer: string); var CountSessions: cardinal; //numero sessioni i, j: integer; hServer: THandle; //identificativo univoco del server pBuffer: Pointer; pBytesreturned: cardinal; begin hServer := WTSOpenServer(pChar(NomeServer)); WTSEnumerateSessions(hServer, 0, 1, pSessionInfo, CountSessions); for j := 0 to CountSessions - 1 do begin with (PWtsSessionInfo(pChar(pSessionInfo) + j * sizeof(TWtsSessionInfo)))^ do begin if SessionId = 0 then //sessione console begin NomeNodo := 'Console'; end else begin case State of WTSListen: NomeNodo := 'RDP-Tcp (Ascoltatore)'; WTSIdle: NomeNodo := '(Pausa)'; WTSShadow: NomeNodo := pWinStationName + ' (shadow)'; WTSDown: NomeNodo := '(Gi)'; WTSInit: NomeNodo := '(Init)'; WTSReset: NomeNodo := '(Reset)'; WTSConnectQuery: NomeNodo := '(ConnectQuery)'; WTSDisconnected: NomeNodo := 'Disconnesso'; else begin NomeNodo := pWinStationName; end; if State = WTSActive then NomeNodo := NomeNodo + ' (Attiva)'; end; NomeNodo := 'Id. Sessione := ' + IntToStr(SessionId) + ' ' + NomeNodo; end; end; WTSCloseServer(hServer); WTSFreeMemory(pSessionInfo); end;

3. Data una sessione elencarne le caratteristiche

Si usa l' API WTSQuerySessionInformation

function WTSQuerySessionInformation( hServer: Cardinal; //handle del server terminal //(ottenuto con WTSOpenServer(pChar(NomeServer))) SessionId: Cardinal; //Identificativo univoco della sessione //nel contesto del server terminal WTSInfoClass: WTS_INFO_CLASS; //tipo enumerativo che indica l' informazione //che si vuole ottenere sulla sessione var pBuffer: Pointer; //puntatore all' informazione richiesta var pBytesReturned: Cardinal //dimensione totale dell' informazione richiesta ): Boolean; stdcall;

procedure CaratteristicheSessione(NomeServer: string; SesId: cardinal); //NomeServer: server di riferimento //SesId: identificativo univoco della sessione che ci interessa, nel server di riferimento var hServer: cardinal; pBuffer: Pointer; pBytesreturned: cardinal; i: integer; begin hServer := WTSOpenServer(pChar(NomeServer)); //elenco di chiamate all' API WTSQuerySessionInformation con i vari valori di WTSInfoClass: //WTSQuerySessionInformation(hServer, SesId,, pBuffer, pBytesReturned); WTSCloseServer(hServer); end;

andiamo di seguito ad elencare i vari valori del tipo enumerativo _WTS_INFO_CLASS ed il conseguente contenuto di pBuffer

WTSInitialProgram

pBuffer
contiene un puntatore ad una stringa che definisce il programma che viene eseguito all'apertura di una sessione terminal

showMessage('InitialProgram: ' + pChar(pBuffer));

WTSApplicationName

pBuffer contiene un puntatore ad una stringa che definisce il nome del programma che esegue la sessione terminal; se la sessione di riferimento la sessione console allora il puntatore nullo

showMessage('ApplicationName: ' + pChar(pBuffer));

WTSWorkingDirectory

pBuffer contiene un puntatore ad una stringa che definisce la cartella di lavoro utilizzata quando viene lanciato il programma definito da WTSInitialProgram

showMessage('WorkingDirectory: ' + pChar(pBuffer));

WTSOEMId

non usato

WTSSessionId

pBuffer contiene un puntatore ad un intero che definisce l' identificativo univo della sessione nel contesto del server

showMessage('SessionId: ' + IntToStr(integer(pBuffer^)));

WTSUserName

pBuffer contiene puntatore ad una stringa che definisce il nome dell' utenza che ha aperto la sessione terminal

showMessage('UserName: ' + pChar(pBuffer));

WTSWinStationName

pBuffer contiene un puntatore ad una stringa che identifica il nome della sessione terminal (RDP-Tcp#<numero>)

showMessage('WinstaName: ' + pChar(pBuffer));

WTSDomainName

pBuffer contiene un puntatore ad una stringa che identifica il nome del dominio di appartenenza del server in cui gira la sessione terminal

showMessage('DomainName: ' + pChar(pBuffer));

WTSConnectState

pBuffer
contiene un puntatore al tipo enumerativo TWtsConnectStateClass che definisci i vari possibili stati di una sessione terminal

function ConnectState(ConnectState: TWtsConnectStateClass): string; begin case ConnectState of WTSActive: Result := 'Attiva'; WTSConnected: Result := 'Connessa'; WTSConnectQuery: Result := 'In corso di connessione'; WTSShadow: Result := 'In controllo remoto'; WTSDisconnected: Result := 'Disconnessa'; WTSIdle: Result := 'Pausa'; WTSListen: Result := 'Ascoltatore'; WTSReset: Result := 'Reimpostata'; WTSDown: Result := 'Gi'; WTSInit: Result := 'Inizializzazione'; end; end; ShowMessage(ConnectState(TWtsConnectStateClass(pBuffer^)));

WTSClientBuildNumber

pBuffer contiene un puntatore ad un intero che identifica il tipo di applicativo usato per effettuare la connessione al terminal server: ad esempio utilizzando l' applicativo presente in Windows XP e scaricabile da Internet si ha 2600, usando invece l' applicativo presente nel CD di Windows 2000 Server si ha 2242, usando invece il client rdesktop presente in Linux Mandrake 9 si ha 419

showMessage('ClientBuildNumber: ' + IntToStr(integer(pBuffer^)));

WTSClientName

pBuffer contiene un puntatore ad una stringa che identifica il nome NETBIOS della macchina che ha aperto la sessione terminal

showMessage('ClientName: ' + pChar(pBuffer));

WTSClientDirectory

pBuffer contiene un puntatore ad una stringa che identifica la dll che implementa l' applicativo client per la connessione terminal su Windows XP di default sar C:\WINDOWS\system32\mstscax.dll, su Windows 2000 C:\WINNT\system32\mstscax.dll. Se ad esempio scarico da internet una versione aggiornata di mstscax.dll, me la salvo dentro e:\software\terminal_services e mi collegao utilizzando questa nuova versione, allora la stringa ottenuta sar
e:\software\terminal_services\mstscax.dll

showMessage('ClientDirectory: ' + pChar(pBuffer));

WTSClientProductId

pBuffer contiene un puntatore ad un intero che identifica il tipo di client

showMessage('ClientProductId: ' + IntToStr(integer(pBuffer^)));

WTSClientHardwareId

pBuffer contiene un puntatore ad un intero che identifica il tipo di hardware del client

showMessage('ClientHardwareId: ' + IntToStr(integer(pBuffer^)));

WTSClientAddress

pBuffer contiene un puntatore al record _WTS_CLIENT_ADDRESS definito nel seguente modo

_WTS_CLIENT_ADDRESS = record AddressFamily: Cardinal; // AF_INET, AF_IPX, AF_NETBIOS, AF_UNSPEC Address: array [0..19] of BYTE; // indirizzo IP del client end;

I 4 numeri che vanno a definire l' indirizzo IP sono gli elementi di posizione 2,3,4,5 (indice su base 0) dell' arrary Address
Non sempre possibile ottenere l' indirizzo IP: ad esempio con il client rdesktop di Mandrake Linux 9 (WTSClientBuildNumber restituisce valore 419) non si ottiene un indirizzo IP corretto; con i client Microsoft (WTSClientBuildNumber restituisce valore 2242 o 2600) comunque tutto OK.

PWtsClientAddress un tipo puntatore a _WTS_CLIENT_ADDRESS

with PWtsClientAddress(pBuffer)^ do begin ShowMessage('ClientAddress: ' + IntToStr(Address[2]) + '.' + IntToStr(Address[3]) + '.' + IntToStr(Address[4]) + '.' + IntToStr(Address[5])); end;

WTSClientDisplay

pBuffer contiene un puntatore al record _WTS_CLIENT_DISPLAY definito nel seguente modo

_WTS_CLIENT_DISPLAY = record HorizontalResolution: Cardinal; // larghezza in pixels VerticalResolution: Cardinal; // altezza in pixels ColorDepth: Cardinal; end;

tale record definisce le impostazioni dello schermo lato client ColorDepth restituisce un intero che definisce il numero di colori nel seguente modo

function ColorsNumber(ColorDepth: integer): string; begin case ColorDepth of 1: Result := '16 colori'; 2: Result := '256 colori'; 4: Result := '2^16 colori'; 8: Result := '2^24 colori'; 16: Result := '2^15 colori'; end; end; with PWtsClientDisplay(pBuffer)^ do begin ShowMessage('ClientDisplay: ' + IntToStr(HorizontalResolution) + 'x' + IntToStr(VerticalResolution) + ' (' + ColorsNumber(ColorDepth) + ')' ); end;

WTSClientProtocolType

pBuffer contiene un puntatore ad un intero che definisce il protocollo usato per l' apertura della sessione terminal nel seguente modo

function ProtocolType(Tipo: integer): string; begin case Tipo of WTS_PROTOCOL_TYPE_CONSOLE: 'console'; WTS_PROTOCOL_TYPE_ICA: 'ICA'; WTS_PROTOCOL_TYPE_RDP: 'RDP'; end; end; ShowMessage(ProtocolType(integer(pBuffer^)))

3. Enumerare i processi

Si usa l' API WTSEnumerateProcesses

function WTSEnumerateProcesses( hServer: Cardinal; //handle del server terminal //(ottenuto con WTSOpenServer(pChar(NomeServer))) Reserved: Cardinal; //deve essere settato a 0 Version: Cardinal; //deve essere settato ad 1 var ppProcessInfo: PWTS_PROCESS_INFOA; //informazioni sul processo var pCount: Cardinal //elenco dei processi ): Boolean; stdcall;

PWTS_PROCESS_INFOA un tipo puntatore a

_WTS_PROCESS_INFOA = record SessionId: Cardinal; // identificativo univoco della sessione nel contesto del server terminal ProcessId: Cardinal; // Process Id pProcessName: pChar; // puntatore ad una stringa che definisce il nome del processo pUserSid: PSID; // puntatore al SID dell' utente end;

procedure ElencoProcessi() var i: integer; CountProcesses: integer; pProcessInfo: PWtsProcessInfo; begin WTSEnumerateProcesses(hServer, 0, 1, pProcessInfo, CountProcesses); for i := 0 to CountProcesses - 1 do begin with (PWtsProcessInfo(pChar(pProcessInfo) + i * sizeof(TWtsProcessInfo)))^ do begin if (SessionId = SesId) then ShowMessage(IntToStr(SessionId) + '---' + IntToStr(ProcessId) + '---' + pProcessName); end; end; end;

 

 

 

 

 

 

 

 

 

 

 

 


 

 

 


 

 
 
Your Ad Here