Как использовать COM из python win32com или comtypes для доступа к IRTDServer?Python

Программы на Python
Ответить
Anonymous
 Как использовать COM из python win32com или comtypes для доступа к IRTDServer?

Сообщение Anonymous »

Окружающая среда

Windows 10 + Python 3.6.3 64-разрядная версия (также пробовал 32-разрядную версию). Я разработчик Python, пытаюсь использовать COM (почти) впервые и столкнулся с этим огромным блокировщиком.

Проблема

У меня возникали различные ошибки при попытке использовать IRTDServer, реализованный в dll (написанной не мной), через win32com или comtypes. Использовать win32com оказалось сложнее. Ниже я включил пример модульного теста для обеих библиотек.

Доступ к серверу из Excel 2016 работает как положено; это возвращает ожидаемое значение:

Код: Выделить всё

=RTD("foo.bar", , "STAT1", "METRIC1")


Код с использованием библиотеки win32com

Вот простой тестовый пример, который должен подключиться к серверу, но не подключается. (Это всего лишь одна версия, так как я много раз менял ее, пытаясь отладить проблему.)

Код: Выделить всё

from unittest import TestCase

class COMtest(TestCase):
def test_win32com(self):
import win32com.client
from win32com.server.util import wrap

class RTDclient:
# are these only required when implementing the server?
_com_interfaces_ = ["IRTDUpdateEvent"]
_public_methods_ = ["Disconnect", "UpdateNotify"]
_public_attrs_ = ["HeartbeatInterval"]

def __init__(self, *args, **kwargs):
self._comObj = win32com.client.Dispatch(*args, **kwargs)
def connect(self):
self._rtd = win32com.client.CastTo(self._comObj, 'IRtdServer')
result = self._rtd.ServerStart(wrap(self))
assert result > 0

def UpdateNotify(self):
print("UpdateNotify() callback")
def Disconnect(self):
print("Disconnect() called")
HeartbeatInterval = -1

_rtd = RTDclient("foo.bar")
_rtd.connect()
Результат:

Код: Выделить всё

Traceback (most recent call last):
File "env\lib\site-packages\win32com\client\gencache.py", line 532, in EnsureDispatch
ti = disp._oleobj_.GetTypeInfo()
pywintypes.com_error: (-2147467263, 'Not implemented', None, None)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "test\test.py", line 23, in test_win32com
_rtd.connect()
File "test\test.py", line 16, in connect
self._rtd = win32com.client.CastTo(dispatch, 'IRtdServer')
File "env\lib\site-packages\win32com\client\__init__.py", line 134, in CastTo
ob = gencache.EnsureDispatch(ob)
File "env\lib\site-packages\win32com\client\gencache.py", line 543, in EnsureDispatch
raise TypeError("This COM object can not automate the makepy process - please run makepy manually for this object")
TypeError: This COM object can not automate the makepy process - please run makepy manually for this object
Следуя этим инструкциям, я успешно запустил скрипт makepy:

Код: Выделить всё

> env\Scripts\python.exe env\lib\site-packages\win32com\client\makepy.py "foo.bar"
Generating to C:\Users\user1\AppData\Local\Temp\gen_py\3.5\longuuid1x0x1x0.py
Building definitions from type library...
Generating...
Importing module
(Я заменил UUID в stackoverflow в целях конфиденциальности. Этот UUID совпадает с UUID библиотеки типов для «foo.bar».)< /p>

Сгенерированный файл содержит различные определения функций и типов IRTdServer и IRTDUpdateEvent. Но в этом файле оба интерфейса являются подклассами win32com.client.DispatchBaseClass, тогда как по OleViewDotNet они должны быть подклассами IUnknown?

Однако, когда я попытался снова запустить модульный тест, я получил ту же ошибку, что и раньше. Как будто механизм поиска не находит сгенерированный модуль?

Кроме того, меня тревожит возврат GetTypeInfo «Не реализовано». Насколько я понимаю, win32com использует этот метод (часть COM-интерфейса IDispatch) для определения типов аргументов и возвращаемых значений для всех других функций в других интерфейсах, включая IRtdServer. Если он не реализован, он не сможет правильно определить типы. Тем не менее, сгенерированный файл, похоже, содержит эту информацию, что также вызывает недоумение.



Код с использованием библиотеки comtypes

Код: Выделить всё

from unittest import TestCase

class COMtest(TestCase):
def test_comtypes(self):
import comtypes.client

