【问题标题】:JNA cannot find functionJNA 找不到函数
【发布时间】:2012-04-24 05:44:09
【问题描述】:

JNA 和 DLL 对我来说是全新的领域...我有一个自定义 DLL,它有一个带有此声明的函数:

int myfunc (const char*);

使用以下命令在 MinGW 下 dll 可以正常编译:

>gcc -shared -omydll.dll mydll.c -lgdi32

但是,使用 JNA 加载它会失败,因为它在 DLL 中找不到函数。

public interface mydll extends StdCallLibrary {
  mydll INSTANCE = (mydll)Native.loadLibrary("mydll", mydll.class);
  int myfunc (String arg);
  }

我做了一些研究,似乎这个特定的错误与 DLL 函数的调用过程有关。我见过__stdcall__cdecl 程序。我还看到许多 DLL 函数将__declspec(dllexport) 放在它们的函数声明/实现之前(我不知道这是什么意思或它的作用)。所以,由于 JNA 似乎更喜欢 __stdcall 过程,现在我的函数看起来像这样:

__declspec(dllexport) int __stdcall myfunc (const char*);

这看起来超级复杂,但并不比我尝试过的任何其他方法更好。使用 HashMap 添加下划线前缀和@4 后缀也不起作用:

mydll INSTANCE = (mydll)Native.loadLibrary("mydll", mydll.class, new HashMap () {{
  add("myfunc", "_myfunc@4");
  }});

JNA 文档完全没有帮助。老实说,我已经不知道自己在做什么了。

【问题讨论】:

  • 从字面上看,您遇到了什么特别的错误?
  • 你设置-Djna.library.path=<path location of your DLLs/libraries>了吗?
  • 您应该提供您看到的实际异常,这将指出问题所在。
  • 遵循 Java 约定并使用大写字母和大小写混合命名类(例如 MyDLL.class)。如果您不这样做,则表明您是 Java 新手,并没有真正关注。
  • 除非有特定理由,否则不要使用 stdcall。如果你确实使用了stdcall,你可以通过告诉gcc使用“-Wl,add-stdcall-alias”来包含未修饰的名称来避免函数映射器。

标签: java c dll jna unsatisfiedlinkerror


【解决方案1】:

事实证明,我的 DLL 构建得很好,而 JNA 发现我的 DLL 也很好;我在确定编译器如何破坏我的符号时出错。我命名为myfunc 的函数导出为myfunc@8myfunc@32,具体取决于它们作为参数的字节数。这是我在 JNA 项目中使用的代码:

import java.util.*;
import com.sun.jna.*;
import com.sun.jna.win32.*;
//
public class Test
  {
  public interface mydll extends StdCallLibrary
    {
    mydll INSTANCE = Native.loadLibrary("mydll", mydll.class, new HashMap {{
      put("myfunc", "myfunc@8");
      //Other functions
      }});
    public int myfunc (long arg);
    //Other functions
    }
  //
  public static void main (String[] args)
    {
    System.out.println
      (mydll.INSTANCE.myfunc((long)0x23A3920F)); //Or whatever
    return 0;
    }
  }

我的c代码:

#include <windows.h>
#include <stdio.h>

__declspec(dllexport) int __stdcall myfunc (__int64);
/* Other functions */

__declspec(dllexport) int __stdcall myfunc (__int64 arg)
  {
  /* Whatever */
  return return_value;
  }

GCC 对 -shared 开关和链接到正确的库感到满意,就像我原来的问题一样。 我强烈建议您下载this tool,这样您就可以准确了解您的函数名称。

【讨论】:

  • JNA 提供了一个 StdCallFunctionMapper 来手动执行您一直在执行的操作,尽管我仍然建议您放弃 std 调用并改用标准 C 调用约定。
【解决方案2】:

查看 JNA 中的测试库是如何构建的(本机/Makefile)。遵循该示例将指示正确的导出签名和调用约定。

__declspec(dllexport)表示要导出函数名。

__stdcall 是大多数 MS API 使用的;你通常没有理由在你自己的代码中使用它,因为它只会使链接变得复杂,因为它的名称被修改了。

在实际编译(和链接)时,您需要告诉 GCC 您正在构建一个共享库。仅将文件命名为“*.dll”是不够的。

gcc -o mydll.dll -shared mydll.c 

您可能需要一个或多个 -l&lt;libname&gt; 最后选项,具体取决于您访问的本机库。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-24
    • 2012-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多