Convert SAFEARRAYByReference to something else

36 views
Skip to first unread message

crazy ghost pseudo555

unread,
Dec 26, 2024, 7:30:15 AM12/26/24
to Java Native Access
Hello everyone,

I'm playing with JNA, to do some requests on Win32_NetworkAdapterConfiguration class.
I manage to get some results, but few properties are "null" when same call using vbscript returns proper values.

The properties i'm interested here are : IPAddress, IPSubne & DefaultIPGateway.
Using jna, they all are null, because their variant type is 8200 (which is VT_ARRAY & VT_BSTR) and WbemcliUtil.enumerateProperties() falls in the default case (around line 355 for the 5.5.0 version). 
Using debuger, i find out the object is a SAFEARRAY.ByReference 

As it's a safearray, i try to get each element using getElement() method. 
It fails again, this time because the VarType (which is 116) is not handled.

Anyone has a idea how to get the proper value for thoses properties ?

Matthias Bläsing

unread,
Dec 26, 2024, 1:35:32 PM12/26/24
to jna-...@googlegroups.com
Hi

please provide a _minimal runnable_ sample of what you tried.

Greetings

Matthias

Am Donnerstag, dem 26.12.2024 um 04:30 -0800 schrieb crazy ghost
pseudo555:
> --
> You received this message because you are subscribed to the Google Groups "Java Native Access" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to jna-users+...@googlegroups.com.
> To view this discussion visit https://groups.google.com/d/msgid/jna-users/88cc9135-77d3-42b4-8ec7-d02a7aa6615dn%40googlegroups.com.

crazy ghost pseudo555

unread,
Dec 27, 2024, 5:40:19 AM12/27/24
to jna-...@googlegroups.com
Hello,

Originally, I based my code over oshi-core implementation.

    public enum NetworkAdapterConfigurationProperty {
        InterfaceIndex,
        IPAddress;
    }

    /* package for test */ Void wmiCmd2() {
        final WmiQueryHandler instance = WmiQueryHandler.createInstance(); // src: https://github.com/oshi/oshi/blob/master/oshi-core/src/main/java/oshi/util/platform/windows/WmiQueryHandler.java
        if (instance != null) {
            final WmiQuery<NetworkAdapterConfigurationProperty> nacConfQuery = new WmiQuery<>( "Win32_NetworkAdapterConfiguration" , NetworkAdapterConfigurationProperty.class);
            final WmiResult<NetworkAdapterConfigurationProperty> nacConfRes = instance.queryWMI(nacConfQuery);
            for (int i = 0; i < nacConfRes.getResultCount(); i++) {
                final Object key = nacConfRes.getValue(NetworkAdapterConfigurationProperty.InterfaceIndex, i);
                Object ip = nacConfRes.getValue(NetworkAdapterConfigurationProperty.IPAddress, i);
                if (ip == null) {
                    System.err.println("CIMTYPE is : " + nacConfRes.getCIMType(NetworkAdapterConfigurationProperty.IPAddress));
                    System.err.println(" VtType is : " + nacConfRes.getVtType(NetworkAdapterConfigurationProperty.IPAddress));
                } else if (ip instanceof SAFEARRAY) {
                    final SAFEARRAY arr = (SAFEARRAY) ip;
                    if (arr != null) {
                        System.err.println("dim: " + arr.getDimensionCount());
                        System.err.println("elm : " + arr.getElemsize());
                        System.err.println("vt  : " + arr.getVarType());
                        System.err.println("from " + arr.getLBound(0) + " to " + arr.getUBound(0));
                        for (int ii = arr.getLBound(0); ii <= arr.getUBound(0); ii++) {
                            System.out.println("\t" + arr.getElement(ii));
                        }
                    }
                } else {
                    System.err.println(" IP   : " + ip.getClass());
                }
                System.err.println("+++++++++++++++++++++++");
            }
        }
        return null;
    }

Which provide this result :

Deal with Key #20
CIMTYPE is : 8200
 VtType is : 8200
+++++++++++++++++++++++
Deal with Key #8
CIMTYPE is : 8200
 VtType is : 8200
+++++++++++++++++++++++
Deal with Key #5
CIMTYPE is : 8200
 VtType is : 8200
+++++++++++++++++++++++


So i edit WbemcliUtil WmiResult<T> enumerateProperties(IEnumWbemClassObject enumerator, Class<T> propertyEnum, int timeout) to add the following case:
case 8200:
    values.add(vtType, cimType, property, pVal.getValue());
    break;

doing so, the output changed, as ip is no longer null, but a SAFEARRAY:

Deal with Key #20
CIMTYPE is : 8200
 VtType is : 8200
