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 :

Pchar et comportement bizarre


Sujet :

Langage Delphi

  1. #1
    Membre confirmé

    Inscrit en
    Novembre 2002
    Messages
    744
    Détails du profil
    Informations forums :
    Inscription : Novembre 2002
    Messages : 744
    Points : 500
    Points
    500
    Par défaut Pchar et comportement bizarre
    Bonjour a tous..

    OS. XP
    DELPHI 7

    J'utilise des "Pchar" pour passer des strings entre DLL et cela ne n'avait poser aucun problème jusqu’à présent. Mais je viens de me rendre compte d'une anomalie que je n'arrive pas a résoudre.

    Extrait des méthodes utilisées.

    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 se trouvent dans la DLL
    function ExInstruction(NumInstruction:integer ; var R1: Pchar):integer; STDCALL;
    var st: string;
    begin
    ...
         R1:=Pchar(StResult);
         result:=0;
    end;
     
    // Unité appellant la procedure se trouvant dans la DLL
    Procedure Reception;
    var status : integer;
    begin
         ...
         status:=ExInstruction (LigneProg[NumligneProg].mesure , r[1]);
         ...
    end;
    Une anomalie m'a été retournée par un client sur un caractère qui apparaissait en fin d'une chaîne.

    N'ayant pas compris la raison de ce problème, j'ai essayé le transfert de chaîne allant de la Taille 2 à la taille 230 caractères (le max pour mon application).

    A ma grande surprise toutes les chaînes de caractères d'une taille de :

    28 carac : ajoute le caractère ',' en fin de chaîne.
    44 carac : ajoute le caractère '<' en fin de chaîne.
    162 carac : ajoute le caractère '°' en fin de chaîne.
    et 156,157,158 carac qui sont tronqué a 155 caractères max.

    toutes les autres sont conformes.

    quand en pas à pas, je visualise R1 juste avant l'envoie tout est correct
    quand je visualise r[1] juste après l’exécution de la procédure "réception", la chaine n'est plus conforme.


    quelqu'un aurait il une idée ? une solution ..
    Bye et bon code...

    Ce n'est pas tant l'aide de nos amis qui nous aide , mais notre confiance dans cette aide .

  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
    le code est insuffisant pour comprendre

    est-ce que la DLL utilise une variable global StResult ou est-ce une erreur de copier/coller et elle utilise la variable locale St ?

    comment est déclaré "r" dans l'application ?
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  3. #3
    Membre confirmé

    Inscrit en
    Novembre 2002
    Messages
    744
    Détails du profil
    Informations forums :
    Inscription : Novembre 2002
    Messages : 744
    Points : 500
    Points
    500
    Par défaut
    rebonjour ,


    Après recherche, il semblerait que mes conversions Pchar=> string ou String => Pchar, ne fonctionne pas.

    Si je retourne directement Le Pchar reçus, sans le convertir et le traiter en string, le problème semble disparaitre.

    des idées .. ?


    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
     
    function ExInstruction(NumInstruction:integer;
                           P1,P2,P3,P4,P5,P6,P7,P8,P9,P10          :Pchar;
                           P11,P12,P13,P14,P15,P16,P17,P18,P19,P20 :real;
                           MemoEtatRack                            :byte;
                           TareResitive                            :real;
                           PtmaxMultiplexeur                       :integer;
                           TableTrancoCourante                     :Pchar;
     
                           Var MemoEtatRack1:byte;
                           var R1,R2,R3,R4,R5,R6,R7,R8,R9,R10:Pchar;
                           var R11,R12,R13,R14,R15,R16,R17,R18,R19,R20:Real;
                           var Status:byte):integer; STDCALL;
    var
        ST,ST1,STconcat : string;
        P :integer;
    begin
        R1:='' ;R2:='' ;R3:='' ;R4:='' ;R5:='' ;R6:='' ;R7:='' ;R8:='' ;R9:='' ;R10:='';
        R11:=-1;R12:=-1;R13:=-1;R14:=-1;R15:=-1;R16:=-1;R17:=-1;R18:=-1;R19:=-1;R20:=-1;
     
    //    R1:=P1;
    //    exit;
     
     
        STconcat:=strPas(P1);
        R1:=Pchar(STconcat);
        result:=0;
    end;










    //=======================================================

    Pour info les codes épures des deux appli.

    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
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
     
     
    // L'Application appelante
     
    unit UessaiIns;
     
    interface
     
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls,UtilPhoenix;
     
    type
      TForm1 = class(TForm)
        Button1: TButton;
        Label1: TLabel;
        Label2: TLabel;
        Memo1: TMemo;
        Memo2: TMemo;
        procedure FormCreate(Sender: TObject);
        procedure Button1Click(Sender: TObject);
        procedure lanceInstructionSoft ;
      private
        { Déclarations privées }
      public
        { Déclarations publiques }
      end;
     
    var
      Form1: TForm1;
     
    implementation
     
    {$R *.dfm}
     
     
    var      PSr:array[1..10] of real;
             ResultInsCharLiteral:array[1..10]of string;
     
    var HandleDLLInstruction: Thandle;
     
     
      ExInstruction:function (NumInstruction:integer;
                           P1,P2,P3,P4,P5,P6,P7,P8,P9,P10:Pchar;
                           P11,P12,P13,P14,P15,P16,P17,P18,P19,P20:real;
                           MemoEtatRack:byte;
                           TareResitive:real;
                           PtmaxMultiplexeur:integer;
                           TableTrancoCourante:Pchar;
                           Var MemoEtatRack1:byte;
                           var R1,R2,R3,R4,R5,R6,R7,R8,R9,R10:Pchar;
                           var R11,R12,R13,R14,R15,R16,R17,R18,R19,R20:Real;
                           var Status:byte):integer; STDCALL;
     
     
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      HandleDLLInstruction:=LoadLibrary(PChar(CheminDLL+'DLLinstruction.dll'));
      if HandleDLLInstruction<>0 then
      begin
         @ExInstruction:=GetProcAddress(HandleDLLInstruction,'ExInstruction');
      end;
    end;
     
     
    procedure TForm1.Button1Click(Sender: TObject);
    var i:integer ;
    begin
       lanceInstructionSoft;
    end;
     
    //****************************************************************************//
    procedure TForm1.lanceInstructionSoft ;
    var status:byte;
        V:array[1..10] of string;
        t:array[1..10] of Pchar;
        r:array[1..10] of real;
        i,j:integer;
        EtatRack1:byte;
    begin
         for j:=0 to 4 do
         begin
     
             V[1]:=memo1.Lines[j];
             ExInstruction (10,  // numero Dll de l'instruction
                            Pchar(string(V[1])),
                            '','','','','','','','','',
                            0,0,0,0,0,0,0,0,0,0,
                            1,0,11,'',
                            EtatRack1,
                            t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8],t[9],t[10],
                            r[1],r[2],r[3],r[4],r[5],r[6],r[7],r[8],r[9],r[10],
                            Status);
     
             for i:=1 to 10 do ResultInsCharLiteral[i]:=strPas(Pchar(T[i]));
     
     
     
             memo2.Lines.add(ResultInsCharLiteral[1]);
             Label1.caption:=inttostr(length(ResultInsCharLiteral[1]));
             Label2.caption:=inttostr(length(memo2.Lines[J]));
         end;
    end;
    end
     
     
    //La DLL
     
    unit DLLUinstruction;
     
    interface
     
     
    uses
      Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
      ComCtrls, ExtCtrls, StdCtrls, OleCtrls;
     
    function ExInstruction(NumInstruction:integer;
                           P1,P2,P3,P4,P5,P6,P7,P8,P9,P10:Pchar;
                           P11,P12,P13,P14,P15,P16,P17,P18,P19,P20:real;
                           MemoEtatRack:byte;
                           TareResitive:real;
                           PtmaxMultiplexeur:integer;
                           TableTrancoCourante:Pchar;
                           Var MemoEtatRack1:byte;
                           var R1,R2,R3,R4,R5,R6,R7,R8,R9,R10:Pchar;
                           var R11,R12,R13,R14,R15,R16,R17,R18,R19,R20:Real;
                           var Status:byte):integer; STDCALL;
     
    type
      TFInstruction = class(TForm)
      Private
        { Déclarations privées }
      public
        { Déclarations publiques }
      end;
    //------------------------------------------------------------------------------
    var
      FInstruction: TFInstruction;
     
    implementation
     
    exports ExInstruction              name'ExInstruction';
     
    {$R *.DFM}
    //-----------------------------------------------------------------------------
    function ExInstruction(NumInstruction:integer;
                           P1,P2,P3,P4,P5,P6,P7,P8,P9,P10          :Pchar;
                           P11,P12,P13,P14,P15,P16,P17,P18,P19,P20 :real;
                           MemoEtatRack                            :byte;
                           TareResitive                            :real;
                           PtmaxMultiplexeur                       :integer;
                           TableTrancoCourante                     :Pchar;
     
                           Var MemoEtatRack1:byte;
                           var R1,R2,R3,R4,R5,R6,R7,R8,R9,R10:Pchar;
                           var R11,R12,R13,R14,R15,R16,R17,R18,R19,R20:Real;
                           var Status:byte):integer; STDCALL;
    var
        ST,ST1,STconcat : string;
        P :integer;
    begin
        R1:='' ;R2:='' ;R3:='' ;R4:='' ;R5:='' ;R6:='' ;R7:='' ;R8:='' ;R9:='' ;R10:='';
        R11:=-1;R12:=-1;R13:=-1;R14:=-1;R15:=-1;R16:=-1;R17:=-1;R18:=-1;R19:=-1;R20:=-1;
     
    //    R1:=P1;
    //    exit;
     
     
        STconcat:=strPas(P1);
        R1:=Pchar(STconcat);
        result:=0;
    end;
     
    //-----------------------------------------------------------------------------
     
    end.
    Bye et bon code...

    Ce n'est pas tant l'aide de nos amis qui nous aide , mais notre confiance dans cette aide .

  4. #4
    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
    ok, c'est bien ça, ta DLL renvoie l'adresse d'une variable locale...qui disparaît dès la fin de la fonction.

    Quand une DLL renvoie un PChar, elle est responsable de sa libération.

    deux solutions

    1) la DLL retourne un PChar et propose une autre fonction pour le libérer
    Dans ce cas tu peux allouer le PChar car il sera libéré explicitement par la suite

    2) la DLL n'est pas mutlithread ni réentrante
    Dans ce cas tu peux utiliser (mais c'est très mal) une variable globale à la DLL qui restera en vie après la fin de la fonction et qui sera détruite quand on changera sa valeur par exemple.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    var
      Str: string;
     
    function GetPChar: PChar; 
    begin
      Str := 'Hello';
      Result := PChar(Str);
    end;
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  5. #5
    Membre confirmé

    Inscrit en
    Novembre 2002
    Messages
    744
    Détails du profil
    Informations forums :
    Inscription : Novembre 2002
    Messages : 744
    Points : 500
    Points
    500
    Par défaut
    Merci Paul ,

    Mes 1er essais semble concluant, mais peux tu m'en dire plus s'il te plait.
    J'ai pas mal de fonction dans cette DLL qui me revoie un résultat sous cette forme et jamais personne en m'avait remonté d'erreur.

    Je croyais que les allocations et libérations des Pchar en Delphi était géré par lui même....

    si tu as un exemple de libération de Pchar dans une DLL , je suis preneur et encore merci.

    Juste Pour info, pourquoi cette erreur semblait liée au nombre de caractère et non aleatoirement.. ?
    Bye et bon code...

    Ce n'est pas tant l'aide de nos amis qui nous aide , mais notre confiance dans cette aide .

  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
    Citation Envoyé par petitcoucou31 Voir le message
    Merci Paul ,

    Mes 1er essais semble concluant, mais peux tu m'en dire plus s'il te plait.
    J'ai pas mal de fonction dans cette DLL qui me revoie un résultat sous cette forme et jamais personne en m'avait remonté d'erreur.

    Je croyais que les allocations et libérations des Pchar en Delphi était géré par lui même....

    si tu as un exemple de libération de Pchar dans une DLL , je suis preneur et encore merci.

    Juste Pour info, pourquoi cette erreur semblait liée au nombre de caractère et non aleatoirement.. ?
    non un PChar est un pointeur sans gestion particulière, se sont les string qui sont gérées automatiquement. Et c'est bien là le problème de ton code, la chaîne est libérée automatiquement en fin de procédure. ça peut tout de même fonctionner (avec du bol) car une chaîne libérée n'est pas effacée de la mémoire, mais son contenu sera cependant écrasé par d'autres valeurs dès qu'on fera une nouvelle allocation mémoire; c'est probablement ce qu'il se passe avec la fin de ta chaîne.

    pour gérer proprement les choses il faut simplement une fonction de libération

    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
     
    function GetStr:PChar;
    var
      str: string;
      len: Integer;
    begin
      str := 'Hello'; // ici je peux travailler un string
      len := SizeOf(Char) * (Length(Str) + 1); // +1 pour le 0 terminal, SizeOf(char) pour l'unicode
      GetMem(Result, len);
      Move(Str[1], Result^, len); // Copier la chaîne dans un PChar
    end;
     
    function FreeStr(P: PChar);
    begin
      FreeMem(P);
    end;
    NB: en plaçant le FreeMem(P) dans la DLL et non dans l'exe, on n'est pas obligé de partager le gestionnaire de mémoire (ShareMem).

    Avec la variable String globale, c'est plus simple, mais ça implique quelques limitations:
    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
     
    var
      Str: string;
     
    function GetStr1: PChar;
    begin
      Str := 'Hello';
      Result := PChar(Str);
    end;
     
    function GetStr2: PChar;
    begin
      Str := 'World';
      Result := PChar(Str);
    end;
    si j'appelle GetStr1, j'ai un pointeur vers Str qui contient 'hello',je peux utiliser ce PChar aussi longtemps que je n'invoque pas une autre fonction. Notamment si j'appelle Getstr2, Str change de valeur et le pointeur que m'a retourné GetStr1 n'est plus valide.

    Ceci dit c'est une limitation acceptable qu'on retrouve d'ailleurs dans l'API Windows, par exemple dans inet_ntoa:
    Note that the string returned by inet_ntoa resides in memory which is allocated by Windows Sockets. The application should not make any assumptions about the way in which the memory is allocated. The data is guaranteed to be valid until the next Windows Sockets function call within the same thread, but no longer.
    NB: pour que Str soit threadsafe, il faut la déclarer en "threadvar".
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

Discussions similaires

  1. Comportement bizarre de mes FPS
    Par Ekinoks dans le forum OpenGL
    Réponses: 7
    Dernier message: 22/08/2005, 15h14
  2. xsl:test .... avec comportement bizarre
    Par Blue LC dans le forum XMLRAD
    Réponses: 2
    Dernier message: 10/06/2005, 13h56
  3. [ACESS][MEMO][ISNULL]Comportement bizarre
    Par seb.49 dans le forum ASP
    Réponses: 2
    Dernier message: 09/06/2004, 10h44
  4. [HttpClient] comportement bizarre, saute des catch()...
    Par iubito dans le forum Développement Web en Java
    Réponses: 4
    Dernier message: 04/02/2004, 15h25
  5. [Sybase] Comportement bizarre d'une table
    Par sdozias dans le forum Sybase
    Réponses: 4
    Dernier message: 03/02/2004, 10h39

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