将嵌入的Python IO重定向到使用AllocConsole创建的控制台

11 投票
2 回答
4069 浏览
提问于 2025-04-15 15:48

我在把Python的输入输出重定向到我为我的Win32应用程序分配的控制台时遇到了一些麻烦。请问有没有什么Python特定的流需要我去重定向呢?

现在我大致上是这样做的(错误检查的部分省略了等):

int __stdcall WinMain(/*Usual stuff here*/) {
    // Create the console
    AllocConsole();
    SetConsoleTitle(L"My Console");

    // Redirect Standard IO Streams to the new console
    freopen("CONOUT$","w",stdout);
    freopen("CONOUT$","w",stderr);
    freopen("CONIN$","r",stdin);

    // Test the console:
    printf("This Works.\r\n");
    cout << "So Does this" << endl;

    // Python Stuff (This is where it fails)
    Py_Initialize();
    PyRun_SimpleString("print('I don't work.')\n");
    Py_Finalize();
}

如果我运行同样的代码,但作为一个控制台应用程序(顺便说一下,是用Visual Studio 05做的),并且去掉AllocConsole的调用,所有的东西都能正常工作。有人知道我漏掉了什么吗?

补充说明:我想知道如何通过C的API来实现这个功能。

又一个补充:Alex的解决方案是正确的,但对于使用Python 3.x的人来说,你可能会发现新API中缺少了PyFile_FromString这个函数。虽然这可能不是最好的替代方案,但我发现这个在Python 3.x中可以正常工作:

PyObject* sys = PyImport_ImportModule("sys");
PyObject* io = PyImport_ImportModule("io");
PyObject* pystdout = PyObject_CallMethod(io, "open", "ss", "CONOUT$", "wt");
if (-1 == PyObject_SetAttrString(sys, "stdout", pystdout)) {
    /* Announce your error to the world */
}
Py_DECREF(sys);
Py_DECREF(io);
Py_DECREF(pystdout);

2 个回答

0

直接让嵌入的Python把输出结果保存到一个文件里要简单得多。

试试这段代码:

PyRun_SimpleString("import sys\n");
PyRun_SimpleString( "sys.stdout = sys.stderr = open(\"C:\\embedded_log_file.txt\", \"w\")\n" );
12

在Python中,设置sys.stdout(通常是用open('CONOUT$', 'wt'))可以让Python的print正常工作,sys.stderrsys.stdin也是一样的做法。虽然从C扩展中有更快的方法来实现这个,但最简单的方式就是直接执行Python语句,前面加上import sys就可以了;-)。

为什么要这样做呢?因为在Python启动时,它发现标准的文件描述符(FD)是关闭的,所以就相应地设置了sys.stdout等,但它不会再检查一次并重新设置。因此,你只需要自己明确地设置这些,就没问题了。

如果你想在C-API层面上完成这一切,虽然只需要几行代码,但当然是可以做到的……

PyObject* sys = PyImport_ImportModule("sys");
PyObject* pystdout = PyFile_FromString("CONOUT$", "wt");
if (-1 == PyObject_SetAttrString(sys, "stdout", pystdout)) {
  /* raise errors and wail very loud */
}
Py_DECREF(sys);
Py_DECREF(pystdout);

这实际上等同于一行Python代码:

sys.stdout = open('CONOUT$', 'wt')

撰写回答