Skip to content

Commit 62fae72

Browse files
qryxipamodm
authored andcommitted
Call ShellExecuteW on Windows
1 parent 863f50f commit 62fae72

File tree

2 files changed

+60
-6
lines changed

2 files changed

+60
-6
lines changed

Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,7 @@ repository = "https://github.com/amodm/webbrowser-rs"
99
readme = "README.md"
1010
keywords = ["webbrowser", "browser"]
1111
license = "MIT OR Apache-2.0"
12+
edition = "2015"
1213

13-
[dependencies]
14+
[target.'cfg(windows)'.dependencies]
15+
winapi = { version = "0.3.6", features = ["combaseapi", "objbase", "shellapi", "winerror"] }

src/lib.rs

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,29 @@
2626
//! }
2727
//! ```
2828
29+
#[cfg(windows)]
30+
extern crate widestring;
31+
#[cfg(windows)]
32+
extern crate winapi;
33+
2934
use std::default::Default;
30-
use std::error;
31-
use std::fmt;
3235
use std::io::{Error, ErrorKind, Result};
33-
use std::process::{Command, Output};
36+
use std::process::Output;
3437
use std::str::FromStr;
38+
use std::{error, fmt};
39+
40+
#[cfg(windows)]
41+
use std::os::windows::process::ExitStatusExt;
42+
#[cfg(windows)]
43+
use std::process::ExitStatus;
44+
#[cfg(windows)]
45+
use std::ptr;
46+
47+
#[cfg(not(windows))]
48+
use std::process::Command;
49+
50+
#[cfg(windows)]
51+
use widestring::U16CString;
3552

3653
#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
3754
/// Browser types available
@@ -145,12 +162,46 @@ pub fn open_browser(browser: Browser, url: &str) -> Result<Output> {
145162
open_browser_internal(browser, url)
146163
}
147164

148-
/// Deal with opening of browsers on Windows, using `start` command
165+
/// Deal with opening of browsers on Windows, using [`ShellExecuteW`](
166+
/// https://docs.microsoft.com/en-us/windows/desktop/api/shellapi/nf-shellapi-shellexecutew)
167+
/// fucntion.
149168
#[cfg(target_os = "windows")]
150169
#[inline]
151170
fn open_browser_internal(browser: Browser, url: &str) -> Result<Output> {
171+
use winapi::um::combaseapi::CoInitializeEx;
172+
use winapi::um::objbase::{COINIT_APARTMENTTHREADED, COINIT_DISABLE_OLE1DDE};
173+
use winapi::um::shellapi::ShellExecuteW;
174+
use winapi::um::winuser::SW_SHOWNORMAL;
175+
152176
match browser {
153-
Browser::Default => Command::new("cmd").arg("/C").arg("start").arg(url).output(),
177+
Browser::Default => {
178+
static OPEN: &[u16] = &['o' as u16, 'p' as u16, 'e' as u16, 'n' as u16, 0x0000];
179+
let url =
180+
U16CString::from_str(url).map_err(|e| Error::new(ErrorKind::InvalidInput, e))?;
181+
let code = unsafe {
182+
let _ = CoInitializeEx(
183+
ptr::null_mut(),
184+
COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE,
185+
);
186+
ShellExecuteW(
187+
ptr::null_mut(),
188+
OPEN.as_ptr(),
189+
url.as_ptr(),
190+
ptr::null(),
191+
ptr::null(),
192+
SW_SHOWNORMAL,
193+
) as usize as i32
194+
};
195+
if code > 32 {
196+
Ok(Output {
197+
status: ExitStatus::from_raw(0),
198+
stdout: vec![],
199+
stderr: vec![],
200+
})
201+
} else {
202+
Err(Error::last_os_error())
203+
}
204+
}
154205
_ => Err(Error::new(
155206
ErrorKind::NotFound,
156207
"Only the default browser is supported on this platform right now",
@@ -246,6 +297,7 @@ compile_error!("Only Windows, Mac OS and Linux are currently supported");
246297
#[test]
247298
fn test_open_default() {
248299
assert!(open("http://github.com").is_ok());
300+
assert!(open("http://github.com?dummy_query1=0&dummy_query2=nonascii").is_ok());
249301
}
250302

251303
#[test]

0 commit comments

Comments
 (0)