JNA调用本地dll

一,JNA的定义
JNA(Java Native Access)是一个开源的Java框架,是Sun公司推出的一个调用本地动态库的文件中方法的技术,是建立在经典的JNI基础上的一个框架。
优点:1,基本上在java环境就可以完成操作。
          2,不需要重写动态库中的方法(jni需要为每个方法写一个jni方法),直接调用API。
缺点:1,有少许性能损失,但是总体影响不大。
          2,只能实现java访问c,而不能实现c访问java。

二,JNA使用
1,JNA和C数据类型转换

Native Type
Size
Java Type
Common Windows Types
char
8-bit integer
byte
BYTE,TCHAR
short
16-bit integer
short
WORD
wchar_t
16/32-bit character
char
TCHAR
int
32-bit integer
int
DWORD
int
boolean value
boolean
BOOL
long
32/64-bit integer
NativaLong
LONG
long long
64-bit integer
long
__int64
float
32-bit FP
float

double
64-bit FP
double

char *
C string
String
LPTCSTR
void *
pointer
Pointer
LPVOID,HANDLE,LPXXX
JNA还支持其他的类型转换,可以到 http://java-native-access.github.io/jna/4.4.0/javadoc/ 查看。

2,JNA调用例子1
导入JNA的jar包,可以通过maven中添加:
< dependency >
< groupId > com.sun.jna </ groupId >
< artifactId > jna </ artifactId >
< version > 3.0.9 </ version >
</ dependency >

代码如下:
c接口:   int   add( int   a,   int   b);

java代码:
public interface  TestInteface  extends  Library {
    int  add( int  a,  int  b);
}

public class  App
{
    public static void  main( String[] args )
    {
        System. load ( "D:/vsproject/jnavctest/x64/Release/jnavctest.dll" );
        try  {
            TestInteface INSTANCE = (TestInteface) Native. loadLibrary ( "jnavctest" TestInteface. class );
            System. out .println(INSTANCE.add( 6 77 ));
        }   catch   (Exception e1) {
            System. out .println(e1.getMessage());
        }
        System. out .println( "end" );
   }
}

程序解释:
(1)建立一个接口继承Library,默认继承是Library,如果c中是stdcall方式导出的,就继承StdCallLibrary。
public interface  TestInteface  extends  Library {
}

(2)声明方法,方法的返回值和参数要和本地dll对应,对应类型可以查看上节类型转换。
public interface  TestInteface  extends  Library {
    int  add( int  a,  int  b);
}

(3)实例化接口实例
TestInteface INSTANCE = (TestInteface) Native. loadLibrary ( "jnavctest" TestInteface. class );
注意:1,要把动态库路径加载到系统路径中, System. load ( "D:/vsproject/jnavctest/x64/Release/jnavctest.dll" ),这里为了方便采用的绝对路径。
     2,实例化的第一个参数jnavctest不能带有.dll,java是跨平台,在Linux下面是so 。

(4)调用接口
INSTANCE.add( 6 77 );

3,JNA调用例子二
上面的例子比较简单,但是c中经常有结构体,指针等数据类型,我们调用一个结构体和指针的例子。
导入jar、实例化接口等参考上节。
代码如下:
c接口:
typedef struct{
    byte b1;
    byte b2[2048];
    byte b3[2048];
}myUserStruct;

extern "C" __declspec(dllexport) int testStruct2(myUserStruct sturct);
extern "C" __declspec(dllexport) int testStruct3(myUserStruct *sturct, byte *a, int *length);

java代码:
public class myUserStruct extends Structure {
   public byte b1;
   public byte[] b2 = new byte[2048];
   public byte[] b3 = new byte[2048];

   public static class ByReference extends myUserStruct implements Structure.ByReference {}
   public static class ByValue extends myUserStruct implements Structure.ByValue {}
}

public interface TestInteface extends Library {
   int testStruct2(myUserStruct.ByValue userStruct);
   int testStruct3(myUserStruct.ByReference userStruct, ByteByReference a, IntByReference length);
}

