Как получить доступ к данным запроса WMI (через JNA) SAFEARRAY - PullRequest
1 голос
/ 12 апреля 2019

Я использую jna для выполнения запросов WMI.Следующий код запрашивает WMI SELECT Caption,Capabilities from Win32_DiskDrive.Тип Win32_DiskDrive.Capabilities - это uint16 [], а result.getValue возвращает экземпляр SAFEARRAY.

System.out.println("Var Type(3 expected): " + value.getVarType().intValue());

возвращает случайно 0 или 3, если я запускаю процесс несколько раз.

System.out.println("Size (>0 expected): " + (value.getUBound(0) - value.getLBound(0)));

правильно, но

Object el = value.getElement(0);

не удается.

value.accessData();

возвращает null, что также является неожиданным, поэтому я не могу использовать OaIdlUtil # toPrimitiveArray (Nullpointer)

К сожалению, код не работает, и я понятия не имею, что может быть не так.Есть идеи?

enum Win32_DiskDrive_Values {
        Caption,
        Capabilities
    }

    public static void main(String[] args) throws IOException, InterruptedException {
        try {
            WmiQuery<Win32_DiskDrive_Values> serialNumberQuery = new WmiQuery<Win32_DiskDrive_Values>("Win32_DiskDrive", Win32_DiskDrive_Values.class);
            Ole32.INSTANCE.CoInitializeEx(null, Ole32.COINIT_MULTITHREADED);
            WmiResult<Win32_DiskDrive_Values> result = serialNumberQuery.execute();
            for (int i = 0; i < result.getResultCount(); i++) {
                System.out.println(result.getValue(Win32_DiskDrive_Values.Caption, i));
                SAFEARRAY value = (SAFEARRAY) result.getValue(Win32_DiskDrive_Values.Capabilities, i);
                // According to https://docs.microsoft.com/en-us/windows/desktop/cimwin32prov/win32-diskdrive, the type of Capabilities
                // should be uint16[] which should be Variant.VT_I2 (2-byte integer)
                // however, it is not constant. sometimes it is 0, sometimes Variant.VT_I2 (3);
                System.out.println("Var Type(3 expected): " + value.getVarType().intValue());
                System.out.println("Size (>0 expected): " + (value.getUBound(0) - value.getLBound(0)));
                Object el = value.getElement(0);
                System.out.println("Element 0 (!=null expected): " + el);
                Pointer pointer = value.accessData();
                System.out.println("pointer (!=null expected): " + pointer);
            }
        } catch (Throwable e) {
            e.printStackTrace();
        } finally {
            Ole32.INSTANCE.CoUninitialize();
        }
    }

1 Ответ

0 голосов
/ 13 апреля 2019

Код WMI, который я отправил в проект JNA, настроен только на обработку примитивных значений и строк, а не массивов. Проблема, с которой вы сталкиваетесь, заключается в том, что WMI возвращает адрес указателя в массив (либо пустой массив с VT_EMPTY = 0, либо 32-разрядный компонент с VT_I4 = 3). Но результат WMI высвобождается после итерации, поэтому вы не можете использовать WmiResult для извлечения объекта.

Вам нужно написать собственный код (используя реализацию JNA в качестве отправной точки), чтобы получить SAFEARRAY во время итерации. Вы задали этот вопрос на веб-сайте JNA , а @matthiasblaesing опубликовал следующий фрагмент кода, который подходит для вашего варианта использования:

public static void main(String[] args) throws IOException, InterruptedException {
    Ole32.INSTANCE.CoInitializeEx(null, Ole32.COINIT_MULTITHREADED);

    // Connect to the server
    Wbemcli.IWbemServices svc = WbemcliUtil.connectServer("ROOT\\CIMV2");

    // Send query
    try {
        Wbemcli.IEnumWbemClassObject enumerator = svc.ExecQuery("WQL", "SELECT Caption, Capabilities, CapabilityDescriptions FROM Win32_DiskDrive",
                Wbemcli.WBEM_FLAG_FORWARD_ONLY | Wbemcli.WBEM_FLAG_RETURN_IMMEDIATELY, null);

        try {
            IWbemClassObject[] result;
            VARIANT.ByReference pVal = new VARIANT.ByReference();
            IntByReference pType = new IntByReference();
            IntByReference plFlavor = new IntByReference();
            while(true) {
                result = enumerator.Next(0, 1);
                if(result.length == 0) {
                    break;
                }
                COMUtils.checkRC(result[0].Get("Caption", 0, pVal, pType, plFlavor));
                System.out.println("---------" + pVal.getValue() + "-------------");
                OleAuto.INSTANCE.VariantClear(pVal);
                COMUtils.checkRC(result[0].Get("CapabilityDescriptions", 0, pVal, pType, plFlavor));
                SAFEARRAY safeArray = (SAFEARRAY) pVal.getValue();
                for(int i = safeArray.getLBound(0); i<=safeArray.getUBound(0); i++) {
                    System.out.println("\t" + safeArray.getElement(i));
                }
                OleAuto.INSTANCE.VariantClear(pVal);
                COMUtils.checkRC(result[0].Get("Capabilities", 0, pVal, pType, plFlavor));
                safeArray = (SAFEARRAY) pVal.getValue();
                for(int i = safeArray.getLBound(0); i<=safeArray.getUBound(0); i++) {
                    System.out.println("\t" + safeArray.getElement(i));
                }
                OleAuto.INSTANCE.VariantClear(pVal);
                result[0].Release();
            }
        } finally {
            // Cleanup
            enumerator.Release();
        }
    } finally {
        // Cleanup
        svc.Release();
    }

    Ole32.INSTANCE.CoUninitialize();
}
...