Skip to content

Commit

Permalink
Auto merge of #1117 - mattico:use-shellexecute, r=Diggsey
Browse files Browse the repository at this point in the history
Use ShellExecute rather than start.exe to open docs on windows

Closes #499

The implementation is not too complicated, so it's a bit better than spawning a cmd.exe just to open docs. It also should fix opening docs for the few people still using a year-old insider preview build.
  • Loading branch information
bors committed May 18, 2017
2 parents 07582cd + 9733eaf commit b8b620d
Showing 1 changed file with 45 additions and 28 deletions.
73 changes: 45 additions & 28 deletions src/rustup-utils/src/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@ use std::fs;
use std::io::Write;
use std::io;
use std::path::Path;
use std::process::{Command, Stdio, ExitStatus};
use std::process::{Command, ExitStatus};
use std::str;
use std::thread;
use std::time::Duration;

use rand::random;

Expand Down Expand Up @@ -194,27 +192,14 @@ fn symlink_junction_inner(target: &Path, junction: &Path) -> io::Result<()> {
pub ReparseTarget: WCHAR,
}

fn to_u16s<S: AsRef<OsStr>>(s: S) -> io::Result<Vec<u16>> {
fn inner(s: &OsStr) -> io::Result<Vec<u16>> {
let mut maybe_result: Vec<u16> = s.encode_wide().collect();
if maybe_result.iter().any(|&u| u == 0) {
return Err(io::Error::new(io::ErrorKind::InvalidInput,
"strings passed to WinAPI cannot contain NULs"));
}
maybe_result.push(0);
Ok(maybe_result)
}
inner(s.as_ref())
}

// We're using low-level APIs to create the junction, and these are more picky about paths.
// For example, forward slashes cannot be used as a path separator, so we should try to
// canonicalize the path first.
let target = try!(fs::canonicalize(target));

try!(fs::create_dir(junction));

let path = try!(to_u16s(junction));
let path = try!(windows::to_u16s(junction));

unsafe {
let h = CreateFileW(path.as_ptr(),
Expand Down Expand Up @@ -367,6 +352,8 @@ pub fn find_cmd<'a>(cmds: &[&'a str]) -> Option<&'a str> {
pub fn open_browser(path: &Path) -> io::Result<bool> {
#[cfg(not(windows))]
fn inner(path: &Path) -> io::Result<bool> {
use std::process::Stdio;

let commands = ["xdg-open", "open", "firefox", "chromium", "sensible-browser"];
if let Some(cmd) = find_cmd(&commands) {
Command::new(cmd)
Expand All @@ -382,15 +369,32 @@ pub fn open_browser(path: &Path) -> io::Result<bool> {
}
#[cfg(windows)]
fn inner(path: &Path) -> io::Result<bool> {
Command::new("cmd")
.arg("/C")
.arg("start")
.arg(path)
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null())
.spawn()
.map(|_| true)
use winapi;
use std::ptr;

// FIXME: When winapi has this function, use their version
extern "system" {
pub fn ShellExecuteW(hwnd: winapi::HWND,
lpOperation: winapi::LPCWSTR,
lpFile: winapi::LPCWSTR,
lpParameters: winapi::LPCWSTR,
lpDirectory: winapi::LPCWSTR,
nShowCmd: winapi::c_int)
-> winapi::HINSTANCE;
}
const SW_SHOW: winapi::c_int = 5;

let path = windows::to_u16s(path)?;
let operation = windows::to_u16s("open")?;
let result = unsafe {
ShellExecuteW(ptr::null_mut(),
operation.as_ptr(),
path.as_ptr(),
ptr::null(),
ptr::null(),
SW_SHOW)
};
Ok(result as usize > 32)
}
inner(path)
}
Expand All @@ -402,8 +406,8 @@ pub mod windows {
use std::path::PathBuf;
use std::ptr;
use std::slice;
use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;
use std::ffi::{OsString, OsStr};
use std::os::windows::ffi::{OsStringExt, OsStrExt};
use shell32;
use ole32;

Expand Down Expand Up @@ -444,4 +448,17 @@ pub mod windows {
}
result
}

pub fn to_u16s<S: AsRef<OsStr>>(s: S) -> io::Result<Vec<u16>> {
fn inner(s: &OsStr) -> io::Result<Vec<u16>> {
let mut maybe_result: Vec<u16> = s.encode_wide().collect();
if maybe_result.iter().any(|&u| u == 0) {
return Err(io::Error::new(io::ErrorKind::InvalidInput,
"strings passed to WinAPI cannot contain NULs"));
}
maybe_result.push(0);
Ok(maybe_result)
}
inner(s.as_ref())
}
}

0 comments on commit b8b620d

Please sign in to comment.