IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Delphi Discussion :

Position du Try


Sujet :

Langage Delphi

  1. #1
    Membre expert
    Avatar de Charly910
    Homme Profil pro
    Ingénieur TP
    Inscrit en
    Décembre 2006
    Messages
    2 344
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur TP
    Secteur : Bâtiment Travaux Publics

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 344
    Points : 3 122
    Points
    3 122
    Par défaut Position du Try
    Bonjour,

    A la compilation de ce code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
      try
        New(Mes_Services);
        Nombre_Srv := 0;
        OctetsNecessaires:=0;
        ResumeHandle := 0;
        if EnumServicesStatus(AHandle_SCM,
                              SERVICE_WIN32, //Uniquement les services, pas les drivers
                              SERVICE_STATE_ALL, // Peut importe l'état
                              Mes_Services^[0],
                              SizeOf(Mes_Services^),
                              OctetsNecessaires,
                              Nombre_Srv,
                              ResumeHandle)
         then
          For i := 0 to Nombre_Srv-1 do
           //List.Add(Mes_Services^[i].lpServiceName);
           List.Add(Mes_Services^[i].lpDisplayName);
         //else GetlastErrorCode
     
       finally
         Dispose(Mes_Services);
       end;
    j'ai un avertissement : La variable Mes_Services n'est peut être pas initialisée

    Est ce que cela veut dire qu'il faut que je mette le New avant le Try ?

    Merci de vos conseils

    A+
    Charly

  2. #2
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 430
    Points
    28 430
    Par défaut
    oui, en supposant que le New() ne fonctionne pas, il ne faut pas faire de Dispose(), il est donc logique de mettre le Try juste après le New() et non juste avant
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  3. #3
    Membre expert
    Avatar de Charly910
    Homme Profil pro
    Ingénieur TP
    Inscrit en
    Décembre 2006
    Messages
    2 344
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur TP
    Secteur : Bâtiment Travaux Publics

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 344
    Points : 3 122
    Points
    3 122
    Par défaut
    Merci Paul

    mais si le new ne fonctionne pas j'ai une erreur à l'exécution ?

    il faudrait ajouter un Try Except ?


    A+
    Charly

  4. #4
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 454
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 454
    Points : 24 866
    Points
    24 866
    Par défaut
    Pour les plus paranos

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    try
      New ou Create
      try
        ...
      finally
        Dispose ou Free
      end;
    except
      on E: EOutOfMemory do  
        ... // euh quoi faire si l'on a plus de RAM accessible ou plus souvent trop de Handle
    end;
    Tu peux effectivement capturer l'erreur pour afficher un message propre mais c'est rare, même sur un D7 sur un Win32 à 500Mo tu pouvais allouer 1930Mo de mémoire, sauf que 99% étant en swap
    La documentation indique que de toute façon, le maximum c'est 256 Ko


    C'est le code de la FAQ : Comment lister les services référencés dans le SCM ?

    Enfin, je dirais que l'on pourrait faire plus simple même si c'est tout aussi faux

    0..512 ça donne 513 ... bon on va garder le 512 pour la suite

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Var 
     Mes_Services : array of TEnumServiceStatus;
    on oublie PNTServices et à la place du New :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SetLength(Mes_Services, 512);
    Ce pointeur sert en réalité à ne pas allouer le tableau sur la pile en utilisant directement un TNTServices, en fait on dirait même un code D3, les tableaux dynamiques ne sont pas apparus dès le début donc on faisait un type de tableau fixe et l'on allouait un pointeur dessus avec un GetMem (voir le code de la TList de D7)

    ET donc

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
                              Mes_Services^[0],
                              SizeOf(Mes_Services^),
    devient
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
                              @Mes_Services[0],
                              SizeOf(TEnumServiceStatus) * 512,
    Et encore, faudrait en réalité séparer la partie tableau de TEnumServiceStatus et la partie donnée des chaines pointées par chaque TEnumServiceStatus
    512 TEnumServiceStatus en 32Bits c'est rien, 512 * 40o, 20480 o c'est pas bcp de données
    40o pour TEnumServiceStatus ça doit pas être loin, deux pointeurs et 7 Dwords soit 9*4 = 36 en 32Bits et 44 en 64Bits

    Pour ma part, je préfèrerais écrire plutôt

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    var
      lpServices: PEnumServiceStatus; // avec PEnumServiceStatus = ^TEnumServiceStatus
    cbBufSize: Integer
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
        cbBufSize := (SizeOf(TEnumServiceStatus) + 256 * 2) * 474;
        GetMem(lpServices, cbBufSize ; // finally avec FreeMem donc !
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
                              lpServices,
                               cbBufSize,
    Ainsi on prévoit 474 emplacement mémoire de TEnumServiceStatus et 474 * 2 * 256 octets pour lpServiceName et lpDisplayName
    Ce qui donne 18960 o + 242688 o = 261648 o qui est tout proche du plafond de 262144 (256Ko)


    Bon et j'ajouterais pas qu'il faut en réalité faire deux appels à EnumServicesStatusA, le premier pour récupérer la taille nécessaire pcbBytesNeeded en ne fournissant pas de buffer puis un second appel
    On voit cela par exemple dans RegEnumValue pour savoir quelle taille de buffer allouée pour récupérer les données d'une valeur binaire.
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  5. #5
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 454
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 454
    Points : 24 866
    Points
    24 866
    Par défaut
    Je n'ai pas testé mais ça donne un truc genre
    Finalement, je l'ai testé, 32 Bits et Delphi 10


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
     
    uses Winapi.WinSvc;
     
     
     
    Procedure Refresh_Liste_Services(AHandle_SCM : SC_Handle; List: TStrings);
    var
      lpServices, lpServiceItem: PEnumServiceStatus; // avec PEnumServiceStatus = ^TEnumServiceStatus
      cbBufSize: DWORD;
      pcbBytesNeeded: DWORD;
      lpResumeHandle: DWORD;
      lpServicesReturned: DWORD;
      Res: Boolean;
      I: Integer;
    begin
           // Premier appel pour déterminer la taille: To determine the required size, specify NULL for this parameter and 0 for the cbBufSize parameter
          cbBufSize := 0;
          lpServices := nil;
          lpResumeHandle := 0; // A pointer to a variable that, on input, specifies the starting point of enumeration. You must set this value to zero the first time this function is called.
          Res := EnumServicesStatus(
           AHandle_SCM,
           SERVICE_WIN32,
           SERVICE_STATE_ALL,
           lpServices^,
           cbBufSize,
           pcbBytesNeeded,
           lpServicesReturned,
           lpResumeHandle);
     
     
          if not Res then
           if GetLastError <> ERROR_MORE_DATA then
             RaiseLastOSError();
     
         cbBufSize := pcbBytesNeeded; // la fameuse Astuce du double appel !
         GetMem(lpServices, cbBufSize) ;
         try
            Res := EnumServicesStatus(
              AHandle_SCM,
              SERVICE_WIN32,
              SERVICE_STATE_ALL,
              lpServices^,
              cbBufSize,
              pcbBytesNeeded,
              lpServicesReturned,
              lpResumeHandle);
     
            if not Res then
               RaiseLastOSError();
     
            lpServiceItem := lpServices; // Second astuce pour se passer de la syntaxe tableau
            for i := 1 to lpServicesReturned do
            begin
              List.Add(lpServiceItem.lpDisplayName); // lpServices. ou lpServices^. Delphi est sympa, il sait faire un déréférencement implicite
              Inc(lpServiceItem);
            end;
          finally
              FreeMem(lpServices);
          end;
    end;
     
    procedure TForm1.Button1Click(Sender: TObject);
    var
      SvcMgr: SC_HANDLE;
    begin
      // Ajout de la description dans services.msc
      SvcMgr := OpenSCManager(nil, nil, SC_MANAGER_ENUMERATE_SERVICE);
      try
           Refresh_Liste_Services(SvcMgr, Memo1.Lines);
      finally
        CloseServiceHandle(SvcMgr);
      end;
    end;

    et encore, on pourrait pousser le vice à gerer lpResumeHandle pour appeler plusieurs fois le code ci-dessus en boucle pour gérer de très grande liste dépassant les 256Ko :

    Citation Envoyé par lpResumeHandle
    On output, this value is zero if the function succeeds. However, if the function returns zero and the GetLastError function returns ERROR_MORE_DATA, this value is used to indicate the next service entry to be read when the function is called to retrieve the additional data.
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  6. #6
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 430
    Points
    28 430
    Par défaut
    voilà, tu as tout ce qu'il faut je pense

    ça savoir aussi qu'une appli Delphi classique possède un gestionnaire d'exception par défaut qui fait un ShowMessage de l'erreur...donc tu aurais un message "Mémoire insuffisante" et voilà tout....mais en effet une erreur d'allocation mémoire sur un si petit nombre d'octets ne présagerait rien de bon de toute façon
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  7. #7
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 454
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 454
    Points : 24 866
    Points
    24 866
    Par défaut
    Par exemple sur mon poste de travail, pcbBytesNeeded retourne 42180 pour un lpServicesReturned à 305 donc clair qu'avec le code de la FAQ, tu es trop juste !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
      ShowMessage(IntToStr(SizeOf(Mes_Services^)));
    Affiche 18468 soit bien 513 * 36 ou 513 * (4+4 + 7*4) pour les pointeurs lpServiceName+lpDisplayName et le record SERVICE_STATUS
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  8. #8
    Membre expert
    Avatar de Charly910
    Homme Profil pro
    Ingénieur TP
    Inscrit en
    Décembre 2006
    Messages
    2 344
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur TP
    Secteur : Bâtiment Travaux Publics

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 344
    Points : 3 122
    Points
    3 122
    Par défaut
    Merci à tous les deux pour toutes ces précisions. C'est vrai qu'avec le double Try on est un peu parano ! Je retiens quand même que le Try de la FAQ est mal placé.

    Avec D7 et W10 le code de la FAQ fonctionne bien, mais je vais regarder celui de ShaiLeTroll

    A+
    Charly

  9. #9
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    322
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Janvier 2009
    Messages : 322
    Points : 310
    Points
    310
    Par défaut
    Je me trompe peut-être mais
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    try 
        Liste=tstringlist.create;
    finally
        Liste.free;
    end;
    puisqu'il peut y avoir théoriquement une erreur à la suite du try alors Liste ne serait pas initialisée

    c'est pour ça le message d'avertissement

    Et ce même si il n'y aucune raison "raisonnable" que le create ne se fasse pas... à moins qu'il n'y ait plus les ressources suffisantes pour créer la liste. Et si tu mets un "try" avant c'est parce que tu crois que ça peut planter, le compilateur n'a pas à juger de ton code.

  10. #10
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 430
    Points
    28 430
    Par défaut
    le problème de ce code est plus profond

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    // Liste est INDETERMINE
      try
        Liste := TStringList.Create; // si le create ne se passe pas bien, Liste est toujours indéterminé
      finally
        Liste.Free; // ici on pourrait avoir à libérer une variable indéterminée !
      end;
    on peut éventuellement faire ceci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
      Liste := nil; // Liste est déterminé
      try
        Liste := TStringList.Create; // Liste est déterminé que cela marche ou pas
      finally
        Liste.Free; // ici Liste est TOUJOURS déterminé
      end;
    mais comme faire un Free sur une instance vide ne sert à rien on préfèrera
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
      Liste := TStringList.Create; // si le create se passe bien, Liste est déterminé
      try  
      finally
        Liste.Free; // ici Liste est TOUJOURS déterminé
      end;
    notez qu'il m'arrive d'utiliser la seconde forme dans certains cas particuliers où la création est faite sous condition, et que si elle est bien crée je veux qu'elle soit détruire, mais c'est rare et il est généralement possible de faire les choses différemment
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
      Liste := nil; // Liste est déterminé
      try
        if Condition then
          Liste := TStringList.Create; 
      finally
        Liste.Free; // ici Liste est TOUJOURS déterminé
      end;

    Alors sur un TStringList les "chances" que ça foire sont limitées, mais c'est aussi une question de bonne pratique et de savoir ce qu'on fait, il n'y a pas lieu de libérer une classe potentiellement indéterminée
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  11. #11
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    322
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Janvier 2009
    Messages : 322
    Points : 310
    Points
    310
    Par défaut
    Toujours aussi précis... Merci Paul!

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [C#] Positions d'Eléments triés d'un dataview
    Par mardoch dans le forum ASP.NET
    Réponses: 16
    Dernier message: 25/09/2011, 02h50
  2. position d'un enregistrement dans une table après tri
    Par jaccess dans le forum Requêtes et SQL.
    Réponses: 3
    Dernier message: 31/03/2009, 14h01
  3. [BINDINGSOURCE] Perte de position lors du tri
    Par freud dans le forum Windows Forms
    Réponses: 6
    Dernier message: 21/12/2007, 11h55
  4. [XSLT] [JavaScript] tri + affichage à partir d'une position
    Par Fabouney dans le forum XSL/XSLT/XPATH
    Réponses: 3
    Dernier message: 21/11/2006, 08h46
  5. Réponses: 3
    Dernier message: 23/02/2006, 18h14

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo