Доступ к незарегистрированным COM-объектам из Python через зарегистрированный TLB

У меня есть три части кода, с которым я работаю в данный момент:

  • Приложение с закрытым исходным кодом (Main.exe)
  • COM-объект VB с закрытым исходным кодом, реализованный как dll (comobj.dll)
  • Код, который я разрабатываю в Python

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, и я не отбросил бы файлов в том каталоге, если я могу избежать его.

Спасибо за справку.

11
задан EB. 18 May 2012 в 17:03
поделиться

1 ответ

Вот метод, который я придумал для загрузки 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
8
ответ дан 3 December 2019 в 05:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: