【问题标题】:py2exe/pyinstaller and DispatchWithEventspy2exe/pyinstaller 和 DispatchWithEvents
【发布时间】:2015-09-14 22:14:35
【问题描述】:

我有一个使用 win32com 库来控制 iTunes 的程序,但在将其编译为可执行文件时遇到了一些问题。问题似乎围绕着使用DispatchWithEvents 而不是Dispatch。我创建了一个非常简单的程序来说明我的问题:

import win32com.client
win32com.client.gencache.is_readonly = False #From py2exe wiki

class ITunesEvents(object):
    def __init__(self): self.comEnabled = True
    def OnCOMCallsDisabledEvent(self, reason): self.comEnabled = False
    def OnCOMCallsEnabledEvent(self): self.comEnabled = True

# The first line works in the exe, the second doesn't.
itunes = win32com.client.Dispatch("iTunes.Application")
#itunes = win32com.client.DispatchWithEvents("iTunes.Application", ITunesEvents)

lib = getattr(itunes, "LibraryPlaylist")
src = getattr(lib, "Source")
playlists = getattr(src, "Playlists")

print "Found %i playlists." % getattr(playlists, "Count")

使用Dispatch,程序可以正确编译并运行。使用DispatchWithEvents,从命令行调用程序运行良好,但运行exe时出现以下错误:

Traceback (most recent call last):
File "sandbox.py", line 16, in <module>
  itunes = win32com.client.DispatchWithEvents("iTunes.Application", ITunesEvents)
File "win32com\client\__init__.pyc", line 252, in DispatchWithEvents
File "win32com\client\gencache.pyc", line 520, in EnsureModule
File "win32com\client\gencache.pyc", line 287, in MakeModuleForTypelib
File "win32com\client\makepy.pyc", line 259, in GenerateFromTypeLibSpec
File "win32com\client\gencache.pyc", line 141, in GetGeneratePath
IOError: [Errno 2] No such file or directory: '[distDir]\\library.zip\\win32com\\gen_py\\__init__.py'

我也尝试过使用 PyInstaller,它给出了类似的错误:

File "<string>", line 16, in <module>
File "[outDir]/win32com.client", line 252, in DispatchWithEvents
File "[outDir]/win32com.client.gencache", line 520, in EnsureModule
File "[outDir]/win32com.client.gencache", line 287, in MakeModuleForTypelib
File "[outDir]/win32com.client.makepy", line 286, in GenerateFromTypeLibSpec
File "[outDir]/win32com.client.gencache", line 550, in AddModuleToCache
File "[outDir]/win32com.client.gencache", line 629, in _GetModule
File "[pyinstallerDir]\iu.py", line 455, in importHook
    raise ImportError, "No module named %s" % fqname
ImportError: No module named win32com.gen_py.9E93C96F-CF0D-43F6-8BA8-B807A3370712x0x1x13

我知道我可以在我的setup.py 文件中手动添加类型库,但我想在具有不同版本 iTunes 的计算机上运行代码而无需重新编译,因此我更喜欢动态创建它。如果设置/规范无法做到这一点,也许还有另一种加载事件的方法?谢谢。


加法:

感谢 Ryan,我发现我可以获取生成的 py 文件,经过一番挖掘,能够提出以下内容。

获取生成的 py 文件(来自 makepy.py)并将其重命名为 cominterface.py。然后,您需要执行以下操作才能使用事件处理程序实际创建 COM 对象。

import cominterface
from types import ClassType
from win32com.client import EventsProxy, _event_setattr_

class ItunesEvents:
    '''iTunes events class. See cominterface for details.'''
    def OnPlayerPlayEvent(self, t):print "Playing..."
    def OnPlayerStopEvent(self, t): print "Stopping..."

itunes = cominterface.iTunesApp()
rClass = ClassType("COMEventClass", (itunes.__class__, itunes.default_source, ItunesEvents), {'__setattr__': _event_setattr_})
instance = rClass(itunes._oleobj_)
itunes.default_source.__init__(instance, instance)
#ItunesEvents.__init__(instance) #Uncomment this line if your events class has __init__.
itunes = EventsProxy(instance)

然后你就可以开始你的事业了。

【问题讨论】:

    标签: python py2exe win32com pyinstaller


    【解决方案1】:

    我遇到了完全相同的错误。 这个链接让我朝着正确的方向前进--> http://www.py2exe.org/index.cgi/UsingEnsureDispatch 但是它提到: 注意您必须确保 python...\win32com.client.gen_py 目录不存在 允许在 %temp% 中创建缓存 这有点令人困惑。 为我解决的问题是将“C:\Python26\Lib\site-packages\win32com\gen_py”重命名为“C:\Python26\Lib\site-packages\win32com\gen_pybak”(运行 py2exe 时)

    【讨论】:

      【解决方案2】:

      This 是官方的做法。

      (编辑:从上面的链接中逐字复制示例)

      import win32com.client
      if win32com.client.gencache.is_readonly == True:
      
          #allow gencache to create the cached wrapper objects
          win32com.client.gencache.is_readonly = False
      
          # under p2exe the call in gencache to __init__() does not happen
          # so we use Rebuild() to force the creation of the gen_py folder
          win32com.client.gencache.Rebuild()
      
          # NB You must ensure that the python...\win32com.client.gen_py dir does not exist
          # to allow creation of the cache in %temp%
      
      # Use SAPI speech through IDispatch
      from win32com.client.gencache import EnsureDispatch
      from win32com.client import constants
      voice = EnsureDispatch("Sapi.SpVoice", bForDemand=0)
      voice.Speak( "Hello World.", constants.SVSFlagsAsync )
      

      【讨论】:

        【解决方案3】:

        我建议不要依赖缓存,而是进入本地缓存目录,将生成的文件复制到本地项目文件中,并将其命名为 ITunesInterface.py 之类的名称,然后显式调用它。这将使 py2exe 将其拉入您编译的应用程序中。

        【讨论】:

        • 我认为这可行,但我似乎无法弄清楚如何显式调用接口,尤其是使用事件。我有Dispatch 工作,但后来意识到这只是正常调用win32com。是否有关于如何执行此操作的信息?
        猜你喜欢
        • 2016-06-20
        • 2014-07-24
        • 2012-09-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多