У меня есть три части кода, с которым я работаю в данный момент:
comobj.dll размещает COM-объект (позволяет, говорят, 'MainInteract'), что я хотел бы использовать из Python. Я могу уже использовать этот объект, превосходный от IronPython, но из-за других требований я должен использовать его из обычного Python. Я полагаю, что лучший метод здесь должен использовать win32com, но я не могу вполне сделать прогресс вообще.
Во-первых, некоторый рабочий код IronPython:
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)
И теперь код, которого я делал попытку в обычном Python:
>>> import win32com.client
>>> win32com.client.Dispatch("{11111111-comobj_guid_i_got_from_com_inspector}")
Traceback (most recent call last):
File "", line 1, in
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)
Я также делал попытку использования дружественного названия TLB:
>>> import win32com.client
>>> win32com.client.Dispatch("Friendly TLB Name I Saw")
Traceback (most recent call last):
File "", line 1, in
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)
На самом деле единственный успех, который я имел, был этим:
import pythoncom
tlb = pythoncom.LoadRegTypeLib("{11111111-comobj_guid_i_got_from_com_inspector}",1,1,0)
>>> tlb
>>> tlb.GetDocumentation(1)
(u'clsMainInteract', None, 0, None)
Но я не уверен, как перейти оттуда к получению объекта. Я думаю, что моя проблема состоит в том, что я должен загрузить dll в свой процесс и заставить его регистрировать себя в источнике моего процесса COM, таким образом, я могу правильно CoCreateInstance / win32com.client. Отправка () на нем.
Я также видел Контексты Активации, на которые ссылаются, особенно не говоря о 'никакой регистрации COM', но обычно в, предложения как "Windows создадут контекст для Вас при определении правильного материала в .manifest файлах". Я хотел бы избежать файлов манифеста бы, если это возможно, поскольку можно было бы требоваться в той же папке как COM-объект (с закрытым исходным кодом) dll, и я не отбросил бы файлов в том каталоге, если я могу избежать его.
Спасибо за справку.
Вот метод, который я придумал для загрузки COM-объекта из DLL. Он был основан на большом количестве прочитанного о COM и т.д. Я не уверен на 100% насчет последних строк, в частности d=. Я думаю, что это работает только если передан IID_Dispatch (который вы можете увидеть, если параметр по умолчанию).
Кроме того, я считаю, что этот код дает утечку - во-первых, DLL никогда не выгружается (используется ctypes.windll.kernel32.FreeLibraryW), и я считаю, что счетчики COM ссылок для начальной фабрики классов смещены на единицу, и поэтому никогда не освобождаются. Но все же, это работает для моего приложения.
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