小记Java调用C++开发的动态链接库(DLL)

一、背景

五一快乐吖!死肥宅正趁着五一这段时间,努力提升自己!

最近使用Java拦截Windows系统中一些默认事件时,发现了一些瓶颈。

我用Java操作浏览器、用Java最小化其他应用窗口,但是我发现这个操作,他都是异步的。

比如,写个程序,获取当前前置窗口,给他缩小。由于它是异步的,只是给操作系统发个通知你要缩小,但是否执行完,开发者不知道。实际上由于循环过快,就成了死循环一直获取到的是当前窗口,然后一直缩小当前窗口。最后把电脑卡死了。所以用Java写系统级的功能,并不好使。

经过我在C++/C#/Java/Go中的语言选型,以下排序分先后

开发语言适用平台适用场景备注
C++跨平台底层应用、上层应用-
C#Windows底层应用、上层应用也支持跨平台,但不如直接C++
Java跨平台上层应用借助其他语言,如C/C++、C#可调用操作系统底层API
Go跨平台上层应用借助其他语言,如C/C++、C#可调用操作系统底层API。不过说替代C++,完全是扯淡,如果真要说作用,那就是为了分Java一杯羹。

二、动态链接库

2.1 概念

动态链接库(Dynamic Link Library,简称DLL)是一种Windows操作系统下常见的可执行文件格式,它包含了一些可被其他应用程序调用的函数和数据,可以用来实现模块化开发和共享代码等功能。

与静态链接库(Static Link Library,简称LIB)不同,DLL在程序运行时才会被加载和链接,而不是在编译时。这样做的好处是可以减小可执行文件的体积,并且可以在程序运行时动态加载和卸载DLL,从而实现模块化开发和动态扩展等功能。

DLL可以包含多个函数和数据,这些函数和数据都有一个独立的入口地址,可以被其他应用程序通过调用入口地址来使用。应用程序可以通过Windows API提供的一系列函数(如LoadLibrary、GetProcAddress等)来动态加载和链接DLL中的函数和数据,并在不需要时将其卸载。

使用DLL可以带来许多好处,比如:

  1. 代码复用:多个应用程序可以共享同一个DLL,从而避免重复编写相同的代码。
  2. 模块化开发:可以将大型应用程序拆分成多个DLL,每个DLL只包含一部分功能,从而降低代码复杂度,方便维护和升级。
  3. 动态加载和卸载:可以在程序运行时动态加载和卸载DLL,从而实现动态扩展和插件化开发等功能。

但是,DLL也存在一些缺点,比如:

  1. 版本兼容性问题:如果DLL的版本发生变化,调用该DLL的应用程序也需要相应地修改,否则可能会出现不兼容的问题。
  2. 安全性问题:DLL可以被其他应用程序调用,如果DLL中的代码存在漏洞或安全问题,可能会被黑客利用,造成安全风险。
  3. 性能问题:由于DLL需要动态加载和链接,所以在程序运行时可能会带来一些性能开销。

因此,在使用DLL时需要注意版本兼容性、安全性和性能等问题,合理地使用DLL可以提高代码复用和程序可维护性,提升开发效率和程序性能。

2.2 环境配置

开发IDE:Visual Studio 2022

该页面如果已安装,可以在 新建 - 安装多个工具和功能 选项中查找到

2.3 C++开发动态链接库

2.3.1 创建项目

2.3.2 编写代码

编写代码TestDLL.cpp

// TestDLL.cpp : 定义 DLL 的导出函数。
//

#include "pch.h"
#include "framework.h"
#include "TestDLL.h"
#include <iostream>
#include <thread>
#include <chrono>
#include <string>
using namespace std;


// 这是导出变量的一个示例
TESTDLL_API int nTestDLL=0;

// 这是导出函数的一个示例。
TESTDLL_API int fnTestDLL(void)
{
    return 0;
}

TESTDLL_API int add(int a, int b) {
    int value = a + b;
   //c++打印
    cout << "C++打印: TestDLL add: " << value << endl;
    //c打印
    printf("C打印: TestDLL add: %d", value);
    // 线程休眠5秒
    std::this_thread::sleep_for(std::chrono::seconds(5));
    return value;
}


TESTDLL_API void openBrowser(char* str) {
    std::string cmd = "start " + std::string(str);
    system(cmd.c_str());
}

// 这是已导出类的构造函数。
CTestDLL::CTestDLL()
{
    return;
}

编写代码TestDLL.h头文件

