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

news2024/12/23 6:46:02

简单讲讲需求: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博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1119412.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OpenStack云计算平台实战-----创建空白虚拟机

1、创建空白虚拟机 需要注意的步骤会截图一下&#xff0c;其它的基本都是下一步&#xff0c;默认的即可 建议将虚拟机命名为自己的名字加后缀 将处理器数量和每个处理器的内核量都修改为2 将虚拟机的内存设置为8G&#xff0c;不然不够用 将指定磁盘大小设置为200G&#xff0c;…

面试题:什么是微服务 ?

文章目录 微服务是什么微服务是什么样的服务化的前提服务的发布与引用声明式Restful API服务的注册与发现一致性与可用性注册方式存储结构服务健康监测状态变更通知 服务的远程通信网络I/O的处理传输协议序列化方式 注册中心如何保障稳定性节点信息的保障服务节点的摘除服务节点…

微信分销小程序商城的作用是什么

众人拾柴火焰高&#xff0c;分销商城值得是商家通过一定比列的佣金或奖品激励会员或用户分销商品/服务的手段&#xff0c;以低成本获得高收益&#xff0c;也成为不少线上线下商家寻求增长的一种方法。 商家难以完善“引流拓客-转化-留存-复购-裂变-分享”等路径&#xff0c;导…

游戏反虚拟框架检测方案

游戏风险环境&#xff0c;是指独立于原有设备或破坏设备原有系统的环境。常见的游戏风险环境有&#xff1a;iOS越狱、安卓设备root、虚拟机、虚拟框架、云手机等。 因为这类风险环境可以为游戏外挂、破解提供所需的高级别设备权限&#xff0c;所以当游戏处于这些设备环境下&am…

Element UI 密码输入框--可切换显示隐藏,自定义图标

<el-form-item prop"password"><el-inputkeyup.enter.native"login"placeholder"密码"v-model"formData.password":type"showPassword ? text : password"><i slot"suffix" click"switchPas…

策略模式在社会中的应用

文章目录 &#x1f31f; 如何将设计模式策略模式运用到社会当中&#x1f34a; 什么是策略模式&#x1f34a; 策略模式在社会中的应用&#x1f389; 1. 政治选举&#x1f389; 2. 商业竞争&#x1f389; 3. 教育培训 &#x1f34a; 策略模式的优缺点&#x1f389; 优点&#x1f…

SSM - Springboot - MyBatis-Plus 全栈体系(三十三)

第八章 项目实战 终极实战&#xff1a;SpringBoot 版微头条实战 一、微头条案例介绍 1. 微头条业务简介 用户功能 注册功能登录功能jwt 实现 头条新闻 新闻的分页浏览通过标题关键字搜索新闻查看新闻详情新闻的修改和删除 2. 技术栈介绍 2.1 前端技术栈 ES6 作为基础 J…

操作系统——信号量机制(王道视频p30、课本ch6)

1.记忆有技巧&#xff1a;PV操作 —— wait,signal ——肯定是先申请/等待&#xff0c;再释放 2.这里特别指出 记录型信号量就是 后面会重点研究的内容

软件测试肖sir__python之ui自动化实战和讲解(03)

python之ui自动化实战和讲解 一、讲解常见控件定位 链接&#xff1a;http://cms.duoceshi.cn/cms/manage/login.do 1、定位文本框&#xff0c;密码框&#xff0c;按钮 2. 输入 &#xff1a;send_keys()方法 3、点击 &#xff1a;click&#xff08;&#xff09; 方法 案例&…

uniapp在线预约到家按摩系统安装部署二次开发 可以搭建H5公众号+小程序+APP

后端Thinkphp框架开发。前端采用uni-app开发&#xff0c;适配多端&#xff08;小程序&#xff0b;公众号H5&#xff0b;APP&#xff09;源码全开源。 Nginx1.22.1Mysql5.6php7.3redis扩展 支持h5、公众号、小程序、APP&#xff0c;提供相关教程和详细功能文档&#xff01; 含开…

LeetCode算法刷题(python) Day41|09动态规划|理论基础、509. 斐波那契数、70. 爬楼梯、746. 使用最小花费爬楼梯

