使用 IntPtr 将结构数组从 C# 传递到C++
本文关键字:C++ IntPtr 结构 数组 使用 | 更新日期: 2023-09-27 18:31:06
我有一个结构 -->
public struct readers
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1000)]
public IntPtr[] tag_list;
};
编组必须在"IntPtr[] tag_list"和结构TAG_IN_PARAM之间完成
[StructLayout(LayoutKind.Sequential)]
internal struct TAG_IN_PARAM
{
public int vis_cnt;
public bool valid;
}
它也是一个数组 => TAG_IN_PARAM[] tag_list = 新的TAG_IN_PARAM[1000];
我想将结构"读取器"从 C# 传递到C++ DLL。但是,我一直在进行编组,但是垃圾值正在DLL端出现。
分配内存Marshal.StructureToPtr(tag_list[j], Reader.tag_list[j], false);
或者,如果我能用任何其他方法,请传达。任何帮助将不胜感激。提前谢谢。
根据您的
评论,您尝试匹配的C++类型是:
class Readers
{
public:
TAG_IN_PARAM* tag_list;
};
这是一个指向数组的指针。
但 C# 代码声明了一个内联数组。您的 C# 代码将匹配以下内容:
class Readers
{
public:
TAG_IN_PARAM tag_list[1000];
};
显然,这不是你想要的路。
需要更改 C# 代码以使其匹配。不幸的是,当数组位于结构内时,编组器似乎不会将数组封送为指向第一个元素的指针。由于数组是结构中的唯一内容,因此您应该简单地将数组作为参数传递。
或者,如果您绝对需要在结构中传递数组,那么我认为您需要手动封送。喜欢这个。
public struct readers
{
public IntPtr tag_list;
};
然后,您可以简单地固定阵列。
TAG_IN_PARAM[] tag_list = ...;
GCHandle pinnedArray = GCHandle.Alloc(tag_list, GCHandleType.Pinned);
readers r;
r.tag_list = pinnedArray.AddrOfPinnedObject();
// call function passing r
pinnedArray.Free();
不幸的是,这并不完全有效,因为 C# bool
不是可 blitable。因此,您可以通过对该字段使用不同的类型来解决此问题。例如,byte
或int
取决于C++方面的情况。
还有另一种选择是在每个字段上Marshal.StructureToPtr
。这将像这样运行:
TAG_IN_PARAM[] tag_list = ...;
int structSize = Marshal.SizeOf(typeof(TAG_IN_PARAM));
r.tag_list = Marshal.AllocHGlobal(tag_list.Length*structSize);
IntPtr ptr = r.tag_list;
for (int i = 0; i < tag_list.Length; i++)
{
Marshal.StructureToPtr(tag_list[i], ptr, false);
ptr += structSize;
// or on older versions of .net without arithmetic support on IntPtr
// ptr = (IntPtr) (long)ptr + structSize;
}
// call function passing r
Marshal.FreeHGlobal(r.tag_list);