问题描述
我使用jna运行WMI查询.以下代码查询WMI SELECT Caption,Capabilities from Win32_DiskDrive
. Win32_DiskDrive.Capabilities的类型为uint16 [],并且result.getValue返回一个SAFEARRAY实例.
I use jna to run WMI queries.The following code queries WMI SELECT Caption,Capabilities from Win32_DiskDrive
. The Type of Win32_DiskDrive.Capabilities is uint16[] and result.getValue returns a SAFEARRAY Instance.
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)
returns null which is unexpected as well, so I cannot use OaIdlUtil#toPrimitiveArray (Nullpointer)
不幸的是,该代码无法正常工作,我也不知道可能出了什么问题.有任何想法吗?
Unfortunately, the code does not work, and I have no idea what might be wrong. Any Ideas?
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();
}
}
推荐答案
我提交给JNA项目的WMI代码仅设置为处理原始值和字符串,而不是数组.您遇到的问题是WMI正在将指针地址返回到数组(VT_EMPTY = 0的空数组或VT_I4 = 3的32位Poniter).但是WMI结果会在迭代后发布,因此您不能使用WmiResult
来获取对象.
The WMI code that I submitted to the JNA project is only set up to handle primitive values and Strings, not arrays. The problem you are encountering is that WMI is returning the pointer address to the array (either an empty array with VT_EMPTY = 0, or a 32-bit poniter with VT_I4 = 3). But the WMI result is released after the iteration, so you cannot use the WmiResult
to fetch the object.
您需要编写自己的代码(以JNA实现为起点)以在迭代过程中获取SAFEARRAY
.您在JNA网站上提出了这个问题,并且@matthiasblaesing发表了以下内容适用于您的用例的代码段:
You need to write your own code (using the JNA implementation as a starting point) to grab the SAFEARRAY
during iteration. You asked this question on the JNA website and @matthiasblaesing posted the following snippet which works for your use case:
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();
}
这篇关于如何访问WMI查询的数据(通过JNA)SAFEARRAY结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!