How to use GetProcAddress with JNA?

792 views Asked by At

First of all, i'm a JNA newbie. I would like to control my motherboard's LED lighting from java code. Asus provides an SDK for this purpose which is written in C (C++?).

Their header file looks simple:

#pragma once

#include <Windows.h>


typedef void* MbLightControl;
typedef void* GPULightControl;
typedef void* ClaymoreKeyboardLightControl;
typedef void* RogMouseLightControl;


typedef DWORD(WINAPI* EnumerateMbControllerFunc)(MbLightControl handles[], DWORD size);
typedef DWORD(WINAPI* SetMbModeFunc) (MbLightControl handle, DWORD mode);
typedef DWORD(WINAPI* SetMbColorFunc) (MbLightControl handle, BYTE* color, DWORD size);
typedef DWORD(WINAPI* GetMbColorFunc) (MbLightControl handle, BYTE* color, DWORD size);
typedef DWORD(WINAPI* GetMbLedCountFunc)(MbLightControl handle);

typedef DWORD(WINAPI* EnumerateGPUFunc)(GPULightControl handles[], DWORD size);
typedef DWORD(WINAPI* SetGPUModeFunc) (GPULightControl handle, DWORD mode);
typedef DWORD(WINAPI* SetGPUColorFunc) (GPULightControl handle, BYTE* color, DWORD size);
typedef DWORD(WINAPI* GetGPULedCountFunc)(GPULightControl handle);

typedef DWORD(WINAPI* CreateClaymoreKeyboardFunc)(ClaymoreKeyboardLightControl* handle);
typedef DWORD(WINAPI* SetClaymoreKeyboardModeFunc) (ClaymoreKeyboardLightControl handle, DWORD mode);
typedef DWORD(WINAPI* SetClaymoreKeyboardColorFunc) (ClaymoreKeyboardLightControl handle, BYTE* color, DWORD size);
typedef DWORD(WINAPI* GetClaymoreKeyboardLedCountFunc)(ClaymoreKeyboardLightControl handle);

typedef DWORD(WINAPI* CreateRogMouseFunc)(RogMouseLightControl* handle);
typedef DWORD(WINAPI* SetRogMouseModeFunc) (RogMouseLightControl handle, DWORD mode);
typedef DWORD(WINAPI* SetRogMouseColorFunc) (RogMouseLightControl handle, BYTE* color, DWORD size);
typedef DWORD(WINAPI* RogMouseLedCountFunc)(RogMouseLightControl handle);

I used JNAerator to get the JNA mappings, and this is the result i got:

import com.ochafik.lang.jnaerator.runtime.LibraryExtractor;
import com.ochafik.lang.jnaerator.runtime.MangledFunctionMapper;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.NativeLibrary;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.PointerByReference;
import com.sun.jna.win32.StdCallLibrary.StdCallCallback;

public interface Aura extends Library {

    String JNA_LIBRARY_NAME = LibraryExtractor.getLibraryPath("AURA_SDK", true, Aura.class);

    NativeLibrary JNA_NATIVE_LIB = NativeLibrary.getInstance(Aura.JNA_LIBRARY_NAME, MangledFunctionMapper.DEFAULT_OPTIONS);

    Aura INSTANCE = (Aura) Native.loadLibrary(Aura.JNA_LIBRARY_NAME, Aura.class, MangledFunctionMapper.DEFAULT_OPTIONS);

    interface EnumerateMbControllerFunc extends StdCallCallback {
        int apply(PointerByReference handles, int size);
    }

    interface SetMbModeFunc extends StdCallCallback {
        int apply(Pointer handle, int mode);
    }

    interface SetMbColorFunc extends StdCallCallback {
        int apply(Pointer handle, Pointer color, int size);
    }

    interface GetMbColorFunc extends StdCallCallback {
        int apply(Pointer handle, Pointer color, int size);
    }

    interface GetMbLedCountFunc extends StdCallCallback {
        int apply(Pointer handle);
    }

    interface EnumerateGPUFunc extends StdCallCallback {
        int apply(PointerByReference handles, int size);
    }

    interface SetGPUModeFunc extends StdCallCallback {
        int apply(Pointer handle, int mode);
    }

    interface SetGPUColorFunc extends StdCallCallback {
        int apply(Pointer handle, Pointer color, int size);
    }

    interface GetGPULedCountFunc extends StdCallCallback {
        int apply(Pointer handle);
    }

    interface CreateClaymoreKeyboardFunc extends StdCallCallback {
        int apply(PointerByReference handle);
    }

    interface SetClaymoreKeyboardModeFunc extends StdCallCallback {
        int apply(Pointer handle, int mode);
    }

    interface SetClaymoreKeyboardColorFunc extends StdCallCallback {
        int apply(Pointer handle, Pointer color, int size);
    }

    interface GetClaymoreKeyboardLedCountFunc extends StdCallCallback {
        int apply(Pointer handle);
    }

    interface CreateRogMouseFunc extends StdCallCallback {
        int apply(PointerByReference handle);
    }

    interface SetRogMouseModeFunc extends StdCallCallback {
        int apply(Pointer handle, int mode);
    }

    interface SetRogMouseColorFunc extends StdCallCallback {
        int apply(Pointer handle, Pointer color, int size);
    }

    interface RogMouseLedCountFunc extends StdCallCallback {
        int apply(Pointer handle);
    }
}

In the example C++ code they use GetProcAddress to obtain the address to the above methods, and that way they can call them:

HMODULE hLib = nullptr;

hLib = LoadLibraryA("AURA_SDK.dll");

(FARPROC&)EnumerateMbController = GetProcAddress(hLib, "EnumerateMbController");

DWORD _count = EnumerateMbController(NULL, 0);

How do i do the same with JNA?

Thanks in advance.

1

There are 1 answers

1
Matthias Bläsing On BEST ANSWER

I don't know why the header files look as they do, but based on the C sample you provided, the function EnumerateMbController that resides in the library AURA_SDK is called with two parameters - the first one being an array of MbLightControl (these are opaque pointers) and the second an that represents the "size".

I would deduce from context:

  • The MbLightControl array will receive the pointers
  • size is the size of the array you provide
  • the return value of the function will be the number of MbLightControl entries really returned

The call with NULL indicates, that it will return the number of MbLightControl instances it would return.

My suggestion for the correct binding:

public interface Aura extends StdCallLibrary {

    Aura INSTANCE = Native.loadLibrary("AURA_SDK", Aura.class, W32APIOptions.DEFAULT_OPTIONS);

    public static class MbLightControl extends WinDef.PVOID {}

    public int EnumerateMbController(MbLightControl[] handles, int size);
    public int SetMbMode(MbLightControl handle, int mode);
    public int SetMbColor(MbLightControl handle, byte[] color, int size);
    public int GetMbColor(MbLightControl handle, byte[] color, int size);
    public int GetMbLedCount(MbLightControl handle);
}

This loads the dll called AURA_SDK and makes five functions accessible. It also mimics the typedef in the header files for MbLightControl. The DWORDs are bound as java ints to make calling easier, as an int in java is always 32 Bit and a DWORD on Windows is the same.

I don't know the details of the color codes, but if these are RGB leds, then I assume, that each LED will occupy 3 bytes in the byte array.

It might help to know, that under the hood JNA used LoadLibraryEx (the big brother of LoadLibrary) and also GetProcAddress to load functions.