Recently I am working on a small program and need to use Java to call the DLL. The technology used is JNA.
The specific content is found on the internet, but many posts have similar content, and there are some problems, and I don't know if it is a version issue. Anyway, the code will take a copy of various problems, after a long time, I finally came up with an eye and wrote it to share it with you.
First, the C/C ++ code is as follows:
extern "C" _declspec(dllexport) int add(int first, int second);
Implementation Code:
int add(int first, int second) {printf("(c) test jna : %d + %d = %d\n", first, second, first + second);return first + second;}
Package it into a DLL and copy it to the bin directory of the Java project,
When using Java, You need to first import the JNA package, which is available on the Internet during the process. Then you need to add the following in the Code:
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;
The call code is as follows:
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); }
Okay. The first one has no problem. Pass.
Try struct now:
Add these to the DLL Project (used in the tutorial ):
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);}
According to the tutorial, The encapsulation and calling rules are as follows:
public static class UserStruct extends Structure { public int id; public String name; public int age; public static class ByReference extends UserStructimplements Structure.ByReference { } public static class ByValue extends UserStruct implements Structure.ByValue{ }@Overrideprotected List getFieldOrder() {List a = new ArrayList(); a.add("id"); a.add("name"); a.add("age"); return a;} }
Note that the getfieldorder function is not mentioned in the teaching process. Therefore, an error is reported during compilation. You have to implement the function and check whether the list returns the variable name in the encapsulated struct, this must not be reversed (whether it is a basic variable, a struct variable, or an array or something, you only need to add a name ).
Call the function declaration:
void sayUser(UserStruct.ByReference struct);
About:
public static class ByReference extends UserStructimplements Structure.ByReference { } public static class ByValue extends UserStruct implements Structure.ByValue{ }
The two parameters need to be mentioned. In this tutorial, the displayed values or references are used. If this parameter is removed, it is not affected, provided that the variables are defined as follows:
TestJnaLib.UserStruct userStruct=new TestJnaLib.UserStruct();
After testing, this write operation has no impact on the result. The DLL call is successful, but we recommend that you add it to make it more correct.
Test code:
Testjnalib. userstruct. byreference userstruct = new testjnalib. userstruct. byreference (); userstruct. id = 100; userstruct. age = 30; userstruct. name = new string ("Obama"); testjnalib. instance. sayuser (userstruct );
The Declaration is to pass the reference, so byreference is used for display.
Be sure to use userstruct. byreference when defining variables, because the function declares byreference. Must be consistent.
The following is the most problematic one: struct array:
Definition:
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);}
Nested struct:
In the tutorial, the call is encapsulated as follows:
public static class CompanyStruct extends Structure{public NativeLong id;public WString name;public UserStruct.ByValue[] users=newUserStruct.ByValue[100];public int count;}
However, an error is returned (except for the getfiledorder function ).
Looking back, it may be because of version issues. The posts and tutorials are for 4.0 years. Now JNA has been updated to, and some things may have been changed, so an error will be reported.
Try to define it like this: use the original method definition:
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 CompanyStructimplements Structure.ByReference { } public static class ByValue extends CompanyStruct implements Structure.ByValue{ }@Overrideprotected List getFieldOrder() {List a = new ArrayList(); a.add("id"); a.add("name"); a.add("count"); a.add("users"); return a;} }
No byvalue. If byvalue or byreferfece is used here, an error will be reported. Even if it has been compiled, the operation is also wrong (among them, there are a lot of strange issues such as invalid memory access ).
Think about it. In C mode, arrays are actually "connected" with pointers.
Function declaration:
void sayCom(CompanyStruct.ByReference struct);
The call is as follows:
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);
Because the function is a reference declaration, byreference is defined. (Note: If the function declaration in Java is a general declaration, a general declaration is also used to define variables. Although it is a pointer parameter in the DLL, it is successful to call the DLL, I am wondering about this. Maybe Java has automatically recognized it during the conversion. I 'd like to make sure that the usage statement is displayed)
Note:
TestJnaLib.UserStruct pUserStruct=new TestJnaLib.UserStruct();
You do not need to use reference for display. Because common new is used for definition, common variables must also be used here.
In this way, the call is successful.
Other instructions are described in detail in the tutorial.
Because the technology is also developing, some things in the tutorial may be modified due to updates. Therefore, you need to test and use them before reading.