From 7f69364803b855d7abc6272c4b02b6499099c60e Mon Sep 17 00:00:00 2001 From: David Knaack Date: Sat, 31 Aug 2024 13:27:23 +0200 Subject: [PATCH] feat: replace winapi with windows-sys (#70) * feat: replace winapi with windows-sys * bump windows-sys to v0.59.0 --- Cargo.toml | 16 +- src/lib.rs | 4 - src/platform/windows/device.rs | 48 +++- src/platform/windows/ffi/ioctl/info.rs | 56 ++--- src/platform/windows/ffi/ioctl/mod.rs | 31 --- src/platform/windows/ffi/ioctl/query_info.rs | 46 ---- src/platform/windows/ffi/ioctl/status.rs | 55 ++--- src/platform/windows/ffi/ioctl/wait_status.rs | 40 ---- src/platform/windows/ffi/mod.rs | 226 ++++++++---------- src/platform/windows/ffi/wrappers.rs | 29 +-- src/platform/windows/manager.rs | 2 +- 11 files changed, 221 insertions(+), 332 deletions(-) delete mode 100644 src/platform/windows/ffi/ioctl/query_info.rs delete mode 100644 src/platform/windows/ffi/ioctl/wait_status.rs diff --git a/Cargo.toml b/Cargo.toml index 99093a6..23e9714 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,8 +30,20 @@ libc = "^0.2.158" mach = { version = "^0.4.2", package = "mach2" } core-foundation = "~0.10.0" -[target.'cfg(target_os = "windows")'.dependencies] -winapi = { version = "~0.3.9", features = ["impl-default", "devguid", "winbase", "ioapiset", "ntdef", "setupapi", "handleapi", "errhandlingapi", "winerror"] } +[target.'cfg(target_os = "windows")'.dependencies.windows-sys] +version = "0.59.0" +features = [ + "Win32_Devices", + "Win32_Devices_DeviceAndDriverInstallation", + "Win32_Foundation", + "Win32_Security", + "Win32_Storage", + "Win32_Storage_FileSystem", + "Win32_System", + "Win32_System_IO", + "Win32_System_Memory", + "Win32_System_Power", +] [target.'cfg(any(target_os = "dragonfly", target_os = "freebsd"))'.dependencies] libc = "~0.2.158" diff --git a/src/lib.rs b/src/lib.rs index a5ce171..ccc4fe6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,10 +29,6 @@ #[macro_use] extern crate cfg_if; -#[cfg(target_os = "windows")] -#[macro_use] -extern crate winapi; - #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd"))] #[macro_use] extern crate nix; diff --git a/src/platform/windows/device.rs b/src/platform/windows/device.rs index 4b7a5c8..2672d78 100644 --- a/src/platform/windows/device.rs +++ b/src/platform/windows/device.rs @@ -1,15 +1,16 @@ use std::convert::AsRef; use std::fmt; -use super::ffi::{BatteryQueryInformation, DeviceHandle}; +use windows_sys::Win32::System::Power::BATTERY_QUERY_INFORMATION; + +use super::ffi::DeviceHandle; use crate::platform::traits::BatteryDevice; use crate::units::{ElectricPotential, Energy, Power, ThermodynamicTemperature}; use crate::{Error, Result, State, Technology}; -#[derive(Default)] pub struct PowerDevice { // Used later for information refreshing - tag: BatteryQueryInformation, + tag: BATTERY_QUERY_INFORMATION, technology: Technology, state: State, @@ -25,6 +26,26 @@ pub struct PowerDevice { serial_number: Option, } +impl Default for PowerDevice { + fn default() -> Self { + Self { + technology: Default::default(), + state: Default::default(), + voltage: Default::default(), + energy_rate: Default::default(), + capacity: Default::default(), + design_capacity: Default::default(), + full_charged_capacity: Default::default(), + temperature: None, + cycle_count: None, + device_name: None, + manufacturer: None, + serial_number: None, + tag: unsafe { std::mem::zeroed() }, + } + } +} + impl PowerDevice { pub fn try_from(mut handle: DeviceHandle) -> Result> { let info = handle.information()?; @@ -47,7 +68,7 @@ impl PowerDevice { }; let mut device = PowerDevice { - tag: handle.tag.clone(), + tag: handle.tag, technology: info.technology(), device_name, manufacturer, @@ -92,7 +113,7 @@ impl PowerDevice { Ok(()) } - pub fn tag(&self) -> &BatteryQueryInformation { + pub fn tag(&self) -> &BATTERY_QUERY_INFORMATION { &self.tag } } @@ -148,9 +169,20 @@ impl BatteryDevice for PowerDevice { } impl fmt::Debug for PowerDevice { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("WindowsDevice") - .field("tag", &self.tag.battery_tag()) + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("PowerDevice") + .field("technology", &self.technology) + .field("state", &self.state) + .field("voltage", &self.voltage) + .field("energy_rate", &self.energy_rate) + .field("capacity", &self.capacity) + .field("design_capacity", &self.design_capacity) + .field("full_charged_capacity", &self.full_charged_capacity) + .field("temperature", &self.temperature) + .field("cycle_count", &self.cycle_count) + .field("device_name", &self.device_name) + .field("manufacturer", &self.manufacturer) + .field("serial_number", &self.serial_number) .finish() } } diff --git a/src/platform/windows/ffi/ioctl/info.rs b/src/platform/windows/ffi/ioctl/info.rs index 6fa83d0..5d470ff 100644 --- a/src/platform/windows/ffi/ioctl/info.rs +++ b/src/platform/windows/ffi/ioctl/info.rs @@ -2,48 +2,44 @@ #![allow(non_snake_case, clippy::unreadable_literal)] -use std::default::Default; -use std::mem; -use std::ops; -use std::str::{self, FromStr}; - use crate::Technology; -use winapi::shared::ntdef; - -pub const BATTERY_CAPACITY_RELATIVE: ntdef::ULONG = 0x40000000; -pub const BATTERY_SYSTEM_BATTERY: ntdef::ULONG = 0x80000000; +use std::str::FromStr; +use windows_sys::Win32::System::Power::*; -STRUCT! {#[cfg_attr(target_arch = "x86", repr(packed))] #[derive(Debug)] struct BATTERY_INFORMATION { - Capabilities: ntdef::ULONG, - Technology: ntdef::UCHAR, - Reserved: [ntdef::UCHAR; 3], - Chemistry: [ntdef::UCHAR; 4], - DesignedCapacity: ntdef::ULONG, // mWh - FullChargedCapacity: ntdef::ULONG, // mWh - DefaultAlert1: ntdef::ULONG, - DefaultAlert2: ntdef::ULONG, - CriticalBias: ntdef::ULONG, - CycleCount: ntdef::ULONG, -}} +pub struct BatteryInformation(BATTERY_INFORMATION); -impl Default for BATTERY_INFORMATION { - #[inline] +impl Default for BatteryInformation { fn default() -> Self { - unsafe { mem::zeroed() } + Self(unsafe { std::mem::zeroed() }) } } -#[derive(Debug, Default)] -pub struct BatteryInformation(BATTERY_INFORMATION); +impl std::fmt::Debug for BatteryInformation { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + f.debug_struct("BatteryInformation") + .field("Capabilities", &self.0.Capabilities) + .field("Technology", &self.technology()) + .field("DesignedCapacity", &self.0.DesignedCapacity) + .field("FullChargedCapacity", &self.0.FullChargedCapacity) + .field("CycleCount", &self.0.CycleCount) + .finish() + } +} + +impl From for BatteryInformation { + fn from(info: BATTERY_INFORMATION) -> Self { + Self(info) + } +} -impl ops::Deref for BatteryInformation { +impl std::ops::Deref for BatteryInformation { type Target = BATTERY_INFORMATION; fn deref(&self) -> &Self::Target { &self.0 } } -impl ops::DerefMut for BatteryInformation { +impl std::ops::DerefMut for BatteryInformation { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } @@ -61,8 +57,8 @@ impl BatteryInformation { } pub fn technology(&self) -> Technology { - let raw = unsafe { str::from_utf8_unchecked(&self.0.Chemistry) }; - match Technology::from_str(raw) { + let raw = String::from_utf8_lossy(&self.0.Chemistry); + match Technology::from_str(&raw) { Ok(tech) => tech, Err(_) => Technology::Unknown, } diff --git a/src/platform/windows/ffi/ioctl/mod.rs b/src/platform/windows/ffi/ioctl/mod.rs index 1cc2a3d..b60aac2 100644 --- a/src/platform/windows/ffi/ioctl/mod.rs +++ b/src/platform/windows/ffi/ioctl/mod.rs @@ -3,39 +3,8 @@ // Each sub-module represents a C-level struct to respective IOCTL request // and idiomatic Rust struct around it. -use winapi::shared::minwindef; - mod info; -mod query_info; mod status; -mod wait_status; pub use self::info::BatteryInformation; -pub use self::query_info::BatteryQueryInformation; pub use self::status::BatteryStatus; -pub use self::wait_status::BatteryWaitStatus; - -// Following values are based on the https://www.ioctls.net data -pub const IOCTL_BATTERY_QUERY_TAG: minwindef::DWORD = 0x294040; -pub const IOCTL_BATTERY_QUERY_INFORMATION: minwindef::DWORD = 0x294044; -pub const IOCTL_BATTERY_QUERY_STATUS: minwindef::DWORD = 0x29404c; - -pub mod info_level { - #![allow(non_camel_case_types, non_upper_case_globals)] - - /// For some reasons, "winapi==0.3.6" `ENUM!` macro fails to compile with - /// error: no rules expected the token `@` - /// so defining `BATTERY_QUERY_INFORMATION_LEVEL` "enum" manually. - - pub type BATTERY_QUERY_INFORMATION_LEVEL = u32; - - // pub const BatteryInformation: BATTERY_QUERY_INFORMATION_LEVEL = 0; - // pub const BatteryGranularityInformation: BATTERY_QUERY_INFORMATION_LEVEL = 1; - pub const BatteryTemperature: BATTERY_QUERY_INFORMATION_LEVEL = 2; - // pub const BatteryEstimatedTime: BATTERY_QUERY_INFORMATION_LEVEL = 3; - pub const BatteryDeviceName: BATTERY_QUERY_INFORMATION_LEVEL = 4; - // pub const BatteryManufactureDate: BATTERY_QUERY_INFORMATION_LEVEL = 5; - pub const BatteryManufactureName: BATTERY_QUERY_INFORMATION_LEVEL = 6; - // pub const BatteryUniqueID: BATTERY_QUERY_INFORMATION_LEVEL = 7; - pub const BatterySerialNumber: BATTERY_QUERY_INFORMATION_LEVEL = 8; -} diff --git a/src/platform/windows/ffi/ioctl/query_info.rs b/src/platform/windows/ffi/ioctl/query_info.rs deleted file mode 100644 index f74b7c1..0000000 --- a/src/platform/windows/ffi/ioctl/query_info.rs +++ /dev/null @@ -1,46 +0,0 @@ -//! https://docs.microsoft.com/en-us/windows/desktop/power/battery-query-information-str - -#![allow(non_snake_case)] - -use std::default::Default; -use std::mem; -use std::ops; - -use winapi::shared::ntdef; - -use super::info_level; - -STRUCT! {#[cfg_attr(target_arch = "x86", repr(packed))] #[derive(Debug)] struct BATTERY_QUERY_INFORMATION { - BatteryTag: ntdef::ULONG, - InformationLevel: info_level::BATTERY_QUERY_INFORMATION_LEVEL, - AtRate: ntdef::LONG, -}} - -impl Default for BATTERY_QUERY_INFORMATION { - #[inline] - fn default() -> Self { - unsafe { mem::zeroed() } - } -} - -#[derive(Debug, Clone, Default)] -pub struct BatteryQueryInformation(BATTERY_QUERY_INFORMATION); - -impl BatteryQueryInformation { - pub fn battery_tag(&self) -> ntdef::ULONG { - self.0.BatteryTag - } -} - -impl ops::Deref for BatteryQueryInformation { - type Target = BATTERY_QUERY_INFORMATION; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} -impl ops::DerefMut for BatteryQueryInformation { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} diff --git a/src/platform/windows/ffi/ioctl/status.rs b/src/platform/windows/ffi/ioctl/status.rs index 8cd1b63..2e75a83 100644 --- a/src/platform/windows/ffi/ioctl/status.rs +++ b/src/platform/windows/ffi/ioctl/status.rs @@ -2,47 +2,30 @@ #![allow(non_snake_case, clippy::unreadable_literal)] -use std::default::Default; -use std::mem; use std::ops; -use winapi::shared::ntdef; +use windows_sys::Win32::System::Power::*; use crate::State; -/// Current battery capacity is unknown. -const BATTERY_UNKNOWN_CAPACITY: ntdef::ULONG = 0xFFFFFFFF; -/// Current battery voltage is unknown. -const BATTERY_UNKNOWN_VOLTAGE: ntdef::ULONG = 0xFFFFFFFF; -/// Current battery rage is unknown. -#[allow(overflowing_literals)] -const BATTERY_UNKNOWN_RATE: ntdef::LONG = 0x80000000; - -/// Indicates that the battery is currently charging. -const BATTERY_CHARGING: ntdef::ULONG = 0x00000004; -/// Indicates that battery failure is imminent. See the Remarks section for more information. -const BATTERY_CRITICAL: ntdef::ULONG = 0x00000008; -/// Indicates that the battery is currently discharging. -const BATTERY_DISCHARGING: ntdef::ULONG = 0x00000002; -/// Indicates that the system has access to AC power, so no batteries are being discharged. -const BATTERY_POWER_ON_LINE: ntdef::ULONG = 0x00000001; - -STRUCT! {#[cfg_attr(target_arch = "x86", repr(packed))] #[derive(Debug)] struct BATTERY_STATUS { - PowerState: ntdef::ULONG, - Capacity: ntdef::ULONG, // mWh or BATTERY_UNKNOWN_CAPACITY - Voltage: ntdef::ULONG, // mV or BATTERY_UNKNOWN_VOLTAGE - Rate: ntdef::LONG, // mW, might be negative -}} - -impl Default for BATTERY_STATUS { - #[inline] +pub struct BatteryStatus(BATTERY_STATUS); + +impl Default for BatteryStatus { fn default() -> Self { - unsafe { mem::zeroed() } + Self(unsafe { std::mem::zeroed() }) } } -#[derive(Debug, Default)] -pub struct BatteryStatus(BATTERY_STATUS); +impl std::fmt::Debug for BatteryStatus { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + f.debug_struct("PowerState") + .field("PowerState", &self.0.PowerState) + .field("Capacity", &self.capacity()) + .field("Voltage", &self.voltage()) + .field("Rate", &self.rate()) + .finish() + } +} impl ops::Deref for BatteryStatus { type Target = BATTERY_STATUS; @@ -57,6 +40,12 @@ impl ops::DerefMut for BatteryStatus { } } +impl From for BatteryStatus { + fn from(status: BATTERY_STATUS) -> Self { + Self(status) + } +} + impl BatteryStatus { #[inline] pub fn is_charging(&self) -> bool { @@ -106,7 +95,7 @@ impl BatteryStatus { /// The current rate of battery charge or discharge. pub fn rate(&self) -> Option { - if self.0.Rate == BATTERY_UNKNOWN_RATE { + if self.0.Rate == BATTERY_UNKNOWN_RATE as i32 { None } else { Some(self.0.Rate.abs()) diff --git a/src/platform/windows/ffi/ioctl/wait_status.rs b/src/platform/windows/ffi/ioctl/wait_status.rs deleted file mode 100644 index 975a868..0000000 --- a/src/platform/windows/ffi/ioctl/wait_status.rs +++ /dev/null @@ -1,40 +0,0 @@ -//! https://docs.microsoft.com/en-us/windows/desktop/power/battery-status-str - -#![allow(non_snake_case)] - -use std::default::Default; -use std::mem; -use std::ops; - -use winapi::shared::ntdef; - -STRUCT! {#[cfg_attr(target_arch = "x86", repr(packed))] #[derive(Debug)] struct BATTERY_WAIT_STATUS { - BatteryTag: ntdef::ULONG, - Timeout: ntdef::ULONG, - PowerState: ntdef::ULONG, - LowCapacity: ntdef::ULONG, - HighCapacity: ntdef::ULONG, -}} - -impl Default for BATTERY_WAIT_STATUS { - #[inline] - fn default() -> Self { - unsafe { mem::zeroed() } - } -} - -#[derive(Debug, Default)] -pub struct BatteryWaitStatus(BATTERY_WAIT_STATUS); - -impl ops::Deref for BatteryWaitStatus { - type Target = BATTERY_WAIT_STATUS; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} -impl ops::DerefMut for BatteryWaitStatus { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} diff --git a/src/platform/windows/ffi/mod.rs b/src/platform/windows/ffi/mod.rs index 7c414d9..3e83865 100644 --- a/src/platform/windows/ffi/mod.rs +++ b/src/platform/windows/ffi/mod.rs @@ -1,47 +1,44 @@ use std::default::Default; +use std::ffi; use std::io; use std::iter; use std::mem; -use std::ops::DerefMut; +use std::mem::MaybeUninit; +use std::os::windows::raw::HANDLE; +use std::ptr; -use winapi::ctypes; -use winapi::shared::{basetsd, devguid, minwindef, ntdef, windef, winerror}; -use winapi::um::{ - errhandlingapi, fileapi, handleapi, ioapiset, minwinbase, setupapi, winbase, winnt, -}; +use windows_sys::core::*; +use windows_sys::Win32::Devices::DeviceAndDriverInstallation as setupapi; +use windows_sys::Win32::Foundation; +use windows_sys::Win32::Storage::FileSystem as fileapi; +use windows_sys::Win32::System::Power as systempower; +use windows_sys::Win32::System::IO as ioapiset; mod ioctl; mod wide_string; mod wrappers; -pub(crate) use self::ioctl::BatteryQueryInformation; use self::wide_string::WideString; use self::wrappers::*; -#[inline] -fn get_last_error() -> io::Error { - let error_type = unsafe { errhandlingapi::GetLastError() }; - io::Error::from_raw_os_error(error_type as i32) -} - #[derive(Debug)] pub struct DeviceIterator { device: setupapi::HDEVINFO, - current: minwindef::DWORD, + current: u32, } impl DeviceIterator { pub fn new() -> io::Result { let hdev = unsafe { setupapi::SetupDiGetClassDevsW( - &devguid::GUID_DEVCLASS_BATTERY, - ntdef::NULL as winnt::PCWSTR, - ntdef::NULL as windef::HWND, + &setupapi::GUID_DEVCLASS_BATTERY, + ptr::null() as PCWSTR, + ptr::null_mut(), setupapi::DIGCF_PRESENT | setupapi::DIGCF_DEVICEINTERFACE, ) }; - if hdev == handleapi::INVALID_HANDLE_VALUE { - Err(get_last_error()) + if hdev as HANDLE == Foundation::INVALID_HANDLE_VALUE { + Err(io::Error::last_os_error()) } else { Ok(DeviceIterator { device: hdev, @@ -51,15 +48,13 @@ impl DeviceIterator { } fn get_interface_data(&self) -> io::Result { - let mut data = setupapi::SP_DEVICE_INTERFACE_DATA { - cbSize: mem::size_of::() as u32, - ..Default::default() - }; + let mut data = unsafe { mem::zeroed::() }; + data.cbSize = mem::size_of::() as u32; let result = unsafe { setupapi::SetupDiEnumDeviceInterfaces( self.device, - ntdef::NULL as *mut setupapi::SP_DEVINFO_DATA, - &devguid::GUID_DEVCLASS_BATTERY, + ptr::null_mut() as *mut setupapi::SP_DEVINFO_DATA, + &setupapi::GUID_DEVCLASS_BATTERY, self.current, &mut data, ) @@ -67,7 +62,7 @@ impl DeviceIterator { // TODO: Add trace if result == 0 { - Err(get_last_error()) + Err(io::Error::last_os_error()) } else { Ok(data) } @@ -77,25 +72,27 @@ impl DeviceIterator { &self, data: &mut setupapi::SP_DEVICE_INTERFACE_DATA, ) -> io::Result { - let mut buf_size: minwindef::DWORD = 0; + let mut buf_size = 0; unsafe { setupapi::SetupDiGetDeviceInterfaceDetailW( self.device, data, - ntdef::NULL as setupapi::PSP_DEVICE_INTERFACE_DETAIL_DATA_W, + ptr::null_mut() as *mut setupapi::SP_DEVICE_INTERFACE_DETAIL_DATA_W, 0, &mut buf_size, - 0 as setupapi::PSP_DEVINFO_DATA, + ptr::null_mut() as *mut setupapi::SP_DEVINFO_DATA, ) }; - let result = unsafe { errhandlingapi::GetLastError() }; - if result != winerror::ERROR_INSUFFICIENT_BUFFER { + let result = unsafe { Foundation::GetLastError() }; + if result != Foundation::ERROR_INSUFFICIENT_BUFFER { return Err(io::Error::from_raw_os_error(result as i32)); } let pdidd = unsafe { - winbase::LocalAlloc(minwinbase::LPTR, buf_size as basetsd::SIZE_T) - as setupapi::PSP_DEVICE_INTERFACE_DETAIL_DATA_W + windows_sys::Win32::System::Memory::LocalAlloc( + windows_sys::Win32::System::Memory::LPTR, + buf_size as _, + ) as *mut setupapi::SP_DEVICE_INTERFACE_DETAIL_DATA_W }; unsafe { (*pdidd).cbSize = mem::size_of::() as u32; @@ -104,13 +101,13 @@ impl DeviceIterator { setupapi::SetupDiGetDeviceInterfaceDetailW( self.device, data, - pdidd, + pdidd as *mut setupapi::SP_DEVICE_INTERFACE_DETAIL_DATA_W, buf_size, &mut buf_size, - 0 as setupapi::PSP_DEVINFO_DATA, + ptr::null_mut() as *mut setupapi::SP_DEVINFO_DATA, ) }; - let result = unsafe { errhandlingapi::GetLastError() }; + let result = unsafe { Foundation::GetLastError() }; if result != 0 { return Err(io::Error::from_raw_os_error(result as i32)); } @@ -127,43 +124,43 @@ impl DeviceIterator { let file = unsafe { fileapi::CreateFileW( device_path, - winnt::GENERIC_READ | winnt::GENERIC_WRITE, - winnt::FILE_SHARE_READ | winnt::FILE_SHARE_WRITE, - ntdef::NULL as minwinbase::LPSECURITY_ATTRIBUTES, + Foundation::GENERIC_READ | Foundation::GENERIC_WRITE, + fileapi::FILE_SHARE_READ | fileapi::FILE_SHARE_WRITE, + ptr::null(), fileapi::OPEN_EXISTING, - winnt::FILE_ATTRIBUTE_NORMAL, - ntdef::NULL, + fileapi::FILE_ATTRIBUTE_NORMAL, + ptr::null_mut(), ) }; - if file == handleapi::INVALID_HANDLE_VALUE { - Err(get_last_error()) + if file == Foundation::INVALID_HANDLE_VALUE { + Err(io::Error::last_os_error()) } else { Ok(file.into()) } } - fn get_tag(&self, handle: &mut Handle) -> io::Result { - let mut query = ioctl::BatteryQueryInformation::default(); - let mut wait_timeout: minwindef::DWORD = 0; - let mut bytes_returned: minwindef::DWORD = 0; + fn get_tag(&self, handle: &mut Handle) -> io::Result { + let mut query = unsafe { mem::zeroed::() }; + let mut wait_timeout: u32 = 0; + let mut bytes_returned: u32 = 0; let mut battery_tag = { query.BatteryTag }; let res = unsafe { ioapiset::DeviceIoControl( - **handle as *mut _ as *mut ctypes::c_void, - ioctl::IOCTL_BATTERY_QUERY_TAG, - &mut wait_timeout as *mut _ as minwindef::LPVOID, - mem::size_of::() as minwindef::DWORD, - &mut battery_tag as *mut _ as minwindef::LPVOID, - mem::size_of::() as minwindef::DWORD, + handle.0, + systempower::IOCTL_BATTERY_QUERY_TAG, + &mut wait_timeout as *mut _ as *mut ffi::c_void, + mem::size_of_val(&wait_timeout) as _, + &mut battery_tag as *mut _ as *mut ffi::c_void, + mem::size_of_val(&bytes_returned) as _, &mut bytes_returned as *mut _, - ntdef::NULL as minwinbase::LPOVERLAPPED, + ptr::null_mut(), ) }; query.BatteryTag = battery_tag; if res == 0 || query.BatteryTag == 0 { - return Err(get_last_error()); + return Err(io::Error::last_os_error()); } Ok(query) @@ -181,15 +178,8 @@ impl iter::Iterator for DeviceIterator { type Item = DeviceHandle; fn next(&mut self) -> Option { - let mut handle = match self.prepare_handle() { - Ok(h) => h, - Err(_) => return None, - }; - - let tag = match self.get_tag(&mut handle) { - Ok(tag) => tag, - Err(_) => return None, - }; + let mut handle = self.prepare_handle().ok()?; + let tag = self.get_tag(&mut handle).ok()?; self.current += 1; @@ -209,146 +199,136 @@ impl Drop for DeviceIterator { } // Our inner representation of the battery device. -#[derive(Debug)] pub struct DeviceHandle { // interface_details: InterfaceDetailData, pub handle: Handle, // TODO: Carry only `.BatteryTag` field ? - pub tag: ioctl::BatteryQueryInformation, + pub tag: systempower::BATTERY_QUERY_INFORMATION, } impl DeviceHandle { pub fn information(&mut self) -> io::Result { - let mut query = ioctl::BatteryQueryInformation::default(); + let mut query = unsafe { mem::zeroed::() }; query.BatteryTag = self.tag.BatteryTag; - let mut out = ioctl::BatteryInformation::default(); - let mut bytes_returned: minwindef::DWORD = 0; + let mut out = MaybeUninit::::uninit(); + let mut bytes_returned = 0u32; let res = unsafe { ioapiset::DeviceIoControl( - *self.handle, - ioctl::IOCTL_BATTERY_QUERY_INFORMATION, - query.deref_mut() as *mut _ as minwindef::LPVOID, - // Since wrapper is a newtype struct, `mem::size_of` will be the same as with - // underline structure. Yet, this might lead to bug if wrapper structure will change. - // TODO: Get memory size of the underline struct directly - mem::size_of::() as minwindef::DWORD, - &mut out as *mut _ as minwindef::LPVOID, - mem::size_of::() as minwindef::DWORD, + self.handle.0, + systempower::IOCTL_BATTERY_QUERY_INFORMATION, + &mut query as *mut _ as *mut ffi::c_void, + mem::size_of::() as _, + &mut out as *mut _ as *mut ffi::c_void, + mem::size_of::() as _, &mut bytes_returned as *mut _, - ntdef::NULL as minwinbase::LPOVERLAPPED, + ptr::null_mut(), ) }; if res == 0 { - Err(get_last_error()) + Err(io::Error::last_os_error()) } else { - Ok(out) + Ok(unsafe { out.assume_init() }.into()) } } pub fn status(&mut self) -> io::Result { - let mut query = ioctl::BatteryWaitStatus::default(); + let mut query = unsafe { mem::zeroed::() }; query.BatteryTag = self.tag.BatteryTag; - let mut out = ioctl::BatteryStatus::default(); - let mut bytes_returned: minwindef::DWORD = 0; + let mut out = MaybeUninit::::uninit(); + let mut bytes_returned = 0u32; let res = unsafe { ioapiset::DeviceIoControl( *self.handle, - ioctl::IOCTL_BATTERY_QUERY_STATUS, - query.deref_mut() as *mut _ as minwindef::LPVOID, - // Since wrapper is a newtype struct, `mem::size_of` will be the same as with - // underline structure. Yet, this might lead to bug if wrapper structure will change. - // TODO: Get memory size of the underline struct directly - mem::size_of::() as minwindef::DWORD, - &mut out as *mut _ as minwindef::LPVOID, - mem::size_of::() as minwindef::DWORD, + systempower::IOCTL_BATTERY_QUERY_STATUS, + &mut query as *mut _ as *mut ffi::c_void, + mem::size_of::() as _, + &mut out as *mut _ as *mut ffi::c_void, + mem::size_of::() as _, &mut bytes_returned as *mut _, - ntdef::NULL as minwinbase::LPOVERLAPPED, + ptr::null_mut(), ) }; if res == 0 { - Err(get_last_error()) + Err(io::Error::last_os_error()) } else { - Ok(out) + Ok(unsafe { out.assume_init() }.into()) } } // 10ths of a degree Kelvin (or decikelvin) - pub fn temperature(&mut self) -> io::Result { - let mut query = ioctl::BatteryQueryInformation::default(); + pub fn temperature(&mut self) -> io::Result { + let mut query = unsafe { mem::zeroed::() }; query.BatteryTag = self.tag.BatteryTag; - query.InformationLevel = ioctl::info_level::BatteryTemperature; - let mut out: ntdef::ULONG = 0; - let mut bytes_returned: minwindef::DWORD = 0; + query.InformationLevel = systempower::BatteryTemperature; + let mut out: u64 = 0; + let mut bytes_returned: u32 = 0; let res = unsafe { ioapiset::DeviceIoControl( *self.handle, - ioctl::IOCTL_BATTERY_QUERY_INFORMATION, - query.deref_mut() as *mut _ as minwindef::LPVOID, + systempower::IOCTL_BATTERY_QUERY_INFORMATION, + &mut query as *mut _ as *mut ffi::c_void, // Since wrapper is a newtype struct, `mem::size_of` will be the same as with // underline structure. Yet, this might lead to bug if wrapper structure will change. // TODO: Get memory size of the underline struct directly - mem::size_of::() as minwindef::DWORD, - &mut out as *mut _ as minwindef::LPVOID, - mem::size_of::() as minwindef::DWORD, + mem::size_of::() as _, + &mut out as *mut _ as *mut ffi::c_void, + mem::size_of_val(&out) as _, &mut bytes_returned as *mut _, - ntdef::NULL as minwinbase::LPOVERLAPPED, + ptr::null_mut(), ) }; if res == 0 { - Err(get_last_error()) + Err(io::Error::last_os_error()) } else { Ok(out) } } pub fn device_name(&mut self) -> io::Result { - self.query_string(ioctl::info_level::BatteryDeviceName) + self.query_string(systempower::BatteryDeviceName) } pub fn manufacture_name(&mut self) -> io::Result { - self.query_string(ioctl::info_level::BatteryManufactureName) + self.query_string(systempower::BatteryManufactureName) } pub fn serial_number(&mut self) -> io::Result { - self.query_string(ioctl::info_level::BatterySerialNumber) + self.query_string(systempower::BatterySerialNumber) } fn query_string( &mut self, - level: ioctl::info_level::BATTERY_QUERY_INFORMATION_LEVEL, + level: systempower::BATTERY_QUERY_INFORMATION_LEVEL, ) -> io::Result { - let mut query = ioctl::BatteryQueryInformation::default(); + let mut query = unsafe { mem::zeroed::() }; query.BatteryTag = self.tag.BatteryTag; query.InformationLevel = level; let mut out = WideString::default(); - let mut bytes_returned: minwindef::DWORD = 0; + let mut bytes_returned = 0u32; let res = unsafe { ioapiset::DeviceIoControl( *self.handle, - ioctl::IOCTL_BATTERY_QUERY_INFORMATION, - query.deref_mut() as *mut _ as minwindef::LPVOID, - // Since wrapper is a newtype struct, `mem::size_of` will be the same as with - // underline structure. Yet, this might lead to bug if wrapper structure will change. - // TODO: Get memory size of the underline struct directly - mem::size_of::() as minwindef::DWORD, - out.as_mut_ptr() as *mut _ as minwindef::LPVOID, - (out.len() * 2) as minwindef::DWORD, + systempower::IOCTL_BATTERY_QUERY_INFORMATION, + &mut query as *mut _ as *mut ffi::c_void, + mem::size_of::() as _, + out.as_mut_ptr() as *mut _ as *mut ffi::c_void, + (out.len() * 2) as _, &mut bytes_returned as *mut _, - ntdef::NULL as minwinbase::LPOVERLAPPED, + ptr::null_mut(), ) }; out.truncate(bytes_returned as usize); if res == 0 { - Err(get_last_error()) + Err(io::Error::last_os_error()) } else { Ok(out.into()) } diff --git a/src/platform/windows/ffi/wrappers.rs b/src/platform/windows/ffi/wrappers.rs index 12e60c9..f1c8ee8 100644 --- a/src/platform/windows/ffi/wrappers.rs +++ b/src/platform/windows/ffi/wrappers.rs @@ -1,23 +1,24 @@ // Wrappers around the FFI things that should be freed later. // It is better to Drop than free them manually. +use std::ffi::c_void; use std::ops; +use std::ptr::null_mut; -use winapi::ctypes::c_void; -use winapi::shared::ntdef; -use winapi::um::{handleapi, setupapi, winbase}; +use windows_sys::Win32::Devices::DeviceAndDriverInstallation as setupapi; +use windows_sys::Win32::Foundation; #[derive(Debug)] -pub struct InterfaceDetailData(setupapi::PSP_DEVICE_INTERFACE_DETAIL_DATA_W); +pub struct InterfaceDetailData(*mut setupapi::SP_DEVICE_INTERFACE_DETAIL_DATA_W); -impl From for InterfaceDetailData { - fn from(p: setupapi::PSP_DEVICE_INTERFACE_DETAIL_DATA_W) -> Self { +impl From<*mut setupapi::SP_DEVICE_INTERFACE_DETAIL_DATA_W> for InterfaceDetailData { + fn from(p: *mut setupapi::SP_DEVICE_INTERFACE_DETAIL_DATA_W) -> Self { Self(p) } } impl ops::Deref for InterfaceDetailData { - type Target = setupapi::PSP_DEVICE_INTERFACE_DETAIL_DATA_W; + type Target = *mut setupapi::SP_DEVICE_INTERFACE_DETAIL_DATA_W; fn deref(&self) -> &Self::Target { &self.0 @@ -26,26 +27,26 @@ impl ops::Deref for InterfaceDetailData { impl Drop for InterfaceDetailData { fn drop(&mut self) { - let res = unsafe { winbase::LocalFree(self.0 as *mut c_void) }; + let res = unsafe { Foundation::LocalFree(self.0 as *mut c_void) }; debug_assert_eq!( res, - ntdef::NULL, + null_mut(), "Unable to free device interface detail data" ); } } #[derive(Debug)] -pub struct Handle(ntdef::HANDLE); +pub struct Handle(pub(crate) Foundation::HANDLE); -impl From for Handle { - fn from(handle: ntdef::HANDLE) -> Self { +impl From for Handle { + fn from(handle: Foundation::HANDLE) -> Self { Self(handle) } } impl ops::Deref for Handle { - type Target = ntdef::HANDLE; + type Target = Foundation::HANDLE; fn deref(&self) -> &Self::Target { &self.0 @@ -60,7 +61,7 @@ impl ops::DerefMut for Handle { impl Drop for Handle { fn drop(&mut self) { - let res = unsafe { handleapi::CloseHandle(self.0) }; + let res = unsafe { Foundation::CloseHandle(self.0) }; debug_assert_ne!(res, 0, "Unable to close device handle"); } } diff --git a/src/platform/windows/manager.rs b/src/platform/windows/manager.rs index ca8d911..03a6e01 100644 --- a/src/platform/windows/manager.rs +++ b/src/platform/windows/manager.rs @@ -15,7 +15,7 @@ impl BatteryManager for PowerManager { } fn refresh(&self, device: &mut PowerDevice) -> Result<()> { - let battery_tag = device.tag().clone(); + let battery_tag = *device.tag(); let di = ffi::DeviceIterator::new()?; let handle = di.prepare_handle()?; let device_handle = ffi::DeviceHandle {