如何使用jnr-ffi将以下功能映射到Java?
BOOLEAN PacketRequest(LPADAPTER AdapterObject,BOOLEAN设置,PPACKET_OID_DATA OidData);
public interface NativeMappings {
public static class PPACKET_OID_DATA extends Struct {
public final UnsignedLong Oid = new UnsignedLong();
public final UnsignedLong Length = new UnsignedLong();
public final byte[] Data = new byte[6];
public PPACKET_OID_DATA(Runtime runtime) {
super(runtime);
}
}
Pointer PacketOpenAdapter(String AdapterName);
int PacketRequest(Pointer AdapterObject, int set, @Out PPACKET_OID_DATA OidData);
void PacketCloseAdapter(Pointer lpAdapter);
public static class Main {
public static void main(String[] args) {
NativeMappings mappings = LibraryLoader.create(NativeMappings.class).load("Packet");
Runtime runtime = Runtime.getRuntime(mappings);
Pointer adapterObject = mappings.PacketOpenAdapter("\\Device\\NPF_{53152A2F-39F7-458E-BD58-24D17099256A}");
PPACKET_OID_DATA oid_data = new PPACKET_OID_DATA(runtime);
oid_data.Oid.set(0x01010102L);
oid_data.Length.set(6L);
int status = mappings.PacketRequest(adapterObject, 0, oid_data);
if (status == 0) {
System.out.println("Fail.");
} else {
System.out.println("Success.");
}
mappings.PacketCloseAdapter(adapterObject);
}
}
}
答案 0 :(得分:0)
首先要进行适当的映射,您应该查看要映射的类型的定义。 PacketRequest
函数返回BOOLEAN
变量。根据{{3}},BOOLEAN
被声明为typedef BYTE BOOLEAN;
。这意味着,您可以在Java中使用byte
类型作为函数类型。但是JNR还支持将boolean
类型映射到本地byte
或从本地byte PacketRequest (...)
映射。所以这两个定义都是正确的:
boolean PacketRequest (...)
boolean PacketRequest(Pointer AdapterObject, boolean set, PPACKET_OID_DATA OidData);
接下来,您需要映射参数。同样,在这里查看定义,您将知道要使用的类型。结果将是:
set
int
参数被错误地声明为@Out
。此外,最后一个字段的PPACKET_OID_DATA
批注告诉JNR传递一个空结构而不将值复制到本机内存。因此不会传递任何预设值。
最后一个参数的类型为struct _PACKET_OID_DATA {
ULONG Oid; ///< OID code. See the Microsoft DDK documentation or the file ntddndis.h
///< for a complete list of valid codes.
ULONG Length; ///< Length of the data field
UCHAR Data[1]; ///< variable-lenght field that contains the information passed to or received
///< from the adapter.
};
-一个windows data type description。
jnr.ffi.Struct
结构映射比本地类型要复杂一些。您不能在此处使用Java类型。相反,您应该使用class PPACKET_OID_DATA extends Struct {
public final UnsignedLong Oid = new UnsignedLong();
public final UnsignedLong Length = new UnsignedLong();
public final Unsigned8[] Data = array(new Unsigned8[6]);
public PPACKET_OID_DATA(Runtime runtime) {
super(runtime);
}
}
内部类来定义结构字段。该规则包括数组定义。您的结构的正确定义如下所示:
UCHAR
请注意此unsigned char
数组定义。本地将这种类型定义为jnr.ffi.Strunc.Unsigned8
,因此对于JNR结构,它将映射到jnr.ffi.Struct.BYTE
类或jnr.ffi.Struct#array(...)
(几乎相同)。
要声明数组字段,应在构造时初始化数组。您需要使用Struct
函数来正确执行此操作。该aslo意味着您应该知道数组的大小。该示例如上所示。
为什么要用这种方式定义它?
在初始化期间,array
是某种长度可变的指针。在其中初始化的每个内部类字段都保留其自己的空间,从而增加此指针的最大大小。因此,每个字段都是某些内存片段的“视图”,并具有自己与该内存进行交互的方式(公共方法)。但是要制作一个这样的视图数组,您需要用视图实例填充空数组。这就是 private HttpClientHandler HttpClientHandler()
{
var handler = new HttpClientHandler
{
ClientCertificateOptions = ClientCertificateOption.Manual,
SslProtocols = SslProtocols.Tls12
};
handler.ClientCertificates.Add(new X509Certificate2("cert.crt")); //TODO: fetch from AWS.
return handler;
}
函数的作用。