Zugriff auf nicht registrierte COM-Objekte aus Python über einen registrierten TLB

Ich habe drei Stücke Code, mit dem ich im Moment arbeite:

  • Eine geschlossene Quellanwendung (Main.exe)
  • Ein geschlossenes Quell-VB-COM-Objekt, das als dll (comobj.dll) implementiert ist
  • Code, den ich in Python entwickle

Comobj.dll hostet ein COM-Objekt (lasst uns sagen, 'MainInteract'), die ich von Python verwenden möchte. Ich kann dieses Objekt schon ganz gut aus IronPython verwenden, aber wegen anderer Anforderungen muss ich es von der normalen Python verwenden. Ich glaube, die beste Methode hier ist, win32com zu verwenden, aber ich kann überhaupt nicht irgendwelche Fortschritte machen.

Erstens, einige arbeiten IronPython Code:

import clr import os import sys __dir__ = os.path.dirname(os.path.realpath(__file__)) sys.path.insert(0, __dir__) sys.path.append(r"C:\Path\To\comobj.dll") #This is where the com object dll actually is clr.AddReferenceToFileAndPath(os.path.join(__dir__, r'comobj_1_1.dll')) #This is the .NET interop assembly that was created automatically via SharpDevelop's COM Inspector from comobj_1_1 import clsMainInteract o = clsMainInteract() o.DoStuff(True) 

Und jetzt der Code, den ich in regelmäßigen Python versucht habe:

 >>> import win32com.client >>> win32com.client.Dispatch("{11111111-comobj_guid_i_got_from_com_inspector}") Traceback (most recent call last): File "<stdin>", line 1, in <module> File "C:\Python26\lib\site-packages\win32com\client\__init__.py", line 95, in Dispatch dispatch, userName = dynamic._GetGoodDispatchAndUserName(dispatch,userName,clsctx) File "C:\Python26\lib\site-packages\win32com\client\dynamic.py", line 104, in _GetGoodDispatchAndUserName return (_GetGoodDispatch(IDispatch, clsctx), userName) File "C:\Python26\lib\site-packages\win32com\client\dynamic.py", line 84, in _GetGoodDispatch IDispatch = pythoncom.CoCreateInstance(IDispatch, None, clsctx, pythoncom.IID_IDispatch) pywintypes.com_error: (-2147221164, 'Class not registered', None, None) 

Ich habe auch versucht, den freundlichen Namen des TLB zu benutzen:

 >>> import win32com.client >>> win32com.client.Dispatch("Friendly TLB Name I Saw") Traceback (most recent call last): File "<stdin>", line 1, in <module> File "C:\Python26\lib\site-packages\win32com\client\__init__.py", line 95, in Dispatch dispatch, userName = dynamic._GetGoodDispatchAndUserName(dispatch,userName,clsctx) File "C:\Python26\lib\site-packages\win32com\client\dynamic.py", line 104, in _GetGoodDispatchAndUserName return (_GetGoodDispatch(IDispatch, clsctx), userName) File "C:\Python26\lib\site-packages\win32com\client\dynamic.py", line 84, in _GetGoodDispatch IDispatch = pythoncom.CoCreateInstance(IDispatch, None, clsctx, pythoncom.IID_IDispatch) pywintypes.com_error: (-2147221005, 'Invalid class string', None, None) 

In der Tat, der einzige Erfolg, den ich hatte, war das:

 import pythoncom tlb = pythoncom.LoadRegTypeLib("{11111111-comobj_guid_i_got_from_com_inspector}",1,1,0) >>> tlb <PyITypeLib at 0x00AD7D78 with obj at 0x0025EDF0> >>> tlb.GetDocumentation(1) (u'clsMainInteract', None, 0, None) 

Aber ich bin mir nicht sicher, wie man von dort zu einem Objekt geht. Ich denke, mein Problem ist, dass ich die DLL in meinen Prozess laden und es sich mit der COM-Quelle meines Prozesses registrieren muss, also kann ich richtig CoCreateInstance / win32com.client.Dispatch () auf sie.

Ich habe auch gesehen Aktivierungskontexte referenziert, vor allem, wenn man über "keine Registrierung COM", aber in der Regel in einer Sätze wie "Windows wird einen Kontext für Sie erstellen, wenn Sie das richtige Zeug in Ihrem .manifest Dateien". Ich würde gerne manifest Dateien vermeiden, wenn möglich, wie man in dem gleichen Ordner wie die (geschlossene Quelle) COM-Objekt Dll erforderlich wäre, und ich würde lieber keine Dateien in diesem Verzeichnis, wenn ich es vermeiden kann.

Danke für die Hilfe.

3 Solutions collect form web for “Zugriff auf nicht registrierte COM-Objekte aus Python über einen registrierten TLB”

