简体   繁体   English

将对象/结构的数组/列表从C#库传递到C ++ MFC应用程序

[英]Passing array/list of object/struct from C# Library to C++ MFC application

I'm trying to pass an array of object or struct from a C# library (.net 4.5) called by a C++ MFC application but I can't get correct data. 我正在尝试从C ++ MFC应用程序调用的C#库(.net 4.5)中传递对象或结构的数组,但无法获取正确的数据。 An additional difficulty is that C++ application don't know the object count. 另一个困难是C ++应用程序不知道对象数。

I have successfully passed simple type (int, string) and also a struct with the following code (using UnmanagedExports 1.2.7): 我已经成功传递了简单类型(int,字符串)以及带有以下代码的结构(使用UnmanagedExports 1.2.7):

C# 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++ 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);    
}

I have searched everywhere but I don't find any functionnal response to my specific problem. 我到处搜索过,但找不到针对我的特定问题的功能说明。 Can you help to write both C# and C++ codes for GetItemAList which can return an array of struct or another type to C++ application? 您是否可以帮助为GetItemAList编写C#和C ++代码,它们可以将结构数组或其他类型返回给C ++应用程序?

Thanks in advance! 提前致谢!

Edit1 : I changed my code to solve packing/size struct issue (64 bits compilation). Edit1:我更改了代码以解决打包/大小结构问题(64位编译)。

Edit2 : I replace manual alignment by #pragma pack. Edit2:我用#pragma pack代替了手动对齐。

Edit3 : I'm always stuck with GetItemAList. Edit3:我总是卡在GetItemAList上。 Here is my actual c#/c++ codes with an MemoryException after calling c#. 这是我在调用c#之后使用MemoryException的实际c#/ c ++代码。 Can you help me with this sh**? 你能帮我这个忙吗? Thanks in advance. 提前致谢。

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++ C ++

extern "C"
{
    void GetItemAList(ItemA*& myArray, int& length);
}

// (...)

void CMyAppDlg::OnBnClickedButtonGetItemA()
{
    ItemA* myArray = new ItemA[100];
    int length = 100;
    GetItemAList(myArray, length);   
}

I have not done any checking, but your C++ version is probably compiled with 4 bytes packing (assuming your are compiling in 32 bits). 我没有做任何检查,但是您的C ++版本可能是用4个字节的包装进行编译的(假设您使用32位编译)。

In that case, you would have on C++ side: 在这种情况下,您可能会在C ++方面:

// Field,   Field size, Total size
// -------------------------------
// Id,               0,          4
// Name,            50,         54
// IsEnabled,        1,         55
// (padding)         1,         56

On that side, you should add a static_assert validating that you got the expected size. 在那一边,您应该添加一个static_assert验证您是否具有预期的大小。

static_check(sizeof ItemA == 56, "Size does not match C# struct size")

On the hand on C# side, you would have: 在C#方面,您将拥有:

// Field,   Field size, Total size
// -------------------------------
// Id,               0,          4
// Name,            50,         54
// IsEnabled,        4,         58
// (no padding)      0,         58

And if bool was 1 byte, you would have a size of 55 instead. 如果bool为1字节,则大小为55。 In both case, it would not match the size on C++ side. 在这两种情况下,它都不会与C ++端的大小匹配。

As it is somewhat hard to know all rules and not make any mistake and also to ensure nothing is broken in future maintenance, you should always add validation in your code. 由于很难了解所有规则且不会犯任何错误,并且还要确保以后的维护中没有任何问题,因此应始终在代码中添加验证。

On C# side, typical validation would be something like: Debug.Assert(Marshal.Sizeof(typeof(ItemA)) == 58 . 在C#方面,典型的验证将类似于: Debug.Assert(Marshal.Sizeof(typeof(ItemA)) == 58

You could also validate the offset or size of some fields but generally if the size you compute by hand do match on both sides, you probably got it right particularily if you use 1 byte packing. 您也可以验证某些字段的偏移量或大小,但是通常情况下,如果手动计算的大小在两侧都匹配,则如果使用1字节打包,则可能特别正确。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM