Packet.dll получить MAC-адрес (JNR-FFI)

Как можно сопоставить приведенную ниже функцию с java с помощью jnr-ffi?

BOOLEAN PacketRequest (LPADAPTER AdapterObject, BOOLEAN Set, PPACKET_OID_DATA OidData);

Пример (C): https://github.com/patmarion/winpcap/blob/master/WpcapSrc_4_1_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);
        }
    }

}

1 ответ

Решение

Прежде всего, чтобы сделать правильное сопоставление, вы должны взглянуть на определения типов, которые вы отображаете. PacketRequest функция возвращает BOOLEAN переменная. Согласно описанию типа данных windows, BOOLEAN объявлен как typedef BYTE BOOLEAN;, Это означает, что вы можете использовать byte Тип как тип функции в Java. Но JNR также поддерживает отображение boolean введите в / из родного byte, Так что оба определения верны:

  • byte PacketRequest (...)
  • boolean PacketRequest (...)

Далее необходимо сопоставить параметры. То же самое здесь, посмотрите на определения, и вы будете знать, какие типы использовать. Результат будет:

boolean PacketRequest(Pointer AdapterObject, boolean set, PPACKET_OID_DATA OidData);

set параметр был неправильно объявлен как int, Кроме того @Out аннотация последнего поля указывает JNR передавать пустую структуру без копирования значений в собственную память. Таким образом, никакие предварительно установленные значения не будут переданы.

Последний параметр имеет PPACKET_OID_DATA Тип - это структура.

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 внутренние классы для определения структурных полей. Это правило включает определения массивов. Правильное определение для вашей структуры будет выглядеть так:

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 функция делает.

Другие вопросы по тегам