py2exe/pyinstallerおよびdispatchwithevents
-
01-10-2019 - |
質問
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
私は手動でTypelibを自分の中に追加できることを知っています setup.py
ファイルですが、再コンパイルせずにiTunesのさまざまなバージョンのコンピューターでコードを実行したいので、動的に作成したいと思います。セットアップ/仕様でこれを行う方法がない場合、イベントをロードする別の方法があるかもしれませんか?ありがとう。
添加:
ライアンのおかげで、生成されたpyファイルを取ることができることがわかりました。少し掘り下げた後、以下を思いつくことができました。
生成されたpyファイルを取ります(from 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)
その後、あなたはあなたのビジネスに取り組むことができます。
解決
キャッシュに依存する代わりに、ローカルキャッシュディレクトリに移動し、生成されたファイルをローカルプロジェクトファイルにコピーし、iTunesinterface.pyのような名前を付けて、明示的に呼び出すことをお勧めします。これにより、Py2exeがコンパイルされたアプリにそれを引き込みます。
他のヒント
まったく同じエラーが発生していました。このリンクは私を正しい方向に置いた - >http://www.py2exe.org/index.cgi/usingensuredispatchただし、次のことに言及しています。NBあなたは、Python ... win32com.client.gen_py dirが存在しないことを確認する必要があります。私のためにそれを解決したのは、「C: python26 lib site-packages win32com gen_py "" c: python26 lib site-packages win32com gen_pybak "(py2exeを実行しているとき)に名前を変更することでした。
これ それを行う公式の方法です。
(編集:上記のリンクからコピーされた逐語的な例)
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 )