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

本文关键字:ByRef 数组 AccessViolationException 字节数 字节 c++ 之间 | 更新日期: 2023-09-27 18:07:48

我正在尝试创建一个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++代码中异常的标志,然而,下面的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++和c#之间传递字节数组ByRef会引发AccessViolationException

您正在返回一个通过调用c++ new分配的数组,并希望封送处理程序将其转换为c#字节[]。这不会发生。

你需要通过引用传递一个指针,然后手工封送它。您的p/调用应该像这样:

[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来删除native函数返回的内存。考虑在调用者分配缓冲区的地方重新设计。