繁体   English   中英

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

[英]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.

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