使用 char** 调用 cdecl 约定

Pinvoke cdecl convention with char**

总结: 我正在尝试使用带有 cdecl 调用约定 的 C++ dll 所有 运行 都很好,除非我得到这个方法签名:

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

根据我的阅读,我应该这样使用它:

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

如果从 C# 程序崩溃调用此函数,这将不起作用。 我想这与 Cdecl 调用模型有关,应该使用 Marshal.AllocHGlobal(value), 我无法想象应该如何正确完成。

我也试过这个:

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

然后分配足够的内存

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

通过这种方式调用,我从 SaveToBuffer 中获得了 return 值,指示函数成功但是:bufSize returns 变为 0,我应该如何从 IntPtr 读取数据。

我完全坚持这一点。

这不是调用约定的问题。问题出在缓冲区处理中。

实际上只有一种合理的方式来解释 C++ 参数类型和 return 字节数组的明显意图。也就是说,缓冲区由被调用者分配和填充,其地址 returned in buf。缓冲区长度在 buf_size 中 returned。

使用这些语义,函数参数无法自动编组,您必须手动进行:

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

这样调用

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

然后像这样复制到字节数组:

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

DLL 还需要导出一个函数来释放非托管缓冲区。