class RTDclient:
# are these for win32com only?
_com_interfaces_ = ["IRTDUpdateEvent"]
_public_methods_ = ["Disconnect", "UpdateNotify"]
_public_attrs_ = ["HeartbeatInterval"]

def __init__(self, clsid):
self._comObj = comtypes.client.CreateObject(clsid)
def connect(self):
self._rtd = self._comObj.IRtdServer()
result = self._rtd.ServerStart(self)
assert result > 0

def UpdateNotify(self):
print("UpdateNotify() callback")
def Disconnect(self):
print("Disconnect() called")
HeartbeatInterval = -1

_rtd = RTDclient("foo.bar")
_rtd.connect()
Результат:

Код: Выделить всё

  File "test\test.py", line 27, in test_comtypes
_rtd.connect()
File "test\test.py", line 16, in connect
self._rtd = self._comObj.IRTDServer()
File "env\lib\site-packages\comtypes\client\dynamic.py", line 110, in __getattr__
dispid = self._comobj.GetIDsOfNames(name)[0]
File "env\lib\site-packages\comtypes\automation.py", line 708, in GetIDsOfNames
self.__com_GetIDsOfNames(riid_null, arr, len(names), lcid, ids)
_ctypes.COMError: (-2147352570, 'Unknown name.', (None, None, None, 0, None))


Некоторые другие решения, которые я пробовал

( На основе поиска в Google и ответов в комментариях ниже)
  • (Пере-)Зарегистрировал DLL
  • Зарегистрировал 32-битную версию DLL и попробовал 32-битную версию Python
  • Установить режим совместимости python.exe с Windows XP SP3
  • Попробовал не создавать экземпляр IRtdServer, то есть заменить эти две строки:

    Код: Выделить всё

    self._rtd = self._comObj.IRtdServer()
    result = self._rtd.ServerStart(self)
    
    с:

    Код: Выделить всё

    result = self._comObj.ServerStart(self)
    
    На этот раз ошибка:

    Код: Выделить всё

    TypeError: 'NoneType' object is not callable
    
    Казалось бы, это указывает на то, что функция ServerStart существует, но она не определена? (Выглядит очень странно. В этой загадке должно быть что-то еще.)
  • Попробовал передать параметр интерфейса="IRtdServer" в CreateObject :

    Код: Выделить всё

    def __init__(self, clsid):
    self._comObj = comtypes.client.CreateObject(clsid, interface="IRtdServer")
    def connect(self):
    result = self._comObj.ServerStart(self)
    ...
    
    Получена ошибка:

    Код: Выделить всё

      File "test\test.py", line 13, in __init__
    self._comObj = comtypes.client.CreateObject(clsid, interface="IRtdServer")
    File "env\lib\site-packages\comtypes\client\__init__.py", line 238, in CreateObject
    obj = comtypes.CoCreateInstance(clsid, clsctx=clsctx, interface=interface)
    File "env\lib\site-packages\comtypes\__init__.py", line 1223, in CoCreateInstance
    p = POINTER(interface)()
    TypeError: Cannot create instance: has no _type_
    
    Код трассировки в библиотеке comtypes, который, казалось бы, указывает на то, что параметру интерфейса нужен класс интерфейса, а не строка. Я нашел различные интерфейсы, определенные в библиотеке comtypes: IDispatch, IPersist, IServiceProvider. Все они являются подклассами IUnknown. Согласно OleViewDotNet, IRTdServer также является подклассом IUnknown. Это наводит меня на мысль, что мне нужно аналогичным образом написать класс IRTdServer на Python, чтобы использовать интерфейс, но я не знаю, как это сделать.
  • Я заметил динамический параметр CreateObject. Код указывает, что это взаимоисключающее значение параметра интерфейса, поэтому я попробовал это:

    Код: Выделить всё

    def __init__(self, clsid):
    self._comObj = comtypes.client.CreateObject(clsid, dynamic=True)
    def connect(self):
    self._rtd = self._comObj.IRtdServer()
    result = self._rtd.ServerStart(self)
    
    Но ошибка такая же, как и моя исходная ошибка: IRtdServer имеет _ctypes.COMError: (-2147352570, «Неизвестное имя»., (Нет, Нет , Нет, 0, Нет))
Будем очень благодарны за любую помощь или подсказки. Заранее спасибо.



(Не совсем понимаю, что делаю) Я пытался использовать OleViewDotNet, чтобы посмотреть в DLL:

Изображение


Изображение


Изображение


[img]https://i. sstatic.net/dt5xC.png[/img]




Подробнее здесь: https://stackoverflow.com/questions/479 ... irtdserver
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Python»