I've had another go at this. I've copied & slightly modified code from sccache.
Here's the calling code:
fn doc() -> Result<i32> {
let reply = run_detached("cmd.exe /C start \"\" doc.html");
thread::sleep(time::Duration::new(5, 0)); // Windows needs time to get going...
reply
}
and here's the copied/modified code:
fn run_detached(cmd: &str) -> Result<i32> {
//use std::error::Error as StdError;
use std::io::Error;
use std::mem;
use std::ptr;
use winapi::shared::minwindef::{TRUE, FALSE, DWORD};
use winapi::um::handleapi::CloseHandle;
use winapi::um::processthreadsapi::{CreateProcessW, PROCESS_INFORMATION,
STARTUPINFOW};
use winapi::um::winbase::{CREATE_UNICODE_ENVIRONMENT, DETACHED_PROCESS,
CREATE_NEW_PROCESS_GROUP};
use widestring::WideCString;
let cmd = cmd.replace("&", "^&");
let cli = WideCString::from_str(&cmd).unwrap();
let mut pi = PROCESS_INFORMATION {
hProcess: ptr::null_mut(),
hThread: ptr::null_mut(),
dwProcessId: 0,
dwThreadId: 0,
};
let mut si: STARTUPINFOW = unsafe { mem::zeroed() };
si.cb = mem::size_of::<STARTUPINFOW>() as DWORD;
if unsafe {
CreateProcessW(
cli.as_ptr(), // appname or command line
ptr::null_mut(), // command line or NULL and all above
ptr::null_mut(), // security
ptr::null_mut(), // security
FALSE, // inherit handles
CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS |
CREATE_NEW_PROCESS_GROUP, // flags
ptr::null_mut(), // env
ptr::null(), // cwd
&mut si, // startup info
&mut pi) // process info
== TRUE } {
unsafe {
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
Ok(0)
} else {
bail!("failed to run '{}': {:?}", cmd, Error::last_os_error())
//bail!("failed to run {}: {}",
// cmd, Error::last_os_error().description())
}
}
When I do this in the console it works perfectly:
cmd.exe /C start "" doc.html
But when I run the program, it doesn't work:
V:\myapp>myapp.exe --doc
Error: failed to run 'cmd.exe /C start "" doc.html': Os { code: 123, kind: Other, message: "The filename, directory name, or volume label syntax is incorrect." }
BTW It is best to give start
an empty string as its first argument.
PS Cargo.toml
:
[dependencies]
...
widestring = "0.3"
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["winuser", "handleapi",
"processthreadsapi"] }