Hi,
I have a Delphi dll defined like this:
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);
My current c# signatures looks like this:
[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);
I first call Init setting the BirthDay, LastName and FirstName. I then call GetData but the TMPData structure I get back is incorrect. The FirstName, LastName and Birthday fields are populated but the data is incorrect. Is the mapping correct? ( "array[0..40] of char" equal to "[MarshalAs(UnmanagedType.LPStr, SizeConst = 40)]" )?
Update:
I have updated the c# mapping with the feedback to look like this:
[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;
}
The Init function:
[DllImport("MyDll.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool Init(TMPData tmpData, int ErrorCode, bool ResetFatalError);
now fails with the following error:
"Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
when I call it as shown below:
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);
If I change the ByValTStr to LPStr in the struct definition then the Init function succeeds but the GetData function returns incorrect string values. If I change LPStr back to ByValTStr the Init function fails but the GetData function returns the correct strings. I am not sure if I should marshal array[0..x] of char as LPStr of ByValTStr?