diff --git a/CHANGES.md b/CHANGES.md index c7fd6bad70..7c10f121f6 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -10,6 +10,7 @@ Features * [#1454](https://github.com/java-native-access/jna/pull/1454): Add `c.s.j.p.win32.Psapi.QueryWorkingSetEx` and associated Types - [@crain-32](https://github.com/Crain-32). * [#1459](https://github.com/java-native-access/jna/pull/1459): Add `VirtualLock` and `VirtualUnlock` in `c.s.j.p.win32.Kernel32` - [@matthiasblaesing](https://github.com/matthiasblaesing). * [#1471](https://github.com/java-native-access/jna/pull/1471): Add `c.s.j.p.win32.Advapi32Util#isCurrentProcessElevated` and associated Types - [@dbwiddis](https://github.com/dbwiddis). +* [#1474](https://github.com/java-native-access/jna/pull/1474): Add `c.s.j.p.win32.WbemCli#IWbemClassObject.IWbemQualifierSet`, `IWbemServices.GetObject`, `IWbemContext.SetValue` and associated methods - [@rchateauneu](https://github.com/rchateauneu). Bug Fixes --------- diff --git a/contrib/platform/src/com/sun/jna/platform/win32/COM/Wbemcli.java b/contrib/platform/src/com/sun/jna/platform/win32/COM/Wbemcli.java index 1fccfc8d37..4a2039ceda 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/COM/Wbemcli.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/COM/Wbemcli.java @@ -25,6 +25,9 @@ import com.sun.jna.Pointer; import com.sun.jna.WString; +import com.sun.jna.platform.win32.*; +import com.sun.jna.platform.win32.COM.COMUtils; +import com.sun.jna.platform.win32.COM.Unknown; import com.sun.jna.platform.win32.Guid.CLSID; import com.sun.jna.platform.win32.Guid.GUID; import com.sun.jna.platform.win32.OaIdl.SAFEARRAY; @@ -45,8 +48,16 @@ */ public interface Wbemcli { + public static final int WBEM_FLAG_RETURN_WBEM_COMPLETE = 0x00000000; public static final int WBEM_FLAG_RETURN_IMMEDIATELY = 0x00000010; public static final int WBEM_FLAG_FORWARD_ONLY = 0x00000020; + public static final int WBEM_FLAG_NO_ERROR_OBJECT = 0x00000040; + public static final int WBEM_FLAG_SEND_STATUS = 0x00000080; + public static final int WBEM_FLAG_ENSURE_LOCATABLE = 0x00000100; + public static final int WBEM_FLAG_DIRECT_READ = 0x00000200; + public static final int WBEM_MASK_RESERVED_FLAGS = 0x0001F000; + public static final int WBEM_FLAG_USE_AMENDED_QUALIFIERS = 0x00020000; + public static final int WBEM_FLAG_STRONG_VALIDATION = 0x00100000; public static final int WBEM_INFINITE = 0xFFFFFFFF; // Non-error constants @@ -146,6 +157,88 @@ public String[] GetNames(String wszQualifierName, int lFlags, VARIANT.ByReferenc } return names; } + + public HRESULT GetQualifierSet(PointerByReference ppQualSet) { + // Get is the fourth method of IWbemClassObjectVtbl in WbemCli.h : + return (HRESULT) _invokeNativeObject(3, + new Object[] { getPointer(), ppQualSet }, HRESULT.class); + } + + public IWbemQualifierSet GetQualifierSet() { + PointerByReference ppQualSet = new PointerByReference(); + HRESULT hr = GetQualifierSet(ppQualSet); + COMUtils.checkRC(hr); + IWbemQualifierSet qualifier = new IWbemQualifierSet(ppQualSet.getValue()); + + return qualifier; + } + + /* + // https://docs.microsoft.com/en-us/windows/win32/api/wbemcli/nf-wbemcli-iwbemclassobject-getpropertyqualifierset + HRESULT GetPropertyQualifierSet( + [in] LPCWSTR wszProperty, + [out] IWbemQualifierSet **ppQualSet + ); + */ + public HRESULT GetPropertyQualifierSet(WString wszProperty, PointerByReference ppQualSet) { + // Get is 12th method of IWbemClassObjectVtbl in WbemCli.h : + return (HRESULT) _invokeNativeObject(11, + new Object[] { getPointer(), wszProperty, ppQualSet }, HRESULT.class); + } + + public IWbemQualifierSet GetPropertyQualifierSet(String strProperty) { + WString wszProperty = new WString(strProperty); + PointerByReference ppQualSet = new PointerByReference(); + + COMUtils.checkRC(GetPropertyQualifierSet(wszProperty, ppQualSet)); + IWbemQualifierSet qualifier = new IWbemQualifierSet(ppQualSet.getValue()); + return qualifier; + } + } + + class IWbemQualifierSet extends Unknown { + public IWbemQualifierSet(Pointer pvInstance) { + super(pvInstance); + } + + public HRESULT Get(WString wszName, int lFlags, VARIANT.ByReference pVal, IntByReference plFlavor) { + return (HRESULT) _invokeNativeObject(3, + new Object[] { getPointer(), wszName, lFlags, pVal, plFlavor }, HRESULT.class); + } + + public String Get(String wszName) { + WString wszNameStr = new WString(wszName); + Variant.VARIANT.ByReference pQualifierVal = new Variant.VARIANT.ByReference(); + HRESULT hres = Get(wszNameStr, 0, pQualifierVal, null); + if(hres.intValue() == 0x80041002) { + // This error for some classes only. + return null; + } + int qualifierInt = pQualifierVal.getVarType().intValue(); + switch(qualifierInt) { + case Wbemcli.CIM_BOOLEAN: + return String.valueOf(pQualifierVal.booleanValue()); + case Wbemcli.CIM_STRING: + return pQualifierVal.stringValue(); + } + return null; + } + + public HRESULT GetNames(int lFlags, PointerByReference pNames) { + return (HRESULT) _invokeNativeObject(6, + new Object[] { getPointer(), lFlags, pNames }, HRESULT.class); + } + + public String[] GetNames() { + PointerByReference pbr = new PointerByReference(); + COMUtils.checkRC(GetNames(0, pbr)); + Object[] nameObjects = (Object[]) OaIdlUtil.toPrimitiveArray(new SAFEARRAY(pbr.getValue()), true); + String[] qualifierNames = new String[nameObjects.length]; + for(int i = 0; i < nameObjects.length; i++) { + qualifierNames[i] = (String) nameObjects[i]; + } + return qualifierNames; + } } /** @@ -278,6 +371,25 @@ public IEnumWbemClassObject ExecQuery(String strQueryLanguage, String strQuery, OleAuto.INSTANCE.SysFreeString(strQueryBSTR); } } + + public HRESULT GetObject(BSTR strObjectPath, int lFlags, IWbemContext pCtx, + PointerByReference ppObject, PointerByReference ppCallResult) { + // GetObject is the 7th method of IWbemServicesVtbl in WbemCli.h + return (HRESULT) _invokeNativeObject(6, + new Object[] { getPointer(), strObjectPath, lFlags, pCtx, ppObject, ppCallResult}, HRESULT.class); + } + + public IWbemClassObject GetObject(String strObjectPath, int lFlags, IWbemContext pCtx) { + BSTR strObjectPathBSTR = OleAuto.INSTANCE.SysAllocString(strObjectPath); + try { + PointerByReference ppObject = new PointerByReference(); + HRESULT res = GetObject(strObjectPathBSTR, lFlags, pCtx, ppObject, null); + COMUtils.checkRC(res); + return new IWbemClassObject(ppObject.getValue()); + } finally { + OleAuto.INSTANCE.SysFreeString(strObjectPathBSTR); + } + } } /** @@ -285,12 +397,57 @@ public IEnumWbemClassObject ExecQuery(String strQueryLanguage, String strQuery, * providers when submitting IWbemServices calls to WMI */ class IWbemContext extends Unknown { + public static final CLSID CLSID_WbemContext = new CLSID("674B6698-EE92-11D0-AD71-00C04FD8FDFF"); + public static final GUID IID_IWbemContext = new GUID("44aca674-e8fc-11d0-a07c-00c04fb68820"); public IWbemContext() { } + public static IWbemContext create() { + PointerByReference pbr = new PointerByReference(); + + HRESULT hres = Ole32.INSTANCE.CoCreateInstance(CLSID_WbemContext, null, WTypes.CLSCTX_INPROC_SERVER, + IID_IWbemContext, pbr); + if (COMUtils.FAILED(hres)) { + return null; + } + + return new IWbemContext(pbr.getValue()); + } + public IWbemContext(Pointer pvInstance) { super(pvInstance); } + + public void SetValue(String wszName, int lFlag, Variant.VARIANT pValue) { + BSTR wszNameBSTR = OleAuto.INSTANCE.SysAllocString(wszName); + try { + // SetValue is the 9th method of IWbemContextVtbl in WbemCli.h + HRESULT res = (HRESULT) _invokeNativeObject(8, + new Object[] { getPointer(), wszNameBSTR, lFlag, pValue}, HRESULT.class); + COMUtils.checkRC(res); + } finally { + OleAuto.INSTANCE.SysFreeString(wszNameBSTR); + } + } + + public void SetValue(String wszName, int lFlag, boolean pValue) { + Variant.VARIANT aVariant = new Variant.VARIANT(); + aVariant.setValue(Variant.VT_BOOL, pValue ? Variant.VARIANT_TRUE : Variant.VARIANT_FALSE); + SetValue(wszName, lFlag, aVariant); + OleAuto.INSTANCE.VariantClear(aVariant); + } + + public void SetValue(String wszName, int lFlag, String pValue) { + Variant.VARIANT aVariant = new Variant.VARIANT(); + BSTR strValue = OleAuto.INSTANCE.SysAllocString(pValue); + try { + aVariant.setValue(Variant.VT_LPSTR, strValue); + SetValue(wszName, lFlag, aVariant); + } + finally { + OleAuto.INSTANCE.SysFreeString(strValue); + } + } } } diff --git a/contrib/platform/test/com/sun/jna/platform/win32/COM/WbemcliTest.java b/contrib/platform/test/com/sun/jna/platform/win32/COM/WbemcliTest.java index 9d6ae26352..fbc9591152 100644 --- a/contrib/platform/test/com/sun/jna/platform/win32/COM/WbemcliTest.java +++ b/contrib/platform/test/com/sun/jna/platform/win32/COM/WbemcliTest.java @@ -36,6 +36,9 @@ import org.junit.Before; import org.junit.Test; +import static com.sun.jna.platform.win32.Variant.VT_ARRAY; +import static com.sun.jna.platform.win32.Variant.VT_BSTR; + import com.sun.jna.platform.win32.Ole32; import com.sun.jna.platform.win32.Variant; import com.sun.jna.platform.win32.COM.Wbemcli.IEnumWbemClassObject; @@ -43,6 +46,10 @@ import com.sun.jna.platform.win32.COM.WbemcliUtil.WmiQuery; import com.sun.jna.platform.win32.COM.WbemcliUtil.WmiResult; import com.sun.jna.platform.win32.OleAuto; +import com.sun.jna.platform.win32.OaIdl.SAFEARRAY; +import com.sun.jna.platform.win32.WTypes; +import com.sun.jna.platform.win32.Kernel32; +import com.sun.jna.platform.win32.WinNT; import com.sun.jna.ptr.IntByReference; import java.util.Arrays; import java.util.HashSet; @@ -309,4 +316,138 @@ public void testUnsupportedValues() { assertNull(result.getValue(Win32_DiskDrive_Values.CAPABILITIES, i)); } } + + @Test + public void testIWbemClassObjectGetQualifierSet() { + + Wbemcli.IWbemServices svc = null; + Wbemcli.IEnumWbemClassObject enumRes = null; + Variant.VARIANT.ByReference pVal = new Variant.VARIANT.ByReference(); + IntByReference pType = new IntByReference(); + IntByReference plFlavor = new IntByReference(); + + boolean foundWin32_Process = false; + try { + svc = connectServerEnglishLocale(WbemcliUtil.DEFAULT_NAMESPACE); + enumRes = svc.ExecQuery( + "WQL", + "SELECT * FROM meta_class", + Wbemcli.WBEM_FLAG_FORWARD_ONLY | Wbemcli.WBEM_FLAG_USE_AMENDED_QUALIFIERS, null); + + while (true) { + Wbemcli.IWbemClassObject[] results = enumRes.Next(Wbemcli.WBEM_INFINITE, 1); + if (results.length == 0) { + break; + } + + Wbemcli.IWbemClassObject classObject = results[0]; + Variant.VARIANT.ByReference pQualifierVal = new Variant.VARIANT.ByReference(); + + COMUtils.checkRC(classObject.Get("__CLASS", 0, pVal, pType, plFlavor)); + String className = pVal.stringValue(); + if(! className.equals("Win32_Process")) { + continue; + } + foundWin32_Process = true; + OleAuto.INSTANCE.VariantClear(pVal); + + COMUtils.checkRC(classObject.Get("__SUPERCLASS", 0, pVal, pType, plFlavor)); + Object baseClass = pVal.getValue(); + OleAuto.INSTANCE.VariantClear(pVal); + assertEquals("CIM_Process", baseClass.toString()); + + String[] propertyNames = classObject.GetNames(null, 0, pQualifierVal); + assertTrue(Arrays.asList(propertyNames).contains("ProcessId")); + + Wbemcli.IWbemQualifierSet classQualifiersSet = classObject.GetQualifierSet(); + String[] classQualifiersNames = classQualifiersSet.GetNames(); + assertTrue(Arrays.asList(classQualifiersNames).contains("DisplayName")); + String classDisplayName = classQualifiersSet.Get("DisplayName"); + assertEquals("Processes", classDisplayName); + + Wbemcli.IWbemQualifierSet propertyQualifiersSet = classObject.GetPropertyQualifierSet("ProcessId"); + String[] propertyQualifierNames = propertyQualifiersSet.GetNames(); + + assertTrue(Arrays.asList(propertyQualifierNames).contains("DisplayName")); + String propertyDisplayName = propertyQualifiersSet.Get("DisplayName"); + assertEquals("Process Id", propertyDisplayName); + + assertTrue(Arrays.asList(propertyQualifierNames).contains("CIMTYPE")); + String propertyCIMTYPE = propertyQualifiersSet.Get("CIMTYPE"); + assertEquals("uint32", propertyCIMTYPE); + + classObject.Release(); + } + } finally { + if (svc != null) svc.Release(); + if (enumRes != null) enumRes.Release(); + } + assertTrue(foundWin32_Process); + } + + @Test + public void testIWbemContextSetValue() { + long currentPid = Kernel32.INSTANCE.GetCurrentProcessId(); + String objectPath = String.format("\\\\.\\%s:Win32_Process.Handle=\"%d\"", WbemcliUtil.DEFAULT_NAMESPACE, currentPid); + + // This context object retrieves only parts of a WMI instance. + Wbemcli.IWbemContext pctxDrive = new Wbemcli.IWbemContext().create(); + pctxDrive.SetValue("__GET_EXTENSIONS", 0, true); + pctxDrive.SetValue("__GET_EXT_CLIENT_REQUEST", 0, true); + + // Create a safe array of just one property to retrieve. + SAFEARRAY psaProperties = SAFEARRAY.createSafeArray(new WTypes.VARTYPE(VT_BSTR), 1); + OleAuto.INSTANCE.SafeArrayLock(psaProperties); + try { + WTypes.BSTR strPropertyBSTR = OleAuto.INSTANCE.SysAllocString("ProcessId"); + try { + psaProperties.putElement(strPropertyBSTR, 0); + } finally { + OleAuto.INSTANCE.SysFreeString(strPropertyBSTR); + } + } finally { + OleAuto.INSTANCE.SafeArrayUnlock(psaProperties); + } + + Variant.VARIANT.ByReference vPropertyList = new Variant.VARIANT.ByReference(); + vPropertyList.setVarType((short) (VT_ARRAY | VT_BSTR)); + vPropertyList.setValue(psaProperties); + pctxDrive.SetValue("__GET_EXT_PROPERTIES", 0, vPropertyList); + psaProperties.destroy(); + + Variant.VARIANT.ByReference pVal = new Variant.VARIANT.ByReference(); + Wbemcli.IWbemServices svc = null; + try { + svc = WbemcliUtil.connectServer(WbemcliUtil.DEFAULT_NAMESPACE); + Wbemcli.IWbemClassObject classObject = svc.GetObject(objectPath, Wbemcli.WBEM_FLAG_RETURN_WBEM_COMPLETE, pctxDrive); + // The properties "Handle" and "PropertyId" must have the same values with different types. + COMUtils.checkRC(classObject.Get("ProcessId", 0, pVal, null, null)); + } + finally { + if (svc != null) svc.Release(); + } + assertEquals(currentPid, pVal.longValue()); + } + + /** + * Copy from WbemcliUtil#connectServer with American English selected as + * locale. + */ + private static Wbemcli.IWbemServices connectServerEnglishLocale(String namespace) { + Wbemcli.IWbemLocator loc = Wbemcli.IWbemLocator.create(); + if (loc == null) { + throw new COMException("Failed to create WbemLocator object."); + } + + Wbemcli.IWbemServices services = loc.ConnectServer(namespace, null, null, "MS_409", 0, null, null); + loc.Release(); + + WinNT.HRESULT hres = Ole32.INSTANCE.CoSetProxyBlanket(services, Ole32.RPC_C_AUTHN_WINNT, Ole32.RPC_C_AUTHZ_NONE, null, + Ole32.RPC_C_AUTHN_LEVEL_CALL, Ole32.RPC_C_IMP_LEVEL_IMPERSONATE, null, Ole32.EOAC_NONE); + if (COMUtils.FAILED(hres)) { + services.Release(); + throw new COMException("Could not set proxy blanket.", hres); + } + return services; + } }