簡體   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