使用互操作将一个整数数组从C#传递到本地代码

3

我有一个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);
}

接下来是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);
}

还有一个UnmanagedStuff.cpp文件:

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

我该如何将Main中的int[] ai传递到ManagedStuff::DoSomething?由于所有涉及的代码都是托管的,因此在这个调用中没有任何编组。
然后,我该如何编组int^ _ai以调用UnmanagedStuff::DoSomething中的内容?如果我有一个int[] _ai,那么回答这个SO问题的代码可以帮助我(C#: Marshalling a "pointer to an int array" from a SendMessage() lParam)。
或者,我如何避免使用C#、C++互操作、Microsoft和Windows,并停止世界痛苦?

你正在使用的是C++/CLI,而非纯粹的C++,对吗? - Cody Gray
非常抱歉,我对C#这个世界还很陌生,仍然没有正确理解许多术语和概念。我认为Blah.cs是用不安全代码(基本上是指针和地址)编写的C#代码,CManagedStuff使用C++/CLI(指向托管内存的指针,类型^样式以及指向非托管内存的指针,类型*样式),而CUnmanagedStuff则完全是用C++编写的。 - rturrado
由于您是C++转来的C#新手,您可能应该阅读IDisposable: What Your Mother Never Told You About Resource Deallocation。实际上,当您在更大的上下文中使用它时,似乎您确实需要IDisposable模式来处理此程序。 - Tamschi
3个回答

2
我只想指出原始想法有多么糟糕。
在本地代码中,您可以通过传递第一个元素的地址来传递数组,因为可以通过指针算术找到相邻的元素。
在托管代码中,元素也存储在相邻位置,但传递 int^ 会对元素进行装箱,从而使得在数组外部产生拷贝。这个拷贝将不会有其他相邻的数组元素。
实际上,在本地跨进程通信中也会发生这种情况。使用指针算术查找其他元素的技巧仅适用于进程内,并不普遍适用。

1

您必须固定托管资源(即您的数组),以便在使用指针时垃圾回收器不会将其移动。

在C#中,您可以使用fixed语句来实现:fixed Statement (C# Reference)

C++中的固定工作原理是使用固定指针,它们在范围内固定托管对象。(对任何元素的指针都会固定整个数组):

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

更多信息:C++/CLI实战-使用内部指针和固定指针


固定内存地址是需要考虑的问题。但首先,我必须能够从C#代码传递一个整数数组到C++/CLI(从Blah.cs到ManagedStuff)。 - rturrado

1

好的,我已经让它像这样工作了:

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);
}

首先,传递一个 array<int>^
其次,如Tamschi所建议的那样,使用指向数组第一个元素地址的固定指针。


3
"_stai"参数完全没有必要,只需使用"_ai->Length"即可。 - ildjarn
@ildjarn 没错。我之前使用 _stai 是因为我收到了一个 int^ - rturrado

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