How to interrupt Python subprocesses on Windows when using Python C API?

穿精又带淫゛_ 提交于 2019-12-08 02:15:30

问题


I'm able to interrupt my subprocesses in Windows with

import ctypes
ctypes.windll.kernel32.GenerateConsoleCtrlEvent(1, _proc.pid)

but only if I run it via normal Python process.

When I run the same code via a separate launcher program using Python C API (code is below), the code above doesn't have any effect.

Should I change my launcher somehow in order to be able to interrupt subprocesses?

#include <Python.h>
#include <windows.h>

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
{
    LPWSTR *argv;
    int argc;

    argv = CommandLineToArgvW(GetCommandLine(), &argc);
    if (argv == NULL)
    {
        MessageBox(NULL, L"Unable to parse command line", L"Error", MB_OK);
        return 10;
    }

    Py_SetProgramName(argv[0]);
    Py_Initialize();
    PySys_SetArgvEx(argc, argv, 0);

    PyObject *py_main, *py_dict;
    py_main = PyImport_AddModule("__main__");
    py_dict = PyModule_GetDict(py_main);

    PyObject* result = PyRun_String(
        "from runpy import run_module\n"
        "run_module('thonny')\n",
        Py_file_input,
        py_dict,
        py_dict
        );

    int code;
    if (!result) {
        PyObject *ptype, *pvalue, *ptraceback;
        PyErr_Fetch(&ptype, &pvalue, &ptraceback);

        PyObject* valueAsString = PyObject_Str(pvalue);

        wchar_t* error_msg = PyUnicode_AsWideCharString(valueAsString, NULL);
        MessageBox(0, error_msg, L"Thonny startup error", MB_OK | MB_ICONERROR);
        code = -1;
    }
    else {
        code = 1;
    }

    Py_Finalize();

    return code;
}

EDIT: Turns out the same problems comes with pythonw.exe.


回答1:


That's how I finally got the console allocated without flashing console window (thanks to @eryksun for the pointers):

import sys
import ctypes
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)

cmd = [sys.executable, "-c", "print('Hi!'); input()"]
child = subprocess.Popen(cmd,
                         stdin=subprocess.PIPE,
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE,
                         shell=True)

child.stdout.readline() # now I know subprocess is ready
result = kernel32.AttachConsole(child.pid)
if not result:
    err = ctypes.get_last_error()
    print("Could not allocate console. Error code:", err, file=sys.stderr)
child.stdin.write(b"\n") # allow subprocess to complete
child.stdin.flush()

Basically I stole the console from a dummy subprocess.




回答2:


I'll propose one possible solution according to @eryksun's comment.

Just do

import ctypes
ctypes.windll.kernel32.AllocConsole() 

in parent process.

Unfortunately (as eryksun also noted), this also creates unnecessary and confusing console window.



来源:https://stackoverflow.com/questions/43450861/how-to-interrupt-python-subprocesses-on-windows-when-using-python-c-api

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!