FAQ DelphiConsultez toutes les FAQ

Nombre d'auteurs : 123, nombre de questions : 920, dernière mise à jour : 8 novembre 2019  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.

Commentez


SommaireSystèmeRéseauRéseau Microsoft (7)
précédent sommaire suivant
 

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 API Active Directory Service Interfaces (ADSI) peuvent être utilisées en lieu et place de celles de LanManager.
Les procédures proposées ici contiennent du code redondant, libre à vous de les améliorer.

Mis à jour le 18 octobre 2013 Laurent Dardenne

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;

Mis à jour le 18 octobre 2013 Pierre Castelain

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;
Exemple :
Code delphi : Sélectionner tout
MessageDlg('Le contrôleur de domaine est : '+GetPDCName('MyDomaine'), mtError,[mbOk], 0);

Mis à jour le 14 janvier 2014 Laurent Dardenne

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;
Exemple :
Code delphi : Sélectionner tout
1
2
ListBox1.Items.Clear; 
 GetServerListNT('MyDomaine',SV_TYPE_NT,ListBox1.Items);

Mis à jour le 14 janvier 2014 Laurent Dardenne

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;
Exemple :
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);

Mis à jour le 14 janvier 2014 Laurent Dardenne

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;
Exemple :
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);

Mis à jour le 14 janvier 2014 Laurent Dardenne

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;
On l'appelle ainsi
Code delphi : Sélectionner tout
EnumererRessources(nil, ListBox1.Items );

Mis à jour le 14 janvier 2014 Laurent Dardenne

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 ça


Réponse à la question

Liens sous la question
précédent sommaire suivant
 

Les 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 © 2019 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.