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

Delphi Discussion :

[D6] Comment passer un pointeur sur un enregistrement (record) à une DLL ? [FAQ]


Sujet :

Delphi

  1. #1
    Expert éminent
    Avatar de Lung
    Profil pro
    Analyste-programmeur
    Inscrit en
    Mai 2002
    Messages
    2 664
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France, Haute Savoie (Rhône Alpes)

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

    Informations forums :
    Inscription : Mai 2002
    Messages : 2 664
    Points : 6 967
    Points
    6 967
    Par défaut [D6] Comment passer un pointeur sur un enregistrement (record) à une DLL ?
    Comment passer un pointeur sur un enregistrement (record) à une DLL ?
    Je sèche depuis un moment ...

    Voici une fonction de la DLL (en gros, je remplis mon enregistrement):
    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
     
    procedure GetInfoDemande(pInfoDmd: PInfoDemande);
    var
       i: Integer;
    begin
       if Assigned(FormDemandeExt) then
       begin
          pInfoDmd^.sSociete := PChar(FormDemandeExt.ComboBoxDSociete.Items[FormDemandeExt.ComboBoxDSociete.ItemIndex]);
          pInfoDmd^.sSite := PChar(FormDemandeExt.ComboBoxDSite.Items[FormDemandeExt.ComboBoxDSite.ItemIndex]);
          pInfoDmd^.sTypeDemande := PChar(FormDemandeExt.ComboBoxDTypeDemande.Items[FormDemandeExt.ComboBoxDTypeDemande.ItemIndex]);
     
    ...
     
          SetLength(pInfoDmd^.TabContenantPChar, FormListeContenantExtColisExt.ListBoxContenantSelect.Count);
          for i:=0 to Pred(FormListeContenantExtColisExt.ListBoxContenantSelect.Count) do
             pInfoDmd^.TabContenantPChar[i] := PChar(FormListeContenantExtColisExt.ListBoxContenantSelect.Items[i]);
       end;
    end;
    Les types utilisés (l'enregistrement) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
       TTabChar = array of PChar;
     
       PInfoDemande = ^TInfoDemande;
       TInfoDemande = record
          sSociete, sSite, sTypeDemande, sDateDemande, sService, sDemandeur, sDateRetour: PChar;
          sContenant, sRacine, sFinition, sQuantiteMini, sQuantiteMaxi, sNumCommande, sPorteRetour, sObservation: PChar;
          TabContenantPChar, TabColisPChar: TTabChar;
       end;
    Le code appelant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    var
        _pInfoDemande: PInfoDemande;
    begin
       New(_pInfoDemande);
       try
          GetInfoDemande(_pInfoDemande);      //.La fonction de ma DLL.
          if(_pInfoDemande^.sTypeDemande = '1') then
                ...
       finally
          Dispose(_pInfoDemande);
       end;
    Et là, le if n'est jamais vrai, car la valeur que je teste n'est pas renseignée.
    Il doit y avoir quelque chose que je n'ai pas compris, mais quoi ?

    L'urgent est fait, l'impossible est en cours, pour les miracles prévoir un délai. ___ Écrivez dans un français correct !!

    C++Builder 5 - Delphi 6#2 Entreprise - Delphi 2007 Entreprise - Delphi 2010 Architecte - Delphi XE Entreprise - Delphi XE7 Entreprise - Delphi 10 Entreprise - Delphi 10.3.2 Entreprise - Delphi 10.4.2 Entreprise - Delphi 11.1 Entreprise
    OpenGL 2.1 - Oracle 10g - Paradox - Interbase (XE) - PostgreSQL (15.4)

  2. #2
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    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 459
    Points : 24 873
    Points
    24 873
    Par défaut
    Ta fonction en terme de manipulation de PChar est dans le même esprit que GetStartupInfo ... qui fourni Title et Desktop ...

    quelle est ta déclaration de ta fonction ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    procedure GetInfoDemande(pInfoDmd: PInfoDemande); external ...
    tu peux le remplacer par, c'est la même chose ...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    procedure GetInfoDemande(var InfoDmd: TInfoDemande);
    external ...
    OU tu peux éviter le new aussi ...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    var
        InfoDemande: TInfoDemande;
    begin
        GetInfoDemande(@InfoDemande);      //.La fonction de ma DLL.
          if(InfoDemande.sTypeDemande = '1') then
                ...
    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

  3. #3
    Expert éminent
    Avatar de Lung
    Profil pro
    Analyste-programmeur
    Inscrit en
    Mai 2002
    Messages
    2 664
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France, Haute Savoie (Rhône Alpes)

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

    Informations forums :
    Inscription : Mai 2002
    Messages : 2 664
    Points : 6 967
    Points
    6 967
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    var
        InfoDemande: TInfoDemande;
    begin
        GetInfoDemande(@InfoDemande);      //.La fonction de ma DLL.
          if(InfoDemande.sTypeDemande = '1') then
                ...
    Ca marche comme çà.

    En fait le problème se situait au niveau des PChar.
    Je n'avais pas pensé qu'il fallait allouer la mémoire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    GetMem(_InfoDemande.sSociete, 2);
    ...
    try
       GetInfoDemande(@_InfoDemande);
       if _InfoDemande.sSociete = 'XX' then
       ...
     
    finally
       FreeMem(_InfoDemande.sSociete);
       ...
    end;
    L'urgent est fait, l'impossible est en cours, pour les miracles prévoir un délai. ___ Écrivez dans un français correct !!

    C++Builder 5 - Delphi 6#2 Entreprise - Delphi 2007 Entreprise - Delphi 2010 Architecte - Delphi XE Entreprise - Delphi XE7 Entreprise - Delphi 10 Entreprise - Delphi 10.3.2 Entreprise - Delphi 10.4.2 Entreprise - Delphi 11.1 Entreprise
    OpenGL 2.1 - Oracle 10g - Paradox - Interbase (XE) - PostgreSQL (15.4)

  4. #4
    Expert éminent
    Avatar de Lung
    Profil pro
    Analyste-programmeur
    Inscrit en
    Mai 2002
    Messages
    2 664
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France, Haute Savoie (Rhône Alpes)

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

    Informations forums :
    Inscription : Mai 2002
    Messages : 2 664
    Points : 6 967
    Points
    6 967
    Par défaut
    Maintenant, le problème se situe au niveau de mon tableau de PChar.
    Comment allouer la mémoire ?


    Je m'explique :
    - Je créer mon enregistrement dans mon application.
    - J'alloue la mémoire de tous les PChar de l'enregistrement (je connais d'avance la taille maximum que peux me renvoyer ma DLL).
    - Je passe l'adresse de l'enregistrement à une fonction de ma DLL.
    - La DLL me rempli mes PChar.
    - Dans mon application, je traite les valeurs stockées par la DLL dans l'enregistrement.
    - Je libère la mémoire allouée.
    Là, tout ce passe bien.

    Le problème :
    Dans mon enregistrement, j'ai aussi des tableaux (dynamiques) de PChar. Comment allouer la mémoire, sachant que je ne peux pas savoir combien d'éléments la DLL va stocker dans mes tableaux ?

    L'urgent est fait, l'impossible est en cours, pour les miracles prévoir un délai. ___ Écrivez dans un français correct !!

    C++Builder 5 - Delphi 6#2 Entreprise - Delphi 2007 Entreprise - Delphi 2010 Architecte - Delphi XE Entreprise - Delphi XE7 Entreprise - Delphi 10 Entreprise - Delphi 10.3.2 Entreprise - Delphi 10.4.2 Entreprise - Delphi 11.1 Entreprise
    OpenGL 2.1 - Oracle 10g - Paradox - Interbase (XE) - PostgreSQL (15.4)

  5. #5
    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 445
    Points
    28 445
    Par défaut
    Citation Envoyé par Lung
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    var
        InfoDemande: TInfoDemande;
    begin
        GetInfoDemande(@InfoDemande);      //.La fonction de ma DLL.
          if(InfoDemande.sTypeDemande = '1') then
                ...
    Ca marche comme çà.

    En fait le problème se situait au niveau des PChar.
    Je n'avais pas pensé qu'il fallait allouer la mémoire :
    vu le code donné plus haut, il n'y a rien à allouer puisque la DLL affecte les pointeurs...pire le pointeur alloué est perdu quand la DLL le remplace (fuite de mémoire) et le FreeMem se ferait sur un pointeur alloué par la DLL ce qui causerait une exception.
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  6. #6
    Expert éminent
    Avatar de Lung
    Profil pro
    Analyste-programmeur
    Inscrit en
    Mai 2002
    Messages
    2 664
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France, Haute Savoie (Rhône Alpes)

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

    Informations forums :
    Inscription : Mai 2002
    Messages : 2 664
    Points : 6 967
    Points
    6 967
    Par défaut
    Citation Envoyé par Paul TOTH
    vu le code donné plus haut, il n'y a rien à allouer puisque la DLL affecte les pointeurs...pire le pointeur alloué est perdu quand la DLL le remplace (fuite de mémoire) et le FreeMem se ferait sur un pointeur alloué par la DLL ce qui causerait une exception.
    Pourrais-tu développer un peu ?
    Je sens que je n'ai toujours pas compris la mécanique des pointeurs ...

    L'urgent est fait, l'impossible est en cours, pour les miracles prévoir un délai. ___ Écrivez dans un français correct !!

    C++Builder 5 - Delphi 6#2 Entreprise - Delphi 2007 Entreprise - Delphi 2010 Architecte - Delphi XE Entreprise - Delphi XE7 Entreprise - Delphi 10 Entreprise - Delphi 10.3.2 Entreprise - Delphi 10.4.2 Entreprise - Delphi 11.1 Entreprise
    OpenGL 2.1 - Oracle 10g - Paradox - Interbase (XE) - PostgreSQL (15.4)

  7. #7
    Expert éminent
    Avatar de Lung
    Profil pro
    Analyste-programmeur
    Inscrit en
    Mai 2002
    Messages
    2 664
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France, Haute Savoie (Rhône Alpes)

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

    Informations forums :
    Inscription : Mai 2002
    Messages : 2 664
    Points : 6 967
    Points
    6 967
    Par défaut
    Pour info, voici la fonction de ma DLL (un extrait):
    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
     
    procedure GetInfoDemande(pInfoDmd: PInfoDemande);
    var
       i: Integer;
    begin
       if Assigned(FormDemandeExt) then
       begin                               
          StrCopy(pInfoDmd^.sSociete, PAnsiChar(FormDemandeExt.ComboBoxDSociete.Items[FormDemandeExt.ComboBoxDSociete.ItemIndex]));
          StrCopy(pInfoDmd^.sSite, PAnsiChar(FormDemandeExt.ComboBoxDSite.Items[FormDemandeExt.ComboBoxDSite.ItemIndex]));
          StrCopy(pInfoDmd^.sTypeDemande, PAnsiChar(FormDemandeExt.ComboBoxDTypeDemande.Items[FormDemandeExt.ComboBoxDTypeDemande.ItemIndex]));
     
    ...
     
          SetLength(pInfoDmd^.TabContenantPChar, FormListeContenantExtColisExt.ListBoxContenantSelect.Count);
          for i:=0 to Pred(FormListeContenantExtColisExt.ListBoxContenantSelect.Count) do
             pInfoDmd^.TabContenantPChar[i] := PChar(FormListeContenantExtColisExt.ListBoxContenantSelect.Items[i]);
          SetLength(pInfoDmd^.TabColisPChar, FormListeContenantExtColisExt.ListBoxColisSelect.Count);
          for i:=0 to Pred(FormListeContenantExtColisExt.ListBoxColisSelect.Count) do
             pInfoDmd^.TabColisPChar[i] := PChar(FormListeContenantExtColisExt.ListBoxColisSelect.Items[i]);
       end;
    end;
    Et comment j'y fait appel :
    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
     
    var
        _InfoDemande: TInfoDemande;
     
    begin
     
    GetMem(_InfoDemande.sSociete, 2);
    ...
    try
       GetInfoDemande(@_InfoDemande);
       if _InfoDemande.sSociete = 'XX' then
       ...
     
    finally
       FreeMem(_InfoDemande.sSociete);
       ...
    end;
    Et l'enregistrement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    type
       TTabChar = array of PAnsiChar;
     
       PInfoDemande = ^TInfoDemande;
       TInfoDemande = record
          sSociete, sSite, sTypeDemande, sDateDemande, sService, sDemandeur, sDateRetour: PAnsiChar;
          sContenant, sRacine, sFinition, sQuantiteMini, sQuantiteMaxi, sNumCommande, sPorteRetour, sObservation: PAnsiChar;
          TabContenantPChar, TabColisPChar: TTabChar;
       end;
    L'urgent est fait, l'impossible est en cours, pour les miracles prévoir un délai. ___ Écrivez dans un français correct !!

    C++Builder 5 - Delphi 6#2 Entreprise - Delphi 2007 Entreprise - Delphi 2010 Architecte - Delphi XE Entreprise - Delphi XE7 Entreprise - Delphi 10 Entreprise - Delphi 10.3.2 Entreprise - Delphi 10.4.2 Entreprise - Delphi 11.1 Entreprise
    OpenGL 2.1 - Oracle 10g - Paradox - Interbase (XE) - PostgreSQL (15.4)

  8. #8
    Membre éclairé
    Profil pro
    Inscrit en
    Février 2006
    Messages
    624
    Détails du profil
    Informations personnelles :
    Âge : 49
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 624
    Points : 754
    Points
    754
    Par défaut
    Bonjour,

    Je pense qu'il a voulu dire que l'on ne doit pas allouer un pointeur sur le tas de l'aplication et effectuer la libération sur le tas de la DLL... ou l'inverse.

    @+

  9. #9
    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 445
    Points
    28 445
    Par défaut
    ah ben oui mais si tu changes tout entre deux

    premier code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
          pInfoDmd^.sSociete := PChar(FormDemandeExt.ComboBoxDSociete.Items[FormDemandeExt.ComboBoxDSociete.ItemIndex]);
    second code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
          StrCopy(pInfoDmd^.sSociete, PAnsiChar(FormDemandeExt.ComboBoxDSociete.Items[FormDemandeExt.ComboBoxDSociete.ItemIndex]));
    dans le premier cas, tu récupères l'adresse d'un pointeur..et il t'appartient de t'assurer que celui-ci reste valide tant qu'il est utilisé. Notamment si tu venais à changer les items de FormDemandeExt.ComboBoxDSociete, l'adresse de la chaine retournée peux changer ou tout simplement ne plus être valide !

    exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    var
     s:string;
     p:pchar;
    begin
     s:='hello';
     p:=pchar(s);
     s:='toto';
    // ici p ne pointe plus ni sur "toto", ni sur "hello"
    end;
    p pointe toujours sur l'ancienne adresse mémoire ou avait été stockée la chaine "hello". Cet espace mémoire n'est plus utilisé à cette fin, et son contenu n'est pas connu. Il peut contenir "toto" comme il peut contenir n'importe quoi d'autre selon le bon vouloir du gestionnaire de mémoire.

    C'est pareil pour ta combobox.

    Dans le second code, tu recopies la chaine dans un PChar qui non seulement doit avoir été alloué avant, mais qui en plus doit avoir un taille suffisante pour contenir toute la chaine...sous peine de reproduire le bug classique en C : le buffer overflow

    NB: il est possible de ruser avec les STRING si tu sais ce que tu fais

    un STRING est un pointeur vers le premier caractère de la chaine...en ce sens il est identique à un PCHAR.

    ce qui le distingue du PCHAR c'est qu'on trouve 2 integer en mémoire, juste avant ce pointer, le premier donne la taille de la chaine, et le second le nombre de fois ou elle est référencée par une variable de type string. Delphi gère automatiquement ces deux valeurs pour connaitre la taille de la chaine et savoir quand la libérer.

    fort ce cette constatation il est possible de tromper le compilateur en déclarant ta structure différemment entre l'EXE et la DLL

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    type
     TMaStructureCoteExe=record
      Str:pchar;
     ...
     end;
     
     TMaStructureCoteDLL=record
      Str:string;
     end;
    l'exe verra un PChar qu'il ne cherchera pas à gérer comme un string, et la DLL verra un STRING dont elle gèrera la durée de vie

    mais ATTENTION ! dans ce cas, le PCHAR côté EXE doit être utilisé uniquement en lecture sous peine de déclencher des effets de bord...exemple

    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
     
    // dans la DLL
    var
     ChaineGlobale1:string;
     ChaineGlobale2:string;
     ChaineGlobale3:string;
     
    function RemplireStructure(var s:TMaStructureCoteDLL);
    begin
     ChaineGlobale1:='Hello';
     ChaineGlobale2:=ChaineGlobale1;
     ChaineGlobale3:=ChaineGlobale1;
     s.Str:=ChaineGlobale1;
     ChaineGlobale3:='bye';
    end;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    // dans l'EXE
    procedure test;
    var
      s:TMaStructureCoteEXE;
    begin
     FillChar(s,SizeOf(s),0); // permet d'avoir des STRING DLL valides (nil)
     RemplireStructure(s); // appel à la DLL
     ShowMessage(s.Str);
     s.Str[0]:='H'; // modification du PCHAR non recommandée
    end;
    qu'est ce que donne ce code ?

    au départ les ChaineGlobalX pointent toutes les trois sur la même zone mémoire contenant "hello" avec un compteur de référence à 3

    ensuite ce compteur passe à 2 car ChaineGlobal3 change de valeur et pointe sur une nouvelle chaine "bye" (dont le compteur de référence vaut 1)...c'est le fonctionnement normal des STRING

    L'exe récupère bien la chaine "hello" attendue, mais lorsqu'il modifie son contenu en passant le h en majuscule, il modifie en même temps ChaineGlobale1 et 2 ! en effet, il ne tient pas compte du compteur de référence car il pense travailler sur un PCHAR simple
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  10. #10
    Expert éminent
    Avatar de Lung
    Profil pro
    Analyste-programmeur
    Inscrit en
    Mai 2002
    Messages
    2 664
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France, Haute Savoie (Rhône Alpes)

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

    Informations forums :
    Inscription : Mai 2002
    Messages : 2 664
    Points : 6 967
    Points
    6 967
    Par défaut
    Bon, je crois que ça commence à s'éclaircir. pour les précisions.
    Pas simple, tout ça ...

    Sinon, consernant mon problème de tableau, quelqu'un aurait-il une idée ?
    Citation Envoyé par Lung
    Maintenant, le problème se situe au niveau de mon tableau de PChar.
    Comment allouer la mémoire ?


    Je m'explique :
    - Je créer mon enregistrement dans mon application.
    - J'alloue la mémoire de tous les PChar de l'enregistrement (je connais d'avance la taille maximum que peux me renvoyer ma DLL).
    - Je passe l'adresse de l'enregistrement à une fonction de ma DLL.
    - La DLL me rempli mes PChar.
    - Dans mon application, je traite les valeurs stockées par la DLL dans l'enregistrement.
    - Je libère la mémoire allouée.
    Là, tout ce passe bien.

    Le problème :
    Dans mon enregistrement, j'ai aussi des tableaux (dynamiques) de PChar. Comment allouer la mémoire, sachant que je ne peux pas savoir combien d'éléments la DLL va stocker dans mes tableaux ?
    L'urgent est fait, l'impossible est en cours, pour les miracles prévoir un délai. ___ Écrivez dans un français correct !!

    C++Builder 5 - Delphi 6#2 Entreprise - Delphi 2007 Entreprise - Delphi 2010 Architecte - Delphi XE Entreprise - Delphi XE7 Entreprise - Delphi 10 Entreprise - Delphi 10.3.2 Entreprise - Delphi 10.4.2 Entreprise - Delphi 11.1 Entreprise
    OpenGL 2.1 - Oracle 10g - Paradox - Interbase (XE) - PostgreSQL (15.4)

  11. #11
    Expert éminent
    Avatar de Lung
    Profil pro
    Analyste-programmeur
    Inscrit en
    Mai 2002
    Messages
    2 664
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France, Haute Savoie (Rhône Alpes)

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

    Informations forums :
    Inscription : Mai 2002
    Messages : 2 664
    Points : 6 967
    Points
    6 967
    Par défaut
    J'ai bien vu la FAQ (http://delphi.developpez.com/faq/?pa...nededllversapp), mais ça me parait bien lourd d'appeller deux fois une fonction pour mes PChar. Et les atomes, j'ai rien compris.
    Il n'existe pas mieux ?

    L'urgent est fait, l'impossible est en cours, pour les miracles prévoir un délai. ___ Écrivez dans un français correct !!

    C++Builder 5 - Delphi 6#2 Entreprise - Delphi 2007 Entreprise - Delphi 2010 Architecte - Delphi XE Entreprise - Delphi XE7 Entreprise - Delphi 10 Entreprise - Delphi 10.3.2 Entreprise - Delphi 10.4.2 Entreprise - Delphi 11.1 Entreprise
    OpenGL 2.1 - Oracle 10g - Paradox - Interbase (XE) - PostgreSQL (15.4)

  12. #12
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    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 459
    Points : 24 873
    Points
    24 873
    Par défaut
    Ensuite, si c'est pour du pur delphi (quoi qu'en indiquant un PChar avec un Len, du C peu se débrouiller aussi) tu peux utiliser des ShortString (en var) (ou string[50] ou du Array[0..255] of Char, cela fonctionne à merveille, pas besoin de Bordelmn.dll et ShareMerde.pas ...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     (je connais d'avance la taille maximum que peux me renvoyer ma DLL).
    Pour quelle raison se prendre la tête avec des PChar si l'on connait la longueur, vive le String[...], cela revient au même en quantité mémoire et c'est moins prise de tête ...

    Ensuite, personnellement, je n'ai pas testé avec des Record contenant des PChar, mais avec des fonctions qui se passe des PChar, je n'ai pas de soucis, bon cela vient surement de mon "out" qui fait un Pointer de Pointer sur Char ...

    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
    procedure ShowLastError(HandleNeoMatrixDLL: HMODULE = 0);
    var
      HandleProcError: procedure(out Msg: PChar); stdcall;
      Msg: PChar;
      DoFree: Boolean;
    begin
      DoFree := HandleNeoMatrixDLL = 0;
      if HandleNeoMatrixDLL = 0 then
        HandleNeoMatrixDLL := LoadDLL();
     
      if HandleNeoMatrixDLL > 0 then
      begin
        try
          @HandleProcError := GetProcAddress(HandleNeoMatrixDLL, 'GetLastError');
          if Assigned(@HandleProcError) then
          begin
            HandleProcError(Msg);
            if Assigned(Msg) and (Trim(Msg) <> '') then
              ShowMessage(Msg)
          end else
          begin
            ShowMessage('Impossible d''Afficher la Dernière Erreur !');
          end;
        finally
          if DoFree then
            FreeLibrary(HandleNeoMatrixDLL);
        end;
      end;
    end;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    {* -----------------------------------------------------------------------------
    Renvoie le Message de la Dernière Exception
    ------------------------------------------------------------------------------ }
    procedure GetLastError(out Msg: PChar); stdcall;
    begin
      Msg := PChar(_LastError);
    end;
    en théorie, tes PChar dans ta structure sont à nil (un petit ZeroMemory pour garantir un bon nettoyage de la structure ...) et donc il recoivent ces PChar, donc il ne devrait pas avoir de problème, ...

    Pour les ShortString passé en var, c'est modifiable, cela revient ni plus ni moins à un PChar de 256 en longueur ... bon je passe un string en const ça fonctionne parce que c'est juste de la lecture ... sinon ça serait BOOM !

    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
    function GetFileVersion(const sFileName: string; var fileversion: ShortString): boolean; stdcall;
    begin
       Result := true;
       try
          try
             fileversion := UpdateMyDatabase.GetMatrix_web_servicePortType.GetFileVersion(sFileName);
          except
            on E: Exception do
              raise Exception.CreateFmt('Impossible de récupérer la Version du Fichier "%s", il n''existe probablement pas sur le Serveur !'#13#10#13#10'( %s : %s )', [sFileName, E.ClassName, E.Message]);
          end;
       except
          on E: Exception do
          begin
            _LastError := E.Message;
            fileversion := 'erreur_get_fileversion'; //Si IsGoodVersion, ça renvoie donc une clé à "Hasher"
            Result := false;
          end;
       end;
    end;


    Sinon, il y au moins trois façons de faire dans les DLL pour le PChar, on le voit avec les API Windows

    tu as la méthode de GetClassName, PréAlloué du Côté Appelant

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int GetClassName(
     
        HWND hWnd,	// handle of window
        LPTSTR lpClassName,	// address of buffer for class name
        int nMaxCount 	// size of buffer, in characters
       );
    tu peux passer un PChar alloué via GetMem, mais aussi un Array Of Char, si Dynamique faut faire

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    GetClassName(ClassID, @DynArray[0], Length(DynArray);
    pour un Fixe, tu peux écrire la syntaxe du dessus, mais aussi celle du dessous, car ce n'est plus un pointeur ... mais directement le tableau ...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    GetClassName(ClassID, DynArray, Length(DynArray);

    ensuite, tu as la méthode de GetStartupInfo

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    VOID GetStartupInfo(
     
        LPSTARTUPINFO lpStartupInfo 	// address of STARTUPINFO structure 
       );
    tu pourras accéder à lpDesktop et lpTitle sans pourtant les avoir alloué, ... car dans ta structure, normalement les PChar était null, et jamais tu n'indique à ta fonction GetStartupInfo la taille quelle doit gérer pour ses chaines ...

    Enfin, il faut défnir la taille de la structure passé et il détermine par ce biais quelle version de structure utilisé, cas pour Shell_NotifyIcon qui possède plusieurs forme avec une structure avec char szTip[64], une autre en 128, et Vista apporte une version PChar plus longue.
    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

  13. #13
    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 445
    Points
    28 445
    Par défaut
    Citation Envoyé par Lung
    J'ai bien vu la FAQ (http://delphi.developpez.com/faq/?pa...nededllversapp), mais ça me parait bien lourd d'appeller deux fois une fonction pour mes PChar. Et les atomes, j'ai rien compris.
    Il n'existe pas mieux ?

    y'a pas de secret, tu dois faire attention à la gestion mémoire

    ShareMem ou FastMM sont une première solution, mais alors les DLL ne pourront jamais être réalisées avec autre chose que Delphi...c'est un choix.

    Sinon, il faut laisser toute la gestion d'un côté ou de l'autre.

    1) c'est l'exe qui alloue

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    var
     s:string;
     l:integer;
    begin
     l:=GetStr(nil); // demande la taille
     SetLength(s,l);
     GetStr(pchar(s)); // lit la chaine
    // autre variante
     l:=1024; // donner une taille "suffisante"
     SetLength(s,1024);
     l:=GetStr(phar(s),1024);
     SetLength(s,l); // ajuster après coup
    end;
    2) c'est la DLL qui alloue
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    var
     p:pchar;
    begin
     p:=GetStr(); // retourne une chaine allouée par un GetMem dans la DLL
     ...
     FreeStr(p); // une fonction de la DLL qui fait un FreeMem() sur p :D
    end;
    3) ruser pour éviter tout cela
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    // dans la DLL
    var
     _GetStr:string; // variable globale utilisée pour stocker le Pchar
     
    function GetStr(parm:integer):pchar;
    begin
     _GetStr:='la chaine à retourner en fonction de parm';
     Result:=pchar(_GetStr);
    end;
    dans ce cas on réutilise "_GetStr" à chaque fois
    du coup la valeur du pointer retourné n'est valide qu'entre deux appels

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    var
     s1:string;
     s2:string;
    begin
     
     s1:=GetStr(1); // en plaçant le résultat dans un string
     s2:=GetStr(2); // on peut invoquer une nouvelle fois la fonction
     
    // alors qu'un appel multiple ne fonctionnera pas
    // le pointeur du premier appel ne sera plus valide lors du second
     s1:=GetStr(1)+GetStr(2);
    end;
    c'est dernière méthode se retrouve dans Windows avec inet_ntoa qui précise "The data should be copied before another Windows Sockets call is made."
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  14. #14
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    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 459
    Points : 24 873
    Points
    24 873
    Par défaut
    C'est aussi ma méthode pour mon GetLastError comme par hazard, c'est surement pour cela que ça fonctionne
    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

  15. #15
    Expert éminent
    Avatar de Lung
    Profil pro
    Analyste-programmeur
    Inscrit en
    Mai 2002
    Messages
    2 664
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France, Haute Savoie (Rhône Alpes)

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

    Informations forums :
    Inscription : Mai 2002
    Messages : 2 664
    Points : 6 967
    Points
    6 967
    Par défaut
    pour vos réponses.
    Je regarde tout ça ...
    L'urgent est fait, l'impossible est en cours, pour les miracles prévoir un délai. ___ Écrivez dans un français correct !!

    C++Builder 5 - Delphi 6#2 Entreprise - Delphi 2007 Entreprise - Delphi 2010 Architecte - Delphi XE Entreprise - Delphi XE7 Entreprise - Delphi 10 Entreprise - Delphi 10.3.2 Entreprise - Delphi 10.4.2 Entreprise - Delphi 11.1 Entreprise
    OpenGL 2.1 - Oracle 10g - Paradox - Interbase (XE) - PostgreSQL (15.4)

  16. #16
    Expert éminent
    Avatar de Lung
    Profil pro
    Analyste-programmeur
    Inscrit en
    Mai 2002
    Messages
    2 664
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France, Haute Savoie (Rhône Alpes)

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

    Informations forums :
    Inscription : Mai 2002
    Messages : 2 664
    Points : 6 967
    Points
    6 967
    Par défaut
    Sinon, s'il y a quelqu'un qui maîtrise aussi le C++, je suis preneur : http://www.developpez.net/forums/sho...d.php?t=364223



    Je coince pour définir correctement ce de pointeur.
    L'urgent est fait, l'impossible est en cours, pour les miracles prévoir un délai. ___ Écrivez dans un français correct !!

    C++Builder 5 - Delphi 6#2 Entreprise - Delphi 2007 Entreprise - Delphi 2010 Architecte - Delphi XE Entreprise - Delphi XE7 Entreprise - Delphi 10 Entreprise - Delphi 10.3.2 Entreprise - Delphi 10.4.2 Entreprise - Delphi 11.1 Entreprise
    OpenGL 2.1 - Oracle 10g - Paradox - Interbase (XE) - PostgreSQL (15.4)

Discussions similaires

  1. Réponses: 52
    Dernier message: 23/10/2014, 11h22
  2. Réponses: 2
    Dernier message: 06/05/2007, 12h52
  3. Réponses: 8
    Dernier message: 30/05/2006, 01h26
  4. TADOCommand + Pointeur sur l'enregistrement + affichage
    Par kurkaine dans le forum C++Builder
    Réponses: 3
    Dernier message: 18/11/2005, 16h15
  5. TADOCommand + Pointeur sur l'enregistrement + affichage
    Par kurkaine dans le forum Bases de données
    Réponses: 2
    Dernier message: 18/11/2005, 06h02

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