使用 StdCallFunctionMapper 重命名 JNA 中的 DLL 函数

发布于 2024-07-13 10:04:41 字数 408 浏览 7 评论 0原文

我尝试在 Windows 中将 JNA 与 DLL 一起使用,到目前为止,我能够成功调用名为 c_aa_find_devices() 的函数。 但所有函数都以 c_aa 开头,我想将其重命名为 find_devices()

据我所知,执行此操作的方法是使用 StdCallFunctionMapper 但我找不到如何在示例中使用它的文档(即如何按名称或序号将 DLL 函数映射到包装的 Java 库接口中的所需名称) 。 关于文档在哪里有什么建议吗?

I'm trying to use JNA with a DLL in Windows, so far I was able to successfully call a function called c_aa_find_devices(). But all the functions start with c_aa and I would like to rename it to find_devices().

From what I gather the way to do this is with StdCallFunctionMapper but I can't find the documentation of how to use it in an example (i.e. how to map a DLL function by name or by ordinal to a desired name in the wrapped Java library interface). Any suggestions on where the docs are?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

小矜持 2024-07-20 10:04:41

使用函数映射器的完整工作示例。

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
    }


}

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
    }


}
苦妄 2024-07-20 10:04:41

使用 StdCallMapper 效果不佳 - 它应该映射奇怪的 Windows std lib 名称,这些名称嵌入了作为名称一部分嵌入的参数的总字节长度。 因为它仅针对 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

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

£烟消云散 2024-07-20 10:04:41

根据文档,您需要在对 loadLibrary 的原始调用中提供一个 FunctionMapper 来转换名称。 但是,您还需要保留标准调用映射,因此请尝试以下操作:

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

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);
唐婉 2024-07-20 10:04:41

所有 JNA 文档均位于 主网页JavaDoc 概述,以及 JavaDocs 本身。

上面的示例是正确的想法,因为您需要调整通用 StdCallFunctionMapper 返回的函数名称(假设您使用的是 stdcall 调用约定)。 但是,Method.setName() 不存在,如果存在,您也不会想调用它。 您需要获取字符串结果,并将其中的 Java 函数名称替换为目标本机名称,例如,

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

更一般地,您可以简单地在返回的名称上添加“c_aa_”前缀(或在任何前导下划线之后),因为stdcall 装饰位于名称末尾。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文