java调用dll动态库方法

jnative的jar下载地址:

http://download.csdn.net/detail/heqinghua217/8865831


也可以去官网下载,地址如下

http://sourceforge.net/projects/jnative/


简单点的说明步骤:

我的是 windows环境 ,步骤如下,

1、把jnative.jar解压,  打开lib-bin目录,找到JNativeCpp.dll,把此文件放入系统盘,我的是c盘,路径如下, C:\Windows\System32 下

2、把自己要调用的动态库,放入你指定的目录,我这里放入的是F:\\EhfscliaxDll.dll 

3、把jar导入到web项目的lib目录中,如果不是web项目,可以放入jdk的ext目录中,

4、执行如下代码:返回http://中文127.0.0.1:10087 表示成功


代码如下

public static void exeDll1(){
try {

System.load("F:\\EhfscliaxDll.dll");
JNative getUrl = new JNative("EhfscliaxDll.dll", "getUrl");
getUrl.setRetVal(Type.STRING);
getUrl.setParameter(0, "127.0.0.1");
getUrl.setParameter(1, 10087);
getUrl.setParameter(2, 123);
getUrl.invoke();
System.out.println(getUrl.getRetVal());
} catch (Exception e) {
e.printStackTrace();
}

}

--输出参数还是需要自己去定义的,比如我如下的列子,0-6是输入参数,7是输出参数,要获取输出参数,需要黑色字体的写法

原来是这么写的,设置返回值是getUrl.setRetVal(Type.String);获取返回值是:System.out.println(getUrl.getRetVal());  //,

然后输出了一大堆日志,报了一堆错误,改写成现在这样就好了,终于搞定了,

public static void exeDll2(){
try {
System.load("F:\\OnLineDll.dll");
JNative getUrl = new JNative("OnLineDll.dll", "OnlineSign");
getUrl.setRetVal(Type.INT);//返回状态
getUrl.setParameter(0, 1);
getUrl.setParameter(1, "1202020709914498651");
getUrl.setParameter(2, "20150714");
getUrl.setParameter(3, "1");
getUrl.setParameter(4, "1234567890");
getUrl.setParameter(5, "79274");
getUrl.setParameter(6, "false");

MemoryBlock m = MemoryBlockFactory.createMemoryBlock(1024);
//指向内存块的指针
Pointer pp = new Pointer(m);
getUrl.setParameter(7, pp); //输出参数
getUrl.invoke();
System.out.println(getUrl.getRetVal());//调用状态
System.out.println(pp.getAsString());//输出参数

// 原来是这么写的,设置返回值是getUrl.setRetVal(Type.String);获取返回值是:System.out.println(getUrl.getRetVal());  //,然后输出了一大堆日志,报了一堆错误,改写成现在这样就好了,终于搞定了

getUrl.dispose(); // 记得释放 



} catch (Exception e) {
e.printStackTrace();
}

}


------------------------------   以下内容来自 http://tvjody.iteye.com/blog/125643  (他写的很好)

因为项目的需求,要在JAVA项目中调用Windows的Dll(动态链接库)文件,之前用Jni调用过C写的Dll文件,比较麻烦,这里不多说,网上也有很多这方面的文档。

