我有一个非托管 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/