Created
January 24, 2024 13:48
-
-
Save flysand7/6685c4e568f7f703aae5eac692cff7c0 to your computer and use it in GitHub Desktop.
Run shell commands and start processes on windows.
This file contains hidden or 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
//+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