qt采用C++/CLI 方式调用C#dll的封装方法(高阶应用)

简单讲讲需求: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 
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 m_CSref;
    };
};


// return a pointer to base class CppWrap.  CppWrapImpl cannot be declared in unmanaged code
__declspec(dllexport) CppWrapLibrary::CCppWrap* CreateWrapper()
{
    return static_cast(new CppWrapLibrary::CCppWrapImpl);
}


//int CMainWrapper::GetInt()
//{
//    return 0;
//}
//
//int CMainWrapper::GetInt2()
//{
//    return 0;
//}

在C++主程序里作为调用方


#include 
#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 <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");
}

运行结果

qt采用C++/CLI 方式调用C#dll的封装方法(高阶应用)_第1张图片

具体工程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博客

你可能感兴趣的:(C#,c++,c#,开发语言,C++\CLI,QT,C++,函数指针(回调))