1、打开Visual Studio,新建一个C#的Class Library项目(这里选择的是.Net Framework 4),项目名为CSharpDll。
2、由于默认没有引入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); } } }
里面包含一个加法add,一个减法substract(为了测试指针,所以在减法的返回类型是void,而把计算结果通过ref参数c给返回),一个showBox方法(里面采用C#的MessageBox对话框显示用户输入的参数字串)
4、对project进行release build,在release目录下生成了CSharpDll.dll
(待会用到)。
5、关闭CSharpDll项目,另外新建一个C++ CLR类型的Class Library项目(选择与C#项目相同的.Net Framework 4),项目名称为CppDll。
一开始我用的VS2019,发现VS2019好像无法新建 C++ CLR类型的Class Library项目了,所以学习微软的技术一定要小心,学习主流的支持很久的技术,尽量不要学习新出的技术,如果必须学新技术,一定要认真考量,一些边缘化的技术一定不要学习,没准哪天微软就不维护了。
6、选择Project->CppDll Properties…,在弹出的属性页面选择“Add New Reference..”,点击“browsing.”后选择CSharpDll项目中release目录下的CSharpDll.dll。
7、选择CSharpDll.dll后,可以看到在项目属性的References中出现了CSharpDll这个Library。
8、在CppDll项目中的CppDll.h中利用 _declspec(dllexport)
导出对应的3个接口函数add,substract,showBox 。需要using namespace System::Reflection,对于这里的showBox,其参数不能采用CSharpDll里面的showBox参数的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项目,在release文件夹中生成了CppDll.dll文件,可以看到同时其也将引用的CSharpDll.dll也给拷贝到release文件夹中了。
10、接下来在Qt中进行调用, 在QtCreator中新建一个TestCSharpDll GUI项目,编译器选的mingw。通过VS自带的命令行工具中的dumpbin工具可以查看CppDll.dll导出的函数接口。
dumpbin -exports (+dll路径)
在TestCSharpDll工程中通过typedef定义函数指针,同时采用QLibrary动态加载并resolve函数。
在这里.dll的路径设为当前目录下“./CppDllMingW.dll”,也就是编译好的程序exe同一目录下的dll,去resolve由普通导出方式的接口即“?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复制到同一目录下,执行TestCSharpDll.exe,可看出点击按钮后,通过QLibrary进行动态resolve,均正常调用。
最好是将相关dll置于同一目录下运行,不然会出现“未能加载文件或程序集”的异常。针对.lib链接方式,理应是置于同一目录下。而针对QLibrary进行resolve方式,可能通常一开始的想法是,CppDll.dll和CSharpDll.dll放在与程序不同目录的地方,程序中利用了QLibrary指定了CppDll.dll的方式进行加载,而CppDll.dll和CSharpDll.dll,因此程序调用CppDll.dll里面的函数时,CppDll.dll会找到与CppDll.dll同一目录下的CSharpDll.dll,然而CppDll.dll在被程序进行加载时,其继承了程序的环境变量,因此会从程序的当前目录下去查找,所以最好还是将CppDll.dll和CSharpDll.dll放置于程序同一目录下,同时QLibrary加载当前目录下的CppDll.dll。当然,部署到另外一台机器上时,目标机器还是需要安装.Net Framework,其版本至少不能低于当前CSharpDll.dll所使用的版本。
总结
到此这篇关于Qt程序中调用C#编写的dll的文章就介绍到这了,更多相关Qt 调用C#编写的dll内容请搜索易盾网络以前的文章或继续浏览下面的相关文章希望大家以后多多支持易盾网络!