Skip to content

Commit

Permalink
OsString
Browse files Browse the repository at this point in the history
  • Loading branch information
kennykerr committed Jun 24, 2024
1 parent 863a7cf commit b5dbbb0
Show file tree
Hide file tree
Showing 9 changed files with 97 additions and 18 deletions.
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

0 comments on commit b5dbbb0

Please sign in to comment.