从Java中引用DLL代码 列表四演示代码引用DLL函数 public interface CLibrary extends Library { CLibrary INSTANCE = (CLibrary) NativeloadLibrary((PlatformisWindows() ? nativecode : c) CLibraryclass); int helloWorld(int divider); } public static void main(String[] args) { CLibraryINSTANCEhelloWorld()); } 列表四访问DLL函数在列表四中CLibrary实例被创建这个对象允许指定的DLL被下载接下来是库的装入过程标志需要从库中标记——在列表四的实例中只有一个标志被称为helloWorld() 列表五演示的程序来自列表四的代码 C:\jnacode>java HelloWorld Value is 列表五调用的DLL的代码在列表五中没有什么好惊奇的——值获准进入函数紧接着在函数内部参数()被除得出答案 当我尝试着着手解决DLL的问题与调用约定联系起来我想看看生成DLL的过程幸运的是你可以通过一种工具实现这个愿望这个工具被称为Dependency Walker通过Dependency Walker你可以看到DLL的生成过程为了实现你需要下载一个免费的Dependency Walker副本打开然后把DLL装载在里面你就可以看见如图一所示的类似内容 图一DLL内部信息 注意图一中的函数名称这些函数名称与DLL标志helloWorld()相匹配如果当你创建一个DLL的时候使用标准调用约定函数名称将会如图所示 图标准调用约定 注意函数名称变化的方式现在如果你尝试运行Java程序将会得到令人厌烦的错误提示如列表六所示 C:\jnacode>java HelloWorld Exception in thread main javalangUnsatisfiedLinkError: Error looking up function helloWorld: The specified procedure could not be found at comsunjnaFunction(Functionjava:) at comsunjnaNativeLibrarygetFunction(NativeLibraryjava:) at comsunjnaLibrary$Handlerinvoke(Libraryjava:) at $ProxyhelloWorld(Unknown Source) at HelloWorldmain(HelloWorldjava:) 列表六连接器错误包括上面的错误情况因为我自己也突然遇到了以上情形所以这是一个完全的JNA现场演示案例这与JNI是如何联系的——JNA的前身? JNI不是今天谢谢! 我经常想到这些年来JNI承受了很多评论在很多实例中一个软件支持部门要做的第一件事情就是说你使用JNI吗?如果答案是肯定的然后在很多例子中没有接踵而来的支持另一方面在很多顾问工作中我看见很多JNI案例这些JNI案例在大型Java和C++代码基础之间使用在这样一种情况中Java和C++通过所有的单元结合测试但是生产出来的代码随时有崩溃的可能性这种情况下Java和C++程序员尝试着掩饰这种情况每个人都在指责对方 解决JNI的悲哀的一个比较好的方案是通过一系列清单项目运行这些在任何一边的清单项目都是为了代码举个例子在C这边的代码 · 一个数组边界被突破? · 一个空指针被取消引用? · 动态内存被正确的分配? JNA有可能结束这种类型情况 库许可问题? JNA令人感兴趣的是它开启了Java直接存储DLL代码的功能它也适用于其它的库技术比如共享的Unix库软件组成部分得到许可的意思是什么?JNA的使用也许是令人信服的可以用来存取Java中的许可的库代码另一方面是JNA代码可以允许存取安全限制库代码 除了上面所考虑的问题具有存取遗留代码的能力也是很重要的现在让我们来看一看 当遗留代码调用通过JNA报错时 回顾列表三中的代码除一个参数使之成为一个不变值如果我把设置为除数执行操作的时候会发生什么那? public interface CLibrary extends Library { CLibrary INSTANCE = (CLibrary) NativeloadLibrary((PlatformisWindows() ? nativecode : c) CLibraryclass); int helloWorld(int divider); } public static void main(String[] args) { CLibraryINSTANCEhelloWorld()); Systemoutprintln(Value: + CLibraryINSTANCEhelloWorld()); } 列表把设置为除数的情况当我执行列表七中的代码我将会得到如列表八所示的输出示意 C:\jna_article\jnacode>java HelloWorld Value is # # An unexpected error has been detected by HotSpot Virtual Machine: # # EXCEPTION_INT_DIVIDE_BY_ZERO (xc) at pc=xb pid= tid=
# # Java VM: Java HotSpot(TM) Client VM (_b mixed mode) # Problematic frame: # C [nativecodedll+x] # # An error report file with more information is saved as hs_err_pidlog # # If you would like to submit a bug report please visit: # 列表障碍除数为的意外情况这可不漂亮但是我们还是得到了一些结果无论如何在现实生活中是线性增长的例子想像一下尝试在一个大的代码库中查找的状况总的来说JNA是很强大的但是就像任何强大的事情一样它还需要责任感 运行提供的代码以及CLASSPATH事务 伴随着JNA对此进行安排并且运行并不是十分困难——确认你跟随了一些简单的指导方针我已经实现了自己定制的DLL并且编辑Java代码作为源代码的一部分Zip文件你需要确定这些代码可以在Windows XP上面运行不需要编辑其它什么部件 运行代码解压源文件到一个文件夹比如C:\jnacode接下来的步骤是可选择的因为源文件包含一个jnajar 副本如果你打算拥有自己的jnajar 副本或者一个新的发布版本然后再下载jnajar文件的副本为了使事情更为简单将jnajar文件放到上面的文件夹中然后确认jnajar和包含文件夹都在CLASSPATH中接下来你可以尝试运行HelloWorld类 如果你感到充满了刺激或者活力你也许会喜欢尝试着创建你自己的DLL就像是我们在前面所描述的只需要按照上面所描述的做你能做的很好以防万一如果你遇到任何问题你都可以拜访JNA站点 结论JNA是如何一步步走来的? 我很喜欢JNA它非常的易于使用如果你的库代码是使用正确的方法编辑的你就不会遇到很多繁琐的问题JNA即将成为非常有用的工具来组织处理大量的复杂的工作关键业务遗留代码不再有厌烦的JNI标记并且头文件可以自动生成 有一点非常重要与任何新技术相比是非常容易把人们带进麻烦中的任何JNA都不例外因为这个原因如果JNA有条不紊的使用它将必定会超越JNI以及那些昂贵的私有的桥接机制什么样的形式可能会采取这样的规则?JNA资源中的任何调用(比如库代码)将会被充分的记录提供审查索引面向方面的技术建议自己使用这种方案比如说EJB拦截装置将会被用于确定JNA代码记录的效果 另外任何数据获准进入本地库(通过JNA代码)将会被认真的检查我猜想JNA成功的关键就是操作进行的缓慢而认真 |