使用Python C API时如何在Windows上中断Python子进程?

时间:2017-04-17 11:46:15

标签: python windows subprocess interrupt

我可以使用

中断Windows中的子进程
import ctypes
ctypes.windll.kernel32.GenerateConsoleCtrlEvent(1, _proc.pid)

但仅当我通过普通的Python进程运行它时。

当我使用Python C API(代码如下)通过单独的启动程序运行相同的代码时,上面的代码没有任何效果。

我是否应该以某种方式更改我的启动器以便能够中断子进程?

#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;
}

编辑:结果pythonw.exe带来了同样的问题。

2 个答案:

答案 0 :(得分:1)

这就是我如何在没有闪烁控制台窗口的情况下分配控制台的方式(感谢@eryksun的指针):

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()

基本上我从虚拟子进程中偷走了控制台。

答案 1 :(得分:0)

我会根据@ eryksun的评论提出一个可能的解决方案。

只做

import ctypes
ctypes.windll.kernel32.AllocConsole() 
在父进程中

不幸的是(正如eryksun所指出的那样),这也会造成不必要且令人困惑的控制台窗口。