我通过stackoverflow和互联网搜索了这个,但还没有找到答案。
我有一个指纹识别器的SDK,我没有源代码,这意味着我无法改变它。
我需要访问一些方法,我将在下面列出哪个接口(来自RS_API.h):
REALSCANSDK_API int __stdcall RS_InitSDK( const char* configFileName, int option, int* numOfDevice );
REALSCANSDK_API int __stdcall RS_InitDevice( int deviceIndex, int*deviceHandle );
REALSCANSDK_API int __stdcall RS_SetCaptureMode( int deviceHandle, int captureMode, int captureOption, bool withModeLED );
REALSCANSDK_API int __stdcall RS_SetViewWindow( int deviceHandle, HWND windowHandle, RECT drawRectangle, bool autoContrast );
REALSCANSDK_API int __stdcall RS_TakeImageDataEx( int deviceHandle, int timeout, int fingerIndex, bool withLED, unsigned char** imageData, int* imageWidth, int* imageHeight );
我设法将所有这些转换为Delphi,但我也想从java应用程序访问它。
我的原型是这样的:
public class Leitor {
public native int RS_InitSDK(String configFileName, int option, int numOfDevice );
public static void main(String[] args) {
Leitor leitor= new Leitor();
leitor.RS_InitSDK(null, 0, 0);
}
static
{
System.load("C:\\temp\\SDKSuprema\\SDK\\RS_SDK.dll");
}
}
加载位工作正常(我相信它意味着它可以找到dll文件),但是当它运行本机方法时会抛出异常:
线程“main”中的异常java.lang.UnsatisfiedLinkError:leitor.Leitor.RS_InitSDK(Ljava / lang / String; II)I at leitor.Leitor.RS_InitSK(原生方法) 在leitor.Leitor.main(Leitor.java:14)
如果我重命名dll,它将错误更改为“无法加载库”,所以我认为问题是方法的映射。
我也找不到如何映射要从Java调用的引用参数的传递。唯一的解决方案是通过更改dll来返回结构而不是单个结果,但这是不可能的,因为我无法更改代码。
第二个问题是将窗口句柄从swt发送到JNI本机方法......
非常欢迎任何帮助!
答案 0 :(得分:2)
您需要编写显式粘合代码,将参数作为Java对象接受,并将它们转换为现有C入口点所期望的表示形式。 JVM本身不会为您执行此操作。
阅读JNI specification以了解如何编写此胶水代码。
特别是,为了匹配您的Java声明,JNI入口点必须命名为package_name_here_Leitor_RS_1InitSDK
或package_name_here_Leitor_RS_1InitSDK__Ljava_lang_String_2II
;请参阅规范第2章的“解析本机方法名称”部分。这个函数必须在Java可见的前面加一些额外的参数;请参阅规范
在该方法中,您将字符串作为jstring
值传递,您必须使用JVM中的GetStringUTFChars
辅助函数转换为C字符串。
对于pass-by-reference参数,您需要找到一种方法来模拟它们对调用Java代码有意义的方法,例如通过传递其字段由JNI代码分配的对象,或者(快速而肮脏)传递一个int[]
,其第一个元素由您的JNI代码分配。
答案 1 :(得分:1)
您需要创建c / c ++ glue代码来实现java方法,使用类调用javah将创建一个标头,声明标记为native的java方法的本机对应。
如果你不想编写c / c ++,你可以使用JNA在大多数情况下将java代码映射到现有的c方法和结构。