繁体   English   中英

实现 python RTD 客户端时出现 UpdateNotify 错误

[英]Getting UpdateNotify error when implementing a python RTD client

我试图以这个项目为例来实现一个 RTD 客户端,但没有成功。

Instance as RTD server 下面的 win32com 包中包含的示例,在 Excel 中它可以正常工作,但是在用作模板的 RTD 客户端中,它会生成此错误。

RTD 客户端代码

import functools

import pythoncom
import win32com.client
from win32com import universal
from win32com.client import gencache
from win32com.server.util import wrap


EXCEL_TLB_GUID = '{00020813-0000-0000-C000-000000000046}'
EXCEL_TLB_LCID = 0
EXCEL_TLB_MAJOR = 1
EXCEL_TLB_MINOR = 4

gencache.EnsureModule(EXCEL_TLB_GUID, EXCEL_TLB_LCID, EXCEL_TLB_MAJOR, EXCEL_TLB_MINOR)

universal.RegisterInterfaces(EXCEL_TLB_GUID,
                         EXCEL_TLB_LCID, EXCEL_TLB_MAJOR, EXCEL_TLB_MINOR,
                         ['IRtdServer', 'IRTDUpdateEvent'])


# noinspection PyProtectedMember
class ObjectWrapperCOM:

LCID = 0x0

def __init__(self, obj):
    self._impl = obj  # type: win32com.client.CDispatch

def __getattr__(self, item):
    flags, dispid = self._impl._find_dispatch_type_(item)
    if dispid is None:
        raise AttributeError("{} is not a valid property or method for this object.".format(item))
    return functools.partial(self._impl._oleobj_.Invoke, dispid, self.LCID, flags, True)


# noinspection PyPep8Naming
class RTDUpdateEvent:

   _com_interfaces_ = ['IRTDUpdateEvent']
   _public_methods_ = ['Disconnect', 'UpdateNotify']
   _public_attrs_ = ['HeartbeatInterval']

   # Implementation of IRTDUpdateEvent.
   HeartbeatInterval = -1

   def __init__(self, event_driven=True):
       self.ready = False
       self._event_driven = event_driven

   def UpdateNotify(self):
       if self._event_driven:
           self.ready = True

   def Disconnect(self):
       pass


class RTDClient:


 MAX_REGISTERED_TOPICS = 1024

 def __init__(self, class_id):
    """
    :param classid: can either be class ID or program ID
    """
    self._class_id = class_id
    self._rtd = None
    self._update_event = None

    self._topic_to_id = {}
    self._id_to_topic = {}
    self._topic_values = {}
    self._last_topic_id = 0

 def connect(self, event_driven=True):
    """
    Connects to the RTD server.

    Set event_driven to false if you to disable update notifications.
    In this case you'll need to call refresh_data manually.
    """

    dispatch = win32com.client.Dispatch(self._class_id)
    self._update_event = RTDUpdateEvent(event_driven)
    try:
        self._rtd = win32com.client.CastTo(dispatch, 'IRtdServer')
    except TypeError:
        # Automated makepy failed...no detailed construction available for the class
        self._rtd = ObjectWrapperCOM(dispatch)

    self._rtd.ServerStart(wrap(self._update_event))

 def update(self):
    """
    Check if there is data waiting and call RefreshData if necessary. Returns True if new data has been received.
    Note that you should call this following a call to pythoncom.PumpWaitingMessages(). If you neglect to
    pump the message loop you'll never receive UpdateNotify callbacks.
    """
    # noinspection PyUnresolvedReferences
    pythoncom.PumpWaitingMessages()
    if self._update_event.ready:
        self._update_event.ready = False
        self.refresh_data()
        return True
    else:
        return False

 def refresh_data(self):
    """
    Grabs new data from the RTD server.
    """

    (ids, values) = self._rtd.RefreshData(self.MAX_REGISTERED_TOPICS)
    for id_, value in zip(ids, values):
        if id_ is None and value is None:
            # This is probably the end of message
            continue
        assert id_ in self._id_to_topic, "Topic ID {} is not registered.".format(id_)
        topic = self._id_to_topic[id_]
        self._topic_values[topic] = value

 def get(self, topic: tuple):
    """
    Gets the value of a registered topic. Returns None if no value is available. Throws an exception if
    the topic isn't registered.
    """
    assert topic in self._topic_to_id, 'Topic %s not registered.' % (topic,)
    return self._topic_values.get(topic)

 def register_topic(self, topic: tuple):
    """
    Registers a topic with the RTD server. The topic's value will be updated in subsequent data refreshes.
    """
    if topic not in self._topic_to_id:
        id_ = self._last_topic_id
        self._last_topic_id += 1

        self._topic_to_id[topic] = id_
        self._id_to_topic[id_] = topic

        self._rtd.ConnectData(id_, topic, True)

 def unregister_topic(self, topic: tuple):
    """
    Un-register topic so that it will not get updated.
    :param topic:
    :return:
    """
    assert topic in self._topic_to_id, 'Topic %s not registered.' % (topic,)
    self._rtd.DisconnectData(self._topic_to_id[topic])

 def disconnect(self):
    """
    Closes RTD server connection.
    :return:
    """
    self._rtd.ServerTerminate()

示例 RTD 服务器是 Python.RTD.TimeServer,它在 Excel 中运行良好,但上面示例中的 RTD 客户端抛出此错误:文件“C:\Users\XXXXXX\AppData\Local\Temp\gen_py\3.9\00020813- 0000-0000-C000-000000000046x0x1x9.py”,第 20963 行,在 UpdateNotify 中返回自身。 oleobj .InvokeTypes(10, LCID, 1, (24, 0), (),) pywintypes.com_error: (-2147352573, '找不到成员。', None, None)

我对COM一无所知,但在努力学习。

朋友有什么建议吗?

您需要实现 IRTDServer 接口定义的所有方法。

https://docs.microsoft.com/en-us/dotnet/api/microsoft.office.interop.excel.irtdserver?view=excel-pia

一旦你这样做了,excel应该能够找到它需要与你的服务器一起工作的所有方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM