Home | Chi sono | Contattami
 

Progr. lineare

Delphi
 
Componenti
  Database
 
Miei articoli

Windows

Miei articoli 

 

Window Stations e Desktops


In questo articolo vengono esaminati i concetti di Sessione, Window Station e Desktop, concetti che, come vedremo hanno un rapporto di inclusione l'uno con l'altro.

1. Sessioni

Con i seguenti sistemi operativi è possibile avere più sessioni interattive aperte contemporaneamente: Windows 2003 server, Windows 2000 server, Windows XP. Bene: come fare per enumerare le sessioni interattive aperte in un dato istante? Si può usare l' api WTSEnumerateSessions

1.1 Enumerare le sessioni

Come già detto nell'introduzione, si può usare l'api win32 WTSEnumerateSessions: rimando all'articolo API dei Terminal Services in cui la funzione viene descritta con dovizia di dettagli. Come si può vedere dall'articolo stesso, la funzione consente l'enumerazione delle sessioni interattive e la restituzione per ognuna delle caratteristiche corrispondenti.

Di seguito la composizione di una Sessione

  • Una o più Window Sations

Bene. Vediamo cosa sono queste Window Stations

2. Window Stations

Di seguito la composizione di una Window Station

  • Una Clipboard
  • Una Tabella di ATOM
  • Uno o più Desktop
     

2.1 Enumerare le Window Stations in una Sessione

Si usa l'api Win32 EnumWindowStations così definita

type TFNWinStaEnumProc = function (lpszWindowStation: PAnsiChar; lP: Integer ): Boolean; stdcall; function EnumWindowStations(lpEnumFunc: TFNWinStaEnumProc; lParam: Integer): Boolean; stdcall;

  • lpEnumFunc: funzione di callback che viene chiamata per ogni Window Station rilevata: gli viene in pratica assegnata una funzione scritta da noi in cui andiamo a definire il comportamento in corrispondenza di ogni Window Station (ad es. enumerare i Desktops contenuti o altro)
  • lParam: parametro il cui valore viene passato al parametro lP della funzione di callback

N.B. la funzione EnumWindowStations non contiene un parametro per specificare la sessione di riferimento e quindi restituisce il risultato relativo alla sessione corrente. Vediamo ora cosa sono i Desktop

3. Desktops

Di seguito la composizione di un Desktop

  • Finestre
  • Menù
  • Hooks

3.1 Enumerare i Desktops in una Window Stations

Si usa l'api win32 EnumDesktops così definita

function EnumDesktopProc(lpszDesktop: PAnsiChar; lP: Integer ): Boolean; stdcall; function EnumDesktops(hwinsta: Cardinal; lpEnumFunc: TFNDeskTopEnumProc; lParam: Integer): Boolean; stdcall;

  • hwinsta: handle alla Window Station di cui si vogliono enumerare i Desktop; questo valore può essere ad esempio ottenuto tramite chiamata all'api win32 OpenWindowStation
  • lpEnumFunc: funzione di callback che viene chiamata per ogni Desktop rilevato: gli viene in pratica assegnata una funzione scritta da noi in cui andiamo a definire il comportamento in corrispondenza di ogni Desktop (ad es. enumerare le finestre contenute o altro)
  • lParam: parametro il cui valore viene passato al parametro lP della funzione di callback

Una Window Station può contenere più di un Desktop, tuttavia vi sarà sempre un solo oggetto Desktop che rappresenta l' interfaccia utente e riceve input dall' utente stesso: tale Desktop viene detto Input Desktop.

4. Esempio

Ecco un esempio di enumerazione di Windows Stations e Desktop nell'ambito della sessione corrente

