|
26 | 26 | //! } |
27 | 27 | //! ``` |
28 | 28 |
|
| 29 | +#[cfg(windows)] |
| 30 | +extern crate widestring; |
| 31 | +#[cfg(windows)] |
| 32 | +extern crate winapi; |
| 33 | + |
29 | 34 | use std::default::Default; |
30 | | -use std::error; |
31 | | -use std::fmt; |
32 | 35 | use std::io::{Error, ErrorKind, Result}; |
33 | | -use std::process::{Command, Output}; |
| 36 | +use std::process::Output; |
34 | 37 | 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; |
35 | 52 |
|
36 | 53 | #[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)] |
37 | 54 | /// Browser types available |
@@ -145,12 +162,46 @@ pub fn open_browser(browser: Browser, url: &str) -> Result<Output> { |
145 | 162 | open_browser_internal(browser, url) |
146 | 163 | } |
147 | 164 |
|
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. |
149 | 168 | #[cfg(target_os = "windows")] |
150 | 169 | #[inline] |
151 | 170 | 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 | + |
152 | 176 | 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 | + } |
154 | 205 | _ => Err(Error::new( |
155 | 206 | ErrorKind::NotFound, |
156 | 207 | "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"); |
246 | 297 | #[test] |
247 | 298 | fn test_open_default() { |
248 | 299 | assert!(open("http://github.com").is_ok()); |
| 300 | + assert!(open("http://github.com?dummy_query1=0&dummy_query2=nonascii").is_ok()); |
249 | 301 | } |
250 | 302 |
|
251 | 303 | #[test] |
|
0 commit comments