qt uses C++/CLI to call the encapsulation method of C#dll (high-order application)

Let’s briefly talk about the requirements: cpp serves as the main program, c# is called as a third-party program, and methods in the main program need to be called in the c# code

The dll written in C# does not have the dllMain entry function. It is an intermediate language and requires the .Net runtime for localization work. Therefore, if you want to call the dll written in C#, you need to rely on the .Net runtime. However, Qt cannot directly Calling the .Net runtime, and Qt’s own moc mechanism naturally conflicts with the .Net runtime, requires the CLI shell

Calling process:

(QT) Unmanaged C++ --> (C++/CLR) Managed C++ --> (DLL exported by C# in the project, based on .NET FRAMEWORK) C#

There are a lot of C# adjustments to C++ on the Internet, but there are very few in reverse. Some are very simple. In practical applications, not only do you need to export classes, but you also need to pass function pointers as callbacks.

The following is the main code in C# DLL, mainly for callback and export

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace CSharpScriptExport
{
    // Declare a callback delegate
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate int callback_int_int(int nVal);

    public classCCSharpImpl
    {
        // Declare a delegate field to store the callback function
        public callback_int_int absCallback { get; set; }

        //Register callback function
        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;

            // Call the callback delegate in the method, if registered
            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;
    }
}

Wrapping in 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;
        //The first "_" represents the return value, and the second represents the formal parameter list
        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); //Wrap cpp-style function pointers so that they can be used as delegate construction parameters
            CSharpScriptExport::callback_int_int^ callbackFun = gcnew CSharpScriptExport::callback_int_int(funWrapper, & amp;CCppFunWrapper::callFun); //Instantiate the delegate object
            m_CSref->RegCallBack_Abs(callbackFun); //Register
        }

        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;
//}

As a caller in the C++ main program

#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: The main function simulates the QT main program.
// Because QT cannot run in the CLR, it needs to interact with the dll generated by the CLR
// (QT) Unmanaged C++ --> (C++/CLR) Managed C++ --> (DLL exported by C# in the project, based on .NET FRAMEWORK) C#
// That is: QT executable program->CSharpExportWrapper dynamic library (CLR)->CSharpScriptExport
int main()
{
    /*int a = GetInt();
    std::cout <Add(10, 10);
            int y = pWrapper->Subtract(100, 58);
            cout << "10 + 10 = " << x << "\\
100 - 58 = " << y << endl;
        }
        {//callback
            cout << "--------Registered callback: absM--------" << endl;
            pWrapper->RegCallback_int_int(absM);
            int b = pWrapper->Add(-10, 10);
            cout << "absM(-10) + 10 = " << b << endl;

            cout << "--------Registered callback: powM--------" << endl;
            pWrapper->RegCallback_int_int(powM);
            b = pWrapper->Add(-10, 10);
            cout << "powM(-10) + 10 = " << b << endl;
        }
        delete pWrapper;
    }
    system("pause");
}

operation result

Specific project Demo download link: https://download.csdn.net/download/Charles_ke/88453493

Reference resources:

1.How to use C# objects returned in QT. - Microsoft Q &A

2.Lesson 15: Function Pointers and Delegates

3. How does QT (C++) call C#’s dynamic link library DLL_qt c++ calls c# dll_Silly Little Happy Go’s Blog-CSDN Blog