[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/python/pymanager/main/src/pymanager/_launch.cpp [Back]  [Original]

#include 
#include 
#include 


static BOOL WINAPI
ctrl_c_handler(DWORD code)
{
    // just ignore control events
    return TRUE;
}


static int
dup_handle(HANDLE input, HANDLE *output)
{
    static HANDLE self = NULL;
    if (self == NULL) {
        self = GetCurrentProcess();
    }
    if (input == NULL || input == INVALID_HANDLE_VALUE) {
        *output = input;
        return 0;
    }
    if (!DuplicateHandle(self, input, self, output, 0, TRUE, DUPLICATE_SAME_ACCESS)) {
        if (GetLastError() == ERROR_INVALID_HANDLE) {
            *output = NULL;
            return 0;
        }
        return HRESULT_FROM_WIN32(GetLastError());
    }
    return 0;
}


int
launch(
    const wchar_t *executable,
    const wchar_t *orig_cmd_line,
    const wchar_t *insert_args,
    int skip_argc,
    DWORD *exit_code
) {
    HANDLE job;
    JOBOBJECT_EXTENDED_LIMIT_INFORMATION info;
    DWORD info_len;
    STARTUPINFOW si;
    PROCESS_INFORMATION pi;
    int lastError = 0;
    const wchar_t *cmd_line = NULL;

    if (orig_cmd_line[0] == L'"') {
        cmd_line = wcschr(orig_cmd_line + 1, L'"');
    } else {
        cmd_line = wcschr(orig_cmd_line, L' ');
    }

    size_t n = wcslen(executable) + wcslen(orig_cmd_line) + (insert_args ? wcslen(insert_args) : 0) + 6;
    wchar_t *new_cmd_line = (wchar_t *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, n * sizeof(wchar_t));
    if (!new_cmd_line) {
        lastError = GetLastError();
        goto exit;
    }

    // Skip any requested args, deliberately leaving any trailing spaces
    // (we'll skip one later on and add our own space, and preserve multiple)
    while (cmd_line && *cmd_line && skip_argc-- > 0) {
        wchar_t c;
        while (*++cmd_line && *cmd_line == L' ') { }
        while (*++cmd_line && *cmd_line != L' ') { }
    }

    swprintf_s(new_cmd_line, n, L"\"%s\"%s%s%s%s",
               executable,
               (insert_args && *insert_args) ? L" ": L"",
               (insert_args && *insert_args) ? insert_args : L"",
               (cmd_line && *cmd_line) ? L" " : L"",
               (cmd_line && *cmd_line) ? cmd_line + 1 : L"");

    job = CreateJobObject(NULL, NULL);
    if (!job
        || !QueryInformationJobObject(job, JobObjectExtendedLimitInformation, &info, sizeof(info), &info_len)
        || info_len != sizeof(info)
    ) {
        lastError = GetLastError();
        goto exit;
    }
    info.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE |
                                             JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK;
    if (!SetInformationJobObject(job, JobObjectExtendedLimitInformation, &info, sizeof(info))) {
        lastError = GetLastError();
        goto exit;
    }

    memset(&si, 0, sizeof(si));
    GetStartupInfoW(&si);
    if ((lastError = dup_handle(GetStdHandle(STD_INPUT_HANDLE), &si.hStdInput))
        || (lastError = dup_handle(GetStdHandle(STD_OUTPUT_HANDLE), &si.hStdOutput))
        || (lastError = dup_handle(GetStdHandle(STD_ERROR_HANDLE), &si.hStdError))
    ) {
        goto exit;
    }
    if (!SetConsoleCtrlHandler(ctrl_c_handler, TRUE)) {
        lastError = GetLastError();
        goto exit;
    }

    si.dwFlags |= STARTF_USESTDHANDLES;
    if (!CreateProcessW(executable, new_cmd_line, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) {
        lastError = GetLastError();
        goto exit;
    }

    AssignProcessToJobObject(job, pi.hProcess);
    CloseHandle(pi.hThread);

#if PY_WINDOWED
    /*
    When explorer launches a Windows (GUI) application, it displays
    the "app starting" (the "pointer + hourglass") cursor for a number
    of seconds, or until the app does something UI-ish (eg, creating a
    window, or fetching a message).  As this launcher doesn't do this
    directly, that cursor remains even after the child process does these
    things.  We avoid that by doing a simple post+get message.
    See http://bugs.python.org/issue17290
    */
    MSG msg;

    PostMessage(0, 0, 0, 0);
    GetMessage(&msg, 0, 0, 0);
#endif

    WaitForSingleObjectEx(pi.hProcess, INFINITE, FALSE);
    if (!GetExitCodeProcess(pi.hProcess, exit_code)) {
        lastError = GetLastError();
    }
exit:
    if (new_cmd_line) {
        HeapFree(GetProcessHeap(), 0, new_cmd_line);
    }
    return lastError ? HRESULT_FROM_WIN32(lastError) : 0;
}

Web Proxy Viewer  |  New URL  |  Original Page