Qt C++动态库SDK在Visual Studio 2022使用(C++/C#版本)

01  

将C++ SDK 集成到 IDE 中

以下是在 Microsoft Visual Studio 平台下 SDK 的集成。

2.1 Visual Studio 平台下 C/C++环境配置及集成到 IDE 中

xxx.lib 和 xxx.dll 适合在 Windows 操作系统平台使用,这里以 VS2022 环境为例。

2.1.1 C/C++ 工程环境配置与集成

1C# SDK 接口文件包含

a、将 a.hb.hc.h

a.cpp 拷贝到用户指定路径下。

b、点击项目 属性 - C/C++ -常规。在附加包含目录下指定头文件的路径。

2、添加库引用和库的路径

、 将 提 供 的 a_sdk.dll , b.dll 拷 贝 到 程 序 运 行 的 目 录 下 ; 将

a.lib 拷贝到用户指定路径下。

b、点击项目 属性 链接器 常规。在附加库目录中指定 a.lib 的路

径。

02  

2.1.2 在用户 C/C++ 项目中使用 SDK

以下为获取数据的简单步骤,更详细的使用方法可以参考提供的 Demo 程序。

添加头文件,添加库以后,将dll放在可执行目录,即可调用外部SDK动态库使用。

03  

2.2 Visual Studio 平台下 C#环境配置及集成到 IDE 中

CSharp_Lib 适合在 Windows 操作系统平台使用,这里以 VS2022 环境为例。

2.2.1 C# 工程环境配置与集成

1、工程文件包含

将 CSharp_Lib 文件夹拷贝到工程目录下,并把 dll 文件夹相对应 x64 和 x86

的 aa.dll 和bb_sdk.dll 拷贝到工程目录的运行目录下。

注意:将C++ DLL给C#上位机使用,有很多语法需要转换,这个我们会详细介绍。

04  

C#为例

将C++ 的动态库依赖的头文件和源文件转为.cs格式。

C#需要的模块

  1. using System;:引用了System命名空间,这是C#中最基础的命名空间,包含了基本的类和功能,如Console类、Math类等。

  2. using System.Collections.Generic;:引用了System.Collections.Generic命名空间,这个命名空间包含了泛型集合类,如List<T>Dictionary<TKey, TValue>等,这些类在处理数据集合时非常有用。

  3. using System.Linq;:引用了System.Linq命名空间,这个命名空间包含了LINQ(Language Integrated Query)相关的类和功能,LINQ允许在C#中编写查询语句来操作数据集合。

  4. using System.Text;:引用了System.Text命名空间,这个命名空间包含了处理字符串和文本的类,如StringBuilder类。

  5. using System.Threading.Tasks;:引用了System.Threading.Tasks命名空间,这个命名空间包含了异步编程相关的类和功能,如Task类和async/await关键字。

代码格式

    namespace DEVICE{    classParameterDefine    {        //代码实现         public const string a = "123";    }}    

    枚举格式

       public enum StatusTypeDef {    RED; }

      使用C++动态库的头文件的结构体的中含有字符串,需要进行转化。

      • [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]

         这是一个特性,用于指定结构体在内存中的布局方式以及如何处理字符串数据。

      • LayoutKind.Sequential

         表示结构体中的元素在内存中按它们在代码中定义的顺序进行布局,不会被打乱。这对于与非托管代码(如C++编写的DLL)进行交互非常重要,以确保数据在内存中的排列方式匹配。

      • CharSet = CharSet.Ansi

         指定了结构体中的字符串使用ANSI字符集。ANSI字符集是一种单字节字符集,通常用于支持英语和其他西欧语言。这对于与需要ANSI字符串的非托管代码进行交互是有必要的。如果需要支持Unicode字符集,则应使用 CharSet = CharSet.Unicode。这里使用ANSI是为了确保与SDK中的函数参数类型匹配。

      使用C++动态库的头文件的字符数组,需要进行转化。如char a[32];

      C++ 字符数组转为字符串

      1. [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]:

        • [MarshalAs(...)]

          : 这是一个C#中的特性(attribute),用于指定字段在封送到非托管代码时应如何处理。它属于System.Runtime.InteropServices命名空间,因此在使用之前需要引入该命名空间。

        • UnmanagedType.ByValTStr

          : 这个值指定字段应该被封送为固定长度的ANSI字符数组。ANSI字符通常是单字节字符,适合处理不包含Unicode字符的数据。

        • SizeConst = 32

          : 这个值指定了字段在非托管代码中的大小(以字符为单位)。在这里,SizeConst = 32表示字符数组的长度为32个字符(包括结束符’\0’)。

         [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] //设备IP地址和端口号 public struct DeviceNetPara_t {     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]     public string ip_addr;     public UInt32 port; }

        C++ char*转为字符数组

        1. 特性(Attributes): 特性是用于向程序中的类型、方法或属性添加元数据的方式。C#中的特性可以用于编译时检查以及运行时的行为修改。

        2. StructLayout: 这是一个特性,用于指定结构体在内存中的布局方式。它有几个参数可以配置,这里主要用到了LayoutKind.SequentialCharSetPack

        3. LayoutKind.Sequential: 这个参数指定结构体中的字段按照它们在代码中声明的顺序存储在内存中。这与C/C++中的结构体布局方式一致。

        4. CharSet = CharSet.Ansi: 这个参数用于指定结构体中字符串字段的字符编码方式。CharSet.Ansi表示使用ANSI字符集来存储字符串。这意味着每个字符占用一个字节,适用于ASCII字符集。

        5. Pack = 4: 这个参数用于指定结构体字段的对齐方式。Pack = 4表示结构体中的字段按照4字节对齐。这意味着每个字段的起始地址必须是4字节的倍数。这通常用于优化性能,特别是在与非托管代码(如C/C++库)交互时。

           [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 4)] //数据 public struct Info_t {       [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]     public char[] ip; }

          C++ void* 转换IntPtr

          1. 特性声明 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]

            :

            • StructLayout

               是一个C#特性,用于定义结构体在内存中的布局方式。在C#中,结构体默认使用 LayoutKind.Auto,这意味着编译器可以根据需要重新排列结构体中的字段以优化内存使用。

            • LayoutKind.Sequential

               选项强制编译器按结构体中字段定义的顺序在内存中布局这些字段。这对于与非托管代码(如C/C++代码)进行交互非常重要,因为你需要确保结构体的布局与非托管代码期望的布局一致。

            • CharSet = CharSet.Auto

               选项指定了非托管字符串的类型。CharSet.Auto 在Windows平台上通常被解释为 CharSet.Unicode,但在其他平台上则可能是 CharSet.Ansi。这确保了字符串在与非托管代码交互时的正确编码。

            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]//异步事件参数public struct Args_t{    public IntPtr data;                 //数据}

            C++ 回调函数指针转为C#

            1. 特性(Attribute):

              • [UnmanagedFunctionPointer(CallingConvention.Cdecl)]

                :这是一个特性,用于修饰一个委托(delegate),告诉编译器这个委托指向的函数是未托管代码中的函数,并且使用哪种调用约定(Calling Convention)来调用这些函数。

            2. UnmanagedFunctionPointer 特性:

              • UnmanagedFunctionPointer

                :这是一个.NET 特性,用于定义一个委托,该委托指向的函数存在于非托管代码中(例如C/C++编写的DLL)。通过这个特性,可以确保.NET 应用程序能够正确地调用这些非托管函数。

            3. CallingConvention.Cdecl:

              • CallingConvention.Cdecl

                :这是调用约定的一种类型。在这种约定下,函数的调用者负责清理堆栈。这通常用于C语言的函数调用,因此在调用C/C++编写的函数时,使用这种约定是比较常见的。Cdecl约定通常提供更好的性能,因为它让调用者(而不是被调函数)负责清理堆栈,从而避免了额外的堆栈操作。

                  // 事件委托类型    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]    // public delegate void DBL_UserEventCallbackHandleDelegate: 这行代码定义了一个名为DBL_UserEventCallbackHandleDelegate的委托。    public delegate void UserEventCallbackHandleDelegate(int id, Args_t arg, IntPtr userThis);

              05  

              C++ 动态库DLL转为C#

              • DLL导入

                : 通过DllImport属性,你可以在C#中调用a_sdk.dll中的函数。这意味着你的程序可以利用这个DLL中的功能,例如硬件控制、数据采集等。

              • 字符集

                CharSet.Auto允许程序根据运行时环境自动选择字符集,这在处理不同平台上的字符串时非常有用。

              • 调用约定

                CallingConvention.Cdecl确保了函数调用的参数传递和清理方式符合C语言的规范,这对于确保你的C#代码能够正确地与非托管代码交互非常重要。

                // 外部库,记得的放在可执行文件目录下[DllImport("a_sdk.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]// 外部库dll中的函数extern static int ScanDeviceList(ref IntPtr deviceList, ref UInt32 deviceNumber);

                ref如同C++的& 代表引用。IntPtr如同C++的*

                06  

                字节数组转为结构体

                  // 返回类型:object 表示该方法返回一个类型为 object 的对象。由于 object 是所有类型的基类,返回的值可以是任何类型。// Type type:表示目标结构体的类型public static object BytesToStuct(byte[] bytes, int pos, Type type){    //得到结构体的大小    int size = Marshal.SizeOf(type);    //byte数组长度小于结构体的大小    if (size > bytes.Length + pos)    {        //返回空        return null;    }    //分配结构体大小的内存空间    IntPtr structPtr = Marshal.AllocHGlobal(size);    //将byte数组拷到分配好的内存空间    Marshal.Copy(bytes, pos, structPtr, size);    //将内存空间转换为目标结构体    object obj = Marshal.PtrToStructure(structPtr, type);    //释放内存空间    Marshal.FreeHGlobal(structPtr);    //返回结构体    return obj;}

                  其实以目前的AI来看,只要掌握其中一门语言,转化一下就好。

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

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

                  相关文章

                  大语言模型 LLM 通过 Excel 知识库 增强日志分析,根因分析能力的技术方案(2):LangChain + LlamaIndex 实现

                  文章大纲 1 技术原理总览 2 详细实现步骤(含代码) 2.1 环境准备 2.2 Excel → LlamaIndex 节点 2.3 构建向量索引(FAISS 本地) 2.4 Google Cloud 向量检索(可选替换 FAISS) 2.5 LangChain 问答链 A. RAG 模式(向量检索 + LLM 生成) B. SQL 模式(无 RAG,直接查表) 2.…

                  提升ARM Cortex-M系统性能的关键技术:TCM技术解析与实战指南

                  文章目录引言一、TCM基础架构与工作原理1.1 TCM的物理特性1.2 与缓存机制的对比1.3 ARM Cortex-M系列对TCM的支持二、TCM的典型应用场景2.1 实时中断处理2.2 低功耗模式下的待机代码2.3 高性能算法执行2.4 系统初始化阶段的关键代码三、实战指南&#xff1a;在STM32H7上配置和优…

                  大数据之路:阿里巴巴大数据实践——大数据领域建模综述

                  为什么需要数据建模 核心痛点 数据冗余&#xff1a;不同业务重复存储相同数据&#xff08;如用户基础信息&#xff09;&#xff0c;导致存储成本激增。计算资源浪费&#xff1a;未经聚合的明细数据直接参与计算&#xff08;如全表扫描&#xff09;&#xff0c;消耗大量CPU/内存…

                  实战演练1:实战演练之命名实体识别

                  实战演练1:实战演练之命名实体识别 命名实体识别简介 代码 命名实体识别简介 什么是命名实体识别任务 命名实体识别(Named Entity Recognition,简称NER)是指识别文本中具有特定意义的实体,主要包括人名、地名、机构名、专有名词等。通常包括两部分: (1)实体边界识别。(2)确定…

                  数据结构基础内容(第七篇:堆、哈夫曼树)

                  # 堆 Heap 优先队列(Priority Queue) 结构性:用 *数组* 表示的完全二叉树; 有序性:任一结点的关键字是其子树所有结点的最大值(或最小值) * “最大堆(MaxHeap)”,也称“大顶堆”:最大值 * “最小堆(MinHeap)”,也称“小顶堆” :最小值 主要操作有: • MaxHeap Create( i…

                  CS231n-2017 Lecture7训练神经网络(二)笔记

                  本节主要是神经网络的动态部分&#xff0c;也就是神经网络学习参数和搜索最优超参数的过程梯度检查&#xff1a;进行梯度检查&#xff0c;就是简单地把解析梯度与数值计算梯度进行比较&#xff0c;防止反向传播的逻辑出错&#xff0c;仅在调试过程中使用。有如下技巧 &#xff…

                  IntelliJ IDEA 中左上方未显示项目根目录问题

                  问题&#xff1a; 在IDEA中编写代码时&#xff0c;发现左上方只显示项目的子模块&#xff0c;未显示根项目名称。 如图所示&#xff0c;未显示子模块的根项目&#xff1a;问题分析 顶层根目录未被识别为项目根目录&#xff0c;需要手动添加识别。 问题解决 进入File – Project…

                  OpenCV 图像变换全解析:从镜像翻转到仿射变换的实践指南

                  前言处理图像时&#xff0c;翻转、旋转、平移等操作很常用。OpenCV 提供了简单的方法实现这些变换&#xff0c;本文带你快速学会用它做图像翻转和仿射变换。1 图像翻转(图像镜像旋转)在OpenCV中&#xff0c;图片的镜像旋转是以图像的中心为原点进行镜像翻转的。cv2.flip(img,fl…

                  【运维】Linux运维命令记录

                  重置root密码使用命令重新设置一下root账户的密码 passwd root根据提示设置一下密码&#xff0c;然后使用sudo -i 时输入密码就可以切换到root账户了ssh登陆以后&#xff0c;要用sudo -i命令给用户提权&#xff0c;提到超级管理员&#xff0c;然后输入密码才有用

                  PandasAI连接LLM进行智能数据分析

                  1. 引言 Pandas是一个数据分析开源组件库&#xff0c;提供了高性能、易用的数据结构和数据分析工具。它的核心的功能是其DataFrame对象&#xff0c;这是一个带有行和列标签的二维表格数据结构&#xff0c;支持缺失数据处理、时间序列功能、灵活的数据输入输出方法、数据对齐和…

                  Spring之【Bean的生命周期】

                  目录 1、生成BeanDefinition BeanDefinitionRegistry接口 DefaultListableBeanFactory实现类 2、合并BeanDefnition AbstractBeanFactory类 3、BeanFactoryPostProcessor的方法回调 AbstractApplicationContext类 PostProcessorRegistrationDelegate类 4、BeanPostPro…

                  搜狐新闻直播间适配HarmonyOs实现点赞动画

                  01背景介绍随着新闻客户端鸿蒙单框架系统适配工作的推进&#xff0c;从原来的基础功能到现在已经适配全功能的85%以上。与此同时&#xff0c;我们也在持续深入挖掘鸿蒙系统的特性&#xff0c;以提升整体应用的质量与用户体验。在这一过程中&#xff0c;动画作为增强交互与视觉体…

                  83、设置有人DTU设备USR-M100采集传感器数据,然后上传阿里云服务

                  基本思想:设置M100 采集传感器数据 一、首先将DTU设备USR-M100连接路由器上,然后使用python代码搜索同一局域网设备, import platform import sys import os import time import threadinglive_ip = 0def get_os():os = platform.system()if os == "Windows":re…

                  P1019 [NOIP 2000 提高组] 单词接龙

                  题目描述单词接龙是一个与我们经常玩的成语接龙相类似的游戏&#xff0c;现在我们已知一组单词&#xff0c;且给定一个开头的字母&#xff0c;要求出以这个字母开头的最长的“龙”&#xff08;每个单词都最多在“龙”中出现两次&#xff09;&#xff0c;在两个单词相连时&#…

                  详解力扣高频SQL50题之1633. 各赛事的用户注册率【简单】

                  传送门&#xff1a;1633. 各赛事的用户注册率 题目 用户表&#xff1a; Users -------------------- | Column Name | Type | -------------------- | user_id | int | | user_name | varchar | -------------------- user_id 是该表的主键(具有唯一值的列)。 该表中的每行包…

                  FROM stakater/java8-alpine 构建cocker镜像

                  在 Dockerfile 中&#xff0c;FROM stakater/java8-alpine 是第一条也是最核心的指令&#xff0c;它定义了构建新镜像所基于的「基础镜像」。以下是逐层解析&#xff1a;&#x1f50d; 关键字拆解 1. FROM —— 起点指令 ✅ 作用&#xff1a;声明当前镜像的起点&#xff08;父镜…

                  Word2Vec模型训练全流程解析:从数据预处理到实体识别应用

                  请添加图片描述 训练Word2Vec模型 概述 问题 我们如何训练Word2Vec模型&#xff1f;在特定数据集上训练Word2Vec模型何时是有利的&#xff1f; 目标 理解在自有数据上训练Word2Vec模型而非使用预训练模型的优势 Colab环境配置 运行以下代码以启用辅助函数并重新读取数据…

                  在Ubuntu上使用QEMU学习RISC-V程序(2)gdb调试

                  文章目录一、准备工作二、基本调试流程1. 设置断点2. 执行程序3. 查看源代码/汇编三、查看寄存器1. 查看通用寄存器2. 查看特殊寄存器四、查看内存1. 内存查看命令2. 内存修改命令五、调试实战示例六、高级调试技巧1. 条件断点2. 自动显示3. 内存断点&#xff08;观察点&#x…

                  不止于“亮”:一盏智慧路灯的技术进化史——塔能科技用“落地性”定义行业标准

                  在凌晨3点的园区道路之上&#xff0c;路灯会随着车辆的靠近而自动亮起&#xff0c;待车辆逐渐远去之后&#xff0c;又会缓缓地调暗下来&#xff1b;当电缆意外被触碰的时候&#xff0c;系统能够在短短3秒之内自动发出报警信息&#xff0c;并且推送出维修工单&#xff1b;而当一…

                  Redis的String数据类型底层实现

                  redis就是用c语言写&#xff0c;但redis的string并没有直接用c语言的string&#xff0c;而是自己搞了一个 SDS 结构体来表示字符串。SDS 的全称是 Simple Dynamic String&#xff0c;中文叫做“简单动态字符串”。想知道为什么这么做&#xff0c;我们先看看c语言的string是什么…