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 :

Portage d'une appli C# vers Delphi


Sujet :

Langage Delphi

  1. #1
    Membre confirmé
    Avatar de Higgins
    Inscrit en
    Juillet 2002
    Messages
    520
    Détails du profil
    Informations forums :
    Inscription : Juillet 2002
    Messages : 520
    Points : 543
    Points
    543
    Par défaut Portage d'une appli C# vers Delphi
    Bonjour tout le monde,

    Je porte une application écrite en C# vers Delphi qui fait plusieurs appels à une DLL externe. Je ne rencontre pas de problème pour la ces appels sauf un pour lequel je ne comprend pas où est le problème.
    Voici le code C#:
    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
     
     
     [DllImport("maDLL.dll")]
            public static extern int readBlock(byte address, byte number, int tagTyp, byte blockNR, byte[] serialnumber, int length, ref READBLOCK readblock);
     
     public struct READBLOCK
            {
                public byte loc;
                public byte rst;
                public byte nob1;
                public int tt1;
                public int dt1;
                public byte nr1;
                public byte size1;
                public unsafe fixed byte snr[120];
                public byte nob2;
                public int tt2;
                public int dt2;
                public byte nr2;
                public byte size2;
                public unsafe fixed byte data[120];
            };
     
    //L'appel de la fonction se fait comme ceci:
     byte[] serialnumber = new byte[0];
    READBLOCK readblock = new READBLOCK();
    int error=readBlock(63,1,5,0,serialnumber,0,ref readblock);
    que j'ai traduit comme ceci
    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
     
    type READBLOCK=record
               // Location */
              loc:byte;
              // Reader Status */
              rst:byte;
              // Number of Blocks 1 */
              nob1:byte;
              // Tag typ 1 */
              tt1:integer;
              // Data typ 1 */
              dt1:integer;
              // The nr1 */
              nr1:byte;
              // size of serialnumber */
              size1:byte;
              // The serialnumber */
              snr:array[0..119] of byte;
              // Number of Blocks 2 */
              nob2:byte;
              // Tag typ 2 */
              tt2:integer;
              // Data typ 2 */
              dt2:integer;
              // The nr2 */
              nr2:byte;
              // size of data */
              size2:byte;
              // The messagetyp */
              data:array[0..119] of byte;
     end;
    pREADBLOCK=^READBLOCK;
     
    maFonction:Function(address:byte;number:byte;tagTyp:integer;blockNr:byte;serialnumber: array of byte;length:integer;BLOCK: pREADBLOCK) :integer;stdcall;
       Blk:READBLOCK;
       hDLL:THandle;
       serial:array of byte;
       error:integer;
     
    hDLL:=LoadLibrary('maDLL.dll');
    if hDLL>0 then
    begin
         maFunction:=GetProcAddress(hDLL,'readBlock');
          if assigned(maFunction) then
           error:=  maFunction(63,1,5,0,serial,0,@Blk);  
    end;
    Sur visual studio, aucune erreur, l'appel à la DLL fonctionne correctement (elle lit des données sur un périphérique USB).
    Sur Delphi, le bip de lecture du périphérique est déclenché mais j'obtiens une violation d'accès.
    J'ai essayé de remplacer byte par UINT8 dans delphi mais sans succès.
    Mon compilateur Visual studio, la DLL et mon OS sont en 64bits alors que Delphi compile en 32bits. Je pense que le problème doit se situer au niveau des types mais je n'ai pas trouvé. J'ai remplacé integer par int64 dans ma structure et dans la déclaration de la DLL mais ça n'a rien changé.
    Avez-vous des pistes pour ça?
    7 fois à terre, 8 fois debout

  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
    euh...si la DLL est en 64bits il faut un programme Delphi en 64bits aussi...

    sinon je ne connais pas assez C# pour avoir la réponse, donc le mieux serait de demander à C# de t'afficher la taille de la structure READBLOCK afin de t'assurer quelle est identique sous Delphi, que ce soit sous C# ou Delphi, il est possible que le Byte n'occupe pas 1 seul octet dans la structure. Dans ce genre de situation je préfère déclarer un "packed record" quitte à ajouter des champs pour aligner le tout

    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
     
    type
      READBLOCK=packed record
               // Location */
              loc:byte;
              pad1:array[0..2] of Byte;
              // Reader Status */
              rst:byte;
              pad2:array[0..2] of Byte;
              // Number of Blocks 1 */
              nob1:byte;
              pad3:array[0..2] of Byte;
              // Tag typ 1 */
              tt1:integer;
              // Data typ 1 */
              dt1:integer;
              // The nr1 */
              nr1:byte;
              pad4:array[0..2] of Byte;
              // size of serialnumber */
              size1:byte;
              // The serialnumber */
              snr:array[0..119] of byte;
              // Number of Blocks 2 */
              nob2:byte;
              // Tag typ 2 */
              tt2:integer;
              // Data typ 2 */
              dt2:integer;
              // The nr2 */
              nr2:byte;
              // size of data */
              size2:byte;
              // The messagetyp */
              data:array[0..119] of byte;
     end;
    Question annexe, qu'est-ce qui a poussé le choix de migration C# vers Delphi ?
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  3. #3
    Membre confirmé
    Avatar de Higgins
    Inscrit en
    Juillet 2002
    Messages
    520
    Détails du profil
    Informations forums :
    Inscription : Juillet 2002
    Messages : 520
    Points : 543
    Points
    543
    Par défaut
    Citation Envoyé par Paul TOTH Voir le message
    Dans ce genre de situation je préfère déclarer un "packed record" quitte à ajouter des champs pour aligner le tout
    Je n'ai pas bien compris le fonctionnement du packed record. Comment se fait l'alignement puisque la DLL ne renseigne que les champs qu'elle connait?
    J'ai trouvé ça sur les packed record dans l'aide de Delphi:
    L'utilisation de packed n'est pas une pratique recommandée, car elle empêche la compatibilité avec d'autres langages ou plates-formes. Elle ralentit l'accès aux données et, dans le cas d'un tableau de caractères, affecte la compatibilité des types. Pour de plus amples informations, voir Gestion de la mémoire et Alignement packed implicite des champs avec une spécification de type commune.
    et un peu plus loin
    Puisque l'alignement des données peut changer, c'est une bonne idée de compacter toute structure d'enregistrement que vous avez l'intention d'écrire sur disque ou de passer en mémoire à un autre module compilé avec une version du compilateur différente.
    Je ne sais pas quoi en penser.....
    Informations complémentaires, j'ai trouvé une version 32 bits de la DLL avec laquelle j'ai le même problème. Petit détail complémentaire qui peut avoir son importance, il s'agit d'une application Firemonkey.
    Citation Envoyé par Paul TOTH Voir le message
    Question annexe, qu'est-ce qui a poussé le choix de migration C# vers Delphi ?
    Très bonne question
    En fait l'application en C# est un simple utilitaire de paramétrage+lecture du périphérique. Je dois inclure ces fonctionnalités dans une application Delphi existante.
    7 fois à terre, 8 fois debout

  4. #4
    Membre confirmé
    Avatar de Higgins
    Inscrit en
    Juillet 2002
    Messages
    520
    Détails du profil
    Informations forums :
    Inscription : Juillet 2002
    Messages : 520
    Points : 543
    Points
    543
    Par défaut
    A priori, c'est bien lié aux types. Je me suis dépatouillé en remplaçant le "array of byte" dans les paramètres de la fonction par un pointeur sur un "array of byte"

    Tous les champs ne sont pas renseignés correctement mais ceux qui m'intéressent le sont.
    7 fois à terre, 8 fois debout

  5. #5
    Membre habitué
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2012
    Messages
    92
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2012
    Messages : 92
    Points : 159
    Points
    159
    Par défaut
    Citation Envoyé par Higgins Voir le message
    Tous les champs ne sont pas renseignés correctement mais ceux qui m'intéressent le sont.
    as tu pensé à faire un zeromemory sur ton record pour avoir un record vierge ?
    parce que j'ai l'impression que tes valeurs farfelues viennent de là

  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 Higgins Voir le message
    A priori, c'est bien lié aux types. Je me suis dépatouillé en remplaçant le "array of byte" dans les paramètres de la fonction par un pointeur sur un "array of byte"

    Tous les champs ne sont pas renseignés correctement mais ceux qui m'intéressent le sont.
    ah j'avais pas vu ça ! "array of" c'est un faux ami, il ne faut pas l'utiliser dans ce contexte.

    regarde le code ci-dessous

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    procedure test(a: array of char); stdcall;
    var
      i: Integer;
    begin
      for i := Low(a) to High(a) do
        ShowMessage(a[i]);
    end;
     
    begin
      test(['a','b', 'c']);
    end;
    il fonctionne, mais les fonctions low() et high() ne sont pas magiques, il faut bien que Delphi puisse déterminer que low(a) = 0 (ça c'est facile) et que high(a) = 2, ça c'est moins évident. Et bien il n'y a pas de secret, un "array of" occupe deux paramètres dans la fonction ! le premier est le pointeur sur le premier élément, et le second le nombre d'éléments moins un (la valeur de High()) !

    la fonction pourrait s'écrire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    procedure test(a: PInteger; high: Integer);
    tu dois donc bien envoyer un Pointeur vers le premier élément du tableau...ceci dit, la notation byte[] serialnumber = new byte[0]; me fait penser que c'est juste un PByte ou un "var serialnum: Byte"
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  7. #7
    Membre confirmé
    Avatar de Higgins
    Inscrit en
    Juillet 2002
    Messages
    520
    Détails du profil
    Informations forums :
    Inscription : Juillet 2002
    Messages : 520
    Points : 543
    Points
    543
    Par défaut
    Citation Envoyé par jeromelef2 Voir le message
    as tu pensé à faire un zeromemory sur ton record pour avoir un record vierge ?
    parce que j'ai l'impression que tes valeurs farfelues viennent de là
    En fait, je n'ai pas réellement de données farfelues, juste un "décalage" entre les champs de la structure:
    la valeur de size1 se trouve en fait dans snr[0]
    mais bon, je m'en accommode pour le moment.
    7 fois à terre, 8 fois debout

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

Discussions similaires

  1. Migrer une appli JEE vers Websphere v8?
    Par mimi_grebici dans le forum Websphere
    Réponses: 0
    Dernier message: 25/08/2011, 12h08
  2. passage d'une macro excel vers delphi
    Par zanoubya dans le forum Débuter
    Réponses: 11
    Dernier message: 18/06/2009, 17h55
  3. Problème d'accents lors du portage d'une appli
    Par manudwarf dans le forum Applications et environnements graphiques
    Réponses: 2
    Dernier message: 26/05/2009, 09h42
  4. Réponses: 2
    Dernier message: 31/03/2009, 10h59
  5. portage d'une appli utilisant la librairie word
    Par neonico dans le forum MFC
    Réponses: 4
    Dernier message: 23/02/2005, 23h48

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