很久没写过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 条评论。