Functions
com.etdon.winj.function
One of the primary features of the library is the implementation of native function bindings. Those bindings allows you to easily build and call functions exported by native libraries.
Calling
In order to call a native function with (or without) an existing binding you should use a NativeCaller
. The default constructor takes both a Linker
as well as a SymbolLookupCache
as its parameters. If you already created a WindowsAPI
instance however, you can access a shared instance using its ServiceProvider
available through the #getServiceProvider
method:
try (final Arena arena = Arena.ofConfined()) {
final WindowsAPI windowsAPI = WindowsAPI.of(arena);
final ServiceProvider serviceProvider = windowsAPI.getServiceProvider();
final NativeCaller nativeCaller = serviceProvider.get(NativeCaller.class);
}
The #call
method of NativeCaller
takes a NativeFunction
as its only parameter. NativeFunction
is the abstract parent of all native functions with an implemented binding. This is how you can use your obtained NativeCaller
to - for example - call the GetForegroundWindow
function of the user32
system library:
try (final Arena arena = Arena.ofConfined()) {
final WindowsAPI windowsAPI = WindowsAPI.of(arena);
final ServiceProvider serviceProvider = windowsAPI.getServiceProvider();
final NativeCaller nativeCaller = serviceProvider.get(NativeCaller.class);
nativeCaller.call(GetForegroundWindow.getInstance());
}
Bindings for functions with parameters always feature a fluent builder that allows for easy construction of complex calls while respecting optional parameters and other properties of the function:
final MemorySegment windowHandle = (MemorySegment) nativeCaller.call(
OpenProcess.builder()
.access(ProcessAccessRight.PROCESS_ALL_ACCESS)
.inheritHandle(false)
.processId(12345)
.build()
);
As you can see in the provided example named constants exist for all relevant types and functions with implemented bindings. References to the classes that hold these constants can be found in the corresponding Javadoc comments.
In case the function you're trying to call doesn't have an implemented binding yet, you can use a GenericFunction
instance instead. The way you call a GenericFunction
doesn't differ from an implemented one, however, the building works slightly differently. Instead of having named builder methods for every component you'll have to provide the library name, function name, potential return type and all parameter instances (or their MemoryLayout
in case they are null
) instead:
GenericFunction.builder()
.library(Library.KERNEL_32)
.name("CloseHandle")
.returnType(boolean.class)
.parameter(handlePointer)
.build();
Last updated