简体   繁体   English

将整数数组从 C# 传递到具有互操作性的本机代码

[英]Passing an array of ints from C# to native code with interop

I have a Blah.cs:我有一个 Blah.cs:

public unsafe static int Main()
{
  int[] ai = {1, 2, 3, 4, 5};
  UIntPtr stai = (UIntPtr) ai.Length;
  CManagedStuff obj = new CManagedStuff();
  obj.DoSomething(ai, stai);
}

Then a ManagedStuff.cpp:然后是 ManagedStuff.cpp:

void CManagedStuff::DoSomething(int^ _ai, UIntPtr _stai)
{
  // Here I should do something to marshal the int^ to an int*
  pUnmanagedStuff->DoSomething(_ai, (size_t) _stai);
}

And an UnmanagedStuff.cpp:还有一个 UnmanagedStuff.cpp:

void CUnmanagedStuff::DoSomething(int* _ai, size_t _stai)
{
  // Walk and print the _stai ints in _ai
}

How can I pass int[] ai from Main to ManagedStuff::DoSomething?如何将int[] ai从 Main 传递到 ManagedStuff::DoSomething? I understand there is no marshaling in that call, because all the code involved is managed.我知道该调用中没有编组,因为涉及的所有代码都是托管的。

And how can I then marshal int^ _ai in ManagedStuff::DoSomething to call UnmanagedStuff::DoSomething?然后我怎样才能在 ManagedStuff::DoSomething 中编组int^ _ai来调用 UnmanagedStuff::DoSomething? If I had an int[] _ai the code in the answer for this SO question may help ( C#: Marshalling a "pointer to an int array" from a SendMessage() lParam ).如果我有一个int[] _ai ,那么这个 SO 问题的答案中的代码可能会有所帮助( C#: Marshalling a "pointer to an int array" from a SendMessage() lParam )。

Alternatively, how can I avoid working with C#, C++ interop, Microsoft and Windows, and stop world suffering?或者,我怎样才能避免使用 C#、C++ 互操作、Microsoft 和 Windows,并停止世界苦难?

I just need to point out how broken the original idea is.我只需要指出最初的想法是多么破碎。

In native code, you can pass an array by passing the address of the first element, because adjacent elements can be found through pointer arithmetic.在本机代码中,您可以通过传递第一个元素的地址来传递数组,因为可以通过指针运算找到相邻元素。

In managed code, the elements are also stored adjacently, but passing a int^ boxes the element, making a copy outside the array.在托管代码中,元素也是相邻存储的,但传递一个int^将元素装箱,在数组外部制作副本。 This copy will not have any other array elements stored nearby.此副本不会在附近存储任何其他数组元素。

In fact, this also happens in native cross-process communications.事实上,这也发生在原生跨进程通信中。 The trick of using pointer arithmetic to find other elements only works in-process, and is not generally applicable.使用指针算法查找其他元素的技巧仅在进程中起作用,并且通常不适用。

You have to pin the managed resource (your array), so the garbage collector doesn't move it while you're using the pointer.您必须固定托管资源(您的数组),因此垃圾收集器在您使用指针时不会移动它。

In C#, you can do this with the fixed statement: fixed Statement (C# Reference)在 C# 中,您可以使用fixed语句执行此操作:固定语句(C# 参考)

Pinning in C++ works with pinning pointers, wich pin a managed object while they're in scope. C++ 中的固定与固定指针一起使用,当它们在 scope 中时,固定托管 object。 (A pointer to any element will pin the entire array): (指向任何元素的指针将固定整个数组):

// In CManagedStuff:
pin_ptr<int> _aiPinned = _ai

More info: C++/CLI in Action - Using interior and pinning pointers更多信息: C++/CLI in Action - 使用内部和固定指针

OK, I've got it working like this:好的,我让它像这样工作:

void CManagedStuff::DoSomething(array<int>^ _ai, UIntPtr _stai)
{
  // Here I should do something to marshal the int^ to an int*
  pin_ptr<int> _aiPinned = &_ai[0];
  pUnmanagedStuff->DoSomething(_aiPinned, (size_t) _stai);
}

First, passing an array<int>^ .首先,传递一个array<int>^
Secondly, as Tamschi was suggesting, using a pin pointer pointing to the address of the first element in the array.其次,正如 Tamschi 建议的那样,使用指向数组中第一个元素的地址的 pin 指针。

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

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