我试图从C ++ MFC应用程序调用的C#库(.net 4.5)传递一个对象或结构数组,但是我无法获得正确的数据。另一个困难是C ++应用程序不知道对象计数。
我已成功传递简单类型(int,string)以及带有以下代码的结构(使用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替换手动对齐。
编辑3:我一直坚持使用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);
}
答案 0 :(得分:0)
我还没有做任何检查,但是你的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个字节的打包,则可能特别正确。