对于C++编程人员, 他们一般会在C++工程中进行相关功能的封装, 形成一个独立的库文件, 这时可以将这个库文件提供给其他人员使用; 对于Java编程人员来说, Java 也是可以调用C++的DLL库的, 其操作方式也是类似, 以下描述Java中如何使用C++库(注: 这里假设库的编写人员也是自己, 库的名字为libhh.dll):
1. 操作步骤
a. 创建Java调用C++库的程序文件, 这里假设为: com.gg.utils.DmoHello.java, 其内容为:
package com.gg.utils;
public class DmoHello {
public native int say_hello(String user);
}
b. 编译Java工程, 生成class文件: com.gg.utils.DmoHello.class
c. 进入目录target/classes下, 打开cmd窗口或者powershell, 输入以下命令:
javah com.gg.utils.DmoHello
d. 生成了一个名为: com_gg_utils_DmoHello.h头文件在当前目录, 打开可以看到其部分内容为:
JNIEXPORT jint JNICALL Java_com_gg_utils_DmoHello
(JNIEnv *, jobject, jstring);
e. 将这个头文件拷贝到C++工程中, 并且新建一个名为com_gg_utils_DmoHello.cpp的文件, 其内容为实现d中接口的代码
略
f. 重新编译整个库文件, 生成库libhh.dll
g. 新增com.gg.utils.DmoHello.java以下内容:
public class DmoHello {
// load dll library
static {
System.loadLibrary("kernel32");
System.loadLibrary("libeay32");
System.loadLibrary("libhh");
}
public native int say_hello(String user);
// debug function
public static void main(String args[]) {
DmoHello hello = new DmoHello();
int iRet = hello.say_hello("Tom");
System.out.println("iRet: " + iRet);
}
h. 编译Java工程, 我们可以在这里直接进行debug操作;
2. 可能出现的问题
a. javah时可能出现异常错误
Exception in thread "main" java.lang.IllegalArgumentException: Not a valid class name: .\com\gg\utils\DmoHello
at com.sun.tools.javac.api.JavacTool.getTask(JavacTool.java:129)
at com.sun.tools.javac.api.JavacTool.getTask(JavacTool.java:107)
at com.sun.tools.javac.api.JavacTool.getTask(JavacTool.java:64)
at com.sun.tools.javah.JavahTask.run(JavahTask.java:503)
at com.sun.tools.javah.JavahTask.run(JavahTask.java:329)
at com.sun.tools.javah.Main.main(Main.java:46)
cmd或者powershell不在合适的位置上打开, 这里是在target/classes下打开并运行该命令的;
b. 运行时出现以下错误
Exception in thread "main" java.lang.UnsatisfiedLinkError: no libeay32 in java.library.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1860)
at java.lang.Runtime.loadLibrary0(Runtime.java:871)
at java.lang.System.loadLibrary(System.java:1122)
at com.gg.utils.crypto.DmoCrypto.<clinit>(DmoCrypto.java:9)
此时是因为Java加载DLL库时找不到对应的库文件, 因此这里统一新建一个DLL库目录: d:\Lib, 将C++生成的动态链接库及相关的依赖库放入此目录中; 然后在运行时配置java参数如下:
-Djava.library.path=D:\Lib
c. 运行时出现
Exception in thread "main" java.lang.UnsatisfiedLinkError: .... Can't find dependent libraries
at java.lang.ClassLoader$NativeLibrary.load(Native Method)
at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1934)
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1850)
at java.lang.Runtime.loadLibrary0(Runtime.java:871)
at java.lang.System.loadLibrary(System.java:1122)
这是没有将动态链接库及依赖的动态链接库加载进来的原因. 注意: 依赖的动态链接库也有加载进来, 并且注意依赖顺序!例如, 上面我依赖了kernel32.dll及libeay32.dll.
d. 切记不要随意在一个目录下创建Java文件, 然后生成对应的“.h”头文件, 然后再将它引入到自己的实际工程中, 它将会出现运行出错信息, 不好排查.
3. C++动态链接库是其他人(第三方人员)编写的, 怎么办?
这时可以自己对第三方人员编写的库进行封装, 形成一个代理库, 再结合上面的步骤, 将该库引入到Java代码中来.