C# 当返回结构时,PInvoke仅在64位中工作 我有以下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# 当返回结构时,PInvoke仅在64位中工作 我有以下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#,c++,interop,pinvoke,C#,C++,Interop,Pinvoke,我用C#调用它,使用: 以x86运行时,在将dll构建为x86之后,我收到一个错误试图读取或写入受保护内存。。在x64中,它可以正常工作 当我使用托管/本机调试器时,我看到它在返回rgb时崩溃 将返回类型更改为long(C#中的int)时,即使是x86也可以正常工作 RGB结构为什么会出现这个问题?不要将结构用于“复杂”的返回类型,最好是这样: C++: C#: 请注意,在您的特定情况下,它会失败,因为结构大小为3,因此,如果您像这样更改结构,则可以使其工作,例如: C++: C# 使用这个定义

我用C#调用它,使用:

以x86运行时,在将dll构建为x86之后,我收到一个错误
试图读取或写入受保护内存。
。在x64中,它可以正常工作

当我使用托管/本机调试器时,我看到它在
返回rgb时崩溃

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

RGB结构为什么会出现这个问题?

不要将结构用于“复杂”的返回类型,最好是这样:

C++:

C#:

请注意,在您的特定情况下,它会失败,因为结构大小为3,因此,如果您像这样更改结构,则可以使其工作,例如:

C++:

C#


使用这个定义,大小将为4,因此C++编译器将生成一个返回返回一个It32值而不是返回的代码——可能是指某个内部内存,在执行时将消失到.NET端。这是纯粹的运气(或者黑客),我想依赖C++编译器。

你应该添加参数。代码>[StructLayout(LayoutKind.Sequential,Pack=1)]
到StructLayout,因为您的结构有3个字节长。对于C++,你应该检查<代码> JeroenvanLangen编译1(PASS,/Cux> @),这不会有任何区别,因为Stutt包含3个字节,所有可能的对齐方式都是相同的。事实上它是错误的,因为C++结构没有打包。@ DavidHeffernan,我不相信这是一个复制品,因为另一个问题是返回一个指针,这显然不起作用。我正在返回结构本身,这个问题中没有任何东西可以解释为什么它不起作用。我阅读了问题中的C#代码,该代码假定结构是通过值返回的。无论如何,你现在知道了解决方案。如果你想理解它,你需要了解二进制接口的两面是如何工作的。这可以通过在CPU/asm级别调试函数调用来实现。可以返回仅包含可blittable类型的
格式化值类型。除非大小为3,否则不会显示
。这有什么关系?@wezten-这不是一个可飞艇与不可飞艇的问题。这是一个“函数的返回值从非托管变为托管”问题。正如我所说的,如果通过引用传递结构,它就可以正常工作。微软的所有例子都遵循这种模式。在那篇文章中,它说从平台调用返回的
结构必须是可blittable类型。平台调用不支持将不可blittable结构作为返回类型。
。然后它继续解释,包含可blittable类型的复杂类型本身是可blittable的,这意味着它们可以返回。@wezten-他们在这里谈论的“返回类型”不能与函数在二进制级别返回的内容混淆。他们在谈论裁判和出局类型。同样,C stdcall或cdecl函数在32位进程中返回的值是32位值,存储在EAX句点中(因此,当传递结构时,编译器之外的结果是未定义的)。在使用同一个C编译器编译的两个函数之间返回一个结构是很好的,因为它知道自己的内部结构,但仅此而已。谢谢,这真的让事情变得明朗了。但是将
LayoutKind.Sequential
struct作为参数(按值)传递是否安全?
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; }
extern "C" __declspec(dllexport) void __stdcall TestMethod2(RGB *prgb) {
    prgb->R = 1;
    prgb->G = 2;
    prgb->B = 3;
}
[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);
}
typedef struct _RGB {
    unsigned char R, G, B, A;
} RGB;
[StructLayout(LayoutKind.Sequential)]
struct RGB { public byte R, G, B, A; }