JNA java调用c/c++代码
2013-08-11 12:45
387 查看
最近在搞一个小程序,需要用java调用DLL。用到的技术是JNA。
具体的内容在网上一搜都有,但是很多帖子内容都差不多,而且都有些问题,也不知道是不是版本的问题,反正代码拿来一copy各种问题,倒腾了好久,终于弄出点眉目出来,写来与大家分享下。
首先,c/c++代码如下:
封装成DLL,copy到java工程的bin目录下,
在java中使用时,首先需要导入jna的包,过程网上都有,就不多说了,然后在代码中需要添加:
调用代码如下:
好,第一个没有任何问题,通过。
现在试试结构体:
给DLL 工程中添加这些(教程里用的):
按照教程的说法,封装以及调用规则如下:
注意在教程里没有提到getFieldOrder这个函数,所以编译会报错,只好实现一下,查了一下,这个list返回的是封装结构体中的变量名称,这个一定不能写反(不管是基本变量还是结构体变量,或者是数组什么的,只需要添加名称就可以)。
调用函数声明:
关于:
这两个需要说一下,教程里是说显示的说明是值或引用,如果去掉也不影响,前提是定义变量的时候应该这样写:
我测试过了,这个写对结果也没有什么影响,DLL调用成功,不过还是建议加上,这样显得更正确些。
测试代码:
看声明,是传递引用,所以显示的使用了ByReference。
一定注意,在定义变量的时候使用的是UserStruct.ByReference ,因为函数声明的是ByReference。前后一定要一致。
下面是问题最多的一块:结构体数组:
定义如下:
嵌套结构体:
教程里是这样封装调用的:
但是会报错(除了那个getFiledOrder函数外)。
回头看看,可能是因为版本的问题吧,帖子和教程都是08年的,现在JNA更新到了4.0了,可能对某些东西做了改动,所以会报错。
尝试着这样定义:使用原始的方法定义:
想想,不管怎样,在c模式下,数组其实跟指针是“相通”的。
函数声明:
调用如下:
因为函数是Reference声明,所以定义使用ByReference。(注意,如果在java里函数声明是一般声明,那么定义变量时也是用一般声明,虽然在DLL中是指针参数,但是调用DLL经测试是成功的,这点我很纳闷,可能在转换的时候java已经自动识别了吧,保险一下,还是显示的使用声明吧)
注意这里:
这样调用就成功了。
其他的说明教程里都有讲的比较详细,就不多说了。
因为技术也在发展,所以教程里的某些东西可能因为更新而被修改,所以阅读的时候还需要自己再实际的测试使用才行。
具体的内容在网上一搜都有,但是很多帖子内容都差不多,而且都有些问题,也不知道是不是版本的问题,反正代码拿来一copy各种问题,倒腾了好久,终于弄出点眉目出来,写来与大家分享下。
首先,c/c++代码如下:
extern "C" _declspec(dllexport) int add(int first, int second);实现代码:
int add(int first, int second) { printf("(c) test jna : %d + %d = %d\n", first, second, first + second); return first + second; }
封装成DLL,copy到java工程的bin目录下,
在java中使用时,首先需要导入jna的包,过程网上都有,就不多说了,然后在代码中需要添加:
import com.sun.jna.Library; import com.sun.jna.Native; import com.sun.jna.NativeLong; import com.sun.jna.Platform; import com.sun.jna.Pointer; import com.sun.jna.Structure;
调用代码如下:
public class Dll { public interface TestJnaLib extends Library { TestJnaLib INSTANCE = (TestJnaLib)Native.loadLibrary("DLL.dll", TestJnaLib.class); int add(int first, int second); } public static void main(String[] args) { TestJnaLib.INSTANCE.add(23, 34); }
好,第一个没有任何问题,通过。
现在试试结构体:
给DLL 工程中添加这些(教程里用的):
struct UserStruct{ int id; char* name; int age; }; extern "C" __declspec( dllexport )void sayUser(UserStruct* pUserStruct) { printf("%ld %s %d\n",pUserStruct->id,pUserStruct->name,pUserStruct->age); }
按照教程的说法,封装以及调用规则如下:
public static class UserStruct extends Structure { public int id; public String name; public int age; public static class ByReference extends UserStruct implements Structure.ByReference { } public static class ByValue extends UserStruct implements Structure.ByValue{ } @Override protected List getFieldOrder() { List a = new ArrayList(); a.add("id"); a.add("name"); a.add("age"); return a; } }
注意在教程里没有提到getFieldOrder这个函数,所以编译会报错,只好实现一下,查了一下,这个list返回的是封装结构体中的变量名称,这个一定不能写反(不管是基本变量还是结构体变量,或者是数组什么的,只需要添加名称就可以)。
调用函数声明:
void sayUser(UserStruct.ByReference struct);
关于:
public static class ByReference extends UserStruct implements Structure.ByReference { } public static class ByValue extends UserStruct implements Structure.ByValue{ }
这两个需要说一下,教程里是说显示的说明是值或引用,如果去掉也不影响,前提是定义变量的时候应该这样写:
TestJnaLib.UserStruct userStruct=new TestJnaLib.UserStruct();
我测试过了,这个写对结果也没有什么影响,DLL调用成功,不过还是建议加上,这样显得更正确些。
测试代码:
TestJnaLib.UserStruct.ByReference userStruct=new TestJnaLib.UserStruct.ByReference(); userStruct.id=100; userStruct.age=30; userStruct.name=new String("奥巴马"); TestJnaLib.INSTANCE.sayUser(userStruct);
看声明,是传递引用,所以显示的使用了ByReference。
一定注意,在定义变量的时候使用的是UserStruct.ByReference ,因为函数声明的是ByReference。前后一定要一致。
下面是问题最多的一块:结构体数组:
定义如下:
struct CompanyStruct{ int id; char* name; int count; UserStruct users[10]; }; extern "C" __declspec( dllexport )void sayCom(CompanyStruct* pCompanyStruct) { printf("%ld %s %d\n",pCompanyStruct->id,pCompanyStruct->name,pCompanyStruct->count); for(int i=0;i<10;i++) printf("%ld %s %d\n",pCompanyStruct->users[i].id,pCompanyStruct->users[i].name,pCompanyStruct->users[i].age); }
嵌套结构体:
教程里是这样封装调用的:
public static class CompanyStruct extends Structure{ public NativeLong id; public WString name; public UserStruct.ByValue[] users=new UserStruct.ByValue[100]; public int count; }
但是会报错(除了那个getFiledOrder函数外)。
回头看看,可能是因为版本的问题吧,帖子和教程都是08年的,现在JNA更新到了4.0了,可能对某些东西做了改动,所以会报错。
尝试着这样定义:使用原始的方法定义:
public static class CompanyStruct extends Structure{ public int id; public String name; public int count; public UserStruct [] users=new UserStruct[10]; public static class ByReference extends CompanyStruct implements Structure.ByReference { } public static class ByValue extends CompanyStruct implements Structure.ByValue{ } @Override protected List getFieldOrder() { List a = new ArrayList(); a.add("id"); a.add("name"); a.add("count"); a.add("users"); return a; } }不用byValue了。如果这里用到了byValue或者byReferfece都会报错,即使编译过了,运行也是错的(其中有什么invalid memory 访问等一大堆各种奇葩的问题)。
想想,不管怎样,在c模式下,数组其实跟指针是“相通”的。
函数声明:
void sayCom(CompanyStruct.ByReference struct);
调用如下:
TestJnaLib.CompanyStruct.ByReference companyStruct2=new TestJnaLib.CompanyStruct.ByReference(); companyStruct2.id=1000; companyStruct2.name=new String("xueerfei"); companyStruct2.count=10; TestJnaLib.UserStruct pUserStruct=new TestJnaLib.UserStruct(); pUserStruct.id=90; pUserStruct.name=new String("xueerfei"); pUserStruct.age=99; pUserStruct.write(); int offset = 0; for(int i=0;i<companyStruct2.users.length;i++){ companyStruct2.users[i]=pUserStruct; } TestJnaLib.INSTANCE.sayCom(companyStruct2);
因为函数是Reference声明,所以定义使用ByReference。(注意,如果在java里函数声明是一般声明,那么定义变量时也是用一般声明,虽然在DLL中是指针参数,但是调用DLL经测试是成功的,这点我很纳闷,可能在转换的时候java已经自动识别了吧,保险一下,还是显示的使用声明吧)
注意这里:
TestJnaLib.UserStruct pUserStruct=new TestJnaLib.UserStruct();不用显示的使用Reference,因为在定义的时候使用的是普通的new,所以这里也而且必须使用普通的变量定义。
这样调用就成功了。
其他的说明教程里都有讲的比较详细,就不多说了。
因为技术也在发展,所以教程里的某些东西可能因为更新而被修改,所以阅读的时候还需要自己再实际的测试使用才行。
相关文章推荐
- JNA java调用c/c++代码
- Java 调用 C/C++ 之 JNA 系列实战篇 —— 输出wchar_t* (三)
- cocos2d-x 中多线程的c/c++代码通过JNI调用java代码
- java程序如何调用C++代码
- 有关非Java代码(即Java调用C++中自然方法)的问题
- Cocos2d-x中通过JNI进行C++调用Java代码
- Java 调用 C/C++ 之 JNA 系列实战篇 —— 输出wchar_t** (四)
- Cocos2d-x中通过JNI进行C++调用Java代码
- 在java中调用c/c++代码的方法(jni)
- JNI_最简单的Java调用C/C++代码
- java调用C++代码-JNI的使用
- JNI NDK (AndroidStudio+CMake )实现C C++调用Java代码流程
- 从 C/C++ 程序调用 Java 代码
- java使用JNI调用C++代码(vs2010生成dll文件)
- Linux环境Java通过jni调用C++ OpenCv代码
- Cocos2d-x中通过JNI进行C++调用Java代码
- Java中如何调用C/C++代码
- Java 调用 C/C++ 之 JNA 系列实战篇 —— 输入char * (五)
- Cocos2d-x中通过JNI进行C++调用Java代码
- Cocos2d-x中通过JNI进行C++调用Java代码 JniHelper类的使用