博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
DLL 函数中使用结构体指针作函数参数(C# 调用 C++ 的 DLL)
阅读量:4605 次
发布时间:2019-06-09

本文共 2448 字,大约阅读时间需要 8 分钟。

存在的问题:

问题1:C++ 与 C# 同样定义的结构体在内存布局上有时并不一致;

问题2:C# 中引入了垃圾自动回收机制,其垃圾回收器可能会重新定位指针所指向的结构体变量。

解决方案:

问题1方案:强制指定 C++、C# 结构体的内存布局,使其一致(两者都固定为:结构体的成员按其声明时出现的顺序依次布局,结构体成员的内存对齐为1字节对齐);

为题2方案:C# 调用时将待传递的结构体转化为字节数组,并使用 fixed 语句将该字节数组固定住。

 

示例代码如下:

1、C++结构体定义:

  #pragma pack(1)

  struct Person
  {
      #define Count_FavoriteNumbers 6
  
      int id;
  
      float favoriteNumbers[Count_FavoriteNumbers];
  
  };
  #pragma pack()        // #pragma pack(1) end

 

  C++ 导出函数:

  #define DllExport extern "C" __declspec(dllexport)

  DllExport void __stdcall InitPersonInfo_DLL(Person* p_Person)

  {
      p_Person->id = 0;
  
      for (int i = 1; i <= Count_FavoriteNumbers; i++)
      {
          p_Person->favoriteNumbers[i - 1] = 1.11 * i;
      }    
  }

 

2、C# 结构体定义:

  [StructLayout(LayoutKind.Sequential, Pack = 1)]

      public class Person
      {
          public const int Count_FavoriteNumbers = 6;
          public int id;
          [MarshalAs(UnmanagedType.ByValArray, SizeConst = Count_FavoriteNumbers, ArraySubType = UnmanagedType.U4)]
          public float[] favoriteNumbers = new float[Count_FavoriteNumbers];  
      }

 

  C# 调用(WPF窗体程序):

  public partial class MainWindow : Window

  {

    [DllImport("MFCLibrary_ExportFunction.dll", EntryPoint = "InitPersonInfo_DLL")]

          static extern unsafe void InitPersonInfo_DLL(byte* p_Person);
          public unsafe void InitPersonInfo(ref Person person)
          {
              byte[] structBytes = StructToBytes(person);
              fixed (byte* p_Person = &structBytes[0])
              {
                  InitPersonInfo_DLL(p_Person);
                  person = (Person)BytesToStruct(structBytes, person.GetType());
              }

 

    public MainWindow()

          {
      InitializeComponent();

      Person zhangSan = new Person();

      InitPersonInfo(ref zhangSan);
          }

 

    #region // 结构体与 byte[] 互转

    // Struct 转换为 byte[]

          public static byte[] StructToBytes(object structure)
          {
              int size = Marshal.SizeOf(structure);
              IntPtr buffer = Marshal.AllocHGlobal(size);
              try
              {
                  Marshal.StructureToPtr(structure, buffer, false);
                  byte[] bytes = new byte[size];
                  Marshal.Copy(buffer, bytes, 0, size);
                  return bytes;
              }
              finally
              {
                  Marshal.FreeHGlobal(buffer);
              }
          }
          // byte[] 转换为 Struct
          public static object BytesToStruct(byte[] bytes, Type strcutType)
          {
              int size = Marshal.SizeOf(strcutType);
              IntPtr buffer = Marshal.AllocHGlobal(size);
              try
              {
                  Marshal.Copy(bytes, 0, buffer, size);
                  return Marshal.PtrToStructure(buffer, strcutType);
              }
              finally
              {
                  Marshal.FreeHGlobal(buffer);
              }
          }
          #endregion

  }

转载于:https://www.cnblogs.com/dhqy/p/10192062.html

你可能感兴趣的文章
linux命令系列 stat & touch
查看>>
[Tools] Webstorm Github的配置与使用
查看>>
鬼谷子绝学
查看>>
用Html5与Asp.net MVC上传多个文件
查看>>
Xcode中匹配的配置包的存放目录
查看>>
JavaScript将具有父子关系的原始数据格式化成树形结构数据(id,pid)
查看>>
MySQL服务使用
查看>>
C语言练手自己编写学生成绩管理系统
查看>>
20175204 张湲祯 2018-2019-2《Java程序设计》第二周学习总结
查看>>
How to lisp Lisp output a paragraph"500 Tph Dry Process Cement Plant Machinery Manufacturers"
查看>>
OpenMobile's Application Compatibility Layer (ACL)
查看>>
竞价广告系统-广告检索
查看>>
强哥PHP面向对象学习笔记
查看>>
[转]基于.NET平台常用的框架整理
查看>>
Symbian (Read Inbox)读取收件箱的内容
查看>>
良好的编程规范
查看>>
struts2 入门
查看>>
.net 编译原理
查看>>
mean 快速开发和现有技术的对比分析
查看>>
Metro Style app :浏览器扩展
查看>>