Introduction
In JNA, in order to map with native functions, we can have two mapping methods, the first is interface mapping, and the second is direct mapping. Although the two methods are different, in the specific method mapping, we all need to define a method in JAVA to map with the native method.
And this mapping in JAVA is a function in JNA. Through the or function object, we can achieve some very powerful functions, let's take a look.
Definition of function
Let's first look at the definition of Function in JNA:
public class Function extends Pointer
You can see that Function is actually a Pointer, which points to a pointer to a native function.
So how to get an instance of Function?
We know that the process of JNA is to map the Library first, and then map the Function in the Library. So naturally we should be able to get Function from Library.
Let's take a look at the method definition for getting a function instance based on the Library name:
public static Function getFunction(String libraryName, String functionName, int callFlags, String encoding) {
return NativeLibrary.getInstance(libraryName).getFunction(functionName, callFlags, encoding);
}
This method can accept 4 parameters. The first two parameters should be familiar to everyone. The third parameter is callFlags, which represents the flags of the function call. Function defines three callFlags:
public static final int C_CONVENTION = 0;
public static final int ALT_CONVENTION = 0x3F;
public static final int THROW_LAST_ERROR = 0x40;
Among them, C_CONVENTION represents the method call of the C language type.
Other calling methods represented by ALT_CONVENTION.
THROW_LAST_ERROR means that if the return value of the native function is non-zero, a LastErrorException will be thrown.
The last parameter is encoding, which indicates the encoding method of the string, which actually refers to the conversion method between Java unicode and native (const char*) strings.
In addition to getting Function based on Library name, JNA also provides a method to get Function based on Pointer.
public static Function getFunction(Pointer p, int callFlags, String encoding) {
return new Function(p, callFlags, encoding);
}
The Pointer here refers to a pointer that executes the native method, because Function itself is inherited from Pointer. So the essence of creating Function with Pointer is to add some Function-specific properties on the basis of Pointer.
With the definition of Function, the more important thing is how to call the corresponding method through Function. Similar to reflection, there is also an invoke method in Function. By calling invoke, we can execute the function of the corresponding Function.
There are two kinds of invoke methods in Function, one is a general return object Object, and the other is an invoke method with a return value, such as invokeString, invokePointer, invokeInt, etc.
Practical application of Function
The actual use of Function is somewhat similar to reflection in JAVA. The workflow is to first obtain the NativeLibrary to be loaded, then find the Function to be called from the NativeLibrary, and finally invoke some methods of the Function.
The printf in C language should be the most familiar native method. Let's see how to use Function to call this method:
NativeLibrary lib = NativeLibrary.getInstance(Platform.C_LIBRARY_NAME);
Function f = lib.getFunction("printf");
try {
f.invoke(getClass(), new Object[] { getName() });
fail("Invalid return types should throw an exception");
} catch(IllegalArgumentException e) {
// expected
}
You can see that the calling process is very simple. If it is in the form of interface Mapping or direct Mapping, we also need to customize an interface or class, and define a corresponding java method mapping in it. But if you use Function, none of this is needed. We can directly get the corresponding function from NativeLibrary, and finally call the method in it.
The prototype of printf in C language is as follows:
# include <stdio.h>
int printf(const char *format, ...);
If printf has a return value, if you want to output this return value, you can call the invokeInt command in Function. Let's look at another example of a call with a return value:
NativeLibrary lib = NativeLibrary.getInstance(Platform.C_LIBRARY_NAME);
Function f = lib.getFunction("printf");
Object[] args = new Object[Function.MAX_NARGS+1];
// Make sure we don't break 'printf'
args[0] = getName();
try {
f.invokeInt(args);
fail("Arguments should be limited to " + Function.MAX_NARGS);
} catch(UnsupportedOperationException e) {
// expected
}
Summarize
Using Function can reduce the work of handwritten Mapping, which is very useful in some cases, but Function's invoke supports TypeMapper and does not support FunctionMapper, so there are still some limitations in use.
You can consider it as appropriate during the use process.
This article has been included in http://www.flydean.com/07-jna-function/
The most popular interpretation, the most profound dry goods, the most concise tutorials, and many tricks you don't know are waiting for you to discover!
Welcome to pay attention to my official account: "Program those things", understand technology, understand you better!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。