【问题标题】:Copying data from a DLL to a ByteBuffer (JNA)将数据从 DLL 复制到 ByteBuffer (JNA)
【发布时间】:2021-04-14 02:08:24
【问题描述】:

我正在将使用 ctypes 的 Python 脚本移植到 Java。

脚本的一部分将数据从 DLL 的虚拟内存复制到缓冲区,该缓冲区存储所述数据以便稍后复制回来。我不确定如何在 JNA 中完成此操作。

我确实有存储我想要的数据的虚拟地址的确切值,但我不确定如何获取指向这些虚拟地址的指针,因为 JNA 的 Javadoc 从未指定指针是否与系统相关内存或 DLL 内存。

如何在 Java 中设置一个指向指定(虚拟)内存地址的指针?在 Python 中,可以使用dll._handle + address 设置正确的值。

【问题讨论】:

  • 只是一个旁注,但我注意到handle 存在某个私有字段NativeLibrary。我不确定这是否是我要找的地址,但我认为是。
  • 加载后可以从库的toString()中提取handle的值。
  • 会指向基址吗?我发现这比通过 Windows API 更方便。
  • 它将指向 DLL 的基地址。但是,我不能保证 DLL 会被加载到连续的内存中。使用风险自负!
  • 似乎当我设置一个指针指向正确的地址并尝试写入它时,JNA 给了我一个无效的内存访问错误。这就是 JNA 的工作原理吗?

标签: java dll jna


【解决方案1】:

JNA 的 Pointer 类间接(全局)系统内存,等效于 C 的 &foo 表示法,用于指向唯一的全局系统范围内存地址 foo

该类有一个Pointer(long peer) 构造函数,它将实际的本机内存地址作为参数。 (您也可以使用Pointer.nativeValue() 提取此值。)这通常不需要,因为用户通常不必担心特定的内存地址。正如 Javadoc 所述:

除非你知道自己在做什么,否则不要使用它。

除此之外,如果您需要一个相对于其他基点的虚拟地址,您需要找到合适的特定于平台的函数,该函数可以为您识别该本地指针地址。例如,在 Windows 中,您将使用 GetModuleInformation()Psapi接口中用户贡献的JNA映射(jna-platform工件)中的This is mapped,也可以自己映射。使用该方法获得的 MODULEINFO 结构将包含 DLL 的起始地址,并且您可以添加一个偏移量,尽管它似乎与 HMODULE 输入相同,所以您可能只需要调用 EnumProcessModules() . This other answer 提供了执行此操作所需的代码(尽管我将 long 用于 64 位指针)。

请注意 JNA 的 Psapi 类中的 cautions in the Javadoc

如果目标进程中的模块列表已损坏或尚未初始化,或者在函数调用期间由于加载或卸载 DLL 而导致模块列表发生更改,则 EnumProcessModules 可能会失败或返回错误信息。

还有很多注意事项。

更新:根据您的评论,已加载 DLL 的 handle 公开在库的 toString() 中。例如:

Kernel32 foo = Kernel32.INSTANCE;
System.out.println(foo.toString());

会回来

原生库 kernel32.dll@140737217757184 的代理接口

再说一遍,“除非你知道自己在做什么,否则不要使用它。”

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-30
    • 2014-05-06
    • 2016-04-03
    相关资源
    最近更新 更多