在C ++和C#ByRef之间传递字节数组会引发AccessViolationException

我试图创建一个Win32 DLL公开一些在C#中调用的函数,如下所示

__declspec(dllexport) int GetData(unsigned char* *data, int* size) { try { int tlen = 3; unsigned char* tchr = new unsigned char[5]; tchr[0] = 'a'; tchr[1] = 'b'; tchr[2] = 'c'; *size = tlen; *data = tchr; return 1; } catch (char *p) { return 0; } } 

在C#方面

 [DllImport("MyDll.dll")] static extern int GetData(ref byte[] data, ref int size); static void Main() { try { int hr = 0; byte[] gData = null; int gSize = 0; hr = GetData(ref gData, ref gSize); Console.WriteLine(gSize); for (int i = 0; i < gSize; i++) Console.WriteLine((char)gData[i]); } catch (Exception p) { Console.WriteLine(p.ToString()); } } 

当我运行C#代码时, AccessViolationException发生在GetData函数上,这是C ++代码中exception的标志,但是,遵循C ++代码片段工作正常,没有任何错误。

 int _tmain(int argc, _TCHAR* argv[]) { unsigned char* data = NULL; int size = NULL; GetData(&data, &size); printf("%d", size); for (int i = 0; i < size; i++) printf("%c,", data[i]); return 0; } 

如果你比较C# main函数和C ++ _tmain ,它们几乎是类似的,所以我可能会犯错误?

您正在返回通过调用C ++ new分配的数组,并希望封送器将其转换为C#byte []。 这不会发生。

您需要通过引用传递指针,然后手动编组。 你的p / invoke应如下所示:

 [DllImport("MyDll.dll")] static extern int GetData(out IntPtr data, out int size); 

当函数返回数据时,将指向数组,您可以使用Marshal类读取内容。 我想你会把它复制到一个新的字节数组 。

 var arr = new byte[size]; Marshal.Copy(data, arr, 0, size); 

其他一些观点:

  1. 调用约定不匹配。 本机端是cdecl,托管是stdcall。
  2. 您需要导出deallocator以删除本机函数返回的内存。 考虑重新设计调用者分配缓冲区。