I'm trying Project Panama (foreign function interface) of Java 19 with following code to read the current directory on Windows 10 (as a simple example). This is the begin of my code:
final Linker linker = Linker.nativeLinker();
final SymbolLookup linkerLookup = linker.defaultLookup();
final SymbolLookup systemLookup = SymbolLookup.loaderLookup();
final SymbolLookup symbolLookup = name -> systemLookup.lookup(name)
.or(() -> linkerLookup.lookup(name));
final MemorySegment addr = symbolLookup.lookup("GetCurrentDirectory")
.orElse(null);
...
The problem is, when debugging addr
is null
, so it looks like it can't find the method by this name. Do I somehow need to tell the lookup in what DLL it should look for this function (for a test with printf
this was not necessary)?
Do I somehow need to tell the lookup in what DLL it should look for this function
Yes, you have to load the library that contains GetCurrentDirectory
, which is Kernel32
(according to the documentation):
System.loadLibrary("Kernel32");
After loading a library with System::load
or System::loadLibrary
, it can be found using the loader lookup (i.e. SymbolLookup.loaderLookup()
). See the documentation:
Returns a symbol lookup for symbols in the libraries associated with the caller's class loader.
A library is associated with a class loader
CL
when the library is loaded via an invocation ofSystem.load(String)
orSystem.loadLibrary(String)
from code in a class defined byCL
. ...
Note that System::loadLibrary
also requires the directory that contains the library to be listed in the java.library.path
system property (you will get an exception if it's not). For Kernel32
this should be C:\Windows\System32
(for a test with printf this was not necessary)?
The reason it works for printf
is because you are using the defaultLookup
of the nativeLinker
which can find all the symbols in the standard C library. GetCurrentDirectory
is not a part of that library though.
Furthermore, it looks like GetCurrentDirectory
is defined as __inline
, which means you can not link against it dynamically, as the symbol/function is simply not present in Kernel32.dll
, AFAICT:
> dumpbin.exe /EXPORTS C:\Windows\System32\kernel32.dll | sls GetCurrentDirectory
555 22A 0001F010 GetCurrentDirectoryA
556 22B 00018CA0 GetCurrentDirectoryW
Instead, you have to look up and call GetCurrentDirectoryA
for char
s or GetCurrentDirectoryW
for wchar_t
s directly:
System.loadLibrary("Kernel32");
SymbolLookup loaderSyms = SymbolLookup.loaderLookup();
MemorySegment addr = loaderSyms.lookup("GetCurrentDirectoryA").orElseThrow();
// use 'addr'