返回结构体时,PInvoke仅在64位下工作

时间:2019-06-24 07:09:14

标签: c# c++ interop pinvoke

我有以下C ++代码,可编译为dll:

typedef struct _RGB {
    unsigned char R, G, B;
} RGB;

extern "C" __declspec(dllexport) RGB __stdcall TestMethod1() {
    RGB rgb{1,2,3};
    return rgb;
}

并使用以下代码在C#中调用它:

static void Main(string[] args)
{
    var res = TestMethod1();
}

[DllImport(@"D:\Develop\res\VSProjects\ConsoleApp1\Debug\Dll1.dll", CallingConvention = CallingConvention.StdCall)]
static extern RGB TestMethod1();

[StructLayout(LayoutKind.Sequential)]
struct RGB { public byte R, G, B; }

当将其作为x86运行时,将dll构建为x86后,出现错误Attempted to read or write protected memory.。在x64中可以正常工作。

使用托管/本机调试器时,我看到它在return rgb;上崩溃了。

将返回类型更改为long(在C#中为int)时,即使在x86上也可以正常工作。

RGB结构is blittable为何会出现此问题?

1 个答案:

答案 0 :(得分:1)

不要将struct用于“复杂”返回类型,而是喜欢这样的东西:

C ++:

extern "C" __declspec(dllexport) void __stdcall TestMethod2(RGB *prgb) {
    prgb->R = 1;
    prgb->G = 2;
    prgb->B = 3;
}

C#:

[DllImport(@"D:\smo\source\repos\ConsoleApplication4\Debug\Dll1.dll")]
static extern void TestMethod2(ref RGB rgb);

static void Main(string[] args)
{
    var rgb = new RGB();
    TestMethod2(ref rgb);
}

请注意,在您的特殊情况下,它会失败,因为结构大小为3,因此,例如,当您更改结构时,可以使它起作用:

C ++:

typedef struct _RGB {
    unsigned char R, G, B, A;
} RGB;

C#

[StructLayout(LayoutKind.Sequential)]
struct RGB { public byte R, G, B, A; }

使用此定义,大小将为4,因此C ++编译器将生成一个代码,该代码将返回int32值,而不是返回-可能-对某些内部存储器的引用,该引用将在执行到达时消失。 NET端。这纯粹是运气(或破解),取决于我猜想的C ++编译器。