很久没写过jni了。这次项目中用到,准备使用vs2015生成dll,供java调用。我用premake5生成了vs2015项目,但生成出来的dll,无法在java中调用,报以下错误:
Exception in thread "main" java.lang.UnsatisfiedLinkError: RecastLib.hello()V at RecastLib.hello(Native Method) at RecastLib.main(RecastLib.java:22)
使用vs2015中的工具 dumpbin 查看dll中的方法:
1 0 00001200 ?Java_RecastLib_hello@@YAXPEAUJNIEnv_@@PEAV_jobject@@@ Z = ?Java_RecastLib_hello@@YAXPEAUJNIEnv_@@PEAV_jobject@@@Z (void __cdecl Java_R ecastLib_hello(struct JNIEnv_ *,class _jobject *)) 2 1 00001220 ?_Java_RecastLib_hello@@YAXPEAUJNIEnv_@@PEAV_jobject@@ @Z = ?_Java_RecastLib_hello@@YAXPEAUJNIEnv_@@PEAV_jobject@@@Z (void __cdecl _Jav a_RecastLib_hello(struct JNIEnv_ *,class _jobject *))
发现 vs2015 编译的方法名全部被添加上了@后缀。
正确的应该是:
ordinal hint RVA name 1 0 00011091 Java_RecastLib_hello = @ILT+140(Java_RecastLib_hello)
这是因为 vc++中的 Name Mangling:
JNIEXPORT void JNICALL Java_RecastLib_hello (JNIEnv *, jobject);
如果要导出的cpp中使用了c++特性,即使指定为 extern “C” 也受Name Mangling的影响。
这里可以定义一个 java.def 文件也解决。定义如下:
LIBRARY recastDll EXPORTS Java_RecastLib_hello
然后在vs2015的链接器中定义:
这样导出的函数即不会受name mangling 的影响。
除此之外,还可以使用 RegisterNatives 的方式将函数入口注入java vm(两种试并无性能差异)。
如下:
static JNINativeMethod s_methods[] = { { "jniHello", "()V", (void*)Java_RecastLib_hello }, { "jniLoad", "(Ljava/lang/String;)I", (void*)Java_RecastLib_load }, { "jniFind", "(FFFFFF)Ljava/util/List;", (void*)Java_RecastLib_find } }; JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { JNIEnv* env = NULL; if (vm->GetEnv((void**)&env, JNI_VERSION_1_8) != JNI_OK) { return JNI_ERR; } jclass cls = env->FindClass("LRecastLib;"); if (cls == NULL) { return JNI_ERR; } int len = sizeof(s_methods) / sizeof(s_methods[0]); if (env->RegisterNatives(cls, s_methods, len) < 0) { return JNI_ERR; } return JNI_VERSION_1_8; }
0 条评论。