在网上找到一个开源的组件JNative,使用后感觉比较方便。


  • 获得三个文件,分别是:JNativeCpp.dll,libJNativeCpp.so,JNative.jar 。 
    JNativeCpp.dll Windows下用的,拷贝到windows / system32目录下;
    libJNativeCpp.so Linux下的,拷贝到系统目录下;
    JNative.jar 这是一个扩展包,导入工程LIB中或将其拷贝到jdk\jre\lib\ext 下,系统会自动加载。

  • 使用说明

    我的项目将使用JNative组件调用一个测试应用服务器状态的TestAppSvr.dll文件,Dll文件中包含一个TestConnect()方法,返回一个整形的结果(1或0)

    首先配置好JNative组件的windows环境:
    将Native要用到JNativeCpp.dll放在系统盘的\WINDOWS\system32

    将JNative.jar导入工程中,新建一个调用类:

    java 代码
    1. package com.tvjody;   
    2.   
    3. import java.io.File;   
    4. import java.io.FileOutputStream;   
    5. import java.io.IOException;   
    6. import java.io.InputStream;   
    7.   
    8. import org.xvolks.jnative.JNative;   
    9. import org.xvolks.jnative.Type;   
    10. import org.xvolks.jnative.exceptions.NativeException;   
    11.   
    12. public class AppSvrTestConnect {   
    13.   
    14.     public AppSvrTestConnect() {   
    15.   
    16.     }   
    17.        
    18.     /**  
    19.      * 测试应用服务器连接状态  
    20.      *   
    21.      *  TestConnect   
    22.      * @param ip 应用服务器IP  
    23.      * @param port 端口  
    24.      * @param intrcpt  是否采用数据压缩方式 1 :true 0:false  
    25.      * @return int 1 :成功 0:失败  
    26.      * @throws NativeException  
    27.      * @throws IllegalAccessException  
    28.      */  
    29.     private static final int TestConnect(String ip, int port, int intrcpt)throws NativeException, IllegalAccessException {   
    30.         JNative n = null;   
    31.         try {              
    32.             n = new JNative("TestAppSvr.dll""TestConnect");   
    33.             n.setRetVal(Type.INT);   
    34.             int i = 0;   
    35.             n.setParameter(i++, Type.STRING, ip);   
    36.             n.setParameter(i++, Type.INT, "" + port);   
    37.             n.setParameter(i++, Type.INT, "" + intrcpt);   
    38.             n.invoke();   
    39.             return Integer.parseInt(n.getRetVal());   
    40.         } finally {   
    41.             if (n != null)   
    42.                 n.dispose();   
    43.         }   
    44.     }   
    45.     /**  
    46.      * 指定Dll文件路径,动态加载本地链接库,测试应用服务器连接状态  
    47.      * setDllPath  
    48.      * @param path Dll文件的路径,不包含DLL名称 例如:windows - d:\test\test\ unix - root/test/test/  
    49.      * @param ip 应用服务器IP  
    50.      * @param port 端口  
    51.      * @param intrcpt  是否采用数据压缩方式 1 :true 0:false  
    52.      * @return int 1 :成功 0:失败  
    53.      * @throws NativeException  
    54.      * @throws IllegalAccessException  
    55.      */  
    56.     public static final int TestConnectFromDllPath(String path,String ip, int port, int intrcpt) throws NativeException, IllegalAccessException{   
    57.         path += "TestAppSvr.dll";   
    58.         System.load(path);   
    59.         return TestConnect(ip,port,intrcpt);   
    60.     }   
    61.     /**  
    62.      * Dll文件放在JRE\bin目录下面,ClassLoader就能通过System.loadLibrary()动态加载本地链接库  
    63.      * TestConnectFromDllPath  
    64.      * @param ip 应用服务器IP  
    65.      * @param port 端口  
    66.      * @param intrcpt  是否采用数据压缩方式 1 :true 0:false  
    67.      * @return int 1 :成功 0:失败  
    68.      * @throws NativeException  
    69.      * @throws IllegalAccessException  
    70.      */  
    71.     public static final int TestConnectFromDllPath(String ip, int port, int intrcpt) throws NativeException, IllegalAccessException{   
    72.         System.loadLibrary("TestAppSvr");   
    73.         return TestConnect(ip,port,intrcpt);   
    74.     }   
    75. }  

    这个类实现了一个静态私有方法,用来调用Dll文件中的方法返回结果

    private static final int TestConnect(String ip, int port, int intrcpt)

    两个静态公共方法,分两种方式装载DLL文件

    public static final int TestConnectFromDllPath(String path,String ip, int port, int intrcpt)  //通过DLL文件的路径
    public static final int TestConnectFromDllPath(String ip, int port, int intrcpt) //通过ClassLoader

             然后新建一个类,调用AppSvrTestConnect.java,实现方法一调用,我是将TestAppSvr.dll文件与Demo.java放在一个目录下 ,所以得到Demo.java的路径后就可以得到TestAppSvr.dll的路径,调用AppSvrTestConnect.TestConnectFromDllPath()方法后就能返回正确的信息.方法二是已经将TestAppSvr.dll放在了Jre\bin目录下,在JVM的Classloader的时候会自动加载,然后通过System.loadLibrary("TestAppSvr")就可以装配DLL文件.

