Our application involves an external device that mounts as a USB mass storage device. I need to be able to check the integrity of that USB mass storage device from a Java application, running on Windows.
Currently I execute "chkdsk", which works fine unless the user's computer isn't configured for English. (Because I need to examine the chkdsk output to determine the state of the drive.) And, surprise, surprise, not every computer in the world is configured for English!
There is a Win32 class called "Win32_Volume" with a method called "Chkdsk" that is just what I'm looking for.
I need to call it from Java, and JNA seems the way to go.
How can I use COM to call a method from a Win32 WMI class?
CodePudding user response:
You can send an FSCTL_IS_VOLUME_DIRTY message using DeviceIoControl.
Here is and example of calling DeviceIoControl.
Or you can use WMI, both the the Win32_Volume and the Win32_LogicalDisk class expose a DirtyBitSet property. However WMI is really inteded for scripting languages and is not preferred because of it's incredible performance overhead.
CodePudding user response:
The Win32_Volume documentation with the Chkdsk method you cite indicates it is a legacy API, but has not yet been deprecated so you could use it.
The current Storage Management API equivalent is MSFT_Volume. It has a Diagnose method that looks to perform similar functionality.
To execute a method on a WMI object via COM you need to obtain a pointer to a WbemServices object. It has an ExecMethod method you can invoke that does what you want for WMI classes. The code to retrieve this object is in JNA's WbemcliUtil class as a return type from the connectServer() method.
You will also need the full path to the Class Object; this is available by querying WMI for the __PATH, similarly to how you'd query any other field. That same WbemcliUtil class has a WmiQuery class you can instantiate to execute the query, collecting that path from the WmiResult. See the JNA test classes for examples on using these.
Finally, you can execute the WMI method. The code below will accomplish it for String properties, e.g., the MSFT_StorageDiagnoseResult object you'd get from MSFT_Volume's Diagnose method. You'd have to treat other return types differently.
/**
* Convenience method for executing WMI methods without any input parameters
*
* @param svc
* The WbemServices object
* @param clsObj
* The full path to the class object to execute (result of WMI
* "__PATH" query)
* @param method
* The name of the method to execute
* @param properties
* One or more properties returned as a result of the query
* @return An array of the properties returned from the method
*/
private static String[] execMethod(WbemServices svc, String clsObj, String method, String... properties) {
List<String> result = new ArrayList<>();
PointerByReference ppOutParams = new PointerByReference();
HRESULT hres = svc.ExecMethod(new BSTR(clsObj), new BSTR(method), new NativeLong(0L), null, null, ppOutParams,
null);
if (COMUtils.FAILED(hres)) {
return new String[0];
}
WbemClassObject obj = new WbemClassObject(ppOutParams.getValue());
VARIANT.ByReference vtProp = new VARIANT.ByReference();
for (String prop : properties) {
hres = obj.Get(new BSTR(prop), new NativeLong(0L), vtProp, null, null);
if (!COMUtils.FAILED(hres)) {
result.add(vtProp.getValue() == null ? "" : vtProp.stringValue());
}
}
obj.Release();
return result.toArray(new String[result.size()]);
}
A more complete example of querying a COM object, where I extracted the above code, is in this utility class which queries the GetOwner() and GetOwnerSid() methods on the Win32_Process object. It's legacy code from before I contributed the WbemCli class to JNA, so you'll have to adapt some of it, but it should be a good starting point.
