ohadravid / wmi-rs

WMI crate for rust
Apache License 2.0
80 stars 27 forks source link

IWbemServices::ExecMethod support for WMIConnection #58

Open disassembledd opened 2 years ago

disassembledd commented 2 years ago

Hi,

As this is intended to be an "all things WMI" sort of crate by the look of it, I would like to introduce the idea of implementing a high-level ExecMethod. It appears rather straightforward, requiring only a couple helper methods for obtaining the parameters a method requires and setting the properties for said parameters if they are classes.

I propose a single exposed method, execute_method, which would take in an object path (strObjectPath: BStr), method name (strMethodName: BStr), potentially a HashMap<String, T> or serialized class for parameters (pInParams: *mut IWbemClassObject) and another potential HashMap<String, Variant> or serialized class for results (ppOutParams: &*mut IWbemClassObject).

fn execute_method(&self, strObjectPath: &str, strMethodName: &str, inParams: HashMap<String, T>) -> Result<U, WMIError> {
    let object_path = BStr::from_str(strObjectPath)?;
    let method_name = BStr::from_str(strMethodName)?;

    let mut pObject = ptr::null_mut::<IWbemClassObject>();
    unsafe {
        check_hres((*self.svc).GetObject(
            object_path.as_bstr(),
            0,
            ptr::null_mut(),
            &mut pObject,
            ptr::null_mut()
        ))?;
    }

    let mut pInParams = ptr::null_mut::<IWbemClassObject>();
    let mut pOutParams = ptr::null_mut::<IWbemClassObject>();
    unsafe {
        check_hres((*pObject).GetMethod(
            method_name.as_lpcwstr(),
            0,
            &mut pInParams,
            &mut pOutParams
        ))?;
    }

    // Work with Variants/serializing etc. (I am still fairly new to Rust and the Win32 API so I am unsure of this yet)
    unsafe {
        check_hres((*self.svc).ExecMethod(
            object_path.as_bstr(),
            method_name.as_bstr(),
            0,
            ptr::null_mut(),
            pInParams,
            &mut pOutParams,
            ptr::null_mut()
        ))?;
    }

    // Handle serializing of pOutParams
}

Note: I am still by all means a beginner with Rust best practices. This example is most likely not the best way to go about this, I just wanted to bring this to attention and state that I am currently attempting to implement it as a side project.

disassembledd commented 2 years ago

This can be related to #18, however I am approaching the design from a different aspect. Also after further work, I have managed to make basic method calls (such as StopService/StartService) as well as calls that require parameters to be passed in (such as ChangeStartMode). My original example does not include all the necessary code to, for example, spawn an instance of the pInParams class object and use VARIANTs to set the instance's properties before passing to ExecMethod. I will return to working on an implementation once I finish my original goal of creating a CLI for work.

ohadravid commented 1 year ago

Hi 🙂

I think that creating the initial safe and more Rust-y API is a great first step for this feature.

A way to support out-params will also be interesting, maybe something like:

fn execute_method<In, Out>(&self, object_path: &str, method_name: &str, in_params: In) -> Result<Out, WMIError>;

Where In: Serialize and Out: Deserialize, and let serialized_in: HashMap<String, Variant> = /* something with in */;, and the return is like the current query methods.

Some links for reference from MSDN: https://learn.microsoft.com/en-us/windows/win32/wmisdk/example--calling-a-provider-method https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/create-method-in-class-win32-process https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/terminate-method-in-class-win32-process

ydirson commented 9 months ago

@Soul85 I see you did make progress in https://github.com/microsoft/windows-rs/issues/2040, do you have some updates?

ydirson commented 9 months ago

@ohadravid I'm try to get such method calls to work in an iterative manner, first implementing one rust func for each method call, and then we'll see what can be done to build a rustified abstraction.

But I admit not being accustomed to the Windows APIs does not make things easy. And the lack of access to previous windows-rs docs combined with wmi-rs using old 0.48 is also getting in the way (though I dread the day when I'll have to rework for 0.52).

Found this post which is quite didactic as to how things work in C, and borrowed from https://github.com/microsoft/windows-rs/issues/2040.

Also opened a feature request for a full ExecMethod example in windows-rs, that would really help.

Ongoing exploration work pushed to https://github.com/xcp-ng/xenstore-win/