The Windows Run dialog (Win+R) is used to launch arbitrary programs from a user-inputted string. What's cool about it is that it can handle spaces in the program path without any escaping.
So for example, this works fine: C:\Program Files\Git\git-bash --cd=./bin. With CMD or Powershell, C:\Program would be interpreted as the program path, and the rest as arguments.
Can this behavior of launching a program from a string that might have spaces in its path be replicated using CreateProcessW or ShellExecuteW? ShellExecuteW needs a separate parameter for the program path and its arguments, which seems tough to work-around with paths that may have spaces. CreateProcessW without passing an lpApplicationName seemed like it could be the solution, but I can't get it working (sample code in Rust below - responses with any lang are fine of course).
use windows::core::PWSTR;
use windows::Win32::Foundation::CloseHandle;
use windows::Win32::System::Threading::{
CreateProcessW, PROCESS_CREATION_FLAGS, PROCESS_INFORMATION,
STARTUPINFOW,
};
pub fn shell_exec() -> anyhow::Result<()> {
// Arbitrary command to execute. The command in the variable doesn't work
// but this path does: r#"C:\Program Files\Git\git-bash"#;
let command = r#"C:\Program Files\Git\git-bash --cd=./bin"#;
let command_utf16: Vec<u16> =
command.encode_utf16().chain(Some(0)).collect();
let mut si = STARTUPINFOW::default();
let mut pi = PROCESS_INFORMATION::default();
unsafe {
CreateProcessW(
None,
PWSTR(command_utf16.as_ptr() as *mut u16),
None,
None,
false,
PROCESS_CREATION_FLAGS::default(),
None,
None,
&mut si,
&mut pi,
)?;
println!("Command executed successfully.");
CloseHandle(pi.hProcess)?;
CloseHandle(pi.hThread)?;
}
Ok(())
}
possible use SHEvaluateSystemCommandTemplate
SHSTDAPI SHEvaluateSystemCommandTemplate(
_In_ PCWSTR pszCmdTemplate,
_Out_ PWSTR *ppszApplication,
_Out_opt_ PWSTR *ppszCommandLine,
_Out_opt_ PWSTR *ppszParameters
);
which exactly design for this purpose
The documentation you linked says:
The
lpApplicationNameparameter can beNULL. In that case, the module name must be the first white space–delimited token in thelpCommandLinestring
So let command = r#"C:\Program Files\Git\git-bash --cd=./bin"#; would be interpreted as the command C:\Program with the parameters Files\Git\git-bash and --cd=./bin
The run dialog does it's own parsing of the input (it can also accept URL/URI or any real paths for example) which you have to replicate.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With