From ada952591acb6312d3d43352b8c672ad556a6664 Mon Sep 17 00:00:00 2001 From: yozhgoor Date: Mon, 8 Nov 2021 17:44:22 +0100 Subject: [PATCH 01/37] Transform the bin in a lib --- Cargo.toml | 1 + src/lib.rs | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 54 ++++++++++----------------------------- 3 files changed, 88 insertions(+), 40 deletions(-) create mode 100644 src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 44f61d0..a294c26 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,6 @@ [package] name = "CreateProcessW" +alias = "create_process_w" version = "0.1.0" edition = "2021" diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..2e43dad --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,73 @@ +use std::ffi::c_void; +use windows::Win32::Foundation::{CloseHandle, GetLastError, PWSTR}; +use windows::Win32::Security::SECURITY_ATTRIBUTES; +use windows::Win32::System::Threading::{ + TerminateProcess, WaitForSingleObject, PROCESS_CREATION_FLAGS, PROCESS_INFORMATION, + STARTUPINFOW, +}; +use windows::Win32::System::WindowsProgramming::INFINITE; + +pub struct ChildProcess { + process_information: PROCESS_INFORMATION, +} + +pub type ChildProcessError = String; + +impl ChildProcess { + pub fn new(command: &str) -> Result { + let startup_info = STARTUPINFOW::default(); + let process_information = PROCESS_INFORMATION::default(); + + if create_process(startup_info, process_information, command) { + Ok(Self { + process_information, + }) + } else { + Err(format!("{:?}", unsafe { GetLastError() })) + } + } + + pub fn wait(&self) { + unsafe { + WaitForSingleObject(self.process_information.hProcess, INFINITE); + close_handle(self.process_information); + } + } + + pub fn kill(&self) -> Result<(), ChildProcessError> { + unsafe { + if TerminateProcess(self.process_information.hProcess, 0).as_bool() { + close_handle(self.process_information); + + Ok(()) + } else { + Err(String::from("An error occurred when killing the process")) + } + } + } +} + +fn create_process(si: STARTUPINFOW, mut pi: PROCESS_INFORMATION, command: &str) -> bool { + unsafe { + windows::Win32::System::Threading::CreateProcessW( + PWSTR::default(), + command, + std::ptr::null() as *const SECURITY_ATTRIBUTES, + std::ptr::null() as *const SECURITY_ATTRIBUTES, + false, + PROCESS_CREATION_FLAGS(0), + std::ptr::null() as *const c_void, + PWSTR::default(), + &si, + &mut pi as *mut PROCESS_INFORMATION, + ) + .as_bool() + } +} + +fn close_handle(process_information: PROCESS_INFORMATION) { + unsafe { + CloseHandle(process_information.hProcess); + CloseHandle(process_information.hThread); + } +} diff --git a/src/main.rs b/src/main.rs index fc23ee4..6529619 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,47 +1,21 @@ -use windows::Win32::Security::SECURITY_ATTRIBUTES; -use windows::Win32::System::Threading::{PROCESS_CREATION_FLAGS, PROCESS_INFORMATION, STARTUPINFOW, TerminateProcess, WaitForSingleObject}; -use windows::Win32::Foundation::{PWSTR, CloseHandle, GetLastError}; -use windows::Win32::System::WindowsProgramming::INFINITE; -use std::os::raw::c_void; - fn main() { - let si = STARTUPINFOW::default(); - let mut pi = PROCESS_INFORMATION::default(); - - let kill = false; - - unsafe { - if windows::Win32::System::Threading::CreateProcessW( - PWSTR::default(), - "notepad.exe", - std::ptr::null() as *const SECURITY_ATTRIBUTES, - std::ptr::null() as *const SECURITY_ATTRIBUTES, - false, - PROCESS_CREATION_FLAGS(0), - std::ptr::null() as *const c_void, - PWSTR::default(), - &si, - &mut pi as *mut PROCESS_INFORMATION, - ).as_bool() { - if kill { - std::thread::sleep(std::time::Duration::from_secs(2)); - - TerminateProcess( pi.hProcess, 0 ); - } else { - WaitForSingleObject( pi.hProcess, INFINITE ); - } + let wait = false; - CloseHandle (pi.hProcess); - CloseHandle (pi.hThread); + let process = match CreateProcessW::ChildProcess::new("notepad.exe") { + Ok(child) => child, + Err(err) => { + panic!("An error occurred: {}", err); + } + }; - std::thread::sleep(std::time::Duration::from_secs(2)); + if wait { + process.wait(); + } else { + std::thread::sleep(std::time::Duration::from_secs(2)); - println!("Success"); - } else { - println!("failed {:?}", GetLastError()); + match process.kill() { + Ok(_) => {} + Err(err) => println!("{}", err), } } } - - -// fn create_process(command: String, foreground: bool, keep_on_exit: bool, working_dir: Option, stdout: bool, stderr: bool) \ No newline at end of file From 585cd8eca89c6fa7db39518f4406ab20e511ad7d Mon Sep 17 00:00:00 2001 From: yozhgoor Date: Mon, 8 Nov 2021 18:03:47 +0100 Subject: [PATCH 02/37] WIP --- src/lib.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 2e43dad..5824014 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,15 +15,9 @@ pub type ChildProcessError = String; impl ChildProcess { pub fn new(command: &str) -> Result { - let startup_info = STARTUPINFOW::default(); - let process_information = PROCESS_INFORMATION::default(); - - if create_process(startup_info, process_information, command) { - Ok(Self { - process_information, - }) - } else { - Err(format!("{:?}", unsafe { GetLastError() })) + match create_process(command) { + Ok(process_information) => Ok(Self { process_information }), + Err(err) => Err(format!("{}", err)), } } @@ -47,9 +41,12 @@ impl ChildProcess { } } -fn create_process(si: STARTUPINFOW, mut pi: PROCESS_INFORMATION, command: &str) -> bool { +fn create_process(command: &str) -> Result { unsafe { - windows::Win32::System::Threading::CreateProcessW( + let si = STARTUPINFOW::default(); + let mut pi = PROCESS_INFORMATION::default(); + + if windows::Win32::System::Threading::CreateProcessW( PWSTR::default(), command, std::ptr::null() as *const SECURITY_ATTRIBUTES, @@ -60,8 +57,11 @@ fn create_process(si: STARTUPINFOW, mut pi: PROCESS_INFORMATION, command: &str) PWSTR::default(), &si, &mut pi as *mut PROCESS_INFORMATION, - ) - .as_bool() + ).as_bool() { + Ok(pi) + } else { + Err(format!("{:?}", GetLastError())) + } } } From 55c90c4ca8466e674e3f488790dfeb43451bca95 Mon Sep 17 00:00:00 2001 From: yozhgoor Date: Mon, 8 Nov 2021 18:05:31 +0100 Subject: [PATCH 03/37] Modify errors messages --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 5824014..17664de 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,7 +17,7 @@ impl ChildProcess { pub fn new(command: &str) -> Result { match create_process(command) { Ok(process_information) => Ok(Self { process_information }), - Err(err) => Err(format!("{}", err)), + Err(err) => Err(format!("an error occurred when creating process : {}", err)), } } @@ -35,7 +35,7 @@ impl ChildProcess { Ok(()) } else { - Err(String::from("An error occurred when killing the process")) + Err(String::from("an error occurred when killing the process")) } } } From 5b9fc158f6e8dcd0562266bd663dc5d3a42743ce Mon Sep 17 00:00:00 2001 From: yozhgoor Date: Mon, 8 Nov 2021 18:06:51 +0100 Subject: [PATCH 04/37] formatting --- src/lib.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 17664de..c1692d3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,7 +16,9 @@ pub type ChildProcessError = String; impl ChildProcess { pub fn new(command: &str) -> Result { match create_process(command) { - Ok(process_information) => Ok(Self { process_information }), + Ok(process_information) => Ok(Self { + process_information, + }), Err(err) => Err(format!("an error occurred when creating process : {}", err)), } } @@ -57,7 +59,9 @@ fn create_process(command: &str) -> Result Date: Tue, 9 Nov 2021 10:04:29 +0100 Subject: [PATCH 05/37] Clean up --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index a294c26..44f61d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,5 @@ [package] name = "CreateProcessW" -alias = "create_process_w" version = "0.1.0" edition = "2021" From e5235c93b5f54dfb0b491ecd55430c9beeee6b0e Mon Sep 17 00:00:00 2001 From: yozhgoor Date: Tue, 9 Nov 2021 10:08:27 +0100 Subject: [PATCH 06/37] Remove main.rs --- src/main.rs | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 src/main.rs diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index 6529619..0000000 --- a/src/main.rs +++ /dev/null @@ -1,21 +0,0 @@ -fn main() { - let wait = false; - - let process = match CreateProcessW::ChildProcess::new("notepad.exe") { - Ok(child) => child, - Err(err) => { - panic!("An error occurred: {}", err); - } - }; - - if wait { - process.wait(); - } else { - std::thread::sleep(std::time::Duration::from_secs(2)); - - match process.kill() { - Ok(_) => {} - Err(err) => println!("{}", err), - } - } -} From 493648b0161d7566628afcf992671e8b916a4b97 Mon Sep 17 00:00:00 2001 From: yozhgoor Date: Tue, 9 Nov 2021 12:47:28 +0100 Subject: [PATCH 07/37] Add arguments to the new function and remove create_process --- src/lib.rs | 73 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 40 insertions(+), 33 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b6420b6..b3854c4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ #![allow(non_snake_case)] use std::ffi::c_void; -use windows::Win32::Foundation::{CloseHandle, GetLastError, PWSTR}; +use windows::Win32::Foundation::{CloseHandle, GetLastError}; use windows::Win32::Security::SECURITY_ATTRIBUTES; use windows::Win32::System::Threading::{ TerminateProcess, WaitForSingleObject, PROCESS_CREATION_FLAGS, PROCESS_INFORMATION, @@ -9,22 +9,55 @@ use windows::Win32::System::Threading::{ }; use windows::Win32::System::WindowsProgramming::INFINITE; +#[derive(Debug)] pub struct ChildProcess { + command: String, process_information: PROCESS_INFORMATION, } pub type ChildProcessError = String; impl ChildProcess { - pub fn new(command: &str) -> Result { - match create_process(command) { - Ok(process_information) => Ok(Self { - process_information, - }), - Err(err) => Err(format!("an error occurred when creating process : {}", err)), + pub fn new( + application_name: Option<&str>, + command: Option<&str>, + inherit_handles: bool, + current_directory: Option<&str>, + ) -> Result { + unsafe { + let si = STARTUPINFOW::default(); + let mut pi = PROCESS_INFORMATION::default(); + + let command = command.unwrap_or_default(); + + if windows::Win32::System::Threading::CreateProcessW( + application_name.unwrap_or_default(), + command, + std::ptr::null() as *const SECURITY_ATTRIBUTES, + std::ptr::null() as *const SECURITY_ATTRIBUTES, + inherit_handles, + PROCESS_CREATION_FLAGS(0), + std::ptr::null() as *const c_void, + current_directory.unwrap_or_default(), + &si, + &mut pi as *mut PROCESS_INFORMATION, + ) + .as_bool() + { + Ok(Self { + command: command.to_string(), + process_information: pi, + }) + } else { + Err(format!("Cannot create process: {:?}", GetLastError())) + } } } + pub fn command(&self) -> String { + self.command.clone() + } + pub fn wait(&self) { unsafe { WaitForSingleObject(self.process_information.hProcess, INFINITE); @@ -45,32 +78,6 @@ impl ChildProcess { } } -fn create_process(command: &str) -> Result { - unsafe { - let si = STARTUPINFOW::default(); - let mut pi = PROCESS_INFORMATION::default(); - - if windows::Win32::System::Threading::CreateProcessW( - PWSTR::default(), - command, - std::ptr::null() as *const SECURITY_ATTRIBUTES, - std::ptr::null() as *const SECURITY_ATTRIBUTES, - false, - PROCESS_CREATION_FLAGS(0), - std::ptr::null() as *const c_void, - PWSTR::default(), - &si, - &mut pi as *mut PROCESS_INFORMATION, - ) - .as_bool() - { - Ok(pi) - } else { - Err(format!("{:?}", GetLastError())) - } - } -} - fn close_handle(process_information: PROCESS_INFORMATION) { unsafe { CloseHandle(process_information.hProcess); From 0597c314ae25c347cba6621c48069c8885ab36e7 Mon Sep 17 00:00:00 2001 From: yozhgoor Date: Tue, 9 Nov 2021 13:05:13 +0100 Subject: [PATCH 08/37] Attempt to use an Option for the `current_directory` argument --- src/lib.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b3854c4..163f0eb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,8 @@ #![allow(non_snake_case)] use std::ffi::c_void; -use windows::Win32::Foundation::{CloseHandle, GetLastError}; +use windows::runtime::{IntoParam, Param}; +use windows::Win32::Foundation::{CloseHandle, GetLastError, PWSTR}; use windows::Win32::Security::SECURITY_ATTRIBUTES; use windows::Win32::System::Threading::{ TerminateProcess, WaitForSingleObject, PROCESS_CREATION_FLAGS, PROCESS_INFORMATION, @@ -19,8 +20,7 @@ pub type ChildProcessError = String; impl ChildProcess { pub fn new( - application_name: Option<&str>, - command: Option<&str>, + command: &str, inherit_handles: bool, current_directory: Option<&str>, ) -> Result { @@ -28,17 +28,18 @@ impl ChildProcess { let si = STARTUPINFOW::default(); let mut pi = PROCESS_INFORMATION::default(); - let command = command.unwrap_or_default(); + let current_directory: Param<'static, PWSTR> = + current_directory.unwrap_or_default().into_param(); if windows::Win32::System::Threading::CreateProcessW( - application_name.unwrap_or_default(), + PWSTR::default(), command, std::ptr::null() as *const SECURITY_ATTRIBUTES, std::ptr::null() as *const SECURITY_ATTRIBUTES, inherit_handles, PROCESS_CREATION_FLAGS(0), std::ptr::null() as *const c_void, - current_directory.unwrap_or_default(), + current_directory, &si, &mut pi as *mut PROCESS_INFORMATION, ) From f0cf958b84441bfae1775b2d0868138be44aa73e Mon Sep 17 00:00:00 2001 From: yozhgoor Date: Tue, 9 Nov 2021 13:34:13 +0100 Subject: [PATCH 09/37] Clean up --- src/lib.rs | 47 ++++++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 163f0eb..41d0d37 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,6 @@ #![allow(non_snake_case)] use std::ffi::c_void; -use windows::runtime::{IntoParam, Param}; use windows::Win32::Foundation::{CloseHandle, GetLastError, PWSTR}; use windows::Win32::Security::SECURITY_ATTRIBUTES; use windows::Win32::System::Threading::{ @@ -28,23 +27,37 @@ impl ChildProcess { let si = STARTUPINFOW::default(); let mut pi = PROCESS_INFORMATION::default(); - let current_directory: Param<'static, PWSTR> = - current_directory.unwrap_or_default().into_param(); + let process = if let Some(directory) = current_directory { + windows::Win32::System::Threading::CreateProcessW( + PWSTR::default(), + command, + std::ptr::null() as *const SECURITY_ATTRIBUTES, + std::ptr::null() as *const SECURITY_ATTRIBUTES, + inherit_handles, + PROCESS_CREATION_FLAGS(0), + std::ptr::null() as *const c_void, + directory, + &si, + &mut pi as *mut PROCESS_INFORMATION, + ) + .as_bool() + } else { + windows::Win32::System::Threading::CreateProcessW( + PWSTR::default(), + command, + std::ptr::null() as *const SECURITY_ATTRIBUTES, + std::ptr::null() as *const SECURITY_ATTRIBUTES, + inherit_handles, + PROCESS_CREATION_FLAGS(0), + std::ptr::null() as *const c_void, + PWSTR::default(), + &si, + &mut pi as *mut PROCESS_INFORMATION, + ) + .as_bool() + }; - if windows::Win32::System::Threading::CreateProcessW( - PWSTR::default(), - command, - std::ptr::null() as *const SECURITY_ATTRIBUTES, - std::ptr::null() as *const SECURITY_ATTRIBUTES, - inherit_handles, - PROCESS_CREATION_FLAGS(0), - std::ptr::null() as *const c_void, - current_directory, - &si, - &mut pi as *mut PROCESS_INFORMATION, - ) - .as_bool() - { + if process { Ok(Self { command: command.to_string(), process_information: pi, From ec3d73d903967b38edeff0cc4fd0caf1dc961fa6 Mon Sep 17 00:00:00 2001 From: yozhgoor Date: Tue, 9 Nov 2021 13:49:59 +0100 Subject: [PATCH 10/37] Looks good --- src/lib.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 41d0d37..e3924a4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -63,7 +63,7 @@ impl ChildProcess { process_information: pi, }) } else { - Err(format!("Cannot create process: {:?}", GetLastError())) + Err(format!("cannot create process: {:?}", GetLastError())) } } } @@ -72,10 +72,12 @@ impl ChildProcess { self.command.clone() } - pub fn wait(&self) { + pub fn wait(&self) -> u32 { unsafe { - WaitForSingleObject(self.process_information.hProcess, INFINITE); + let exit_code = WaitForSingleObject(self.process_information.hProcess, INFINITE); close_handle(self.process_information); + + exit_code } } @@ -86,7 +88,8 @@ impl ChildProcess { Ok(()) } else { - Err(String::from("an error occurred when killing the process")) + close_handle(self.process_information); + Err(format!("cannot kill process: {:?}", GetLastError())) } } } From 844d3a3a304b10c44648b8ff78870a43a59c76b1 Mon Sep 17 00:00:00 2001 From: yozhgoor Date: Tue, 9 Nov 2021 13:55:40 +0100 Subject: [PATCH 11/37] Listen to the Clippy --- src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e3924a4..271a49b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -83,12 +83,12 @@ impl ChildProcess { pub fn kill(&self) -> Result<(), ChildProcessError> { unsafe { - if TerminateProcess(self.process_information.hProcess, 0).as_bool() { - close_handle(self.process_information); + let terminate = TerminateProcess(self.process_information.hProcess, 0).as_bool(); + close_handle(self.process_information); + if terminate { Ok(()) } else { - close_handle(self.process_information); Err(format!("cannot kill process: {:?}", GetLastError())) } } From 240f4382c9e24743bcb4992ff332bebd07bb8d4f Mon Sep 17 00:00:00 2001 From: yozhgoor Date: Tue, 9 Nov 2021 14:08:32 +0100 Subject: [PATCH 12/37] Add ExitCode --- src/lib.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 271a49b..2ba3072 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,6 +17,8 @@ pub struct ChildProcess { pub type ChildProcessError = String; +pub struct ExitCode(u32); + impl ChildProcess { pub fn new( command: &str, @@ -72,12 +74,12 @@ impl ChildProcess { self.command.clone() } - pub fn wait(&self) -> u32 { + pub fn wait(&self) -> ExitCode { unsafe { let exit_code = WaitForSingleObject(self.process_information.hProcess, INFINITE); close_handle(self.process_information); - exit_code + ExitCode(exit_code) } } @@ -95,6 +97,16 @@ impl ChildProcess { } } +impl ExitCode { + pub fn success(&self) -> bool { + self.0 == 0 + } + + pub fn display(&self) -> u32 { + self.0 + } +} + fn close_handle(process_information: PROCESS_INFORMATION) { unsafe { CloseHandle(process_information.hProcess); From 6238a18814d17e61669c82bde37425b24e43a2a6 Mon Sep 17 00:00:00 2001 From: yozhgoor Date: Tue, 9 Nov 2021 14:11:05 +0100 Subject: [PATCH 13/37] Remove duplicate --- src/lib.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 2ba3072..f939372 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,7 +42,6 @@ impl ChildProcess { &si, &mut pi as *mut PROCESS_INFORMATION, ) - .as_bool() } else { windows::Win32::System::Threading::CreateProcessW( PWSTR::default(), @@ -56,8 +55,8 @@ impl ChildProcess { &si, &mut pi as *mut PROCESS_INFORMATION, ) - .as_bool() - }; + } + .as_bool(); if process { Ok(Self { From 268c4d1a5eab14ff44bd1ee3b0a293545e2f1f9c Mon Sep 17 00:00:00 2001 From: yozhgoor Date: Tue, 9 Nov 2021 14:13:46 +0100 Subject: [PATCH 14/37] Better naming --- src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f939372..42189aa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,7 +29,7 @@ impl ChildProcess { let si = STARTUPINFOW::default(); let mut pi = PROCESS_INFORMATION::default(); - let process = if let Some(directory) = current_directory { + let started_process = if let Some(directory) = current_directory { windows::Win32::System::Threading::CreateProcessW( PWSTR::default(), command, @@ -58,7 +58,7 @@ impl ChildProcess { } .as_bool(); - if process { + if started_process { Ok(Self { command: command.to_string(), process_information: pi, @@ -84,10 +84,10 @@ impl ChildProcess { pub fn kill(&self) -> Result<(), ChildProcessError> { unsafe { - let terminate = TerminateProcess(self.process_information.hProcess, 0).as_bool(); + let killed_process = TerminateProcess(self.process_information.hProcess, 0).as_bool(); close_handle(self.process_information); - if terminate { + if killed_process { Ok(()) } else { Err(format!("cannot kill process: {:?}", GetLastError())) From 03522fe8be741ae635bd8cc755a42845ab5f83d9 Mon Sep 17 00:00:00 2001 From: yozhgoor Date: Tue, 9 Nov 2021 14:38:14 +0100 Subject: [PATCH 15/37] Initialize memory for startup_info --- src/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 42189aa..562ea88 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ #![allow(non_snake_case)] use std::ffi::c_void; +use std::mem::size_of; use windows::Win32::Foundation::{CloseHandle, GetLastError, PWSTR}; use windows::Win32::Security::SECURITY_ATTRIBUTES; use windows::Win32::System::Threading::{ @@ -26,9 +27,11 @@ impl ChildProcess { current_directory: Option<&str>, ) -> Result { unsafe { - let si = STARTUPINFOW::default(); + let mut si = STARTUPINFOW::default(); let mut pi = PROCESS_INFORMATION::default(); + si.cb = size_of::() as u32; + let started_process = if let Some(directory) = current_directory { windows::Win32::System::Threading::CreateProcessW( PWSTR::default(), From c9335590a950c1145d98835b0f117285456b1a4b Mon Sep 17 00:00:00 2001 From: yozhgoor Date: Tue, 9 Nov 2021 14:45:52 +0100 Subject: [PATCH 16/37] Better naming --- src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 562ea88..0547edc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,7 +32,7 @@ impl ChildProcess { si.cb = size_of::() as u32; - let started_process = if let Some(directory) = current_directory { + let res = if let Some(directory) = current_directory { windows::Win32::System::Threading::CreateProcessW( PWSTR::default(), command, @@ -61,7 +61,7 @@ impl ChildProcess { } .as_bool(); - if started_process { + if res { Ok(Self { command: command.to_string(), process_information: pi, @@ -87,10 +87,10 @@ impl ChildProcess { pub fn kill(&self) -> Result<(), ChildProcessError> { unsafe { - let killed_process = TerminateProcess(self.process_information.hProcess, 0).as_bool(); + let res = TerminateProcess(self.process_information.hProcess, 0).as_bool(); close_handle(self.process_information); - if killed_process { + if res { Ok(()) } else { Err(format!("cannot kill process: {:?}", GetLastError())) From dd34f5ce21e0178dbf632eaf73bd9c66fb882439 Mon Sep 17 00:00:00 2001 From: yozhgoor Date: Tue, 9 Nov 2021 14:52:20 +0100 Subject: [PATCH 17/37] After review --- src/lib.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 0547edc..c5deac8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -58,10 +58,9 @@ impl ChildProcess { &si, &mut pi as *mut PROCESS_INFORMATION, ) - } - .as_bool(); + }; - if res { + if res.as_bool() { Ok(Self { command: command.to_string(), process_information: pi, @@ -87,10 +86,10 @@ impl ChildProcess { pub fn kill(&self) -> Result<(), ChildProcessError> { unsafe { - let res = TerminateProcess(self.process_information.hProcess, 0).as_bool(); + let res = TerminateProcess(self.process_information.hProcess, 0); close_handle(self.process_information); - if res { + if res.as_bool() { Ok(()) } else { Err(format!("cannot kill process: {:?}", GetLastError())) From 1c014f4b837b2d6ab54d6dd66b91f9f57c2910b5 Mon Sep 17 00:00:00 2001 From: yozhgoor Date: Tue, 9 Nov 2021 14:56:11 +0100 Subject: [PATCH 18/37] Create a variable for the process_creation_flags --- src/lib.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c5deac8..633c102 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,6 +32,8 @@ impl ChildProcess { si.cb = size_of::() as u32; + let process_creation_flags = PROCESS_CREATION_FLAGS(0); + let res = if let Some(directory) = current_directory { windows::Win32::System::Threading::CreateProcessW( PWSTR::default(), @@ -39,7 +41,7 @@ impl ChildProcess { std::ptr::null() as *const SECURITY_ATTRIBUTES, std::ptr::null() as *const SECURITY_ATTRIBUTES, inherit_handles, - PROCESS_CREATION_FLAGS(0), + process_creation_flags, std::ptr::null() as *const c_void, directory, &si, @@ -52,7 +54,7 @@ impl ChildProcess { std::ptr::null() as *const SECURITY_ATTRIBUTES, std::ptr::null() as *const SECURITY_ATTRIBUTES, inherit_handles, - PROCESS_CREATION_FLAGS(0), + process_creation_flags, std::ptr::null() as *const c_void, PWSTR::default(), &si, From 2663ea74c25a46ce8c28ff3601bb4caae5bac1a0 Mon Sep 17 00:00:00 2001 From: yozhgoor Date: Tue, 9 Nov 2021 15:45:17 +0100 Subject: [PATCH 19/37] Fix error in main workflow --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ad0fabe..81f812d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -16,7 +16,7 @@ jobs: - name: Checkout source uses: actions/checkout@v2 - - uses: Swatinem/rust-cargo@v1 + - uses: Swatinem/rust-cache@v1 - name: cargo test uses: actions-rs/cargo@v1 From d94b5b9242cf4905e76c4aba9b344341ed003cbe Mon Sep 17 00:00:00 2001 From: yozhgoor Date: Tue, 9 Nov 2021 15:57:10 +0100 Subject: [PATCH 20/37] Use thiserror for the Error type of the Result --- Cargo.lock | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 3 +++ src/lib.rs | 19 +++++++++++++++--- 3 files changed, 75 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 60e8adf..95cb5c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6,9 +6,65 @@ version = 3 name = "CreateProcessW" version = "0.1.0" dependencies = [ + "thiserror", "windows", ] +[[package]] +name = "proc-macro2" +version = "1.0.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "thiserror" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + [[package]] name = "windows" version = "0.24.0" diff --git a/Cargo.toml b/Cargo.toml index 44f61d0..bd2368e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,9 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[dependencies] +thiserror = "1.0.30" + [dependencies.windows] version = "0.24.0" features = [ diff --git a/src/lib.rs b/src/lib.rs index 633c102..e9615c4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,7 @@ use std::ffi::c_void; use std::mem::size_of; +use thiserror::Error; use windows::Win32::Foundation::{CloseHandle, GetLastError, PWSTR}; use windows::Win32::Security::SECURITY_ATTRIBUTES; use windows::Win32::System::Threading::{ @@ -16,7 +17,13 @@ pub struct ChildProcess { process_information: PROCESS_INFORMATION, } -pub type ChildProcessError = String; +#[derive(Error, Debug)] +pub enum ChildProcessError { + #[error("cannot create childprocess: {0}")] + CreationFailed(String), + #[error("cannot kill process: {0}")] + KillFailed(String), +} pub struct ExitCode(u32); @@ -68,7 +75,10 @@ impl ChildProcess { process_information: pi, }) } else { - Err(format!("cannot create process: {:?}", GetLastError())) + Err(ChildProcessError::CreationFailed(format!( + "{:?}", + GetLastError() + ))) } } } @@ -94,7 +104,10 @@ impl ChildProcess { if res.as_bool() { Ok(()) } else { - Err(format!("cannot kill process: {:?}", GetLastError())) + Err(ChildProcessError::KillFailed(format!( + "{:?}", + GetLastError() + ))) } } } From b689041cfb3d0f758a9dbc3b3106408943ce36b3 Mon Sep 17 00:00:00 2001 From: yozhgoor Date: Tue, 9 Nov 2021 16:33:19 +0100 Subject: [PATCH 21/37] Use a path instead of a &str for the current_directory argument --- src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index e9615c4..027f3f5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,7 @@ use std::ffi::c_void; use std::mem::size_of; +use std::path::Path; use thiserror::Error; use windows::Win32::Foundation::{CloseHandle, GetLastError, PWSTR}; use windows::Win32::Security::SECURITY_ATTRIBUTES; @@ -31,7 +32,7 @@ impl ChildProcess { pub fn new( command: &str, inherit_handles: bool, - current_directory: Option<&str>, + current_directory: Option>, ) -> Result { unsafe { let mut si = STARTUPINFOW::default(); @@ -42,6 +43,7 @@ impl ChildProcess { let process_creation_flags = PROCESS_CREATION_FLAGS(0); let res = if let Some(directory) = current_directory { + let directory = directory.as_ref().as_os_str(); windows::Win32::System::Threading::CreateProcessW( PWSTR::default(), command, From 050f91ee8a465f01e9ad173c01003ae50d8f57b6 Mon Sep 17 00:00:00 2001 From: yozhgoor Date: Tue, 9 Nov 2021 16:37:03 +0100 Subject: [PATCH 22/37] Remove the close_handle function since it's not duplicate code anymore --- src/lib.rs | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 027f3f5..2df729f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -92,7 +92,8 @@ impl ChildProcess { pub fn wait(&self) -> ExitCode { unsafe { let exit_code = WaitForSingleObject(self.process_information.hProcess, INFINITE); - close_handle(self.process_information); + CloseHandle(self.process_information.hProcess); + CloseHandle(self.process_information.hThread); ExitCode(exit_code) } @@ -100,10 +101,7 @@ impl ChildProcess { pub fn kill(&self) -> Result<(), ChildProcessError> { unsafe { - let res = TerminateProcess(self.process_information.hProcess, 0); - close_handle(self.process_information); - - if res.as_bool() { + if TerminateProcess(self.process_information.hProcess, 0).as_bool() { Ok(()) } else { Err(ChildProcessError::KillFailed(format!( @@ -124,10 +122,3 @@ impl ExitCode { self.0 } } - -fn close_handle(process_information: PROCESS_INFORMATION) { - unsafe { - CloseHandle(process_information.hProcess); - CloseHandle(process_information.hThread); - } -} From e1c520bf37db3063d311ee1353ce98f8198099c0 Mon Sep 17 00:00:00 2001 From: yozhgoor Date: Tue, 9 Nov 2021 16:40:54 +0100 Subject: [PATCH 23/37] Use ExitStatus instead of StatusCode --- src/lib.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 2df729f..1bec03d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,16 +18,6 @@ pub struct ChildProcess { process_information: PROCESS_INFORMATION, } -#[derive(Error, Debug)] -pub enum ChildProcessError { - #[error("cannot create childprocess: {0}")] - CreationFailed(String), - #[error("cannot kill process: {0}")] - KillFailed(String), -} - -pub struct ExitCode(u32); - impl ChildProcess { pub fn new( command: &str, @@ -89,13 +79,13 @@ impl ChildProcess { self.command.clone() } - pub fn wait(&self) -> ExitCode { + pub fn wait(&self) -> ExitStatus { unsafe { let exit_code = WaitForSingleObject(self.process_information.hProcess, INFINITE); CloseHandle(self.process_information.hProcess); CloseHandle(self.process_information.hThread); - ExitCode(exit_code) + ExitStatus(exit_code) } } @@ -113,12 +103,22 @@ impl ChildProcess { } } -impl ExitCode { +#[derive(Error, Debug)] +pub enum ChildProcessError { + #[error("cannot create childprocess: {0}")] + CreationFailed(String), + #[error("cannot kill process: {0}")] + KillFailed(String), +} + +pub struct ExitStatus(u32); + +impl ExitStatus { pub fn success(&self) -> bool { self.0 == 0 } - pub fn display(&self) -> u32 { + pub fn code(&self) -> u32 { self.0 } } From 9c1e1c70f9aba30f396b36e9896fba218c3ae94c Mon Sep 17 00:00:00 2001 From: yozhgoor Date: Tue, 9 Nov 2021 17:31:59 +0100 Subject: [PATCH 24/37] Remove the command function --- src/lib.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 1bec03d..a8af04a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -75,10 +75,6 @@ impl ChildProcess { } } - pub fn command(&self) -> String { - self.command.clone() - } - pub fn wait(&self) -> ExitStatus { unsafe { let exit_code = WaitForSingleObject(self.process_information.hProcess, INFINITE); From 7a8a47089f3cd43ee7673e4e16a2c71cad0b01bc Mon Sep 17 00:00:00 2001 From: yozhgoor Date: Tue, 9 Nov 2021 17:42:14 +0100 Subject: [PATCH 25/37] Attempt to add a `try_wait` function --- src/lib.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index a8af04a..0494978 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -85,6 +85,16 @@ impl ChildProcess { } } + pub fn try_wait(&self, duration: u32) -> Result { + unsafe { + if WaitForSingleObject(self.process_information.hProcess, duration) == 0 { + Ok(ExitStatus(0)) + } else { + Err(ExitStatusError::WaitFailed(0)) + } + } + } + pub fn kill(&self) -> Result<(), ChildProcessError> { unsafe { if TerminateProcess(self.process_information.hProcess, 0).as_bool() { @@ -118,3 +128,13 @@ impl ExitStatus { self.0 } } + +#[derive(Error, Debug)] +pub enum ExitStatusError { + #[error("failed to wait ({0})")] + WaitFailed(u32), + #[error("time-out elapsed ({0})")] + WaitTimeout(u32), + #[error("wait abandoned ({0})")] + WaitAbandoned(u32) +} From 0004d521a8d1fa26cc217984343e3951791260c6 Mon Sep 17 00:00:00 2001 From: yozhgoor Date: Tue, 9 Nov 2021 17:46:18 +0100 Subject: [PATCH 26/37] Use a match instead of if else --- src/lib.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 0494978..0beb5d8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -87,10 +87,9 @@ impl ChildProcess { pub fn try_wait(&self, duration: u32) -> Result { unsafe { - if WaitForSingleObject(self.process_information.hProcess, duration) == 0 { - Ok(ExitStatus(0)) - } else { - Err(ExitStatusError::WaitFailed(0)) + match WaitForSingleObject(self.process_information.hProcess, duration) { + 0 => Ok(ExitStatus(0)), + _ => Err(ExitStatusError::WaitFailed(format!("{:?}", GetLastError()))), } } } @@ -131,10 +130,10 @@ impl ExitStatus { #[derive(Error, Debug)] pub enum ExitStatusError { - #[error("failed to wait ({0})")] - WaitFailed(u32), #[error("time-out elapsed ({0})")] WaitTimeout(u32), #[error("wait abandoned ({0})")] - WaitAbandoned(u32) + WaitAbandoned(u32), + #[error("failed to wait: {0}")] + WaitFailed(String), } From bd139ab1adb35965fc332a5116dd27bda51cb4e1 Mon Sep 17 00:00:00 2001 From: yozhgoor Date: Wed, 10 Nov 2021 03:57:33 +0100 Subject: [PATCH 27/37] Use GetExitCodeProcess in try_wait --- src/lib.rs | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 0beb5d8..f6f9277 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,8 +7,8 @@ use thiserror::Error; use windows::Win32::Foundation::{CloseHandle, GetLastError, PWSTR}; use windows::Win32::Security::SECURITY_ATTRIBUTES; use windows::Win32::System::Threading::{ - TerminateProcess, WaitForSingleObject, PROCESS_CREATION_FLAGS, PROCESS_INFORMATION, - STARTUPINFOW, + GetExitCodeProcess, TerminateProcess, WaitForSingleObject, PROCESS_CREATION_FLAGS, + PROCESS_INFORMATION, STARTUPINFOW, }; use windows::Win32::System::WindowsProgramming::INFINITE; @@ -22,7 +22,7 @@ impl ChildProcess { pub fn new( command: &str, inherit_handles: bool, - current_directory: Option>, + current_directory: Option<&Path>, ) -> Result { unsafe { let mut si = STARTUPINFOW::default(); @@ -33,7 +33,7 @@ impl ChildProcess { let process_creation_flags = PROCESS_CREATION_FLAGS(0); let res = if let Some(directory) = current_directory { - let directory = directory.as_ref().as_os_str(); + let directory = directory.as_os_str(); windows::Win32::System::Threading::CreateProcessW( PWSTR::default(), command, @@ -85,11 +85,21 @@ impl ChildProcess { } } - pub fn try_wait(&self, duration: u32) -> Result { + pub fn try_wait(&self) -> Result, ExitStatusError> { + let mut exit_code: u32 = 0; unsafe { - match WaitForSingleObject(self.process_information.hProcess, duration) { - 0 => Ok(ExitStatus(0)), - _ => Err(ExitStatusError::WaitFailed(format!("{:?}", GetLastError()))), + if GetExitCodeProcess( + self.process_information.hProcess, + &mut exit_code as *mut u32, + ) + .as_bool() + { + match exit_code { + 259 => Ok(None), + _ => Ok(Some(ExitStatus(exit_code))), + } + } else { + Err(ExitStatusError::WaitFailed(format!("{:?}", GetLastError()))) } } } @@ -130,10 +140,6 @@ impl ExitStatus { #[derive(Error, Debug)] pub enum ExitStatusError { - #[error("time-out elapsed ({0})")] - WaitTimeout(u32), - #[error("wait abandoned ({0})")] - WaitAbandoned(u32), - #[error("failed to wait: {0}")] + #[error("cannot wait: {0}")] WaitFailed(String), } From 6a36a7a069a5d69896575462cda217c030dbd052 Mon Sep 17 00:00:00 2001 From: yozhgoor Date: Wed, 10 Nov 2021 14:20:00 +0100 Subject: [PATCH 28/37] Modify the wait function to return an exit code --- src/lib.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index f6f9277..2d4ca0b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -77,7 +77,13 @@ impl ChildProcess { pub fn wait(&self) -> ExitStatus { unsafe { - let exit_code = WaitForSingleObject(self.process_information.hProcess, INFINITE); + let mut exit_code: u32 = 0; + + WaitForSingleObject(self.process_information.hProcess, INFINITE); + GetExitCodeProcess( + self.process_information.hProcess, + &mut exit_code as *mut u32, + ); CloseHandle(self.process_information.hProcess); CloseHandle(self.process_information.hThread); From 3da034bb54bf4da9be4d76012f5b975223a2e0df Mon Sep 17 00:00:00 2001 From: yozhgoor Date: Wed, 10 Nov 2021 14:42:38 +0100 Subject: [PATCH 29/37] Clean up --- src/lib.rs | 58 +++++++++++++++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 2d4ca0b..1c61fdc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -67,66 +67,62 @@ impl ChildProcess { process_information: pi, }) } else { - Err(ChildProcessError::CreationFailed(format!( - "{:?}", - GetLastError() - ))) + Err(ChildProcessError::CreationFailed(get_last_error())) } } } pub fn wait(&self) -> ExitStatus { - unsafe { - let mut exit_code: u32 = 0; + let mut exit_code: u32 = 0; + unsafe { WaitForSingleObject(self.process_information.hProcess, INFINITE); GetExitCodeProcess( self.process_information.hProcess, &mut exit_code as *mut u32, ); + CloseHandle(self.process_information.hProcess); CloseHandle(self.process_information.hThread); - - ExitStatus(exit_code) } + + ExitStatus(exit_code) } pub fn try_wait(&self) -> Result, ExitStatusError> { let mut exit_code: u32 = 0; - unsafe { - if GetExitCodeProcess( + + let res = unsafe { + GetExitCodeProcess( self.process_information.hProcess, &mut exit_code as *mut u32, ) - .as_bool() - { - match exit_code { - 259 => Ok(None), - _ => Ok(Some(ExitStatus(exit_code))), - } - } else { - Err(ExitStatusError::WaitFailed(format!("{:?}", GetLastError()))) + }; + + if res.as_bool() { + match exit_code { + 259 => Ok(None), + _ => Ok(Some(ExitStatus(exit_code))), } + } else { + Err(ExitStatusError::WaitFailed(get_last_error())) } } pub fn kill(&self) -> Result<(), ChildProcessError> { - unsafe { - if TerminateProcess(self.process_information.hProcess, 0).as_bool() { - Ok(()) - } else { - Err(ChildProcessError::KillFailed(format!( - "{:?}", - GetLastError() - ))) - } + let res = unsafe { TerminateProcess(self.process_information.hProcess, 0) }; + + if res.as_bool() { + Ok(()) + } else { + Err(ChildProcessError::KillFailed(get_last_error())) } } } #[derive(Error, Debug)] pub enum ChildProcessError { - #[error("cannot create childprocess: {0}")] + #[error("cannot create process: {0}")] CreationFailed(String), #[error("cannot kill process: {0}")] KillFailed(String), @@ -146,6 +142,10 @@ impl ExitStatus { #[derive(Error, Debug)] pub enum ExitStatusError { - #[error("cannot wait: {0}")] + #[error("cannot wait process: {0}")] WaitFailed(String), } + +fn get_last_error() -> String { + unsafe { format!("{:?}", GetLastError()) } +} From f30270b7a1b551f50b85b039555e558429df1033 Mon Sep 17 00:00:00 2001 From: yozhgoor Date: Wed, 10 Nov 2021 14:57:53 +0100 Subject: [PATCH 30/37] Better error handling --- src/lib.rs | 46 +++++++++++++++++++--------------------------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 1c61fdc..28c7ff7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,7 +4,7 @@ use std::ffi::c_void; use std::mem::size_of; use std::path::Path; use thiserror::Error; -use windows::Win32::Foundation::{CloseHandle, GetLastError, PWSTR}; +use windows::Win32::Foundation::{CloseHandle, PWSTR}; use windows::Win32::Security::SECURITY_ATTRIBUTES; use windows::Win32::System::Threading::{ GetExitCodeProcess, TerminateProcess, WaitForSingleObject, PROCESS_CREATION_FLAGS, @@ -12,9 +12,20 @@ use windows::Win32::System::Threading::{ }; use windows::Win32::System::WindowsProgramming::INFINITE; +#[derive(Error, Debug)] +pub enum Error { + #[error("cannot create process")] + CreationFailed, + #[error("cannot wait process")] + WaitFailed, + #[error("cannot kill process")] + KillFailed, +} + +type Result = std::result::Result; + #[derive(Debug)] pub struct ChildProcess { - command: String, process_information: PROCESS_INFORMATION, } @@ -23,7 +34,7 @@ impl ChildProcess { command: &str, inherit_handles: bool, current_directory: Option<&Path>, - ) -> Result { + ) -> Result { unsafe { let mut si = STARTUPINFOW::default(); let mut pi = PROCESS_INFORMATION::default(); @@ -63,11 +74,10 @@ impl ChildProcess { if res.as_bool() { Ok(Self { - command: command.to_string(), process_information: pi, }) } else { - Err(ChildProcessError::CreationFailed(get_last_error())) + Err(Error::CreationFailed) } } } @@ -89,7 +99,7 @@ impl ChildProcess { ExitStatus(exit_code) } - pub fn try_wait(&self) -> Result, ExitStatusError> { + pub fn try_wait(&self) -> Result> { let mut exit_code: u32 = 0; let res = unsafe { @@ -105,29 +115,21 @@ impl ChildProcess { _ => Ok(Some(ExitStatus(exit_code))), } } else { - Err(ExitStatusError::WaitFailed(get_last_error())) + Err(Error::WaitFailed) } } - pub fn kill(&self) -> Result<(), ChildProcessError> { + pub fn kill(&self) -> Result<()> { let res = unsafe { TerminateProcess(self.process_information.hProcess, 0) }; if res.as_bool() { Ok(()) } else { - Err(ChildProcessError::KillFailed(get_last_error())) + Err(Error::KillFailed) } } } -#[derive(Error, Debug)] -pub enum ChildProcessError { - #[error("cannot create process: {0}")] - CreationFailed(String), - #[error("cannot kill process: {0}")] - KillFailed(String), -} - pub struct ExitStatus(u32); impl ExitStatus { @@ -139,13 +141,3 @@ impl ExitStatus { self.0 } } - -#[derive(Error, Debug)] -pub enum ExitStatusError { - #[error("cannot wait process: {0}")] - WaitFailed(String), -} - -fn get_last_error() -> String { - unsafe { format!("{:?}", GetLastError()) } -} From 9f8c1cc7ac9740d1146c892d333097e5177dd53a Mon Sep 17 00:00:00 2001 From: yozhgoor Date: Wed, 10 Nov 2021 15:04:55 +0100 Subject: [PATCH 31/37] Get the error code instead of formatting it into a string --- src/lib.rs | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 28c7ff7..e122894 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,7 +4,7 @@ use std::ffi::c_void; use std::mem::size_of; use std::path::Path; use thiserror::Error; -use windows::Win32::Foundation::{CloseHandle, PWSTR}; +use windows::Win32::Foundation::{CloseHandle, PWSTR, GetLastError}; use windows::Win32::Security::SECURITY_ATTRIBUTES; use windows::Win32::System::Threading::{ GetExitCodeProcess, TerminateProcess, WaitForSingleObject, PROCESS_CREATION_FLAGS, @@ -14,12 +14,12 @@ use windows::Win32::System::WindowsProgramming::INFINITE; #[derive(Error, Debug)] pub enum Error { - #[error("cannot create process")] - CreationFailed, - #[error("cannot wait process")] - WaitFailed, - #[error("cannot kill process")] - KillFailed, + #[error("cannot create process: {0}")] + CreationFailed(u32), + #[error("cannot wait process: {0}")] + WaitFailed(u32), + #[error("cannot kill process: {0}")] + KillFailed(u32), } type Result = std::result::Result; @@ -77,7 +77,7 @@ impl ChildProcess { process_information: pi, }) } else { - Err(Error::CreationFailed) + Err(Error::CreationFailed(get_last_error())) } } } @@ -115,7 +115,7 @@ impl ChildProcess { _ => Ok(Some(ExitStatus(exit_code))), } } else { - Err(Error::WaitFailed) + Err(Error::WaitFailed(get_last_error())) } } @@ -125,7 +125,7 @@ impl ChildProcess { if res.as_bool() { Ok(()) } else { - Err(Error::KillFailed) + Err(Error::KillFailed(get_last_error())) } } } @@ -141,3 +141,9 @@ impl ExitStatus { self.0 } } + +fn get_last_error() -> u32 { + unsafe { + GetLastError().0 + } +} \ No newline at end of file From 4b48d31e086db554d4389044ffe8ca7bef9b2013 Mon Sep 17 00:00:00 2001 From: yozhgoor Date: Wed, 10 Nov 2021 15:09:46 +0100 Subject: [PATCH 32/37] fmt --- src/lib.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e122894..324b05a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,7 +4,7 @@ use std::ffi::c_void; use std::mem::size_of; use std::path::Path; use thiserror::Error; -use windows::Win32::Foundation::{CloseHandle, PWSTR, GetLastError}; +use windows::Win32::Foundation::{CloseHandle, GetLastError, PWSTR}; use windows::Win32::Security::SECURITY_ATTRIBUTES; use windows::Win32::System::Threading::{ GetExitCodeProcess, TerminateProcess, WaitForSingleObject, PROCESS_CREATION_FLAGS, @@ -143,7 +143,5 @@ impl ExitStatus { } fn get_last_error() -> u32 { - unsafe { - GetLastError().0 - } -} \ No newline at end of file + unsafe { GetLastError().0 } +} From afbfef47d8745df8eee7520091806957d27470a9 Mon Sep 17 00:00:00 2001 From: yozhgoor Date: Thu, 11 Nov 2021 02:59:31 +0100 Subject: [PATCH 33/37] Add a Command struct to create process --- src/lib.rs | 59 +++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 52 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 324b05a..59e3e84 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,8 @@ #![allow(non_snake_case)] -use std::ffi::c_void; +use std::ffi::{c_void, OsStr, OsString}; use std::mem::size_of; -use std::path::Path; +use std::path::{Path, PathBuf}; use thiserror::Error; use windows::Win32::Foundation::{CloseHandle, GetLastError, PWSTR}; use windows::Win32::Security::SECURITY_ATTRIBUTES; @@ -25,15 +25,60 @@ pub enum Error { type Result = std::result::Result; #[derive(Debug)] -pub struct ChildProcess { +pub struct Command { + command: OsString, + inherit_handles: Option, + current_directory: Option, +} + +impl Command { + pub fn new(command: impl AsRef) -> Command { + Command { + command: command.as_ref().to_owned(), + inherit_handles: None, + current_directory: None, + } + } + + pub fn inherit(mut self, bool: bool) -> Command { + self.inherit_handles = Some(bool); + self + } + + pub fn current_dir(mut self, dir: impl AsRef) -> Command { + self.current_directory = Some(dir.as_ref().to_owned()); + self + } + + pub fn spawn(&mut self) -> Result { + match Child::new( + &self.command, + self.inherit_handles.unwrap_or(false), + self.current_directory.as_ref(), + ) { + Ok(child) => Ok(child), + Err(err) => Err(err), + } + } + + pub fn status(&mut self) -> Result { + match self.spawn() { + Ok(child) => Ok(child.wait()), + Err(err) => Err(err), + } + } +} + +#[derive(Debug)] +pub struct Child { process_information: PROCESS_INFORMATION, } -impl ChildProcess { - pub fn new( - command: &str, +impl Child { + fn new( + command: &OsStr, inherit_handles: bool, - current_directory: Option<&Path>, + current_directory: Option<&PathBuf>, ) -> Result { unsafe { let mut si = STARTUPINFOW::default(); From a24a798aba6a1d438e893106f14265601f79ab01 Mon Sep 17 00:00:00 2001 From: yozhgoor Date: Thu, 11 Nov 2021 15:15:45 +0100 Subject: [PATCH 34/37] After review --- src/lib.rs | 94 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 55 insertions(+), 39 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 59e3e84..57fcb4f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,11 +4,11 @@ use std::ffi::{c_void, OsStr, OsString}; use std::mem::size_of; use std::path::{Path, PathBuf}; use thiserror::Error; -use windows::Win32::Foundation::{CloseHandle, GetLastError, PWSTR}; +use windows::Win32::Foundation::{CloseHandle, GetLastError, PWSTR, STATUS_PENDING}; use windows::Win32::Security::SECURITY_ATTRIBUTES; use windows::Win32::System::Threading::{ GetExitCodeProcess, TerminateProcess, WaitForSingleObject, PROCESS_CREATION_FLAGS, - PROCESS_INFORMATION, STARTUPINFOW, + PROCESS_INFORMATION, STARTUPINFOW, WAIT_OBJECT_0, }; use windows::Win32::System::WindowsProgramming::INFINITE; @@ -16,8 +16,8 @@ use windows::Win32::System::WindowsProgramming::INFINITE; pub enum Error { #[error("cannot create process: {0}")] CreationFailed(u32), - #[error("cannot wait process: {0}")] - WaitFailed(u32), + #[error("cannot get exit status: {0}")] + GetExitCodeFailed(u32), #[error("cannot kill process: {0}")] KillFailed(u32), } @@ -27,34 +27,34 @@ type Result = std::result::Result; #[derive(Debug)] pub struct Command { command: OsString, - inherit_handles: Option, + inherit_handles: bool, current_directory: Option, } impl Command { - pub fn new(command: impl AsRef) -> Command { - Command { - command: command.as_ref().to_owned(), - inherit_handles: None, + pub fn new(command: impl Into) -> Self { + Self { + command: command.into(), + inherit_handles: true, current_directory: None, } } - pub fn inherit(mut self, bool: bool) -> Command { - self.inherit_handles = Some(bool); + pub fn inherit(&mut self, inherit: bool) -> &mut Self { + self.inherit_handles = inherit; self } - pub fn current_dir(mut self, dir: impl AsRef) -> Command { - self.current_directory = Some(dir.as_ref().to_owned()); + pub fn current_dir(&mut self, dir: impl Into) -> &mut Self { + self.current_directory = Some(dir.into()); self } pub fn spawn(&mut self) -> Result { match Child::new( &self.command, - self.inherit_handles.unwrap_or(false), - self.current_directory.as_ref(), + self.inherit_handles, + self.current_directory.as_deref(), ) { Ok(child) => Ok(child), Err(err) => Err(err), @@ -63,7 +63,7 @@ impl Command { pub fn status(&mut self) -> Result { match self.spawn() { - Ok(child) => Ok(child.wait()), + Ok(child) => child.wait(), Err(err) => Err(err), } } @@ -78,13 +78,13 @@ impl Child { fn new( command: &OsStr, inherit_handles: bool, - current_directory: Option<&PathBuf>, + current_directory: Option<&Path>, ) -> Result { unsafe { - let mut si = STARTUPINFOW::default(); - let mut pi = PROCESS_INFORMATION::default(); + let mut startup_info = STARTUPINFOW::default(); + let mut process_info = PROCESS_INFORMATION::default(); - si.cb = size_of::() as u32; + startup_info.cb = size_of::() as u32; let process_creation_flags = PROCESS_CREATION_FLAGS(0); @@ -99,8 +99,8 @@ impl Child { process_creation_flags, std::ptr::null() as *const c_void, directory, - &si, - &mut pi as *mut PROCESS_INFORMATION, + &startup_info, + &mut process_info as *mut PROCESS_INFORMATION, ) } else { windows::Win32::System::Threading::CreateProcessW( @@ -112,14 +112,14 @@ impl Child { process_creation_flags, std::ptr::null() as *const c_void, PWSTR::default(), - &si, - &mut pi as *mut PROCESS_INFORMATION, + &startup_info, + &mut process_info as *mut PROCESS_INFORMATION, ) }; if res.as_bool() { Ok(Self { - process_information: pi, + process_information: process_info, }) } else { Err(Error::CreationFailed(get_last_error())) @@ -127,21 +127,28 @@ impl Child { } } - pub fn wait(&self) -> ExitStatus { + pub fn wait(&self) -> Result { let mut exit_code: u32 = 0; unsafe { - WaitForSingleObject(self.process_information.hProcess, INFINITE); - GetExitCodeProcess( - self.process_information.hProcess, - &mut exit_code as *mut u32, - ); + let res = WaitForSingleObject(self.process_information.hProcess, INFINITE); - CloseHandle(self.process_information.hProcess); - CloseHandle(self.process_information.hThread); + if res == WAIT_OBJECT_0 { + if GetExitCodeProcess( + self.process_information.hProcess, + &mut exit_code as *mut u32, + ) + .as_bool() + { + close_handle(self.process_information); + Ok(ExitStatus(exit_code)) + } else { + Err(Error::GetExitCodeFailed(get_last_error())) + } + } else { + Err(Error::GetExitCodeFailed(get_last_error())) + } } - - ExitStatus(exit_code) } pub fn try_wait(&self) -> Result> { @@ -155,12 +162,14 @@ impl Child { }; if res.as_bool() { - match exit_code { - 259 => Ok(None), - _ => Ok(Some(ExitStatus(exit_code))), + if exit_code == STATUS_PENDING.0 { + Ok(None) + } else { + close_handle(self.process_information); + Ok(Some(ExitStatus(exit_code))) } } else { - Err(Error::WaitFailed(get_last_error())) + Err(Error::GetExitCodeFailed(get_last_error())) } } @@ -190,3 +199,10 @@ impl ExitStatus { fn get_last_error() -> u32 { unsafe { GetLastError().0 } } + +fn close_handle(process_info: PROCESS_INFORMATION) { + unsafe { + CloseHandle(process_info.hProcess); + CloseHandle(process_info.hThread); + } +} From 574435f75f914f4a9f48a573237c19425ce1e226 Mon Sep 17 00:00:00 2001 From: yozhgoor Date: Thu, 11 Nov 2021 20:09:58 +0100 Subject: [PATCH 35/37] Oops --- src/lib.rs | 117 +++++++++++++++++++++++++---------------------------- 1 file changed, 55 insertions(+), 62 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 57fcb4f..186faa4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -51,13 +51,12 @@ impl Command { } pub fn spawn(&mut self) -> Result { - match Child::new( - &self.command, - self.inherit_handles, - self.current_directory.as_deref(), - ) { - Ok(child) => Ok(child), - Err(err) => Err(err), + unsafe { + Child::new( + &self.command, + self.inherit_handles, + self.current_directory.as_deref(), + ) } } @@ -75,55 +74,53 @@ pub struct Child { } impl Child { - fn new( + unsafe fn new( command: &OsStr, inherit_handles: bool, current_directory: Option<&Path>, ) -> Result { - unsafe { - let mut startup_info = STARTUPINFOW::default(); - let mut process_info = PROCESS_INFORMATION::default(); - - startup_info.cb = size_of::() as u32; - - let process_creation_flags = PROCESS_CREATION_FLAGS(0); - - let res = if let Some(directory) = current_directory { - let directory = directory.as_os_str(); - windows::Win32::System::Threading::CreateProcessW( - PWSTR::default(), - command, - std::ptr::null() as *const SECURITY_ATTRIBUTES, - std::ptr::null() as *const SECURITY_ATTRIBUTES, - inherit_handles, - process_creation_flags, - std::ptr::null() as *const c_void, - directory, - &startup_info, - &mut process_info as *mut PROCESS_INFORMATION, - ) - } else { - windows::Win32::System::Threading::CreateProcessW( - PWSTR::default(), - command, - std::ptr::null() as *const SECURITY_ATTRIBUTES, - std::ptr::null() as *const SECURITY_ATTRIBUTES, - inherit_handles, - process_creation_flags, - std::ptr::null() as *const c_void, - PWSTR::default(), - &startup_info, - &mut process_info as *mut PROCESS_INFORMATION, - ) - }; + let mut startup_info = STARTUPINFOW::default(); + let mut process_info = PROCESS_INFORMATION::default(); + + startup_info.cb = size_of::() as u32; + + let process_creation_flags = PROCESS_CREATION_FLAGS(0); + + let res = if let Some(directory) = current_directory { + let directory = directory.as_os_str(); + windows::Win32::System::Threading::CreateProcessW( + PWSTR::default(), + command, + std::ptr::null() as *const SECURITY_ATTRIBUTES, + std::ptr::null() as *const SECURITY_ATTRIBUTES, + inherit_handles, + process_creation_flags, + std::ptr::null() as *const c_void, + directory, + &startup_info, + &mut process_info as *mut PROCESS_INFORMATION, + ) + } else { + windows::Win32::System::Threading::CreateProcessW( + PWSTR::default(), + command, + std::ptr::null() as *const SECURITY_ATTRIBUTES, + std::ptr::null() as *const SECURITY_ATTRIBUTES, + inherit_handles, + process_creation_flags, + std::ptr::null() as *const c_void, + PWSTR::default(), + &startup_info, + &mut process_info as *mut PROCESS_INFORMATION, + ) + }; - if res.as_bool() { - Ok(Self { - process_information: process_info, - }) - } else { - Err(Error::CreationFailed(get_last_error())) - } + if res.as_bool() { + Ok(Self { + process_information: process_info, + }) + } else { + Err(Error::CreationFailed(GetLastError().0)) } } @@ -140,13 +137,13 @@ impl Child { ) .as_bool() { - close_handle(self.process_information); + close_handle(&self.process_information); Ok(ExitStatus(exit_code)) } else { - Err(Error::GetExitCodeFailed(get_last_error())) + Err(Error::GetExitCodeFailed(GetLastError().0)) } } else { - Err(Error::GetExitCodeFailed(get_last_error())) + Err(Error::GetExitCodeFailed(GetLastError().0)) } } } @@ -165,11 +162,11 @@ impl Child { if exit_code == STATUS_PENDING.0 { Ok(None) } else { - close_handle(self.process_information); + close_handle(&self.process_information); Ok(Some(ExitStatus(exit_code))) } } else { - Err(Error::GetExitCodeFailed(get_last_error())) + Err(Error::GetExitCodeFailed(unsafe { GetLastError().0 })) } } @@ -179,7 +176,7 @@ impl Child { if res.as_bool() { Ok(()) } else { - Err(Error::KillFailed(get_last_error())) + Err(Error::KillFailed(unsafe { GetLastError().0 })) } } } @@ -196,11 +193,7 @@ impl ExitStatus { } } -fn get_last_error() -> u32 { - unsafe { GetLastError().0 } -} - -fn close_handle(process_info: PROCESS_INFORMATION) { +fn close_handle(process_info: &PROCESS_INFORMATION) { unsafe { CloseHandle(process_info.hProcess); CloseHandle(process_info.hThread); From 048337dd1a4a09c74829343a90aeef079dc40aab Mon Sep 17 00:00:00 2001 From: yozhgoor Date: Fri, 12 Nov 2021 11:50:10 +0100 Subject: [PATCH 36/37] Add comment about the allowed lint `non_snake_case` --- src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 186faa4..6603269 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ +// Disable warning for the crate name, not a really good way to do this but.. +// (https://github.com/rust-lang/rust/issues/45127) #![allow(non_snake_case)] use std::ffi::{c_void, OsStr, OsString}; From 5eca5fdb72f9b56b3e6ada9b67c7e005d155c840 Mon Sep 17 00:00:00 2001 From: yozhgoor Date: Fri, 12 Nov 2021 16:20:08 +0100 Subject: [PATCH 37/37] After review --- src/lib.rs | 128 ++++++++++++++++++++++++++--------------------------- 1 file changed, 62 insertions(+), 66 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 6603269..b1fa0d0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,7 +42,7 @@ impl Command { } } - pub fn inherit(&mut self, inherit: bool) -> &mut Self { + pub fn inherit_handles(&mut self, inherit: bool) -> &mut Self { self.inherit_handles = inherit; self } @@ -53,20 +53,15 @@ impl Command { } pub fn spawn(&mut self) -> Result { - unsafe { - Child::new( - &self.command, - self.inherit_handles, - self.current_directory.as_deref(), - ) - } + Child::new( + &self.command, + self.inherit_handles, + self.current_directory.as_deref(), + ) } pub fn status(&mut self) -> Result { - match self.spawn() { - Ok(child) => child.wait(), - Err(err) => Err(err), - } + self.spawn()?.wait() } } @@ -76,7 +71,7 @@ pub struct Child { } impl Child { - unsafe fn new( + fn new( command: &OsStr, inherit_handles: bool, current_directory: Option<&Path>, @@ -88,33 +83,35 @@ impl Child { let process_creation_flags = PROCESS_CREATION_FLAGS(0); - let res = if let Some(directory) = current_directory { - let directory = directory.as_os_str(); - windows::Win32::System::Threading::CreateProcessW( - PWSTR::default(), - command, - std::ptr::null() as *const SECURITY_ATTRIBUTES, - std::ptr::null() as *const SECURITY_ATTRIBUTES, - inherit_handles, - process_creation_flags, - std::ptr::null() as *const c_void, - directory, - &startup_info, - &mut process_info as *mut PROCESS_INFORMATION, - ) - } else { - windows::Win32::System::Threading::CreateProcessW( - PWSTR::default(), - command, - std::ptr::null() as *const SECURITY_ATTRIBUTES, - std::ptr::null() as *const SECURITY_ATTRIBUTES, - inherit_handles, - process_creation_flags, - std::ptr::null() as *const c_void, - PWSTR::default(), - &startup_info, - &mut process_info as *mut PROCESS_INFORMATION, - ) + let res = unsafe { + if let Some(directory) = current_directory { + let directory = directory.as_os_str(); + windows::Win32::System::Threading::CreateProcessW( + PWSTR::default(), + command, + std::ptr::null() as *const SECURITY_ATTRIBUTES, + std::ptr::null() as *const SECURITY_ATTRIBUTES, + inherit_handles, + process_creation_flags, + std::ptr::null() as *const c_void, + directory, + &startup_info, + &mut process_info as *mut PROCESS_INFORMATION, + ) + } else { + windows::Win32::System::Threading::CreateProcessW( + PWSTR::default(), + command, + std::ptr::null() as *const SECURITY_ATTRIBUTES, + std::ptr::null() as *const SECURITY_ATTRIBUTES, + inherit_handles, + process_creation_flags, + std::ptr::null() as *const c_void, + PWSTR::default(), + &startup_info, + &mut process_info as *mut PROCESS_INFORMATION, + ) + } }; if res.as_bool() { @@ -122,14 +119,13 @@ impl Child { process_information: process_info, }) } else { - Err(Error::CreationFailed(GetLastError().0)) + Err(Error::CreationFailed(unsafe { GetLastError().0 })) } } pub fn wait(&self) -> Result { - let mut exit_code: u32 = 0; - unsafe { + let mut exit_code: u32 = 0; let res = WaitForSingleObject(self.process_information.hProcess, INFINITE); if res == WAIT_OBJECT_0 { @@ -139,7 +135,7 @@ impl Child { ) .as_bool() { - close_handle(&self.process_information); + close_handles(&self.process_information); Ok(ExitStatus(exit_code)) } else { Err(Error::GetExitCodeFailed(GetLastError().0)) @@ -151,34 +147,36 @@ impl Child { } pub fn try_wait(&self) -> Result> { - let mut exit_code: u32 = 0; + unsafe { + let mut exit_code: u32 = 0; - let res = unsafe { - GetExitCodeProcess( + let res = GetExitCodeProcess( self.process_information.hProcess, &mut exit_code as *mut u32, - ) - }; + ); - if res.as_bool() { - if exit_code == STATUS_PENDING.0 { - Ok(None) + if res.as_bool() { + if exit_code == STATUS_PENDING.0 { + Ok(None) + } else { + close_handles(&self.process_information); + Ok(Some(ExitStatus(exit_code))) + } } else { - close_handle(&self.process_information); - Ok(Some(ExitStatus(exit_code))) + Err(Error::GetExitCodeFailed(GetLastError().0)) } - } else { - Err(Error::GetExitCodeFailed(unsafe { GetLastError().0 })) } } pub fn kill(&self) -> Result<()> { - let res = unsafe { TerminateProcess(self.process_information.hProcess, 0) }; + unsafe { + let res = TerminateProcess(self.process_information.hProcess, 0); - if res.as_bool() { - Ok(()) - } else { - Err(Error::KillFailed(unsafe { GetLastError().0 })) + if res.as_bool() { + Ok(()) + } else { + Err(Error::KillFailed(GetLastError().0)) + } } } } @@ -195,9 +193,7 @@ impl ExitStatus { } } -fn close_handle(process_info: &PROCESS_INFORMATION) { - unsafe { - CloseHandle(process_info.hProcess); - CloseHandle(process_info.hThread); - } +unsafe fn close_handles(process_info: &PROCESS_INFORMATION) { + CloseHandle(process_info.hProcess); + CloseHandle(process_info.hThread); }