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:如何将包文件添加到 library.zip 中?