Qt 调用C#编写的dll Qt程序中调用C#编写的dll(推荐)
风向晚。 人气:01、打开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所使用的版本。
总结
加载全部内容