当前位置:编程学习 > C#/ASP.NET >>

求救,哪位大佬可以帮我写一段代码

我想用VB做一个类似于excel的RTD (real_time_data )客户端。


有服务端的代码范例,来自微软。


建立範例 RealTimeData 伺服器
下列範例將告訴您,如何利用 Microsoft Excel 2002 建立和使用 RealTimeData 伺服器。此伺服器只會在工作表上提供每 10 秒更新一次的計數器。伺服器最多可接受兩個主題字串。第一個主題字串可以是 AAA、BBB 和 CCC,而任何其他主題字串會被視為無效,並且伺服器會傳回 #VALUE! 至 RTD 函數。第二個字串是數值,表示傳回值該如何遞增。如果省略第二個字串,遞增值會預設為 1;如果第二個字串不是數值,則伺服器會傳回 #NUM! 至 RTD 函數。 
在 Visual Basic 中開啟新的 ActiveX DLL 專案。
在 [專案] 功能表上,按一下 [參考],選取 Excel 的物件程式庫,然後按一下 [確定]。
在 Microsoft Excel 2002 中:[Microsoft Excel 10.0 物件程式庫]
在 Microsoft Office Excel 2003 中:[Microsoft Excel 11.0 物件程式庫]
在 [專案] 功能表上,按一下 [Project1 屬性]。將 [專案名稱] 變更為 ExcelRTD,然後按一下 [確定]。
將 Class1 類別模組的 Name 屬性變更為 RTDFunctions。將下列程式易做图加入至 RTDFunctions:
Option Explicit

Implements IRtdServer  'Inte易做图ce allows Excel to contact this RealTimeData server

Private m_colTopics As Collection
    
Private Function IRtdServer_ConnectData(ByVal TopicID As Long, Strings() As Variant, GetNewValues As Boolean) As Variant
    '** ConnectData is called whenever a new RTD topic is requested
    
    'Create a new topic class with the given TopicId and string and add it to the
    'm_colTopics collection
    Dim oTopic As New Topic
    m_colTopics.Add oTopic, CStr(TopicID)
    oTopic.TopicID = TopicID
    oTopic.TopicString = Strings(0)
    If UBound(Strings) >= 1 Then oTopic.SetIncrement Strings(1)
    
    'For this example, the initial value for a new topic is always 0
    IRtdServer_ConnectData = oTopic.TopicValue
    
    Debug.Print "ConnectData", TopicID
End Function

Private Sub IRtdServer_DisconnectData(ByVal TopicID As Long)
   '** DisconnectData is called whenever a specific topic is not longer needed
   
   'Remove the topic from the collection
   m_colTopics.Remove CStr(TopicID)
   
   Debug.Print "DisconnectData", TopicID
End Sub

Private Function IRtdServer_Heartbeat() As Long
    '** Called by Excel if the heartbeat interval has elapsed since the last time
    '   Excel was called with UpdateNotify.
    Debug.Print "HeartBeat"
End Function

Private Function IRtdServer_RefreshData(TopicCount As Long) As Variant()
    '** Called when Excel is requesting a refresh on topics. RefreshData will be called
    '   after an UpdateNotify has been issued by the server. This event should:
    '   - supply a value for TopicCount (number of topics to update)
    '   - return a two dimensional variant array containing the topic ids and the
    '     new values of each.
   
    Dim oTopic As Topic, n As Integer
    ReDim aUpdates(0 To 1, 0 To m_colTopics.Count - 1) As Variant
    For Each oTopic In m_colTopics
        oTopic.Update
        aUpdates(0, n) = oTopic.TopicID
        aUpdates(1, n) = oTopic.TopicValue
        n = n + 1
    Next
    TopicCount = m_colTopics.Count
    IRtdServer_RefreshData = aUpdates
   
   Debug.Print "RefreshData", TopicCount & " topics updated"
End Function

Private Function IRtdServer_ServerStart(ByVal CallbackObject As Excel.IRTDUpdateEvent) As Long
    '** ServerStart is called when the first RTD topic is requested
    
    Set oCallBack = CallbackObject
    Set m_colTopics = New Collection
    g_TimerID = SetTimer(0, 0, TIMER_INTERVAL, AddressOf TimerCallback)
    If g_TimerID > 0 Then IRtdServer_ServerStart = 1       'Any value <1 indicates failure.
    
    Debug.Print "ServerStart"
End Function