+++++++++++++++++++++++
Deal with Key #8
dim: 1
elm : 4
vt  : 8
from 0 to 3
Exception in thread "main" com.sun.jna.platform.win32.COM.COMException: Paramètre incorrect.(HRESULT: 80070057)
at com.sun.jna.platform.win32.COM.COMUtils.checkRC(COMUtils.java:117)
at com.sun.jna.platform.win32.OaIdl$SAFEARRAY.getElement(OaIdl.java:821)
at fr.def.iss.ssiutils.network.adapters.WindowsNetworkAdapterConfTest.wmiCmd2(WindowsNetworkAdapterConfTest.java:135)
at fr.def.iss.ssiutils.network.adapters.WindowsNetworkAdapterConfTest.main(WindowsNetworkAdapterConfTest.java:34)

So I gave up there.


Doing some research, i found out this reported issue was almost what i'm looking for: https://github.com/java-native-access/jna/issues/1083
I adapt the code to use the expected "Win32_NetworkAdapterConfiguration" instead.
Which game me this code:

    private static void pouet() throws Exception {
        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 InterfaceIndex, IPAddress FROM Win32_NetworkAdapterConfiguration",
                    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("InterfaceIndex", 0, pVal, pType, plFlavor));
                    System.out.println("---------" + pVal.getValue() + "-------------");
                    OleAuto.INSTANCE.VariantClear(pVal);
                    COMUtils.checkRC(result[0].Get("IPAddress", 0, pVal, pType, plFlavor));
                    SAFEARRAY safeArray = (SAFEARRAY) pVal.getValue();
                    if(safeArray != null) {
                        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();
        }
    }

Which doesn't work well either. By that I mean running it produces no result at all.
So i add some syserr / catchblock here and there : 

    private static void pouet() throws Exception {
        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 InterfaceIndex, IPAddress, IPSubnet FROM Win32_NetworkAdapterConfiguration",
                    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) {
                        System.err.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! break");
                        break;
                    }
                    COMUtils.checkRC(result[0].Get("InterfaceIndex", 0, pVal, pType, plFlavor));
                    System.out.println("---------" + pVal.getValue() + "-------------");
                    OleAuto.INSTANCE.VariantClear(pVal);
                    COMUtils.checkRC(result[0].Get("IPAddress", 0, pVal, pType, plFlavor));
                    SAFEARRAY safeArray = (SAFEARRAY) pVal.getValue();
                    if(safeArray != null) {
                        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();
                }
            } catch (Throwable e) {
                e.printStackTrace();
            } finally {
                // Cleanup
                enumerator.Release();
                System.err.println("finaly2");
            }
        } catch (Throwable e1) {
            e1.printStackTrace();
        } finally {
            // Cleanup
            svc.Release();
            System.err.println("finaly1");
        }
    }

And still using debugger (a breakpoint on the "Wbemcli.IEnumWbemClassObject enumerator" the going line per line), i get some answers : 

---------20-------------
---------8-------------
192.168.1.39
fe80::a150:9e1:f91d:3ea0
2001:861:3840:1c90:dd15:c68:82f2:a947
2001:861:3840:1c90:50e5:9470:5c72:93ad
java.lang.Error: Invalid memory access
at com.sun.jna.Native.getShort(Native Method)
at com.sun.jna.Pointer.getShort(Pointer.java:568)
at com.sun.jna.Pointer.getValue(Pointer.java:378)
at com.sun.jna.Structure.readField(Structure.java:732)
at com.sun.jna.Structure.read(Structure.java:591)
at com.sun.jna.platform.win32.OaIdl$SAFEARRAY.read(OaIdl.java:586)
at com.sun.jna.Structure.autoRead(Structure.java:2203)
at com.sun.jna.Structure.conditionalAutoRead(Structure.java:561)
at com.sun.jna.Structure.updateStructureByReference(Structure.java:690)
at com.sun.jna.Pointer.getValue(Pointer.java:367)
at com.sun.jna.Structure.readField(Structure.java:732)
at com.sun.jna.Union.readField(Union.java:223)
at com.sun.jna.Structure.read(Structure.java:591)
at com.sun.jna.Pointer.getValue(Pointer.java:370)
at com.sun.jna.Structure.readField(Structure.java:732)
at com.sun.jna.Structure.read(Structure.java:591)
at com.sun.jna.Pointer.getValue(Pointer.java:370)
at com.sun.jna.Structure.readField(Structure.java:732)
at com.sun.jna.Union.readField(Union.java:223)
at com.sun.jna.Structure.read(Structure.java:591)
at com.sun.jna.Structure.autoRead(Structure.java:2203)
at com.sun.jna.Function.invoke(Function.java:381)
at com.sun.jna.Function.invoke(Function.java:315)
at com.sun.jna.Function.invoke(Function.java:306)
at com.sun.jna.platform.win32.COM.COMInvoker._invokeNativeObject(COMInvoker.java:48)
at com.sun.jna.platform.win32.COM.Wbemcli$IWbemClassObject.Get(Wbemcli.java:120)
at com.sun.jna.platform.win32.COM.Wbemcli$IWbemClassObject.Get(Wbemcli.java:126)
at fr.def.iss.ssiutils.network.adapters.WindowsNetworkAdapterConfTest.pouet(WindowsNetworkAdapterConfTest.java:60)
at fr.def.iss.ssiutils.network.adapters.WindowsNetworkAdapterConfTest.main(WindowsNetworkAdapterConfTest.java:31)

