Skip to content

Commit

Permalink
Merge pull request #37 from andfoy/dependabot/cargo/windows-0.38.0
Browse files Browse the repository at this point in the history
Update windows requirement from 0.29.0 to 0.38.0
  • Loading branch information
andfoy authored Jul 5, 2022
2 parents be52155 + eb81e32 commit 6a58fba
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 56 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/windows_stable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,14 @@ jobs:
shell: bash -l {0}
run: |
rustup component add llvm-tools-preview
echo "RUSTFLAGS=-Zinstrument-coverage" >> $GITHUB_ENV
echo "RUSTFLAGS=-Cinstrument-coverage" >> $GITHUB_ENV
- name: Install miniconda
uses: conda-incubator/setup-miniconda@v2
with:
auto-update-conda: true
activate-environment: test
channels: conda-forge,defaults
python-version: 3.7
python-version: 3.9
- name: Conda env info
shell: bash -l {0}
run: conda env list
Expand Down
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ bitflags = "1.3"
which = "4.1.0"

[dependencies.windows]
version = "0.29.0"
version = "0.38.0"
features = [
"Win32_Foundation",
"Win32_Storage_FileSystem",
Expand All @@ -34,7 +34,7 @@ features = [
]

[build-dependencies.windows]
version = "0.29.0"
version = "0.38.0"
features = [
"Win32_Foundation",
"Win32_System_LibraryLoader"
Expand Down
39 changes: 36 additions & 3 deletions build.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use windows::Win32::System::LibraryLoader::{GetProcAddress, GetModuleHandleW};
use windows::Win32::Foundation::{PWSTR, PSTR};
use windows::core::{PWSTR, PSTR, PCWSTR, PCSTR};
use std::i64;
use std::process::Command;
use std::str;
Expand All @@ -13,6 +13,25 @@ trait IntoPSTR {
fn into_pstr(self) -> PSTR;
}

trait IntoPCSTR {
fn into_pcstr(self) -> PCSTR;
}

trait IntoPCWSTR {
fn into_pcwstr(self) -> PCWSTR;
}

impl IntoPCWSTR for &str {
fn into_pcwstr(self) -> PCWSTR {
let encoded = self
.encode_utf16()
.chain([0u16])
.collect::<Vec<u16>>();

PCWSTR(encoded.as_ptr())
}
}

impl IntoPWSTR for &str {
fn into_pwstr(self) -> PWSTR {
let mut encoded = self
Expand All @@ -35,6 +54,18 @@ impl IntoPSTR for &str {
PSTR(encoded.as_mut_ptr()) }
}

impl IntoPCSTR for &str {
fn into_pcstr(self) -> PCSTR {
let encoded = self
.as_bytes()
.iter()
.cloned()
.chain([0u8])
.collect::<Vec<u8>>();

PCSTR(encoded.as_ptr()) }
}

impl IntoPWSTR for String {
fn into_pwstr(self) -> PWSTR {
let mut encoded = self
Expand Down Expand Up @@ -99,8 +130,10 @@ fn main() {
println!("Windows build number: {:?}", build_version);

let conpty_enabled;
let kernel32 = unsafe { GetModuleHandleW("kernel32.dll".into_pwstr()) };
let conpty = unsafe { GetProcAddress(kernel32, "CreatePseudoConsole".into_pstr()) };
let kernel32_res = unsafe { GetModuleHandleW("kernel32.dll".into_pcwstr()) };
let kernel32 = kernel32_res.unwrap();

let conpty = unsafe { GetProcAddress(kernel32, "CreatePseudoConsole".into_pcstr()) };
match conpty {
Some(_) => {
conpty_enabled = "1";
Expand Down
29 changes: 15 additions & 14 deletions src/pty/base.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
/// Base struct used to generalize some of the PTY I/O operations.
use windows::Win32::Foundation::{HANDLE, S_OK, STATUS_PENDING, CloseHandle, PSTR, PWSTR, WAIT_FAILED, WAIT_TIMEOUT};
use windows::Win32::Foundation::{HANDLE, S_OK, STATUS_PENDING, CloseHandle, WAIT_FAILED, WAIT_TIMEOUT};
use windows::Win32::Storage::FileSystem::{GetFileSizeEx, ReadFile, WriteFile};
use windows::Win32::System::Pipes::PeekNamedPipe;
use windows::Win32::System::IO::{OVERLAPPED, CancelIoEx};
use windows::Win32::System::Threading::{GetExitCodeProcess, GetProcessId, WaitForSingleObject};
use windows::Win32::Globalization::{MultiByteToWideChar, WideCharToMultiByte, CP_UTF8};
use windows::core::{HRESULT, Error};
use windows::Win32::Globalization::{MultiByteToWideChar, WideCharToMultiByte, CP_UTF8, MULTI_BYTE_TO_WIDE_CHAR_FLAGS};
use windows::core::{HRESULT, Error, PSTR, PCSTR};

use std::ptr;
use std::sync::mpsc;
Expand Down Expand Up @@ -193,11 +193,10 @@ fn read(mut length: u32, blocking: bool, stream: HANDLE, using_pipes: bool) -> R

// let os_str = OsString::with_capacity(buf_vec.len());
let mut vec_buf: Vec<u16> = std::iter::repeat(0).take(buf_vec.len()).collect();
let vec_ptr = vec_buf.as_mut_ptr();
let pstr = PSTR(buf_vec.as_mut_ptr());
let pwstr = PWSTR(vec_ptr);

unsafe {
MultiByteToWideChar(CP_UTF8, 0, pstr, -1, pwstr, (total_bytes + 1) as i32);
MultiByteToWideChar(
CP_UTF8, MULTI_BYTE_TO_WIDE_CHAR_FLAGS(0), &buf_vec[..], &mut vec_buf[..]);
}

// let non_zeros: Vec<u16> = vec_buf.split(|elem| *elem == 0 as u16).collect();
Expand All @@ -218,10 +217,10 @@ fn read(mut length: u32, blocking: bool, stream: HANDLE, using_pipes: bool) -> R
fn is_alive(process: HANDLE) -> Result<bool, OsString> {
unsafe {
let is_timeout = WaitForSingleObject(process, 0);
let succ = is_timeout != WAIT_FAILED;
let succ = is_timeout != WAIT_FAILED.0;

if succ {
let alive = is_timeout == WAIT_TIMEOUT;
let alive = is_timeout == WAIT_TIMEOUT.0;
Ok(alive)
} else {
let err: HRESULT = Error::from_win32().into();
Expand Down Expand Up @@ -458,22 +457,24 @@ impl PTYProcess {
/// The total number of characters written if the call was successful, else
/// an [`OsString`] containing an human-readable error.
pub fn write(&self, buf: OsString) -> Result<u32, OsString> {
let mut vec_buf: Vec<u16> = buf.encode_wide().collect();
let vec_buf: Vec<u16> = buf.encode_wide().collect();

let null_overlapped: *mut OVERLAPPED = ptr::null_mut();
let result: HRESULT;

unsafe {
let pwstr = PWSTR(vec_buf.as_mut_ptr());
let required_size = WideCharToMultiByte(
CP_UTF8, 0, pwstr, vec_buf.len().try_into().map_err(|_| "buf too large")?, PSTR(ptr::null_mut::<u8>()),
0, PSTR(ptr::null_mut::<u8>()), ptr::null_mut::<i32>());
CP_UTF8, 0, &vec_buf[..], PSTR(ptr::null_mut::<u8>()),
0, PCSTR(ptr::null_mut::<u8>()), ptr::null_mut::<i32>());

let mut bytes_buf: Vec<u8> = std::iter::repeat(0).take((required_size) as usize).collect();
let bytes_buf_ptr = bytes_buf.as_mut_ptr();
let pstr = PSTR(bytes_buf_ptr);

WideCharToMultiByte(CP_UTF8, 0, pwstr, vec_buf.len().try_into().unwrap(), pstr, required_size, PSTR(ptr::null_mut::<u8>()), ptr::null_mut::<i32>());
WideCharToMultiByte(
CP_UTF8, 0, &vec_buf[..], pstr,
required_size, PCSTR(ptr::null_mut::<u8>()),
ptr::null_mut::<i32>());

let mut written_bytes = MaybeUninit::<u32>::uninit();
let bytes_ptr: *mut u32 = ptr::addr_of_mut!(*written_bytes.as_mut_ptr());
Expand Down
60 changes: 30 additions & 30 deletions src/pty/conpty/pty_impl.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
/// Actual ConPTY implementation.
use windows::core::{PWSTR, PCWSTR, Error};
use windows::Win32::Foundation::{
CloseHandle, PWSTR, HANDLE,
CloseHandle, HANDLE,
S_OK, INVALID_HANDLE_VALUE};
use windows::Win32::Storage::FileSystem::{
CreateFileW, FILE_GENERIC_READ, FILE_SHARE_READ,
FILE_SHARE_WRITE, OPEN_EXISTING, FILE_GENERIC_WRITE,
FILE_ATTRIBUTE_NORMAL};
FILE_ATTRIBUTE_NORMAL, FILE_FLAGS_AND_ATTRIBUTES};
use windows::Win32::System::Console::{
HPCON, AllocConsole, GetConsoleWindow,
GetConsoleMode, CONSOLE_MODE, ENABLE_VIRTUAL_TERMINAL_PROCESSING,
Expand All @@ -21,7 +22,7 @@ use windows::Win32::System::Threading::{
EXTENDED_STARTUPINFO_PRESENT, CREATE_UNICODE_ENVIRONMENT,
DeleteProcThreadAttributeList};
use windows::Win32::UI::WindowsAndMessaging::{ShowWindow, SW_HIDE};
use windows::core::{HRESULT, Error};
use windows::core::{HRESULT};

use std::{mem, ptr};
use std::mem::MaybeUninit;
Expand All @@ -47,7 +48,7 @@ unsafe impl Sync for ConPTY {}

impl PTYImpl for ConPTY {
fn new(args: &PTYArgs) -> Result<Box<dyn PTYImpl>, OsString> {
let mut result: HRESULT = S_OK;
let mut result: HRESULT;
if args.cols <= 0 || args.rows <= 0 {
let err: OsString = OsString::from(format!(
"PTY cols and rows must be positive and non-zero. Got: ({}, {})", args.cols, args.rows));
Expand All @@ -64,46 +65,43 @@ impl PTYImpl for ConPTY {
// Recreate the standard stream inputs in case the parent process
// has redirected them.
let conout_name = OsString::from("CONOUT$\0");
let mut conout_vec: Vec<u16> = conout_name.encode_wide().collect();
let conout_pwstr = PWSTR(conout_vec.as_mut_ptr());
let conout_vec: Vec<u16> = conout_name.encode_wide().collect();
let conout_pwstr = PCWSTR(conout_vec.as_ptr());

let h_console = CreateFileW(
let h_console_res = CreateFileW(
conout_pwstr, FILE_GENERIC_READ | FILE_GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
ptr::null(), OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, HANDLE(0));

if h_console.is_invalid() {
result = Error::from_win32().into();
}

if result.is_err() {
let result_msg = result.message();
if let Err(err) = h_console_res {
let result_msg = err.message();
let err_msg: &[u16] = result_msg.as_wide();
let string = OsString::from_wide(err_msg);
return Err(string);
}

let h_console = h_console_res.unwrap();

let conin_name = OsString::from("CONIN$\0");
let mut conin_vec: Vec<u16> = conin_name.encode_wide().collect();
let conin_pwstr = PWSTR(conin_vec.as_mut_ptr());
let conin_vec: Vec<u16> = conin_name.encode_wide().collect();
let conin_pwstr = PCWSTR(conin_vec.as_ptr());

let h_in = CreateFileW(
let h_in_res = CreateFileW(
conin_pwstr,
FILE_GENERIC_READ | FILE_GENERIC_WRITE,
FILE_SHARE_READ, ptr::null(),
OPEN_EXISTING, 0, HANDLE(0));
OPEN_EXISTING, FILE_FLAGS_AND_ATTRIBUTES(0),
HANDLE(0));

if h_in.is_invalid() {
result = Error::from_win32().into();
}

if result.is_err() {
let result_msg = result.message();
if let Err(err) = h_in_res {
let result_msg = err.message();
let err_msg: &[u16] = result_msg.as_wide();
let string = OsString::from_wide(err_msg);
return Err(string);
}

let h_in = h_in_res.unwrap();

let mut console_mode_un = MaybeUninit::<CONSOLE_MODE>::uninit();
let console_mode_ptr = console_mode_un.as_mut_ptr();

Expand Down Expand Up @@ -222,7 +220,7 @@ impl PTYImpl for ConPTY {
fn spawn(&mut self, appname: OsString, cmdline: Option<OsString>, cwd: Option<OsString>, env: Option<OsString>) -> Result<bool, OsString> {
let result: HRESULT;
let mut environ: *const u16 = ptr::null();
let mut working_dir: *mut u16 = ptr::null_mut();
let mut working_dir: *const u16 = ptr::null_mut();
let mut env_buf: Vec<u16>;
let mut cwd_buf: Vec<u16>;
let cmd_buf: Vec<u16>;
Expand All @@ -240,7 +238,7 @@ impl PTYImpl for ConPTY {
if let Some(cwd_opt) = cwd {
cwd_buf = cwd_opt.encode_wide().collect();
cwd_buf.push(0);
working_dir = cwd_buf.as_mut_ptr();
working_dir = cwd_buf.as_ptr();
}

if let Some(cmdline_opt) = cmdline {
Expand All @@ -256,12 +254,14 @@ impl PTYImpl for ConPTY {
// Discover the size required for the list
let mut required_bytes_u = MaybeUninit::<usize>::uninit();
let required_bytes_ptr = required_bytes_u.as_mut_ptr();
InitializeProcThreadAttributeList(ptr::null_mut(), 1, 0, required_bytes_ptr);
InitializeProcThreadAttributeList(
LPPROC_THREAD_ATTRIBUTE_LIST(ptr::null_mut()), 1, 0, required_bytes_ptr);

// Allocate memory to represent the list
let mut required_bytes = required_bytes_u.assume_init();
let mut lp_attribute_list: Box<[u8]> = vec![0; required_bytes].into_boxed_slice();
let proc_thread_list: LPPROC_THREAD_ATTRIBUTE_LIST = lp_attribute_list.as_mut_ptr().cast::<_>();
let proc_thread_list: LPPROC_THREAD_ATTRIBUTE_LIST = LPPROC_THREAD_ATTRIBUTE_LIST(
lp_attribute_list.as_mut_ptr().cast::<_>());

// Prepare Startup Information structure
let start_info = STARTUPINFOEXW {
Expand All @@ -284,7 +284,7 @@ impl PTYImpl for ConPTY {
// Set the pseudoconsole information into the list
if !UpdateProcThreadAttribute(
start_info.lpAttributeList, 0, 0x00020016,
self.handle as _, mem::size_of::<HPCON>(),
self.handle.0 as _, mem::size_of::<HPCON>(),
ptr::null_mut(), ptr::null_mut()).as_bool() {
result = Error::from_win32().into();
let result_msg = result.message();
Expand All @@ -298,14 +298,14 @@ impl PTYImpl for ConPTY {
let si_ptr = &start_info as *const STARTUPINFOEXW;

let succ = CreateProcessW(
PWSTR(ptr::null_mut()),
PCWSTR(ptr::null_mut()),
PWSTR(cmd),
ptr::null_mut(),
ptr::null_mut(),
false,
EXTENDED_STARTUPINFO_PRESENT | CREATE_UNICODE_ENVIRONMENT,
environ as _,
PWSTR(working_dir),
PCWSTR(working_dir),
si_ptr as *const _,
pi_ptr
).as_bool();
Expand Down
28 changes: 23 additions & 5 deletions src/pty/winpty/pty_impl.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/// Actual WinPTY backend implementation.
use windows::Win32::Foundation::{PWSTR, HANDLE};
use windows::Win32::Foundation::{HANDLE};
use windows::core::{PCWSTR};
use windows::Win32::Storage::FileSystem::{
CreateFileW, FILE_GENERIC_READ, FILE_SHARE_NONE,
OPEN_EXISTING, FILE_GENERIC_WRITE,
Expand Down Expand Up @@ -168,16 +169,33 @@ impl PTYImpl for WinPTY {
let conout_name = pty_ptr.get_conout_name();

let empty_handle = HANDLE(0);
let conin = CreateFileW(
PWSTR(conin_name as *mut u16), FILE_GENERIC_WRITE, FILE_SHARE_NONE, ptr::null(),
let conin_res = CreateFileW(
PCWSTR(conin_name as *const u16), FILE_GENERIC_WRITE, FILE_SHARE_NONE, ptr::null(),
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, empty_handle
);

let conout = CreateFileW(
PWSTR(conout_name as *mut u16), FILE_GENERIC_READ, FILE_SHARE_NONE, ptr::null(),
if let Err(err) = conin_res {
let result_msg = err.message();
let err_msg: &[u16] = result_msg.as_wide();
let string = OsString::from_wide(err_msg);
return Err(string);
}

let conout_res = CreateFileW(
PCWSTR(conout_name as *mut u16), FILE_GENERIC_READ, FILE_SHARE_NONE, ptr::null(),
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, empty_handle
);

if let Err(err) = conout_res {
let result_msg = err.message();
let err_msg: &[u16] = result_msg.as_wide();
let string = OsString::from_wide(err_msg);
return Err(string);
}

let conin = conin_res.unwrap();
let conout = conout_res.unwrap();

let process = PTYProcess::new(conin, conout, false);
Ok(Box::new(WinPTY { ptr: pty_ptr, process }) as Box<dyn PTYImpl>)
}
Expand Down

0 comments on commit 6a58fba

Please sign in to comment.