简单讲讲需求:cpp作为主程序,c#作为第三方程序被调用,并且需要在c#代码里调用主程序里的方法
C#写的dll是没有dllMain入口函数的,是一种中间语言,需要.Net运行时进行做本地化工作,因此如果要调用C#写的dll,需要依赖.Net运行时,然而Qt中还无法直接调用.Net运行时,而且Qt本身的moc机制与.Net运行时天然冲突,需要CLI这一层壳
调用流程:
(QT)非托管C++ --> (C++/CLR)托管C++ --> (项目中C#导出的DLL,基于.NET FRAMEWORK)C#
网上c#调c++的一大堆,但是反过来的却寥寥无几。有的也很简单,实际应用中,不仅需要导出类,还需要传递函数指针作为回调
以下为C#DLL里的主要代码,主要做回调和导出
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace CSharpScriptExport
{
// 声明一个回调委托
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int callback_int_int(int nVal);
public class CCSharpImpl
{
// 声明一个委托字段用于存储回调函数
public callback_int_int absCallback { get; set; }
// 注册回调函数
public void RegCallBack_Abs(callback_int_int fn)
{
absCallback = fn;
}
public void SetInt(int nVal)
{
m_nVal = nVal;
}
public int GetInt()
{
return m_nVal;
}
public int Add(int a, int b)
{
int result = a + b;
// 在方法中调用回调委托,如果已注册
var val= absCallback?.Invoke(a);
if (val.HasValue)
{
result = b + val.Value;
}
return result;
}
public int Subtract(int a, int b)
{
return a - b;
}
private int m_nVal = -5;
}
}
在CLR的DLL里做包装
#include "pch.h"
//#include "CMainWrapper.h"
#include <msclr\gcroot.h>
using namespace System::Runtime::InteropServices;
#using "..\x64\Debug\CSharpScriptExport.dll"
using namespace CSharpScriptExport;
using namespace System;
namespace CppWrapLibrary {
class CCppWrap
{
public:
virtual int Add(int a, int b) = 0;
virtual int Subtract(int a, int b) = 0;
virtual void RegCallback() = 0;
//第一个"_"表示返回值,第二个表示形参列表
virtual void RegCallback_int_int(int(*fn)(int)) = 0;
virtual ~CCppWrap() = default;
};
public ref class CCppFunWrapper {
public:
CCppFunWrapper(int (*cppFun)(int)) {
m_pCppFun = cppFun;
}
int callFun(int arg) {
return m_pCppFun(arg);
}
private:
int (*m_pCppFun)(int);
};
class CCppWrapImpl : public CCppWrap
{
public:
virtual int Add(int a, int b)
{
return m_CSref->Add(a, b);
}
virtual int Subtract(int a, int b)
{
return m_CSref->Subtract(a, b);
}
virtual void RegCallback() {
}
virtual void RegCallback_int_int(int(*fn)(int)) {
CCppFunWrapper^ funWrapper = gcnew CCppFunWrapper(fn); //将cpp风格的函数指针做包装,使得可以作为委托构造参数
CSharpScriptExport::callback_int_int^ callbackFun = gcnew CSharpScriptExport::callback_int_int(funWrapper,&CCppFunWrapper::callFun); //实例化委托对象
m_CSref->RegCallBack_Abs(callbackFun); //注册
}
CCppWrapImpl() : m_CSref(gcnew CSharpScriptExport::CCSharpImpl())
{
}
// Included for debugging breakpoint instead of using compiler generated default destructor
virtual ~CCppWrapImpl()
{
};
private:
// m_CSref holds a reference to the C# class library.
msclr::gcroot<CSharpScriptExport::CCSharpImpl^> m_CSref;
};
};
// return a pointer to base class CppWrap. CppWrapImpl cannot be declared in unmanaged code
__declspec(dllexport) CppWrapLibrary::CCppWrap* CreateWrapper()
{
return static_cast<CppWrapLibrary::CCppWrap*>(new CppWrapLibrary::CCppWrapImpl);
}
//int CMainWrapper::GetInt()
//{
// return 0;
//}
//
//int CMainWrapper::GetInt2()
//{
// return 0;
//}
在C++主程序里作为调用方
#include <iostream>
#include "../CSharpExportWrapper/pch.h"
using namespace std;
//extern "C" _declspec(dllexport) int GetInt();
namespace CppWrapLibrary {
class CCppWrap
{
public:
virtual int Add(int a, int b) = 0;
virtual int Subtract(int a, int b) = 0;
virtual void RegCallback() = 0;
virtual void RegCallback_int_int(int(*fn)(int)) = 0;
virtual ~CCppWrap() = default;
};
};
__declspec(dllimport) CppWrapLibrary::CCppWrap* CreateWrapper();
using namespace CppWrapLibrary;
int powM(int a) {
return a*a;
}
int absM(int a) {
return a >= 0 ? a : -a;
}
//note:主函数模拟QT主程序.
// 因为QT不能在CLR中运行,所以需要借助CLR生成的dll交互
// (QT)非托管C++ --> (C++/CLR)托管C++ --> (项目中C#导出的DLL,基于.NET FRAMEWORK)C#
// 即:QT可执行程序->CSharpExportWrapper动态库(CLR)->CSharpScriptExport
int main()
{
/*int a = GetInt();
std::cout <<a<< "\nHello World!\n";*/
CCppWrap* pWrapper = CreateWrapper();
if (pWrapper)
{
{//类成员调用
cout << "--------类成员调用-------" << endl;
int x = pWrapper->Add(10, 10);
int y = pWrapper->Subtract(100, 58);
cout << "10 + 10 = " << x << "\n100 - 58 = " << y << endl;
}
{//callback
cout << "--------注册回调:absM--------" << endl;
pWrapper->RegCallback_int_int(absM);
int b = pWrapper->Add(-10, 10);
cout << "absM(-10)+10 = " << b << endl;
cout << "--------注册回调:powM--------" << endl;
pWrapper->RegCallback_int_int(powM);
b = pWrapper->Add(-10, 10);
cout << "powM(-10) + 10 = " << b << endl;
}
delete pWrapper;
}
system("pause");
}
运行结果
具体工程Demo下载链接:https://download.csdn.net/download/Charles_ke/88453493
参考资源:
1.How to use C# objects returned in QT. - Microsoft Q&A
2.Lesson 15: Function Pointers and Delegates
3.QT(C++)如何调用C#的动态链接库DLL_qt c++ 调用c# dll_傻傻的小幸福go的博客-CSDN博客