Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add OsString support to windows-registry crate #3121

Closed
wants to merge 1 commit into from
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)]
kennykerr marked this conversation as resolved.
Show resolved Hide resolved

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 = []
kennykerr marked this conversation as resolved.
Show resolved Hide resolved

[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(),
kennykerr marked this conversation as resolved.
Show resolved Hide resolved
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> {
kennykerr marked this conversation as resolved.
Show resolved Hide resolved
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)]
kennykerr marked this conversation as resolved.
Show resolved Hide resolved

#[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)]
kennykerr marked this conversation as resolved.
Show resolved Hide resolved
#![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
Loading