java JNA的行为与我的C#对手不同,为什么?
我正在为一个硬件开发一些东西,我有一个C库来与硬件通信。我有一些方法可以向硬件发送信号(比如打开灯泡),这些方法在使用JNA的C#和Java上都可以正常工作
机器还有一个可按下的按钮,当按下该按钮时,它将记录一个信号,该信号可通过一种称为a的方法检索
其工作方式是创建一个新线程,该线程不断调用此方法,直到返回1为止,在这种情况下,它将具有有关按钮按下的信息
我在C#中使用了以下代码:
while (true)
{
byte[] ccbdata = new byte[255];
short TagCommand = -1, nMsg_type = -1;
int ccblen = 0, nGwId = 0, nNode = 0;
int ret = CWrapper.Wrapper.A(ref nGwId, ref nNode, ref TagCommand, ref nMsg_type, ref ccbdata[0], ref ccblen);
if (ret > 0)
{
// do stuff
}
Thread.Sleep(100);
}
方法以C#形式导入时,如:
[DllImport("Clibrary.dll")]
public static extern int C(ref int Gateway_ID, ref int Node_Addr, ref short Subcmd, ref short msg_type, ref byte data, ref int data_cnt);
我希望这段代码也能在Java上运行。不幸的是,当我用java运行它时,它从未像C#实现那样返回1
我想知道我是否做错了什么,因为我没有使用JNA的经验。在Java中,我导入如下方法:
int C(LongByReference gatewayID, LongByReference tag_addr, LongByReference Subcmd, LongByReference msg_type,
ByteByReference data, LongByReference data_cnt);
我试着这样运行代码:
while(run) {
gatewayID.setValue(0);
tag_addr.setValue(0);
subcmd.setValue(-1);
msg_type.setValue(-1);
byte b = 0;
data.setValue(b);
data_cnt.setValue(0);
int ref = CWrapper.INSTANCE.C(gatewayID, tag_addr, subcmd, msg_type, data, data_cnt);
if (ref > 0) {
System.out.println("hit");
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
在我关于此方法的文档中,它是用C定义的,如:
C(ByRef gatewayID As Integer, ByRef tag_addr As Integer, ByRef subcmd As Integer, ByRef msg_type As Integer, ByRef data As Byte, ByRef data_cnt As Integer)
有人知道为什么C#示例有效,而Java示例无效吗
--编辑25-08-2021 12:04
文件中说,使用了提供给该方法的参数。所以我想,如果它们为null,那么该方法将不会返回任何内容。使用ByReference对象的初始化可能是错误的
--编辑26-08-2021
我得到了C++签名,即:
typedef int (__stdcall *pC)(int& Gateway_ID, int& Node_Addr, short& Subcmd,
short& Msg_Type, unsigned char* Data, short& Data_Cnt);
# 1 楼答案
具有给定的C签名:
我要这样装订:
C上的int在重要的地方应该是32位的,因此它可以清晰地映射到javaint,因为所有参数都是通过引用传递的IntByReference是您的朋友。short和ShortByReference也是如此(只是比特数不同)
这就留下了数据和数据会发生什么的问题。我猜,该数据是一个缓冲区,函数在其中放置数据(调用C是一个拉操作)。该缓冲区的长度为255字节(我假设,这是作为库的一项要求而记录的)。现在,当pull操作成功时,我希望数据被写入缓冲区backingdata,接收的数据量被写入data\u Cnt。现在,调用方(Java)可以读取传输的数据量(data_Cnt.getValue()),并从字节[]读取这么多数据。Java数组通过引用传递-JNI创建数组的副本,将其传递给函数,函数运行,数据被复制回数组
下面是您应该始终创建最小可运行示例的原因:
您跳过了绑定的重要部分。C签名有一个u stdcall标记。这改变了呼叫约定。从StdCallLibrary派生应该可以解决这个问题
# 2 楼答案
在java中,long是8个字节,您的c#代码使用
ref int
,即4个字节你试过使用
IntByReference
吗