public static void main( String[] args )
{
   System.load("D:/vsproject/jnavctest/x64/Release/jnavctest.dll");
   System.out.println( "start" );
   try {
      TestInteface INSTANCE = (TestInteface) Native.loadLibrary("jnavctest"TestInteface.class);

      byte[] array = new byte[]{0x31, 0x32, 0x33, 0x34};
      myUserStruct.ByValue testStruct = new myUserStruct.ByValue();
      testStruct.b1 = 0x31;
      testStruct.b3 = array;
      System.out.println(INSTANCE.testStruct2(testStruct));

      myUserStruct.ByReference testStruct1 = new myUserStruct.ByReference();
      testStruct1.b1 = 0x31;
      testStruct1.b3 = new byte[2048];
      testStruct1.b3[0] = 0x31;
      ByteByReference reference1 = new ByteByReference();
      Memory memory1 = new Memory(4);
      reference1.setPointer(memory1);
      IntByReference intByReference1 = new IntByReference(4);

      int kkkkret = INSTANCE.testStruct3(testStruct1, reference1, intByReference1);
      byte[] temp1 = new byte[4];
      memory1.read(0, temp1, 0, 4);
      System.out.println(Arrays.toString(temp1));
      System.out.println(reference1.getValue());
      System.out.println(kkkkret);
   } catch (Exception e) {
      System.out.println(e.getMessage());
   }

   System.out.println("end");
}

程序解释:
(1)结构体指针和值参数的传递
c中的值类型对应java的value类型,也就是值类型,指针类型则对应引用类型。自定义的结构要传值或引用就要继承Structure,并实现Structure.ByReference和Structure.ByValue实现为空即可。
public class myUserStruct extends Structure {
   public byte b1;
   public byte[] b2 = new byte[2048];
   public byte[] b3 = new byte[2048];

   public static class ByReference extends myUserStruct implements Structure.ByReference {}
   public static class ByValue extends myUserStruct implements Structure.ByValue {}
}

(2)接口参数对应
结构体指针和结构体分别对应myUserStruct.ByReference和myUserStruct.ByValue。
基础类型可以查阅JNA文档。byte *对应ByteByReference,int *对应IntByReference。
public interface TestInteface extends Library {
   int testStruct2(myUserStruct.ByValue userStruct);
   int testStruct3(myUserStruct.ByReference userStruct, ByteByReference a, IntByReference length);
}

(3)结构体的调用
实例化结构体的ByValue并传入。
byte[] array = new byte[]{0x31, 0x32, 0x33, 0x34};
myUserStruct.ByValue testStruct = new myUserStruct.ByValue();
testStruct.b1 = 0x31;
testStruct.b3 = array;
System.out.println(INSTANCE.testStruct2(testStruct));

(4)byte,int指针的调用和读取数据
byte是一个数组,这里的例子中是通过一个int的引用的传入的长度,实际使用中应该传入数组的长度并不允许越界,当byte长度为4,c中操作了byte[5]就会出错。由于java中申请的内存空间并不是连续,而c操作数组类的数据是根据指针来操作的,所有要自己申请一个内存空间,并用setPointer方法把内存赋给数组。
ByteByReference reference1 = new ByteByReference();
Memory memory1 = new Memory(4);
reference1.setPointer(memory1);

读取数据的时候,要把内存中数据读取出来赋给一个数组,然后读取数组的数据即可。
byte[] temp1 = new byte[4];
memory1.read(0, temp1, 0, 4);

int是对单一一个int的引用,只用实例化IntByReference,并赋值即可。
IntByReference intByReference1 = new IntByReference(4);

读取单一一个int的数据只用调用getValue方法即可。
System.out.println(reference1.getValue());

(5)结构体指针的调用
只需实例化的结构体的ByReference的实例传入即可
myUserStruct.ByReference testStruct1 = new myUserStruct.ByReference();
testStruct1.b1 = 0x31;
testStruct1.b3 = new byte[2048];
testStruct1.b3[0] = 0x31;
int testStruct3(myUserStruct.ByReference userStruct, ByteByReference a, IntByReference length);

4,使用中问题的记录
(1) Can't load IA 32-bit .dll on a AMD 64-bit platform
主要问题是dll是32位,本地的jdk是64位,可以编译64位的dll或者换32的jdk

三、参考文档
1, JNI的替代者—使用JNA访问Java外部功能接口( http://www.cnblogs.com/lanxuezaipiao/p/3635556.html )







评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值