переименование функций DLL в JNA с использованием StdCallFunctionMapper - PullRequest
3 голосов
/ 06 февраля 2009

Я пытаюсь использовать JNA с DLL в Windows, поэтому мне удалось успешно вызвать функцию с именем c_aa_find_devices(). Но все функции начинаются с c_aa, и я хотел бы переименовать его в find_devices().

Исходя из того, что я понял, способ сделать это с StdCallFunctionMapper, но я не могу найти документацию о том, как использовать его в примере (то есть как сопоставить функцию DLL по имени или по порядковому номеру в имя обернутого интерфейса библиотеки Java). Любые предложения о том, где документы?

Ответы [ 4 ]

4 голосов
/ 13 мая 2009

Использование StdCallMapper не принесет пользы - оно должно отображать имена библиотек werid windows std, которые имеют общую длину байтов параметров, встроенных как часть имени. Так как это делается только для std lib (только догадываюсь об этом, но 99% ваших функций не в этом).

Если ваша dll использует какой-то общий префикс для всех функций, вам нужно просто использовать что-то вроде:

class Mapper implements FunctionMapper{
    public String getFunctionName(NativeLibrary library, Method method) {
       return GenieConnector.FUNCTION_PREFIX + method.getName();
    }
}

Где GenieConnector.FUNCTION_PREFIX - это общий префикс. Имейте в виду, что я реализую FunctionMapper, а не расширяю StdCallMapper

2 голосов
/ 24 февраля 2016

Полный рабочий пример с использованием функции отображения.

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.NativeLibrary;
import com.sun.jna.win32.StdCallFunctionMapper;

import java.io.File;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public class JnaTest {


    static {
    Map options = new HashMap();
        options.
                put(
                        Library.OPTION_FUNCTION_MAPPER,
                        new StdCallFunctionMapper() {
                            HashMap<String, String> map = new HashMap() {
                                {
                                    put("testMethod", "testMethod@0");
                                }
                            };
                            @Override
                            public String getFunctionName(NativeLibrary library, Method method) {
                                String methodName = method.getName();
                                return map.get(methodName);

                            }
                        }
                );

        File LIB_FILE = new File("test.dll");
        Native.register(NativeLibrary.getInstance(LIB_FILE.getAbsolutePath(), options));

    }

    private static native int testMethod();

    public static void main(String[] args) {
        testMethod(); // call the native method in the loaded dll with the function name testMethod@0
    }


}
2 голосов
/ 06 февраля 2009

Из документации вам необходимо предоставить FunctionMapper в исходном вызове loadLibrary, который преобразует имя. Однако вам также необходимо сохранить стандартное сопоставление вызовов, поэтому попробуйте что-то вроде следующего:

Map options = new HashMap();

options.
    put(
        Library.OPTION_FUNCTION_MAPPER, 
        new StdCallFunctionWrapper() {
            public String getFunctionName(NativeLibrary library, Method method) {
                if (method.getName().equals("findDevices") 
                    method.setName("c_aa_find_devices");
                // do any others
                return super.getFunctionName(library, method);
            }
        }
    );

Native.loadLibrary(..., ..., options);
1 голос
/ 12 мая 2009

Вся документация JNA находится на основной веб-странице , обзоре JavaDoc и самих JavaDocs .

Приведенный выше пример является правильной идеей, так как вам нужно настроить имя функции, возвращаемое универсальным StdCallFunctionMapper (при условии, что вы используете соглашение о вызовах stdcall). Однако Method.setName () не существует, и вы не захотите вызывать его, если он существует. Вам нужно получить результат String и заменить имя функции Java внутри него целевым собственным именем, например,

name = super.getFunctionName();
name = name.replace("find_devices", "c_aa_find_devices");

В более общем смысле, вы можете просто прикрепить префикс "c_aa_" к возвращенному имени (или после любого начального подчеркивания), так как украшения stdcall находятся в конце имени.

...