Qt程序中調(diào)用C#編寫的dll(推薦)
1、打開Visual Studio,新建一個(gè)C#的Class Library項(xiàng)目(這里選擇的是.Net Framework 4),項(xiàng)目名為CSharpDll。

2、由于默認(rèn)沒有引入Forms等UI庫,先在reference中添加引用System.Windows.Forms以便可以在測試中使用MessageBox等。

3、最終C#編寫的dll的源代碼如下圖所示,命名空間為CSharpDll,公共類為CSharpClass。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace CSharpDll
{
public class CSharpClass
{
public CSharpClass() { }
public int add(int a , int b)
{
return a + b;
}
public void substract( int a , int b , ref int c)
{
c = a - b;
}
public static void showBox(string str)
{
MessageBox.Show("C#:" + str);
}
}
}
里面包含一個(gè)加法add,一個(gè)減法substract(為了測試指針,所以在減法的返回類型是void,而把計(jì)算結(jié)果通過ref參數(shù)c給返回),一個(gè)showBox方法(里面采用C#的MessageBox對(duì)話框顯示用戶輸入的參數(shù)字串)
4、對(duì)project進(jìn)行release build,在release目錄下生成了CSharpDll.dll(待會(huì)用到)。
5、關(guān)閉CSharpDll項(xiàng)目,另外新建一個(gè)C++ CLR類型的Class Library項(xiàng)目(選擇與C#項(xiàng)目相同的.Net Framework 4),項(xiàng)目名稱為CppDll。

一開始我用的VS2019,發(fā)現(xiàn)VS2019好像無法新建 C++ CLR類型的Class Library項(xiàng)目了,所以學(xué)習(xí)微軟的技術(shù)一定要小心,學(xué)習(xí)主流的支持很久的技術(shù),盡量不要學(xué)習(xí)新出的技術(shù),如果必須學(xué)新技術(shù),一定要認(rèn)真考量,一些邊緣化的技術(shù)一定不要學(xué)習(xí),沒準(zhǔn)哪天微軟就不維護(hù)了。
6、選擇Project->CppDll Properties…,在彈出的屬性頁面選擇“Add New Reference..”,點(diǎn)擊“browsing.”后選擇CSharpDll項(xiàng)目中release目錄下的CSharpDll.dll。

7、選擇CSharpDll.dll后,可以看到在項(xiàng)目屬性的References中出現(xiàn)了CSharpDll這個(gè)Library。
8、在CppDll項(xiàng)目中的CppDll.h中利用 _declspec(dllexport)導(dǎo)出對(duì)應(yīng)的3個(gè)接口函數(shù)add,substract,showBox 。需要using namespace System::Reflection,對(duì)于這里的showBox,其參數(shù)不能采用CSharpDll里面的showBox參數(shù)的String類型,而是使用const char* 類型。
主要代碼如下所示:
// CppDll.h
#pragma once
using namespace System;
using namespace System::Reflection;
__declspec(dllexport) int add(int a, int b)
{
CSharpDll::CSharpClass obj;
return obj.add(a, b);
}
__declspec(dllexport) void substract(int a, int b, int *c)
{
CSharpDll::CSharpClass obj;
obj.substract(a, b, *c);
}
__declspec(dllexport) void showBox(const char* content)
{
CSharpDll::CSharpClass obj;
String^ str = gcnew String(content);
obj.showBox(str);
}
namespace CppDll {
public ref class Class1
{
// TODO: 在此處添加此類的方法。
};
}
9、選擇release方式build CppDll項(xiàng)目,在release文件夾中生成了CppDll.dll文件,可以看到同時(shí)其也將引用的CSharpDll.dll也給拷貝到release文件夾中了。

10、接下來在Qt中進(jìn)行調(diào)用, 在QtCreator中新建一個(gè)TestCSharpDll GUI項(xiàng)目,編譯器選的mingw。通過VS自帶的命令行工具中的dumpbin工具可以查看CppDll.dll導(dǎo)出的函數(shù)接口。
dumpbin -exports (+dll路徑)

在TestCSharpDll工程中通過typedef定義函數(shù)指針,同時(shí)采用QLibrary動(dòng)態(tài)加載并resolve函數(shù)。
在這里.dll的路徑設(shè)為當(dāng)前目錄下“./CppDllMingW.dll”,也就是編譯好的程序exe同一目錄下的dll,去resolve由普通導(dǎo)出方式的接口即“?add@@YAHHH@Z”。
主要代碼如下所示:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QLibrary>
#include<QMessageBox>
typedef int (*x_add)(int a , int b);
typedef void (*x_substract)(int a , int b , int* c);
typedef void (*x_showBox)(const char* content);
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
//add
void MainWindow::on_pushButton_clicked()
{
int a = ui->lineEdit->text().toInt();
int b = ui->lineEdit_2->text().toInt();
QLibrary library("./CppDll.dll");
if(library.load()){
x_add add = (x_add)library.resolve("?add@@YAHHH@Z");
if(add){
QString str = QString::number(add(a , b));
QMessageBox::information(this , "call add from dll" , str);
}
}
}
//sub
void MainWindow::on_pushButton_2_clicked()
{
int a = ui->lineEdit_3->text().toInt();
int b = ui->lineEdit_4->text().toInt();
int c = 0;
QLibrary library("./CppDll.dll");
if(library.load()){
x_substract sub = (x_substract)library.resolve("?substract@@YAXHHPAH@Z");
if(sub){
sub(a , b , &c);
QString str = QString::number(c);
QMessageBox::information(this , "call sub from dll" , str);
}
}
}
//showBox
void MainWindow::on_pushButton_3_clicked()
{
QLibrary library("./CppDll.dll");
if(library.load()){
x_showBox showBox = (x_showBox)library.resolve("?showBox@@YAXPBD@Z");
if(showBox){
showBox("showBox!");
}
}
}
編譯TestCSharpDll工程,將CppDll.dll和CSharpDll.dll復(fù)制到同一目錄下,執(zhí)行TestCSharpDll.exe,可看出點(diǎn)擊按鈕后,通過QLibrary進(jìn)行動(dòng)態(tài)resolve,均正常調(diào)用。


最好是將相關(guān)dll置于同一目錄下運(yùn)行,不然會(huì)出現(xiàn)“未能加載文件或程序集”的異常。針對(duì).lib鏈接方式,理應(yīng)是置于同一目錄下。而針對(duì)QLibrary進(jìn)行resolve方式,可能通常一開始的想法是,CppDll.dll和CSharpDll.dll放在與程序不同目錄的地方,程序中利用了QLibrary指定了CppDll.dll的方式進(jìn)行加載,而CppDll.dll和CSharpDll.dll,因此程序調(diào)用CppDll.dll里面的函數(shù)時(shí),CppDll.dll會(huì)找到與CppDll.dll同一目錄下的CSharpDll.dll,然而CppDll.dll在被程序進(jìn)行加載時(shí),其繼承了程序的環(huán)境變量,因此會(huì)從程序的當(dāng)前目錄下去查找,所以最好還是將CppDll.dll和CSharpDll.dll放置于程序同一目錄下,同時(shí)QLibrary加載當(dāng)前目錄下的CppDll.dll。當(dāng)然,部署到另外一臺(tái)機(jī)器上時(shí),目標(biāo)機(jī)器還是需要安裝.Net Framework,其版本至少不能低于當(dāng)前CSharpDll.dll所使用的版本。
總結(jié)
到此這篇關(guān)于Qt程序中調(diào)用C#編寫的dll的文章就介紹到這了,更多相關(guān)Qt 調(diào)用C#編寫的dll內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
采用C#實(shí)現(xiàn)軟件自動(dòng)更新的方法
這篇文章主要介紹了采用C#實(shí)現(xiàn)軟件自動(dòng)更新的方法,非常實(shí)用的功能,需要的朋友可以參考下2014-08-08
UnityShader3實(shí)現(xiàn)2D描邊效果
這篇文章主要為大家詳細(xì)介紹了UnityShader3實(shí)現(xiàn)2D描邊效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-02-02
.NET(C#):Emit創(chuàng)建異常處理的方法
.NET(C#):Emit創(chuàng)建異常處理的方法,需要的朋友可以參考一下2013-04-04
C# 向Word中設(shè)置/更改文本方向的方法(兩種)
在一般情況下word中輸入的文字都是橫向的,今天小編給大家?guī)韮煞N方法來設(shè)置更改文本方向的方法,非常不錯(cuò),對(duì)c# word 更改文本方向的知識(shí)感興趣的朋友一起看看吧2016-08-08
C#中使用IFormattable實(shí)現(xiàn)自定義格式化字符串輸出示例
這篇文章主要介紹了C#中使用IFormattable實(shí)現(xiàn)自定義格式字符串輸出示例,本文直接給出實(shí)例代碼,需要的朋友可以參考下2015-06-06
如何在Mac系統(tǒng)使用Visual Studio Code運(yùn)行Python
這篇文章主要介紹了Mac使用Visual Studio Code運(yùn)行Python環(huán)境的方法,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04
使用C#快速搭建一個(gè)在windows運(yùn)行的exe應(yīng)用
這篇文章主要介紹了使用C#快速搭建一個(gè)在windows運(yùn)行的exe應(yīng)用,這是一個(gè)比較舊的內(nèi)容,但是一直都沒有空寫,今天花點(diǎn)時(shí)間,把我掌握的C# 分享給初學(xué)的人或者感興趣的人,希望能對(duì)你有一定幫助,感興趣的小伙伴跟著小編一起來看看吧2024-07-07

