首页 > 解决方案 > 从 PInvoke 返回一个结构

问题描述

我试图从 c# 对 c++ dll 的调用返回一个结构,但我得到了一些我不理解的复杂和不良行为。如果我的结构包含一个构造函数,我在返回它时会遇到内存访问冲突,如果它小于 12 个字节。如果大一点就没有问题。如果我删除构造函数,它适用于所有尺寸。我想这可能与我的 c 风格调用有关,但我找不到有关此的信息。因此,如果有人可以解释或指出我正在发生的事情的一个好的方向,将不胜感激。以下是有效和无效的代码示例:

有效的代码

C++ 端标题:

#define DLL_API __declspec(dllexport)

struct Struct4Byte
{
 int x1;
};

struct Struct12Byte
{
 int x1;
 int x2;
 int x3;
 Struct12Byte() { x1 = 0; x2 = 1; x3 = 2; }
};

#ifdef __cplusplus
extern "C" {
#endif
 DLL_API Struct4Byte Function4Byte(int x);
 DLL_API Struct12Byte Function12Byte(int x);
#ifdef __cplusplus
}
#endif

C++ 文件:

Struct4Byte Function4Byte(int x)
{
 Struct4Byte output;
 output.x1 = 1 + x;
 return output;
}

Struct12Byte Function12Byte(int x)
{
 Struct12Byte output;
 output.x1 = 1 + x;
 output.x2 = 2 + x;
 output.x3 = 3 + x;
 return output;
}

在调用方(C#)我做:

[StructLayout(LayoutKind.Sequential)]
internal struct Struct4Byte
{
 public int x1;
}

[StructLayout(LayoutKind.Sequential)]
internal struct Struct12Byte
{
 public int x1;
 public int x2;
 public int x3;
}

class Program
{
    static void Main(string[] args)
    {
            Struct4Byte result1 = Function4Byte(3);
            Struct12Byte result2 = Function12Byte(3);
    }

    [DllImport(@"PInvokeCheck.dll")]
    internal static extern Struct4Byte Function4Byte(int x);

    [DllImport(@"PInvokeCheck.dll")]
    internal static extern Struct12Byte Function12Byte(int x);
}

不起作用的代码

如果我现在在头文件中将 Struct4Byte 的定义更改为:

struct Struct4Byte
{
 int x1;
 Struct4Byte(){ x1 = 0; }
};

然后我得到内存访问冲突。

我注意到了一些可能感兴趣的东西。问题已经在调用 Function4Byte 时出现了。在函数中放置一个断点并查看 x(我在下面再次放置了该函数)表明 x 得到了一些随机值。

Struct4Byte Function4Byte(int x)
{
 Struct4Byte output;
 output.x1 = 1 + x;
 return output;
} 

标签: c#c++pinvoke

解决方案


我可能发现了这个问题。他们是我错过的警告:警告C4190:'Function4Byte'已指定C-linkage,但返回与C不兼容的UDT'Struct4Byte'。从这个讨论中可以清楚地看出它可能导致一些未定义的行为并且结构的布局可能会改变:C++ 代码链接错误:警告 C4190:类型已指定 C 链接,但返回与 C 不兼容的 UDT

所以这似乎解释了我遇到的问题。


推荐阅读