java 代码
  1. public class Demo {   
  2.     public int getInfo() throws NativeException, IllegalAccessException{   
  3.            
  4.         String path=getClass().getResource(File.separator).getPath();          
  5.         path = path.substring(1,path.length());   
  6.         System.out.println(path);   //得到DLL文件的路径   
  7.            
  8.         String ip = "192.168.0.48"//服务器IP   
  9.         int port = 221;             //端口   
  10.         int intrcpt = 1;            //数据压缩方式传送,1为采用;0为不采用   
  11.         //方法1 传入Dll文件的路径   
  12.         //int info = AppSvrTestConnect.TestConnectFromDllPath(path, ip, port, intrcpt);  
  13.            
  14.         //方法2 Dll文件已经放在JRE\bin目录下面   
  15.         int info = AppSvrTestConnect.TestConnectFromDllPath(ip, port, intrcpt);   
  16.            
  17.         //1为成功,0为失败   
  18.         if (info == 1)   
  19.             System.out.println("应用服务器可用。");   
  20.         else  
  21.             System.out.println("应用服务器不可用,请检查IP地址和端口是否正确。");   
  22.            
  23.         return info;   
  24.     }   
  25.       


 System.loadLibrary():装载Windows\System32下或jre\bin或Tomcat\bin目录下的本地链接库

System.load():根据具体的目录来加截本地链接库,必须是绝对路径

 

  • 备注

    上面的示例工程,因为是例子,所以没有大多的设计,只是实现了装载DLL文件,调用DLL文件方法,返回信息.

    JNative的详细说明,请参考JNative的源程序和例子.

    注意JVM只允许一个默认的ClassLoader来load native library,同时并不提供专门的API来unload一个loaded native library,所以在项目调试的时候,独立启动Web Server.
     


---------------------------------注意事项:来自http://www.cnblogs.com/beastplus/p/3156080.html


JNative用法注意事项

公司要做个跟设备打交道的web系统,需要java调用dll。搞java的同事说JNative看起来挺好使的,找俺帮忙调通。用的是1.3.1版本

  1. 环境设置。

    JNative的调试信息需要打开才能更清楚些,要不总是说没加载库,跟没说一样。

    System.setProperty("jnative.debug", "true");

    如果调试信息里有System.LoadLibrary(),说明没有加载JNativeCpp.dll,指定全路径即可,双斜杠哦。

    System.setProperty("jnative.loadNative", "D:\\Test\\JNativeCpp.dll");

  2. lib库路径问题
    • windows

      在windows下需要把调用的dll路径设置到环境变量PATH中,除非你不介意拷到win32中,dll依赖的库也得在PATH或win32中。

    • linux

       linux下同样需要设置环境变量,编辑bashrc,添加 export LD_LIBRARY=so路径,依赖的库也得在PATH中,除非都放在/usr/lib/下

  3. lib库名称问题

    无论linux还是windows在JNative的构造函数中的lib库名字为库全名,包括扩展名dll、so,而且so需要包括前面的‘lib’,貌似与网上说的不太一样。

  4. 资源释放问题

    有些设备需要先初始化在操作,最后释放,所有功能都分散在不同函数中,JNative需要有个静态的实例,每次创建调用函数时lib库依旧是加载的。



-----------------------------------------------------------一下文章来自http://blog.163.com/wex660@126/blog/static/24153065201031554358152/



今天,使用JNative遇到了一些小问题,郁闷是我,弄了很久才发现问题的所在: 
先说一下JNative的使用吧(JNative是封装了访问动态库的相关东西,方便java访问动态库的一个jar包): 
首先:下载JNative(http://sourceforge.net/projects/jnative/)又是sourceforge的东西;


其次:将你需要调用的的动态库放到系统系统盘下的system32或者其他地方(这些其他地方你可以查一下,WEB 项目则将动态库拷贝到容器的bin目录下,如tomcat的bin下 );


再次: 建立一个java项目,在项目中调用动态库,我这里粘贴一个我的例子供参考:

 

package com.gxmis.password;

import org.jasig.cas.authentication.handler.PasswordEncoder;
import org.xvolks.jnative.JNative;
import org.xvolks.jnative.Type;
import org.xvolks.jnative.exceptions.NativeException;
import org.xvolks.jnative.pointers.Pointer;
import org.xvolks.jnative.pointers.memory.MemoryBlock;
import org.xvolks.jnative.pointers.memory.MemoryBlockFactory;

 

//这是CAS里要使用的一个加密类,我实现了PasswordEncoder 的接口

 public class AccPasswordEncoder implements PasswordEncoder {
  public AccPasswordEncoder(){
   
  }

//重写的加密方法
  public String encode(String pass) {

      //定义JNative
       JNative jn = null;

      //返回密码的长度
       int retInt ;

       //返回的密码字符串
       String retPass = "";

   try {
    

   //申请一个内存块,因为要将加密后的数据取回来用,所以将加密后的数据放在这个内存块,方便返回的时候取出
    MemoryBlock m = MemoryBlockFactory.createMemoryBlock(1024);

   //指向内存块的指针
    Pointer pp = new Pointer(m);
    

    //设置日志记录的开启,方便跟踪JNative的运行过程
    JNative.setLoggingEnabled(true);

   //加载系统system32目录下的动态库
    System.loadLibrary("encrypt");

    //将动态库的名字和方法传递给JNative
    jn= new JNative ("encrypt","encrypttext");
    

   //设置调用动态库的方法后的返回类型(即encrypttext方法的返回类型)
    jn.setRetVal(Type.INT);
    
    int passLen = pass.length();
 
    int intOut = 2 * passLen + 16;
 

    //注意,我的encrypttext方法是有4个参数的,返回值为整型,第0,2个参数是字符串,第1,3个是整形
          jn.setParameter(0, pass);
          jn.setParameter(1, passLen);
          jn.setParameter(2, pp);
          jn.setParameter(3, intOut);
     

   //调用encrypttext方法     
          jn.invoke();
     

  //获得返回值     
          intOut = Integer.parseInt(jn.getRetVal()); 
 
          if (intOut == -1){
           jn.dispose();
           retPass = ""; 
          }
          else{
           jn.dispose();

          //取得加密数据
           retPass = pp.getAsString().substring(0,6);    
          }      
   } catch (NativeException e) { 
    System.out.println("NativeException异常:");
    e.printStackTrace();
   } catch (IllegalAccessException e) {
    System.out.println("IllegalAccessException异常:");
    e.printStackTrace();
   }finally{
    try {
     jn.dispose();
    } catch (NativeException e) {
     e.printStackTrace();
    } catch (IllegalAccessException e) {
     e.printStackTrace();
    } 
   }
   return retPass;
  }
 

}


我自己是调用动态库进行加密的操作:


遇到的问题1:

这个问题是找不到日志文件的异常,但是加密已经完成,从数据可以看出来:

 
2009-11-5 10:43:01, [DEBUG] [org.xvolks.jnative.JNative] [loadLibrary]: Successfully loaded library 'encrypt', functionName = encrypttext: hModule = 268435456 
1af154(这个是加密后出现的数据)java.lang.NoSuchFieldError: lastError 
at org.xvolks.jnative.JNative.nInvoke(Native Method) 
at org.xvolks.jnative.JNative.invoke(JNative.java:807) 
at com.passkey.AccPasswordEncoder.encode(AccPasswordEncoder.java:50) 
at com.passkey.test.main(test.java:10) 
2009-11-5 10:43:01, [DEBUG] [org.xvolks.jnative.JNative] [unLoad]: Unloading native library 'encrypt' 
ccx_jni_utils.c.writeLog : can't get a Java Logger instance. 
Exception in thread "main" 
解决办法:这个问题是jar包的原因,更新新版本的JNative.jar包就可以解决 

遇到的问题2:

JVM的问题:


# An unexpected error has been detected by Java Runtime Environment: 

#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x02e37b1a, pid=4008, tid=456 

Java VM: Java HotSpot(TM) Client VM (1.6.0-beta2-b86 mixed mode, sharing) 
# Problematic frame: 
# C  [IC_WS_CPU.dll+0x7b1a] 

# If you would like to submit a bug report, please visit: 
#   http://java.sun.com/webapps/bugreport/crash.jsp 

解决办法:是JDK版本的原因,注意要更新JDK的版本,1.5以下的可能会出现一些异常,更新到1.6的正式发布版本(尽量不使用测试版本)就好了

遇到的问题3:

我看网上还有个问题是:

开发一个web的时候,一个类用了JNative,JNativeCpp.dll文件发到了windows/system32下面, 
junit 也测试通过了,实际调用的时候报了个 
java.lang.IllegalStateException: JNative library not loaded, sorry ! 
  at org.xvolks.jnative.JNative. <init>(JNative.java:337) 
  at org.xvolks.jnative.JNative. <init>(JNative.java:269) 
.... 
的错误, 

后来把JNativeCpp.dll拷到tomcat的bin下面就解决了。 

不过,不知道了解里面的机制。

 

我也试了一下不用将JNativeCpp.dll拷贝到相应的目录,因为最新的JNative.jar包里面是打包了JNativeCpp.dll文件,所以这个问题在新版本我是没有遇到

 

 

以上的是鄙人遇到的一些东西,记录下来方便查找,若有错误之处忘回帖指教,若你也遇到了问题,也麻烦你写下问题和问题的解决办法,大家共同学习进步,谢谢.





  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java调用DLL动态库,可以使用Java Native Interface(JNI)来实现。下面是一个简单的步骤: 1. 编写C/C++代码,并将其编译成DLL动态库文件; 2. 在Java代码声明native方法,用于调用DLL动态库的函数; 3. 使用Javah命令生成C/C++头文件; 4. 在C/C++代码实现native方法调用DLL动态库的函数; 5. 将C/C++代码编译成动态库文件,并将其与Java代码一起运行。 下面是一个简单的例子: Java代码: ```java public class NativeMethod { static { System.loadLibrary("MyDLL"); // 加载动态库文件 } public static native int add(int a, int b); // 声明native方法 } ``` C/C++代码: ```c++ #include "NativeMethod.h" // 头文件 JNIEXPORT jint JNICALL Java_NativeMethod_add(JNIEnv *env, jclass cls, jint a, jint b) { jint result; // 调用DLL动态库的函数 result = MyAddFunction(a, b); return result; } ``` 其NativeMethod.h文件由Javah命令生成。在命令行,使用以下命令生成头文件: ``` javah -jni NativeMethod ``` 在这个例子,MyAddFunction是DLL动态库的函数,它的原型应该与Java代码声明的native方法的原型相同。编译C/C++代码时,需要将其编译成DLL动态库文件,并将其与Java代码一起运行。 需要注意的是,使用JNI调用DLL动态库需要谨慎,因为错误的操作可能会导致程序崩溃或安全漏洞。建议仔细了解JNI的使用方法和安全机制,以确保程序的安全性和稳定性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值