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

时间:2016-02-20 05:53:24

标签: c# c++ marshalling void-pointers

我有一个问题,将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 ,一切都会正常工作。

我知道Marshal是atrribute,但问题是我不能使用SizeConst,因为Buf大小总是不同的。但它的大小总是宽*高。

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

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

1 个答案:

答案 0 :(得分:1)

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

  

Buf的大小宽度*高度

您最好的选择是使用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基类的其他数据(Borland的文档不清楚该类' layout) - 在这种情况下,直接传递参数会更容易:

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.
}