从c#调用delphi dll

时间:2010-06-11 21:58:42

标签: c# delphi dllimport

我有一个像这样定义的Delphi dll:

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);

我目前的c#签名如下所示:

[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);

我首先调用Init设置BirthDay,LastName和FirstName。然后我调用GetData,但我得到的TMPData结构不正确。将填充FirstName,LastName和Birthday字段,但数据不正确。映射是否正确? (“array [0..40] of char”等于“[MarshalAs(UnmanagedType.LPStr,SizeConst = 40)]”)?

更新

我已经使用反馈更新了c#映射,如下所示:

[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; 
} 

Init函数:

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

现在因以下错误而失败:

“尝试读取或写入受保护的内存。这通常表示其他内存已损坏。

当我打电话给它时如下所示:

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);    

如果我在结构定义中将ByValTStr更改为LPStr,则Init函数成功,但GetData函数返回不正确的字符串值。如果我将LPStr更改回ByValTStr,则Init函数会失败,但GetData函数会返回正确的字符串。我不确定我是否应该将char的数组[0..x]编组为ByValTStr的LPStr?

3 个答案:

答案 0 :(得分:1)

好吧我终于搞定了。谢谢你的帮助。

[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);    

答案 1 :(得分:0)

正如dtb在评论中提到的,0..40是41个字符,而不是40个。显然你的所有字符串定义都没有考虑到第0个元素。

另外,如果我正确阅读,(我不知道C#,但我知道C,)看起来你将char数组定义为指向long(Unicode,16位)每个字符串)。这有两个潜在的问题。首先,声明这种方式的char数组不是指向字符串的指针,它是一个内联字符串。其次,如果使用Delphi 2009或更高版本构建,它只是一个WideChars数组(每个字符16位)。否则,它是一个Ansi数组(每个字符8位)字符。

答案 2 :(得分:0)

使用什么版本的Delphi构建DLL? Delphi 2009引入了 Unicode ,这意味着你需要在C#中使用Unicode字符串类型,而如果它是在Delphi 2009之前,那么就没有Unicode。 LPStr为8位,而 ByValTStr 的字符类型由应用于包含的System.Runtime.InteropServices.StructLayoutAttribute的System.Runtime.InteropServices.CharSet参数确定。结构

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

你原来说你收到了数据,但这是不正确的。怎么不对?垃圾,还是只是交换,截断等?