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