使用P / Invoke时存储非托管代码的数据

时间:2017-03-21 08:10:34

标签: c# c++ unity3d pinvoke marshalling

我有一个这个结构的数组数组(在C#中显示,但也存在于C ++中):

[StructLayout(LayoutKind.Sequential)]
public struct MyStruct
{
    IntPtr name;             //pointer to string, char* on C++ side

    long pValues;
    long jValues;
    long eValues;
    long kValues;

    int cost;
};

和C ++ DLL中的一个算法,它可以在托管C#代码中调用它。它的CPU很重,这就是必需的,因为它在C ++中的运行速度比C#快得多。托管(C#)方面永远不必知道结构数据的内容,因为算法只返回单个int数组。

那么,在应用程序的生命周期内,我将如何以最有效的方式(即开销最小)存储这些数据?我想我已经把它缩小到两个选项:

  1. 初始化C#中的结构和设置值,使用GCHandle设置内存,并在我想要工作时将引用传递给C ++(参见Unity论坛上的this post

  2. 在C ++中初始化结构和设置值,结构在非托管端的内存中保留

  3. 所以我的问题非常具体:

    1,我对编组的工作方式感到困惑。在MSDN: Copying and Pinning中,您可以通过固定并传递对固定数据的引用来传递结构数组,而无需复制或转换任何(并且只要结构在两边看起来都一样)。我是否正确阅读,它是如何实际工作的?参考Unity3d论坛帖子,我看到Marshal.PtrToStructure正在被调用;我以为会执行复制操作?由于数据将在此实例中存储在托管端,因此每次调用C ++函数时都必须复制和/或转换数据会导致大量开销,除非我认为这些类型的操作是比他们实际上要贵很多。

    有了2,我想知道是否可以在C ++调用之间保持持久性。据我所知,如果你从DLL调用P / Invoke,你就不能在非托管端拥有持久数据,所以我不能在那里定义和存储我的struct数组,使得在托管和非托管之间传输的唯一数据是由非托管算法产生的int数组。这是对的吗?

    非常感谢你花时间阅读和帮助!

1 个答案:

答案 0 :(得分:3)

如果C#代码不需要知道数组的内部结构和结构,请不要将它暴露给C#代码。在非托管代码中完成此类型的所有工作,避免编组开销。

基本上,你想要遵循这个基本模式。我确定细节会有所不同,但这应该为您提供基本概念。

<强> C ++

MyStruct* newArray(const int len)
{
    return new MyStruct[len];
}

void workOnArray(MyStruct* array, const int len)
{
    // do stuff with the array
}

void deleteArray(const MyStruct* array)
{
    delete[] array;
}

C#

[DllImport(dllname)]
static extern IntPtr newArray(int len);

[DllImport(dllname)]
static extern void workOnArray(IntPtr array int len);

[DllImport(dllname)]
static extern void deleteArray(IntPtr array);