zoukankan      html  css  js  c++  java
  • JNA 传参char[] 和结构体等

    近日项目中需要用java调用c/c++编写的dll库,所有了解到jna这个东东,下面是使用的一些经验:

    一、java使用Jna需要两个jar包,eg:jna-3.5.1.jar和platform-3.5.1.jar 下载地址,添加完依赖包后把需调用的dll放到项目根目录下就是和src同级目录下

    二、报错:Unable to load DLL 'xxx.dll': 找不到指定的模块,可能有一下几个问题:

         1、使用的jdk和dll位数不同,64位的jdk只能调用64位的dll,32一样。

         2、dll的位置放的不对(也有说放在c盘的systen32下的)

      3、电脑缺少dll依赖的组件(例如我重装完系统怎么调用都不成功,最后发现缺少了Visual C++ Redistributable Packages for Visual Studio 2013这个组件 下载地址,也有可能是其他组件可以用VS的插件查看,具体请百度)

    三、java-c 数据类型映射   jna操作文档 下载地址

    常见的映射就不说了,这里说一下我项目中用到的:

    1、char*&

    //dll中
    int pack_clou102(char*& sendstr)
    
    //java中接口    PointerByReference 表示指针的引用类型
    public int pack_clou102(PointerByReference send);
    
    //获取send      
    String str = send.getValue().getString(0);
    //send.getValue()获取的是一个指针   而getString(0)是获取指针的值   这里不可以用
     send.getValue().toString()//会导致乱码

    2、char*

    //根据dll的操作来决定,官方char*对应String
    
    //但是下面这个例子中用byte[]才可以
    
    //dll中
    //UINT8是指无符号8位二进制整型  在这里映射String会出现编码问题的,所以这里用byte[]
    int unpack_clou102(char* recvbuf)
    {
    	UINT8* pbuf = (UINT8*)recvbuf;   
    	UINT8 ucCheckSum = 0;// 校验和
    
    。。。
    }
    
    //java中
     public int unpack_clou102(byte[] recvbuf);
    

    3、传参char[]

    //dll
    int pack_clou102(char[20] send){
    。。。
    return 0;
    }
    //有时候会遇到dll中用char[]传字符串的,java中是用byte[],这时候可以借用“”.getbytes()
    //jna
    byte[20] bytes = "2016-08-29 11:06:23".getbytes();
    int mun = pack_clou102(bytes);

    4、传参结构体    可以参考  原文地址

    //DLL中
    struct
    CompanyStruct{ long id; wchar_t* name; UserStruct* users[100]; int count; };
    //java中
    public
    static class CompanyStruct2 extends Structure{   public NativeLong id;   public WString name;   public UserStruct.ByReference[] users=new UserStruct.ByReference[100];   public int count; }
    //测试代码
    CompanyStruct2.ByReference companyStruct2=new CompanyStruct2.ByReference(); companyStruct2.id=new NativeLong(2); companyStruct2.name=new WString("Yahoo"); companyStruct2.count=10; UserStruct.ByReference pUserStruct=new UserStruct.ByReference(); pUserStruct.id=new NativeLong(90); pUserStruct.age=99; pUserStruct.name=new WString("杨致远"); // pUserStruct.write(); for(int i=0;i<companyStruct2.count;i++){ companyStruct2.users[i]=pUserStruct; } TestDll1.INSTANCE.sayCompany2(companyStruct2);

    执行测试代码,报错了。这是怎么回事?
    考察JNI 技术,我们发现Java 调用原生函数时,会把传递给原生函数的Java 数据固定
    在内存中,这样原生函数才可以访问这些Java 数据。对于没有固定住的Java 对象,GC 可以
    删除它,也可以移动它在内存中的位置,以使堆上的内存连续。如果原生函数访问没有被固
    定住的Java 对象,就会导致调用失败。
    固定住哪些java 对象,是JVM 根据原生函数调用自动判断的。而上面的CompanyStruct2
    结构体中的一个字段是UserStruct 对象指针的数组,因此,JVM 在执行时只是固定住了
    CompanyStruct2 对象的内存,而没有固定住users 字段引用的UserStruct 数组。因此,造成
    了错误。
    我们需要把users 字段引用的UserStruct 数组的所有成员也全部固定住,禁止GC 移动
    或者删除。
    如果我们执行了pUserStruct.write();这段代码,那么就可以成功执行上述代码。
    Structure 类的write()方法会把结构体的所有字段固定住,使原生函数可以访问。

  • 相关阅读:
    VB Open 函数详解 打开、关闭、读、写文件
    VB程序设计中Combobox的取值问题
    vb中typename函数
    VB.NET Event RaiseEvent用处
    通过关键字Event定义用户自己的事件
    [转]如何在注册表中进行查找
    [转]ADT中通过DDMS导入文件出错ddms transfer error: Read-only file system,Failed to push selection: Read-only file system
    [转]在eclipse打开的android虚拟手机,打开File Explorer,下面是空的没有data、mnt、system三个文件
    [转]Android开发过程中遇到的问题
    [转]如何解决android模拟器慢的问题
  • 原文地址:https://www.cnblogs.com/lwx521/p/10552632.html
Copyright © 2011-2022 走看看