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 (inclus) à 40 (inclus) = 41 articles? – dtb
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
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? –