refactor(windows-rs): use "wide" fns uniformly

This commit builds on @EBNull's comment shedding light on the uses of
the -A and -W functions in the Win32 API, and standardizes the calling
of the -W functions across the project.

Since UTF-16 String handling is a bit lacking in the Rust standard
library, I have pulled in the widestring crate to use the
from_slice_truncate fn to automagically remove all of the trailing null
chars when handling values returned from the various Win32 -W fns.

Comment ref: 657ac441ae (r135643553)
This commit is contained in:
LGUG2Z
2023-12-23 16:39:53 -08:00
parent e221d96785
commit cf86b2cf98
6 changed files with 70 additions and 57 deletions

7
Cargo.lock generated
View File

@@ -827,6 +827,7 @@ dependencies = [
"tracing-subscriber",
"uds_windows",
"which",
"widestring",
"windows",
"windows-implement",
"windows-interface",
@@ -2331,6 +2332,12 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "widestring"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8"
[[package]]
name = "winapi"
version = "0.2.8"

View File

@@ -45,6 +45,7 @@ windows-implement = { workspace = true }
windows = { workspace = true }
color-eyre = { workspace = true }
dirs = { workspace = true }
widestring = "1"
[features]
deadlock_detection = []

View File

@@ -2,15 +2,15 @@ use std::sync::atomic::Ordering;
use std::time::Duration;
use color_eyre::Result;
use windows::core::PCSTR;
use windows::core::PCWSTR;
use windows::Win32::Foundation::HWND;
use windows::Win32::UI::WindowsAndMessaging::DispatchMessageA;
use windows::Win32::UI::WindowsAndMessaging::FindWindowA;
use windows::Win32::UI::WindowsAndMessaging::GetMessageA;
use windows::Win32::UI::WindowsAndMessaging::DispatchMessageW;
use windows::Win32::UI::WindowsAndMessaging::FindWindowW;
use windows::Win32::UI::WindowsAndMessaging::GetMessageW;
use windows::Win32::UI::WindowsAndMessaging::CS_HREDRAW;
use windows::Win32::UI::WindowsAndMessaging::CS_VREDRAW;
use windows::Win32::UI::WindowsAndMessaging::MSG;
use windows::Win32::UI::WindowsAndMessaging::WNDCLASSA;
use windows::Win32::UI::WindowsAndMessaging::WNDCLASSW;
use komorebi_core::Rect;
@@ -43,11 +43,11 @@ impl Border {
}
pub fn create(name: &str) -> Result<()> {
let name = format!("{name}\0");
let name: Vec<u16> = format!("{name}\0").encode_utf16().collect();
let instance = WindowsApi::module_handle_w()?;
let class_name = PCSTR(name.as_ptr());
let class_name = PCWSTR(name.as_ptr());
let brush = WindowsApi::create_solid_brush(TRANSPARENCY_COLOUR);
let window_class = WNDCLASSA {
let window_class = WNDCLASSW {
hInstance: instance.into(),
lpszClassName: class_name,
style: CS_HREDRAW | CS_VREDRAW,
@@ -56,18 +56,18 @@ impl Border {
..Default::default()
};
let _atom = WindowsApi::register_class_a(&window_class)?;
let _atom = WindowsApi::register_class_w(&window_class)?;
let name_cl = name.clone();
std::thread::spawn(move || -> Result<()> {
let hwnd = WindowsApi::create_border_window(PCSTR(name_cl.as_ptr()), instance)?;
let hwnd = WindowsApi::create_border_window(PCWSTR(name_cl.as_ptr()), instance)?;
let border = Self::from(hwnd);
let mut message = MSG::default();
unsafe {
while GetMessageA(&mut message, border.hwnd(), 0, 0).into() {
DispatchMessageA(&message);
while GetMessageW(&mut message, border.hwnd(), 0, 0).into() {
DispatchMessageW(&message);
std::thread::sleep(Duration::from_millis(10));
}
}
@@ -77,7 +77,7 @@ impl Border {
let mut hwnd = HWND(0);
while hwnd == HWND(0) {
hwnd = unsafe { FindWindowA(PCSTR(name.as_ptr()), PCSTR::null()) };
hwnd = unsafe { FindWindowW(PCWSTR(name.as_ptr()), PCWSTR::null()) };
}
BORDER_HWND.store(hwnd.0, Ordering::SeqCst);

View File

@@ -2,15 +2,15 @@ use std::sync::atomic::Ordering;
use std::time::Duration;
use color_eyre::Result;
use windows::core::PCSTR;
use windows::core::PCWSTR;
use windows::Win32::Foundation::HWND;
use windows::Win32::UI::WindowsAndMessaging::DispatchMessageA;
use windows::Win32::UI::WindowsAndMessaging::FindWindowA;
use windows::Win32::UI::WindowsAndMessaging::GetMessageA;
use windows::Win32::UI::WindowsAndMessaging::DispatchMessageW;
use windows::Win32::UI::WindowsAndMessaging::FindWindowW;
use windows::Win32::UI::WindowsAndMessaging::GetMessageW;
use windows::Win32::UI::WindowsAndMessaging::CS_HREDRAW;
use windows::Win32::UI::WindowsAndMessaging::CS_VREDRAW;
use windows::Win32::UI::WindowsAndMessaging::MSG;
use windows::Win32::UI::WindowsAndMessaging::WNDCLASSA;
use windows::Win32::UI::WindowsAndMessaging::WNDCLASSW;
use crate::windows_callbacks;
use crate::WindowsApi;
@@ -34,11 +34,11 @@ impl Hidden {
}
pub fn create(name: &str) -> Result<()> {
let name = format!("{name}\0");
let name: Vec<u16> = format!("{name}\0").encode_utf16().collect();
let instance = WindowsApi::module_handle_w()?;
let class_name = PCSTR(name.as_ptr());
let class_name = PCWSTR(name.as_ptr());
let brush = WindowsApi::create_solid_brush(TRANSPARENCY_COLOUR);
let window_class = WNDCLASSA {
let window_class = WNDCLASSW {
hInstance: instance.into(),
lpszClassName: class_name,
style: CS_HREDRAW | CS_VREDRAW,
@@ -47,18 +47,18 @@ impl Hidden {
..Default::default()
};
let _atom = WindowsApi::register_class_a(&window_class)?;
let _atom = WindowsApi::register_class_w(&window_class)?;
let name_cl = name.clone();
std::thread::spawn(move || -> Result<()> {
let hwnd = WindowsApi::create_hidden_window(PCSTR(name_cl.as_ptr()), instance)?;
let hwnd = WindowsApi::create_hidden_window(PCWSTR(name_cl.as_ptr()), instance)?;
let hidden = Self::from(hwnd);
let mut message = MSG::default();
unsafe {
while GetMessageA(&mut message, hidden.hwnd(), 0, 0).into() {
DispatchMessageA(&message);
while GetMessageW(&mut message, hidden.hwnd(), 0, 0).into() {
DispatchMessageW(&message);
std::thread::sleep(Duration::from_millis(10));
}
}
@@ -68,7 +68,7 @@ impl Hidden {
let mut hwnd = HWND(0);
while hwnd == HWND(0) {
hwnd = unsafe { FindWindowA(PCSTR(name.as_ptr()), PCSTR::null()) };
hwnd = unsafe { FindWindowW(PCWSTR(name.as_ptr()), PCWSTR::null()) };
}
HIDDEN_HWND.store(hwnd.0, Ordering::SeqCst);

View File

@@ -1,15 +1,14 @@
use std::collections::VecDeque;
use std::convert::TryFrom;
use std::ffi::c_void;
use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;
use std::sync::atomic::Ordering;
use color_eyre::eyre::anyhow;
use color_eyre::eyre::Error;
use color_eyre::Result;
use widestring::U16CStr;
use windows::core::Result as WindowsCrateResult;
use windows::core::PCSTR;
use windows::core::PCWSTR;
use windows::core::PWSTR;
use windows::Win32::Foundation::CloseHandle;
use windows::Win32::Foundation::BOOL;
@@ -30,13 +29,13 @@ use windows::Win32::Graphics::Dwm::DWM_CLOAKED_APP;
use windows::Win32::Graphics::Dwm::DWM_CLOAKED_INHERITED;
use windows::Win32::Graphics::Dwm::DWM_CLOAKED_SHELL;
use windows::Win32::Graphics::Gdi::CreateSolidBrush;
use windows::Win32::Graphics::Gdi::EnumDisplayDevicesA;
use windows::Win32::Graphics::Gdi::EnumDisplayDevicesW;
use windows::Win32::Graphics::Gdi::EnumDisplayMonitors;
use windows::Win32::Graphics::Gdi::GetMonitorInfoW;
use windows::Win32::Graphics::Gdi::InvalidateRect;
use windows::Win32::Graphics::Gdi::MonitorFromPoint;
use windows::Win32::Graphics::Gdi::MonitorFromWindow;
use windows::Win32::Graphics::Gdi::DISPLAY_DEVICEA;
use windows::Win32::Graphics::Gdi::DISPLAY_DEVICEW;
use windows::Win32::Graphics::Gdi::HBRUSH;
use windows::Win32::Graphics::Gdi::HDC;
use windows::Win32::Graphics::Gdi::HMONITOR;
@@ -69,7 +68,7 @@ use windows::Win32::UI::Shell::Common::DEVICE_SCALE_FACTOR;
use windows::Win32::UI::Shell::GetScaleFactorForMonitor;
use windows::Win32::UI::WindowsAndMessaging::AllowSetForegroundWindow;
use windows::Win32::UI::WindowsAndMessaging::BringWindowToTop;
use windows::Win32::UI::WindowsAndMessaging::CreateWindowExA;
use windows::Win32::UI::WindowsAndMessaging::CreateWindowExW;
use windows::Win32::UI::WindowsAndMessaging::EnumWindows;
use windows::Win32::UI::WindowsAndMessaging::GetCursorPos;
use windows::Win32::UI::WindowsAndMessaging::GetDesktopWindow;
@@ -85,7 +84,7 @@ use windows::Win32::UI::WindowsAndMessaging::IsWindow;
use windows::Win32::UI::WindowsAndMessaging::IsWindowVisible;
use windows::Win32::UI::WindowsAndMessaging::PostMessageW;
use windows::Win32::UI::WindowsAndMessaging::RealGetWindowClassW;
use windows::Win32::UI::WindowsAndMessaging::RegisterClassA;
use windows::Win32::UI::WindowsAndMessaging::RegisterClassW;
use windows::Win32::UI::WindowsAndMessaging::SetCursorPos;
use windows::Win32::UI::WindowsAndMessaging::SetForegroundWindow;
use windows::Win32::UI::WindowsAndMessaging::SetLayeredWindowAttributes;
@@ -120,7 +119,7 @@ use windows::Win32::UI::WindowsAndMessaging::SYSTEM_PARAMETERS_INFO_ACTION;
use windows::Win32::UI::WindowsAndMessaging::SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS;
use windows::Win32::UI::WindowsAndMessaging::WINDOW_LONG_PTR_INDEX;
use windows::Win32::UI::WindowsAndMessaging::WM_CLOSE;
use windows::Win32::UI::WindowsAndMessaging::WNDCLASSA;
use windows::Win32::UI::WindowsAndMessaging::WNDCLASSW;
use windows::Win32::UI::WindowsAndMessaging::WNDENUMPROC;
use windows::Win32::UI::WindowsAndMessaging::WS_DISABLED;
use windows::Win32::UI::WindowsAndMessaging::WS_EX_LAYERED;
@@ -242,21 +241,21 @@ impl WindowsApi {
pub fn enum_display_devices(
index: u32,
lp_device: Option<*const u8>,
) -> Result<DISPLAY_DEVICEA> {
lp_device: Option<*const u16>,
) -> Result<DISPLAY_DEVICEW> {
#[allow(clippy::option_if_let_else)]
let lp_device = match lp_device {
None => PCSTR::null(),
Some(lp_device) => PCSTR(lp_device),
None => PCWSTR::null(),
Some(lp_device) => PCWSTR(lp_device),
};
let mut display_device = DISPLAY_DEVICEA {
cb: u32::try_from(std::mem::size_of::<DISPLAY_DEVICEA>())?,
let mut display_device = DISPLAY_DEVICEW {
cb: u32::try_from(std::mem::size_of::<DISPLAY_DEVICEW>())?,
..Default::default()
};
match unsafe {
EnumDisplayDevicesA(
EnumDisplayDevicesW(
lp_device,
index,
std::ptr::addr_of_mut!(display_device),
@@ -690,10 +689,10 @@ impl WindowsApi {
pub fn monitor(hmonitor: isize) -> Result<Monitor> {
let ex_info = Self::monitor_info_w(HMONITOR(hmonitor))?;
let name = OsString::from_wide(&ex_info.szDevice);
let name = name
let name = U16CStr::from_slice_truncate(&ex_info.szDevice)
.expect("monitor name was not a valid u16 c string")
.to_ustring()
.to_string_lossy()
.replace('\u{0000}', "")
.trim_start_matches(r"\\.\")
.to_string();
@@ -799,8 +798,8 @@ impl WindowsApi {
unsafe { CreateSolidBrush(COLORREF(colour)) }
}
pub fn register_class_a(window_class: &WNDCLASSA) -> Result<u16> {
Result::from(WindowsResult::from(unsafe { RegisterClassA(window_class) }))
pub fn register_class_w(window_class: &WNDCLASSW) -> Result<u16> {
Result::from(WindowsResult::from(unsafe { RegisterClassW(window_class) }))
}
pub fn scale_factor_for_monitor(hmonitor: isize) -> Result<DEVICE_SCALE_FACTOR> {
@@ -828,9 +827,9 @@ impl WindowsApi {
.process()
}
pub fn create_border_window(name: PCSTR, instance: HMODULE) -> Result<isize> {
pub fn create_border_window(name: PCWSTR, instance: HMODULE) -> Result<isize> {
unsafe {
let hwnd = CreateWindowExA(
let hwnd = CreateWindowExW(
WS_EX_TOOLWINDOW | WS_EX_LAYERED,
name,
name,
@@ -862,9 +861,9 @@ impl WindowsApi {
Ok(())
}
pub fn create_hidden_window(name: PCSTR, instance: HMODULE) -> Result<isize> {
pub fn create_hidden_window(name: PCWSTR, instance: HMODULE) -> Result<isize> {
unsafe {
CreateWindowExA(
CreateWindowExW(
WS_EX_NOACTIVATE,
name,
name,

View File

@@ -1,5 +1,6 @@
use std::collections::VecDeque;
use std::sync::atomic::Ordering;
use widestring::U16CStr;
use windows::Win32::Foundation::BOOL;
use windows::Win32::Foundation::COLORREF;
@@ -78,19 +79,24 @@ pub extern "system" fn enum_display_monitor(
if let Ok(mut m) = WindowsApi::monitor(hmonitor.0) {
#[allow(clippy::cast_possible_truncation)]
if let Ok(d) = WindowsApi::enum_display_devices(current_index as u32, None) {
let name = String::from_utf8_lossy(&d.DeviceName);
let clean_name = name
.replace('\u{0000}', "")
let name = U16CStr::from_slice_truncate(d.DeviceName.as_ref())
.expect("display device name was not a valid u16 c string")
.to_ustring()
.to_string_lossy()
.trim_start_matches(r"\\.\")
.to_string();
if clean_name.eq(m.name()) {
if name.eq(m.name()) {
if let Ok(device) = WindowsApi::enum_display_devices(0, Some(d.DeviceName.as_ptr()))
{
let id = String::from_utf8_lossy(&device.DeviceID);
let clean_id = id.replace('\u{0000}', "");
let id = U16CStr::from_slice_truncate(device.DeviceID.as_ref())
.expect("display device id was not a valid u16 c string")
.to_ustring()
.to_string_lossy()
.trim_start_matches(r"\\?\")
.to_string();
let mut split: Vec<_> = clean_id.split('#').collect();
let mut split: Vec<_> = id.split('#').collect();
split.remove(0);
split.remove(split.len() - 1);