wx.ProgressDialog + py2exe导致应用程序崩溃

时间:2014-02-02 17:36:22

标签: python wxpython wxwidgets py2exe

这个简单的代码运行得非常好:

import wx
app = wx.App(0)
frame = wx.Frame(None)
test = wx.ProgressDialog('Test', 'Test', maximum = 20, parent = frame, style = wx.PD_CAN_ABORT)
app.MainLoop()

但是,在使用py2exe ...

编译/打包成可执行文件时
from distutils.core import setup
import py2exe
setup(script_args = ['py2exe'], windows=[{'script':'progressdlgprobblem.py'}],  
   options = {'py2exe': {'compressed':1,'bundle_files': 1}}, zipfile = None)

...然后.exe文件崩溃。

这次崩溃的原因是什么? wx.ProgressDialog是否需要一些特定的附加元素才能与py2exe一起使用?


附录1 :当我删除style = wx.PD_CAN_ABORT时,不再有崩溃。崩溃如何来自style? 但是,当从.exe启动时,样式是XP风格的:

enter image description here

与我从.py(没有py2exe)启动时获得的样式不同:

enter image description here


附录2 :当我删除'bundle_files': 1时,不再发生崩溃。 但我想将这个捆绑只保留在一个文件中! 如何捆绑到单个.exe文件中导致此次崩溃?

附录3 :使用wx.Python 3.0.1.0b而不是3.0.0.0解决问题的很大一部分(很快就会有更多细节)。

2 个答案:

答案 0 :(得分:2)

py2exe(0.6.9)已经过时,如果没有一些额外的更改,它们就无法处理更新的Windows版本。具体来说,它默认包含一些永远不应捆绑的Windows系统DLL。为防止这种情况,请尝试按如下方式更改设置脚本:

from distutils.core import setup
import py2exe

# Exclude system DLLs
origIsSystemDLL = py2exe.build_exe.isSystemDLL
def isSystemDLL(pathname):
    if os.path.basename(pathname).lower() in ("gdiplus.dll", 
                                              "mfc90.dll"):
        return 0
    if os.path.basename(pathname).lower() in ("powrprof.dll", ) or \
       os.path.basename(pathname).lower().startswith("api-ms-win-"):
        return 1
    return origIsSystemDLL(pathname)
py2exe.build_exe.isSystemDLL = isSystemDLL

# Add the MS VC9 CRT and common controls manifest as resource to the exe
manifest = '''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity
    version="0.0.0.0"
    processorArchitecture="x86"
    name="Enter program name here"
    type="win32"
  />
  <description>Enter program description here</description>
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel level="asInvoker" uiAccess="false" />
      </requestedPrivileges>
    </security>
  </trustInfo>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity
         type="win32"
         name="Microsoft.Windows.Common-Controls"
         version="6.0.0.0"
         processorArchitecture="x86"
         publicKeyToken="6595b64144ccf1df"
         language="*"
       />
    </dependentAssembly>
  </dependency>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity
         type="win32"
         name="Microsoft.VC90.CRT"
         version="9.0.21022.8"
         processorArchitecture="x86"
         publicKeyToken="1fc8b3b9a1e18e3b"
       />
    </dependentAssembly>
  </dependency>
</assembly>
'''

setup(script_args=['py2exe'],
      windows=[{'script': 'progressdlgprobblem.py',
                'other_resources': [(24, 1, manifest)]}],  
      options = {'py2exe': {'compressed': 1,
                            'dll_excludes': ['iertutil.dll', 
                                             'MPR.dll',
                                             'msvcm90.dll', 
                                             'msvcp90.dll', 
                                             'msvcr90.dll', 
                                             'mswsock.dll',
                                             'urlmon.dll',
                                             'w9xpopen.exe'],
                            'bundle_files': 1}},
      zipfile=None)

为获得最佳互操作性,您还需要从C:\ Windows \ winsxs \ x86_microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.21022复制Microsoft.VC90.CRT.manifest,msvcm90.dll,msvcp90.dll和msvcr90.dll。 8_none_bcb86ed6ac711f91(目录名可能略有不同,但正确的版本9.0.21022.8很重要)到你的exe目录,这样用户就不需要自己安装正确版本的MS VC9 CRT了。