Was ich getan habe, um auf die Download-Bibliothek des Free Download Managers zuzugreifen, war folgende:

 import pythoncom, win32com.client fdm = pythoncom.LoadTypeLib('fdm.tlb') downloads_stat = None for index in xrange(0, fdm.GetTypeInfoCount()): type_name = fdm.GetDocumentation(index)[0] if type_name == 'FDMDownloadsStat': type_iid = fdm.GetTypeInfo(index).GetTypeAttr().iid downloads_stat = win32com.client.Dispatch(type_iid) break downloads_stat.BuildListOfDownloads(True, True) print downloads_stat.Download(0).Url 

Der obige Code druckt die URL des ersten Downloads.

Hier ist eine Methode, die ich entworfen habe, um ein COM-Objekt aus einer DLL zu laden. Es basiert auf viel Lesung über COM, etc. Ich bin nicht 100% sicher über die letzten Zeilen, speziell d =. Ich denke, das funktioniert nur, wenn IID_Vispatch passiert ist (was man sehen kann, ob das Default Param).

Darüber hinaus glaube ich, dass dieser Code leckt – zum einen wird die DLL niemals entladen (verwenden Sie ctypes.windll.kernel32.FreeLibraryW) und ich glaube, dass die COM ref zählt für die erste Klasse Fabrik sind von einem, und so nie freigegeben werden. Aber das funktioniert noch für meine Bewerbung.

 import pythoncom import win32com.client def CreateInstanceFromDll(dll, clsid_class, iid_interface=pythoncom.IID_IDispatch, pUnkOuter=None, dwClsContext=pythoncom.CLSCTX_SERVER): from uuid import UUID from ctypes import OleDLL, c_long, byref e = OleDLL(dll) clsid_class = UUID(clsid_class).bytes_le iclassfactory = UUID(str(pythoncom.IID_IClassFactory)).bytes_le com_classfactory = c_long(0) hr = e.DllGetClassObject(clsid_class, iclassfactory, byref(com_classfactory)) MyFactory = pythoncom.ObjectFromAddress(com_classfactory.value, pythoncom.IID_IClassFactory) i = MyFactory.CreateInstance(pUnkOuter, iid_interface) d = win32com.client.__WrapDispatch(i) return d 

