Switch to the windows crate

This commit is contained in:
Damien Elmes 2025-06-29 16:49:20 +07:00
parent 349a696f93
commit 6eb1db0f5d
4 changed files with 40 additions and 33 deletions

2
Cargo.lock generated
View file

@ -3548,7 +3548,7 @@ dependencies = [
"embed-resource", "embed-resource",
"libc", "libc",
"libc-stdhandle", "libc-stdhandle",
"winapi", "windows 0.61.3",
] ]
[[package]] [[package]]

View file

@ -139,7 +139,7 @@ unicode-normalization = "0.1.24"
walkdir = "2.5.0" walkdir = "2.5.0"
which = "8.0.0" which = "8.0.0"
winapi = { version = "0.3", features = ["wincon", "winreg"] } winapi = { version = "0.3", features = ["wincon", "winreg"] }
windows = { version = "0.61.3", features = ["Media_SpeechSynthesis", "Media_Core", "Foundation_Collections", "Storage_Streams"] } windows = { version = "0.61.3", features = ["Media_SpeechSynthesis", "Media_Core", "Foundation_Collections", "Storage_Streams", "Win32_System_Console", "Win32_System_Registry", "Win32_Foundation"] }
wiremock = "0.6.3" wiremock = "0.6.3"
xz2 = "0.1.7" xz2 = "0.1.7"
zip = { version = "4.1.0", default-features = false, features = ["deflate", "time"] } zip = { version = "4.1.0", default-features = false, features = ["deflate", "time"] }

View file

@ -15,7 +15,7 @@ camino.workspace = true
dirs.workspace = true dirs.workspace = true
[target.'cfg(windows)'.dependencies] [target.'cfg(windows)'.dependencies]
winapi.workspace = true windows.workspace = true
libc.workspace = true libc.workspace = true
libc-stdhandle.workspace = true libc-stdhandle.workspace = true

View file

@ -8,14 +8,21 @@ use std::process::Command;
use anyhow::Context; use anyhow::Context;
use anyhow::Result; use anyhow::Result;
use winapi::shared::minwindef::HKEY; use windows::core::PCWSTR;
use winapi::um::wincon; use windows::Win32::System::Registry::HKEY_CURRENT_USER;
use winapi::um::winnt::KEY_READ; use windows::Win32::System::Console::AttachConsole;
use winapi::um::winreg; use windows::Win32::System::Console::GetConsoleWindow;
use windows::Win32::System::Console::ATTACH_PARENT_PROCESS;
use windows::Win32::System::Registry::RegCloseKey;
use windows::Win32::System::Registry::RegOpenKeyExW;
use windows::Win32::System::Registry::RegQueryValueExW;
use windows::Win32::System::Registry::HKEY;
use windows::Win32::System::Registry::KEY_READ;
use windows::Win32::System::Registry::REG_SZ;
pub fn ensure_terminal_shown() -> Result<()> { pub fn ensure_terminal_shown() -> Result<()> {
unsafe { unsafe {
if !wincon::GetConsoleWindow().is_null() { if !GetConsoleWindow().is_invalid() {
// We already have a console, no need to spawn anki-console.exe // We already have a console, no need to spawn anki-console.exe
return Ok(()); return Ok(());
} }
@ -51,12 +58,12 @@ pub fn ensure_terminal_shown() -> Result<()> {
pub fn attach_to_parent_console() -> bool { pub fn attach_to_parent_console() -> bool {
unsafe { unsafe {
if !wincon::GetConsoleWindow().is_null() { if !GetConsoleWindow().is_invalid() {
// we have a console already // we have a console already
return false; return false;
} }
if wincon::AttachConsole(wincon::ATTACH_PARENT_PROCESS) != 0 { if AttachConsole(ATTACH_PARENT_PROCESS).is_ok() {
// successfully attached to parent // successfully attached to parent
reconnect_stdio_to_console(); reconnect_stdio_to_console();
true true
@ -136,7 +143,7 @@ fn get_uninstaller_path() -> Option<std::path::PathBuf> {
fn read_registry_install_dir() -> Option<std::path::PathBuf> { fn read_registry_install_dir() -> Option<std::path::PathBuf> {
unsafe { unsafe {
let mut hkey: HKEY = std::ptr::null_mut(); let mut hkey = HKEY::default();
// Convert the registry path to wide string // Convert the registry path to wide string
let subkey: Vec<u16> = OsStr::new("SOFTWARE\\Anki") let subkey: Vec<u16> = OsStr::new("SOFTWARE\\Anki")
@ -145,15 +152,15 @@ fn read_registry_install_dir() -> Option<std::path::PathBuf> {
.collect(); .collect();
// Open the registry key // Open the registry key
let result = winreg::RegOpenKeyExW( let result = RegOpenKeyExW(
winreg::HKEY_CURRENT_USER, HKEY_CURRENT_USER,
subkey.as_ptr(), PCWSTR(subkey.as_ptr()),
0, Some(0),
KEY_READ, KEY_READ,
&mut hkey, &mut hkey,
); );
if result != 0 { if result.is_err() {
return None; return None;
} }
@ -163,38 +170,38 @@ fn read_registry_install_dir() -> Option<std::path::PathBuf> {
.chain(std::iter::once(0)) .chain(std::iter::once(0))
.collect(); .collect();
let mut value_type = 0u32; let mut value_type = REG_SZ;
let mut data_size = 0u32; let mut data_size = 0u32;
// First call to get the size // First call to get the size
let result = winreg::RegQueryValueExW( let result = RegQueryValueExW(
hkey, hkey,
value_name.as_ptr(), PCWSTR(value_name.as_ptr()),
std::ptr::null_mut(), None,
&mut value_type, Some(&mut value_type),
std::ptr::null_mut(), None,
&mut data_size, Some(&mut data_size),
); );
if result != 0 || data_size == 0 { if result.is_err() || data_size == 0 {
winreg::RegCloseKey(hkey); let _ = RegCloseKey(hkey);
return None; return None;
} }
// Allocate buffer and read the value // Allocate buffer and read the value
let mut buffer: Vec<u16> = vec![0; (data_size / 2) as usize]; let mut buffer: Vec<u16> = vec![0; (data_size / 2) as usize];
let result = winreg::RegQueryValueExW( let result = RegQueryValueExW(
hkey, hkey,
value_name.as_ptr(), PCWSTR(value_name.as_ptr()),
std::ptr::null_mut(), None,
&mut value_type, Some(&mut value_type),
buffer.as_mut_ptr() as *mut u8, Some(buffer.as_mut_ptr() as *mut u8),
&mut data_size, Some(&mut data_size),
); );
winreg::RegCloseKey(hkey); let _ = RegCloseKey(hkey);
if result == 0 { if result.is_ok() {
// Convert wide string back to PathBuf // Convert wide string back to PathBuf
let len = buffer.iter().position(|&x| x == 0).unwrap_or(buffer.len()); let len = buffer.iter().position(|&x| x == 0).unwrap_or(buffer.len());
let path_str = String::from_utf16_lossy(&buffer[..len]); let path_str = String::from_utf16_lossy(&buffer[..len]);