除此之外,您可以尝试PyInstaller,它会自动处理程序集依赖项并默认排除系统DLL。

答案 1 :(得分:1)

ProgressDialog示例存在问题并添加了进度和清理,但其他方面没有变化。

# -*- coding: utf-8 -*-
import wx
app = wx.App(0)
frame = wx.Frame(None)
max_count = 8
dlg = wx.ProgressDialog('Test caption', 'Test text', maximum = max_count, parent = frame, style = wx.PD_CAN_ABORT)

keepGoing = True # progress routine from wxPython demo
count = 0

while keepGoing and count < max_count:
    count += 1
    wx.MilliSleep(125)
    wx.Yield()
    (keepGoing, skip) = dlg.Update(count, 'progress: {0} %'.format(count * 100.0/max_count))        

dlg.Destroy() # proper cleanup otherwise process has to be killed
frame.Destroy()

app.MainLoop()

冻结py2exe是一个痛苦的屁股,但提供恕我直言仍然很好的Windows平台的结果。大多数设置都是尝试错误的。在wxPython wiki中,有一个很好的描述/解释如何管理SxS程序集和清单。

# -*- coding: utf-8 -*-
"""manifest fixes NT-theming and including MSVC runtime issue"""

"""
# Recipe from
http://wiki.wxpython.org/Py2exe%20with%20Python2.6
"""

manifest = """
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity
    version="5.0.0.0"
    processorArchitecture="x86"
    name="%(prog)s"
    type="win32"
  />
  <description>%(prog)s</description>
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel
            level="asInvoker"
            uiAccess="false">
        </requestedExecutionLevel>
      </requestedPrivileges>
    </security>
  </trustInfo>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity
            type="win32"
            name="Microsoft.VC90.CRT"
            version="9.0.21022.8"
            processorArchitecture="x86"
            publicKeyToken="1fc8b3b9a1e18e3b">
      </assemblyIdentity>
    </dependentAssembly>
  </dependency>
  <dependency>
    <dependentAssembly>
        <assemblyIdentity
            type="win32"
            name="Microsoft.Windows.Common-Controls"
            version="6.0.0.0"
            processorArchitecture="X86"
            publicKeyToken="6595b64144ccf1df"
            language="*"
        />
    </dependentAssembly>
  </dependency>
</assembly>
"""

from distutils.core import setup
import py2exe
dll_excludes = [
    'w9xpopen.exe',
   'MSVCP90.dll' # reason see link to wxPython-wiki above
]
setup(script_args = ['py2exe'], windows=[{'script':'progressdlg.py',#
                                          "other_resources": [(24, 1, manifest)]}],   # manifest added
   options = {'py2exe': {'compressed':1,'bundle_files': 1, 'dll_excludes': dll_excludes,
                         }}, zipfile = None)

至少在我的机器上(WinXP 7 + wxPython 2.9.5.0),这个设置(python setup.py py2exe)会产生:

  • .EXE
  • 冻结时正确的主题
  • 没有崩溃,完全可用,使用你喜欢的风格标志

该示例至少可以在您的计算机上运行(已安装MSCV运行时)。有关排除的更完整列表,请参阅[wxPython-users] https://groups.google.com/forum/#!topic/wxpython-users/vrd-0cpiH1E中的并行线程。

esky库已针对已包含的此怪癖进行了修复,并为wx提供了实时更新 - 应用,但您可能会或可能不会喜欢它正在设置的不同项目结构。

侧注:我无法在wxPython 2.9.5.0上重现你的崩溃(即使没有程序集)。在Win8机器上使用3.0.0.0冻结时,我在XP上崩溃了,但根据Robin(见https://groups.google.com/forum/#!topic/wxpython-users/8OeBfxTC9Xo),这应该在3.0.1中解决。

旁注2:这似乎与wxPython 3.0.0.0(经典)有关。在我的XP机器上,即使没有冻结,这个例子也会崩溃。如果升级到wxPython 3.0.1 (phoenix),那么它再次起作用(解冻和py2exe)。冻结的单个文件EXE在Windows8,64位和WinXP上以正确的主题运行时没有问题。