2010-06-11 64 views
1

我有这样定义的德尔福DLL:调用德尔福DLL从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); 

我现在的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); 

我首先调用初始化设置生日,姓氏和名字。然后我调用GetData,但我找回的TMPData结构不正确。 FirstName,LastName和Birthday字段已填充,但数据不正确。映射是否正确? (“char [array [0..40]”等于“[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; 
} 

初始化函数:

[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在结构定义,随后的初始化函数成功,但功能的GetData返回不正确的字符串值。如果我将LPStr更改回ByValTStr,则Init函数将失败,但GetData函数会返回正确的字符串。我不知道我是否应该将数组[0..x]作为BytrVTSTR的LPStr编组?

+0

0(含)至40(含)= 41项? – dtb 2010-06-11 22:06:08

+0

由于您在c#端使用layoutkind.sequential,因此您可能必须在delphi端使用“packed”修饰符(虽然从未尝试过) – JMarsch 2010-06-11 22:32:27

+0

谢谢。我已经改变了结构以考虑第0个元素。但是我仍然遇到了更新中指出的问题。我宁愿不更新德尔福方面,所以我必须使用什么layoutkind来避免这种情况? – 2010-06-14 20:05:38

回答

0

Delphi是用什么版本构建的DLL?德尔福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

你原来说你获取数据的背后,却是不正确的。如何不正确?垃圾,或只是交换,截断等?

+0

dll是用Delphi 6构建的。我收回的数据看起来像垃圾。不知道它是否被交换过,但没有被截断。 – 2010-06-14 22:36:48

+0

因此,如果您在调用之前查看数据,那么调用后的数据会有所不同,但它与您期望的数据并不相同? – 2010-06-15 07:10:45

+0

如果设置为:UnmanagedType.LPStr,则Init调用可以正常工作。如果我调用GetData,那么我得到的TMPData结构中的名字,姓氏字段和所有其他字段的默认值都有垃圾数据。如果我更改为ByValTStr,则Init调用将失败,但我仍然可以成功调用GetData,并且返回值与以前的Init成功调用相同。我想我需要看一下Delphi代码,并试图弄清楚发生了什么。我不知道德尔福,但希望我可以创建一个COM更容易使用互操作比标准的DLL – 2010-06-15 18:25:30

0

由于dtb在他的评论中提到,0..40是41个字符,而不是40个。显然你所有的字符串定义都没有考虑到第0个元素。 (我不知道C#但是我知道C),它看起来像将数组定义为指向long的指针(Unicode,每字符16位)字符串。这有两个潜在的问题。首先,char数组声明的方式不是指向字符串的指针,而是一个内联字符串。其次,如果这是使用Delphi版本2009或更高版本构建的,则它只是WideChars(每个字符16位)的数组。否则,它是一个Ansi数组(每个字符8位)的字符。

+0

感谢您的反馈。你会建议什么样的定义来避免LPStr的潜在问题?我已经尝试了ByValTStr,但它只是部分解决了问题,如更新后的问题 – 2010-06-14 20:12:20

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