// 下列 ifdef 块是创建使从 DLL 导出更简单的
// 宏的标准方法。此 DLL 中的所有文件都是用命令行上定义的 TESTDLL_EXPORTS
// 符号编译的。在使用此 DLL 的
// 任何项目上不应定义此符号。这样,源文件中包含此文件的任何其他项目都会将
// TESTDLL_API 函数视为是从 DLL 导入的,而此 DLL 则将用此宏定义的
// 符号视为是被导出的。
#ifdef TESTDLL_EXPORTS
#define TESTDLL_API __declspec(dllexport)
#else
#define TESTDLL_API __declspec(dllimport)
#endif

// 此类是从 dll 导出的
class TESTDLL_API CTestDLL {
public:
	CTestDLL(void);
	// TODO: 在此处添加方法。
};

extern TESTDLL_API int nTestDLL;

TESTDLL_API int fnTestDLL(void);


// 声明
/*
当C++代码包含C函数或C库的头文件时,由于C++和C语言在函数名称的处理方式上有所不同,C++编译器会将这些C函数或库中的函数名称按照C++的方式进行重整,这会导致函数名称被修改并在链接时找不到函数。
通过在C++代码中使用extern "C"说明符来修饰C函数,可以告诉C++编译器对函数名进行C语言风格的链接,从而避免函数名被重整导致链接错误。

*/
extern "C" TESTDLL_API int add(int a, int b);
extern "C" TESTDLL_API void openBrowser(char* str);

2.3.3 注意事项

参考学习JNA的一天-自定义DLL以及被Java调用 - 简书

由此代码就写完了。注意几点事项

  1. 项目编码设置为UTF-8,不是UTF-8 BOM
  2. 编译系统相应版本。

1.) 设置编码

2.) 编译系统相应版本

生成-配置管理器

2.3.4 编译

三、Java调用动态链接库

3.1 JNA与JNI

JNA是基于JNI技术,实现的一个Java库!

JNI(Java Native Interface)是Java提供的一种与本地代码交互的技术。通过JNI,Java程序可以调用本地编写的C/C++等语言编写的代码,也可以让本地代码调用Java程序中的对象和方法。

JNA(Java Native Access)是一个Java库,它允许Java应用程序直接访问本地库(如动态链接库,DLL)中的功能,而无需编写任何本地代码。JNA通过Java反射和动态代理技术,将Java数据类型和本地C数据类型进行映射,实现Java和本地代码之间的互操作。

JNA(Java Native Access)和JNI(Java Native Interface)都是Java与本地代码交互的技术,但它们有一些区别。

  • 难易程度

    • JNI的使用相对较为复杂,需要编写较多的底层代码,如头文件、Java虚拟机调用等,需要掌握C/C++语言。
    • JNA的使用相对简单,只需要定义接口、使用注解、调用动态库函数即可,无需编写底层代码。
  • 性能

    • JNI在性能方面较为优秀,因为它直接操作本地内存,调用本地代码时速度较快。
    • JNA在性能方面相对较差,因为它使用Java对象来表示本地内存,需要进行频繁的对象转换和内存拷贝。
  • 平台兼容性

    • JNI需要编写本地代码,因此需要针对不同的操作系统和平台进行不同的实现。
    • JNA则是基于Java虚拟机实现的,因此可以很好地跨平台运行,无需考虑本地代码的兼容性问题。
  • 使用场景

    • JNI主要用于需要对本地代码进行直接控制的场景,如操作系统级别的编程、性能敏感的算法等。
    • JNA则主要用于简化Java与本地库交互的过程,如调用本地的API函数等。

总的来说,JNA相比JNI使用起来更加简单、方便,并且具有良好的跨平台性,但在性能方面稍逊于JNI,因此需要根据具体的需求选择合适的技术。

3.2 JNI使用

使用步骤分为三步

  1. 定义Java方法
  2. 编写底层(C/C++)方法
  3. 编译和链接:将本地代码编译为动态链接库或静态库,并将其链接到Java程序中。在Java程序中调用native方法时,动态链接库将被加载并执行本地代码。

一般JNI的方法,都会带有native关键字,如下。

public native void hello();

实际手撕JNI,使用起来较为复杂,所以一般采用JNA库来实现功能

3.3 JNA使用

3.3.1 示例代码

添加maven依赖

<dependency>
    <groupId>net.java.dev.jna</groupId>
    <artifactId>jna</artifactId>
    <version>5.12.1</version>
</dependency>
<dependency>
    <groupId>net.java.dev.jna</groupId>
    <artifactId>jna-platform</artifactId>
    <version>5.12.1</version>
</dependency>

以下是JNA的使用示例

