????????由于C#編寫的是托管代碼,編譯生成微軟中間語言,而C++代碼則編譯生成本地機(jī)器碼(這種C++也有叫做本地C++或者非托管C++,VC6.0就是用于開發(fā)非托管C++代碼的平臺),這兩種語言進(jìn)行混合編程就存在一定困難。比較常用的方法是使用DllImport的方法,這種方法在網(wǎng)上有很多介紹,這里就不詳細(xì)敘述了。但是用過這種方法的人都知道這種方法對于導(dǎo)出函數(shù)還可以但是卻沒法導(dǎo)出非托管C++類!非常的要命。
????????然而,除了C#、非托管C++外,C系列中還存在一種語言叫做托管C++,這種語言語法上和非托管C++幾乎一樣,但是卻和C#一樣編譯成為微軟中間語言,這樣托管C++就可以和C#良好地通信,即可以在C#中使用托管C++類。另外,托管C++還有兩個及其重要的特性就是:可以調(diào)用非托管C++的類和函數(shù)!托管C++的程序集可以嵌套非托管C++編譯的機(jī)器碼!好強(qiáng)大的混合體。所以我們的技術(shù)路徑也就明晰了:C#以托管C++為中介調(diào)用非托管C++的類和函數(shù)。換句話說也就是用托管C++給非托管C++代碼做一個外殼包裝供C#調(diào)用。
? ? ? ? 換種方式解釋:C#調(diào)用C++的dll庫,如果調(diào)用C++的全局函數(shù)還好,估計可以直接調(diào)用,如果需要調(diào)用C++類里面的函數(shù),因為C#和C++是兩種不同的語言,兩者之間不能直接調(diào)用,他們之間需要一個橋梁,而托管C++可以充當(dāng)這個橋梁,這時需要創(chuàng)建一個C++ CLR dll,C#直接調(diào)用這個dll,間接調(diào)用原dll。
? ? ? ? 下面講解VS2017使用C#語言調(diào)用QT5.9.2 MSVC2017編譯生成的dll的步驟。
第一步:準(zhǔn)備普通的C++類庫,這里使用QT5.9.2 MSVC2017生成的.h、.lib、.dll,64位。
這里不再詳細(xì)敘述,dll導(dǎo)出的函數(shù)參數(shù)都是int、double等基本類型的。
第二步:VS2017創(chuàng)建C++ CLR項目,將普通C++dll重新封裝。
一、創(chuàng)建C++ CLR空項目。
二、注意改為與原C++ dll相同的64位
三、原dll類庫相關(guān)文件準(zhǔn)備好,這里放在程序目錄下library文件夾下
四、.h和lib引入項目,debug和release分別引入
選中項目名稱,點擊“項目》屬性》VC++目錄》包含目錄”,設(shè)置.h所在文件夾
選中項目名稱,點擊“項目》屬性》鏈接器》常規(guī)》附加庫目錄”,設(shè)置.lib所在文件夾
選中項目名稱,點擊“項目》屬性》鏈接器》輸入》附加庫依賴項”,設(shè)置.lib名稱
五、項目屬性調(diào)整,調(diào)整為動態(tài)庫dll項目:
選中項目名稱,點擊“項目》屬性》常規(guī)》配置類型”,改為“動態(tài)庫”
選中項目名稱,點擊“項目》屬性》常規(guī)》公共語言運(yùn)行時支持”,改為“公共語言運(yùn)行時支持(/clr)”
“輸出目錄”、“目標(biāo)文件名”等,根據(jù)需要進(jìn)行修改。
選中項目名稱,點擊“項目》屬性》C/C++》語言》符合模式”,確認(rèn)為“否”
六、添加一個空的.h和一個.cpp文件,命名隨意,這里命名為ManageCppDll.h,ManageCppDll.cpp。根據(jù)原dll的頭文件編寫這兩個文件的內(nèi)容。
.h文件內(nèi)容
// ManageCppDll.h
#pragma once
#ifndef MANAGECPPDLL_H
#define MANAGECPPDLL_H
#include "sorter_filter.h"
/*
* 請先初始化配置數(shù)據(jù)和計算數(shù)據(jù),然后再調(diào)用計算函數(shù)進(jìn)行計算
*/
public ref class ManageCppDll
{
public:
ManageCppDll();
~ManageCppDll();
///
/// \brief Init_SrcData:初始化導(dǎo)入計算數(shù)據(jù),OVector格式
/// \param data_count:in,數(shù)據(jù)數(shù)量
/// \param x_coordinate:in,X軸坐標(biāo)
/// \param y_coordinate:in,Y軸坐標(biāo)
/// \param sensor_up:in,上傳感器值
/// \param sensor_down:in,下傳感器值
///
void Init_SrcData(int data_count, double* x_coordinate, double* y_coordinate, double* sensor_up, double* sensor_down);//初始化導(dǎo)入計算數(shù)據(jù)
///
/// \brief Init_SrcData_3D:初始化導(dǎo)入3D計算數(shù)據(jù),僅針對PCL點云移動最小二乘濾波,OVector<QVector>格式(Filter_PCL_MLS_3D函數(shù))
/// \param lineCount:in,行數(shù)量
/// \param columnCountEveryLine:in,每行數(shù)據(jù)數(shù)量
/// \param x_coordinate:in,X軸坐標(biāo)
/// \param y_coordinate:in,Y軸坐標(biāo)
/// \param sensor_up:in,上傳感器值
/// \param sensor_down:in,下傳感器值
///
void Init_SrcData_3D(int lineCount, int* columnCountEveryLine, double* x_coordinate, double* y_coordinate, double* sensor_up, double* sensor_down);//初始化導(dǎo)入3D計算數(shù)據(jù)
//遞歸中值平均濾波參數(shù)設(shè)置
///
/// \brief Init_Median_ConfigData:遞歸中值平均濾波參數(shù)設(shè)置
/// \param layernum:濾波層數(shù)(一般設(shè)置為1)
/// \param windownum:窗口長度
/// \param masknum:掩碼長度
///
void Init_Median_ConfigData(int layernum, int* windownum, int* masknum);//遞歸中值平均濾波參數(shù)設(shè)置
///
/// \brief Filter_Median:遞歸中值平均濾波,使用時先調(diào)用Init_SrcData導(dǎo)入待濾波數(shù)據(jù),再調(diào)用Init_Median_ConfigData設(shè)置濾波窗口相關(guān),最后調(diào)用此函數(shù)
/// \param data_count:out,數(shù)據(jù)數(shù)量
/// \param x_coordinate:out,X軸坐標(biāo)
/// \param y_coordinate:out,Y軸坐標(biāo)
/// \param sensor_up:out,上傳感器值
/// \param sensor_down:out,下傳感器值
/// \return
///
bool Filter_Median(int& data_count, double* &x_coordinate, double* &y_coordinate, double* &sensor_up, double* &sensor_down);//遞歸中值平均濾波
//calman濾波
///
/// \brief Init_Calman_ConfigData:calman濾波參數(shù)設(shè)置
/// * 當(dāng)我們更信任模型估計值時(模型估計基本沒有誤差),那么應(yīng)該讓Kg小一點,我們應(yīng)該將R取大一點,Q取小一點
/// * 當(dāng)我們更信任觀測值時(模型估計誤差較大),那么應(yīng)該讓Kg大一點,我們應(yīng)該將R取小一點,Q取大一點
/// \param Q
/// \param R
///
void Init_Calman_ConfigData(double Q, double R);//calman濾波參數(shù)設(shè)置
///
/// \brief Filter_Calman
/// \param data_count:out,數(shù)據(jù)數(shù)量
/// \param x_coordinate:out,X軸坐標(biāo)
/// \param y_coordinate:out,Y軸坐標(biāo)
/// \param sensor_up:out,上傳感器值
/// \param sensor_down:out,下傳感器值
/// \return
///
bool Filter_Calman(int& data_count, double* &x_coordinate, double* &y_coordinate, double* &sensor_up, double* &sensor_down);//calman濾波
//PCL-MLS(點云移動最小二乘濾波)相關(guān)
///
/// \brief Init_PCL_ConfigData:PCL移動最小二乘濾波參數(shù)設(shè)置
/// \param MLSSearchRadius:最小二乘濾波半徑
///
void Init_PCL_ConfigData(double MLSSearchRadius);//PCL濾波參數(shù)設(shè)置
///
/// \brief Filter_PCL_MLS
/// \param data_count:out,數(shù)據(jù)數(shù)量
/// \param x_coordinate:out,X軸坐標(biāo)
/// \param y_coordinate:out,Y軸坐標(biāo)
/// \param sensor_up:out,上傳感器值
/// \param sensor_down:out,下傳感器值
/// \return
///
int Filter_PCL_MLS(int& data_count, double* &x_coordinate, double* &y_coordinate, double* &sensor_up, double* &sensor_down);//PCL移動最小二乘濾波;返回:0正常,<0異常
///
/// \brief Filter_PCL_MLS_3D
/// \param lineCount:out,行數(shù)量
/// \param columnCountEveryLine:out,每行數(shù)據(jù)數(shù)量
/// \param x_coordinate:out,X軸坐標(biāo)
/// \param y_coordinate:out,Y軸坐標(biāo)
/// \param sensor_up:out,上傳感器值
/// \param sensor_down:out,下傳感器值
/// \return
///
int Filter_PCL_MLS_3D(int& lineCount, int* &columnCountEveryLine, double* &x_coordinate, double* &y_coordinate, double* &sensor_up, double* &sensor_down);//PCL移動最小二乘濾波;返回:0正常,<0異常
private:
// 類SORTER_CALCULATION的指針,用來調(diào)用類SORTER_CALCULATION的成員函數(shù)
SORTER_FILTER* m_pImp;
};
#endif // MANAGECPPDLL_H
.cpp文件內(nèi)容
// ManageCppDll.cpp
#include "ManageCppDll.h"
#include <vcclr.h>
// 在構(gòu)造函數(shù)中創(chuàng)建類CPerson的對象并在析構(gòu)函數(shù)中將該對象銷毀
// 所有的成員函數(shù)實現(xiàn)都是通過指針m_pImp調(diào)用類CPerson的相應(yīng)成員函數(shù)實現(xiàn)
ManageCppDll::ManageCppDll()
{
m_pImp = new SORTER_FILTER();
}
ManageCppDll::~ManageCppDll()
{
// 在析構(gòu)函數(shù)中刪除CPerson對象
delete m_pImp;
}
//初始化導(dǎo)入計算數(shù)據(jù)
void ManageCppDll::Init_SrcData(int data_count, double* x_coordinate, double* y_coordinate, double* sensor_up, double* sensor_down)
{
return m_pImp->Init_SrcData(data_count, x_coordinate, y_coordinate, sensor_up, sensor_down);
}
//初始化導(dǎo)入3D計算數(shù)據(jù)
void ManageCppDll::Init_SrcData_3D(int lineCount, int* columnCountEveryLine, double* x_coordinate, double* y_coordinate, double* sensor_up, double* sensor_down)
{
return m_pImp->Init_SrcData_3D(lineCount, columnCountEveryLine, x_coordinate, y_coordinate, sensor_up, sensor_down);
}
//遞歸中值平均濾波參數(shù)設(shè)置
void ManageCppDll::Init_Median_ConfigData(int layernum, int* windownum, int* masknum)
{
return m_pImp->Init_Median_ConfigData(layernum, windownum, masknum);
}
//遞歸中值平均濾波
bool ManageCppDll::Filter_Median(int& data_count, double* &x_coordinate, double* &y_coordinate, double* &sensor_up, double* &sensor_down)
{
return m_pImp->Filter_Median(data_count, x_coordinate, y_coordinate, sensor_up, sensor_down);
}
//calman濾波參數(shù)設(shè)置
void ManageCppDll::Init_Calman_ConfigData(double Q, double R)
{
return m_pImp->Init_Calman_ConfigData(Q, R);
}
//calman濾波
bool ManageCppDll::Filter_Calman(int& data_count, double* &x_coordinate, double* &y_coordinate, double* &sensor_up, double* &sensor_down)
{
return m_pImp->Filter_Calman(data_count, x_coordinate, y_coordinate, sensor_up, sensor_down);
}
//PCL移動最小二乘濾波參數(shù)設(shè)置
void ManageCppDll::Init_PCL_ConfigData(double MLSSearchRadius)
{
return m_pImp->Init_PCL_ConfigData(MLSSearchRadius);
}
//PCL移動最小二乘濾波
int ManageCppDll::Filter_PCL_MLS(int& data_count, double* &x_coordinate, double* &y_coordinate, double* &sensor_up, double* &sensor_down)
{
return m_pImp->Filter_PCL_MLS(data_count, x_coordinate, y_coordinate, sensor_up, sensor_down);
}
//PCL移動最小二乘濾波
int ManageCppDll::Filter_PCL_MLS_3D(int& lineCount, int* &columnCountEveryLine, double* &x_coordinate, double* &y_coordinate, double* &sensor_up, double* &sensor_down)
{
return m_pImp->Filter_PCL_MLS_3D(lineCount, columnCountEveryLine, x_coordinate, y_coordinate, sensor_up, sensor_down);
}
最后編譯生成dll。
第三步:在C#項目中調(diào)用,VS2017建立C#項目驗證。
這里創(chuàng)建 Winform項目驗證。注意原dll和CLR版的dll都要加入項目。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace cs_call_cpp_dll
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
unsafe private void button1_Click(object sender, EventArgs e)
{
ManageCppDll calculation_dll = new ManageCppDll();
calculation_dll.Init_ConfigData(4, 10, 2, 0, 0);
double[] array_x = { 0, 1, 2, 3, 4 };
double[] array_y = { 0, 1, 2, 3, 4 };
double[] array_up = { 2, 2, 2, 2, 2 };
double[] array_down = { 0, 1, 6, 3, 4 };
int coordinate_count = 5;
fixed (double* coordinate_x = &array_x[0]
, coordinate_y = &array_y[0]
, coordinate_up = &array_up[0]
, coordinate_down = &array_down[0])
{
calculation_dll.Init_CoordinateData(coordinate_count, coordinate_x, coordinate_y, coordinate_up, coordinate_down);
}
double thickness, thickness_center;
calculation_dll.Calculation_THICKNESS(&thickness, &thickness_center);
calculation_dll.Calculation_THICKNESS(&thickness, &thickness_center);
}
}
}
注意,如果用到了指針,需要加入unsafe,并設(shè)置“允許不安全代碼”。double[]轉(zhuǎn)為double*時用到了fixed,注意fixed的使用方法,這里不再多說。文章來源:http://www.zghlxwxcb.cn/news/detail-725698.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-725698.html
到了這里,關(guān)于C#調(diào)用C++類,托管C++方式實現(xiàn)(創(chuàng)建C++ CLR dll項目)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!