2010-04-26 3 views
3

У меня есть программа, которая использует библиотеку win32com для управления iTunes, но у вас возникли некоторые проблемы с ее компиляцией в исполняемый файл. Проблема, похоже, вращается вокруг, используя DispatchWithEvents вместо Dispatch. Я создал очень простую программу, чтобы проиллюстрировать мою проблему:py2exe/pyinstaller и DispatchWithEvents

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 (от 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) 

Тогда вы можете заниматься своим делом.

ответ

-1

Вместо того, чтобы зависеть от кеша, я бы рекомендовал перейти в каталог локального кэша, скопировать сгенерированный файл в ваш файл локального проекта и называть его чем-то вроде ITunesInterface.py и называть его явно. Это заставит py2exe втянуть его в ваше скомпилированное приложение.

+1

I Думаю, это может сработать, но я не могу понять, как явно вызывать интерфейс, особенно с помощью событий. У меня была '' Dispatch'', но потом поняла, что это просто вызов win32com как обычно. Есть ли информация о том, как это сделать? – jeffaudio

1

This - официальный способ сделать это.

(Edit: скопированный пример из этой ссылки выше)

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) 
2

я испытывал ту же самую ошибку. Эта ссылка поставил меня в правильном направлении -> http://www.py2exe.org/index.cgi/UsingEnsureDispatch однако упоминает, что: NB Вы должны убедиться, что питон ... \ win32com.client.gen_py папка не существует разрешить создание кэша в% temp% Это было немного странно. Что для меня решило переименовать «C: \ Python26 \ Lib \ site-packages \ win32com \ gen_py» в «C: \ Python26 \ Lib \ site-packages \ win32com \ gen_pybak» (при запуске py2exe)