该程序的体系结构由PySide构建,使用Py2exe构建。此外,它还有一个使用Py2exe构建的第二个python控制台应用程序。
GUI-App使用命名管道启动控制台应用程序,以便能够发送CTRL_C并捕获stdout / stderr。这是使用pywin32模块完成的。
在控制台应用程序内部,使用子进程模块以阻塞模式执行其他几个Windows应用程序。现在控制台应用程序被一些代码扩展,以非阻塞模式执行另一个程序。
如果执行GUI应用程序和控制台应用程序(在构建到Py2exe应用程序之前),一切都按预期工作并且需要。 如果使用Py2exe构建应用程序,外部Windows应用程序将冻结并弹出Windows错误。 (申请停止工作)
如果外部Windows应用程序的执行代码被隔离并且构建了py2exe可执行文件,那么一切正常。
所以问题必须是py2exe并从GUI应用程序调用控制台应用程序。
我希望有人能指出我正确的方向。
我被要求提供一个最小的例子。问题是该架构并不真正允许一个最小的工作示例。我尽我所能,我希望给定的例子能够更清楚地了解问题。如上所述 通过测试问题可以减少到py2exe。一旦GUI应用程序被编译"在控制台应用程序内启动非阻塞应用程序,但新应用程序导致Windows错误。
最小例子:
Console App console.py:
import logging
import subprocess
from time import sleep
def exec_program_nonblocking(args, cwd=None):
if cwd:
logging.debug("Change working directory to: %s", cwd)
subprocess.Popen(args,
cwd=cwd,
universal_newlines=True)
def main():
args = ["program.exe", "arg1", "arg2"]
exec_program_nonblocking(args)
while (True):
print "do something \n"
sleep(5)
if __name__ == '__main__':
main()
setup.py for console App:
from distutils.core import setup
import py2exe
setup(console=['console.py'])
PySide GUI应用程序gui_app.py:
from PySide.QtGui import QApplication
def start_console_app():
pass
# complex implementation of openening named pipe,
# handling callbacks, allowing to send CTRL_C to new process etc.
# Minimal example is not possible...
app = QtGui.QApplication([])
button = QtGui.QPushButton('Start Console App')
button.clicked.connect(start_console_app)
button.show()
app.exec_()
GUI应用程序的setup.py:
from distutils.core import setup
import py2exe
setup(
options = {
'py2exe' : {
'packages' : 'encodings',
'unbuffered' : True
#dll_excludes....
}
},
zipfile = None,
windows = ['gui_app.py']
)
答案 0 :(得分:0)
对我来说,here发布的解决方案对我有用。不知何故py2exe与从父进程GUI应用程序传递到子子进程的句柄混乱。对于来自控制台应用程序的子进程的所有可执行文件,它甚至不会发生。
子进程模块提供参数 close_fds ,以防止子进程从父进程中提取句柄。这对我的申请不起作用。它仍然必须与py2exe相关。
将DETACHED_PROCESS标志提供给参数 creationflags ,打开一个新的控制台并成功启动该过程!
唯一的缺点是,据我所知,stdout / stderr无法捕获。
工作示例:
import subprocess
DETACHED_PROCESS = 0x00000008
subprocess.Popen(args,
cwd=cwd,
creationflags=DETACHED_PROCESS)