Private Sub IRtdServer_ServerTerminate()
    '** ServerTerminate is called when no more topics are needed by Excel.
    
    KillTimer 0, g_TimerID

    '** Cleanup any remaining topics. This is done here since 
    '   IRtdServer_DisconnectData is only called if a topic is disconnected 
    '   while the book is open. Items left in the collection when we terminate
    '   are those topics left running when the workbook was closed.

    Dim oTopic As Topic
    For Each oTopic In m_colTopics
        m_colTopics.Remove CStr(oTopic.TopicID)
        Set oTopic = Nothing
    Next

    Debug.Print "ServerTerminate"
  
End Sub



在 [專案] 功能表上,按一下 [加入類別模組]。將類別模組 Name 屬性變更為 Topic,並將 Instancing 屬性變更為 Private。將下列程式易做图加入至 Topic 類別模組:
Option Explicit

Private m_TopicID As Long
Private m_TopicString As String
Private m_Value As Variant
Private m_IncrementVal As Long

Private Sub Class_Initialize()
    m_Value = 0
    m_IncrementVal = 1
End Sub

Friend Property Let TopicID(ID As Long)
    m_TopicID = ID
End Property

Friend Property Get TopicID() As Long
    TopicID = m_TopicID
End Property

Friend Property Let TopicString(s As String)
    s = UCase(s)
    If s = "AAA" Or s = "BBB" Or s = "CCC" Then
        m_TopicString = s
    Else
        m_Value = CVErr(xlErrValue) 'Return #VALUE if not one of the listed topics
    End If
End Property

Friend Sub Update()
    On Error Resume Next 'the next operation will fail if m_Value is an error (like #NUM or #VALUE)
    m_Value = m_Value + m_IncrementVal
End Sub

Friend Sub SetIncrement(v As Variant)
    On Error Resume Next
    m_IncrementVal = CLng(v)
    If Err <> 0 Then
        m_Value = CVErr(xlErrNum) 'Return #NUM if Increment value is not numeric
    End If
End Sub

Friend Property Get TopicValue() As Variant
    If Not (IsError(m_Value)) Then
        TopicValue = m_TopicString & ": " & m_Value
    Else
        TopicValue = m_Value
    End If
End Property


在 [專案] 功能表上,選取 [加入模組]。將下列程式易做图加入至新的模組:
Public Declare Function SetTimer Lib "user32" (ByVal hWnd As Long, _
ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long

Public Declare Function KillTimer Lib "user32" (ByVal hWnd As Long, ByVal nIDEvent As Long) As Long

Public Const TIMER_INTERVAL = 5000
Public oCallBack As Excel.IRTDUpdateEvent
Public g_TimerID As Long

Public Sub TimerCallback(ByVal hWnd As Long, ByVal uMsg As Long, ByVal idEvent As Long, ByVal dwTime As Long)
    oCallBack.UpdateNotify
End Sub


在 [檔案] 功能表上,按一下 [建立 ExcelRTD.dll] 以建置元件。







--------------------编程问答-------------------- 以上范例可以执行,在EXCEL里可以自动加上数据。


现在想求哪位高手可以帮我写一段“客户端”的代码,不要调用EXCEL的RTD(),而是用COM在底层调用相关方法。

有一段用python写的代码,可以参考:



import pythoncom

from win32com import client, universal
from win32com.server.util import wrap

# Thanks to Chris Nilsson for these constants.
# Typelib info for Excel 2007.
EXCEL_TLB_GUID = '{00020813-0000-0000-C000-000000000046}'
EXCEL_TLB_LCID = 0
EXCEL_TLB_MAJOR = 1
EXCEL_TLB_MINOR = 6

# Register the two RTD inte易做图ces defined in the Excel typelib.
universal.RegisterInte易做图ces(EXCEL_TLB_GUID, 
                             EXCEL_TLB_LCID, EXCEL_TLB_MAJOR, EXCEL_TLB_MINOR,
                             ['IRtdServer','IRTDUpdateEvent'])
MAX_REGISTERED_TOPICS = 1024

class RTDClient(object):
    """
    Implements a Real-Time-Data (RTD) client for accessing
    COM datasources that provide an IRtdServer inte易做图ce.

     - Implements the IRTDUpdateEvent inte易做图ce and if used
       in event driven mode only calls RefreshData when
       new data is available.

    """

    _com_inte易做图ces_ = ['IRTDUpdateEvent']
    _public_methods_ = ['Disconnect', 'UpdateNotify']
    _public_attrs_ = ['HeartbeatInterval']

    def __init__(self, classid):
        self._classid = classid
        self._rtd = None

        self._data_ready = False

        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 = client.Dispatch(self._classid)
        self._rtd = client.CastTo(dispatch, 'IRtdServer')
        if event_driven:
            self._rtd.ServerStart(wrap(self))
        else:
            self._rtd.ServerStart(None)

    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.

        """
        if self._data_ready:
            self._data_ready = False
            self.refresh_data()
            return True
        else:
            return False

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

        """

        (ids, values), count = self._rtd.RefreshData(MAX_REGISTERED_TOPICS)
        for id, value in zip(ids, values):
            assert id in self._id_to_topic
            topic = self._id_to_topic[id]
            self._topic_values[topic] = value

    def get(self, topic):
        """
        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):
        """
        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)

    # Implementation of IRTDUpdateEvent.
    HeartbeatInterval = -1

    def UpdateNotify(self):
        self._data_ready = True

    def Disconnect(self):
        pass --------------------编程问答-------------------- VB就真不懂了~~~ --------------------编程问答-------------------- vb.net也行哦 --------------------编程问答-------------------- 要使用 Excel 的 RTD 函数,必须注册一个实现 IRTDServer 接口的COM组件。实现这个接口的COM组件就是所谓的RTD Server。IRTDServer具有以下成员:

ServerStart(CallbackObject)

CallbackObject 是一个IRTDUpdateEvent类型的参数,它有一个UpdateNotify方法,用于通知Excel有更新的数据可用(push)。这样Excel就会通过调用RefreshData方法来刷新所有的主题(pull)。当 Excel 请求RTD Server的第一个 RTD 主题时调用ServerStart方法,该方易做图在成功时返回 1,并在失败时返回负值或 0。这个方法在随后应用其他RTD函数时不会再次被调用。

ConnectData(TopicID, Strings, GetNewValues)

其中,TopcID 唯一标识这个函数在Excel中的一个应用,即使复制多份到不同的单元格,对于Excel来讲,也只是对应一个主题。这个 topicID 由Excel返回,我们需要将其记录下来,以便为其提供更新的数据。Strings 是一个System.Array,用于接收RTD函数传入的参数(String 1...String n),这是一个引用类型的参数。GetNewValues 用于确定是否总是获取最新数据,如果这个参数传入true,则每次保存Excel文档以后,再次重新打开时,看到的不一定是上次保存时的数据,而是最新的实时数据,这也是一个引用类型的参数。

每当一个新的主题(Topic)被应用到Excel,ConnectData都会被调用。在这里,需要保存传入的新的TopicID和查询参数以供之后更新数据使用。为此,需要定义好自己的数据结构。

DisconnectData(TopicID)

与ConnectData一样,TopcID 唯一标识这个函数在Excel中的一个应用。当我们从Excel中移除一个主题(删除所有采用相同参数的RTD函数)之后,DisconnectData将被调用,在这里,可以释放对这个主题的监控,并不再为其获取新数据。

Heartbeat

确定RTD Server是不是依然可用,0和负数代表不可用,1代表可用。Excel会调用此方法确定服务是否断连。

RefreshData(TopicCount)

TopicCount表示要更新的主题数量,这是一个引用类型的参数,用于返回给Excel。我们可以定义一个时钟,用于定时向数据源获取数据,这样,在时钟的Elapsed事件中,获取最新数据,并调用xlRTDUpdate成员的UpdateNotify方法以通知Excel,新的数据准备完毕。这样Excel就会调用RefreshData方法,来对工作簿中的数据进行更新。

ServerTerminate

当Excel不再需要从RTD Server获取实时数据时被调用。在这里,可以执行一些清理,例如清除缓存,关闭时钟等等。至此,一个RTD Server的生命周期就结束了。

 