public interface TestDLL extends Library {
    //加载dll,实例成对象。下面的方法,均为dll提供的方法
    TestDLL instance = Native.load("C:\\Users\\meethigher\\Desktop\\DLL\\TestDLL\\x64\\Debug\\TestDLL.dll",TestDLL.class);

    int add(int a,int b);

    void openBrowser(String str);
}

进行测试

@Slf4j
public class Main {
    public static void main(String[] args) {
        log.info("start");
        int add = TestDLL.instance.add(1, 2);
        log.info("end");
        System.out.println(add);
        for (int i = 0; i < 10; i++) {
            TestDLL.instance.openBrowser(String.format("https://meethigher.top/%s", i));
        }
    }
}

3.3.1 数据类型对应关系

表格如下

Java数据类型C/C++数据类型
booleanbool
bytechar
shortshort
intint
longlong long
floatfloat
doubledouble
charchar
Stringconst char*
byte[]char*
short[]short*
int[]int*
long[]long long*
float[]float*
double[]double*
char[]char*
char
Stringconst char*
byte[]char*
short[]short*
int[]int*
long[]long long*
float[]float*
double[]double*
char[]char*

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

几十个简要的游戏案例分析

文章目录 一、 介绍二、 影响游戏体验的因素三、 游戏能爆火的因素1.影响游戏爆火因素的排名2.玩游戏的两种经典心理3.经典案例分析Qq农场植物大战僵尸水果忍者召唤神龙羊了个羊 4.游戏公司可借鉴的经验 四、 几十款游戏的多方面分析FC红白游戏机十二人街霸热血高校系列魂斗罗系…

趣说数据结构(练习1) —— 顺序表/链表力扣刷题

练习 1 —— 顺序表/链表力扣刷题 1. 合并两个有序链表 力扣题目地址&#xff1a;https://leetcode.cn/problems/merge-two-sorted-lists/ 问题描述&#xff1a;将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例&#x…

Java——Java面向对象

该系列博文会告诉你如何从入门到进阶&#xff0c;一步步地学习Java基础知识&#xff0c;并上手进行实战&#xff0c;接着了解每个Java知识点背后的实现原理&#xff0c;更完整地了解整个Java技术体系&#xff0c;形成自己的知识框架。 概述&#xff1a; Java是面向对象的程序…

@Autowired与@Resource原理知识点详解

文章目录 前言springIOC依赖注入的三种方式属性注入&#xff08;字段注入&#xff09;构造方法注入setter注入用哪个&#xff1f; Autowired实现原理 Resource实现原理结论 Autowired与Resource的不同来源不同参数不同使用不同装配顺序 前言 现在spring可以说是一统天下了&…

【Unity-UGUI控件全面解析】| Canvas 画布组件详解

🎬【Unity-UGUI控件全面解析】| Canvas 画布组件详解一、组件介绍1.1 绘制元素的顺序二、组件属性面板2.1 Canvas :画布,控制UI的渲染模式2.2 Canvas Scaler:画布缩放器,控制UI画布的放大缩放的比例2.3 Graphic Raycaster:图形射线投射器,控制是否让UI响应射线点击三、…

【干货分享】一文说透分布式一致性协议(上)

本文首发自「慕课网」&#xff0c;想了解更多IT干货内容&#xff0c;程序员圈内热闻&#xff0c;欢迎关注"慕课网"&#xff01; 作者&#xff1a;大熊老师 | 慕课网讲师 在常见的分布式系统中&#xff0c;总会发生诸如机器宕机或网络异常&#xff08;包括消息的延迟…

数据备份系列:Rsync 备份详解(一)

一、Rsync 简介 1.1 Rsync 是一个远程增量文件备份软件工具 1.2 Rsync 的特性 支持拷贝特殊文件&#xff0c;如连接文件、设备等。可以有排除指定文件或目录同步的功能&#xff0c;相当于打包命令 tar 的排除功能。可以做到保持原文件或目录的权限、时间、软硬链接、属主、组…

Python每日一练(20230502)

目录 1. 被围绕的区域 &#x1f31f;&#x1f31f; 2. 两数之和 II &#x1f31f; 3. 二叉树展开为链表 &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 Java每日一练 专栏 1…

react native ios 添加启动页 xcode14 react-native-splash-screen

最近更新xcode&#xff0c;有些配置有些不同&#xff0c;网上查的方法都是过时的&#xff0c;导致配了一段时间卡在这里&#xff0c;最后访问官网才弄好了&#xff0c;所以以后解决问题的办法先看官网再查其他各路神仙的办法。 官网的步骤&#xff1a;https://github.com/crazy…

颜色空间转换RGB-YCbCr

颜色空间 颜色空间&#xff08;Color Space&#xff09;是描述颜色的一种方式&#xff0c;它是一个由数学模型表示的三维空间&#xff0c;通常用于将数字表示的颜色转换成可见的颜色。颜色空间的不同取决于所选的坐标轴和原点&#xff0c;以及用于表示颜色的色彩模型。在计算机…

【C++入门】一篇搞懂auto关键字

个人主页&#xff1a;平行线也会相交 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 平行线也会相交 原创 收录于专栏【C之路】 目录 作用不那么大的场景auto真正的价值auto和指针结合使用注意点auto不能推导的场景范围for范围for的使用条件 作用不那么大的…

海尔牵头IEEE P2786国际标准通过Sponsor投票并连任工作组主席

01 海尔牵头IEEE P2786国际标准 通过Sponsor投票 并连任工作组主席 海尔牵头制定的全球首个服装物联网国际标准IEEE P2786《Standard for General Requirements and Interoperability for Internet of Clothing》通过Sponsor投票&#xff0c;标志着该国际标准草案得到了行业…

2.6 浮点运算方法和浮点运算器

学习目标&#xff1a; 以下是一些具体的学习目标&#xff1a; 理解浮点数的基本概念和表示方法&#xff0c;包括符号位、指数和尾数。学习浮点数的运算规则和舍入规则&#xff0c;包括加、减、乘、除、开方等。了解浮点数的常见问题和误差&#xff0c;例如舍入误差、溢出、下…

FPGA实现10G万兆网UDP通信 10G Ethernet Subsystem替代网络PHY芯片 提供工程源码和技术支持

目录 1、前言2、我这里已有的UDP方案3、详细设计方案传统 FPGA UDP 方案本 FPGA 10G UDP 方案(牛逼)10G Ethernet 框图10G Ethernet 发送解析10G Ethernet 接收解析10G Ethernet 寄存器配置10G Ethernet UI 配置 4、vivado工程详解5、上板调试验证并演示ping功能测试数据收发测…

一款支持全文检索、工作流审批、知识图谱的企事业知识库

一、项目介绍 一款全源码&#xff0c;可二开&#xff0c;可基于云部署、私有部署的企业级知识库云平台&#xff0c;一款让企业知识变为实打实的数字财富的系统&#xff0c;应用在需要进行文档整理、分类、归集、检索、分析的场景。 获取方式q:262086839 为什么建立知识库平台&…

perf record对C++程序耗时进行分析

本节将介绍如何使用perf工具的perf record对C代码进行性能分析&#xff0c;一切操作都是在ubuntu 20下进行。 perf工具安装 由于perf工具和内核版本有关&#xff0c;因此直接安装容易出错&#xff0c;建议直接通过如下指令安装&#xff1a; sudo apt-get install linux-tool…

00后卷王的自述,我难道真的很卷?

前言 前段时间去面试了一个公司&#xff0c;成功拿到了offer&#xff0c;薪资也从12k涨到了18k&#xff0c;对于工作都还没两年的我来说&#xff0c;还是比较满意的&#xff0c;毕竟一些工作3、4年的可能还没我高。 我可能就是大家说的卷王&#xff0c;感觉自己年轻&#xff…

独立IP服务器和共享IP服务器有什么区别

在选择一个合适的服务器时&#xff0c;最常见的选择是共享IP服务器和独立IP服务器。尽管两者看起来很相似&#xff0c;但它们有着很大的不同。本文将详细介绍共享IP服务器和独立IP服务器的不同之处&#xff0c;以及如何选择适合您需求的服务器。 一、什么是共享IP服务器? 共享…

Python探索性P图,四种增强方式快速玩转pillow库

嗨害大家好鸭&#xff01;我是爱摸鱼的芝士❤ 我们平时使用一些图像处理软件时&#xff0c; 经常会看到其对图像的亮度、对比度、色度或者锐度进行调整。 你是不是觉得这种技术的底层实现很高大上&#xff1f; 其实最基础的实现原理&#xff0c; 用 Python 实现只需要几行…

Java JDK下载安装环境变量配置

目录 一、下载安装 1.简介 2.JDK下载JDK 官网海外历史地址&#xff1a; 3.安装 二、环境变量配置 1.新建JAVA_HOME变量 2.PATH变量 3.CLASSPATH 变量 4.测试是否安装成功 一、下载安装 1.简介 JDK 是SUN公司提供的一套Java 语言的软件开发工具包&#xff0c;简称JDK(JavaDevelo…