2

I have a Delphi 2010 DLL that will be used to compress some data from a C# APP. The DLL function looks like this:

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

The C# method looks like this:

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

My problem is that aOutPutString is being truncated, only part of the data is being seen by the C# App. If I change aOutPutString inside the Delphi DLL to be a simple literal constant (only for testing) it works fine.

Inside the DLL, I am working with strings. In the end of the function, I call:

StrPCopy(aOutPutString, vOutOutAnsiStr);

To convert an AnsiString do PAnsiChar.

I guess I should not be using PAnsiChar but an array of byte, but I am not sure how to do that.

4
  • Strings are not synonymous with "binary" in the compression/serialization sense... This would probably work a lot better with byte[] Commented Sep 29, 2012 at 13:17
  • I totally agree, but I have no idea how to do that. Can you show an example please? Commented Sep 29, 2012 at 13:22
  • Sorry, I haven't touched Delphi/Pascal in over a decade. Commented Sep 29, 2012 at 13:25
  • @Marc Agreed, byte[] would seem to be the most natural. Commented Sep 29, 2012 at 16:48

2 Answers 2

6

Using PAnsiChar makes the string truncate at the first '0' byte.

Instead of having an out parameter of the type PAnsiChar, you can have two out parameters: one of them is a pointer to a byte array, and the other is an integer which will contain the size of the array.

You have to be careful not to free the array on the DLL, once you need to access it later. On C# side, in the external function declaration, you'll catch the pointer as IntPtr and use the Marshal.Copy method to copy the content to a C# byte array.

Sign up to request clarification or add additional context in comments.

Comments

2

Since you are really working with byte arrays I would declare them as such in the C# function.

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

On the Delphi side, you are currently using PAnsiChar, but say that you would rather be using a byte array. I'd use PByte on the Delphi side then, and the function would look like this:

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

For the error message text, I've used WideString and MarshalAs(EnumeratedType.BStr) to make the memory allocation easier. Because a BSTR is allocated of the shared COM heap, it can be allocated in the Delphi code as a WideString and then correctly deallocated on the other side of the boundary.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.