【问题标题】:Passing structure with array of unknown size from unmanaged to managed code将具有未知大小数组的结构从非托管代码传递到托管代码
【发布时间】:2016-06-01 21:03:46
【问题描述】:

我在将 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* 从非托管代码转换为托管代码?

【问题讨论】:

  • 如果没有确定大小的机制,您也无法在非托管世界中使用void* 做很多事情。那么您的非托管代码如何确定Buf 的大小?是否有基于WidthHeight 的计算? (例如,也许Buf 只是一个表示宽度*高度的字节序列?)
  • 是的,Buf 的大小为 Width*Height。

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


【解决方案1】:

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

Buf 的大小为 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 的基类继承的其他数据(Borland 的文档不清楚该类的布局) - 在在这种情况下,直接传递参数会更容易:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-06
    • 1970-01-01
    • 2013-03-06
    相关资源
    最近更新 更多