Skip to content

Instantly share code, notes, and snippets.

@flysand7
Created January 24, 2024 13:48
Show Gist options
  • Save flysand7/6685c4e568f7f703aae5eac692cff7c0 to your computer and use it in GitHub Desktop.
Save flysand7/6685c4e568f7f703aae5eac692cff7c0 to your computer and use it in GitHub Desktop.
Run shell commands and start processes on windows.
//+build windows
package bake
import "core:sys/windows"
import "core:strings"
import "core:slice"
/*
Starts the process.
Note: the first element of argv is the name of executable
* The name won't be searched in $PATH env variable.
* If it doesn't end with .exe it won't try to start .exe.
*/
_os_exec_argv :: proc(argv: []string) -> (int, Exec_Error) {
assert(len(argv) > 0)
app_name := windows.utf8_to_wstring(argv[0])
cmd_builder := make([dynamic]u16)
for arg, arg_idx in argv[1:] {
if arg_idx != 0 {
append(&cmd_builder, ' ')
}
qarg := _win_escape_string(arg)
warg := windows.utf8_to_wstring(qarg)
for i := 0; warg[i] != 0; i += 1 {
append(&cmd_builder, warg[i])
}
}
append(&cmd_builder, 0)
#no_bounds_check cmd_line := &cmd_builder[0]
return _win_exec_cmdline(app_name, cmd_line)
}
/*
Starts a shell command using a default shell. I have no idea what that would be on
windows, pretty sure something like cmd.exe, but honestly I haven't tested this enough
to know for sure.
*/
_os_exec_cmdline :: proc(cmd_line: string) -> (int, Exec_Error) {
wcmd_line := windows.utf8_to_wstring(cmd_line)
return _win_exec_cmdline(nil, wcmd_line)
}
@(private="file")
_win_exec_cmdline :: proc(app_name: windows.wstring, cmd_line: windows.wstring) -> (int, Exec_Error) {
process_info := windows.PROCESS_INFORMATION {}
process_ok := windows.CreateProcessW(
app_name,
cmd_line,
nil,
nil,
false, // inherit handles
0, // flags
nil,
nil,
&windows.STARTUPINFOW {},
&process_info,
)
if !process_ok {
win_err := windows.GetLastError()
if win_err == windows.ERROR_FILE_NOT_FOUND {
return -1, .Executable_Not_Found
}
return -1, .Unhandled_Error
}
wait_status := windows.WaitForSingleObject(process_info.hProcess, windows.INFINITE)
if wait_status == windows.WAIT_FAILED {
printf_verbose("WaitForSingleObject Error: %v\n", windows.GetLastError())
return -1, .Unhandled_Error
}
exit_code := windows.DWORD(0)
exit_code_ok := windows.GetExitCodeProcess(
process_info.hProcess,
&exit_code,
)
if !exit_code_ok {
printf_verbose("GetExitCode Crror: %v\n", windows.GetLastError())
return -1, .Unhandled_Error
}
windows.CloseHandle(process_info.hProcess)
windows.CloseHandle(process_info.hThread)
return cast(int) exit_code, .None
}
@(private="file")
_win_escape_string :: proc(str: string) -> string {
builder := strings.builder_make()
for i in 0 ..< len(str) {
ch := str[i]
if ch == '"' || ch == '\\' {
strings.write_byte(&builder, '\\')
}
strings.write_byte(&builder, ch)
}
return strings.to_string(builder)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment