如何使用jnr-ffi将下面的函数映射到java?
布尔PacketRequest(LPADAPTER AdapterObject,布尔集,PPACKET_OID_DATA OidData);
示例(C):3/Examples/PacketDriver/GetMacAddress/GetMacAddress.c
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);
}
}
}发布于 2018-09-10 08:50:47
首先,要进行propper映射,您应该查看要映射的类型的定义。PacketRequest函数返回BOOLEAN变量。根据windows数据类型描述的说法,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注释告诉JNR传递一个空结构,而不将值复制到本机内存。因此,不会传递预先设置的值。
最后一个参数具有PPACKET_OID_DATA类型-a 结构。
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.
}; 结构映射比本机类型要复杂一些。这里不能使用java类型。相反,您应该使用jnr.ffi.Struct内部类来定义struct字段。此规则包括数组定义。结构的正确定义如下所示:
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结构,它将映射到jnr.ffi.Strunc.Unsigned8类或jnr.ffi.Struct.BYTE (这几乎是一样的)。
若要声明数组字段,应在构造时初始化数组。您需要使用jnr.ffi.Struct#array(...)函数来正确地做到这一点。这意味着您应该知道数组的大小。例子如上所示。
为什么我们要这样定义它?在初始化时,Struct是一种可变长度的指针。在其中初始化的每个内部类字段都保留了自己的空间,增加了该指针的最大大小。因此,每个字段都是某个内存片段的“视图”,具有与此内存交互的方式(公共方法)。但是要创建这样的视图数组,您需要用视图实例填充空数组。这正是array函数所做的。
https://stackoverflow.com/questions/52241049
复制相似问题