Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/libs/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Learn more about Rust for Windows here: <https://github.com/microsoft/windows-rs
windows_debugger_visualizer,
debugger_visualizer(natvis_file = "../.natvis")
)]
#![cfg_attr(all(not(test), not(feature = "std")), no_std)]
#![cfg_attr(all(not(feature = "std")), no_std)]

extern crate self as windows_core;

Expand Down
5 changes: 4 additions & 1 deletion crates/libs/registry/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ description = "Windows registry"
repository = "https://github.com/microsoft/windows-rs"
readme = "readme.md"
categories = ["os::windows-apis"]
exclude = ["tests"]

[features]
default = ["std"]
std = []

[lints]
workspace = true
Expand Down
78 changes: 67 additions & 11 deletions crates/libs/registry/src/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ impl Key {
let result = unsafe {
RegCreateKeyExW(
self.0,
pcwstr(path).as_ptr(),
encode_utf16(path).as_ptr(),
0,
null(),
REG_OPTION_NON_VOLATILE,
Expand All @@ -38,8 +38,15 @@ impl Key {
pub fn open<T: AsRef<str>>(&self, path: T) -> Result<Self> {
let mut handle = core::ptr::null_mut();

let result =
unsafe { RegOpenKeyExW(self.0, pcwstr(path).as_ptr(), 0, KEY_READ, &mut handle) };
let result = unsafe {
RegOpenKeyExW(
self.0,
encode_utf16(path).as_ptr(),
0,
KEY_READ,
&mut handle,
)
};

win32_error(result).map(|_| Self(handle))
}
Expand All @@ -61,13 +68,13 @@ impl Key {

/// Removes the registry keys and values of the specified key recursively.
pub fn remove_tree<T: AsRef<str>>(&self, path: T) -> Result<()> {
let result = unsafe { RegDeleteTreeW(self.0, pcwstr(path).as_ptr()) };
let result = unsafe { RegDeleteTreeW(self.0, encode_utf16(path).as_ptr()) };
win32_error(result)
}

/// Removes the registry value.
pub fn remove_value<T: AsRef<str>>(&self, name: T) -> Result<()> {
let result = unsafe { RegDeleteValueW(self.0, pcwstr(name).as_ptr()) };
let result = unsafe { RegDeleteValueW(self.0, encode_utf16(name).as_ptr()) };
win32_error(result)
}

Expand All @@ -93,15 +100,15 @@ impl Key {

/// Sets the name and value in the registry key.
pub fn set_string<T: AsRef<str>>(&self, name: T, value: T) -> Result<()> {
let value = pcwstr(value);
let value = encode_utf16(value);

unsafe { self.set_value(name, REG_SZ, value.as_ptr() as _, value.len() * 2) }
}

/// Sets the name and value in the registry key.
pub fn set_multi_string<T: AsRef<str>>(&self, name: T, value: &[T]) -> Result<()> {
let mut packed = value.iter().fold(vec![0u16; 0], |mut packed, value| {
packed.append(&mut pcwstr(value));
packed.append(&mut encode_utf16(value));
packed
});

Expand All @@ -117,7 +124,7 @@ impl Key {

/// Gets the type for the name in the registry key.
pub fn get_type<T: AsRef<str>>(&self, name: T) -> Result<Type> {
let name = pcwstr(name);
let name = encode_utf16(name);
let mut ty = 0;

let result = unsafe {
Expand Down Expand Up @@ -145,7 +152,7 @@ impl Key {

/// Gets the value for the name in the registry key.
pub fn get_value<T: AsRef<str>>(&self, name: T) -> Result<Value> {
let name = pcwstr(name);
let name = encode_utf16(name);
let mut ty = 0;
let mut len = 0;

Expand Down Expand Up @@ -280,7 +287,7 @@ impl Key {

/// Gets the value for the name in the registry key.
pub fn get_bytes<T: AsRef<str>>(&self, name: T) -> Result<Vec<u8>> {
let name = pcwstr(name);
let name = encode_utf16(name);
let mut len = 0;

let result = unsafe {
Expand Down Expand Up @@ -320,14 +327,63 @@ impl Key {
}
}

/// Sets the name and value in the registry key.
#[cfg(feature = "std")]
pub fn set_os_string<N: AsRef<str>, V: AsRef<std::ffi::OsStr>>(
&self,
name: N,
value: V,
) -> Result<()> {
let value = encode_wide(value);

unsafe { self.set_value(name, REG_SZ, value.as_ptr() as _, value.len() * 2) }
}

/// Gets the value for the name in the registry key.
#[cfg(feature = "std")]
pub fn get_os_string<T: AsRef<str>>(&self, name: T) -> Result<std::ffi::OsString> {
let name = encode_utf16(name);
let mut ty = 0;
let mut len = 0;

let result = unsafe {
RegQueryValueExW(self.0, name.as_ptr(), null(), &mut ty, null_mut(), &mut len)
};

win32_error(result)?;
let mut value = vec![0u16; len as usize / 2];

let result = unsafe {
RegQueryValueExW(
self.0,
name.as_ptr(),
null(),
null_mut(),
value.as_mut_ptr() as _,
&mut len,
)
};

win32_error(result)?;
use std::os::windows::prelude::*;
Ok(std::ffi::OsString::from_wide(trim(&value)))
}

unsafe fn set_value<T: AsRef<str>>(
&self,
name: T,
ty: REG_VALUE_TYPE,
ptr: *const u8,
len: usize,
) -> Result<()> {
let result = RegSetValueExW(self.0, pcwstr(name).as_ptr(), 0, ty, ptr, len.try_into()?);
let result = RegSetValueExW(
self.0,
encode_utf16(name).as_ptr(),
0,
ty,
ptr,
len.try_into()?,
);

win32_error(result)
}
Expand Down
14 changes: 12 additions & 2 deletions crates/libs/registry/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Learn more about Rust for Windows here: <https://github.com/microsoft/windows-rs>
*/

#![cfg_attr(not(test), no_std)]
#![cfg_attr(all(not(feature = "std")), no_std)]

#[macro_use]
extern crate alloc;
Expand Down Expand Up @@ -45,14 +45,24 @@ pub const LOCAL_MACHINE: &Key = &Key(HKEY_LOCAL_MACHINE);
/// The predefined `HKEY_USERS` registry key.
pub const USERS: &Key = &Key(HKEY_USERS);

fn pcwstr<T: AsRef<str>>(value: T) -> Vec<u16> {
fn encode_utf16<T: AsRef<str>>(value: T) -> Vec<u16> {
value
.as_ref()
.encode_utf16()
.chain(core::iter::once(0))
.collect()
}

#[cfg(feature = "std")]
fn encode_wide<T: AsRef<std::ffi::OsStr>>(value: T) -> Vec<u16> {
use std::os::windows::prelude::*;
value
.as_ref()
.encode_wide()
.chain(core::iter::once(0))
.collect()
}

fn trim(mut value: &[u16]) -> &[u16] {
while value.last() == Some(&0) {
value = &value[..value.len() - 1];
Expand Down
1 change: 0 additions & 1 deletion crates/libs/result/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ description = "Windows error handling"
repository = "https://github.com/microsoft/windows-rs"
readme = "readme.md"
categories = ["os::windows-apis"]
exclude = ["tests"]

[features]
default = ["std"]
Expand Down
2 changes: 1 addition & 1 deletion crates/libs/result/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Learn more about Rust for Windows here: <https://github.com/microsoft/windows-rs
windows_debugger_visualizer,
debugger_visualizer(natvis_file = "../.natvis")
)]
#![cfg_attr(all(not(test), not(feature = "std")), no_std)]
#![cfg_attr(all(not(feature = "std")), no_std)]
#![cfg_attr(not(windows), allow(unused_imports))]

extern crate alloc;
Expand Down
2 changes: 1 addition & 1 deletion crates/libs/version/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Learn more about Rust for Windows here: <https://github.com/microsoft/windows-rs>
*/

#![cfg_attr(not(test), no_std)]
#![no_std]

mod bindings;
use bindings::*;
Expand Down
4 changes: 4 additions & 0 deletions crates/tests/registry/tests/bad_string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,9 @@ fn bad_string() -> Result<()> {

let value_as_bytes = key.get_bytes("name")?;
assert_eq!(value_as_bytes, bad_string_bytes);

let value_as_os_string = key.get_os_string("name")?;
assert_eq!(value_as_os_string.to_string_lossy(), "�ā");

Ok(())
}
7 changes: 7 additions & 0 deletions crates/tests/registry/tests/values.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ fn values() -> Result<()> {
key.set_u32("u32", 123)?;
key.set_u64("u64", 456)?;
key.set_string("string", "hello")?;
key.set_os_string("os_string", "hello os")?;
key.set_bytes("bytes", &[1u8, 2u8, 2u8])?;
key.set_multi_string("multi", &["hello", "world"])?;

assert_eq!(key.get_u32("u32")?, 123u32);
assert_eq!(key.get_u64("u64")?, 456u64);
assert_eq!(key.get_string("string")?, "hello".to_string());
assert_eq!(&key.get_os_string("os_string")?, "hello os");
assert_eq!(key.get_bytes("bytes")?, vec![1u8, 2u8, 2u8]);
assert_eq!(
key.get_multi_string("multi")?,
Expand Down Expand Up @@ -43,6 +45,10 @@ fn values() -> Result<()> {
("u32".to_string(), Value::U32(123)),
("u64".to_string(), Value::U64(456)),
("string".to_string(), Value::String("hello".to_string())),
(
"os_string".to_string(),
Value::String("hello os".to_string())
),
("bytes".to_string(), Value::Bytes(vec![1u8, 2u8, 2u8])),
(
"multi".to_string(),
Expand All @@ -52,6 +58,7 @@ fn values() -> Result<()> {
);

key.remove_value("string")?;
key.remove_value("os_string")?;
key.remove_value("multi")?;
let names: Vec<_> = key.values()?.collect();

Expand Down