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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15862983/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 18:12:11  来源:igfitidea点击:

Passing byte array between C++ and C# ByRef raises AccessViolationException

c#c++pinvokedllimport

提问by anonim

I am trying to create a Win32 DLL exposes some functions which are called in C# as follows

我正在尝试创建一个 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;
    }
}

And on C# side

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

When I run C# code, AccessViolationExceptionhappens on GetDatafunction which is a sign of exception in C++ code however, following C++ code snippet works fine without any error.

当我运行 C# 代码时,AccessViolationException发生在GetData函数上,这是 C++ 代码中的异常标志,但是,遵循 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;
}

If you compare C# mainfunction and C++ _tmain, they are almost analoguous so where I may make a mistake?

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

采纳答案by David Heffernan

You are returning an array allocated by a call to C++ new and hoping that the marshaler will turn it into a C# byte[]. That won't happen.

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

You'll need to pass a pointer by reference and then marshal it by hand. Your p/invoke should look like this:

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

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

When the function returns data will point to the array and you can read the contents using the Marshal class. I guess you would copy it to a new byte array.

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

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

Some other points:

其他几点:

  1. The calling conventions do not match. The native side is cdecl and the managed is stdcall.
  2. You'll need to export a deallocator to delete the memory returned by the native function. Consider a re-design where the caller allocates the buffer.
  1. 调用约定不匹配。本机端是 cdecl,托管端是 stdcall。
  2. 您需要导出一个解除分配器来删除本机函数返回的内存。考虑调用者分配缓冲区的重新设计。