Skip to content

Commit

Permalink
Migrate to windows-sys
Browse files Browse the repository at this point in the history
  • Loading branch information
sweet-de-way committed Dec 1, 2024
1 parent f854b8d commit 30913c3
Show file tree
Hide file tree
Showing 5 changed files with 262 additions and 39 deletions.
22 changes: 22 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,28 @@ features = [
"minwindef", "ntdef", "setupapi", "winbase", "winerror", "winnt",
]

[target."cfg(windows)".dependencies.windows-sys]
version = "0.59.0"
features = [
"Win32_Storage",
"Win32_Storage_FileSystem",
"Win32_Security",
"Win32_Devices",
"Win32_Devices_Communication",
"Win32_Devices_DeviceAndDriverInstallation",
"Win32_Devices_Properties",
"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"
Expand Down
34 changes: 25 additions & 9 deletions src/windows/com.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,38 @@ 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::{SetCommMask, 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::{
ClearBuffer, DataBits, Error, ErrorKind, FlowControl, Parity, Result, SerialPort,
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
Expand Down
154 changes: 149 additions & 5 deletions src/windows/dcb.rs
Original file line number Diff line number Diff line change
@@ -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};

Expand Down Expand Up @@ -31,7 +38,9 @@ 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.EofChar = 26;
// dcb.EvtChar
// always true for communications resources
Expand All @@ -55,6 +64,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, fBinary: DWORD) -> () {
self._bitfield = (self._bitfield & !0b0000_0000_0000_0001) | (fBinary & 0x1);
}
fn set_fParity(&mut self, fParity: DWORD) -> () {
self._bitfield = (self._bitfield & !0b0000_0000_0000_0010) | ((fParity & 0x1) << 1);
}
fn set_fOutxCtsFlow(&mut self, fOutxCtsFlow: DWORD) -> () {
self._bitfield = (self._bitfield & !0b0000_0000_0000_0100) | ((fOutxCtsFlow & 0x1) << 2);
}
fn set_fOutxDsrFlow(&mut self, fOutxDsrFlow: DWORD) -> () {
self._bitfield = (self._bitfield & !0b0000_0000_0000_1000) | ((fOutxDsrFlow & 0x1) << 3);
}
fn set_fDtrControl(&mut self, fDtrControl: DWORD) -> () {
self._bitfield = (self._bitfield & !0b0000_0000_0001_0000) | ((fDtrControl & 0x1) << 4);
self._bitfield = (self._bitfield & !0b0000_0000_0010_0000) | ((fDtrControl & 0x2) << 4);
}
fn set_fDsrSensitivity(&mut self, fDsrSensitivity: DWORD) -> () {
self._bitfield = (self._bitfield & !0b0000_0000_0100_0000) | ((fDsrSensitivity & 0x1) << 6);
}
fn set_fTXContinueOnXoff(&mut self, fTXContinueOnXoff: DWORD) -> () {
self._bitfield = (self._bitfield & !0b0000_0000_1000_0000) | ((fTXContinueOnXoff & 0x1) << 7);
}
fn set_fOutX(&mut self, fOutX: DWORD) -> () {
self._bitfield = (self._bitfield & !0b0000_0001_0000_0000) | ((fOutX & 0x1) << 8);
}
fn set_fInX(&mut self, fInX: DWORD) -> () {
self._bitfield = (self._bitfield & !0b0000_0010_0000_0000) | ((fInX & 0x1) << 9);
}
fn set_fErrorChar(&mut self, fErrorChar: DWORD) -> () {
self._bitfield = (self._bitfield & !0b0000_0100_0000_0000) | ((fErrorChar & 0x1) << 10);
}
fn set_fNull(&mut self, fNull: DWORD) -> () {
self._bitfield = (self._bitfield & !0b0000_1000_0000_0000) | ((fNull & 0x1) << 11);
}
fn set_fRtsControl(&mut self, fRtsControl: DWORD) -> () {
self._bitfield = (self._bitfield & !0b0001_0000_0000_0000) | ((fRtsControl & 0x1) << 12);
self._bitfield = (self._bitfield & !0b0010_0000_0000_0000) | ((fRtsControl & 0x2) << 12);
}
fn set_fAbortOnError(&mut self, fAbortOnError: DWORD) -> () {
self._bitfield = (self._bitfield & !0b0100_0000_0000_0000) | ((fAbortOnError & 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(())
Expand Down
58 changes: 41 additions & 17 deletions src/windows/enumerate.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,42 @@
use std::collections::HashSet;
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<u16> {
utf8.encode_utf16().chain(Some(0)).collect()
Expand Down Expand Up @@ -248,7 +272,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<String> {
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 =
Expand Down Expand Up @@ -284,7 +308,7 @@ impl PortDevice {
///
/// Reference: https://learn.microsoft.com/en-us/windows-hardware/drivers/install/device-instance-ids
fn instance_id(&mut self) -> Option<String> {
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 {
Expand Down Expand Up @@ -339,13 +363,13 @@ impl PortDevice {
)
};

if hkey as *mut c_void == winapi::um::handleapi::INVALID_HANDLE_VALUE {
if hkey as *mut c_void == 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;
Expand Down Expand Up @@ -395,7 +419,7 @@ impl PortDevice {
// doesn't exist.
fn property(&mut self, property_id: DWORD) -> Option<String> {
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(
Expand Down Expand Up @@ -439,7 +463,7 @@ fn get_registry_com_ports() -> HashSet<String> {
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;
Expand Down Expand Up @@ -471,10 +495,10 @@ fn get_registry_com_ports() -> HashSet<String> {
};
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;

Expand Down
Loading

0 comments on commit 30913c3

Please sign in to comment.