1

我需要在 Windows 中获取网络接口的索引。有 NetworkInterface.getIndex() 方法可以做到这一点,但它只在 Java 7 开始可用。老板的要求是应用程序需要在 Java 6 中运行。

经过一番搜索,我找到了 JNA lib 来调用 Win API 函数。该函数本身是 GetIfTable ( http://msdn.microsoft.com/en-us/library/windows/desktop/aa365943(v=vs.85).aspx )

但是,我无法使用 JNA 成功调用此函数。GetIfTable 的返回值始终为 122,这意味着 ERROR_INSUFFICIENT_BUFFER。即使我继续添加缓冲区,它仍然说缓冲区不足,直到提供的值达到某个数字时,才会出现“无效的内存访问”错误。

这是我已经做过的:

public interface IpHlpAPI extends StdCallLibrary {
    IpHlpAPI INSTANCE = (IpHlpAPI) Native.loadLibrary("IpHlpAPI", IpHlpAPI.class);

    public static class MIB_IFTABLE extends Structure {

        public int dwNumEntries;
        public MIB_IFROW table[] = new IpHlpAPI.MIB_IFROW[1];

        public MIB_IFTABLE() {}

        public MIB_IFTABLE(int size) {
            this.allocateMemory(size);
        }

        @Override
        protected List getFieldOrder() {
            return Arrays.asList(new String[]{"dwNumEntries", "table"});
        }
    }

    public static class MIB_IFROW extends Structure {

        public char wszName[] = new char[256];
        public int dwIndex;
        public int dwType;
        public int dwMtu;
        public int dwSpeed;
        public int dwPhysAddrLen;
        public byte bPhysAddr[] = new byte[8];
        public int dwAdminStatus;
        public int dwOperStatus;
        public int dwLastChange;
        public int dwInOctets;
        public int dwInUcastPkts;
        public int dwInNUcastPkts;
        public int dwInDiscards;
        public int dwInErrors;
        public int dwInUnknownProtos;
        public int dwOutOctets;
        public int dwOutUcastPkts;
        public int dwOutNUcastPkts;
        public int dwOutDiscards;
        public int dwOutErrors;
        public int dwOutQLen;
        public int dwDescrLen;
        public byte bDescr[] = new byte[256];

        @Override
        protected List getFieldOrder() {
            return Arrays.asList(new String[]{"wszName", "dwIndex", "dwType", "dwMtu",
                        "dwSpeed", "dwPhysAddrLen", "bPhysAddr", "dwAdminStatus", "dwOperStatus",
                        "dwLastChange", "dwInOctets", "dwInUcastPkts", "dwInNUcastPkts", "dwInDiscards",
                        "dwInErrors", "dwInUnknownProtos", "dwOutOctets", "dwOutUcastPkts",
                        "dwOutNUcastPkts", "dwOutDiscards", "dwOutErrors", "dwOutQLen", "dwDescrLen", "bDescr"});
        }
    }

    int GetIfTable(MIB_IFTABLE pIfTable, IntByReference pdwSize, boolean bOrder);
}

public static void main(String[] args) {
    IpHlpAPI ipHlpApi = IpHlpAPI.INSTANCE;
    IpHlpAPI.MIB_IFTABLE ifTable = new IpHlpAPI.MIB_IFTABLE();
    IntByReference psize = new IntByReference(ifTable.size());

    int status = ipHlpApi.GetIfTable(ifTable, psize, false);

    if (status == 122) {
        // Calculate the required number of elements in the MIB_IFROW array
        ifTable = new IpHlpAPI.MIB_IFTABLE((psize.getValue() - 4) / ifTable.table[0].size());
        psize.setValue(ifTable.size());
        status = ipHlpApi.GetIfTable(ifTable, psize, false);
        System.out.println(status);
    }

    System.exit(0);
}

任何想法为什么会发生这种情况?

4

1 回答 1

1

Your input structure isn't large enough. You need to reallocate the table field to be sufficiently large based on the value returned in the pdwSize parameter.

Add a constructor to MIB_IFTABLE that indicates the size of the table array and initializes it accordingly. That will automatically give you a bigger buffer.

MIB_IFTABLE ifTable = new MIB_IFTABLE();
IntByReference psize = new IntByReference(ifTable.size());
int status = ipHlpApi.GetIfTable(ifTable, psize, false);
if (status == 122) {
    // Calculate the required number of elements in the MIB_IFROW array
    ifTable = new MIB_IFTABLE((psize.getValue() - 4) / ifTable.table[0].size());
    psize.setValue(ifTable.size());
    status = ipHlpApi.GetIfTable(ifTable, psize, false);
    // If status is still 122, then there's an issue with the MIB_IFROW definition
    // ...
}

EDIT

Change your constructor:

public MIB_IFTABLE(int nentries) {
    this.dwNumEntries = nentries;
    this.table = (MIB_IFROW[])new MIB_IFROW().toArray(nentries);
}

You should probably initialize your other ctor to have a default value for dwNumEntries; as it is you'll be passing in a default value of zero, which will guarantee you get a return value of 122 on the first call. I'm assuming dwNumEntries refers to the size of the array.

于 2013-07-26T12:02:38.977 回答