--------------------编程问答-------------------- The Visual Basic .NET RTD Server
The RTD server that we will be building will be relatively 易做图. It will be a server that takes stock symbols and randomly updates the stock price. It will also take an argument to return the opening price for the stock (which doesn't get updated) or the last price for the stock (which gets updated randomly). This will allow us to worry less about the code that is doing the updates and concentrate more on the implementation of the components in Visual Basic .NET. In doing this, we will look at COM interoperability in Visual Basic .NET and go over the steps for using COM interoperability. We will also explore how to debug our Visual Basic .NET RTD server from the Visual Studio .NET Integrated Development Environment (IDE). 

Developing the Real-Time Data Server
To begin our Visual Basic .NET RTD server, we will first need to start Visual Studio .NET Beta 2 and create a new Visual Basic .NET Class Library project, naming it VBNetRTD. Once that is done, we will definitely want to rename the default class that Visual Basic .NET creates for us from Class1 to something more descriptive like StockQuote. We will also need to add a reference to the Microsoft Excel 10.0 Object Library; to do this, click Add Reference on the Project menu, click Add Reference, and click the COM tab. In the list, double-click Microsoft Excel 10.0 Object Library, and click OK.



Figure 1. The Add Reference dialog box (click image to see larger picture)

After clicking OK, you will get the following message: "Could not find a primary interop assembly for the COM component 'Microsoft Excel 10.0 Object Library.' A primary interop assembly is not registered for this type library. Would you like to have a wrapper generated for you?" You will need to click Yes to this dialog and allow Visual Basic .NET to create the interoperability assembly; otherwise, you won't be able to implement the IRTDServer inte易做图ce. Once this is done, a new assembly is created for you with the runtime callable wrappers that will be used to call the COM objects from the managed .NET environment. For more information and details on the import process and alternatives, see Importing a Type Library as an Assembly in the .NET Framework Developer's Guide.

Now that we have a reference to the Excel type library, we will build our RTD server component. In order to allow Excel types to be referenced directly without qualification—as well as some other namespaces that we'll need for our project—we'll add the following imports to the header of the class:

CopyImports Excel                           '<-- Excel object library
Imports System.Timers                   '<-- For our timers.
Imports System.Runtime.InteropServices  '<-- For our interop attributes. 
Imports System.Collections              '<-- For our collections of quotes. 

While it isn't required to use the Imports statements in our class, it greatly simplifies variable declaration because we don't have to fully qualify our object by namespace (for example, we can use Timer instead of System.Timers.Timer). Note that, unlike Visual Basic 6.0, simply adding a reference to the library will not allow us to do this. Instead, the reference includes the assembly in the compilation; in order to allow unqualified reference to types, the namespace (the closest equivalent in .NET to a type library) must be specifically imported in the very beginning of the class file. The Imports statement must precede any other declarations except Option statements. The Imports statement is not a replacement for adding references to required components.

Now that we have set up the imports, we will need to start implementing the IRTDServer inte易做图ce on our StockQuote class. Like Visual Basic 6.0, this is accomplished using the Implements keyword and specifying the inte易做图ce that we want to implement (IRTDServer). 

We'll also need to add some attributes to the class for use by COM Interop services: ProgID and ComVisible. 

The ProgID attribute allows you to specify the ProgID that will be used when the class is registered with COM. This is not required and, if not specified on the COM-registered class, the .NET Framework COM registration utility (regasm.exe) will create the ProgID for you. However, we want to control the ProgID and have it appear as Stock.Quote since it will be easier for us to train our end users to use it that way. 

The ComVisible attribute can also be applied to the assembly in the AssemblyInfo.vb file (to make all public classes visible or invisible to COM) or to individual classes (to make specific classes visible or invisible to COM). In our project, we will apply this only to the classes we want registered with COM (our RTD server class). 

The attributes that are associated with a class must also be on the same line of code as the class declaration (this holds true for subroutines and functions as well), so we will use the line continuation characters to make them a little more readable. Also, since our class will be used by COM, we'll need to make sure that we have a default constructor that takes no arguments. By the time we're done, our class looks like this:

CopyImports Excel                           '<-- Excel's object library.
Imports System.Timers                   '<-- For our timers. 
Imports System.Runtime.InteropServices  '<-- For our interop attributes. 
Imports System.Collections              '<-- For our collections of quotes.

<ComVisible(True), ProgId("Stock.Quote")> _
Public Class StockQuote
    Implements IRtdServer

    'Default constructor with no arguments. 
    'Required for COM interop. 
    Public Sub New()

    End Sub

End Class

Now that we have the class set up, we need to add the inte易做图ce members for the IRTDServer inte易做图ce. While we could type them in manually, we will allow the Visual Basic .NET IDE to create the procedure definitions for us. The process for this is exactly the same as in Visual Basic 6.0; select the inte易做图ce from the Class Name list on the left side of the code editor, and select each procedure from the Method Name list on the right side of the code editor. This allows us to quickly and easily define all of our procedures with the proper syntax and types. 

One significant difference between Visual Basic 6.0 and Visual Basic .NET that is readily apparent is the declaration of implemented methods. In Visual Basic 6.0, this would be a private method and named Inte易做图ceName_MethodName; for example, the RTD server's Heartbeat method would be declared Private Function IRTDServer_Heartbeat() as Long. In Visual Basic .NET, however, the implemented method is specified using the Implements keyword with the method and specifying the inte易做图ce and member that the function is implementing: Public Function Heartbeat() As Integer Implements Excel.IRtdServer.Heartbeat. By specifying the implemented function as Public, it will appear on both our RTD server's default inte易做图ce as well as on the IRTDServer inte易做图ce. If we don't want the function to be a member of the class's inte易做图ce, we would declare it as Private instead.
补充:.NET技术 ,  VB.NET
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,