unit uMain; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TfrmMain = class(TForm) btnEnum: TButton; mmoElenco: TMemo; procedure btnEnumClick(Sender: TObject); private { Private declarations } public { Public declarations } end; var frmMain: TfrmMain; implementation {$R *.dfm} procedure ScriviLog(val: string); begin frmMain.mmoElenco.Lines.Add(val); end; function EnumDesktopProc(lpszDesktop: LPTSTR; lP: LPARAM ): BOOL; stdcall; var hD: HDESK; begin ScriviLog( ' ' + lpszDesktop ); hD := OpenDesktop( lpszDesktop, 0, False, DESKTOP_ENUMERATE ); if hD <> 0 then begin //posso ad esempio enumerare le finestre contenute nel Desktop //EnumDesktopWindows( hD, @EnumWindowsProc, 0 ); CloseDesktop( hD ); end else begin ScriviLog(' - Fallimento nell'' apertura del desktop - ' + SysErrorMessage(GetLastError)); end; Result := True; end; function EnumWindowStationProc(lpszWindowStation: LPTSTR; lP: LPARAM ): BOOL; stdcall; var hS: HWINSTA; begin ScriviLog(lpszWindowStation); hS := OpenWindowStation(lpszWindowStation, False, WINSTA_ENUMDESKTOPS); if hS <> 0 then begin EnumDesktops(hS, @EnumDesktopProc, 0); CloseWindowStation(hS); end else begin ScriviLog(' - Fallimento nell'' apertura della window station - ' + SysErrorMessage(GetLastError)); end; ScriviLog(''); Result := True; end; procedure TfrmMain.btnEnumClick(Sender: TObject); begin // mmoElenco.Lines.Clear; EnumWindowStations(@EnumWindowStationProc, 0); end; end.

5. Analisi del risultato

Chiunque esegua l' esempio al paragrafo 4, constaterà che in linea di massima il risultato deve contenere l' elenco seguente

WinSta0 Default Disconnect - Fallimento nell' apertura del desktop - Accesso negato Winlogon - Fallimento nell' apertura del desktop - Accesso negato Service-0x0-3e7$ - Fallimento nell' apertura del desktop - Accesso negato Service-0x0-3e4$ - Fallimento nell' apertura del desktop - Accesso negato Service-0x0-3e5$ - Fallimento nell' apertura del desktop - Accesso negato SAWinSta SADesktop - Fallimento nell' apertura del desktop - Impossibile trovare il file specificato

