加上了自己的理解,和下面两位大神的作品,我也不知道自己是原创还是转载。仅是将自己的新的写出来,大家一起学习
鼓捣了一天半了,终于算是整明白了。
下面一一介绍流程,虽然网上已经有了好多教程,但是我这一版是针对在java环境下运行C++/C文件时,需要生成dll库时具体的操作。
里面所有的代码全部换成了我的代码
首先是这位大神的讲解
http://blog.sina.com.cn/s/blog_4a806bd9010007hn.html
JAVA以其跨平台的特性深受人们喜爱,而又正由于它的跨平台的目的,使得它和本地机器的各种内部联系变得很少,约束了它的功能。解决JAVA对本地操作的一种方法就是JNI。
JAVA通过JNI调用本地方法,而本地方法是以库文件的形式存放的(在WINDOWS平台上是DLL文件形式,在UNIX机器上是SO文件形式)。通过调用本地的库文件的内部方法,使JAVA可以实现和本地机器的紧密联系,调用系统级的各接口方法。
简单介绍及应用如下:
一、JAVA中所需要做的工作
在JAVA程序中,首先需要在类中声明所调用的库名称,如下:
static {
System.loadLibrary(“Test”);
}
在这里,库的扩展名字可以不用写出来,究竟是DLL还是SO,由系统自己判断。
还需要对将要调用的方法做本地声明,关键字为native。并且只需要声明,而不需要具体实现。如下:
public native static void set(int i);
public native static int get();
然后编译该JAVA程序文件,生成CLASS,再用JAVAH命令,JNI就会生成C/C++的头文件。
例如程序test.java,内容为:
public class test
{
static
{
System.loadLibrary("Test");
}
public native static int get();
public native static void set(int i);
public static void main(String[]args)
{
test.set(10);
System.out.println(test.get());
}
}
用javac test.java编译它,会生成test.class。再用javah test,则会在当前目录下生成testdll.h文件,这个文件需要被C/C++程序调用来生成所需的库文件。
由于是Android下的工程,因此.class文件已经自己自动生成了。如果是java文件需要到相应的路径下编译生成.class文件。
进入该路径D:\androidprogram\Testdll\bin\classes,javah com.example.testdll.**,想编译哪个就写哪个类的名字,蓝色下划线的是包名,不要和路径名混淆。
生成的头文件在D:\androidprogram\Testdll\bin\classes此路径下,
名为:com_example_testdll_test.h
二、C/C++中所需要做的工作
对于已生成的.h头文件,C/C++所需要做的,就是把它的各个方法具体的实现。然后编译连接成库文件即可。再把库文件拷贝到JAVA程序的路径下面,就可以用JAVA调用C/C++所实现的功能了。
接上例子。我们先看一下com_example_testdll_test.h文件的内容:
/* DO NOT EDIT THIS FILE - it is machine generated*/
#include <jni.h>
/* Header for classcom_example_testdll_test */
#ifndef _Included_com_example_testdll_test
#define _Included_com_example_testdll_test
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_example_testdll_test
* Method: set
* Signature: (I)V
*/
JNIEXPORT void JNICALLJava_com_example_testdll_test_set
(JNIEnv *, jclass, jint);
/*
* Class: com_example_testdll_test
* Method: get
* Signature: ()I
*/
JNIEXPORT jint JNICALLJava_com_example_testdll_test_get
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
在具体实现的时候,我们只关心两个函数原型
JNIEXPORT jint JNICALL Java_com_example_testdll_test_get(JNIEnv *, jclass);
和JNIEXPORT void JNICALL Java_com_example_testdll_test_set(JNIEnv*, jclass, jint);
这里JNIEXPORT和JNICALL都是JNI的关键字,表示此函数是要被JNI调用的。而jint是以JNI为中介使JAVA的int类型与本地的int沟通的一种类型,我们可以视而不见,就当做int使用。函数的名称是JAVA_再加上java程序的package路径再加函数名组成的。参数中,我们也只需要关心在JAVA程序中存在的参数,至于JNIEnv*和jclass我们一般没有必要去碰它。
好,下面我们用Test.cpp文件具体实现这两个函数:
#include"com_example_testdll_test.h"
int i = 0;
int j;
JNIEXPORT jint JNICALLJava_com_example_testdll_test_get (JNIEnv *, jclass)
{
return i;
}
JNIEXPORT void JNICALLJava_com_example_testdll_test_set (JNIEnv *, jclass, jint)
{
i =j;
}
编译连接成库文件,本例是在WINDOWS下做的,生成的是DLL文件。并且名称要与JAVA中需要调用的一致,这里就是Test.dll
把Test.dll拷贝到testdll.class的目录下,java testdll运行它,就可以观察到结果了。
下面是针对红色画线的部分进行具体的讲解,来自于这个大神,但是该大神的还有与我的不同的地方,因此做了具体的修改,仅供大家参考
http://wenda.haosou.com/q/1374540952062422
用 vc 6.0 下的cl.exe 和 link.exe工具,请读下文:
声明:下面这篇文章不是我写的,源自:一个叫,有容乃大 的博客
如何手工编写动态链接库(windows dll)
1.本例介绍在命令行(Console)环境下制作dll的方法
2.读者动手前,请确保在windows中安装有编译、链接工具和必要的函数库文件。
3.本例使用C语言实现.
4.本例中使用路径均为我机器上的绝对路径,读者需根据实际情况调整。
工具要求:
Microsoft的编译器cl.exe
MIcrosoft链接器link.exe
dll制作步骤:
1.编写dll函数实现源代码Test.cpp(该cpp在上个大神的文章里已经写完了)
2.编写dll函数输出定义文件Test.def.
LIBRARY Test
EXPORTS
Java_com_example_testdll_test_get @1
Java_com_example_testdll_test_set @2
3.编译dll源码,生成dll,lib文件.
3.1 新建命令行窗口
3.2 设置PATH ¦ INCLUDE ¦ LIB 3个环境变量.
SET Path= D:\VS2010setup\VC\bin;%Path%
SET INCLUDE= D:\VS2010setup\VC\include;%INCLUDE%
SET LIB= D:\VS2010setup\VC\lib;%LIB%
//这里是为了防止出现cannot find kernel32.lib的错误
在系统的环境变量中:要新建一个名称为LIB和INCLUDE的环境变量,以对应上文中的由紫色标记处的部分。
(LIB)C:/Program Files/Microsoft SDKs/Windows/v6.0A/Lib;//不用更改
C:/ProgramFiles/Microsoft SDKs/Windows/v5.0/Lib;//不用更改
D:\VS2010setup\VC\lib//自己电脑上VC的lib库路径
3.3 编译Test.cpp
cd D:\androidprogram\Testdll\jni (hello.c和hello.def所在目录)
cl /c Test.cpp
这里会出现不能找到jni.h文件,解决办法是
将一下路径中的文件
\jdk\include\jni.h
\jdk\include\win32\jawt_md.h
\jdk\include\win32\jni_md.h
复制到Visual Studio的安装目录下的\VC\include目录中
3.4 链接Test.obj,生成Test.dll, Test.lib两个文件.
link /def:Test.def /dll Test.obj
这里就会出现两个错误,
1 找不到kernel32.dll文件,解决办法已经给出
2 extra operand “Test.obj”我出现这个错误的原因主要是在于点击这里没有弄好
至此,我的库文件就弄好了。
4.测试dll函数.
4.1 编写测试代码 test.c
extern int say_hello(char* name);
int main(int argc,char** argv)
{
say_hello( "robbie ");
return 0;
}
4.2 编译测试代码test.c
cl /c test.c
4.3 链接test.obj和 hello.lib,生成可执行文件test.exe
link test.obj hello.lib
4.4 运行test.exe,屏幕输出:
hello robbie
至此,一个dll构造完毕.
下面是我自己的一点补充:
如果要在c++下,或者win32 mfc下使用标准c写的dll,必须把上面的声明
extern int say_hello(char* name);改成:extern "C " int say_hello(char* name);