javaproject-panama

Project Panama: can't find function


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)?


Solution

  • 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 of System.load(String) or System.loadLibrary(String) from code in a class defined by CL. ...

    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 chars or GetCurrentDirectoryW for wchar_ts directly:

    System.loadLibrary("Kernel32");
    SymbolLookup loaderSyms = SymbolLookup.loaderLookup();
    MemorySegment addr = loaderSyms.lookup("GetCurrentDirectoryA").orElseThrow();
    // use 'addr'