Ok(_) => panic!(),
}
}
+
+ /// Test that process creation flags work by debugging a process.
+ /// Other creation flags make it hard or impossible to detect
+ /// behavioral changes in the process.
+ #[test]
+ #[cfg(windows)]
+ fn test_creation_flags() {
+ use os::windows::process::CommandExt;
+ use sys::c::{BOOL, DWORD, INFINITE};
+ #[repr(C, packed)]
+ struct DEBUG_EVENT {
+ pub event_code: DWORD,
+ pub process_id: DWORD,
+ pub thread_id: DWORD,
+ // This is a union in the real struct, but we don't
+ // need this data for the purposes of this test.
+ pub _junk: [u8; 164],
+ }
+
+ extern "system" {
+ fn WaitForDebugEvent(lpDebugEvent: *mut DEBUG_EVENT, dwMilliseconds: DWORD) -> BOOL;
+ fn ContinueDebugEvent(dwProcessId: DWORD, dwThreadId: DWORD, dwContinueStatus: DWORD) -> BOOL;
+ }
+
+ const DEBUG_PROCESS: DWORD = 1;
+ const EXIT_PROCESS_DEBUG_EVENT: DWORD = 5;
+ const DBG_EXCEPTION_NOT_HANDLED: DWORD = 0x80010001;
+
+ let mut child = Command::new("cmd")
+ .add_creation_flags(DEBUG_PROCESS)
+ .stdin(Stdio::piped()).spawn().unwrap();
+ child.stdin.take().unwrap().write_all(b"exit\r\n").unwrap();
+ let mut events = 0;
+ let mut event = DEBUG_EVENT {
+ event_code: 0,
+ process_id: 0,
+ thread_id: 0,
+ _junk: [0; 164],
+ };
+ loop {
+ if unsafe { WaitForDebugEvent(&mut event as *mut DEBUG_EVENT, INFINITE) } == 0 {
+ panic!("WaitForDebugEvent failed!");
+ }
+ events += 1;
+
+ if event.event_code == EXIT_PROCESS_DEBUG_EVENT {
+ break;
+ }
+
+ if unsafe { ContinueDebugEvent(event.process_id,
+ event.thread_id,
+ DBG_EXCEPTION_NOT_HANDLED) } == 0 {
+ panic!("ContinueDebugEvent failed!");
+ }
+ }
+ assert!(events > 0);
+ }
}
use os::windows::io::{FromRawHandle, RawHandle, AsRawHandle, IntoRawHandle};
use process;
use sys;
-use sys_common::{AsInner, FromInner, IntoInner};
+use sys_common::{AsInnerMut, AsInner, FromInner, IntoInner};
#[stable(feature = "process_extensions", since = "1.2.0")]
impl FromRawHandle for process::Stdio {
process::ExitStatus::from_inner(From::from(raw))
}
}
+
+/// Windows-specific extensions to the `std::process::Command` builder
+#[unstable(feature = "windows_process_extensions", issue = "37827")]
+pub trait CommandExt {
+ /// Sets the [process creation flags][1] to be passed to `CreateProcess`.
+ ///
+ /// These will always be ORed with `CREATE_UNICODE_ENVIRONMENT`.
+ /// [1]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx
+ #[unstable(feature = "windows_process_extensions", issue = "37827")]
+ fn set_creation_flags(&mut self, flags: u32) -> &mut process::Command;
+ /// Add `flags` to the the [process creation flags][1] to be passed to `CreateProcess`.
+ ///
+ /// These will always be ORed with `CREATE_UNICODE_ENVIRONMENT`.
+ /// [1]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx
+ #[unstable(feature = "windows_process_extensions", issue = "37827")]
+ fn add_creation_flags(&mut self, flags: u32) -> &mut process::Command;
+}
+
+#[unstable(feature = "windows_process_extensions", issue = "37827")]
+impl CommandExt for process::Command {
+ fn set_creation_flags(&mut self, flags: u32) -> &mut process::Command {
+ self.as_inner_mut().set_creation_flags(flags);
+ self
+ }
+ fn add_creation_flags(&mut self, flags: u32) -> &mut process::Command {
+ self.as_inner_mut().add_creation_flags(flags);
+ self
+ }
+}
args: Vec<OsString>,
env: Option<HashMap<OsString, OsString>>,
cwd: Option<OsString>,
+ flags: u32,
detach: bool, // not currently exposed in std::process
stdin: Option<Stdio>,
stdout: Option<Stdio>,
args: Vec::new(),
env: None,
cwd: None,
+ flags: 0,
detach: false,
stdin: None,
stdout: None,
pub fn stderr(&mut self, stderr: Stdio) {
self.stderr = Some(stderr);
}
+ pub fn set_creation_flags(&mut self, flags: u32) {
+ self.flags = flags;
+ }
+ pub fn add_creation_flags(&mut self, flags: u32) {
+ self.flags = self.flags | flags;
+ }
pub fn spawn(&mut self, default: Stdio, needs_stdin: bool)
-> io::Result<(Process, StdioPipes)> {
cmd_str.push(0); // add null terminator
// stolen from the libuv code.
- let mut flags = c::CREATE_UNICODE_ENVIRONMENT;
+ let mut flags = self.flags | c::CREATE_UNICODE_ENVIRONMENT;
if self.detach {
flags |= c::DETACHED_PROCESS | c::CREATE_NEW_PROCESS_GROUP;
}