c#调用Delphi DLL参数为结构体数组

李席高 发布于 2012/08/27 11:34
阅读 4K+
收藏 1
Delphi结构体如下
 PICRecord=^TICRecord;
  TICRecord=packed record
  Card: array[0..19] of char;
  timeString: array[0..19] of char;
  EmpId: array[0..9] of char;
  mark: Integer;
  flag: Integer;
  cardTimes: Integer;
  end;
Delphi相关DLL函数
   function AddData(var A:integer;var Records:array of TICRecord):integer; stdcall;
  var
  i ,Count :integer;
  begin
  Count:=16;

  for i:=0 to Count do
  begin
  Records[i].Card:='1789456456';
  end;
  result:=A;
  end;
  exports AddData;
C#结构体如下
public struct TICRecord
  {
  [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)]
  public string Card; // 卡号字符串
  [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)]
  public string TimeString; // 14位刷卡时间字符串, 格式为yyyymmddhhnnss
  [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)]
  public string EmpID;
  public Int32 Mark; // 读卡机标识字符
  public Int32 Flag; // 存储卡的结果
  public Int32 CardTimes; // 发卡次数, 0-15
  }

C#调用方法
[DllImport("Test.dll", EntryPoint = "AddData", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern Int32 AddData(ref Int32 A,[In,Out] TICRecord[] B, Int32 Records_Size);




  TICRecord[] TICRecordList = new TICRecord[Records_Size];
  int Result = DongBao.AddData(ref a, TICRecordList, Records_Size);

  MessageBox.Show( "返回值:"+Result+ "");

  string Str = "";
  for (int i = 0; i < Records_Size; i++)
  {
  Str += i + " ";
  Str += Encoding.UTF8.GetString(Encoding.UTF8.GetBytes(TICRecordList[i].Card)) + "\r\n";

  }

  MessageBox.Show("如果成功则返回100:现在返回的是" + Str + "");

返回结果,只有第一条有记录,其他的都为空,求处理过相关问题的老师指导一下
加载中
0
李席高
李席高

多谢各位支持,问题个人已经处理成功了,我把我处理的技术分享一下,


依时利传结构体数组处理方法说明

因为结构体数组本身就是名称本身就是指针,因此不能加REF设置,因此只能申明为[In,out],之前也这样处理过,同样报内存不存在或已坏

原理

C#                                                      Delphi

TICRecardArray                                       TICRecardArray

 

 

 

 

 

 

 


指针的传址就是内存地址的传递,因为保证传过程中不会将数据变成乱码

1.结构内存声明为排序空间([StructLayout(LayoutKind.Sequential)]

2.字段为数据添加声明大小[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]

 

1.运行时遇到了错误。此错误的地址为 0x791c7b88,在线程 0x1604 上。错误代码为 0xc0000005。此错误可能是 CLR 中的 bug,或者是用户代码的不安全部分或不可验证部分中的 bug。此 bug 的常见来源包括用户对 COM-interop PInvoke 的封送处理错误,这些错误可能会损坏堆栈。

处理方法:不能添加REF设置等设置

 

2.运行中内存丢失或已坏

处理方法:结构体保证完全一致,并且初始化也一样

 

3.返回数据乱码,或只有第一条正确

处理方法:初始化空间太少,或者是因为定义大小不一致,或者内存大小偏移

 

0
szf
szf

感觉上有两个问题:

1.貌似C#定义中,每个针对Delphi array of char的都多了一个字节,且empid长度也不对。

2.Delphi的array of 动态数组,并不是标准win32api类型,建议用其它方式代替它。

0
李席高
李席高
我使用char 也是不行
  [MarshalAs(UnmanagedType.ByValArray, SizeConst = 21)]
                          public char[] Card;              
0
szf
szf

仔细看来, 不光是长度错了,类型也错了。

对于Delphi(不是Unicode版本)来说,Char数据类型是8位的(或改成AnsiChar),所以

TICRecord=packed record
  Card: array[0..19] of char;
  timeString: array[0..19] of char;
end;

这个结构体正好占20+20=40个byte的内存长度

 

而C#的char类型(string类型是铁定不能用于跨语言数据交互的),是一个unicode字符,长度16位,所以定义char []...肯定是错的。

我感觉应该如下定义

 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]

                          public byte[] Card; 

 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]

                          public byte[] TimeString; 
 
没条件也没时间试了,凭N年的经验了~~
返回顶部
顶部