• C#调用C++类,托管C++方式实现(创建C++ CLR dll项目)


            由于C#编写的是托管代码,编译生成微软中间语言,而C++代码则编译生成本地机器码(这种C++也有叫做本地C++或者非托管C++,VC6.0就是用于开发非托管C++代码的平台),这两种语言进行混合编程就存在一定困难。比较常用的方法是使用DllImport的方法,这种方法在网上有很多介绍,这里就不详细叙述了。但是用过这种方法的人都知道这种方法对于导出函数还可以但是却没法导出非托管C++类!非常的要命。

            然而,除了C#、非托管C++外,C系列中还存在一种语言叫做托管C++,这种语言语法上和非托管C++几乎一样,但是却和C#一样编译成为微软中间语言,这样托管C++就可以和C#良好地通信,即可以在C#中使用托管C++类。另外,托管C++还有两个及其重要的特性就是:可以调用非托管C++的类和函数!托管C++的程序集可以嵌套非托管C++编译的机器码!好强大的混合体。所以我们的技术路径也就明晰了:C#以托管C++为中介调用非托管C++的类和函数。换句话说也就是用托管C++给非托管C++代码做一个外壳包装供C#调用。

            换种方式解释:C#调用C++的dll库,如果调用C++的全局函数还好,估计可以直接调用,如果需要调用C++类里面的函数,因为C#和C++是两种不同的语言,两者之间不能直接调用,他们之间需要一个桥梁,而托管C++可以充当这个桥梁,这时需要创建一个C++ CLR dll,C#直接调用这个dll,间接调用原dll。

            下面讲解VS2017使用C#语言调用QT5.9.2 MSVC2017编译生成的dll的步骤。

    第一步:准备普通的C++类库,这里使用QT5.9.2 MSVC2017生成的.h、.lib、.dll,64位。

    这里不再详细叙述,dll导出的函数参数都是int、double等基本类型的。

    第二步:VS2017创建C++ CLR项目,将普通C++dll重新封装。

    一、创建C++ CLR空项目。

    二、注意改为与原C++ dll相同的64位

    三、原dll类库相关文件准备好,这里放在程序目录下library文件夹下

    四、.h和lib引入项目,debug和release分别引入

    选中项目名称,点击“项目》属性》VC++目录》包含目录”,设置.h所在文件夹

    选中项目名称,点击“项目》属性》链接器》常规》附加库目录”,设置.lib所在文件夹

    选中项目名称,点击“项目》属性》链接器》输入》附加库依赖项”,设置.lib名称

    五、项目属性调整,调整为动态库dll项目:

    选中项目名称,点击“项目》属性》常规》配置类型”,改为“动态库”

    选中项目名称,点击“项目》属性》常规》公共语言运行时支持”,改为“公共语言运行时支持(/clr)”

    “输出目录”、“目标文件名”等,根据需要进行修改。

    选中项目名称,点击“项目》属性》C/C++》语言》符合模式”,确认为“否”

    六、添加一个空的.h和一个.cpp文件,命名随意,这里命名为ManageCppDll.h,ManageCppDll.cpp。根据原dll的头文件编写这两个文件的内容。

    .h文件内容

    1. // ManageCppDll.h
    2. #pragma once
    3. #ifndef MANAGECPPDLL_H
    4. #define MANAGECPPDLL_H
    5. #include "sorter_filter.h"
    6. /*
    7. * 请先初始化配置数据和计算数据,然后再调用计算函数进行计算
    8. */
    9. public ref class ManageCppDll
    10. {
    11. public:
    12. ManageCppDll();
    13. ~ManageCppDll();
    14. ///
    15. /// \brief Init_SrcData:初始化导入计算数据,OVector格式
    16. /// \param data_count:in,数据数量
    17. /// \param x_coordinate:in,X轴坐标
    18. /// \param y_coordinate:in,Y轴坐标
    19. /// \param sensor_up:in,上传感器值
    20. /// \param sensor_down:in,下传感器值
    21. ///
    22. void Init_SrcData(int data_count, double* x_coordinate, double* y_coordinate, double* sensor_up, double* sensor_down);//初始化导入计算数据
    23. ///
    24. /// \brief Init_SrcData_3D:初始化导入3D计算数据,仅针对PCL点云移动最小二乘滤波,OVector格式(Filter_PCL_MLS_3D函数)
    25. /// \param lineCount:in,行数量
    26. /// \param columnCountEveryLine:in,每行数据数量
    27. /// \param x_coordinate:in,X轴坐标
    28. /// \param y_coordinate:in,Y轴坐标
    29. /// \param sensor_up:in,上传感器值
    30. /// \param sensor_down:in,下传感器值
    31. ///
    32. void Init_SrcData_3D(int lineCount, int* columnCountEveryLine, double* x_coordinate, double* y_coordinate, double* sensor_up, double* sensor_down);//初始化导入3D计算数据
    33. //递归中值平均滤波参数设置
    34. ///
    35. /// \brief Init_Median_ConfigData:递归中值平均滤波参数设置
    36. /// \param layernum:滤波层数(一般设置为1)
    37. /// \param windownum:窗口长度
    38. /// \param masknum:掩码长度
    39. ///
    40. void Init_Median_ConfigData(int layernum, int* windownum, int* masknum);//递归中值平均滤波参数设置
    41. ///
    42. /// \brief Filter_Median:递归中值平均滤波,使用时先调用Init_SrcData导入待滤波数据,再调用Init_Median_ConfigData设置滤波窗口相关,最后调用此函数
    43. /// \param data_count:out,数据数量
    44. /// \param x_coordinate:out,X轴坐标
    45. /// \param y_coordinate:out,Y轴坐标
    46. /// \param sensor_up:out,上传感器值
    47. /// \param sensor_down:out,下传感器值
    48. /// \return
    49. ///
    50. bool Filter_Median(int& data_count, double* &x_coordinate, double* &y_coordinate, double* &sensor_up, double* &sensor_down);//递归中值平均滤波
    51. //calman滤波
    52. ///
    53. /// \brief Init_Calman_ConfigData:calman滤波参数设置
    54. /// * 当我们更信任模型估计值时(模型估计基本没有误差),那么应该让Kg小一点,我们应该将R取大一点,Q取小一点
    55. /// * 当我们更信任观测值时(模型估计误差较大),那么应该让Kg大一点,我们应该将R取小一点,Q取大一点
    56. /// \param Q
    57. /// \param R
    58. ///
    59. void Init_Calman_ConfigData(double Q, double R);//calman滤波参数设置
    60. ///
    61. /// \brief Filter_Calman
    62. /// \param data_count:out,数据数量
    63. /// \param x_coordinate:out,X轴坐标
    64. /// \param y_coordinate:out,Y轴坐标
    65. /// \param sensor_up:out,上传感器值
    66. /// \param sensor_down:out,下传感器值
    67. /// \return
    68. ///
    69. bool Filter_Calman(int& data_count, double* &x_coordinate, double* &y_coordinate, double* &sensor_up, double* &sensor_down);//calman滤波
    70. //PCL-MLS(点云移动最小二乘滤波)相关
    71. ///
    72. /// \brief Init_PCL_ConfigData:PCL移动最小二乘滤波参数设置
    73. /// \param MLSSearchRadius:最小二乘滤波半径
    74. ///
    75. void Init_PCL_ConfigData(double MLSSearchRadius);//PCL滤波参数设置
    76. ///
    77. /// \brief Filter_PCL_MLS
    78. /// \param data_count:out,数据数量
    79. /// \param x_coordinate:out,X轴坐标
    80. /// \param y_coordinate:out,Y轴坐标
    81. /// \param sensor_up:out,上传感器值
    82. /// \param sensor_down:out,下传感器值
    83. /// \return
    84. ///
    85. int Filter_PCL_MLS(int& data_count, double* &x_coordinate, double* &y_coordinate, double* &sensor_up, double* &sensor_down);//PCL移动最小二乘滤波;返回:0正常,<0异常
    86. ///
    87. /// \brief Filter_PCL_MLS_3D
    88. /// \param lineCount:out,行数量
    89. /// \param columnCountEveryLine:out,每行数据数量
    90. /// \param x_coordinate:out,X轴坐标
    91. /// \param y_coordinate:out,Y轴坐标
    92. /// \param sensor_up:out,上传感器值
    93. /// \param sensor_down:out,下传感器值
    94. /// \return
    95. ///
    96. int Filter_PCL_MLS_3D(int& lineCount, int* &columnCountEveryLine, double* &x_coordinate, double* &y_coordinate, double* &sensor_up, double* &sensor_down);//PCL移动最小二乘滤波;返回:0正常,<0异常
    97. private:
    98. // 类SORTER_CALCULATION的指针,用来调用类SORTER_CALCULATION的成员函数
    99. SORTER_FILTER* m_pImp;
    100. };
    101. #endif // MANAGECPPDLL_H

    .cpp文件内容

    1. // ManageCppDll.cpp
    2. #include "ManageCppDll.h"
    3. #include
    4. // 在构造函数中创建类CPerson的对象并在析构函数中将该对象销毁
    5. // 所有的成员函数实现都是通过指针m_pImp调用类CPerson的相应成员函数实现
    6. ManageCppDll::ManageCppDll()
    7. {
    8. m_pImp = new SORTER_FILTER();
    9. }
    10. ManageCppDll::~ManageCppDll()
    11. {
    12. // 在析构函数中删除CPerson对象
    13. delete m_pImp;
    14. }
    15. //初始化导入计算数据
    16. void ManageCppDll::Init_SrcData(int data_count, double* x_coordinate, double* y_coordinate, double* sensor_up, double* sensor_down)
    17. {
    18. return m_pImp->Init_SrcData(data_count, x_coordinate, y_coordinate, sensor_up, sensor_down);
    19. }
    20. //初始化导入3D计算数据
    21. void ManageCppDll::Init_SrcData_3D(int lineCount, int* columnCountEveryLine, double* x_coordinate, double* y_coordinate, double* sensor_up, double* sensor_down)
    22. {
    23. return m_pImp->Init_SrcData_3D(lineCount, columnCountEveryLine, x_coordinate, y_coordinate, sensor_up, sensor_down);
    24. }
    25. //递归中值平均滤波参数设置
    26. void ManageCppDll::Init_Median_ConfigData(int layernum, int* windownum, int* masknum)
    27. {
    28. return m_pImp->Init_Median_ConfigData(layernum, windownum, masknum);
    29. }
    30. //递归中值平均滤波
    31. bool ManageCppDll::Filter_Median(int& data_count, double* &x_coordinate, double* &y_coordinate, double* &sensor_up, double* &sensor_down)
    32. {
    33. return m_pImp->Filter_Median(data_count, x_coordinate, y_coordinate, sensor_up, sensor_down);
    34. }
    35. //calman滤波参数设置
    36. void ManageCppDll::Init_Calman_ConfigData(double Q, double R)
    37. {
    38. return m_pImp->Init_Calman_ConfigData(Q, R);
    39. }
    40. //calman滤波
    41. bool ManageCppDll::Filter_Calman(int& data_count, double* &x_coordinate, double* &y_coordinate, double* &sensor_up, double* &sensor_down)
    42. {
    43. return m_pImp->Filter_Calman(data_count, x_coordinate, y_coordinate, sensor_up, sensor_down);
    44. }
    45. //PCL移动最小二乘滤波参数设置
    46. void ManageCppDll::Init_PCL_ConfigData(double MLSSearchRadius)
    47. {
    48. return m_pImp->Init_PCL_ConfigData(MLSSearchRadius);
    49. }
    50. //PCL移动最小二乘滤波
    51. int ManageCppDll::Filter_PCL_MLS(int& data_count, double* &x_coordinate, double* &y_coordinate, double* &sensor_up, double* &sensor_down)
    52. {
    53. return m_pImp->Filter_PCL_MLS(data_count, x_coordinate, y_coordinate, sensor_up, sensor_down);
    54. }
    55. //PCL移动最小二乘滤波
    56. int ManageCppDll::Filter_PCL_MLS_3D(int& lineCount, int* &columnCountEveryLine, double* &x_coordinate, double* &y_coordinate, double* &sensor_up, double* &sensor_down)
    57. {
    58. return m_pImp->Filter_PCL_MLS_3D(lineCount, columnCountEveryLine, x_coordinate, y_coordinate, sensor_up, sensor_down);
    59. }

    最后编译生成dll。

    第三步:在C#项目中调用,VS2017建立C#项目验证。

    这里创建 Winform项目验证。注意原dll和CLR版的dll都要加入项目。

    1. using System;
    2. using System.Collections.Generic;
    3. using System.ComponentModel;
    4. using System.Data;
    5. using System.Drawing;
    6. using System.Linq;
    7. using System.Text;
    8. using System.Threading.Tasks;
    9. using System.Windows.Forms;
    10. namespace cs_call_cpp_dll
    11. {
    12. public partial class Form1 : Form
    13. {
    14. public Form1()
    15. {
    16. InitializeComponent();
    17. }
    18. unsafe private void button1_Click(object sender, EventArgs e)
    19. {
    20. ManageCppDll calculation_dll = new ManageCppDll();
    21. calculation_dll.Init_ConfigData(4, 10, 2, 0, 0);
    22. double[] array_x = { 0, 1, 2, 3, 4 };
    23. double[] array_y = { 0, 1, 2, 3, 4 };
    24. double[] array_up = { 2, 2, 2, 2, 2 };
    25. double[] array_down = { 0, 1, 6, 3, 4 };
    26. int coordinate_count = 5;
    27. fixed (double* coordinate_x = &array_x[0]
    28. , coordinate_y = &array_y[0]
    29. , coordinate_up = &array_up[0]
    30. , coordinate_down = &array_down[0])
    31. {
    32. calculation_dll.Init_CoordinateData(coordinate_count, coordinate_x, coordinate_y, coordinate_up, coordinate_down);
    33. }
    34. double thickness, thickness_center;
    35. calculation_dll.Calculation_THICKNESS(&thickness, &thickness_center);
    36. calculation_dll.Calculation_THICKNESS(&thickness, &thickness_center);
    37. }
    38. }
    39. }

    注意,如果用到了指针,需要加入unsafe,并设置“允许不安全代码”。double[]转为double*时用到了fixed,注意fixed的使用方法,这里不再多说。

  • 相关阅读:
    JavaSE进阶之(十三)Java 异常处理的 21 个最佳实践
    概述UVM中的build、configure和connect【uvm】
    面向对象设计模式实例
    上海亚商投顾:市场继续缩量调整 汽车、光伏板块领涨
    数据的力量:Facebook如何通过数据分析驱动创新
    如何编辑科学摘要
    聚水潭对接金蝶云星空数据方案
    sqlite3数据库文件损坏修复
    难辨真假的Midjourney案例(附提示词):适合练手
    可用性测试的理解
  • 原文地址:https://blog.csdn.net/csdndenglu/article/details/133815107