[英]Passing array/list of object/struct from C# Library to C++ MFC application
我正在尝试从C ++ MFC应用程序调用的C#库(.net 4.5)中传递对象或结构的数组,但无法获取正确的数据。 另一个困难是C ++应用程序不知道对象数。
我已经成功传递了简单类型(int,字符串)以及带有以下代码的结构(使用UnmanagedExports 1.2.7):
C#
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 4)]
public struct ItemA
{
// Size: 4
public int Id;
// Size: 100
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)]
public string Name;
// Size: 2(4)
public bool IsEnabled;
}
[DllExport(CallingConvention = CallingConvention.Cdecl)]
static public IntPtr GetItemA(int itemId)
{
// Check structure size
Debug.Assert(Marshal.SizeOf(typeof(ItemA)) == 108);
// Get ItemA from a WS
var itemA = client.GetItemsA().First(i => i.Id == itemId);
// Convert ItemA to structure pointer
IntPtr buf = Marshal.AllocHGlobal(Marshal.SizeOf(itemA));
Marshal.StructureToPtr(itemA, buf, false);
return buf;
}
C ++
#pragma pack(4)
typedef struct
{
// Size: 4
int Id;
// Size: 100
TCHAR Name[50];
// Size: 2(4)
bool IsEnabled;
} ItemA;
extern "C"
{
ItemA* GetItemA(int itemId);
}
// (...)
void CMyAppDlg::OnBnClickedButtonGetItemA()
{
// Check structure size
static_assert(sizeof ItemA == 108, "Size does not match C# struct size");
ItemA* structItemA = GetItemA(1);
}
我到处搜索过,但找不到针对我的特定问题的功能说明。 您是否可以帮助为GetItemAList编写C#和C ++代码,它们可以将结构数组或其他类型返回给C ++应用程序?
提前致谢!
Edit1:我更改了代码以解决打包/大小结构问题(64位编译)。
Edit2:我用#pragma pack代替了手动对齐。
Edit3:我总是卡在GetItemAList上。 这是我在调用c#之后使用MemoryException的实际c#/ c ++代码。 你能帮我这个忙吗? 提前致谢。
C#
[DllExport(CallingConvention = CallingConvention.Cdecl)]
static public void GetItemAList([In, Out, MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.Struct, SizeParamIndex = 1)] ref ItemA[] myArray, ref int length)
{
// Get ItemAList from a WS
var itemAArray = client.GetItemsAList().ToArray();
// Set myArray values
length = itemAArray.Length;
for (int i = 0; i < length; i++)
{
myArray[i] = itemAArray[i];
}
}
C ++
extern "C"
{
void GetItemAList(ItemA*& myArray, int& length);
}
// (...)
void CMyAppDlg::OnBnClickedButtonGetItemA()
{
ItemA* myArray = new ItemA[100];
int length = 100;
GetItemAList(myArray, length);
}
我没有做任何检查,但是您的C ++版本可能是用4个字节的包装进行编译的(假设您使用32位编译)。
在这种情况下,您可能会在C ++方面:
// Field, Field size, Total size
// -------------------------------
// Id, 0, 4
// Name, 50, 54
// IsEnabled, 1, 55
// (padding) 1, 56
在那一边,您应该添加一个static_assert
验证您是否具有预期的大小。
static_check(sizeof ItemA == 56, "Size does not match C# struct size")
在C#方面,您将拥有:
// Field, Field size, Total size
// -------------------------------
// Id, 0, 4
// Name, 50, 54
// IsEnabled, 4, 58
// (no padding) 0, 58
如果bool
为1字节,则大小为55。 在这两种情况下,它都不会与C ++端的大小匹配。
由于很难了解所有规则且不会犯任何错误,并且还要确保以后的维护中没有任何问题,因此应始终在代码中添加验证。
在C#方面,典型的验证将类似于: Debug.Assert(Marshal.Sizeof(typeof(ItemA)) == 58
。
您也可以验证某些字段的偏移量或大小,但是通常情况下,如果手动计算的大小在两侧都匹配,则如果使用1字节打包,则可能特别正确。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.