| 684 | } |
| 685 | |
| 686 | int cbm_exec_no_shell(const char *const *argv) { |
| 687 | if (!argv || !argv[0]) { |
| 688 | return CBM_NOT_FOUND; |
| 689 | } |
| 690 | |
| 691 | wchar_t *cmdline = cbm_build_cmdline(argv); |
| 692 | if (!cmdline) { |
| 693 | return CBM_NOT_FOUND; |
| 694 | } |
| 695 | |
| 696 | STARTUPINFOW si; |
| 697 | PROCESS_INFORMATION pi; |
| 698 | memset(&si, 0, sizeof(si)); |
| 699 | memset(&pi, 0, sizeof(pi)); |
| 700 | si.cb = sizeof(si); |
| 701 | |
| 702 | /* CREATE_NO_WINDOW: the third and last spawn site that still needed it |
| 703 | * (#1427). Without it every helper routed through here — git, codesign, |
| 704 | * open — flashes a console window, and under a stdio MCP session with |
| 705 | * auto_watch those steal focus while the user is typing. The other three |
| 706 | * CreateProcessW sites already set it: subprocess.c and cbm_popen_isolated |
| 707 | * via #1448, and the detached daemon spawn in daemon/bootstrap.c, which has |
| 708 | * had it since it was written. */ |
| 709 | if (!CreateProcessW(NULL, cmdline, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) { |
| 710 | free(cmdline); |
| 711 | return CBM_NOT_FOUND; |
| 712 | } |
| 713 | free(cmdline); |
| 714 | |
| 715 | WaitForSingleObject(pi.hProcess, INFINITE); |
| 716 | DWORD exit_code = (DWORD)CBM_NOT_FOUND; |
| 717 | GetExitCodeProcess(pi.hProcess, &exit_code); |
| 718 | CloseHandle(pi.hProcess); |
| 719 | CloseHandle(pi.hThread); |
| 720 | return (int)exit_code; |
| 721 | } |
| 722 | |
| 723 | #else /* POSIX */ |
| 724 |
no test coverage detected