Questo è il risultato minimale che si ottiene lanciando il programma nella sessione interattiva principale (la sessione con "Id di sessione" = 0 che è appunto la prima sessione interattiva che viene aperta dall' avvio di Windows). Nella "Sessione 0" vi sono quindi 5 Window Station di base che andiamo ad analizzare nel seguito

5.1 Winsta0

E' l' unica Window Station interattiva che può essere presente in una Sessione; ciò significa che solo in questa Window Station (e quindi nei suoi Desktop) può essere visualizzata una interfaccia utente ed i programmi stessi che girano possono ricevere l' input dell' utente; detta in maniera molto grezza, se abbiamo un programma che consiste ad esempio in una maschera con delle caselle di testo, potremo vedere la maschera (e riempirne le caselle) solo se il programma viene eseguito nella Winsta0. Contiene i seguenti Desktop

  • Default: è il Desktop di default (ogni volta che viene creata una Window Station viene anche creato un oggetto Desktop di default che viene appunto nominato Default): nel caso di Winsta0, Default rappresenta l' interfaccia utente della sessione di lavoro aperta
  • Winlogon: rappresenta l' interfaccia utente in cui si trova la finestra di login per l' inserimento di nome utente e password
  • Disconnect: contiene la finestra che si presenta quando un utente si disconnette

     

5.2 Service-0x0-3e7$

E la Window Station in cui girano i servizi eseguiti con l' utenza SYSTEM. Anch' essa naturalmente (come tutte le Window Station) è dotata di un Desktop che è appunto Default. 3e7$ è appunto il LUID dell' utenza SYSTEM (SID = S-1-5-18).

5.3 Service-0x0-3e4$

E' la Window Station in cui girano i servizi eseguiti con l' utenza SERVIZIO DI RETE. Anch' essa naturalmente (come tutte le Window Station) è dotata di un Desktop che è appunto Default. 3e4$ è appunto il LUID dell' utenza SERVIZIO DI RETE (SID = S-1-5-20).

5.4 Service-0x0-3e5$

E' la Window Station in cui girano i servizi eseguiti con l' utenza SERVIZIO LOCALE. Anch' essa naturalmente (come tutte le Window Station) è dotata di un Desktop che è appunto Default. 3e5$ è appunto il LUID dell' utenza SERVIZIO LOCALE (SID = S-1-5-19).

5.5 SAWinsta

E' la Window Station in cui girano le operazioni pianificate. E' dotata di un Desktop di nome SaWinsta.

6. Approfondiamo

Se, a questo punto, creo una nuova sessione (con Windows XP occorre che sia attivo il "Cambio rapido utente" per avere più sessioni interattive contemporaneamente aperte fermo restando che ne potrà essere usata solo una alla volta) questa diventa la "Sessione 1". Lanciando il programma nella "Sessione 1" il risultato sarà:

WinSta0 Default Disconnect - Fallimento nell' apertura del desktop - Accesso negato Winlogon - Fallimento nell' apertura del desktop - Accesso negato

Si otterrà un risultato analogo aprendo ulteriori sessioni interattive. Questo ci consente di arrivare ad una prima conclusione importante relativamente alla composizione delle sessioni Windows che è la seguente:





6.1 Servizi eseguiti con utenza specifica

A questo punto un' altra considerazione importante riguarda i servizi: abbiamo visto le 3 Window Station per i servizi però nel caso in cui si decida di far girare un servizio con una utenza diversa dall' utenza di sistema allora in tal caso verrà creata appositamente una nuova Window Station (e conseguentemente il suo Desktop di default ossia Default) il cui nome sarà dato da:

Service-0xZ1-Z2$

dove Z1 e Z2 sono rispettivamente la high part e la low part del SID dell' utenza in questione. Se più di un servizio è stato impostato per essere eseguito con la medesima utenza allora tutti i servizi in questione lavoreranno nella stessa Window Station creata appositamente con il nome suddetto. Ad esempio mi sono creato un servizio stupidissimo ed ho deciso di farlo eseguire con la mia utenza, poi ho lanciato il programma e appunto è comparsa una nuova Window Station di nome Service-0x0-17c16$.

6.2 Diritti di Accesso su Window Station e Desktop

Bene bene ... a questo punto darei un' occhiata ai Diritti di Accesso su Window Station e Desktop (il fatto stesso che nel risultato sopra ci siano alcuni oggetti che non siano accessibili ci fa capire che queste 2 tipologie di oggetti godono della possibilità di definire su di esse dei Diritti di Accesso proprio come file, cartelle, chiavi di registro, etc...). Partirei proprio dal codice definito inizialmente: sia la OpenWindowStation (utilizzata per ottenere un handle ad una Window Station da usare poi come input per la EnumDesktops) sia la OpenDesktop (utilizzata per ottenere un handle ad un Desktop da usare poi come input ad esempio per la EnumDesktopWindows) prendono in input (precisamente il terzo argomento) un valore che specifica qual è il diritto di accesso richiesto sull' oggetto; nella OpenWindowStation specifichiamo WINSTA_ENUMDESKTOPS che significa che richiediamo di poter enumerare i Desktop di quella Window Station mentre nella OpenDesktop specifichiamo DESKTOP_ENUMERATE che significa che richiediamo di poter enumerare gli oggetto di quel Desktop (ad esempio le finestre tramite EnumDesktopWindows). Per un elenco completo dei diritti di accesso che riguardano una Window Station rimando al seguente link nell' MSDN

Window Station Security and Access Rights

Stessa cosa per i diritti di accesso che riguardano un Desktop

Desktop Security and Access Rights

Per quanto riguarda il fatto che nell' enumerazione alcune Window Station non siano accessibili così come alcuni Desktop, basta scaricarsi Process Explorer: per ogni processo in esecuzione è possibile visualizzare nel pannello in basso le dll o gli handle; visualizzando gli handle si possono reperire queli di tipo Window Station e quelli di tipo Desktop: per ognuno di essi basta fare pulsante destro -> Properties -> tab Protezione ed ecco che compare l' ACL relativa all' oggetto in questione; dallo studio dei 2 link precedenti si vedrà che appunto l' utenza che esegue il programma di enumerazione non è autorizzata ad avere quel tipo di accesso all' oggetto specificato.

7. API

Di seguito una carrellata della api win32 che riguardano window stations e desktops

7.1. Specifiche per le window stations

7.1.1 CreateWindowStation

Crea una window station, la associa al processo corrente e la assegna alla sessione corrente. Restituisce un handle alla window station creata.

type PSecurityAttributes = ^TSecurityAttributes; TSecurityAttributes = record nLength: DWORD; lpSecurityDescriptor: Pointer; bInheritHandle: BOOL; end; function CreateWindowStation(lpwinsta: PChar; dwReserved: Cardinal; dwDesiredAccess: Cardinal; lpsa: PSecurityAttributes): Cardinal; stdcall;

  • lpwinsta: nome da dare alla window station che si vuol creare
  • dwReserved: da settare a 0 (valore riservato)
  • dwDesiredAccess: diritto di accesso del processo chiamante alla window station che si va a creare: ad esempio WINSTA_CREATEDESKTOP per poter creare nuovi Desktop; consultare il Platform SDK per tutti i valori.
  • lpsa: puntatore ad una struttura SECURITY_DESCRIPTOR che consente di definire il tipo di accesso alla window station: se non impostato (nil), il tipo di accesso è GENERIC_ALL per tutti gli utenti (consultare il Platform SDK per approfondimenti)

7.1.2 OpenWindowStation

Restituisce un handle alla window station specificata

function OpenWindowStation(lpszWinSta: PChar; fInherit: Boolean; dwDesiredAccess: Cardinal): Cardinal; stdcall;

  • lpszWinSta: nome della window station (case insensitive)
  • fInherit: specifica se l'handle ottenuto verrà ereditato automaticamente da tutti i processi figli creati dal processo chiamante
  • dwDesiredAccess: diritto di accesso (ad esempio WINSTA_ENUMDESKTOPS ci consente di poter enumerare i Desktop contenuti nella window station tramite l'api win32 EnumDesktops; consultare il Platform SDK per tutti i valori.

7.1.3 CloseWindowStation

Chiude un handle ad una window station (ottenuto ad esempio tramite OpenWindowStation).

function CloseWindowStation(hWinSta: Cardinal): Boolean; stdcall;

  • hWinSta: handle ad una window station

7.1.4 GetProcessWindowStation

Restituisce un handle alla window station in cui è in esecuzione il processo chiamante

function GetProcessWindowStation: Cardinal;

7.1.5 SetProcessWindowStation

Assegna una window station al processo chiamante, consentendo quindi al processo chiamante di accedere agli oggetti contenuti nella window station in questione (Desktops, Clipboard e Global Atoms). La window station deve appartenere alla Sessione del processo chiamante

function SetProcessWindowStation(hWinsta: cardinal): Boolean;

  • hWinsta: handle alla window station che si vuole assegnare al processo chiamante (valore ottenuto tramite CreateWindowStation, OpenWindowStation, GetProcessWindowStation

7.1.6 EnumWindowStation

Vedi il paragrafo 2.1

7.2 Specifiche per i Desktop

7.2.1 CreateDesktop

Crea un nuovo Desktop, lo associa alla window station del processo chiamante e lo assegna al thread chiamante

type PSecurityAttributes = ^TSecurityAttributes; TSecurityAttributes = record nLength: Cardinal; lpSecurityDescriptor: Pointer; bInheritHandle: Boolean; end; function CreateDesktop(lpszDesktop: PChar; lpszDevice: PChar; pDevmode: PDeviceMode; dwFlags: Cardinal; dwDesiredAccess: Cardinal; lpsa: PSecurityAttributes): Cardinal; stdcall;

  • lpszDesktop: nome del Desktop che si vuole creare
  • lpszDevice: settarlo a nil;
  • pDevmode: settarlo a nil;
  • dwFlags: valori: 0, 1 (vedre il Platform SDK per approfondimenti)
  • dwDesiredAccess: diritti di accesso del processo chiamante al Desktop che si va a creare (vedi Platform SDK)
  • lpsa: puntatore ad una struttura di tipo SECURITY_DESCRIPTOR che definisce il tipo di accesso al Desktop che si va a creare (vedi Platform SDK)

7.2.2 OpenDesktop

Restituisce un handle al Desktop specificato

function OpenDesktop(lpszDesktop: PChar; dwFlags: Cardinal; fInherit: Boolean; dwDesiredAccess: Cardinal): Cardinal; stdcall;

  • lpszDesktop: nome del Desktop (case insensitive)
  • dwFlags: stesso significato del parametro dwFlags della CreateDesktop
  • fInherit: indica se l'handle verrà automaticamente ereditato dai processi figli che verranno creati dal processo chiamante
  • dwDesiredAccess: diritti di accesso del processo chiamante al Desktop

7.2.3 OpenInputDesktop

Come già detto nel paragrafo 3.1, ci possono essere vari Desktop in una window station ma solo uno di questi può rappresentare l'interfaccia utente e ricevere l'input dell'utente: l'Input Desktop .

La OpenInputDesktop restituisce un handle all'Input Desktop

function OpenInputDesktop(dwFlags: Cardinal; fInherit: Boolean; dwDesiredAccess: Cardinal): Cardinal; stdcall;

Valgono le stesse considerazione fatte per OpenDesktop

7.2.4 CloseDesktop

Chiude un handle ad un Desktop (ottenuto ad esempio tramite OpenDesktop): N.B. non specificare come handle il valore restituito dalla GetThreadDesktop (vedi paragrafo successivo)

function CloseDesktop(hDesktop: Cardinal): Boolean; stdcall;

7.2.5 GetThreadDesktop

Restituisce un handle al Desktop assegnato al thread specificato

function GetThreadDesktop(dwThreadId: Cardinal): Cardinal; stdcall;

  • dwThreadId: Thread ID (TID) del thread (restituito ad esempio dall'api win32 GetCurrentThreadId nel caso del thread chiamante)

7.2.6 SetThreadDesktop

Assegna il Desktop specificato al thread chiamante

function SetThreadDesktop(hDesktop: Cardinal): Boolean; stdcall;

  • hDesktop: handle al Dekstop che si vuole assegnare al thread chiamante (valore che può essere ottenuto tramite CreateDesktop, OpenDesktop, OpenInputDesktop o GetThreadDesktop)

7.2.7 EnumDesktops

Vedi paragrafo 3.1

7.2.8 EnumDesktopWindows

Enumera le finestre contenute in un Dekstop; la tipologia è analoga alle funzioni di enumerazione descritte in precedenza (EnumWindowStations e EnumDesktops): si utilizza quindi anche in questo caso un puntatore ad una funzione di callback

function EnumDesktopWindows(hDesktop: cardinal; lpfn: TFNWndEnumProc; lParam: LPARAM): boolean; stdcall;

  • hDesktop: handle al Desktop di cui si vogliono enumerare le finestre: nelle funzioni usate per ottenere l'handle (CreateDesktop, OpenDesktop, OpenInputDesktop o GetThreadDesktop) bisogna specificare il diritto di accesso (parametro dwDesiredAccess) DESKTOP_ENUMERATE
  • lpfn: puntatore a procedura di callback (vedere la definizione di EnumWindowStations e EnumDesktops)
  • lParam: parametro che verrà passato alla procedura di callback puntata da lpfn

7.2.9 SwitchDesktop

Rende un Desktop, l'Input Desktop; il Desktop deve essere associato alla window station in cui è in esecuzione il processo chiamante

function SwitchDesktop(hDesktop: Cardinal): Boolean; stdcall;

  • hDesktop: handle del Desktop che si vuole rendere Input Desktop; nelle funzioni usate per ottenere l'handle (CreateDesktop, OpenDesktop) bisogna specificare il diritto di accesso (parametro dwDesiredAccess) DESKTOP_SWITCHDESKTOP  

7.3 Comuni sia a window stations e desktops

7.3.1 GetUserObjectInformation

Restituisce un determinato tipo di informazione (definibile tramite uno dei parametri) relativamente ad una window station o ad un desktop.

function GetUserObjectInformation(hObj: Cardinal; nIndex: Integer; pvInfo: Pointer; nLength: Cardinal; var lpnLengthNeeded: Cardinal): Boolean; stdcall;

  • hObj:[input] handle ad una window station o ad un desktop
  • nIndex:[input] tipo di informazione che deve essere restituita: l'informazione verrà restituita nel buffer puntato da pvInfo
  • pvInfo:[input] puntatore al buffer in cui verrà memorizzata l'informazione richiesta
  • nLength:[input] dimensione del buffer puntato da pvInfo
  • lpnLengthNeeded:[output] variabile che riceve la dimensione del buffer richiesto per memorizzare l'informazione richiesta; come nel caso di molte altre api win32 che hanno una struttura analoga, la prassi consiste nel chiamare la funzione settando a 0 il parametro nLength; in questo modo la variabile lpnLengthNeeded riceverà la dimensione dell'informazione richiesta

Esaminiamo ora i valori possibili da assegnare al parametro nIndex (ossia le tipologie di informazione)

  1. UOI_FLAGS: valore intero 1: restituisce le Flags dell'handle in questione (parametro dwFlags presente nelle api descritte in precedenza): pvInfo deve puntare ad una struttura di tipo USEROBJECTFLAGS  (vedi Platform SDK)
  2. UOI_NAME: valore intero 2: restituisce una stringa che definisce il nome dell'oggetto (es. winsta0 nel caso di window station oppure winsta0\default nel caso di desktop)
  3. UOI_TYPE: valore intero 3: restituisce una stringa che definisce il tipo dell'oggetto (es. windowstation o desktop)
  4. UOI_USER_SID: valore intero 4: restituisce il SID che è associato all'oggetto in questione

Di seguito 2 procedure per ottenere le informazioni 2 e 3 (nome e tipo dell'oggetto)

function GetObjectName(hValue: Cardinal): string; var L, LN: Cardinal; Buffer: string; begin Result := ''; L := 0; LN := 0; GetUserObjectInformation(hValue, UOI_NAME, nil, L, LN); SetLength(Buffer, LN); L := LN; if GetUserObjectInformation(hValue, UOI_NAME, PChar(Buffer), L, LN) then begin SetLength(Buffer, StrLen(PChar(Buffer))); Result := Buffer; end; end; function GetObjectType(hValue: Cardinal): string; var L, LN: Cardinal; Buffer: string; begin Result := ''; L := 0; LN := 0; GetUserObjectInformation(hValue, UOI_TYPE, nil, L, LN); SetLength(Buffer, LN); L := LN; if GetUserObjectInformation(hValue, UOI_TYPE, PChar(Buffer), L, LN) then begin SetLength(Buffer, StrLen(PChar(Buffer))); Result := Buffer; end; end;

7.3.2 GetUserObjectSecurity

Restituisce informazioni di sicurezza relativamente all'oggetto specificato; di seguito la dichiarazione della funzione e la definizione di tutti i tipi associati

type PSID_IDENTIFIER_AUTHORITY = ^SID_IDENTIFIER_AUTHORITY; SID_IDENTIFIER_AUTHORITY = record Value: array [0..5] of Byte; end; PSid = ^SID; SID = record Revision: Byte; SubAuthorityCount: Byte; IdentifierAuthority: SID_IDENTIFIER_AUTHORITY; SubAuthority: array [0..0] of Cardinal; //array di qualsiasi dimensione end; PACL = ^TACL; _ACL = record AclRevision: Byte; Sbz1: Byte; AclSize: Word; AceCount: Word; Sbz2: Word; end; TACL = _ACL; ACL = _ACL; SECURITY_DESCRIPTOR_CONTROL = Word; PSECURITY_DESCRIPTOR_CONTROL = ^WORD; PSecurityDescriptor = ^TSecurityDescriptor; _SECURITY_DESCRIPTOR = record Revision: Byte; Sbz1: Byte; Control: SECURITY_DESCRIPTOR_CONTROL; Owner: PSID; Group: PSID; Sacl: PACL; Dacl: PACL; end; TSecurityDescriptor = _SECURITY_DESCRIPTOR; SECURITY_DESCRIPTOR = _SECURITY_DESCRIPTOR; function GetUserObjectSecurity(hObj: Cardinal; var pSIRequested: Cardinal; pSID: PSecurityDescriptor; nLength: Cardinal; var lpnLengthNeeded: Cardinal): Boolean; stdcall;

Ora analizziamo i parametri della funzione GetUserObjectSecurity

  • hObj: handle all'oggetto di cui si vuole prelevare informazione di sicurezza
  • pSIRequested: tipologia di informazione da prelevare; possibili valori sono i seguenti: OWNER_SECURITY_INFORMATION (valore 1), GROUP_SECURITY_INFORMATION (valore 2), DACL_SECURITY_INFORMATION (valore 4), SACL_SECURITY_INFORMATION (valore 8)
  • pSID: puntatore ad una struttura di tipo SECURITY_DESCRIPTOR (informazione che ci viene restituita dalla funzione)
  • nLenght: dimensione del buffer di memoria puntata da pSID
  • lpnLengthNeeded: dimensione dell'informazione che viene restituita; il comportamento di questa funzione è analogo a quello di tante altre api win32 che restituiscono informazioni: settando a 0 il valore di nLength, la funzione fallisce e lpnLengthNeeded riceve la dimensione dell'informazione.

7.3.3 SetUserObjectSecurity

Imposta informazioni di sicurezza relativamente all'oggetto specificato: dichiarazione e definizioni sono analoghe alla GetUserObjectSecurity; rimando pertanto al Platform SDK per approfondimenti.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 
 
Your Ad Here