目录 动规五部曲LeetCode 509. 斐波那契数LeetCode 70. 爬楼梯LeetCode 746. 使用最小花费爬楼梯 动规五部曲 确定dp数组以及下标的含义确定递归公式dp数组如何初始化确定遍历顺序举例推导dp数组 LeetCode 509. 斐波那契数 力扣题目链接 本题最直观是用递归方法 class Sol…

GIL全局解释器锁

文章目录 GIL全局解释器锁一、引入&#xff1a;二、GIL介绍三、GIL与Lock四、GIL与多线程总结 GIL全局解释器锁 一、引入&#xff1a; 首先要明白&#xff0c;GIL并不是Python的一个特性&#xff0c;其实在我们通常所称呼的Python解释器&#xff0c;其实是CPython解释器&…

excel, 熟悉了一般应用的函数,为何还有必要学vba

背景&#xff1a; 1. win10, office 2016, hp Elitebook笔记本电脑 2. 统计数量时&#xff0c;在sheet &#xff08;工作表&#xff09;页面使用函数 sum通过类似 sum(c6:c8) 进行求和&#xff0c;其中C7未被计算在内&#xff0c;例子见图片或附件。即使使用 “数据透视表”…

基于QT的学生考勤系统

低价有偿-获取代码&#xff1a; 知识付费时代&#xff0c;低价有偿获取代码&#xff0c;请理解&#xff01; (1) 下载链接: 后补。 (2) 添加博主微信获取&#xff08;有偿&#xff09;,备注来源: mryang511688 项目描述 技术&#xff1a;C、QT等 摘要&#xff1a; 信息技术的迅…

【Andriod】Appium的不同版本(Appium GUI、Appium Desktop、Appium Server )的安装教程

文章目录 前言一.Appium GUI二.Appium Desktop三.Appium Server 命令行版本1.安装node.js2.安装Appium Server 前言 Appium 安装提供两2方式&#xff1a;桌面版和命令行版。其中桌面版又分为 Appium GUI 和 Appium Desktop。 建议&#xff1a;使用Appium Desktop 一.Appium …

ubuntu安装Anaconda

下载 Anaconda 进入 Ubuntu&#xff0c;自己新建下载路径&#xff0c;输入以下命令开始下载 注意&#xff0c;如果不是 x86_64&#xff0c;需要去镜像看对应的版本&#xff08;https://mirrors.bfsu.edu.cn/anaconda/archive/?CM&OA&#xff09; wget https://mirrors.…

【Java 进阶篇】深入了解 Bootstrap 表格和菜单

表格和菜单是网页设计中的重要组成部分&#xff0c;它们用于展示数据、导航和用户交互。Bootstrap 是一个强大的前端框架&#xff0c;提供了丰富的表格样式和菜单组件&#xff0c;使开发者能够轻松创建功能丰富的网页。在本文中&#xff0c;我们将深入探讨 Bootstrap 中表格和菜…

火热的“出海潮”背后,你还应该知道些什么?

点击文末“阅读原文”即可报名参会 剪辑、音频 / 卷圈 运营 / SandLiu 卷圈 监制 / 姝琦 封面 / 姝琦Midjourney 产品统筹 / bobo 场地支持 / 声湃轩北京录音间 联合制作 / RTE开发者社区 过去几十年&#xff0c;入华的科技企业“走进来”&#xff0c;加速了国内企业的数…

VM虚拟机创建centos7 64位系统提示此主机不支持64位客户机操作系统,此系统无法运行

VM虚拟机创建centos7 64位系统提示此主机不支持64位客户机操作系统,此系统无法运行 背景解决方案 背景 本身系统是window10 64位专业版系统&#xff0c;理论上不应该不支持64位的。 解决方案 最近安装docker开启了虚拟化hyper-v&#xff0c;关闭即可。 打开cmd&#xff08;…

Vue中的v-if和v-show指令有什么区别?

在Vue中,v-if和v-show是两个常用的指令,用于根据条件控制元素的显示和隐藏。虽然它们都可以根据条件来切换元素的可见性,但它们的实现和行为有一些区别。 1:编译时机: v-if是在编译阶段进行条件判断,如果条件为false,则在DOM中不会渲染该元素及其子元素;v-show则是在运…