无效的托管/非托管类型组合与嵌入式动态分配的阵列 [英] Invalid Managed/Unmanaged Type Combination With Embedded, Dynamically-Allocated Array
问题描述
我在非托管Win32 C ++ DLL中有一个通用的构造:
I have a common construct in an unmanaged Win32 C++ DLL:
// FirstElemPtrContainer.h
#include "stdafx.h"
typedef unsigned char elem_type; // a byte
typedef struct FirstElemPtrContainer {
unsigned char num_elems;
void *allocd_ary;
} FirstElemPtrContainer;
该结构中的void *旨在包含一个指向已分配字节数组的第一个元素的指针.
The void* in the struct is meant to contain a pointer to the first element of an allocated byte array.
使用此定义的DLL然后导出函数来分配,填充和取消分配结构:
The DLL that uses this definition then exports functions to allocate, populate, and deallocate the struct:
// The exported allocator function.
extern "C" _declspec(dllexport)
FirstElemPtrContainer *BuildStruct(int elem_count)
{
FirstElemPtrContainer *fepc_ptr = new FirstElemPtrContainer;
fepc_ptr->num_elems = elem_count;
elem_type *ary = new elem_type[fepc_ptr->num_elems];
for (int i = 0; i < fepc_ptr->num_elems; i++)
{
ary[i] = ((i + 1) * 5); // multiples of 5
}
fepc_ptr->allocd_ary = ary;
return fepc_ptr;
}
// The exported deallocator function.
extern "C" _declspec(dllexport) void
DestroyStruct(FirstElemPtrContainer *fepc_ptr)
{
delete[] fepc_ptr->allocd_ary;
delete fepc_ptr;
}
这些功能对于本机呼叫者来说很好.
These work just fine for a native caller.
在C#中,我尝试通过PInvoke描述相同的结构:
In C#, I try to describe this same structure via PInvoke:
[StructLayout(LayoutKind.Sequential)]
public struct FirstElemPtrContainer
{
public byte num_elems;
[MarshalAs(UnmanagedType.LPArray,
ArraySubType = UnmanagedType.U1, SizeConst = 4)]
public IntPtr allocd_ary;
}
...并像这样描述通话界面:
... and describe the call interface like so:
public static class Imports
{
[DllImport("MyLib", CallingConvention = CallingConvention.Winapi)]
public static extern IntPtr BuildStruct(int elem_count);
[DllImport("MyLib", CallingConvention = CallingConvention.Winapi)]
public static extern void DestroyStruct(IntPtr fepc_ptr);
}
现在我尝试调用我的界面:
Now I attempt to call my interface:
class Program
{
const int NUM_ELEMS = 4;
static void Main(string[] args)
{
IntPtr fepc_ptr = Imports.BuildStruct(NUM_ELEMS);
if ( fepc_ptr == IntPtr.Zero )
{
Console.WriteLine("Error getting struct from PInvoke.");
return;
}
FirstElemPtrContainer fepc =
(FirstElemPtrContainer)Marshal.PtrToStructure(fepc_ptr,
typeof(FirstElemPtrContainer));
//...
}
}
PtrToStructure()调用给出错误无法整理类型为'MyLibInvoke.FirstElemPtrContainer'的字段'allocd_ary':无效的托管/非托管类型组合(Int/UInt必须与SysInt或SysUInt配对)."
The PtrToStructure() call gives the error "Cannot marshal field 'allocd_ary' of type 'MyLibInvoke.FirstElemPtrContainer': Invalid managed/unmanaged type combination (Int/UInt must be paired with SysInt or SysUInt)."
您会看到我已经对特定数量的元素进行了硬编码,我们假设调用者坚持使用.我也添加了一个ArraySubType子句,尽管似乎没有什么不同.为什么类型不匹配投诉?
You can see that I've hard-coded a particular number of elements, which we'll assume the caller adheres to. I've also added an ArraySubType clause, though it seems not to make a difference. Why the type mismatch complaint?
推荐答案
您的结构应这样声明:
[StructLayout(LayoutKind.Sequential)]
public struct FirstElemPtrContainer
{
public byte num_elems;
public IntPtr allocd_ary;
}
必须这样做,因为 allocd_ary
是指向非托管内存的指针,并且不能由p/invoke编组器进行编组.
it has to be done this way because allocd_ary
is a pointer to unmanaged memory and cannot be marshalled by the p/invoke marshaller.
In order to read the contents of allocd_ary
you can use Marshal.Copy
.
FirstElemPtrContainer fepc = (FirstElemPtrContainer)Marshal.
PtrToStructure(fepc_ptr, typeof(FirstElemPtrContainer));
byte[] ary = new byte[fepc.num_elems];
Marshal.Copy(fepc.allocd_ary, ary, 0, ary.Length);
我怀疑 CallingConvention.Winapi
是错误的,您应该使用 CallingConvention.Cdecl
.
I suspect that CallingConvention.Winapi
is wrong and that you should be using CallingConvention.Cdecl
.
这篇关于无效的托管/非托管类型组合与嵌入式动态分配的阵列的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!