6

我正在使用本机 DLL。我不确定,但我认为我不能使用 PInvoke decl,因为它不导出任何函数并且没有清单。DLL 附带一个头文件,说明如何使用它。头文件定义了无数的结构、枚举和一个类,使用工厂方法构建,该工厂方法通过 Windows 函数访问::GetProcAddress(通过默默无闻的安全性)。此类包含我想在托管代码中使用的功能。

我已经成功地将这个类包装在一个 CLI ref 类中,并且可以在它上面调用一些简单的方法,也可以包装这些方法。

我正在经历将一些结构从头文件转换为托管结构的过程。例如,本机结构:

struct FooACL{
    int               action;                
    unsigned long     from,to;               
    char              comment[64]; 
    int               reserved[17];          
};

变成托管结构:

[StructLayout(LayoutKind::Sequential, CharSet = CharSet::Ansi)]
public value struct ManagedFooACL{
     int   action;                
     int   from,to;     
     [MarshalAs(UnmanagedType::ByValTStr, SizeConst = 64)]
     String^    comment;
     [MarshalAs(UnmanagedType::ByValArray, SizeConst = 17)]
     array<int>^ reserved;
};

据我所知,这应该使托管结构 blittable 吗?以及遵循类似模式或嵌套结构级别的任何其他结构。只要指定了一个布局并且没有一个 blittable 用 MarshalAs 装饰,那么整个结构会是 blittable 吗?

因此,我正在尝试查看是否有一种方法可以使用Marshal::CopyMarshal::PtrToStructureFooACL*数组转换为array<ManagedFooACL>^.

我从函数调用中获取 FooACL* 数组;我自己不分配。

int total;
FooACL* foos = unamagedClass->GetFooACLS(&total);

total是获取返回数组大小的输入/输出。

到目前为止我设法做了什么,以及什么工作是:

ManagedFooACL first = static_cast<ManagedFooACL>(Marshal::PtrToStructure(IntPtr(&foos [0]), ManagedFooACL::typeid));

我无法理解的是为什么这不会:

array<ManagedFooACL>^ mfoos = gcnew array<ManagedFooACL>(total);
Marshal::PtrToStructure(IntPtr(&foos), mfoos);

这会引发:

System.ArgumentException was unhandled
  Message=The specified structure must be blittable or have layout information.
Parameter name: structure
  Source=mscorlib
  ParamName=structure

有没有办法在一次调用中复制数组数据,还是我真的需要做一个 for 循环?所有这些编组功能似乎有点愚蠢。

4

1 回答 1

3

做了一些更多的研究后,答案似乎是否定的。没有循环就不可能自动编组一个arrayof s。struct

struct我认为编组工作的主要原因PtrToStructure是结构是静态/预定义的。编译器知道如何布局内存。由于您获得了动态大小array,因此无法提前指定内存布局。所以你必须循环s的动态数量struct

或者,如果你知道你总是会得到一个长度为 X 的数组,你可以定义你自己的托管struct持有一个元素,即ManagedFooACL带有 aByValArraySizeConstX 值的数组,并将本机array转换为struct.

于 2013-01-02T22:12:24.243 回答