2010-06-11 17 views
1

J'ai un dll Delphi défini comme ceci:appelant dll delphi de C#

TMPData = record 
Lastname, Firstname: array[0..40] of char; 
Birthday: TDateTime; 
Pid: array[0..16] of char; 
Title: array[0..20] of char; 
Female: Boolean; 
Street: array[0..40] of char; 
ZipCode: array[0..10] of char; 
City: array[0..40] of char; 
Phone, Fax, Department, Company: array[0..20] of char; 
Pn: array[0..40] of char; 
In: array[0..16] of char; 
Hi: array[0..8] of char; 
Account: array[0..20] of char; 
Valid, Status: array[0..10] of char; 
Country, NameAffix: array[0..20] of char; 
W, H: single; 
Bp: array[0..10] of char; 
SocialSecurityNumber: array[0..9] of char; 
State: array[0..2] of char; 
end; 

function Init(const tmpData: TMPData; var ErrorCode: integer; ResetFatalError: boolean = false): boolean; 

procedure GetData(out tmpData: TMPData); 

Mes signatures actuelles C# ressemble à ceci:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
public struct TMPData 
{    
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 40)] 
    public string Lastname; 
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 40)] 
    public string Firstname; 
    [MarshalAs(UnmanagedType.R8)] 
    public double Birthday; 
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 16)] 
    public string Pid; 
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 20)] 
    public string Title; 
    [MarshalAs(UnmanagedType.Bool)] 
    public bool Female; 
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 40)] 
    public string Street; 
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 10)] 
    public string ZipCode; 
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 40)] 
    public string City; 
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 20)] 
    public string Phone; 
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 20)] 
    public string Fax; 
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 20)] 
    public string Department; 
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 20)] 
    public string Company; 
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 40)] 
    public string Pn; 
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 16)] 
    public string In; 
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 8)] 
    public string Hi; 
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 20)] 
    public string Account; 
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 10)] 
    public string Valid; 
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 10)] 
    public string Status; 
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 20)] 
    public string Country; 
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 20)] 
    public string NameAffix; 
    [MarshalAs(UnmanagedType.I4)] 
    public int W; 
    [MarshalAs(UnmanagedType.I4)] 
    public int H; 
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 10)] 
    public string Bp; 
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 9)] 
    public string SocialSecurityNumber; 
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 2)] 
    public string State; 
} 

[DllImport("MyDll.dll")] 
[return: MarshalAs(UnmanagedType.Bool)] 
public static extern bool Init(TMPData tmpData, int ErrorCode, bool ResetFatalError); 

[DllImport("MyDll.dll")] 
[return: MarshalAs(UnmanagedType.Bool)] 
public static extern bool GetData(out TMPData tmpData); 

Je premier appel, dans Init l'BirthDay, LastName et FirstName . J'appelle alors GetData mais la structure de TMPData que je reçois est incorrecte. Les champs Prénom, Nom et Anniversaire sont remplis mais les données sont incorrectes. La cartographie est-elle correcte? ("array [0..40] of char" égal à "[MarshalAs (UnmanagedType.LPStr, SizeConst = 40)]")?

Mise à jour:

J'ai mis à jour le C# cartographie avec les commentaires pour ressembler à ceci:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
public struct TMPData 
{    
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 41)] 
    public string Lastname; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 41)] 
    public string Firstname; 
    [MarshalAs(UnmanagedType.R8)] 
    public double Birthday; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)] 
    public string Pid; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)] 
    public string Title; 
    [MarshalAs(UnmanagedType.Bool)] 
    public bool Female; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 41)] 
    public string Street; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)] 
    public string ZipCode; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 41)] 
    public string City; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)] 
    public string Phone; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)] 
    public string Fax; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)] 
    public string Department; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)] 
    public string Company; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 41)] 
    public string Pn; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)] 
    public string In; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)] 
    public string Hi; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)] 
    public string Account; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)] 
    public string Valid; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)] 
    public string Status; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)] 
    public string Country; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)] 
    public string NameAffix; 
    [MarshalAs(UnmanagedType.I4)] 
    public int W; 
    [MarshalAs(UnmanagedType.I4)] 
    public int H; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)] 
    public string Bp; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)] 
    public string SocialSecurityNumber; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 3)] 
    public string State; 
} 

La fonction Init:

[DllImport("MyDll.dll")] 
[return: MarshalAs(UnmanagedType.Bool)] 
public static extern bool Init(TMPData tmpData, int ErrorCode, bool ResetFatalError); 

échoue maintenant avec l'erreur suivante:

"Tentative de lecture ou d'écriture de la mémoire protégée. n cet autre souvenir est corrompu.

quand je l'appelle comme indiqué ci-dessous:

int errorCode = 0; 
bool resetLastError = true; 
TMPData tmpData = new TMPData(); 

     tmpData.Lastname = "TestLastName"; 
     tmpData.Firstname = "TestName"; 
     tmpData.Birthday = 28856.0; 
     tmpData.Pid = "12345678"; 
     tmpData.Title = null; 
     tmpData.Female = false; 
     tmpData.Street = null; 
     tmpData.ZipCode = null; 
     tmpData.City = null; 
     tmpData.Phone = null; 
     tmpData.Fax = null; 
     tmpData.Department = null; 
     tmpData.Company = null; 
     tmpData.Pn = null; 
     tmpData.In = null; 
     tmpData.Hi = null; 
     tmpData.Account = null; 
     tmpData.Valid = null; 
     tmpData.Status = null; 
     tmpData.Country = null; 
     tmpData.NameAffix = null; 
     tmpData.W = 0; 
     tmpData.H = 0; 
     tmpData.Bp = null; 
     tmpData.SocialSecurityNumber = 0; 
     tmpData.State = null; 

