2

我有一个 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# 应用程序只能看到部分数据。如果我aOutPutString在 Delphi DLL 中更改为一个简单的文字常量(仅用于测试),它可以正常工作。

在 DLL 中,我正在处理字符串。在函数结束时,我调用:

StrPCopy(aOutPutString, vOutOutAnsiStr);

转换一个AnsiStringdo PAnsiChar

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

4

2 回答 2

6

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

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

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

于 2012-09-29T15:27:16.140 回答
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,但说您宁愿使用字节数组。然后我会PByte在 Delphi 端使用,函数看起来像这样:

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

对于错误消息文本,我使用WideStringMarshalAs(EnumeratedType.BStr)使内存分配更容易。因为 aBSTR是从共享 COM 堆中分配的,所以它可以在 Delphi 代码中作为 a 进行分配WideString,然后在边界的另一侧正确地释放。

于 2012-09-29T14:11:05.713 回答