c# - 将 C# 结构传递给 C++ 非托管 DLL 返回不正确的结果

标签 c# c++ pinvoke marshalling

我有一个在 visual studio 2017 中开发并在 64 位环境中编译的简单 C++ win32 DLL,代码如下:

typedef struct sum {
    struct  {
        int num1;
        int num2;
    } nums;
} sum1;

extern "C" {

__declspec(dllexport) int initialize(sum1 *summing)
{
    int res;
    res = summing->nums.num1 + summing->nums.num2;
    return res;
}

}

上面的代码包含一个方法,它通过将 typedef 结构作为参数返回两个整数的总和。

我有一个 C# 客户端应用程序,它使用 PInvoke 使用这个 Win32 C++ DLL。以下是我的 C# 客户端应用程序的代码:

[StructLayout(LayoutKind.Sequential)]
public struct nums
{
    public int a;
    public int b;
}

[StructLayout(LayoutKind.Sequential)]
public struct mydef
{
    public IntPtr sum;
}

public class LibWrap
{    
    [DllImport("C++.dll", EntryPoint = "initialize")]
    public static extern int Initialize(ref mydef mydef);
}

class Program
{
    static void Main(string[] args)
    {
        mydef mydef = new mydef();
        nums nums;
        nums.a = 6;
        nums.b = 6;

        IntPtr buffer1 = Marshal.AllocCoTaskMem(Marshal.SizeOf(nums));
        Marshal.StructureToPtr(nums, buffer1, false);
        mydef.sum = buffer1;

        int res = LibWrap.Initialize(ref mydef);

        Console.WriteLine(res);
    }
}

使用上面的代码,我期望“12”作为输出,但我得到的是“-1504178328”作为输出。

我是一名 C# 开发人员,完全没有 C++ 经验。请帮我解决这个问题。

最佳答案

使用更简单的 P/Invoke 包装器:

public static class LibWrap
{
    [DllImport("C++.dll", EntryPoint = "initialize")]
    public static extern int Initialize(ref Nums nums);

    [StructLayout(LayoutKind.Sequential)]
    public struct Nums
    {
        public int a;
        public int b;
    }
}

并像这样使用它:

void CSharpExample()
{
    LibWrap.Nums nums;
    nums.a = 6;
    nums.b = 7;
    int res = LibWrap.Initialize(ref nums);
    Console.WriteLine(res);
}

在您的示例中,您不需要任何内存分配和编码(marshal)处理,因为:

  • LibWrap.Nums 是一个结构体,因此 CSharpExample() 中的局部变量 nums 完全分配在堆栈上。
  • 通过 ref 将托管结构 LibWrap.Nums 传递给 LibWrap.Initialize 会将指针传递给局部变量 nums 在堆栈上。
  • LibWrap.Initialize 被同步调用,因此您传递给它的指针在 LibWrap.Initialize 函数退出后不会在任何地方使用。这很重要,因为一旦 CSharpExample() 退出,指针就会变得无效。

关于c# - 将 C# 结构传递给 C++ 非托管 DLL 返回不正确的结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47427908/

相关文章:

c# - 尽管数据库中有数据,MySQL 查询数据检索却给出所有内容为空

c# - 加载虚拟属性

c++ - 使用大括号初始化类实例

f# p/invoke on GetClientRect with pointers works 但不适用于 OutAttribute

c# - 对重新排列的问题进行排序的算法,知道新位置和旧位置

c# - IComparable 是在字典中强制使用唯一键的最佳方式吗?

用于条件变量类型和初始化的 C++1y 模板变量

c++ - sleep 功能不起作用

C# 将字符串编码结构发送至 C 库

c# - 使用 char** 参数的 PInvoke 中出现问题,字符串数组不起作用