使用Python C API时如何在Windows上中断Python子进程? [英] How to interrupt Python subprocesses on Windows when using Python C API?

查看:240
本文介绍了使用Python C API时如何在Windows上中断Python子进程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我可以通过以下方式中断Windows中的子进程

I'm able to interrupt my subprocesses in Windows with

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

但仅当我通过正常的Python进程运行它时.

but only if I run it via normal Python process.

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

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

原来,pythonw.exe也会出现相同的问题.

Turns out the same problems comes with pythonw.exe.

推荐答案

这就是我最终在不刷新控制台窗口的情况下分配控制台的方法(感谢@eryksun提供的指针):

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.

这篇关于使用Python C API时如何在Windows上中断Python子进程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