cx_freeze 之后的 subprocess.Popen 行为

Posted

技术标签:

【中文标题】cx_freeze 之后的 subprocess.Popen 行为【英文标题】:subprocess.Popen behavior after cx_freeze 【发布时间】:2014-06-10 21:58:28 【问题描述】:

我有一些 python 代码使用 subprocess.Popen 打开控制台应用程序并从中获取 stdout/stderr。

从解释器启动工作正常且符合预期。

在使用带有--base-name Win32GUI 选项的 cx_freeze 后,Popen 现在会在控制台窗口中弹出,我无法捕获 stdout/stderr。如果我删除 --base-name Win32GUI 它会按预期工作,但我现在在 UI 后面有一个控制台。

这里是代码(我试过没有startupinfo和没有shell=False):

startupinfo = subprocess.STARTUPINFO()
            startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
            startupinfo.wShowWindow = subprocess.SW_HIDE
subprocess.Popen(['exe', 'arg1', 'arg2'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False, startupinfo=startupinfo)

我正在使用out, err = p.communicate() 来获取标准输出/标准错误

【问题讨论】:

尝试给它stdin=subprocess.PIPE,即使你不想发送任何标准输入。 This page 建议您需要为其提供所有三个标准流的句柄。 这似乎可行,但现在p.communicate() 正在为out 返回NoneType(错误仍然有效)。 很奇怪。如果你给它stderr=subprocess.STDOUT 来合并它们会发生什么? 您应该将Popen 调用放在try 语句中,并在引发异常时记录到文件中。 如果您从命令提示符运行 exe,它可能继承了进程标准句柄的错误控制台缓冲区句柄。 Popen 将在无效句柄上调用 DuplicateHandle 时死掉。尝试以start my.exe 运行它。 start命令在进程CreationFlags中设置CREATE_NEW_CONSOLE,所以无效句柄不会被复制到GUI进程中。 【参考方案1】:

好的,我找到了解决方案。看起来因为它的 Windows GUI 应用程序标准输出句柄不存在,并且看起来子进程继承了该行为。所以一种解决方法是一个简单的解决方法,一个涉及win32api并为其创建管道的更复杂的解决方法(没有尝试这种方法)。

这是最终奏效的方法:

startupinfo = subprocess.STARTUPINFO()
            startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
            startupinfo.wShowWindow = subprocess.SW_HIDE
stdout_file = tempfile.NamedTemporaryFile(mode='r+', delete=False)
process = subprocess.Popen(['exe', 'arg1', 'arg2'], stdin=subprocess.PIPE, stdout=stdout_file, stderr=subprocess.PIPE, shell=False, startupinfo=startupinfo)
return_code = process.wait()
stdout_file.flush()
stdout_file.seek(0) # This is required to reset position to the start of the file
out = stdout_file.read()
stdout_file.close()

【讨论】:

就我而言,我必须将encoding="UTF-16" 添加到 NamedTemporaryFile。这可以防止默认的“cp1252”编码......被stdout_file.read()误读(每个字符都用空格分隔)。 - 我的命令是:["wmic", "logicaldisk"] 我遇到了同样的问题,这似乎对我有用 这也适用于我,我使用了asyncio.create_subprocess_exec()

以上是关于cx_freeze 之后的 subprocess.Popen 行为的主要内容,如果未能解决你的问题,请参考以下文章

cx_freeze - 可执行文件仍在本地目录中查找

cx_freeze:如何将包文件添加到 library.zip 中?

subprocess模块

[Python]使用cx_Freeze打包FastApi项目的方法以及遇到的问题

python 模块积累-----subprocess

使用 win32wnet 导入时使用 cx_freeze 编译后的 DLL 问题