Six_Rabbit 2024-08-05 10:54 采纳率: 0%
浏览 4
已结题

Intprt在跨语言调用出现问题

用C++写了个DLL给C#调用,传入的Intptr在DLL中是变更,但是在C#却是Intptr.zero
  • 写回答

4条回答 默认 最新

  • 叫兽-郭老师 新星创作者: Java技术领域 2024-08-05 10:55
    关注

    🕖上午好,题主!目前:🟢[在线]
    📢参考通义千问、由郭老师整理提供!
    📣今日诗号:疏影横斜水清浅,暗香浮动月黄昏。

    你遇到的问题很常见,C# 和 C++ 在处理数据类型和内存管理方面有所不同,导致在跨语言调用时出现数据传递错误。

    问题分析:

    • 值类型与引用类型: C# 中的结构体 (struct) 是值类型,而 C++ 中的结构体默认是值类型,但可以作为引用类型传递。当你将 Intprt 结构体从 C# 传递到 C++ DLL 时,实际上是进行了一次值拷贝。这意味着在 C++ DLL 中对 Intprt 的修改不会影响到 C# 中的原始变量。

    • 内存布局: C# 和 C++ 结构体的内存布局可能不同,特别是在涉及到内存对齐和数据打包时。

    解决方案:

    为了解决这个问题,你需要确保 C# 和 C++ 以相同的方式处理 Intprt 结构体。以下是两种常见的解决方案:

    方法一:使用 IntPtr 作为参数传递内存地址

    1. C++ 代码 (DLL):
    #include <iostream>
    #include <cstdint>
    
    #ifdef DLL_EXPORT
    #define MYAPI __declspec(dllexport)
    #else
    #define MYAPI __declspec(dllimport)
    #endif
    
    // 定义结构体
    struct Intprt 
    {
        int x;
        int y;
    };
    
    // 使用 extern "C" 避免函数名被 C++ 编译器改编
    extern "C" 
    {
        // 接收指向 Intprt 结构体的指针作为参数
        MYAPI void ModifyIntprt(Intprt* intprt) 
        {
            if (intprt != nullptr) 
            {
                intprt->x = 10;
                intprt->y = 20;
            }
        }
    }
    
    1. C# 代码:
    using System;
    using System.Runtime.InteropServices;
    
    // 定义结构体,与 C++ 结构体保持一致
    [StructLayout(LayoutKind.Sequential)] 
    public struct Intprt 
    {
        public int x;
        public int y;
    }
    
    class Program
    {
        // 导入 DLL 函数
        [DllImport("YourDllName.dll")]
        static extern void ModifyIntprt(IntPtr intprt);
    
        static void Main(string[] args)
        {
            // 创建 Intprt 结构体
            Intprt myIntprt = new Intprt();
    
            // 获取结构体的指针
            IntPtr intprtPtr = Marshal.AllocHGlobal(Marshal.SizeOf(myIntprt));
            Marshal.StructureToPtr(myIntprt, intprtPtr, false);
    
            // 调用 DLL 函数
            ModifyIntprt(intprtPtr);
    
            // 将修改后的数据从指针复制回结构体
            myIntprt = (Intprt)Marshal.PtrToStructure(intprtPtr, typeof(Intprt));
    
            // 释放内存
            Marshal.FreeHGlobal(intprtPtr);
    
            Console.WriteLine($"Intprt.x: {myIntprt.x}, Intprt.y: {myIntprt.y}"); 
        }
    }
    

    方法二:使用类传递引用类型

    1. C++ 代码 (DLL):
    #include <iostream>
    #include <cstdint>
    
    #ifdef DLL_EXPORT
    #define MYAPI __declspec(dllexport)
    #else
    #define MYAPI __declspec(dllimport)
    #endif
    
    // 定义结构体
    class Intprt 
    {
    public:
        int x;
        int y;
    
        Intprt() : x(0), y(0) {}
    };
    
    // 使用 extern "C" 避免函数名被 C++ 编译器改编
    extern "C" 
    {
        // 传递 Intprt 对象的引用
        MYAPI void ModifyIntprt(Intprt& intprt) 
        {
            intprt.x = 10;
            intprt.y = 20;
        }
    }
    
    1. C# 代码:
    using System;
    using System.Runtime.InteropServices;
    
    // 定义类,与 C++ 结构体保持一致
    [StructLayout(LayoutKind.Sequential)]
    public class Intprt
    {
        public int x;
        public int y;
    
        public Intprt() 
        {
            x = 0;
            y = 0;
        }
    }
    
    class Program
    {
        // 导入 DLL 函数
        [DllImport("YourDllName.dll")]
        static extern void ModifyIntprt(Intprt intprt);
    
        static void Main(string[] args)
        {
            // 创建 Intprt 对象
            Intprt myIntprt = new Intprt();
    
            // 调用 DLL 函数
            ModifyIntprt(myIntprt);
    
            Console.WriteLine($"Intprt.x: {myIntprt.x}, Intprt.y: {myIntprt.y}"); 
        }
    }
    

    重要说明:

    • YourDllName.dll 替换为你的 DLL 文件名。
    • 确保 C# 项目和 C++ 项目的目标平台一致 (x86 或 x64)。

    希望以上解决方案能够帮助你解决 C# 调用 C++ DLL 时 Intprt 结构体数据传递问题!

    评论

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 8月5日
  • 修改了问题 8月5日
  • 创建了问题 8月5日