Created
October 30, 2019 08:13
-
-
Save Larusso/89a5079bdc8bfe07a203cbabeba4f9ec to your computer and use it in GitHub Desktop.
CommandLineToArgvW rust wrapper
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[dependencies] | |
winapi = { version = "0.3", features = ["shellapi","errhandlingapi"] } | |
widestring = "0.4.0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::error::Error; | |
use std::ffi::OsString; | |
use widestring::U16CString; | |
use widestring::U16String; | |
use winapi::um::winbase::{FormatMessageW, LocalFree, FORMAT_MESSAGE_FROM_SYSTEM, | |
FORMAT_MESSAGE_ALLOCATE_BUFFER, FORMAT_MESSAGE_IGNORE_INSERTS}; | |
use winapi::shared::ntdef::LPWSTR; | |
use winapi::shared::minwindef::HLOCAL; | |
use winapi::ctypes::c_int; | |
use winapi::um::shellapi; | |
use winapi::um::errhandlingapi; | |
use std::ptr; | |
pub fn win_parse_cmd(cmd: &str) -> std::result::Result<Vec<OsString>, String> { | |
use std::slice; | |
trace!("parse commandline args {}", cmd); | |
let cmd = U16CString::from_str(cmd).map_err(|err| err.description().to_string())?; | |
let mut num_args: c_int = 0; | |
unsafe { | |
let raw_args = shellapi::CommandLineToArgvW(cmd.as_ptr(), &mut num_args as *mut c_int); | |
if raw_args.is_null() { | |
let error_code = errhandlingapi::GetLastError(); | |
let mut buffer: LPWSTR = ptr::null_mut(); | |
let strlen = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | | |
FORMAT_MESSAGE_ALLOCATE_BUFFER | | |
FORMAT_MESSAGE_IGNORE_INSERTS, | |
ptr::null(), | |
error_code, | |
0, | |
(&mut buffer as *mut LPWSTR) as LPWSTR, | |
0, | |
ptr::null_mut()); | |
let message = U16String::from_ptr(buffer, strlen as usize); | |
LocalFree(buffer as HLOCAL); | |
return Err(format!("CommandLineToArgvW failed code: ({})", message.to_string_lossy())); | |
} | |
let mut args: Vec<OsString> = Vec::with_capacity(num_args as usize); | |
for s_ptr in slice::from_raw_parts_mut(raw_args, num_args as usize) { | |
let s = U16CString::from_ptr_str(*s_ptr); | |
let os = s.to_os_string(); | |
args.push(os); | |
} | |
LocalFree(raw_args as HLOCAL); | |
Ok(args) | |
} | |
} | |
#[cfg(test)] | |
mod tests { | |
use super::*; | |
#[test] | |
fn parse_command_into_arguments() { | |
use std::ffi::OsStr; | |
let cmd = r#"test.exe --arg1 "PosArg1" "Pos Arg 2" PosArg3"#; | |
let arguments = win_parse_cmd(cmd).unwrap(); | |
let expected_result: Vec<OsString> = [ | |
"test.exe", | |
"--arg1", | |
"PosArg1", | |
"Pos Arg 2", | |
"PosArg3", | |
] | |
.iter() | |
.map(|s| OsStr::new(s).to_os_string()) | |
.collect(); | |
assert_eq!(arguments, expected_result); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment