4

I'm using the IDesktopWallpaper::SetWallpaper method from the windows crate. The second argument to this method is a PCWSTR(pointer) to the full path of an image that's meant to be set as the wallpaper. The problem is that the PCWSTR object is meant to be of type *const u16 not *const String. How can I get a PCWSTR object from a Path/String?

let path = "Path_to_image.jpg".to_string();
let ptr = &path as *const String;
let wallpaper = PCWSTR::from_raw(ptr); 
//                               ^^^  expected raw pointer `*const u16` 
//                                         found raw pointer `*const String`

unsafe { desktop.SetWallpaper(None, wallpaper)};
IInspectable
  • 46,945
  • 8
  • 85
  • 181
Tony
  • 266
  • 1
  • 11
  • If the source is a string literal you can simply make use of the [`w!`](https://microsoft.github.io/windows-docs-rs/doc/windows/macro.w.html) macro, i.e. `desktop.SetWallpaper(None, w!("Path_to_image.jpg"));`. – IInspectable Oct 23 '22 at 17:17
  • @IInspectable For this simple example, it works. However, this solution isn't enough for the overall scope of my project. – Tony Oct 23 '22 at 17:25
  • @IInspectable I found that there is a type "HSTRING" that can be turned into a "PCWSTR". However, I don't think I can initialize it with a specific string. I can only create an empty one. – Tony Oct 23 '22 at 17:53
  • 2
    `HSTRING` has a [`From`](https://microsoft.github.io/windows-docs-rs/doc/windows/core/struct.HSTRING.html#impl-From%3C%26str%3E-for-HSTRING) implementation for `&str` (and a number of other Rust string types). So either use `HSTRING` as an intermediary, or `encode_utf16().chain(iter::once(0)).collect::>()` to get a buffer you can `as_ptr()` to construct a `PCWSTR`. – IInspectable Oct 23 '22 at 17:58
  • @IInspectable Wow, I didn't even see the `From`. Thanks. – Tony Oct 23 '22 at 18:00

1 Answers1

9

When it comes to strings, Rust and Windows couldn't possibly disagree more. There's always going to be conversions involved when using Rust on Windows, and the best you can hope for is a crate that does this for you.

The windows crate doesn't just provide Rust mappings for Windows' API surface, it also contains a tiny library that addresses common issues when programming Windows with Rust, amongst which is string handling. A lot of thought went into string handling, and the result may seem somewhat anticlimactic: All string constants can be represented as HSTRING instances.

Consequently, HSTRING is the pivot point for string conversions in Rust for Windows. Its implementation has a sleuth of From trait implementations for Rust string types (all, I believe), with From implementations of all other Windows string types for HSTRING.

In this case, if path is of type Path you can simply construct an HSTRING from it, and pass it by reference. Everything else just happens due to implicit From trait invocations (namely From<&HSTRING> for PCWSTR):

unsafe { desktop.SetWallpaper(None, &HSTRING::from(path.as_os_str())) };
IInspectable
  • 46,945
  • 8
  • 85
  • 181