简体   繁体   English

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

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

I'm trying to implement an RTD client using this project as an example, but without success.我试图以这个项目为例来实现一个 RTD 客户端,但没有成功。

Instance as RTD server the example contained in the win32com package below, and in Excel it works perfectly, but in the RTD client used as a template, it generates this error. Instance as RTD server 下面的 win32com 包中包含的示例,在 Excel 中它可以正常工作,但是在用作模板的 RTD 客户端中,它会生成此错误。

RTD client code 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()

The example RTD Server is Python.RTD.TimeServer and it works great in Excel, but the RTD client in the above example throws this error: File "C:\Users\XXXXXX\AppData\Local\Temp\gen_py\3.9\00020813-0000-0000-C000-000000000046x0x1x9.py", line 20963, in UpdateNotify return self.示例 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, 'Member not found.', None, None) oleobj .InvokeTypes(10, LCID, 1, (24, 0), (),) pywintypes.com_error: (-2147352573, '找不到成员。', None, None)

I have no knowledge of COM, but in the struggle to learn.我对COM一无所知,但在努力学习。

Any suggestions from friends?朋友有什么建议吗?

You need to implement all the methods defined by the IRTDServer interface.您需要实现 IRTDServer 接口定义的所有方法。

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

Once you do that excel should be able to find all methods it needs to work with your server.一旦你这样做了,excel应该能够找到它需要与你的服务器一起工作的所有方法。

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

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