这是我第一次尝试JNI。我的最终目标是让当前在机器上运行的所有任务,但需要运行一个简单的示例。当我尝试执行我的主程序时,我不断收到此错误。我提供了简单的Java主程序,生成的头文件和错误。
我不知道这个DLL可以依赖什么。它最初引用了我追踪并放入system32(msvcr90.dll)的DLL。
这是我用来编译C代码的命令,它生成了DLL,OBJ,LIB,EXP和清单文件。
cl -I“C:\ Program Files \ Java \ jdk1.6.0 \ include”-I“C:\ Program Files \ Java \ jdk1.6.0 \ include \ win32”-MD -LD HelloWorld.c -FeHelloWorld。 DLL
class HelloWorld {
private native void print();
public static void main(String[] args) {
new HelloWorld().print();
}
static {
System.load("C:\\temp\\HelloWorld.dll");
}
}
#include <jni.h>
#include <stdio.h>
#include "HelloWorld.h"
JNIEXPORT void JNICALL
Java_HelloWorld_print(JNIEnv *env, jobject obj)
{
printf("Hello World!\n");
return;
}
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloWorld */
#ifndef _Included_HelloWorld
#define _Included_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: HelloWorld
* Method: print
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_HelloWorld_print
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
java.lang.UnsatisfiedLinkError: C:\temp\HelloWorld.dll: A dynamic link library (DLL) initialization routine failed
at java.lang.ClassLoader$NativeLibrary.load(Native Method)
at java.lang.ClassLoader.loadLibrary0(Unknown Source)
at java.lang.ClassLoader.loadLibrary(Unknown Source)
at java.lang.Runtime.load0(Unknown Source)
at java.lang.System.load(Unknown Source)
at HelloWorld.<clinit>(HelloWorld.java:7)
Exception in thread "main"
答案 0 :(得分:9)
不满意的链接错误可能意味着许多事情出错了。我会用
System.loadLibrary("HelloWorld");
而不是
System.load();
正如TwentyMiles建议的那样。
此外,在调用程序时,您需要(假设您的DLL与您的类文件位于同一目录中:
java -Djava.library.path =。的HelloWorld
这是我做的一个简单的演示,它调用Win32 API函数(MessageBox)
class CallApi{
private native String showMessageBox(String msg);
private native double getRandomDouble();
static{
try{
System.loadLibrary("CallApi");
System.out.println("Loaded CallApi");
}catch(UnsatisfiedLinkError e){
//nothing to do
System.out.println("Couldn't load CallApi");
System.out.println(e.getMessage());
}
}
public static void main(String args[]){
CallApi api = new CallApi();
double randomNumber = api.getRandomDouble();
String retval = api.showMessageBox("Hello from Java!\n"+
"The native random number: "+randomNumber);
System.out.println("The native string: "+retval);
}
}
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class CallApi */
#ifndef _Included_CallApi
#define _Included_CallApi
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: CallApi
* Method: showMessageBox
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_CallApi_showMessageBox
(JNIEnv *, jobject, jstring);
/*
* Class: CallApi
* Method: getRandomDouble
* Signature: ()D
*/
JNIEXPORT jdouble JNICALL Java_CallApi_getRandomDouble
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
#include "CallApi.h"
#include <windows.h>
#include <stdlib.h>
#include <time.h>
#pragma comment(lib,"user32.lib")
JNIEXPORT jstring JNICALL Java_CallApi_showMessageBox
(JNIEnv *env, jobject thisObject, jstring js)
{
//first convert jstring to const char for use in MessageBox
const jbyte* argvv = (*env)->GetStringUTFChars(env, js, NULL);
char* argv =(char *) argvv;
//Call MessageBoxA
MessageBox(NULL, argv, "Called from Java!", MB_ICONEXCLAMATION | MB_OK);
return js;
}
JNIEXPORT jdouble JNICALL Java_CallApi_getRandomDouble
(JNIEnv *env, jobject thisObject)
{
double num1;
srand((unsigned)(time(0)));
num1 = ((double)rand()/(double)RAND_MAX);
return num1;
}
我使用Visual C ++ express 2008 cl进行编译,删除-ML标志,因为当Java代码尝试调用本机代码时会导致异常:
cl / I“c:\ Program Files \ Java \ jdk1.6.0_10 \ include”/ I“c:\ Program Files \ Java \ jdk1.6.0_10 \ include \ win32”-LD CallApi.c -FeCallApi。 DLL
然后,运行代码:
java -Djava.library.path =。 CallApi
答案 1 :(得分:3)
我并没有声称理解这种情况足以解释它,但有些用户在使用“-MD”编译器标志时报告了错误。
有关更多信息,请参阅 Java Native Interface(JNI) - 无法使用带有Java的VS2005?,它讨论了这个问题并为替代方案提供了可能的解决方法和think techie blog。
答案 2 :(得分:1)
我相信你应该使用
System.loadLibrary("HelloWorld");
而不是System.load。 LoadLibrary将检查您的系统路径(而不是Java库路径),因此请确保HelloWorld.dll位于可以找到的目录中。另请注意,它不需要完整路径,也不需要在末尾添加dll扩展名。
答案 3 :(得分:1)
我刚删除-MD选项并编译它就像魅力一样
cl -I"C:\Program Files\Java\jdk1.6.0_21\include" -I"C:\Program Files\Java\jdk1.6.0_21\include\win32" -LD HelloWorld.c -FeHelloWorld.dll
答案 4 :(得分:0)
如果从Java端更改本机函数声明的位置(包)而不更新h文件,并且在c ++端更改了方法的签名,它将无法解析为该方法,并且将引发不满意的情况。
package x;
public class A {
private native void print();
...
}
移至:
package x.y;
public class A {
private native void print();
...
}
这将需要重新生成H文件(类似于Java_x_y_A_print)。
请注意,您可以手动更改这些签名,但我不建议