FAQ DelphiConsultez toutes les FAQ
Nombre d'auteurs : 124, nombre de questions : 934, dernière mise à jour : 23 octobre 2024 Ajouter une question
Cette FAQ a été réalisée à partir des questions fréquemment posées sur les forums Delphi et Delphi et bases de données de www.developpez.com et de l'expérience personnelle des auteurs.
Nous tenons à souligner que cette FAQ ne garantit en aucun cas que les informations qu'elle propose soient correctes. Les auteurs font le maximum, mais l'erreur est humaine. Cette FAQ ne prétend pas non plus être complète. Si vous souhaitez y apporter des corrections ou la compléter, contactez un responsable (lien au bas de cette page).
Nous espérons que cette FAQ saura répondre à vos attentes. Nous vous en souhaitons une bonne lecture.
L'équipe Delphi de Developpez.com.
- Comment utiliser les API réseau NT ?
- Comment obtenir le nom du domaine courant ?
- Comment retrouver le nom du PDC d'un domaine ?
- Comment retrouver la liste des ordinateurs d'un certain type (serveur, workstation, etc) ?
- Comment retrouver les membres d'un groupe local ?
- Comment retrouver les membres d'un groupe global ?
- Comment lister les ressources réseau ?
Vous trouverez dans le fichier (LM.PAS) qui provient du projet JEDI, une unité permettant de gérer les API réseau NT.
Cette unité contient l'ensemble des déclarations du SDK Windows Microsoft, c'est à dire les constantes, les messages d'erreurs, les types particuliers et les déclarations des API LanManager.
Une unité additionnelle, JclLANMan.pas, présente dans le répertoire source de la distribution JCL, contient les déclarations d'API permettant de gérer les groupes et comptes utilisateurs : création, suppression, recherches des nom de groupes, test d'existence de groupe, etc.
La lecture du [URL="http://msdn.microsoft.com/en-us/library/aa370675.aspx">SDK[/URL] est vivement conseillée car il contient de nombreuses informations importantes qui, faute de place, n'ont pas été recopiées.
La plupart de ces API allouent en interne une zone mémoire que le programme appelant doit libérer par l'appel de l'API NetApiBufferFree.
Les types suivants sont utilisés avec les API qui vous sont proposées dans cette FAQ :
Code Delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 | unit Main; interface Uses ...,LM; Type TNomServerNT = array[1..UNCLEN] of widechar; {17} TNomDomainNT = array[1..DNLEN] of widechar; {15} TNomUserNT = array[1..LM20_UNLEN] of widechar; {20} TNomGroupNT = array[1..UNLEN] of widechar; {256} ... |
Les procédures proposées ici contiennent du code redondant, libre à vous de les améliorer.
Voici une fonction permettant de récupérer le nom de l'utilisateur ainsi que le nom de domaine de la connexion courante. Cette fonction est un portage d'une fonction C fournie dans un article disponible sur MSDN (voir ci-dessous).
Cette méthode n'est valable que pour les versions NT de Windows.
Code Delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | uses AccCtrl; type PTOKEN_USER = ^TOKEN_USER; TOKEN_USER = record User: TSIDAndAttributes; end; function GetCurrentUserAndDomain(var User, Domain: string): boolean; var hToken: THandle; ptiUser: PTOKEN_USER; cbti: DWORD; snu: SID_NAME_USE; pcchUser, pcchDomain: DWORD; begin result:= false; hToken:= 0; ptiUser:= nil; cbti:= 0; pcchUser:= 0; pcchDomain:= 0; try { Get the calling thread's access token.} if not OpenThreadToken(GetCurrentThread, TOKEN_QUERY, true, hToken) then begin if GetLastError <> ERROR_NO_TOKEN then exit; { Retry against process token if no thread token exists.} if not OpenProcessToken(GetCurrentProcess, TOKEN_QUERY, hToken) then exit; end; { Obtain the size of the user information in the token.} if GetTokenInformation(hToken, TokenUser, nil, 0, cbti) then { Call should have failed due to zero-length buffer.} exit else begin { Call should have failed due to zero-length buffer.} if GetLastError <> ERROR_INSUFFICIENT_BUFFER then exit; end; { Allocate buffer for user information in the token.} ptiUser:= PTOKEN_USER(HeapAlloc(GetProcessHeap, 0, cbti)); if not Assigned(ptiUser) then exit; { Retrieve the user information from the token.} if not GetTokenInformation(hToken, TokenUser, ptiUser, cbti, cbti) then exit; { Retrieve user name and domain name based on user's SID.} { Delphi adaptation : The first call is used to get the length of the two strings } LookupAccountSid(nil, ptiUser.User.Sid, nil, pcchUser, nil, pcchDomain, snu); Setlength(User, pcchUser); Setlength(Domain, pcchDomain); if not LookupAccountSid(nil, ptiUser.User.Sid, PChar(User), pcchUser, PChar(Domain), pcchDomain, snu) then exit; result:= true; finally { Free resources.} if hToken <> 0 then CloseHandle(hToken); if Assigned(ptiUser) then HeapFree(GetProcessHeap, 0, ptiUser); end; end; |
Pour retrouver le contrôleur principal d'un domaine on utilise la fonction NetGetDCName. Elle reçoit en entrée le nom du domaine où s'effectuera la recherche. Le PDC hébergeant les informations des comptes du domaine (SAM), les échanges d'informations se font donc via le réseau de manière transparente.
La fonction NetGetAnyDCName quant à elle renvoie le nom de n'importe quel contrôleur de domaine, le principal (PDC) ou un de secours/backup (BDC).
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | Uses ...,LM; Function GetPDCName(LDomain:String):String; var PDomainName, Bufptr : Pointer; DomainName : TNomDomainNT; Res : NET_API_STATUS; begin Result:=''; FillChar(DomainName,SizeOF(DomainName),#0); PDomainName:=@DomainName; StringtoWideChar(lDomain,@DomainName,Length(lDomain)+1); try Res:=NetGetDCName('',PDomainName,@bufptr); {Ne peux pas trouver le contrôleur de domaine pour ce domaine ou le nom ne peut être trouvé.} if (( Res=NERR_DCNotFound) or (Res=ERROR_INVALID_NAME) ) then begin Res:=NetGetAnyDCName('',@PDomainName,@bufptr); if Res<>ERROR_SUCCESS then MessageDlg('Impossible de trouver un contrôleur de domaine pour le domaine '+lDomain, mtError,[mbOk], 0); Exit; end; Result:=WideCharToString(Bufptr); Finally NetApiBufferFree(BufPtr); end; end; |
Code delphi : | Sélectionner tout |
MessageDlg('Le contrôleur de domaine est : '+GetPDCName('MyDomaine'), mtError,[mbOk], 0);
Les ordinateurs présents sur le réseau possèdent tous un type particulier, on doit donc utiliser l'API NetServerEnum en précisant le type que l'on souhaite retrouver.
Exemple :
- SV_TYPE_WORKSTATION : Toutes les station de travail uniquement.
- SV_TYPE_SERVER : Toutes les machines qui ont le service Server en cours d'exécution.
- SV_TYPE_SQLSERVER : Tous les serveurs exécutant Microsoft SQL Server
- SV_TYPE_DOMAIN_CTRL : Tous les contrôleurs principaux (Primary domain controller)
- SV_TYPE_DOMAIN_BAKCTRL : Tous les contrôleurs de secours ( Backup domain controller)
- SV_TYPE_ALL : Tous les serveurs
- SV_TYPE_TERMINALSERVER : Tous les serveurs Terminal Server (TSE)
- ...
Note :
La recherche des ordinateurs Citrix Metaframe 1.8 basé sur TSE doit se faire en utilisant l'API WFEnumerateServersA et ce à partir d'un ordinateur Citrix et pas d'une Workstation, cf WFAPI.DLL.
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | Uses ...,LM; procedure GetServerListNT(LDomain:String;ServerType:DWord;lLstServeur:TStrings); var Res : NET_API_STATUS; PDomainName : LPCWSTR; Bufptr : Pointer; LocalPtr : ^byte; Prefmaxlen : Cardinal; Level, Entriesread, Totalentries : DWORD; Resume_handle : PDWORD; Str : String; ServerInfo : TServerInfo100 ; DomainName : TNomDomainNT; I : Word; begin Level:=100; FillChar(DomainName,SizeOF(DomainName),#0); Resume_handle:=0; PDomainName:=@DomainName; Prefmaxlen:=$FFFFFFFF; {max} StringtoWideChar(LDomain,@DomainName,Length(lDomain)+1); Try Res:=NetServerEnum(NIL,Level, Bufptr,Prefmaxlen,Entriesread,Totalentries,ServerType,PDomainName,Resume_handle); LocalPtr:=Bufptr; if (( Res=Error_Success) or (Res=Error_More_Data) ) and (Entriesread>0) Then for I := 0 to EntriesRead - 1 do begin Move(LocalPtr^,ServerInfo,SizeOf(ServerInfo)); Inc(LocalPtr,SizeOf(ServerInfo)); Str:=WideCharToString(ServerInfo.sv100_name); lLstServeur.Add(Str); end; Finally NetApiBufferFree(BufPtr); end; end; |
Code delphi : | Sélectionner tout |
1 2 | ListBox1.Items.Clear; GetServerListNT('MyDomaine',SV_TYPE_NT,ListBox1.Items); |
L'API NetGroupGetUsers permet de récupérer la liste des membres d'un groupe local.
Le paramètre Level détermine le type de détail des informations renvoyées :
- 0 Renvoie l'identificateur de sécurité (SID) associé au membre du groupe local.Dans ce cas le paramètre bufptr pointe sur un enregistrement de type LOCALGROUP_MEMBERS_INFO_0.
- 1 Renvoie l'identificateur de sécurité (SID) et les informations de compte associé au membre du groupe local. Dans ce cas le paramètre bufptr pointe sur un enregistrement de type LOCALGROUP_MEMBERS_INFO_1.
- 2 Renvoie l'identificateur de sécurité (SID) et le nom de domaine associé au membre du groupe local. Dans ce cas le paramètre bufptr pointe sur un enregistrement de type LOCALGROUP_MEMBERS_INFO_2.
- 3 Renvoie le compte et le nom de domaine du membre du groupe local. Dans ce cas le paramètre bufptr pointe sur un enregistrement de type LOCALGROUP_MEMBERS_INFO_3.
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | Uses ...,LM; procedure GetUserLocalGroupList(lDCServer:String;lLocalGroupName:String;lLstUserLocalGroup:TStrings); var Res : NET_API_STATUS; Bufptr : Pointer; LocalPtr : ^byte; Prefmaxlen : Cardinal; Level, Entriesread, Totalentries : DWORD; Resume_handle : PDWORD; PServerName, PLocalGroupName :PWideChar; ServerName : TNomServerNT; LocalGroupName : TNomGroupNT; LocalGroupInfo : TLocalGroupMembersInfo2; I : Word; S : String; begin Level:=2; Resume_handle:=0; FillChar(ServerName,SizeOF(ServerName),#0); FillChar(LocalGroupName,SizeOF(LocalGroupName),#0); PServerName:=@ServerName; PLocalGroupName:=@LocalGroupName; Prefmaxlen:=$FFFFFFFF; {max} StringtoWideChar(lDCServer,@ServerName,Length(lDCServer)+1); StringtoWideChar(lLocalGroupName,@LocalGroupName,Length(lLocalGroupName)+1); Try Res:=NetLocalGroupGetMembers(PServername,PLocalgroupname,Level, Bufptr,Prefmaxlen,Entriesread,Totalentries,Resume_handle); LocalPtr:=Bufptr; if Res=ERROR_ACCESS_DENIED then begin MessageDlg('Droits insuffisant pour lire les membres du groupe local '+lLocalGroupName, mtInformation,[mbOk], 0); Exit; end; if (( Res=Error_Success) or (Res=Error_More_Data) ) and (Entriesread>0) Then for I := 0 to EntriesRead - 1 do begin Move(LocalPtr^,LocalGroupInfo,SizeOf(LocalGroupInfo)); Inc(LocalPtr,SizeOf(LocalGroupInfo)); S:=WideCharToString(LocalGroupInfo.lgrmi2_domainandname); lLstUserLocalGroup.Add(S); end; Finally NetApiBufferFree(BufPtr); end; end; |
Code delphi : | Sélectionner tout |
1 2 3 4 5 | ListBox1.Items.Clear; // Groupe local du poste exécutant l'appel GetUserLocalGroupList(ComputerName,'Administrateurs',ListBox1.Items); // Groupe local du PDC d'un domaine GetUserLocalGroupList(AnsiReplaceStr(GetPDCName('MyDomaine'), '\\',''),'Administrateurs',ListBox1.Items); |
Sous NT la notion de groupe comporte les groupes locaux et globaux, un groupe local pouvant contenir des utilisateurs et d'autre groupes.
L'API NetGroupGetUsers permet de récupérer la liste des membres d'un groupe global :
- Le paramètre EntriesRead contient le nombre d'enregistrement lu.
- Le paramètre Prefmaxlen précise la taille du buffer à allouer pour contenir les enregistrements.
- Le paramètre Resume_Handle doit être à zéro lors du premier appel. Ensuite vous ne devez pas le modifier si vous souhaitez effectuer d'autre appel, cf Error_More_Data.
Si la fonction renvoie Error_More_Data c'est que le buffer est trop petit pour recevoir la totalité des informations des membres du groupe, dans ce cas effectuer d'autres appels tant qu'il reste des informations à lire ou augmentez la taille du buffer.
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | Uses ...,LM; procedure GetUserGlobalGroupList(lDCServer:String;lGroupName:String;lLstUserGroup:TStrings); var Res : NET_API_STATUS; Bufptr : Pointer; LocalPtr : ^byte; Prefmaxlen : Cardinal; Level, Entriesread, Totalentries : DWORD; Resume_handle : PDWORD; Str : String; PServerName, PGroupName :PWideChar; ServerName : TNomServerNT; GroupName : TNomGroupNT; GroupInfo : TGroupInfo0 ; I : Word; begin Level:=0; Resume_handle:=0; FillChar(ServerName,SizeOF(ServerName),#0); FillChar(GroupName,SizeOF(GroupName),#0); PServerName:=@ServerName; PGroupName:=@GroupName; Prefmaxlen:=$FFFFFFFF; {max} StringtoWideChar(lDCServer,@ServerName,Length(lDCServer)+1); StringtoWideChar(lGroupName,@GroupName,Length(lGroupName)+1); Try Res:=NetGroupGetUsers(PServername,PGroupName,Level,Bufptr, Prefmaxlen,Entriesread,Totalentries,Resume_handle); LocalPtr:=Bufptr; if Res=ERROR_ACCESS_DENIED then begin MessageDlg('Droits insuffisant pour lire les membres du groupe global : '+LgroupName, mtInformation,[mbOk], 0); Exit; end; if (( Res=Error_Success) or (Res=Error_More_Data) ) and (Entriesread>0) Then for I := 0 to EntriesRead - 1 do begin Move(LocalPtr^,GroupInfo,SizeOf(GroupInfo)); Inc(LocalPtr,SizeOf(GroupInfo)); Str:=WideCharToString(GroupInfo.grpi0_name); lLstUserGroup.Add(Str); end; Finally NetApiBufferFree(BufPtr); end; end; |
Code delphi : | Sélectionner tout |
1 2 3 4 | ListBox1.Items.Clear; // Groupe Global sur le PDC NT 4.0 GetUserGlobalGroupList(AnsiReplaceStr(GetPDCName('MyDomaine'), '\\',''), 'Admins du domaine',ListBox1.Items); |
Le code suivant permet de lister nos ressources réseaux :
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | Type TNetResources = array[0..0] of TNetResource; pNetResources = ^TNetResources; procedure TForm1.Button1Click(Sender: TObject); begin Button1.Enabled:=False; EnumererRessources( NIL ); ShowMessage('Enumération des ressources réseaux terminée.'); Button1.Enabled:=True; end; procedure TForm1.EnumererRessources( aRessource:pNetResource ); var Handle : THandle; NetResources : pNetResources; S : String; Size,Count, Ret,Index : LongWord; begin if WNetOpenEnum( RESOURCE_GLOBALNET, //Indique l'étendue de l'énumération, ici toutes les ressources. RESOURCETYPE_ANY, 0, aRessource, Handle ) = No_Error then begin Ret := No_Error; Size := 50 * Sizeof( TNetResource ); GetMem( NetResources, Size ); while Ret = No_Error do begin Count := $FFFFFFFF; //paramètre in/out Size := 50 * Sizeof( TNetResource ); //paramètre in/out Ret := WNetEnumResource( Handle, Count, NetResources, Size ); if Ret <> No_Error then Break; for Index := 0 to Count - 1 do begin S:='Type d''affichage '; case NetResources[Index].dwDisplayType of //Type affichage, permet de déterminer //le mode d'affichage approprié à la ressource // Ex : RESOURCEDISPLAYTYPE_TREE peut être visualisé // dans un TListView en mode vsReport... RESOURCEDISPLAYTYPE_GENERIC: S :=S+'Générique'; RESOURCEDISPLAYTYPE_DOMAIN : S :=S+'Domaine'; RESOURCEDISPLAYTYPE_SERVER : S :=S+'Serveur'; RESOURCEDISPLAYTYPE_SHARE : S :=S+'Partage'; RESOURCEDISPLAYTYPE_FILE : S:=S+'Fichier'; RESOURCEDISPLAYTYPE_GROUP : S:=S+'Groupe'; RESOURCEDISPLAYTYPE_NETWORK : S:=S+'Réseau'; RESOURCEDISPLAYTYPE_ROOT : S:=S+'Racine'; RESOURCEDISPLAYTYPE_SHAREADMIN : S:=S+'Partage administrateur'; RESOURCEDISPLAYTYPE_DIRECTORY : S:=S+'Répertoire'; RESOURCEDISPLAYTYPE_TREE : S:=S+'Arbre'; RESOURCEDISPLAYTYPE_NDSCONTAINER : S:=S+'NDSCONTAINER' else S:='inconnu'; end; //Type de la ressource Case NetResources[Index].dwType of //C'est un disque partagé RESOURCETYPE_DISK: S:=S+' [disque]'; //C'est une imprimante partagée RESOURCETYPE_PRINT: S:=S+' [imprimante]'; // Soit disque et imprimante ou aucun des 2. RESOURCETYPE_ANY : S:=S+' [autre]'; else S:=S+' [inconnu] '; end; With NetResources[Index] Do begin ListBox1.Items.Add(Format('%S %S',[S,lpRemoteName])); // Le temps de traitement peut être long (parcours du réseau) Application.ProcessMessages; if dwUsage and ResourceUsage_Container > 0 then Begin ListBox1.Items.Add(' * La dernière ressource est un conteneur, appel récursif.'); EnumererRessources( @NetResources^[Index] ); end else ListBox1.Items.Add('Vous devez vous connecter à la dernière ressource pour l''énumérer.'); end; end; end; WNetCloseEnum( Handle ); FreeMem(NetResources); end; end; |
Code delphi : | Sélectionner tout |
EnumererRessources(nil, ListBox1.Items );
Proposer une nouvelle réponse sur la FAQ
Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour çaLes sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2024 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.