Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IWbemServices::ExecMethod support for WMIConnection #58

Open
disassembledd opened this issue Sep 4, 2022 · 4 comments
Open

IWbemServices::ExecMethod support for WMIConnection #58

disassembledd opened this issue Sep 4, 2022 · 4 comments

Comments

@disassembledd
Copy link

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
Copy link
Author

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
Copy link
Owner

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
Copy link

ydirson commented Dec 20, 2023

@Soul85 I see you did make progress in microsoft/windows-rs#2040, do you have some updates?

@ydirson
Copy link

ydirson commented Dec 21, 2023

@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 microsoft/windows-rs#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/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants