从Delphi DLL发送二进制数据做C#应用程序

时间:2012-09-29 13:05:05

标签: c# delphi pinvoke delphi-2010

我有一个Delphi 2010 DLL,用于压缩来自C#APP的一些数据。 DLL函数如下所示:

function CompressString(aInputString: PAnsiChar; aInputStringSize: Integer; 
  var aOutPutString: PAnsiChar; var aOutPutStringSize: Integer; 
  var aErrorMsgBuffer: PAnsiChar; var aErrorMsgBufferSize: integer): Integer; 
  stdcall; export;

C#方法如下所示:

[DllImport("MyDLL.dll", CallingConvention=CallingConvention.StdCall, CharSet=CharSet.Ansi)]
public static extern int CompressString(string aInputString, 
  int aInputStringSize, ref string aOutPutString, 
  out int aOutPutStringSize, ref string aErrorMsgBuffer, 
  out int aErrorMsgBufferSize);

我的问题是aOutPutString被截断,C#App只能看到部分数据。如果我将Delphi DLL中的aOutPutString更改为一个简单的文字常量(仅用于测试),它可以正常工作。

在DLL中,我正在使用字符串。在函数的最后,我打电话:

StrPCopy(aOutPutString, vOutOutAnsiStr);

转换AnsiStringPAnsiChar

我想我不应该使用PAnsiChar而是使用array of byte,但我不知道该怎么做。

2 个答案:

答案 0 :(得分:6)

使用PAnsiChar使字符串在第一个'0'字节处截断。

您可以有两个out参数,而不是类型PAnsiChar的out参数,其中一个是指向字节数组的指针,另一个是包含数组大小的整数

一旦您需要稍后访问它,您必须小心不要释放DLL上的数组。在C#端,在外部函数声明中,您将指针捕获为IntPtr并使用Marshal.Copy方法将内容复制到C#字节数组。

答案 1 :(得分:2)

因为你真的在使用字节数组,所以我会在C#函数中声明它们。

[DllImport("MyDLL.dll")]
public static extern int CompressByteArray(
    byte[] InputBuffer,  
    int InputBufferLength, 
    byte[] Output, 
    ref int OutputBufferLength, 
    [MarshalAs(UnmanagedType.BStr)]
    out string ErrorMsg
);

在Delphi方面,您当前正在使用PAnsiChar,但是说您宁愿使用字节数组。那么我在Delphi端使用PByte,函数看起来像这样:

function CompressByteArray(
  InputBuffer: PByte;
  InputBufferLength: Integer;
  OutputBuffer: PByte;
  var OutputBufferLength: Integer;
  out ErrorMsg: WideString
): Integer; stdcall;

对于错误消息文本,我使用了WideStringMarshalAs(EnumeratedType.BStr)来简化内存分配。因为BSTR是为共享COM堆分配的,所以可以在Delphi代码中将其作为WideString分配,然后在边界的另一侧正确释放。