[WIN11 - Java 21] GetProcAddress by name issue

23 views
Skip to first unread message

Ocean Breath

unread,
Oct 20, 2025, 9:19:12 AMOct 20
to Java Native Access
Hi to all,
I experience an unexpected behavior if I call the GetProcAddress function, passing it the name of a function exported from a DLL. The DLL itself is very simple:

#include "windows.h"
#include <iostream>
#include <mutex>

static std::mutex load_mutex;
extern "C" __declspec(dllexport)
BOOL __cdecl test()
{
    std::cerr << "[TEST MUTEX] start" << std::endl;
    std::lock_guard<std::mutex> lock(load_mutex); //crash here
    std::cerr << "[TEST MUTEX] passed" << std::endl;
    return TRUE;
}

and I use it from Java with this code:

import com.sun.jna.Function;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.WString;
import com.sun.jna.win32.W32APIOptions;

public class Probe {
    public interface Kernel32Ext extends Library {

        Kernel32Ext INSTANCE = Native.load("kernel32", Kernel32Ext.class, W32APIOptions.DEFAULT_OPTIONS);

        Pointer LoadLibraryW(WString lpFileName);
        Pointer GetProcAddress(Pointer hModule, String lpProcName);
        Pointer GetProcAddress(Pointer hModule, Pointer ordinal);
    }
    public static void main(String[] args) {
        Pointer hDll = Kernel32Ext.INSTANCE.LoadLibraryW(new WString("test-mutex.dll"));

        if (hDll == null) {
            int err = Native.getLastError();
            throw new IllegalStateException("LoadLibraryExW failed: " + err);
        }

        System.out.println("DLL loaded with handle: " + hDll);

        Pointer ordinalPtr = Pointer.createConstant(1);
        //Pointer fnPtr = Kernel32Ext.INSTANCE.GetProcAddress(hDll, ordinalPtr);
        Pointer fnPtr = Kernel32Ext.INSTANCE.GetProcAddress(hDll, "test");
        if (fnPtr == null) {
            throw new IllegalStateException("GetProcAddress failed, error: " + Native.getLastError());
        } else {
            Function f = Function.getFunction(fnPtr, Function.C_CONVENTION);
            f.invoke(null);
        }
    }
}

If I use the version of GetProcAddress that passes the function name, I get an error 127 (ERROR_PROC_NOT_FOUND), but if I use the ordinal instead, I can retrieve the function address and execute it.

I've checked several trivial error sources using tools like the Dependencies program, dumpbin, and PE-bear, without finding any problems with the DLL. I've written a small C++ program that uses the same instructions as the Java program:

#include <windows.h>
#include <iostream>
#include <string>

int main(int argc, char* argv[]) {
    std::cout << "[TEST] Loading DLL..." << std::endl;

    HMODULE hDll = LoadLibraryExW(L"test-mutex.dll", NULL, 0);
    if (!hDll) {
        std::cerr << "[TEST] LoadLibrary failed" << std::endl;
        return -1;
    }

    typedef BOOL(__cdecl* TestFunc)();
    TestFunc test = (TestFunc)GetProcAddress(hDll, "test");

    if (!test) {
        std::cerr << "[TEST] GetProcAddress failed: "  << GetLastError() << std::endl;
        return -2;
    }
    else {
        std::cout << "[TEST] Calling test()..." << std::endl;
        BOOL result = test();
        std::cout << "[TEST] Result: " << result << std::endl;
    }
    return 0;
}

and I haven't encountered any problems with the same DLL. Incidentally, the mutex instruction crashes in Java, but not in C++, but that's another topic. But, if anyone has an explanation for this, it would be welcome. 

Does anyone know why the name resolution problem occurs? I also tried declaring GetProcAddress as:

Pointer GetProcAddress(Pointer hModule, byte[] lpProcName)

and calling it with 

fnPtr = Kernel32Ext.INSTANCE.GetProcAddress(hDll, "test".getBytes(StandardCharsets.ISO_8859_1))

but sometimes it works for the first function, but if I have other functions, it no longer works.

Thanks for any helpful hints.

Ocean

L Will Ahonen

unread,
Oct 20, 2025, 1:23:43 PMOct 20
to Java Native Access
My crystal ball says your mutex crash is this mutex issue

You can solve it with a simple preprocessor define.

Did you try null-terminating your function name, so ”hello\0”.getbytes(ascii)

Matthias Bläsing

unread,
Oct 20, 2025, 1:39:40 PMOct 20
to jna-...@googlegroups.com
Hi,
If this is not just "I want to learn" code, this is awfully hard and can be simplified to:

import com.sun.jna.Function;
import com.sun.jna.NativeLibrary;

public class Probe {

    public static void main(String[] args) {
        NativeLibrary hDll = NativeLibrary.getInstance("test-mutex.dll");
        Function f = hDll.getFunction("test", Function.C_CONVENTION);
        f.invoke(null);
    }
}



and I haven't encountered any problems with the same DLL. Incidentally, the mutex instruction crashes in Java, but not in C++, but that's another topic. But, if anyone has an explanation for this, it would be welcome. 

Will hinted the problem solution, try to run with the Microsoft JDK. @work we saw crashes in the ONNXRuntime, which occured on Amazon Corretto, but was fixed on the MS JDK. I suspect that MS bundles a newer C++ runtime.

Does anyone know why the name resolution problem occurs? I also tried declaring GetProcAddress as:

Pointer GetProcAddress(Pointer hModule, byte[] lpProcName)

and calling it with 

fnPtr = Kernel32Ext.INSTANCE.GetProcAddress(hDll, "test".getBytes(StandardCharsets.ISO_8859_1))

but sometimes it works for the first function, but if I have other functions, it no longer works.


This is the correct binding. W32APIOptions implies a mapping of java string to native wchar[]. That is right for most of the windows api, but not here.

As Will also already pointed out, you are missing the NULL terminator for the string. Have a look at Native#toByteArray.

Greetings

Matthias

Ocean Breath

unread,
Oct 20, 2025, 1:55:36 PMOct 20
to Java Native Access
Thanks for the helpful tips. Yes, I tried using the directive you mentioned, and it does indeed solve this specific problem. Adding the termination, however, solves the problem of functions not being found.
Reply all
Reply to author
Forward
0 new messages