我需要获取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);
}


任何想法为什么会这样?

最佳答案

您的输入结构不够大。您需要根据table参数中返回的值来重新分配pdwSize字段,使其足够大。

MIB_IFTABLE添加一个指示table数组大小的构造函数,并相应地对其进行初始化。这将自动为您提供更大的缓冲。

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
    // ...
}


编辑

更改您的构造函数:

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


您可能应该将其他ctor初始化为dwNumEntries的默认值。因为它是您将传入的默认值零,这将确保您在第一次调用时得到的返回值为122。我假设dwNumEntries是指数组的大小。

07-24 09:38
查看更多