Skip to content

Commit e08d4a1

Browse files
committed
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.
1 parent a1c6be1 commit e08d4a1

File tree

1 file changed

+40
-27
lines changed

1 file changed

+40
-27
lines changed

src/rustup-utils/src/raw.rs

Lines changed: 40 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,9 @@ use std::fs;
77
use std::io::Write;
88
use std::io;
99
use std::path::Path;
10+
use std::ptr;
1011
use std::process::{Command, Stdio, ExitStatus};
1112
use std::str;
12-
use std::thread;
13-
use std::time::Duration;
1413

1514
use rand::random;
1615

@@ -194,27 +193,14 @@ fn symlink_junction_inner(target: &Path, junction: &Path) -> io::Result<()> {
194193
pub ReparseTarget: WCHAR,
195194
}
196195

197-
fn to_u16s<S: AsRef<OsStr>>(s: S) -> io::Result<Vec<u16>> {
198-
fn inner(s: &OsStr) -> io::Result<Vec<u16>> {
199-
let mut maybe_result: Vec<u16> = s.encode_wide().collect();
200-
if maybe_result.iter().any(|&u| u == 0) {
201-
return Err(io::Error::new(io::ErrorKind::InvalidInput,
202-
"strings passed to WinAPI cannot contain NULs"));
203-
}
204-
maybe_result.push(0);
205-
Ok(maybe_result)
206-
}
207-
inner(s.as_ref())
208-
}
209-
210196
// We're using low-level APIs to create the junction, and these are more picky about paths.
211197
// For example, forward slashes cannot be used as a path separator, so we should try to
212198
// canonicalize the path first.
213199
let target = try!(fs::canonicalize(target));
214200

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

217-
let path = try!(to_u16s(junction));
203+
let path = try!(windows::to_u16s(junction));
218204

219205
unsafe {
220206
let h = CreateFileW(path.as_ptr(),
@@ -382,15 +368,29 @@ pub fn open_browser(path: &Path) -> io::Result<bool> {
382368
}
383369
#[cfg(windows)]
384370
fn inner(path: &Path) -> io::Result<bool> {
385-
Command::new("cmd")
386-
.arg("/C")
387-
.arg("start")
388-
.arg(path)
389-
.stdin(Stdio::null())
390-
.stdout(Stdio::null())
391-
.stderr(Stdio::null())
392-
.spawn()
393-
.map(|_| true)
371+
use winapi;
372+
extern "system" {
373+
pub fn ShellExecuteW(hwnd: winapi::HWND,
374+
lpOperation: winapi::LPCWSTR,
375+
lpFile: winapi::LPCWSTR,
376+
lpParameters: winapi::LPCWSTR,
377+
lpDirectory: winapi::LPCWSTR,
378+
nShowCmd: winapi::c_int)
379+
-> winapi::HINSTANCE;
380+
}
381+
const SW_SHOW: winapi::c_int = 5;
382+
383+
let path = windows::to_u16s(path)?;
384+
let operation = windows::to_u16s("open")?;
385+
let result = unsafe {
386+
ShellExecuteW(ptr::null_mut(),
387+
operation.as_ptr(),
388+
path.as_ptr(),
389+
ptr::null(),
390+
ptr::null(),
391+
SW_SHOW)
392+
};
393+
Ok(result as usize > 32)
394394
}
395395
inner(path)
396396
}
@@ -402,8 +402,8 @@ pub mod windows {
402402
use std::path::PathBuf;
403403
use std::ptr;
404404
use std::slice;
405-
use std::ffi::OsString;
406-
use std::os::windows::ffi::OsStringExt;
405+
use std::ffi::{OsString, OsStr};
406+
use std::os::windows::ffi::{OsStringExt, OsStrExt};
407407
use shell32;
408408
use ole32;
409409

@@ -444,4 +444,17 @@ pub mod windows {
444444
}
445445
result
446446
}
447+
448+
pub fn to_u16s<S: AsRef<OsStr>>(s: S) -> io::Result<Vec<u16>> {
449+
fn inner(s: &OsStr) -> io::Result<Vec<u16>> {
450+
let mut maybe_result: Vec<u16> = s.encode_wide().collect();
451+
if maybe_result.iter().any(|&u| u == 0) {
452+
return Err(io::Error::new(io::ErrorKind::InvalidInput,
453+
"strings passed to WinAPI cannot contain NULs"));
454+
}
455+
maybe_result.push(0);
456+
Ok(maybe_result)
457+
}
458+
inner(s.as_ref())
459+
}
447460
}

0 commit comments

Comments
 (0)