将具有未知大小数组的结构从非托管代码传递到托管代码

Passing structure with array of unknown size from unmanaged to managed code

我在将 void 指针从非托管代码传递到托管代码时遇到问题。 .cpp文件中有函数指针

TESTCALLBACK_FUNCTION testCbFunc;

TESTCALLBACK_FUNCTION 采用 C++ 结构

typedef void (*TESTCALLBACK_FUNCTION )(TImage image);
struct TImage
{
    int Width;                      //width
    int Height;                     //height
    void *Buf;                      //data buffer
};

C#函数和结构

public void TImageReceived(TImage image)
{
    // logic
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1), Serializable]
public struct TImage
{
    public int Width;
    public int Height;
    public IntPtr Buf;
}

TImageReceived 传递给非托管代码,当它被调用时我收到异常。

System.Runtime.InteropServices.SafeArrayTypeMismatchException

如果我通过非托管代码在字段 Buf 中传递 NULL,一切都会正常工作。

我知道 MarshalAs 属性,但问题是我不能使用 SizeConst,因为 Buf 大小总是不同的。但它的大小始终为 Width*Height。

[MarshalAs(UnmanagedType.ByValArray,SizeConst=???)]

如何将 void* 从非托管代码转换为托管代码?

根据您的评论,并假设您的 C++ 代码中的 TImage 巧妙地映射到您的结构(警告 - 如果您使用 Borland VCL 中的 TImage,那么这可能不会像你希望的那样整齐地映射)

Buf has a size Width*Height

您最好的选择是使用 Marshal.Copy,例如

using System.Runtime.InteropServices;

/* ... */

[StructLayout(LayoutKind.Sequential)]
public struct TImage 
{
    public int Width;
    public int Height;
    public IntPtr Buf;
}

/* ... */

public void TImageReceived(TImage image)
{
    var length = image.Height * image.Width;
    var bytes = new byte[length];
    Marshal.Copy(image.Buf, bytes, 0, length);
}

相关: Marshalling struct with embedded pointer from C# to unmanaged driver

...然而...

如果 TImage 属于 Borland 的 VCL 那么我建议重新考虑该结构,因为它将涉及编组从 TImage 的基础 class 继承的其他数据(Borland 的文档不清楚 class' 布局) - 在这种情况下,直接传递参数会更容易:

public void TImageReceived(IntPtr buf, int width, int height)
{
    var length = height * width;
    var bytes = new byte[length];
    Marshal.Copy(buf, bytes, 0, length);

    // etc.
}