0

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?

IInspectable
  • 46,945
  • 8
  • 85
  • 181
Tony
  • 266
  • 1
  • 11
  • All COM methods have a hidden self/this parameter. This makes this a generic question about COM... – Anders Oct 23 '22 at 15:28
  • @Anders Could you point me in the right direction? I'm having trouble making sense of the documentation. – Tony Oct 23 '22 at 15:34
  • I don't use rust. Find a guide about using COM in rust... – Anders Oct 23 '22 at 15:35
  • I'd posted a full example to [this question](https://stackoverflow.com/q/69501315/1889329) previously, in C++, that retrieves the wallpaper for multiple monitors. If you're still struggling, I'll translate it into Rust. – IInspectable Oct 23 '22 at 17:04

1 Answers1

4

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",
]
IInspectable
  • 46,945
  • 8
  • 85
  • 181