C# 集成 C++ 的方法和实践 - P/Invoke(平台调用)- 1

环境:


P/Invoke(平台调用):

C#可以通过P/Invoke调用C++编写的DLL中的函数。

1.1 适用范围:

P/Invoke 是一种在 C# 程序中调用非托管代码(如 C++ 动态链接库)的方式。这种方法适用于函数调用相对简单的情况。

1.2 步骤:

  • 在 C++ 中编写算法并编译生成 DLL。
  • 在 C# 项目中使用 DllImport 属性引入 DLL。

 1.3 案例程序:

1.3.1 新建一个ExportedFunctions.cpp【函数调用法】

// MathFunctions.cpp
#include "MathFunctions.h"int Add(int a, int b) {return a + b;
}

特点

  • 使用了extern "C",这告诉编译器按照C语言的方式处理函数名,避免了名称修饰。
  • 使用了__declspec(dllexport),这指示编译器导出该函数,使其在DLL中可见。
  • 这是一个自由函数(不属于任何类),可以直接被P/Invoke调用。

1.3.2 新建一个 ExportedFunctions.h

// MathFunctions.h
#pragma onceextern "C" {__declspec(dllexport) int Add(int a, int b);
}

 1.3.3 在C#中调用动态库的函数:

using System;
using System.Runtime.InteropServices;class Program
{// 使用DllImport属性声明DLL中的函数[DllImport("MathFunctions.dll", CallingConvention = CallingConvention.Cdecl)]public static extern int Add(int a, int b);static void Main(string[] args){// 调用DLL中的Add函数int result = Add(5, 10);Console.WriteLine("The result of adding 5 and 10 is: " + result);}
}

2 VS STUDIO 生成DLL的DllMain模板给出的意义:

2.1 dllmain.cpp文件

包含了DllMain函数的框架。DllMain是DLL的入口点,它是一个特殊的函数,由Windows操作系统在DLL的生命周期中的关键时刻自动调用。这个函数的原型由Windows API定义,其作用是处理DLL的各种加载和卸载事件。

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"BOOL APIENTRY DllMain( HMODULE hModule,DWORD  ul_reason_for_call,LPVOID lpReserved)
{switch (ul_reason_for_call){case DLL_PROCESS_ATTACH:case DLL_THREAD_ATTACH:case DLL_THREAD_DETACH:case DLL_PROCESS_DETACH:break;}return TRUE;
}

DllMain函数的参数如下:

  • HMODULE hModule:被加载DLL的模块句柄。
  • DWORD ul_reason_for_call:调用原因代码,指示为什么调用DllMain
  • LPVOID lpReserved:保留参数,用于特定调用原因的附加信息。

ul_reason_for_call参数可以有以下几种值:

  • DLL_PROCESS_ATTACH:DLL被加载到地址空间中时调用。这是初始化DLL设置的好地方,例如全局变量的初始化。
  • DLL_THREAD_ATTACH:一个新线程被创建到包含DLL的进程中时调用。这允许DLL为每个线程设置特定的数据。
  • DLL_THREAD_DETACH:一个线程结束时调用,不再需要DLL的服务。这可以用来清理线程特定的数据。
  • DLL_PROCESS_DETACH:DLL从进程的地址空间卸载时调用。这是执行清理工作,如释放资源和注销全局变量的好地方。

DllMain函数中,每个case对应一个调用原因。在默认情况下,Visual Studio生成的模板代码中,这些case下没有任何操作,只是简单的break语句。这意味着DLL在加载和卸载时不会执行任何特别的操作。如果你需要在DLL加载或卸载时执行特定的初始化或清理代码,你可以在相应的case下添加你的代码。例如:

switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:// 初始化代码,如分配资源break;
case DLL_THREAD_ATTACH:// 线程特定初始化代码break;
case DLL_THREAD_DETACH:// 线程退出时的清理代码break;
case DLL_PROCESS_DETACH:// 进程退出时的清理代码,如释放资源break;
}

3 在VS 2019中,融合DllMain模板和P/Invoke(平台调用)

 3.1 在C#中进行集成:

将编译好的DLL文件放在你的C#项目可以访问到的位置。

我现在项目目录下,构建了一个lib目录,

然后,在C#中引入dll,

添加,编译好的C++库


问题:

1 尝试引入DLL

解决:

当您使用P/Invoke调用非托管代码(如C++ DLL)时,不需要注册DLL或将其作为COM组件。 

确保dll文件位于C#项目的输出目录中(如bin/Debugbin/Release),或者将DLL文件路径添加到系统PATH环境变量中。

 2 无法找到入口:

Error: 无法在 DLL“AAMED_DLL_DEMO1.dll”中找到名为“Add”的入口点。
 

 笔者的地址在下面:

D:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.20.27508\bin\HostX64\x64 

 执行命令如下:

 .\dumpbin.exe /EXPORTS K:\Prj_MotosCatch\Prj_Src\AAMED_LIB_Demo\AAMED_DLL_DEMO1\x64\Debug\AAMED_DLL_DEMO1.dll

结果:

PS D:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.20.27508\bin\HostX64\x64> .\dumpbin.exe /EXPORTS K:\Prj_MotosCatch\Prj_Src\AAMED_LIB_Demo\AAMED_DLL_DEMO1\x64\Debug\AAMED_DLL_DEMO1.dll
Microsoft (R) COFF/PE Dumper Version 14.20.27525.0
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file K:\Prj_MotosCatch\Prj_Src\AAMED_LIB_Demo\AAMED_DLL_DEMO1\x64\Debug\AAMED_DLL_DEMO1.dll

File Type: DLL

  Summary

        1000 .00cfg
        1000 .data
        2000 .idata
        1000 .msvcjmc
        3000 .pdata
        3000 .rdata
        1000 .reloc
        1000 .rsrc
        9000 .text
       10000 .textbss

 确实没有看到add的函数入口

修正代码,之前想按CLASS来写不行:

然后,重新执行:

PS D:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.20.27508\bin\HostX64\x64> .\dumpbin.exe /EXPORTS K:\Prj_MotosCatch\Prj_Src\AAMED_LIB_Demo\AAMED_DLL_DEMO1\x64\Debug\AAMED_DLL_DEMO1.dll
Microsoft (R) COFF/PE Dumper Version 14.20.27525.0
Copyright (C) Microsoft Corporation.  All rights reserved.Dump of file K:\Prj_MotosCatch\Prj_Src\AAMED_LIB_Demo\AAMED_DLL_DEMO1\x64\Debug\AAMED_DLL_DEMO1.dllFile Type: DLLSection contains the following exports for AAMED_DLL_DEMO1.dll00000000 characteristicsFFFFFFFF time date stamp0.00 version1 ordinal base1 number of functions1 number of namesordinal hint RVA      name1    0 0001133E Add = @ILT+825(Add)Summary1000 .00cfg1000 .data2000 .idata1000 .msvcjmc3000 .pdata3000 .rdata1000 .reloc1000 .rsrc9000 .text10000 .textbss

这时候,已经能看到Add的函数定义了,运行后结果正常,可以运行DLL的函数内容。


本文的案例代码:需要知识付费:

https://download.csdn.net/download/yellow_hill/89396682

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

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

相关文章

国外媒体软文发稿-引时代潮流-助力跨国企业蓬勃发展

大舍传媒:开疆拓土,引领传媒新潮流 随着全球经济的一体化和信息技术的高速发展,跨国企业在国际市场上的竞争越来越激烈。这也给跨国企业带来了巨大的机遇和挑战。在这个时代背景下,大舍传媒凭借其独特的优势和创新的服务模式&…

pdf的压缩该怎么做?快速在线压缩pdf的方法

pdf文件是现在很常用的一种文件格式,有很多的文件内容都可以通过这种格式来展示内容,比如一些通知文件、设计图、个人信息等等,文件的内容越多就会越大,在使用的时候经常会受到一定的限制。那么有什么方法能够快速的将pdf文件变小…

【C++】C++ QT实现Huffman编码器与解码器(源码+课程论文+文件)【独一无二】

👉博__主👈:米码收割机 👉技__能👈:C/Python语言 👉公众号👈:测试开发自动化【获取源码商业合作】 👉荣__誉👈:阿里云博客专家博主、5…

SVNCloud 与 Navicat和IDEA的连接

文章目录 SVNCloud 配置Navicat访问云端数据库与IDEA Java jdbc 的连接 SVNCloud 配置 访问网址:SVN注册账号,进入mysql区域: 数据库管理->创建数据库,输入数据库名称和密码,注意,这里的数据库名称实际…

Facebook企业户 | Facebook公共主页经营

Facebook作为社交媒体巨头,拥有庞大的用户基数,因此,有效经营公共主页是获取持续流量、提升客户信任度和粘性、促进产品或服务销售与转化的关键。要优化Facebook主页,关注以下几点: 1、参与度是关键指标:因…

如何一键拷贝PPT中的所有文字?

有时我们可能需要引用PPT的文字,但一个幻灯片一个幻灯片拷贝很是麻烦,我们想一键拷贝PPT中所有幻灯片中的内容(最近我就遇到了这个需求)。今天就来讲讲这个一键拷贝的技巧。因为大家可能会遇到同样的问题,所以在此记录…

【MySQL】(基础篇五) —— 排序检索数据

排序检索数据 本章将讲授如何使用SELECT语句的ORDER BY子句,根据需要排序检索出的数据。 排序数据 还是使用上一节中的例子,查询employees表中的last_name字段 SELECT last_name FROM employees;输出结果: 发现其输出并没有特定的顺序。其实&#xf…

Django ListView 列表视图类

ListView是Django的通用视图之一,它用于显示一个对象列表。这个视图将所有的对象作为一个上下文变量传递给模板。 1,创建应用 python manage.py startapp app3 2,注册应用 Test/Test/settings.py Test/Test/urls.py 3,添加模型 …

策略模式的理解和运用

在之前的小游戏项目中,处理websocket长连接请求的时候,需要根据传递数据包的不同类型,进行不同的处理。为了实现这个场景,比较简单的方法就是使用if-else或者switch-case语句,根据条件进行判断。但是这导致了项目代码复…

C语言基础——函数

ʕ • ᴥ • ʔ づ♡ど 🎉 欢迎点赞支持🎉 个人主页:励志不掉头发的内向程序员; 专栏主页:C语言基础; 文章目录 前言 一、函数的概念 二、库函数 2.1 库函数和头文件 2.2 库函数的使用/…

【react】react项目支持鼠标拖拽的边框改变元素宽度的组件

目录 安装使用方法示例Props 属性方法示例代码调整兄弟div的宽度 re-resizable github地址 安装 $ npm install --save re-resizable这将安装re-resizable库并将其保存为项目的依赖项。 使用方法 re-resizable 提供了一个 <Resizable> 组件&#xff0c;它可以包裹任何…

Java——方法详细介绍

一、方法调用机制 1、方法调用机制详细介绍 下面对方法调用在内存中的情况进行分析&#xff0c;以下面的代码为例&#xff1a; public class Test {public static void main(String[] args) {Person person new Person();person.name "张三";person.age 18;int…

“双一流名校”苏州大学计算机专业好考吗?苏州大学计算机考研考情分析

苏州大学&#xff08;Soochow University&#xff09;&#xff0c;简称“苏大”&#xff0c;坐落于历史文化名城苏州&#xff0c;国家“211工程”重点建设高校&#xff0c;国家国防科技工业局和江苏省人民政府共建高校&#xff0c;国家“双一流”世界一流学科建设高校&#xff…

【爬虫实战项目一】Python爬取豆瓣电影榜单数据

目录 一、环境准备 二、编写代码 2.1 分页分析 2.2 编码 一、环境准备 安装requests和lxml pip install requests pip install lxml 二、编写代码 2.1 分页分析 编写代码前我们先看看榜单的url 我们假如要爬取五页的数据&#xff0c;那么五个url分别是&#xff1a; htt…

vue3-使用富文本编辑器-wangEditor-文章发表1

最近在搞项目:我们组内几位成员正在搞一个网站搭建,以后更新会比较缓慢 引言:如果要网站要用的富文本编辑器的话,这边推荐用wangEditor 官网地址传送 : wangEditorhttps://www.wangeditor.com/ 我现在还在扩展我的写文章用的富文本编辑器 现在我将简单介绍一下其基本使用方…

基于STM32开发的智能农业监控系统

目录 引言环境准备智能农业监控系统基础代码实现&#xff1a;实现智能农业监控系统 4.1 土壤湿度传感器数据读取4.2 温湿度传感器数据读取4.3 水泵与风扇控制4.4 用户界面与数据可视化应用场景&#xff1a;农业环境监测与管理问题解决方案与优化收尾与总结 1. 引言 随着智能…

Apache ShardingSphere实战与核心源码剖析

Apache ShardingSphere实战与核心源码剖析 1.数据库架构演变与分库分表介绍 1.1 海量数据存储问题及解决方案 如今随着互联网的发展,数据的量级也是成指数的增长,从GB到TB到PB。对数据的各种操作也是愈加的困难,传统的关系性数据库已经无法满足快速查询与插入数据的需求。…

msvcp140_CODECVT_IDS.dll的解决方法是什么?有多少种解决方法

msvcp140_CODECVT_IDS.dll 是一个动态链接库&#xff08;DLL&#xff09;文件&#xff0c;属于微软Visual C 2015运行时库的一部分。这个文件主要负责字符编码转换&#xff0c;支持Unicode与其他字符集之间的转换&#xff0c;如UTF-8与UTF-16。它对于运行时库的多语言支持至关重…

Golang | Leetcode Golang题解之第133题克隆图

题目&#xff1a; 题解&#xff1a; func cloneGraph(node *Node) *Node {if node nil {return node}visited : map[*Node]*Node{}// 将题目给定的节点添加到队列queue : []*Node{node}// 克隆第一个节点并存储到哈希表中visited[node] &Node{node.Val, []*Node{}}// 广…

算法题目学习汇总

1、二叉树前中后序遍历:https://blog.csdn.net/cm15835106905/article/details/124699173 2、输入一棵二叉搜索树&#xff0c;将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点&#xff0c;只能调整树中结点指针的指向。 public class Solution {private Tr…