这是我的问题。
我有第三部分DLL(我没有源代码),我必须使用JNI进行交谈。提供此DLL的人不是Java家。我在他们的DLL中发现了一个错误,所以写了一些运行他们的DLL的C ++,暴露了这个bug并将它发送给他们进行修复。我终于从他们那里得到了一个更新的DLL,运行了我的C ++代码(工作正常)并发现错误确实已经修复。
但是,现在当我在JNI代码中使用这个新DLL时,我会抛出以下异常;
Exception c0000005, at 1EEE3416
Access violation: attempting to read memory at address 00000004
Native function stack data: 0,3f49c0,20201,801c6,65637845,6f697470,3063206e,30303030
com.jniwrapper.FunctionExecutionException: c0000005
at com.jniwrapper.Function.invokeCFunc(Native Method)
at com.jniwrapper.FunctionCall.a(SourceFile:127)
at com.jniwrapper.FunctionCall.call(SourceFile:35)
at com.jniwrapper.Function.invoke(SourceFile:188)
at com.tme.techdoc3.diagnostic.api.denso.DensoApiInvoker.invoke(DensoApiInvoker.java:78)
at com.tme.techdoc3.diagnostic.api.denso.NewDensoApi.invoke(NewDensoApi.java:106)
at com.tme.techdoc3.diagnostic.api.denso.NewDensoApi.connect(NewDensoApi.java:46)
at ConsoleApiRunner.main(ConsoleApiRunner.java:59)
我实际上是在使用JNIWrapper来提供我的JNI代码,因此为了引起问题而将其产品排除在外,我编写了自己的JNI代码;但我仍然得到同样的错误。这使我确信问题出在第三方DLL中。
我从我调用DLL的第一个函数中得到了这个异常(顺便说一句,这个函数没有错误...)。
我们从中获取DLL的地方明确表示他们不会支持它在JNI环境中的使用,即使他们不会向我发送任何类型的发布说明或固定和非固定之间的更改列表DLL文件。
在政治上,我无能为力。实际上,我仅限于此供应商的DLL。
任何人都可以想到为什么这个DLL在从C ++调用时可以工作,但在JNI中调用时却没有?我一直在玩JNI堆栈大小(-Xss)和其他一些JVM参数,但我要么没有找到正确的设置,要么我看错了。
非常感谢任何想法。
非常感谢。
编辑:添加我自己的JNI代码,看看是否有人可以发现错误。
编辑2:更正了代码复制粘贴错误。
当我使用自己的JNI代码时,这里是我正在使用的.cpp文件的实现;
#include "stdafx.h"
#include "windows.h"
#include "MyJniApi.h"
#include "ThirdParty.h"
#pragma comment(lib, "ThirdParty.lib");
ThirdPartyThing* thirdParty;
JNIEXPORT jlong JNICALL Java_com_mycompany_jni_MyJniApi_connect(JNIEnv *, jobject) {
long connId = 0L;
thirdParty = new ThirdPartyThing();
long retval = thirdParty->GetConnection(&connId);
if(0 == retval) {
return connId;
} else {
return retval;
}
}
正如你所看到的,它非常简单,当我的指针混合起来时,我看不到任何地方。 (免责声明:这几乎是我C ++技能的总和!)
答案 0 :(得分:0)
c0000005表示“访问冲突”,这通常意味着使用了一个包含无效内存地址的指针。这可能只是一个糟糕的指针值,例如未初始化或可能表明该物体已被销毁。
我会看两件事:
您传递的参数,尤其是任何输出类型。我没有直接使用JNI,但我想如果变量是readonly而不是可以写入变量,那么变量可能会以不同的方式桥接到C ++。如果DLL API期望它们已经分配,请确保分配您传递的所有缓冲区。
您正在调用方法或作为参数传递的对象的生命周期。确保在调用C ++期间未收集正在使用的Java对象。
答案 1 :(得分:0)
我的建议是基于这个假设 - 如果你能在C ++中使用它,那么你应该能够在JNI中使用它。
我使用JNI已经有很长一段时间了,但这样的问题通常是由最简单的事情引起的。
我要非常彻底地检查的是你正在使用新DLL附带的所有更新的.h header / .lib等文件。在检查您是否指向所有新文件,正确的路径(包括您当前的JRE)之后,重新生成JNI定义对象。搜索整个文件系统并删除以前版本的旧DLL及其依赖项/ headers / libs / .obj等。一个陈旧的文件可能导致问题。
我曾经因为某个应用程序将核心Windows DLL的副本放在它自己的程序目录中(然后添加到PATH)而浪费了三天的时间,这在尝试加载正确的程序时会造成混乱。
BTW:DLL有任何奇怪的身份验证/许可行为吗?或者是否需要加载无法解析的其他依赖项?答案 2 :(得分:0)
好的,这已经解决了(而不是解决了)。
最近我意识到我沿途引进了一只红鲱鱼。当我编写自己的JNI代码(以排除导致问题的JNIWrapper产品)并宣布仍然抛出异常时,我一定被困在DLL Hell的一个圈子里。当我第一次使用自己的JNI代码引入时,抛出了异常,但是在随后的几天里,重新运行我自己的JNI代码并没有抛出异常。所以我假设我必须在某个地方放置一个旧的DLL,导致一些错误的结果。
所以新信息:当与JNIWrapper一起使用时抛出异常,但与本土JNI代码一起使用时抛出异常。
所以现在我在JNIWrapper中深入挖掘。在其中一个支持论坛帖子中,它说JNI包装器不是为C ++ DLL设计的,即它只支持C ++语言功能的子集。虚拟方法是一个特殊的缺陷。由于我的第三方DLL是C ++版本,我认为在之前的版本中他们使用的不使用JNIWrapper不支持的语言功能,但现在它们已经使用了。对我来说,这意味着我不能再使用JNIWrapper工具了。
相反,我正在使用Swig生成我需要的所有JNI代码。无论如何,Swig看起来是JNIWrapper的更好选择,因为生成的Java代码更清晰。
感谢所有提出建议的人。我认为每个答案的至少一个方面是正确和有用的。