Skip to content

Instantly share code, notes, and snippets.

@sheepla
Last active February 9, 2025 11:09
Show Gist options
  • Save sheepla/e0ed14716f179010adfd12472404daff to your computer and use it in GitHub Desktop.
Save sheepla/e0ed14716f179010adfd12472404daff to your computer and use it in GitHub Desktop.
Cheat Sheet for windows-rs (WIP)

Cheat sheet for windows-rs 🚀

🦀 Basic string types in Rust

  • String:
    A growable, heap-allocated string type. It's the most common string type used in Rust and is often used when you need to modify the string's contents.

  • &str:
    A string slice, which is a reference to a portion of a string, usually a part of a String or a string literal. It is an immutable reference to a sequence of UTF-8 encoded bytes.

  • OsString:
    A type that can represent owned, mutable platform-native strings. It is often used when dealing with operating system-specific APIs, particularly for filenames, paths, and environment variables. It can be cheaply converted into and from String and &str.

  • &Path:
    A string slice of a path, representing an immutable reference to a path on the filesystem. It is used in Rust's std::path::Path to handle file and directory paths in an OS-independent manner.

  • PathBuf:
    A growable, owned, and mutable version of &Path. It allows for manipulation and modification of paths and can be converted back to &Path.

  • Vec<u8>:
    A dynamic, owned collection of bytes. While not directly a string type, it can be used to store raw byte data that can represent a string in UTF-8 or any other encoding.

  • &[u8]:
    A slice of bytes, representing an immutable reference to a sequence of bytes. It can be used to work with raw byte data, including UTF-8 encoded strings.

  • Vec<u16>:
    A dynamic, owned collection of 16-bit unsigned integers. While not a typical string type, it can represent sequences of UTF-16 encoded characters.

  • &[u16]:
    A slice of 16-bit unsigned integers, which can be used to represent a sequence of UTF-16 encoded characters. It provides an immutable reference to the underlying data.

🪟 Windows-Specific String Types in Rust (windows_strings crate)

When working with Windows APIs, different string types are used for interoperability with COM, WinRT, and C-style strings. Below are the most common Windows string types available in Rust.

WinRT Strings

  • HSTRING
    A reference-counted, immutable UTF-16 string used in Windows Runtime (WinRT). HSTRING is designed for efficient sharing across API boundaries and is often used for interop with WinRT components.

COM (Component Object Model) Strings

  • BSTR
    A length-prefixed, mutable UTF-16 string type primarily used in COM programming. Unlike null-terminated strings, BSTR stores its length before the string data, allowing it to contain embedded null characters.

C-Style Strings (Pointer to null-terminated characters)

C-style strings are widely used in low-level Windows API calls and interop scenarios. These types are raw pointers representing ANSI or Unicode strings.

  • PSTR
    A mutable pointer to a null-terminated ANSI string (*mut u8). This is typically used in legacy Windows APIs that expect ANSI encoding (Windows-1252 or system locale).

  • PCSTR
    An immutable pointer to a null-terminated ANSI string (*const u8). Used when a function expects a read-only ANSI string.

  • PWSTR
    A mutable pointer to a null-terminated UTF-16 wide string (*mut u16). This is commonly used in Windows APIs that expect Unicode strings, such as file paths and registry values.

  • PCWSTR
    An immutable pointer to a null-terminated UTF-16 wide string (*const u16). Used when a function requires a read-only wide string.

🦀→🪟 Convert from Rust string types into windows_strings crate strings types

flowchart LR
    WChar["#40;Raw Wide Characters#41;<br>#amp;[u16]"]
    Literal["#38;str Literal"]
    Literal --> |"h! macro"| HSTRING
    Literal --> |"s! macro"| CStyleAsciiStrings
    Literal --> |"w! macro"| CStyleWideStrings
    HSTRING["HSTRING<br>#40;Reference-Counted and immutable UTF-16 String for WinRT#41;"]
    BSTR["BSTR<br>#40;Length-Prefixed Wide String for COM#41;"]  
    CStyleAsciiStrings["#40;C-Style Null-Terminalted ASCII Strings#41;<br>PSTR<br>PCSTR"]
    CStyleWideStrings["#40;C-Style Null-Terminated Wide Strings#41;<br>PWSTR<br>PCWSTR"]


    %% Other string types -> HSTRING
    String["String"] --> |"From"| HSTRING
    OsStr --> |"From" | HSTRING
    OsString --> |"From" | HSTRING
    WChar --> | HSTRING::from_wide | HSTRING

    %% HSTRING -> Other string types
    HSTRING --> |"Deref#lt;Target = #38;#91;u16#93;#62;"| CStyleWideStrings
    %% HSTRING --> |".to_string_lossy#40;#41;"| String
    %% HSTRING --> |".to_os_string#40;#41;"| OsString

    %% Other string types -> BSTR
    String["String"] --> |"From"| BSTR
    OsStr --> |"From" | BSTR
    OsString --> |"From" | BSTR
    WChar --> | BSTR::from_wide | BSTR
Loading
// Example code for convert between Rust strings and Windows strings
use std::ffi::OsString;
use windows::core::{BSTR, HSTRING};
// Rust strings --> Windows strings
fn rust_to_hstring(s: &str) -> HSTRING {
s.into()
}
fn rust_to_bstr(s: &str) -> BSTR {
s.into()
}
fn osstring_to_hstring(os: &OsString) -> HSTRING {
os.clone().into()
}
fn osstring_to_bstr(os: &OsString) -> BSTR {
os.to_string_lossy().to_string().into()
}
fn wide_to_hstring(wide: &[u16]) -> HSTRING {
HSTRING::from_wide(wide)
}
fn wide_to_bstr(wide: &[u16]) -> BSTR {
BSTR::from_wide(wide)
}
// Windows strings --> Rust strings
fn hstring_to_string(h: &HSTRING) -> String {
h.to_string()
}
fn hstring_to_osstring(h: &HSTRING) -> OsString {
h.to_os_string()
}
fn bstr_to_string(b: &BSTR) -> String {
b.to_string()
}
fn bstr_to_osstring(b: &BSTR) -> OsString {
OsString::from(b.to_string())
}
fn main() {
let rust_str = "Hello, Windows!";
let rust_osstring = OsString::from("Hello, OsString!");
let wide: Vec<u16> = rust_str.encode_utf16().collect();
// Convert Rust -> Windows
let hstring = rust_to_hstring(rust_str);
let bstr = rust_to_bstr(rust_str);
let hstring_from_os = osstring_to_hstring(&rust_osstring);
let bstr_from_os = osstring_to_bstr(&rust_osstring);
let hstring_from_wide = wide_to_hstring(&wide);
let bstr_from_wide = wide_to_bstr(&wide);
// Convert Windows -> Rust
let rust_string_from_h = hstring_to_string(&hstring);
let rust_osstring_from_h = hstring_to_osstring(&hstring);
let rust_string_from_b = bstr_to_string(&bstr);
let rust_osstring_from_b = bstr_to_osstring(&bstr);
println!("HSTRING to String: {}", rust_string_from_h);
println!("HSTRING to OsString: {:?}", rust_osstring_from_h);
println!("BSTR to String: {}", rust_string_from_b);
println!("BSTR to OsString: {:?}", rust_osstring_from_b);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment