diff --git a/Cargo.toml b/Cargo.toml index 9ab079e..b9e6e3e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,6 +35,29 @@ features = [ "minwindef", "ntdef", "setupapi", "winbase", "winerror", "winnt", ] +[target."cfg(windows)".dependencies.windows-sys] +version = "0.52.0" +features = [ + "Win32_Storage", + "Win32_Storage_FileSystem", + "Win32_Security", + "Win32_Devices", + "Win32_Devices_Communication", + "Win32_Devices_DeviceAndDriverInstallation", + "Win32_Devices_Properties", + "Win32_Foundation", + "Win32_Media", + "Win32_Media_KernelStreaming", + "Win32_System_Diagnostics", + "Win32_System_Diagnostics_Debug", + "Win32_System_IO", + "Win32_System_Registry", + "Win32_System_SystemServices", + "Win32_System_Threading", + "Win32_System_WindowsProgramming", + "Win32_Globalization", +] + [dependencies] cfg-if = "1.0.0" scopeguard = "1.1" diff --git a/src/windows/com.rs b/src/windows/com.rs index fa1abbc..bc62b7c 100644 --- a/src/windows/com.rs +++ b/src/windows/com.rs @@ -3,15 +3,26 @@ use std::os::windows::prelude::*; use std::time::Duration; use std::{io, ptr}; -use winapi::shared::minwindef::*; -use winapi::um::commapi::*; -use winapi::um::fileapi::*; -use winapi::um::handleapi::*; -use winapi::um::processthreadsapi::GetCurrentProcess; -use winapi::um::winbase::*; -use winapi::um::winnt::{ - DUPLICATE_SAME_ACCESS, FILE_ATTRIBUTE_NORMAL, GENERIC_READ, GENERIC_WRITE, HANDLE, MAXDWORD, -}; +// use winapi::shared::minwindef::*; +// use winapi::um::commapi::*; +// use winapi::um::fileapi::*; +// use winapi::um::handleapi::*; +// use winapi::um::processthreadsapi::GetCurrentProcess; +// use winapi::um::winbase::*; +// use winapi::um::winnt::{ +// DUPLICATE_SAME_ACCESS, FILE_ATTRIBUTE_NORMAL, GENERIC_READ, GENERIC_WRITE, HANDLE, MAXDWORD, +// }; + +use windows_sys::Win32::Storage::FileSystem::*; +use windows_sys::Win32::System::Threading::GetCurrentProcess; +use windows_sys::Win32::System::SystemServices::MAXDWORD; +use windows_sys::Win32::Foundation::{DUPLICATE_SAME_ACCESS, TRUE, GENERIC_READ, GENERIC_WRITE, HANDLE, + INVALID_HANDLE_VALUE, DuplicateHandle, CloseHandle}; +use windows_sys::Win32::Devices::Communication::{ClearCommError, COMMTIMEOUTS, + SETRTS, CLRRTS, SETDTR, CLRDTR, + PURGE_RXABORT, PURGE_RXCLEAR, PURGE_TXABORT, PURGE_TXCLEAR, + MS_RLSD_ON, MS_CTS_ON, MS_DSR_ON ,MS_RING_ON, EscapeCommFunction, SetCommTimeouts, + GetCommModemStatus, PurgeComm, SetCommBreak, ClearCommBreak}; use crate::windows::dcb; use crate::{ @@ -19,6 +30,11 @@ use crate::{ SerialPortBuilder, StopBits, }; +use super::dcb::MyTrait; +//https://github.com/microsoft/windows-rs/issues/881 +type DWORD = u32; +type LPVOID = *mut u8; + /// A serial port implementation for Windows COM ports /// /// The port will be closed when the value is dropped. However, this struct diff --git a/src/windows/dcb.rs b/src/windows/dcb.rs index d0207fd..ab366a7 100644 --- a/src/windows/dcb.rs +++ b/src/windows/dcb.rs @@ -1,8 +1,15 @@ use std::mem::MaybeUninit; -use winapi::shared::minwindef::*; -use winapi::um::commapi::*; -use winapi::um::winbase::*; -use winapi::um::winnt::HANDLE; +// use winapi::shared::minwindef::*; +// use winapi::um::commapi::*; +// use winapi::um::winbase::*; +// use winapi::um::winnt::HANDLE; + +use windows_sys::Win32::Devices::Communication::*; +use windows_sys::Win32::Foundation::HANDLE; +use windows_sys::Win32::Foundation::{TRUE, FALSE}; +use windows_sys::Win32::System::WindowsProgramming::DTR_CONTROL_DISABLE; +//https://github.com/microsoft/windows-rs/issues/881 +type DWORD = u32; use crate::{DataBits, FlowControl, Parity, Result, StopBits}; @@ -31,7 +38,10 @@ pub(crate) fn init(dcb: &mut DCB) { // dcb.StopBits dcb.XonChar = 17; dcb.XoffChar = 19; - dcb.ErrorChar = '\0' as winapi::ctypes::c_char; + //dcb.ErrorChar = '\0' as winapi::ctypes::c_char; + //https://github.com/microsoft/windows-rs/issues/2188 + // dcb.ErrorChar = '\0' as i8; + dcb.ErrorChar = '\0' as u8; dcb.EofChar = 26; // dcb.EvtChar // always true for communications resources @@ -55,6 +65,141 @@ pub(crate) fn init(dcb: &mut DCB) { dcb.set_fAbortOnError(FALSE as DWORD); } +//https://github.com/rust-lang/rfcs/issues/314 +//currently windows-sys does not implement bit fields +// pub struct MyDCB(DCB); +pub trait MyTrait { + fn set_fBinary(&mut self, fBinary: DWORD) -> (); + fn set_fParity(&mut self, fParity: DWORD) -> (); + fn set_fOutxCtsFlow(&mut self, fOutxCtsFlow: DWORD) -> (); + fn set_fOutxDsrFlow(&mut self, fOutxDsrFlow: DWORD) -> (); + fn set_fDtrControl(&mut self, fDtrControl: DWORD) -> (); + fn set_fDsrSensitivity(&mut self, fDsrSensitivity: DWORD) -> (); + fn set_fTXContinueOnXoff(&mut self, fTXContinueOnXoff: DWORD) -> (); + fn set_fOutX(&mut self, fOutX: DWORD) -> (); + fn set_fInX(&mut self, fInX: DWORD) -> (); + fn set_fErrorChar(&mut self, fErrorChar: DWORD) -> (); + fn set_fNull(&mut self, fNull: DWORD) -> (); + fn set_fRtsControl(&mut self, fRtsControl: DWORD) -> (); + fn set_fAbortOnError(&mut self, fAbortOnError: DWORD) -> (); + + fn fBinary(&self) -> DWORD; + fn fParity(&self) -> DWORD; + fn fOutxCtsFlow(&self) -> DWORD; + fn fOutxDsrFlow(&self) -> DWORD; + fn fDtrControl(&self) -> DWORD; + fn fDsrSensitivity(&self) -> DWORD; + fn fTXContinueOnXoff(&self) -> DWORD; + fn fOutX(&self) -> DWORD; + fn fInX(&self) -> DWORD; + fn fErrorChar(&self) -> DWORD; + fn fNull(&self) -> DWORD; + fn fRtsControl(&self) -> DWORD; + fn fAbortOnError(&self) -> DWORD; + +} + +impl MyTrait for DCB { + fn set_fBinary(&mut self, f_binary: DWORD) -> () { + self._bitfield = (self._bitfield & !0b0000_0000_0000_0001) | (f_binary & 0x1); + } + fn set_fParity(&mut self, f_parity: DWORD) -> () { + self._bitfield = (self._bitfield & !0b0000_0000_0000_0010) | ((f_parity & 0x1) << 1); + } + fn set_fOutxCtsFlow(&mut self, f_outx_cts_flow: DWORD) -> () { + self._bitfield = (self._bitfield & !0b0000_0000_0000_0100) | ((f_outx_cts_flow & 0x1) << 2); + } + fn set_fOutxDsrFlow(&mut self, f_outx_dsr_flow: DWORD) -> () { + self._bitfield = (self._bitfield & !0b0000_0000_0000_1000) | ((f_outx_dsr_flow & 0x1) << 3); + } + fn set_fDtrControl(&mut self, f_dtr_control: DWORD) -> () { + self._bitfield = (self._bitfield & !0b0000_0000_0001_0000) | ((f_dtr_control & 0x1) << 4); + self._bitfield = (self._bitfield & !0b0000_0000_0010_0000) | ((f_dtr_control & 0x2) << 4); + } + fn set_fDsrSensitivity(&mut self, f_dsr_sensitivity: DWORD) -> () { + self._bitfield = (self._bitfield & !0b0000_0000_0100_0000) | ((f_dsr_sensitivity & 0x1) << 6); + } + fn set_fTXContinueOnXoff(&mut self, f_tx_continue_on_x_off: DWORD) -> () { + self._bitfield = (self._bitfield & !0b0000_0000_1000_0000) | ((f_tx_continue_on_x_off & 0x1) << 7); + } + fn set_fOutX(&mut self, f_out_x: DWORD) -> () { + self._bitfield = (self._bitfield & !0b0000_0001_0000_0000) | ((f_out_x & 0x1) << 8); + } + fn set_fInX(&mut self, f_in_x: DWORD) -> () { + self._bitfield = (self._bitfield & !0b0000_0010_0000_0000) | ((f_in_x & 0x1) << 9); + } + fn set_fErrorChar(&mut self, f_error_char: DWORD) -> () { + self._bitfield = (self._bitfield & !0b0000_0100_0000_0000) | ((f_error_char & 0x1) << 10); + } + fn set_fNull(&mut self, f_null: DWORD) -> () { + self._bitfield = (self._bitfield & !0b0000_1000_0000_0000) | ((f_null & 0x1) << 11); + } + fn set_fRtsControl(&mut self, f_rts_control: DWORD) -> () { + self._bitfield = (self._bitfield & !0b0001_0000_0000_0000) | ((f_rts_control & 0x1) << 12); + self._bitfield = (self._bitfield & !0b0010_0000_0000_0000) | ((f_rts_control & 0x2) << 12); + } + fn set_fAbortOnError(&mut self, f_abort_on_error: DWORD) -> () { + self._bitfield = (self._bitfield & !0b0100_0000_0000_0000) | ((f_abort_on_error & 0x1) << 14); + } + + fn fBinary(&self) -> DWORD { + let bit: u32 = self._bitfield & (1 << 0); + bit + } + fn fParity(&self) -> DWORD { + let bit: u32 = self._bitfield & (1 << 1); + bit >> 1 + } + fn fOutxCtsFlow(&self) -> DWORD { + let bit: u32 = self._bitfield & (1 << 2); + bit >> 2 + } + fn fOutxDsrFlow(&self) -> DWORD { + let bit: u32 = self._bitfield & (1 << 3); + bit >> 3 + } + fn fDtrControl(&self) -> DWORD { + let bit1: u32 = self._bitfield & (1 << 4); + let bit2: u32 = self._bitfield & (1 << 5); + let bit:u32 = bit1 | bit2; + bit >> 4 + } + fn fDsrSensitivity(&self) -> DWORD { + let bit: u32 = self._bitfield & (1 << 6); + bit >> 6 + } + fn fTXContinueOnXoff(&self) -> DWORD { + let bit: u32 = self._bitfield & (1 << 7); + bit >> 7 + } + fn fOutX(&self) -> DWORD { + let bit: u32 = self._bitfield & (1 << 8); + bit >> 8 + } + fn fInX(&self) -> DWORD { + let bit: u32 = self._bitfield & (1 << 9); + bit >> 9 + } + fn fErrorChar(&self) -> DWORD { + let bit: u32 = self._bitfield & (1 << 10); + bit >> 10 + } + fn fNull(&self) -> DWORD { + let bit: u32 = self._bitfield & (1 << 11); + bit >> 11 + } + fn fRtsControl(&self) -> DWORD { + let bit1: u32 = self._bitfield & (1 << 12); + let bit2: u32 = self._bitfield & (1 << 13); + let bit:u32 = bit1 | bit2; + bit >> 12 + } + fn fAbortOnError(&self) -> DWORD { + let bit: u32 = self._bitfield & (1 << 14); + bit >> 14 + } +} + pub(crate) fn set_dcb(handle: HANDLE, mut dcb: DCB) -> Result<()> { if unsafe { SetCommState(handle, &mut dcb as *mut _) != 0 } { Ok(()) diff --git a/src/windows/enumerate.rs b/src/windows/enumerate.rs index c303e24..25e8b49 100644 --- a/src/windows/enumerate.rs +++ b/src/windows/enumerate.rs @@ -1,18 +1,43 @@ use std::collections::HashSet; +// use std::ffi::NulError; use std::{mem, ptr}; -use winapi::ctypes::c_void; -use winapi::shared::guiddef::*; -use winapi::shared::minwindef::*; -use winapi::shared::winerror::*; -use winapi::um::cfgmgr32::*; -use winapi::um::cguid::GUID_NULL; -use winapi::um::setupapi::*; -use winapi::um::winnt::{KEY_READ, REG_SZ}; -use winapi::um::winreg::*; +// use winapi::ctypes::c_void; +// use winapi::shared::guiddef::*; +// use winapi::shared::minwindef::*; +// use winapi::shared::winerror::*; +// use winapi::um::cfgmgr32::*; +// use winapi::um::cguid::GUID_NULL; +// use winapi::um::setupapi::*; +// use winapi::um::winnt::{KEY_READ, REG_SZ}; +// use winapi::um::winreg::*; + +// use std::os::raw::c_void; +use windows_sys::core::GUID; +use windows_sys::Win32::Media::KernelStreaming::GUID_NULL; +use windows_sys::Win32::Devices::DeviceAndDriverInstallation::*; +use windows_sys::Win32::Foundation::{FALSE, MAX_PATH, INVALID_HANDLE_VALUE, FILETIME}; +use windows_sys::Win32::System::Registry::*; +//https://github.com/microsoft/windows-rs/issues/881 +type DWORD = u32; + +type ULONG = u32; +//in windows-sys the RegQueryValueExW -> u32 +type HRESULT = u32; +//https://docs.rs/winapi/latest/winapi/shared/minwindef/type.PBYTE.html +type PBYTE = *mut u8; use crate::{Error, ErrorKind, Result, SerialPortInfo, SerialPortType, UsbPortInfo}; +//https://docs.rs/winapi/latest/winapi/shared/winerror/fn.FAILED.html +pub fn FAILED(hr: HRESULT) -> bool { + hr < 0 +} +//https://docs.rs/winapi/latest/winapi/shared/winerror/fn.SUCCEEDED.html +pub fn SUCCEEDED(hr: HRESULT) -> bool { + hr >= 0 +} + /// takes normal Rust `str` and outputs a null terminated UTF-16 encoded string fn as_utf16(utf8: &str) -> Vec { utf8.encode_utf16().chain(Some(0)).collect() @@ -194,8 +219,17 @@ impl PortDevices { // Creates PortDevices object which represents the set of devices associated with a particular // Ports class (given by `guid`). pub fn new(guid: &GUID) -> Self { + + //https://github.com/microsoft/windows-rs/issues/3093 + //in windows-sys 0.52.0 + let null:isize = 0; + PortDevices { - hdi: unsafe { SetupDiGetClassDevsW(guid, ptr::null(), ptr::null_mut(), DIGCF_PRESENT) }, + //in windows-sys 0.59.0 + // hdi: unsafe { SetupDiGetClassDevsW(guid, ptr::null(), ptr::null_mut(), DIGCF_PRESENT) }, + + //in windows-sys 0.52.0 + hdi: unsafe { SetupDiGetClassDevsW(guid, ptr::null(), null, DIGCF_PRESENT) }, dev_idx: 0, } } @@ -248,7 +282,7 @@ impl PortDevice { /// Retrieves the device instance id string associated with this device's parent. /// This is useful for determining the serial number of a composite USB device. fn parent_instance_id(&mut self) -> Option { - let mut result_buf = [0u16; MAX_PATH]; + let mut result_buf = [0u16; MAX_PATH as usize]; let mut parent_device_instance_id = 0; let res = @@ -284,7 +318,7 @@ impl PortDevice { /// /// Reference: https://learn.microsoft.com/en-us/windows-hardware/drivers/install/device-instance-ids fn instance_id(&mut self) -> Option { - let mut result_buf = [0u16; MAX_DEVICE_ID_LEN]; + let mut result_buf = [0u16; MAX_DEVICE_ID_LEN as usize]; let working_buffer_len = result_buf.len() - 1; // always null terminated let mut desired_result_len = 0; // possibly larger than the buffer let res = unsafe { @@ -339,13 +373,17 @@ impl PortDevice { ) }; - if hkey as *mut c_void == winapi::um::handleapi::INVALID_HANDLE_VALUE { + //in windows-sys 0.59.0 + // if hkey as *mut c_void == INVALID_HANDLE_VALUE { + + //in windows-sys 0.52.0 + if hkey as isize == INVALID_HANDLE_VALUE { // failed to open registry key. Return empty string as the failure case return String::new(); } // https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regqueryvalueexw - let mut port_name_buffer = [0u16; MAX_PATH]; + let mut port_name_buffer = [0u16; MAX_PATH as usize]; let buffer_byte_len = 2 * port_name_buffer.len() as DWORD; let mut byte_len = buffer_byte_len; let mut value_type = 0; @@ -395,7 +433,7 @@ impl PortDevice { // doesn't exist. fn property(&mut self, property_id: DWORD) -> Option { let mut value_type = 0; - let mut property_buf = [0u16; MAX_PATH]; + let mut property_buf = [0u16; MAX_PATH as usize]; let res = unsafe { SetupDiGetDeviceRegistryPropertyW( @@ -433,13 +471,19 @@ fn get_registry_com_ports() -> HashSet { let reg_key = as_utf16("HARDWARE\\DEVICEMAP\\SERIALCOMM"); let key_ptr = reg_key.as_ptr(); - let mut ports_key = std::ptr::null_mut(); + + //https://github.com/microsoft/windows-rs/issues/3093 + //in windows-sys 0.59.0 + // let mut ports_key = std::ptr::null_mut(); + + //in windows-sys 0.52.0 + let mut ports_key:isize = 0; // SAFETY: ffi, all inputs are correct let open_res = unsafe { RegOpenKeyExW(HKEY_LOCAL_MACHINE, key_ptr, 0, KEY_READ, &mut ports_key) }; if SUCCEEDED(open_res) { - let mut class_name_buff = [0u16; MAX_PATH]; + let mut class_name_buff = [0u16; MAX_PATH as usize]; let mut class_name_size = MAX_PATH as u32; let mut sub_key_count = 0; let mut largest_sub_key = 0; @@ -471,10 +515,10 @@ fn get_registry_com_ports() -> HashSet { }; if SUCCEEDED(query_res) { for idx in 0..num_key_values { - let mut val_name_buff = [0u16; MAX_PATH]; + let mut val_name_buff = [0u16; MAX_PATH as usize]; let mut val_name_size = MAX_PATH as u32; let mut value_type = 0; - let mut val_data = [0u16; MAX_PATH]; + let mut val_data = [0u16; MAX_PATH as usize]; let buffer_byte_len = 2 * val_data.len() as DWORD; // len doubled let mut byte_len = buffer_byte_len; diff --git a/src/windows/error.rs b/src/windows/error.rs index 72c1f0c..05ea8f1 100644 --- a/src/windows/error.rs +++ b/src/windows/error.rs @@ -1,13 +1,38 @@ use std::io; use std::ptr; -use winapi::shared::minwindef::DWORD; -use winapi::shared::winerror::*; -use winapi::um::errhandlingapi::GetLastError; -use winapi::um::winbase::{ - FormatMessageW, FORMAT_MESSAGE_FROM_SYSTEM, FORMAT_MESSAGE_IGNORE_INSERTS, -}; -use winapi::um::winnt::{LANG_SYSTEM_DEFAULT, MAKELANGID, SUBLANG_SYS_DEFAULT, WCHAR}; +// use winapi::shared::minwindef::DWORD; +// use winapi::shared::winerror::*; +// use winapi::um::errhandlingapi::GetLastError; +// use winapi::um::winbase::{ +// FormatMessageW, FORMAT_MESSAGE_FROM_SYSTEM, FORMAT_MESSAGE_IGNORE_INSERTS, +// }; +// use winapi::um::winnt::{LANG_SYSTEM_DEFAULT, MAKELANGID, SUBLANG_SYS_DEFAULT, WCHAR}; + +use windows_sys::Win32::Foundation::{ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND, ERROR_ACCESS_DENIED, GetLastError}; +use windows_sys::Win32::System::Diagnostics::Debug::{FormatMessageW, FORMAT_MESSAGE_FROM_SYSTEM, FORMAT_MESSAGE_IGNORE_INSERTS}; +use windows_sys::Win32::System::SystemServices::SUBLANG_SYS_DEFAULT; + +//in windows-sys 0.59.0 +//In windows-sys 0.52.0 there is no such +// use windows_sys::Win32::Globalization::LANG_SYSTEM_DEFAULT; + +//in windows-sys 0.52.0 +//https://docs.rs/windows-sys/latest/windows_sys/Win32/Globalization/constant.LANG_SYSTEM_DEFAULT.html +pub const LANG_SYSTEM_DEFAULT: i32 = 2048i32; + +//https://github.com/microsoft/windows-rs/issues/881 +type DWORD = u32; +type WORD = u16; +//https://docs.rs/winapi/latest/src/winapi/um/winnt.rs.html#129 +type LANGID = WORD; +//https://github.com/microsoft/windows-rs/issues/1874 +#[cfg(windows)] +type WCHAR = u16; +//https://docs.rs/winapi/latest/src/winapi/um/winnt.rs.html#776-778 +fn MAKELANGID(p: WORD, s: WORD) -> LANGID { + (s << 10) | p +} use crate::{Error, ErrorKind}; @@ -33,7 +58,7 @@ fn error_string(errnum: u32) -> String { // This value is calculated from the macro // MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT) - let langId = MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT) as DWORD; + let langId = MAKELANGID(LANG_SYSTEM_DEFAULT as u16, SUBLANG_SYS_DEFAULT as u16) as DWORD; let mut buf = [0 as WCHAR; 2048];