Search code examples
winapirustwindows-rs

Not sure how to use IDesktopWallpaper


In the documentation there is a struct 'IDesktopWallpaper' with a method named 'GetWallpaper'. The method takes a reference to 'self' but there is no constructor method for 'IDesktopWallpaper'.

use windows::{
    core::*,
    Win32::UI::Shell::IDesktopWallpaper,
};

fn main() -> Result<()> {
    unsafe {
        //                              ?????
        IDesktopWallpaper::GetWallpaper(&self, monitorid);
    }

    Ok(())
}

What am I supposed to do in order to get my desired outcome?


Solution

  • COM generally uses factory methods to construct COM objects. The "standard" factory method for classic COM is CoCreateInstance. It needs a class ID that identifies the specific implementation (in case there are multiple) and an interface ID that names the requested interface.

    The windows crate exposes class IDs differently from the Windows SDK: The latter frequently uses CLSID_-prefixes, wheres the former doesn't. DesktopWallpaper in the windows crate is the same GUID as CLSID_DesktopWallpaper in the Windows SDK.

    Another difference is that CoCreateInstance in the windows crate is generic over its returned interface type (as opposed to taking the address of a type-erased void* in the Windows SDK). Clients will need to explicitly name the interface type they are requesting.

    The following code initializes COM (required), instantiates a COM object, and returns an IDesktopWallpaper interface for further use:

    use windows::{
        core::Result,
        Win32::{
            System::Com::{CoCreateInstance, CoInitialize, CLSCTX_ALL},
            UI::Shell::{DesktopWallpaper, IDesktopWallpaper},
        },
    };
    
    fn main() -> Result<()> {
        // Initialize COM
        unsafe { CoInitialize(None) }?;
        // Create a DesktkopWallpaper object and return its IDesktopWallpaper interface
        let wallpaper: IDesktopWallpaper =
            unsafe { CoCreateInstance(&DesktopWallpaper, None, CLSCTX_ALL) }?;
        // Use the COM object
        unsafe { wallpaper.GetWallpaper(...) };
    
        Ok(())
    }
    

    You'll need to have the following in your Cargo.toml file:

    [dependencies.windows]
    version = "0.42.0"
    features = [
        "Win32_UI_Shell",
        "Win32_System_Com",
    ]