这两天被JNI折腾疯了,而其中困扰我时间最长的问题竟然都是环境问题。。总结一下JNI调用原始dll(不是包含java生成的头文件之后再生成的dll)的过程。
JNI能调用的是符合规范的dll程序,需要根据javah得到的头文件生成。因此当需要调用一个原始dll时,需要我们自己再写一个符合jni规范的dll,来调用原始dll。也就是一个中间层。
1、java生成头文件
用eclipse写完以下代码:
package com.aaa.netcard;
public class Netcard {
public native void displayHelloWorld();
public native int displayPlus(int a, int b);
public native int displayCalculator(int a, int b);
static {
System.loadLibrary("calculator");
}
public static void main(String[] args){
Netcard card = new Netcard();
System.out.println(card.displayCalculator(5, 99));
}
}
写完以后保存,eclipse就会在bin文件夹下自动生成class文件。在bin目录下打开cmd,输入javah -jni com.aaa.netcard.Netcard。回车,生成成功。注意要写包名。
生成了com_aaa_netcard_Netcard.h。此文件第三步用到。
2、原始dll。
自己写了一个简单的加减乘的origin.dll。
// origin.cpp : 定义 DLL 应用程序的导出函数。
//
#include "stdafx.h"
#include "origin.h"
extern "C"_declspec(dllexport) int plus(int a, int b) {
return a+b;
}
extern "C"_declspec(dllexport) int minus(int a, int b) {
return a-b;
}
extern "C"_declspec(dllexport) int times(int a, int b) {
return a*b;
}
注意关键词extern "C" _declspec(dllexport)。_declspec(dllexport)表示要输出的函数/类,extern"C"指明用C的编译方式。(详见上一篇博文)
3、完成jni调用的dll,对原始dll进行包装。
原始dll是不能直接调用的。需要调用的话需要再写一个dll将原始dll载入。
先打开第一步生成的com_aaa_netcard_Netcard.h看一下。
#ifndef _Included_com_aaa_netcard_Netcard
#define _Included_com_aaa_netcard_Netcard
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_aaa_netcard_Netcard
* Method: displayCalculator
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_com_aaa_netcard_Netcard_displayCalculator
(JNIEnv *, jobject, jint, jint);
#ifdef __cplusplus
}
#endif
#endif
新建一个dll项目calculator,将origin.dll放在calculator/debug目录下,放在这里不用在loadLibrary时写origin.dll的绝对路径。接下来我们就在此dll工程的calculator.cpp中实现java生成的头文件中的方法。将com_aaa_netcard_Netcard.h拷贝到工程目录下并include进来。注意函数名参数等等写法要一致。可以看到从java到c++数据类型经过了转换,int变成了jint。
JNIEXPORT jint JNICALL Java_com_aaa_netcard_Netcard_displayCalculator
(JNIEnv *, jobject, jint, jint);
// calculator.cpp : 定义 DLL 应用程序的导出函数。
//
#include "stdafx.h"
#include <iostream>
#include <Windows.h>
#include <jni.h>
#include "calculator.h"
#include "com_aaa_netcard_Netcard.h"
using namespace std;
typedef int(*Dllfun)(int, int);
JNIEXPORT jint JNICALL Java_com_aaa_netcard_Netcard_displayCalculator
(JNIEnv *, jobject, jint a, jint b)
{
Dllfun original;
HINSTANCE hdll;
hdll=LoadLibrary(TEXT("origin.dll"));
if(hdll==NULL){
FreeLibrary(hdll);
}
original=(Dllfun)GetProcAddress(hdll,"plus");
if(original==NULL){
FreeLibrary(hdll);
}
try{
return original(a,b);
} catch (const char * str){
cout<<"fail"<<endl;
return 1111;
}
}
生成了calculator.dll。将此dll粘贴到java项目根目录下。编译运行,控制台输出了调用原始dl得到l的计算结果。成功。
分享到:
相关推荐
Java通过JNI调用DLL动态库,亲测试编写
完整的实现java跨平台调用C程序源码,包含JAVA源码和C源码以及编译后的demo dll。将dll放到jdk bin目录下,java 项目可以直接运行。若要修改dll可以,修改C源码后重新编译生成dll。该demo处理了多线程调用c,全局...
本资源包括JAVA工程,C++工程,C#dll测试工程
Java通过JNI调用C++接口,Demo文档描述(里面有代码),里面有Windows下调用版和linux下调用版,经本人亲自测试,可用。
在JAVA中如何通过JNI调用VC动态库,以及在如何在VC中调试
这两天要弄个JAVA调用DLL,研究了一下有点绕, java部分要生成.h头文件,所以弄了个例子在这分享下 JAVA调用DLL完整步骤 步骤里包括java部分代码及vc写的DLL代码
jni调用c++ delphi中的dll.
请C++同事帮忙写个dll程序,dll去解析开发平台输出的二进制流数据,上层应用平台调用dll得到json报文,然后再去做一些业务处理。 那现在上层应用面临的问题:访问java外部功能接口实现方式(即调用dll)怎么选择及...
里面是一个java使用JNI调用的实例,包含所有情况如结构体、指针等等
springboot+jna/jni调用动态so/dll库
研究了很久,终于初步搞定了jni问题,写了一个最简单的jni调用第三方的实例,dll建立的时候全部使用的空项目,为避免其他的干扰,参数传递也选最简单的int型,以便于大家初步了解jni
我们知道,使用 JNI 调用 .dll/.so 共享类库是非常非常麻烦和痛苦的。 假如有一个现有的 .dll/.so 文件,假如使用 JNI 技术调用,我们首先需要另外使用 C 语言写一个 .dll/.so 共享库,使用 SUN 规定的数据结构替换 ...
[JAVA]使用JNI技术实现JAVA程序调用dll、[JAVA]使用JNI技术实现JAVA程序调用dll
java通过jni调用dll动态链接库及创建dll动态链接库demo。
Android使用JNI调用Python so解释器
完整的展示了Java调用C++ API/dll示例程序. 说明如下: 1. mrSocketAPICInt是准备被java调用的API 2. mrSocketAPIJavaInt是java调用C++ api的中间层 3. mrSocketAPIJavaIntDemo是java程序,展示与C++ api如何对接。...
JAVA如何调用dll:用JNI调用C或C++动态联接库原来如此简单
教你如何生成.h文件,使用window通过NDK编译出.so文件,如何通过JNI调用so文件
该实例是我自己写的jni调用第三方dll例子,可以作为参考,运行环境vs2010,其他环境没试过。
以MessageBox为引子介绍java通过JNI调用dll的事例 附介绍说明,十分实用