danisius
danisius

Reputation: 597

Pinvoke cdecl convention with char**

In summary: I`m trying to use a C++ dll with cdecl calling convention all ran fine unless i get to this method signature:

int SaveToBuffer( char **buf, int *buf_size );

from what i have read i should use it like this:

    [DllImport("entry.dll",
    CallingConvention = CallingConvention.Cdecl,
    EntryPoint = "SaveToBuffer")]
    private static int SaveToBuffer( ref sbyte[] buf, ref int buf_size );

This does not work if this function is called from C# program crashes. I suppose this is related to Cdecl calling model and should use Marshal.AllocHGlobal(value), I can`t imagine how should it be done correct.

I also tryed this:

[DllImport("entry.dll",
    CallingConvention = CallingConvention.Cdecl,
    EntryPoint = "SaveToBuffer")]
private static int SaveToBuffer( IntPtr buf, ref int buf_size );

And then alocate enough memory

  IntPtr data=Marshal.AllocHGlobal(128000);
  int bufSize=128000;
  var sCode=SaveToBuffer(data,bufSize ); /* value of scode idicate succses*/

Calling this way i get return value from SaveToBuffer indicating function succseeded but: bufSize returns to 0 and how should i read my data from IntPtr.

I`m completly stuck on this.

Upvotes: 1

Views: 164

Answers (1)

David Heffernan
David Heffernan

Reputation: 613572

This is not an issue with the calling convention. The problem is in the buffer handling.

There's really only one sensible way to interpret the C++ argument types and the apparent intent to return an array of bytes. That is that the buffer is allocated and populated by the callee, and its address returned in buf. The buffer length is returned in buf_size.

With these semantics the function arguments cannot be marshalled automatically and you'll have to do it manually:

[DllImport("entry.dll", CallingConvention = CallingConvention.Cdecl)]
private static int SaveToBuffer(out IntPtr buf, out int buf_size);

Call like this

IntPtr buf;
int buf_size;
int retval SaveToBuffer(out buf, out buf_size);
// check retval

Then copy to byte array like this:

byte[] buffer = new byte[buf_size];
Marshal.Copy(buf, buffer, 0, buf_size);

The DLL will also need to export a function to deallocate the unmanaged buffer.

Upvotes: 3

Related Questions