c# - 正确的 PInvoke 签名以使用带有 C# 保留内存的嵌套结构?

标签 c# c++ struct pinvoke

我有一个非托管 DLL,我正在尝试使用它,它利用了一些嵌套结构,并在其末尾保留了成员。我在将它们转换为 C# 时遇到问题。

我尝试将代码精简到最重要的部分。 ParentStruct 具有三个不同子结构的四个实例的成员。所有这三个不同的子结构都有 void* 数组来保留内存以供将来使用。

我尝试过将保留值作为 IntPtrs,我尝试过打开不安全代码并使用固定关键字(并将它们更改为整数)。我已经尝试在结构的末尾实际放置适当数量的连续 IntPtr。似乎没有任何作用。

在某些情况下,我会收到一条错误消息(一条无信息的消息,表明某个线程的某个地址出现错误)。但大多数时候,应用程序只是死掉而没有错误消息。我确定那是因为我在这里弄乱了非托管内存。

仅供引用,实际的 Pinvoke 有一个类似的签名

[DllImport("MyDll.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
internal static extern void UseStructs([In,Out] ref ParentStruct parent);

那么在 C# 中声明这些结构以便我可以使用它们的正确方法是什么?

typedef struct
{
    ChildStruct1           childOne;
    ChildStruct2           childTwo;
    ChildStruct2           childTwoB;
    ChildStruct3           childThree;

#if defined K_64_BIT
    /// Reserved for future implementation
    void*          Reserved[15];
#elif defined K_32_BIT
    /// Reserved for future implementation
    void*          Reserved[14];
#endif

} ParentStruct;

typedef struct
{

    bool  Valid;
    float x;
    float y;

    /// Reserved for future implementation.
    void*               Reserved[16];
} ChildStruct3;

typedef struct
{

    bool          Found;
    XYPairFloat xyPair;


    /// Reserved for future implementation.
    void*         Reserved[16];
} ChildStruct2;


typedef struct
{
    unsigned char* imageData;
    RectInt      rectInt;

#if defined QUICK_LINK_64_BIT
    /// Reserved for future implementation
    void*          Reserved[14];
#elif defined QUICK_LINK_32_BIT
    /// Reserved for future implementation
    void*          Reserved[12];
#endif

} ChildStruct1;

typedef struct
{

    int x;
    int y;
    int width;
    int height;
} RectInt;

typedef struct
{
    float x;
    float y;
} XYPairFloat;

编辑:我想我已经更接近了,因为我现在收到一条至少是人类可读的错误消息。但它仍然不起作用。我在保留成员上使用了固定关键字,并适本地设置了成员属性的 SizeConst 部分。我所做的其他一切都只是基本的 pinvoke 工作。但是,我收到错误:

The type definition of this field has layout information but has an invalid managed/unmanaged type combination or is unmarshalable.

引用 ChildStruct1 childOne 成员,这是第一个成员,因此我大胆猜测它也适用于其他成员。想法?

编辑 2:根据 Mark Heath 的请求,这是我对 ChildStruct1 使用的实际定义:

[StructLayout(LayoutKind.Sequential)]
internal unsafe struct ChildStruct1
{
    [MarshalAs(UnmanagedType.LPStr)]
    public string imageData;
    public RectInt rectInt;
    [MarshalAs(UnmanagedType.LPArray, SizeConst=12)]
    public fixed int Reserved[12];
}

编辑3:我做了更多的挖掘。如果我注释掉保留成员,我遇到的错误就会消失。显然这是行不通的。但我猜这个特定的错误是由我定义该成员的方式引起的。

最佳答案

您可以尝试根据 Essential P/Invoke 将最后一个值更改为 IntPtr 数组

所以改变:

[MarshalAs(UnmanagedType.LPArray, SizeConst=12)]
public fixed int Reserved[12];

至:

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
public IntPtr[] Reserved;

关于c# - 正确的 PInvoke 签名以使用带有 C# 保留内存的嵌套结构?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13590097/

相关文章:

C++ 链表不保留新节点

Swift 4 - 为多个按钮创建通用功能

c# - 在动态创建的 Pages() 上覆盖 VerifyRenderingInServerForm

c++ - 为什么 Boost 的 QuickSort 比 Julia 的 QuickSort 慢?

c++ - 对 const 的右值引用有什么用吗?

c++ - 是否在退出时清理

C-错误 : array type has incomplete element type in a extern struct declaration

c# - 在 C# 中显示完整的 SSH shell 输出,包括登录消息和提示

c# - 通过重新排序优化 if 语句

使用流的 C# 链接方法