renaming DLL functions in JNA using StdCallFunctionMapper

时光怂恿深爱的人放手 提交于 2019-11-30 07:36:21

Using StdCallMapper won't do good - it is supposed to map werid windows std lib names that have embedded total byte lenght of parameters embedded as part of the name. Since it is done to std lib only (just guessing on that, but 99% you'r functions are not the case).

If your dll uses some common prefix on all functions you need just to use something like:

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

Where GenieConnector.FUNCTION_PREFIX is that common prefix. Bear in mind that i implement FunctionMapper, not extend StdCallMapper

A complete working example, using a function mapper.

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
    }


}

From the documentation you need to provide a FunctionMapper in the original call to loadLibrary that converts the name. However you also need to keep the standard call mapping so try something like the following:

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

All JNA documentation is located at the primary web page, the JavaDoc overview, and the JavaDocs themselves.

The example above is the right idea, in that you need to tweak the function name returned by the generic StdCallFunctionMapper (assuming you're using the stdcall calling convention). However, Method.setName() doesn't exist and you wouldn't want to call it if it did. You'll need to get the String result and replace the Java function name within it with the target native name, e.g.

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

More generically, you can simply tack on a "c_aa_" prefix to the returned name (or after any leading underscore), since stdcall decorations are at the end of the name.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!