Für ein nützliches Utility-Modul, das den Objekt-from-DLL-Fall sowie andere zusammenfasst, siehe https://gist.github.com/4219140

 __all__ = ( ####### Class Objects #CoGetClassObject - Normal, not wrapped 'CoDllGetClassObject', #Get ClassObject from a DLL file ####### ClassFactory::CreateInstance Wrappers 'CoCreateInstanceFromFactory', #Create an object via IClassFactory::CreateInstance 'CoCreateInstanceFromFactoryLicenced', #Create a licenced object via IClassFactory2::CreateInstanceLic ###### Util 'CoReleaseObject', #Calls Release() on a COM object ###### Main Utility Methods #'CoCreateInstance', #Not wrapped, normal call 'CoCreateInstanceLicenced', #CoCreateInstance, but with a licence key ###### Hacky DLL methods for reg-free COM without Activation Contexts, manifests, etc 'CoCreateInstanceFromDll', #Given a dll, a clsid, and an iid, create an object 'CoCreateInstanceFromDllLicenced', #Given a dll, a clsid, an iid, and a license key, create an object ) IID_IClassFactory2 = "{B196B28F-BAB4-101A-B69C-00AA00341D07}" from uuid import UUID from ctypes import OleDLL, WinDLL, c_ulong, byref, WINFUNCTYPE, POINTER, c_char_p, c_void_p from ctypes.wintypes import HRESULT import pythoncom import win32com.client import logging log = logging.getLogger(__name__) def _raw_guid(guid): """Given a string GUID, or a pythoncom IID, return the GUID laid out in memory suitable for passing to ctypes""" return UUID(str(guid)).bytes_le proto_icf2_base = WINFUNCTYPE(HRESULT, c_ulong, c_ulong, c_char_p, c_ulong, POINTER(c_ulong), ) IClassFactory2__CreateInstanceLic = proto_icf2_base(7, 'CreateInstanceLic', ( (1, 'pUnkOuter'), (1 | 4, 'pUnkReserved'), (1, 'riid'), (1, 'bstrKey'), (2, 'ppvObj'), ), _raw_guid(IID_IClassFactory2)) #-------------------------------- #-------------------------------- def _pc_wrap(iptr, resultCLSID=None): #return win32com.client.__WrapDispatch(iptr) log.debug("_pc_wrap: %s, %s"%(iptr, resultCLSID)) disp = win32com.client.Dispatch(iptr, resultCLSID=resultCLSID) log.debug("_pc_wrap: %s (%s)", disp.__class__.__name__, disp) return disp def CoCreateInstanceFromFactory(factory_ptr, iid_interface=pythoncom.IID_IDispatch, pUnkOuter=None): """Given a factory_ptr whose interface is IClassFactory, create the instance of clsid_class with the specified interface""" ClassFactory = pythoncom.ObjectFromAddress(factory_ptr.value, pythoncom.IID_IClassFactory) i = ClassFactory.CreateInstance(pUnkOuter, iid_interface) return i def CoCreateInstanceFromFactoryLicenced(factory_ptr, key, iid_interface=pythoncom.IID_IDispatch, pUnkOuter=None): """Given a factory_ptr whose interface is IClassFactory2, create the instance of clsid_class with the specified interface""" requested_iid = _raw_guid(iid_interface) ole_aut = WinDLL("OleAut32.dll") key_bstr = ole_aut.SysAllocString(unicode(key)) try: obj = IClassFactory2__CreateInstanceLic(factory_ptr, pUnkOuter or 0, c_char_p(requested_iid), key_bstr) disp_obj = pythoncom.ObjectFromAddress(obj, iid_interface) return disp_obj finally: if key_bstr: ole_aut.SysFreeString(key_bstr) #---------------------------------- def CoReleaseObject(obj_ptr): """Calls Release() on a COM object. obj_ptr should be a c_void_p""" if not obj_ptr: return IUnknown__Release = WINFUNCTYPE(HRESULT)(2, 'Release', (), pythoncom.IID_IUnknown) IUnknown__Release(obj_ptr) #----------------------------------- def CoCreateInstanceLicenced(clsid_class, key, pythoncom_iid_interface=pythoncom.IID_IDispatch, dwClsContext=pythoncom.CLSCTX_SERVER, pythoncom_wrapdisp=True, wrapas=None): """Uses IClassFactory2::CreateInstanceLic to create a COM object given a licence key.""" IID_IClassFactory2 = "{B196B28F-BAB4-101A-B69C-00AA00341D07}" ole = OleDLL("Ole32.dll") clsid_class_raw = _raw_guid(clsid_class) iclassfactory2 = _raw_guid(IID_IClassFactory2) com_classfactory = c_void_p(0) ole.CoGetClassObject(clsid_class_raw, dwClsContext, None, iclassfactory2, byref(com_classfactory)) try: iptr = CoCreateInstanceFromFactoryLicenced( factory_ptr = com_classfactory, key=key, iid_interface=pythoncom_iid_interface, pUnkOuter=None, ) if pythoncom_wrapdisp: return _pc_wrap(iptr, resultCLSID=wrapas or clsid_class) return iptr finally: if com_classfactory: CoReleaseObject(com_classfactory) #----------------------------------------------------------- #DLLs def CoDllGetClassObject(dll_filename, clsid_class, iid_factory=pythoncom.IID_IClassFactory): """Given a DLL filename and a desired class, return the factory for that class (as a c_void_p)""" dll = OleDLL(dll_filename) clsid_class = _raw_guid(clsid_class) iclassfactory = _raw_guid(iid_factory) com_classfactory = c_void_p(0) dll.DllGetClassObject(clsid_class, iclassfactory, byref(com_classfactory)) return com_classfactory def CoCreateInstanceFromDll(dll, clsid_class, iid_interface=pythoncom.IID_IDispatch, pythoncom_wrapdisp=True, wrapas=None): iclassfactory_ptr = CoDllGetClassObject(dll, clsid_class) try: iptr = CoCreateInstanceFromFactory(iclassfactory_ptr, iid_interface) if pythoncom_wrapdisp: return _pc_wrap(iptr, resultCLSID=wrapas or clsid_class) return iptr finally: CoReleaseObject(iclassfactory_ptr) def CoCreateInstanceFromDllLicenced(dll, clsid_class, key, iid_interface=pythoncom.IID_IDispatch, pythoncom_wrapdisp=True, wrapas=None): iclassfactory2_ptr = CoDllGetClassObject(dll, clsid_class, iid_factory=IID_IClassFactory2) try: iptr = CoCreateInstanceFromFactoryLicenced(iclassfactory2_ptr, key, iid_interface) if pythoncom_wrapdisp: return _pc_wrap(iptr, resultCLSID=wrapas or clsid_class) return iptr finally: CoReleaseObject(iclassfactory2_ptr) 
  • Win32com.client selbst beendende Ausgabe
  • Win32com + Excel + Django + Apache = Problem
  • Mit python win32com kann nicht zwei separate Tabellen in MS Word 2007
  • Verwenden von win32com mit Multithreading
  • Wie speichert man Attachment aus Outlook mit win32com.client in Python?
  • Wie benutzt man win32com.client.constants mit MS Word?
  • Wie man python wartet, bis ein Excel-Makro / Refresh getan ist
  • Python: win32com und cx_Freeze - Fehler
  • Automatisierung von Excel mit Win32com auf Linux mit Wein
  • Python lese meine Outlook E-Mail-Mailbox und parse Nachrichten
  • Python - Extra Excel Chart Serie mit Win32com
  • Python ist die beste Programmiersprache der Welt.