【问题标题】:renaming DLL functions in JNA using StdCallFunctionMapper使用 StdCallFunctionMapper 在 JNA 中重命名 DLL 函数
【发布时间】:2009-02-05 21:55:17
【问题描述】:

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

据我所知,这样做的方法是使用StdCallFunctionMapper,但我找不到有关如何在示例中使用它的文档(即如何按名称或序数将 DLL 函数映射到所需的名称在包装的 Java 库接口中)。有关文档在哪里的任何建议?

【问题讨论】:

    标签: java dll jna


    【解决方案1】:

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

    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】:

    使用 StdCallMapper 效果不佳 - 它应该映射具有嵌入参数的总字节长度作为名称的一部分嵌入的 werid 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

    【讨论】:

      【解决方案3】:

      根据文档,您需要在对 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);
      

      【讨论】:

      • 这是未经测试的。应该是 StdCallFunctionMapper 而不是 StdCallFunctionWrapper。而且没有 method.setName() 这样的东西。
      【解决方案4】:

      所有 JNA 文档都位于 primary web pageJavaDoc overviewJavaDocs 本身。

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

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

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

      【讨论】:

        猜你喜欢
        • 2021-11-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-06-05
        • 2012-02-22
        相关资源
        最近更新 更多