【问题标题】:Java use JNA call dll error:Invalid memory accessJava使用JNA调用dll报错:内存访问无效
【发布时间】:2020-12-09 16:27:36
【问题描述】:

我想调用 dll 从硬件写入/读取。但是,我收到以下错误:

dll方法:

int NewKey(char *room,char *gate,char *stime,char *guestname,char *guestid, int  overflag, int Breakfast, long *cardno,char * track1,char * track2);

java方法:

int NewKey(String room, String gate,String time,String guestname,String guestid, int overflag, int Breakfast, NativeLongByReference cardno, String track1, String track2);

api文档显示cardno为out参数,track1,track2可以为null。

NativeLongByReference cardNo = new NativeLongByReference ();

int res = CLibrary.INSTANCE.NewKey("010001", "00", "201712021200201712031200", "Guest Name","Account No.", 0, 1, cardNo, null, null);

它不起作用。所以我用了一个简单的方法:

dll method :

int EraseCard (long  cardno,char * track1,char * track2);

java方法:

int EraseCard(NativeLong cardno, String  track1, String  track2); 

NativeLong a = new NativeLong(0L);

int res = CLibrary.INSTANCE.EraseCard (a, null, null);

它再次得到同样的错误:

Exception in thread "main" java.lang.Error: Invalid memory access
at com.sun.jna.Native.invokeInt(Native Method)
at com.sun.jna.Function.invoke(Function.java:383)
at com.sun.jna.Function.invoke(Function.java:315)
at com.sun.jna.Library$Handler.invoke(Library.java:212)
at A90PmsInterface.main(A90PmsInterface.java:104)

似乎只有当我尝试使用 dll 方法从硬件读取/写入硬件时才会出现该错误。

我该如何解决这个问题?

详情:win7 64位,jre1.8 32位,jna4.1

【问题讨论】:

  • 我刚刚看到您使用的是 32 位 java。我在 64 位操作系统和 32 位 java 之间进行了一些 c 字符串转换时遇到了一些麻烦。但是,它看起来加载正常。

标签: java c++ dll hardware jna


【解决方案1】:

如果您想从 dll 访问内存,则需要设置引用内存位置所需的正确数据类型。在指针对象上,您的 jna 应该对 char* 使用 ByteByReference,或者您也可以使用 PointerByReference 而不是将对象声明为字符串。使用 PointerByReference 将帮助您避免内存泄漏。

JNA Marshalling / Unmarshalling

是一个很好的起点。祝你好运!

编辑: Java 方法声明——(JNA XXByReference 使用示例)

public int E1K_DI_Reads(int connection, byte channel, byte channelCount, IntByReference value);

Java 用法 -

public int readDI(int connection, byte channel, byte count){
    IntByReference refValue = new IntByReference();
    lib.E1K_DI_Reads(connection, channel, count, refValue);
    int value = refValue.getValue();
    return value;
}

从你的例子:

int NewKey(PointerByReference room, PointerByReference gate,PointerByReference time,PointerByReference guestname,PointerByReference guestid, int overflag, int Breakfast, NativeLongByReference cardno, PointerByReference track1, PointerByReference track2);

您必须调整方法代码以获取实际的指针值。

【讨论】:

  • 我用谷歌搜索了 jna 映射,似乎 C "char *" 映射到 java "String"。我使用“String”调用“char *”作为输入变量的其他 jna 方法工作正常,除了那些涉及硬件读/写。这似乎不是“char *”问题。无论如何,谢谢!
  • 我只想使用“char *”作为没有输出参数的输入变量。方法“newKey”的唯一输出参数是“NativeLongByReference cardno”。这就是我只使用 NativeLongByReference 的原因。我试过了您对更改为如下指针的建议: String guestName = "GuestName";指针 guestNameP = new Memory(guestName.length() + 1); guestNameP.setString(0, guestName); PointerByReference guestNamePR = new PointerByReference(guestNameP);它不起作用。
  • 正在使用什么硬件设备?我的示例代码是如果您正在从设备读取。您还需要考虑什么是分配内存。如果它是 DLL,那么 PointerByReference 将起作用。如果它是 Java 代码并且您将指针传递给 DLL,那么您使用 new Memory(); 就在正确的轨道上;我想看看实际的 DLL 函数,这样它就不是猜谜游戏了。
  • 其实它是一种将信息写入卡片的设备。所以卡片可以在几天内打开酒店的门。这就是为什么dll有“newKey”方法和“EraseCard”方法的原因。当酒店客人登记入住时,我们调用 newkey 方法来创建一张卡片。当客人结帐时,我们会擦除卡片。
【解决方案2】:

我猜“MainDll”有多个依赖项。

当我将所有需要的依赖项 dll 放在项目文件夹根路径下并 使用相对路径加载我的dll,终于成功了。

    CLibrary INSTANCE = (CLibrary) Native.synchronizedLibrary((CLibrary) Native.loadLibrary("MainDll", CLibrary.class));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-28
    • 1970-01-01
    • 1970-01-01
    • 2021-11-16
    • 1970-01-01
    相关资源
    最近更新 更多