我有一个C函数,我想从C程序调用它。函数压缩输入的字节数组并输出新的压缩数组。看起来是这样的:

extern __declspec(dllexport) int Compress(chandle handle,
unsigned char *inputBuf, unsigned char **outputBuf, unsigned long *outputSize);

我已经把它翻译成C部分了。但是output我得到的是一个项目数组。
[DllImport("compresslib.dll", CallingConvention = CallingConvention.Cdecl)]
internal extern static int Compress(IntPtr handle, byte[] input, out byte[] output, out uint outputSize);

我该怎么做才能让它工作?
这是我在汉斯·帕桑的帮助下能够编写的工作代码
[DllImport("compresslib.dll", CallingConvention = CallingConvention.Cdecl)]
internal extern static int Compress(IntPtr handle, byte[] input, out IntPtr output, out uint outputSize);

// and this is how i call it
byte[] outputData;
int outputDataSize;
IntPtr outputDataP = IntPtr.Zero;
try
{
    int success = NativeMethods.Compress(handle,
    inputData, out outputDataP, out outputDataSize);
    if (success == -1)
    {
        throw new Exception("Compression failed.");
    }
    outputData = new byte[outputDataSize];
    Marshal.Copy(outputDataP , outputData , 0, (int)outputDataSize);
}
finally
{
    if (outputDataP != IntPtr.Zero)
    NativeMethods.tjFree(outputDataP);// release unmanaged buffer
}

return outputData ;

最佳答案

  ..., unsigned char **outputBuf, ...

这个函数有一个相当严重的问题,它也不能从C程序可靠地调用。调用方在使用输出缓冲区后需要释放它。这需要使用与C代码中使用的分配器完全相同的分配器。这在C程序中很难保证,而且经常出错。就像你的DLL用户没有使用和你使用的完全相同的编译器版本一样。他将使用一个不同版本的C运行库,一个使用自己堆的库。所以不可能释放缓冲区,因为他没有您使用的堆的句柄。
当你用pinvoke的时候,这几乎是不可能的,CLR当然完全不知道你使用的是什么C运行时版本,而且保证不会使用你使用的同一版本,因为它有自己的私有副本。
只得到一个字节的原因与这个问题有关,pinvoke marshaller不知道数组有多大,因为它没有创建数组。这是可以修复的,您需要将tbe[MarshalAs(UnmanagedType.LPArray),SizeParamIndex=3]属性应用于参数。这告诉pinvoke marshaller第4个参数包含数组的大小。
你需要解决内存管理问题,你不能就这样离开它,因为当pinvoke marshaller试图释放数组时,你会在XP上严重泄漏内存,在Vista和更高版本上出现硬崩溃。您需要更改C代码,以便将内存用于在已知堆上分配的返回输出缓冲区。这需要使用CoTaskMemAlloc()
另一个可能的解决方案是导出一个允许调用方释放缓冲区的函数。在这种情况下,应该声明参数out IntPtr并使用marshal.Copy()对自己进行封送处理,然后使用添加的函数释放缓冲区。
或者使用函数的完全不同的方法,比如让Compress()只压缩而不返回数据。客户端代码可以使用额外的函数来发现所需的缓冲区大小并获取数据的副本。

关于c# - 如何P/调用分配并返回指向新数组的指针的函数,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/21786958/

10-12 21:30
查看更多