bool success = Init(tmpData, errorCode, resetLastError);  

Si je change le ByValTStr à LPSTR dans la définition de struct alors la fonction Init réussit mais la fonction retourne GetData les valeurs de chaîne incorrectes. Si je change de LPStr en ByValTStr la fonction Init échoue mais la fonction GetData renvoie les chaînes correctes. Je ne suis pas sûr si je devrais marshal array [0..x] de char comme LPStr de ByValTStr?

+0

0 (inclus) à 40 (inclus) = 41 articles? – dtb

+0

Puisque vous utilisez layoutkind.sequential du côté C#, vous devrez peut-être utiliser le modificateur "packed" du côté delphi (jamais essayé, cependant) – JMarsch

+0

Merci. J'ai changé la structure pour prendre en compte le 0ème élément. Mais j'ai toujours des problèmes comme indiqué dans la mise à jour. Je préférerais ne pas mettre à jour le côté delphi alors quel layoutkind dois-je utiliser pour éviter cela? –

Répondre

0

Quelle est la version de Delphi avec laquelle la DLL a été créée? Delphi 2009 a introduit Unicode, ce qui signifierait que vous auriez besoin d'utiliser un type de chaîne Unicode en C#, alors que si c'est avant Delphi 2009, il n'y a pas d'Unicode. LPStr est 8 bits, tandis que le type de caractère ByValTStr est déterminé par l'argument System.Runtime.InteropServices.CharSet de System.Runtime.InteropServices.StructLayoutAttribute appliqué à la structure conteneur.

Voir: http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.unmanagedtype.aspx

Vous avez dit à l'origine que vous obtenez des données en arrière, mais il était incorrect. Comment était incorrect? Détritus, ou juste échangé, tronqué, etc?

+0

La DLL a été construite avec Delphi 6. Les données que j'ai récupérées ressemblaient à des ordures. Je ne sais pas si il a été échangé mais il n'a pas été tronqué. –

+0

Donc, si vous regardiez vos données avant l'appel, elles étaient différentes des données après l'appel, mais elles ne ressemblaient pas du tout aux données que vous attendiez? –

+0

Oui si le paramètre est: UnmanagedType.LPStr l'appel Init fonctionne correctement. Si j'appelle GetData, la structure TMPData que j'ai récupérée a des données parasites pour le prénom, les champs de nom et les valeurs par défaut pour tous les autres champs. Si je passe à ByValTStr, l'appel Init échoue mais je peux toujours appeler GetData avec succès et les valeurs de retour sont correctes à partir de l'appel précédent réussi de Init. Je pense que je dois regarder le code Delphi et essayer de comprendre ce qui se passe. Je ne connais pas delphi mais j'espère pouvoir créer un dll delphi com plus facile à utiliser avec interop qu'un dll standard –

0

Comme dtb mentionné dans son commentaire, 0..40 est 41 caractères, pas 40. Apparemment, toutes vos définitions de chaînes ne tiennent pas compte du 0e élément. De plus, si je lis bien, (je ne connais pas C# mais je sais C,) il semble que vous définissiez les tableaux char comme pointeurs vers long (Unicode, 16 bits par caractère) cordes. Il y a deux problèmes potentiels avec cela. Tout d'abord, un tableau char déclaré de cette manière n'est pas un pointeur vers une chaîne, c'est une chaîne en ligne. Deuxièmement, c'est seulement un tableau de WideChars (16 bits par char) si cela a été construit avec la version Delphi 2009 ou plus tard. Sinon, c'est un tableau de caractères Ansi (8 bits par caractère).

+0

Merci pour les commentaires. Quelle définition suggérez-vous pour éviter les problèmes potentiels avec LPStr? J'ai essayé ByValTStr mais il ne résout que partiellement le problème comme indiqué dans la question mise à jour –

1

okay je l'ai enfin réussi. Merci pour l'aide.

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
public struct TMPData 
{    
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 41)] 
    public string Lastname; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 41)] 
    public string Firstname; 
    [MarshalAs(UnmanagedType.R8)] 
    public double Birthday; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)] 
    public string Pid; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)] 
    public string Title; 
    [MarshalAs(UnmanagedType.Bool)] 
    public bool Female; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 41)] 
    public string Street; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)] 
    public string ZipCode; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 41)] 
    public string City; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)] 
    public string Phone; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)] 
    public string Fax; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)] 
    public string Department; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)] 
    public string Company; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 41)] 
    public string Pn; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)] 
    public string In; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)] 
    public string Hi; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)] 
    public string Account; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)] 
    public string Valid; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)] 
    public string Status; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)] 
    public string Country; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)] 
    public string NameAffix; 
    [MarshalAs(UnmanagedType.R4)] 
    public int W; 
    [MarshalAs(UnmanagedType.R4)] 
    public int H; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)] 
    public string Bp; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)] 
    public string SocialSecurityNumber; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 3)] 
    public string State; 
} 

[DllImport("MyDll.dll")]   
[return: MarshalAs(UnmanagedType.Bool)]   
public static extern bool Init(ref TMPData tmpData,ref int ErrorCode, bool ResetFatalError);   

[DllImport("MyDll.dll")]   
[return: MarshalAs(UnmanagedType.Bool)]   
public static extern bool GetData(ref TMPData tmpData);