Qt调用Matlab库C#库dll调用C++调用C#库CSharp库lib invoke matlab library .net donet netframework
该文章是一篇说明c++/Qt调用C#库的例子及代码,主要是本人在工作中尝试调用C#过程中,出现了很多的问题,以至于花了很长时间才有些头绪,这也是为了帮助即将有此需求的您,也是为了记录我的操作过程,以便下次不再花费长时间。
我整个过程是使用Matlab转.net库,CLI接口调用Matlab库,使用的是vs2019,matlab2022,Qt5.14.2,windows10系统。所有的代码只是为了测试使用,请根据自己需求修改。该过程中包含算法输入输出的转换方法,这也是过程中的重点所在。
废话少说,开始吧。。。
1、Matlab代码
function [doubleArg, stringArg] = MyAlgoTest(doubleArg1 ,doubleArg2, stringArg3)
%MYALGOTEST 此处显示有关此函数的摘要
% 此处显示详细说明
doubleArg = doubleArg1 + doubleArg2;
stringArg = stringArg3 + "_Matlab";
end
2、deploytool命令转换为.net库
3、建立C#工程,并加入上面生成的matlab库,和Mwarray库
C#代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MyAlgoTest;
using MathWorks.MATLAB.NET.Arrays;
namespace LibCSAlgo
{
public class CSClass
{
//function [doubleArg, stringArg] = MyAlgoTest(doubleArg1 ,doubleArg2, stringArg3)
public string InvokeMatlabAlgo(double arg1, double arg2, string arg3, out double outArg1, out string outArg2)
{
string error = "";
System.Console.WriteLine("ARG1 = ", arg1);
System.Console.WriteLine("ARG2 = ", arg2);
System.Console.WriteLine("ARG3 = ", arg3);
TestClass c = new TestClass();
MWArray[] outData = c.MyAlgoTest(2, arg1, arg2, arg3);
outArg1 = (double)(MWNumericArray)outData[0];
outArg2 = outData[1].ToString();
System.Console.WriteLine("outArg1 = ", outArg1);
System.Console.WriteLine("outArg2 = ", outArg2);
return error;
}
}
}
4、建立CLR库工程,如果无此选项,需要通过vs安装程序安装CLI支持
5、CLR库代码
#include "pch.h"
#include "LibCLRWapper.h"
#include <msclr/marshal_cppstd.h>
#include <iostream>
#using "LibCSAlgo.dll"
using namespace LibCSAlgo;
using namespace System;
using namespace System::IO;
using namespace msclr::interop;
gcroot<CSClass^>* g_csclass = new gcroot<CSClass ^>; //全局变量定义
//CSClass^ g_csclass = gcnew CSClass; //不能使用此方法定义全局托管变量,报错
LibCLRWapper::CLRClass::CLRClass()
{
*g_csclass = gcnew CSClass();
}
std::string LibCLRWapper::CLRClass::InvokeMyAlgo(double arg1, double arg2, const char* arg3, double& oArg1, char** oArg2)
{
System::String^ outString_ = gcnew System::String("");
System::String^ stringArg = gcnew System::String(arg3);
double outDouble = 0;
System::String^ outData = (*g_csclass)->InvokeMatlabAlgo(arg1, arg2, stringArg, outDouble, outString_);
int stringLen = outString_->Length;
std::string oo = marshal_as<std::string>(outString_);
memcpy(*oArg2, oo.c_str(), stringLen);
oArg1 = outDouble;
std::cout << "\n\nThis is CLR:" << std::endl;
std::cout << "outDouble:" << outDouble<< std::endl;
std::cout << "outString:" << oo << std::endl;
outData = "No Error";
return marshal_as<std::string>(outData);
}
#pragma once
#include <string>
//不要在此h文件中using namespace 有关c#的空间,因此可能会与windows.h的空间冲突,建议只在cpp中using
# if defined LIB_CLRLibrary
# define CLRLIBRARY_EXPORT __declspec(dllexport)
# else
# define CLRLIBRARY_EXPORT __declspec(dllimport)
# endif
namespace LibCLRWapper {
/*public ref*/ class CLRLIBRARY_EXPORT CLRClass
{
public:
CLRClass();
std::string InvokeMyAlgo(double arg1, double arg2, const char* arg3, double& oArg1, char** oArg2);
};
}
此工程需要在预处理中加入导出宏,以及添加“引用”第3步建立的C#库
using *.dll的目录可以写绝对路径或者相对路径,否则可能找不到
6、QT工程,带界面,点击按钮执行
void QTinvokeCSMatlab::on_pushButton_invoke_clicked(void)
{
qDebug() << "invoke start" << endl;
if (m_clrclass)
{
//std::string InvokeMyAlgo(double arg1, double arg2, char* arg3, double& oArg1, char** oArg2);
double arg1 = 10;
double arg2 = 20;
QString arg3 = "Test";
double oArg1 = 0;
std::string oArg2 = "";
char * oArg2_ = new char[128];
memset(oArg2_, 0, 128);
char arg3_[128] = {
0 };
memset(arg3_, 0, 128);
memcpy(arg3_, arg3.toLatin1(), arg3.length());
//
std::string outData = m_clrclass->InvokeMyAlgo(arg1, arg2, arg3.toStdString().c_str(), oArg1, &oArg2_);
std::string o2(oArg2_);
if (oArg2_)
{
delete oArg2_;
oArg2_ = nullptr;
}
qDebug() << "\n\nThis is QT:";
qDebug() << "oArg1 = " << QString::number(oArg1);
qDebug() << "oArg2 = " << o2.c_str() << endl;
qDebug() << "outData = " << outData.c_str();
}
qDebug() << "invoke over" << endl;
QMessageBox::information(this, QString("Info"), QString("Over"));
}
到此,代码已经全部完成。
其中CLR既可以使用C#的语法也可以使用C++语法,只是new的表示方法有点区别,主要还是要注意输入输出的变量,以及不同语言之间的编码问题,可能会使得结果不正确或者乱码,至少我写的例子中不会出现,默认就好了。
执行结果: