从非托管代码传递数据到托管代码

4

我有一个三层应用程序:

  1. 一个托管的C#层。
  2. 一个托管的C++/CLI层。
  3. 一个非托管的C++层。

第二层作为C#和本地C++之间的通信层使用。

public class ManagedResult
{
  public float[] firstArray;
  public float[] secondArray;
}

和未管理的类

 class UnmanagedResult
    {
      public:
         float* firstArray, secondArray;
         int arrayLength;
         UnmanagedResult(){};
         ~UnmanagedResult(){};
    }

我在第二层中有以下一个类的方法,其输出一个托管对象:

 ManagedResult^ CLIContext::GetResults(){

   ManagedResult^ primitiveResult = gcnew ManagedResult();

   pin_ptr<int> pFirst = &(primitiveResult->firstArray[0]);
   pin_ptr<float> pSecond = &(primitiveResult->secondArray[0]);
   UnmanagedResult result =UnmanagedResult();
   result.firstArray = pFirst;
   result.secondArray = pSecond;

   _context->GetResults(result);

   return primitiveResult;

 }

在这里,_context是一个未受管理的类类型对象,它操作一个UnmanagedResult类型的对象并影响其内容。

这个解决方案很好用。但我希望能够通过引用传递对象,并且使用第三方API来分配和填充firstArraysecondArray的两个成员。

那么,如何将数据从未受管理的结果转移到primitiveResult中呢?


1
对于从非托管到托管,您需要一个单独的变量来保存项目计数 - 您能提供吗?此外,您将不得不复制数组内容,因为不幸的是,您不能将托管数组放在现有数据之上。这对您来说可以吗? - Lucas Trzesniewski
是的,我可以提供项目数。我感兴趣的是如何以最快的方式将数组内容从一个层复制到另一个层。 - MariaMadalina
如果您想要尽可能快地完成,那么就不要复制。您可能希望从包装第三方API的任何ref类包装器中返回IntPtr,并在此类中再次转换为(float*)。 - Hans Passant
1个回答

1
作为未经管理的数组只是指向其第一个项的指针,您需要知道项计数。
如果您想要一个托管数组,则必须创建一个并将数据复制到那里。您将无法创建指向现有未经管理的内存的托管数组。
使用 System::Runtime::InteropServices::Marshal::Copy 进行此操作:
UnmanagedResult unmanagedResult = GetTheUnmanagedResultSomehow();
ManagedResult^ managedResult = gcnew ManagedResult();

managedResult->firstArray = gcnew array<float>(unmanagedResult.arrayLength);
Marshal::Copy(IntPtr(unmanagedResult.firstArray), managedResult->firstArray, 0, managedResult->firstArray->Length); 

// Do the same for secondArray

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接