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

标签 c# c++ pinvoke dllimport

我正在尝试创建一个 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++ new 分配的数组,并希望编码(marshal)拆收器将其转换为 C# byte[]。那不会发生。

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

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

当函数返回时,数据将指向数组,您可以使用 Marshal 类读取内容。我猜你会 copy it to a new byte array .

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

其他几点:

  1. 调用约定不匹配。 native 端是cdecl,托管是stdcall。
  2. 您需要导出一个释放器来删除 native 函数返回的内存。考虑调用者分配缓冲区的重新设计。

关于c# - 在 C++ 和 C# ByRef 之间传递字节数组引发 AccessViolationException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15862983/

相关文章:

c++ - 将非托管 C++ 库与 .NET API 结合使用

c# - WPF DocumentViewer - 无需确认即可打印

c# - 检查bool变量是否在c#中初始化

C++ 同时赋值给变量

C++ FileRead 用法

C++ - QT - SIGNAL 和 SLOT 理解

c# - 无法将结构从 C++ 返回到 C#

c# - 为什么Cdecl调用在“标准” P/调用约定中经常不匹配?

c# - 如何调试 MSBuild 依赖问题?

c# - 林奇 : saving files to a database