ExecMethod in ISWbemObject returns always 0
Closed this issue · 3 comments
Summary
Hi,
First of all, thanks for your hard work! I really enjoy using windows-rs
so far.
I am trying to access a remote machine. The execution of my wanted logoff
with a given session ID (obtained through query session
) did work just fine. However if you look closely into my code below you will see, that I want to give some feedback if the command logoff
did fail. But no matter the session ID it will always proceed with "ok" or 0 in my case:
use std::mem::ManuallyDrop;
use windows::{
core::{ComInterface, BSTR},
Win32::System::{
Com::IDispatch,
Variant::{VARIANT, VARIANT_0, VT_BSTR, VT_I4},
Wmi::{ISWbemObject, ISWbemServices},
},
};
pub fn logoff_session(server: &ISWbemServices, session_id: u32) -> windows::core::Result<()> {
unsafe {
println!("RUNNING logoff_session...");
// Define the WMI class and method to be used
let class_name = BSTR::from("Win32_Process");
let method_name = BSTR::from("Create");
let command = format!("logoff {}", session_id);
// Get the Win32_Process class object
let process_class_object: ISWbemObject = server.Get(&class_name, 0, None)?;
println!("Got the process class object.");
// Get the method from the class object
let methods = process_class_object.Methods_()?;
let create_method = methods.Item(&method_name, 0)?;
println!("Got the Create method from the process class.");
// Get the input parameters definition and spawn an instance
let in_params_def = create_method.InParameters()?;
let in_params = in_params_def.SpawnInstance_(0)?;
println!("Spawned an instance of the input parameters.");
// Set the CommandLine property with the logoff command
let command_line_prop = in_params
.Properties_()?
.Item(&BSTR::from("CommandLine"), 0)?;
println!("Got the CommandLine property.");
// Prepare the VARIANT for the command line argument
let mut command_variant = VARIANT {
Anonymous: VARIANT_0 {
Anonymous: ManuallyDrop::new(std::mem::zeroed()),
},
};
(*command_variant.Anonymous.Anonymous).vt = VT_BSTR;
(*command_variant.Anonymous.Anonymous).Anonymous.bstrVal =
ManuallyDrop::new(BSTR::from(command.as_str()));
println!("Prepared the VARIANT for the command.");
// Set the CommandLine property value
command_line_prop.SetValue(&command_variant)?;
println!("Set the CommandLine property value to logoff command.");
// Convert in_params to IDispatch reference
let in_params_dispatch = in_params.cast::<IDispatch>()?;
println!("Converted input parameters to IDispatch.");
// Execute the method with the input parameters
let out_params = server.ExecMethod(
&class_name,
&method_name,
Some(&in_params_dispatch),
0,
None,
)?;
println!("Executed the Create method.");
// Check the return value to determine success
let return_value_prop = out_params
.Properties_()?
.Item(&BSTR::from("ReturnValue"), 0)?;
let return_value: VARIANT = return_value_prop.Value()?;
println!(
"Return value variant type: {:?}",
return_value.Anonymous.Anonymous.vt
);
println!(
"Return value: {:?}",
return_value.Anonymous.Anonymous.Anonymous.lVal
);
// Access the value correctly based on the VARIANT type
if return_value.Anonymous.Anonymous.vt == VT_I4 {
if return_value.Anonymous.Anonymous.Anonymous.lVal == 0 {
println!("Session {} logged off successfully.", session_id);
} else {
println!("Failed to log off session {}.", session_id);
}
} else {
println!(
"Unexpected VARIANT type: {:?}",
return_value.Anonymous.Anonymous.vt
);
}
println!("FINISHED logoff_session!");
Ok(())
}
}
Here is the loggin output:
RUNNING logoff_session...
Got the process class object.
Got the Create method from the process class.
Spawned an instance of the input parameters.
Got the CommandLine property.
Prepared the VARIANT for the command.
Set the CommandLine property value to logoff command.
Converted input parameters to IDispatch.
Executed the Create method.
Return value variant type: VARENUM(3)
Return value: 0
Session 999999 logged off successfully.
FINISHED logoff_session!
This feels like a bug to me.
Crate manifest
[package]
name = "windows_interface_test"
version = "1.0.0"
edition = "2021"
[lib]
name = "windows_interface_test"
path = "src/lib.rs"
[[bin]]
name = "windows_interface_test_bin"
path = "src/main.rs"
[dependencies]
windows = { version = "0.52.0", features = [
"implement",
"Win32_Foundation",
"Win32_Security",
"Win32_System_Com",
"Win32_System_Ole",
"Win32_System_Rpc",
"Win32_System_Wmi",
"Win32_System_Variant",
] }
Crate code
No response
Hey, glad you like windows-rs! Can you try the latest version? There are various improvements to both WMI
and VARIANT
support. #2786
Here's an example:
https://github.com/microsoft/windows-rs/tree/master/crates/samples/windows/wmi
Win32_Process::Create returns a value of 0 (zero) if the process was successfully created, and any other number to indicate an error. (doc) It does not return the status code returned by logoff.exe. To verify things are working correctly, try executing abcdef
instead of logoff
.
Hi @kennykerr, hi @riverar,
First off, thank you for your quick responses and the continuous improvements to this project!
Feedback on Version Update (0.52 -> 0.58):
I've recently attempted to upgrade from version 0.52 to 0.58 (noting that 0.59 isn't available on crates.io yet). The number of changes, particularly around the handling of ISWbemObject and VARIANT, has been a bit overwhelming. For instance, the following code that worked in 0.52 is no longer functional:
if let Some(dispatch) = var.Anonymous.Anonymous.Anonymous.pdispVal.as_ref() {
let item: ISWbemObject = dispatch.cast()?;
let instance = T::from_wmi_object(&item)?;
results.push(instance);
}
In the newer versions, this now returns a &c_void
(when accessed with var.as_raw().Anonymous.Anonymous.Anonymous.pdispVal.as_ref()
) instead of the previous ManuallyDrop<Option<IDispatch>>
. This change has significantly impacted my ability to run the desired queries as I heavily rely on VARENUMS
and patterns like the one above.
Given the scope of the changes, I found it difficult to update my code to work with versions beyond 0.52. I do see the value in the new VARIANT
methods for value access, and when I have more time, I plan to refactor my code to match the newer versions. However, for now, the update is more than I can manage.
PS.: Please note that the samples are using WbemObject
whereas I am using SWbemObject
.
Success Code Always 0 Feedback:
Regarding the ExecMethod
function, I've noticed that it returns a value of 0 when the process exists and can be created (thanks for pointing that out @riverar). However, the actual result of that process isn't returned. This isn't a crate-specific issue, but I thought it worth mentioning as I continue to explore this behavior further.
Thanks again for all your hard work on this project. I look forward to integrating the new updates when I have the bandwidth to do so!
Best regards