传递一个向量/阵列从非托管C ++到C#
问题描述:
我想通过大约100 - 从非托管C ++到C#10000点
I want to pass around 100 - 10,000 Points from an unmanaged C++ to C#.
C ++的侧面看起来是这样的:
The C++ side looks like this:
__declspec(dllexport) void detect_targets( char * , int , /* More arguments */ )
{
std::vector<double> id_x_y_z;
// Now what's the best way to pass this vector to C#
}
现在我的C#侧面看起来是这样的:
Now my C# side looks like this:
using System;
using System.Runtime.InteropServices;
class HelloCpp
{
[DllImport("detector.dll")]
public static unsafe extern void detect_targets( string fn , /* More arguments */ );
static void Main()
{
detect_targets("test.png" , /* More arguments */ );
}
}
如何,我需要改变我的code,以通过从非托管C ++中的std ::向量与所有它的内容到C#?
How do I need to alter my code in order to pass the std::vector from unmanaged C++ with all it's content to C#?
答
只要管理code不调整向量,就可以访问该缓冲区,并将它传递与指针vector.data()
(对于C ++ 0x中)或和矢量[0]
。这导致零复制系统
As long as the managed code does not resize the vector, you can access the buffer and pass it as a pointer with vector.data()
(for C++0x) or &vector[0]
. This results in a zero-copy system.
例C ++ API:
#define EXPORT extern "C" __declspec(dllexport)
typedef intptr_t ItemListHandle;
EXPORT bool GenerateItems(ItemListHandle* hItems, double** itemsFound, int* itemCount)
{
auto items = new std::vector<double>();
for (int i = 0; i < 500; i++)
{
items->push_back((double)i);
}
*hItems = reinterpret_cast<ItemListHandle>(items);
*itemsFound = items->data();
*itemCount = items->size();
return true;
}
EXPORT bool ReleaseItems(ItemListHandle hItems)
{
auto items = reinterpret_cast<std::vector<double>*>(hItems);
delete items;
return true;
}
来电:
static unsafe void Main()
{
double* items;
int itemsCount;
using (GenerateItemsWrapper(out items, out itemsCount))
{
double sum = 0;
for (int i = 0; i < itemsCount; i++)
{
sum += items[i];
}
Console.WriteLine("Average is: {0}", sum / itemsCount);
}
Console.ReadLine();
}
#region wrapper
[DllImport("Win32Project1", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
static unsafe extern bool GenerateItems(out ItemsSafeHandle itemsHandle,
out double* items, out int itemCount);
[DllImport("Win32Project1", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
static unsafe extern bool ReleaseItems(IntPtr itemsHandle);
static unsafe ItemsSafeHandle GenerateItemsWrapper(out double* items, out int itemsCount)
{
ItemsSafeHandle itemsHandle;
if (!GenerateItems(out itemsHandle, out items, out itemsCount))
{
throw new InvalidOperationException();
}
return itemsHandle;
}
class ItemsSafeHandle : SafeHandleZeroOrMinusOneIsInvalid
{
public ItemsSafeHandle()
: base(true)
{
}
protected override bool ReleaseHandle()
{
return ReleaseItems(handle);
}
}
#endregion