Conversation
|
@wariuni thanks for the contribution. Can you elaborate if |
|
On Windows 7 at least PowerShell v2.0 seems to be pre-installed, which contains https://blogs.technet.microsoft.com/josebda/2009/11/25/download-for-powershell-v2-for-windows-7-no-need-its-already-there/ But on second thought, there is no specail reason to replace
https://github.com/python/cpython/blob/8c281ed403fd915284d5bba2405d7c47f8195066/Lib/webbrowser.py#L581
//! ```cargo
//! [package]
//! name = "startfile"
//! edition = "2018"
//!
//! [target.'cfg(windows)'.dependencies]
//! env_logger = "0.6.0"
//! log = "0.4.6"
//! percent-encoding = "1.0.1" # part of `url` crate
//! structopt = "0.2.14"
//! strum = "0.12.0"
//! strum_macros = "0.12.0"
//! widestring = "0.4.0"
//! winapi = { version = "0.3.6", features = ["combaseapi", "objbase", "shellapi"] }
//! ```
#![allow(unreachable_code)]
#[cfg(not(windows))]
compile_error!("");
use log::info;
use structopt::StructOpt;
use strum_macros::EnumString;
use widestring::U16CString;
use std::borrow::Cow;
use std::process::{Command, Stdio};
use std::{io, ptr};
#[derive(StructOpt)]
struct Opt {
file: String,
#[structopt(short = "m", long = "method", default_value = "winapi")]
method: Method,
}
#[derive(EnumString)]
#[strum(serialize_all = "snake_case")]
enum Method {
Winapi,
Cmd,
Powershell,
}
fn main() -> io::Result<()> {
env_logger::init();
let Opt { file, method } = Opt::from_args();
match method {
Method::Winapi => startfile_with_winapi(&file),
Method::Cmd => startfile_with_cmd(&encode_if_url(&file)),
Method::Powershell => startfile_with_powershell(&encode_if_url(&file)),
}
}
fn startfile_with_winapi(file: &str) -> io::Result<()> {
// https://docs.microsoft.com/en-us/windows/desktop/api/shellapi/nf-shellapi-shellexecutew
use winapi::um::combaseapi::CoInitializeEx;
use winapi::um::objbase::{COINIT_APARTMENTTHREADED, COINIT_DISABLE_OLE1DDE};
use winapi::um::shellapi::ShellExecuteW;
use winapi::um::winuser::SW_SHOW;
static OPEN: &[u16] = &[0x6f, 0x70, 0x65, 0x6e, 0x00];
let file =
U16CString::from_str(file).map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;
let code = unsafe {
let _ = CoInitializeEx(
ptr::null_mut(),
COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE,
);
ShellExecuteW(
ptr::null_mut(),
OPEN.as_ptr(),
file.as_ptr(),
ptr::null(),
ptr::null(),
SW_SHOW,
) as usize
};
if code > 32 {
Ok(())
} else {
Err(unimplemented!("code: {}", code))
}
}
fn startfile_with_cmd(file: &str) -> io::Result<()> {
let cmd = file.chars().fold("start ".to_owned(), |mut cmd, c| {
cmd.push('^');
cmd.push(c);
cmd
});
info!("cmd = {:?}", cmd);
let status = Command::new("cmd")
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null())
.arg("/C")
.arg(cmd)
.status()?;
if !status.success() {
return Err(unimplemented!("status: {}", status));
}
Ok(())
}
fn startfile_with_powershell(file: &str) -> io::Result<()> {
let (mut cmd, mut in_quotes) = ("Start-Process -FilePath ".to_owned(), false);
file.chars().for_each(|c| match c {
'"' if in_quotes => {
cmd += "\"`\"";
in_quotes = false;
}
'"' => cmd += "`\"",
c if in_quotes => cmd.push(c),
c => {
cmd.push('"');
cmd.push(c);
in_quotes = true;
}
});
if in_quotes {
cmd.push('"');
}
info!("cmd = {:?}", cmd);
let status = Command::new("powershell")
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null())
.arg("-Command")
.arg(cmd)
.status()?;
if !status.success() {
return Err(unimplemented!("status: {}", status));
}
Ok(())
}
fn encode_if_url(file: &str) -> Cow<str> {
use percent_encoding::{utf8_percent_encode, SIMPLE_ENCODE_SET};
if file.contains("://") {
Cow::from(utf8_percent_encode(file, SIMPLE_ENCODE_SET).to_string())
} else {
Cow::from(file)
}
}
#[cfg(test)]
mod tests {
static FILE: &str =
"http://example.com/articles/non-ascii-text?q1=0&q2=0";
#[test]
fn test_startfile_with_winapi() {
super::startfile_with_winapi(FILE).unwrap();
}
#[test]
fn test_startfile_with_cmd() {
super::startfile_with_cmd(FILE).unwrap();
}
#[test]
fn test_startfile_with_poewrshell() {
super::startfile_with_powershell(FILE).unwrap();
}
} |
9294ddc to
d2ff2af
Compare
|
My only recommendation would be to make the |
d2ff2af to
81cb934
Compare
|
Done. |
|
Published 0.4.0 after fixing windows build |
In the current implementation on Windows, this crate cannot open a URL which has special characters for
cmd.exe. (e.g.http://example.com?q1=0&q2=0)This PR fixes the problem by escaping URLs.