Note:
* IPAddress values displayed are the expected one (none for 20, four different results for interfaceIndex 8).
* exception occured when going to the next result (interfaceIndex 5 in my case)

If i comment this block : 

                    COMUtils.checkRC(result[0].Get("IPAddress", 0, pVal, pType, plFlavor));
                    SAFEARRAY safeArray = (SAFEARRAY) pVal.getValue();
                    if(safeArray != null) {
                        for(int i = safeArray.getLBound(0); i<=safeArray.getUBound(0); i++) {
                            System.out.println("\t" + safeArray.getElement(i));
                        }
                    }
                    OleAuto.INSTANCE.VariantClear(pVal);

The error doesn't appear (still using breakpoint, otherwise no result):

---------20-------------
---------8-------------
---------5-------------
---------13-------------
[...]

I manage to solve the java.lang.Error: Invalid memory access by moving 
                    IWbemClassObject[] result;
                    VARIANT.ByReference pVal = new VARIANT.ByReference();
                    IntByReference pType = new IntByReference();
                    IntByReference plFlavor = new IntByReference();
Inside the while loop.

To sum up : 
* I still don't get why the "running way" doesn't work. Why should i have to use a breakpoint on "Wbemcli.IEnumWbemClassObject enumerator" then go step by step ?
* I don't understand why oshi-core implementation doesn't work, as the minimal case provided for issue #1083 "works".



You received this message because you are subscribed to a topic in the Google Groups "Java Native Access" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/jna-users/bpnh4ZkqOTA/unsubscribe.
To unsubscribe from this group and all its topics, send an email to jna-users+...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/jna-users/1efb6a479f06691fb3ab9fc46b9cb21ae181ef8c.camel%40doppel-helix.eu.
Message has been deleted

Daniel B. Widdis

unread,
Dec 27, 2024, 1:39:57 PM12/27/24
to jna-...@googlegroups.com
Why are you clearing pVal before reading it?

                    OleAuto.INSTANCE.VariantClear(pVal);
                    COMUtils.checkRC(result[0].Get("IPAddress", 0, pVal, pType, plFlavor));
                    SAFEARRAY safeArray = (SAFEARRAY) pVal.getValue();


--
Dan Widdis

crazy ghost pseudo555

unread,
Dec 30, 2024, 5:59:24 AM12/30/24
to jna-...@googlegroups.com
I don't ?

For me the following code:

                    COMUtils.checkRC(result[0].Get("InterfaceIndex", 0, pVal, pType, plFlavor));
                    System.out.println("---------" + pVal.getValue() + "-------------");
                    OleAuto.INSTANCE.VariantClear(pVal);
                    COMUtils.checkRC(result[0].Get("IPAddress", 0, pVal, pType, plFlavor));
                    SAFEARRAY safeArray = (SAFEARRAY) pVal.getValue();
                    if(safeArray != null) {
                        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();

can be splitted that way : 


                    COMUtils.checkRC(result[0].Get("InterfaceIndex", 0, pVal, pType, plFlavor));
                    System.out.println("---------" + pVal.getValue() + "-------------");
                    OleAuto.INSTANCE.VariantClear(pVal);

                    COMUtils.checkRC(result[0].Get("IPAddress", 0, pVal, pType, plFlavor));
                    SAFEARRAY safeArray = (SAFEARRAY) pVal.getValue();
                    if(safeArray != null) {
                        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();

So, for me, the first call to VariantClear clears the InterfaceIndex, not the IPAddress part.
And the error occured when going to next iterator value (i mean first result = enumerator.Next(0, 1); is complete, it's the next time this is called that the issue occured.

Daniel B. Widdis

unread,
Dec 30, 2024, 12:11:31 PM12/30/24
to jna-...@googlegroups.com
My apologies.  Probably lack of coffee.

As the author of the oshi-core code, I fully admit it may have a bug; I did my best to port example C source from MS docs.




--
Dan Widdis

crazy ghost pseudo555

unread,
Dec 30, 2024, 1:19:57 PM12/30/24
to jna-...@googlegroups.com
No worries, I could have missed something as well ;)

crazy ghost pseudo555

unread,
Dec 30, 2024, 3:46:43 PM12/30/24
to Java Native Access
I think, i find out why the running way doesn't work.
It's due to 0 as timeout in this line:  result = enumerator.Next(-0 1);

Changing 0 by -1 make it work as expected.
Reply all
Reply to author
Forward
0 new messages