diff options
Diffstat (limited to 'v_windows/v/vlib/os/process_windows.c.v')
-rw-r--r-- | v_windows/v/vlib/os/process_windows.c.v | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/v_windows/v/vlib/os/process_windows.c.v b/v_windows/v/vlib/os/process_windows.c.v new file mode 100644 index 0000000..bcdf971 --- /dev/null +++ b/v_windows/v/vlib/os/process_windows.c.v @@ -0,0 +1,243 @@ +module os + +import strings + +fn C.GenerateConsoleCtrlEvent(event u32, pgid u32) bool +fn C.GetModuleHandleA(name &char) HMODULE +fn C.GetProcAddress(handle voidptr, procname &byte) voidptr +fn C.TerminateProcess(process HANDLE, exit_code u32) bool + +type FN_NTSuspendResume = fn (voidptr) + +fn ntdll_fn(name &char) FN_NTSuspendResume { + ntdll := C.GetModuleHandleA(c'NTDLL') + if ntdll == 0 { + return FN_NTSuspendResume(0) + } + the_fn := FN_NTSuspendResume(C.GetProcAddress(ntdll, name)) + return the_fn +} + +fn failed_cfn_report_error(ok bool, label string) { + if ok { + return + } + error_num := int(C.GetLastError()) + error_msg := get_error_msg(error_num) + eprintln('failed $label: $error_msg') + exit(1) +} + +type PU32 = &u32 + +// TODO: the PU32 alias is used to compensate for the wrong number of &/* +// that V does when doing: `h := &&u32(p)`, which should have casted +// p to a double pointer. +fn close_valid_handle(p voidptr) { + h := &PU32(p) + if *h != &u32(0) { + C.CloseHandle(*h) + unsafe { + *h = &u32(0) + } + } +} + +pub struct WProcess { +pub mut: + proc_info ProcessInformation + command_line [65536]byte + child_stdin &u32 + // + child_stdout_read &u32 + child_stdout_write &u32 + // + child_stderr_read &u32 + child_stderr_write &u32 +} + +fn (mut p Process) win_spawn_process() int { + mut wdata := &WProcess{ + child_stdin: 0 + child_stdout_read: 0 + child_stdout_write: 0 + child_stderr_read: 0 + child_stderr_write: 0 + } + p.wdata = voidptr(wdata) + mut start_info := StartupInfo{ + lp_reserved2: 0 + lp_reserved: 0 + lp_desktop: 0 + lp_title: 0 + cb: sizeof(C.PROCESS_INFORMATION) + } + if p.use_stdio_ctl { + mut sa := SecurityAttributes{} + sa.n_length = sizeof(C.SECURITY_ATTRIBUTES) + sa.b_inherit_handle = true + create_pipe_ok1 := C.CreatePipe(voidptr(&wdata.child_stdout_read), voidptr(&wdata.child_stdout_write), + voidptr(&sa), 0) + failed_cfn_report_error(create_pipe_ok1, 'CreatePipe stdout') + set_handle_info_ok1 := C.SetHandleInformation(wdata.child_stdout_read, C.HANDLE_FLAG_INHERIT, + 0) + failed_cfn_report_error(set_handle_info_ok1, 'SetHandleInformation') + create_pipe_ok2 := C.CreatePipe(voidptr(&wdata.child_stderr_read), voidptr(&wdata.child_stderr_write), + voidptr(&sa), 0) + failed_cfn_report_error(create_pipe_ok2, 'CreatePipe stderr') + set_handle_info_ok2 := C.SetHandleInformation(wdata.child_stderr_read, C.HANDLE_FLAG_INHERIT, + 0) + failed_cfn_report_error(set_handle_info_ok2, 'SetHandleInformation stderr') + start_info.h_std_input = wdata.child_stdin + start_info.h_std_output = wdata.child_stdout_write + start_info.h_std_error = wdata.child_stderr_write + start_info.dw_flags = u32(C.STARTF_USESTDHANDLES) + } + cmd := '$p.filename ' + p.args.join(' ') + C.ExpandEnvironmentStringsW(cmd.to_wide(), voidptr(&wdata.command_line[0]), 32768) + + mut creation_flags := int(C.NORMAL_PRIORITY_CLASS) + if p.use_pgroup { + creation_flags |= C.CREATE_NEW_PROCESS_GROUP + } + create_process_ok := C.CreateProcessW(0, &wdata.command_line[0], 0, 0, C.TRUE, creation_flags, + 0, 0, voidptr(&start_info), voidptr(&wdata.proc_info)) + failed_cfn_report_error(create_process_ok, 'CreateProcess') + if p.use_stdio_ctl { + close_valid_handle(&wdata.child_stdout_write) + close_valid_handle(&wdata.child_stderr_write) + } + p.pid = int(wdata.proc_info.dw_process_id) + return p.pid +} + +fn (mut p Process) win_stop_process() { + the_fn := ntdll_fn(c'NtSuspendProcess') + if voidptr(the_fn) == 0 { + return + } + wdata := &WProcess(p.wdata) + the_fn(wdata.proc_info.h_process) +} + +fn (mut p Process) win_resume_process() { + the_fn := ntdll_fn(c'NtResumeProcess') + if voidptr(the_fn) == 0 { + return + } + wdata := &WProcess(p.wdata) + the_fn(wdata.proc_info.h_process) +} + +fn (mut p Process) win_kill_process() { + wdata := &WProcess(p.wdata) + C.TerminateProcess(wdata.proc_info.h_process, 3) +} + +fn (mut p Process) win_kill_pgroup() { + wdata := &WProcess(p.wdata) + C.GenerateConsoleCtrlEvent(C.CTRL_BREAK_EVENT, wdata.proc_info.dw_process_id) + C.Sleep(20) + C.TerminateProcess(wdata.proc_info.h_process, 3) +} + +fn (mut p Process) win_wait() { + exit_code := u32(1) + mut wdata := &WProcess(p.wdata) + if p.wdata != 0 { + C.WaitForSingleObject(wdata.proc_info.h_process, C.INFINITE) + C.GetExitCodeProcess(wdata.proc_info.h_process, voidptr(&exit_code)) + close_valid_handle(&wdata.child_stdin) + close_valid_handle(&wdata.child_stdout_write) + close_valid_handle(&wdata.child_stderr_write) + close_valid_handle(&wdata.proc_info.h_process) + close_valid_handle(&wdata.proc_info.h_thread) + } + p.status = .exited + p.code = int(exit_code) +} + +fn (mut p Process) win_is_alive() bool { + exit_code := u32(0) + wdata := &WProcess(p.wdata) + C.GetExitCodeProcess(wdata.proc_info.h_process, voidptr(&exit_code)) + if exit_code == C.STILL_ACTIVE { + return true + } + return false +} + +/////////////// + +fn (mut p Process) win_write_string(idx int, s string) { + panic('Process.write_string $idx is not implemented yet') +} + +fn (mut p Process) win_read_string(idx int, maxbytes int) (string, int) { + panic('WProcess.read_string $idx is not implemented yet') + return '', 0 +} + +fn (mut p Process) win_slurp(idx int) string { + mut wdata := &WProcess(p.wdata) + if wdata == 0 { + return '' + } + mut rhandle := &u32(0) + if idx == 1 { + rhandle = wdata.child_stdout_read + } + if idx == 2 { + rhandle = wdata.child_stderr_read + } + if rhandle == 0 { + return '' + } + mut bytes_read := u32(0) + buf := [4096]byte{} + mut read_data := strings.new_builder(1024) + for { + mut result := false + unsafe { + result = C.ReadFile(rhandle, &buf[0], 1000, voidptr(&bytes_read), 0) + read_data.write_ptr(&buf[0], int(bytes_read)) + } + if result == false || int(bytes_read) == 0 { + break + } + } + soutput := read_data.str() + unsafe { read_data.free() } + if idx == 1 { + close_valid_handle(&wdata.child_stdout_read) + } + if idx == 2 { + close_valid_handle(&wdata.child_stderr_read) + } + return soutput +} + +// +// these are here to make v_win.c/v.c generation work in all cases: +fn (mut p Process) unix_spawn_process() int { + return 0 +} + +fn (mut p Process) unix_stop_process() { +} + +fn (mut p Process) unix_resume_process() { +} + +fn (mut p Process) unix_kill_process() { +} + +fn (mut p Process) unix_kill_pgroup() { +} + +fn (mut p Process) unix_wait() { +} + +fn (mut p Process) unix_is_alive() bool { + return false +} |