Excel 用の RealTimeData サーバーを作成する方法

概要

Microsoft Excel には、データをリアルタイムで取得するためにコンポーネントオブジェクトモデル (COM) オートメーションサーバーを呼び出すことができる新しいワークシート関数 RTD が用意されています。 この記事では、Visual Basic を使用して Excel の RTD 関数で使用する RealTimeData サーバーを作成する方法について説明します。

詳細

RTD ワークシート関数の構文は次のとおりです。

=RTD(ProgID,Server,String1,[String2],...)

最初の引数 ProgID は、RealTimeData サーバーのプログラム Id (ProgID) を表します。 Server 引数は、RealTimeData サーバーが実行されているコンピューターの名前を示します。RealTimeData サーバーをローカルで実行する場合は、この引数に null 文字列を指定することも、省略することもできます。 残りの引数は、単に RealTimeData サーバーに送信するパラメーターを表します。これらの各パラメーターの一意の組み合わせは、"topic id" と関連付けられた1つの "トピック" を表します。 パラメーターでは大文字と小文字が区別されます。 たとえば、次の例は、RTD サーバーへの呼び出しを示しています。これにより、3つの異なるトピック id が生成されます。

=RTD("ExcelRTD.RTDFunctions",,"AAA", "10")

=RTD("ExcelRTD.RTDFunctions",,"AAA", "5")

=RTD("ExcelRTD.RTDFunctions",,"aaa", "5")

COM オートメーションサーバーを Excel の RTD 関数で使用するために RealTimeData サーバーにするためには、IRTDServer インターフェイスを実装する必要があります。 サーバーは IRTDServer のすべてのメソッドを実装する必要があります。

  • ServerStart: Excel がサーバーの最初の RTD トピックを要求したときに呼び出されます。 ServerStart は、成功した場合は1を、失敗した場合は負の値または0を返します。 ServerStart メソッドの最初のパラメーターは、RealTimeData サーバーが RealTimeData サーバーから更新を収集する必要がある場合に Excel に通知するために使用するコールバックオブジェクトです。

  • Serverterminate: Excel が RealTimeData サーバーから RTD トピックを必要としなくなったときに呼び出されます。

  • Connectdata: Excel が RealTimeData サーバーから新しい RTD トピックを要求したときに呼び出されます。

  • データの削除: Excel が特定のトピックを必要としなくなったときに呼び出されます。

  • ハートビート: excel によって、RealTimeData サーバーからの更新の通知が前回行われてから、指定された時間が経過した場合に呼び出されます。

  • Refreshdata: トピックの更新を Excel が要求しているときに呼び出されます。 RefreshData は、サーバーが更新が存在することを Excel に通知した後に呼び出され、更新するトピックの数と、各トピックのトピック id と値を返します。

サンプルの RealTimeData サーバーを作成する

次の例は、Microsoft Excel 2002 で RealTimeData サーバーを作成して使用する方法を示しています。 このサーバーは、ワークシート上で10秒ごとに更新されるカウンターを提供するだけです。 サーバーは、最大2つのトピック文字列を受け取ります。 最初のトピック文字列は、AAA、BBB、および CCC とすることができます。その他のトピック文字列は無効とみなされ、サーバーは #VALUE を返します。 を RTD 関数に返します。 2番目の文字列は、戻り値を増分する方法を表す数値です。 2番目の文字列を省略すると、増分値の既定値は1になります。 2番目の文字列が数値ではない場合、サーバーは #NUM を返します。 を RTD 関数に返します。

  1. Visual Basic で新しい ActiveX DLL プロジェクトを開始します。

  2. [プロジェクト] メニューの [参照設定] をクリックし、使用しているバージョンの Excel のオブジェクトライブラリを選択して、[ OK] をクリックします。 たとえば、次のいずれかを選択します。

    • Microsoft Office Excel 2007 の場合は、[ Microsoft Excel 12.0 オブジェクトライブラリ] を選択します。
    • Microsoft Office Excel 2003 の場合は、[ Microsoft Excel 11.0 オブジェクトライブラリ] を選択します。
    • Microsoft Excel 2002 の場合は、[ Microsoft excel 10.0 オブジェクトライブラリ] を選択します。
  3. [プロジェクト] メニューの [Project1 のプロパティ] をクリックします。 プロジェクト名を ExcelRTD に変更し、[OK] をクリックします。

  4. クラスモジュール Class1 の Name プロパティを、RTDFunctions に変更します。 次のコードを RTDFunctions に追加します。

    Option Explicit
    
    Implements IRtdServer  'Interface 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
    
    
  5. [プロジェクト] メニューの [クラスモジュールの追加] をクリックします。 Class module Name プロパティを Topic に変更し、インスタンス化プロパティを 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
    
  6. [プロジェクト] メニューの [モジュールの追加] を選択します。 新しいモジュールに次のコードを追加します。

    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
    
  7. [ファイル] メニューの [ExcelRTD .dll の作成] をクリックして、コンポーネントを構築します。

Excel で RTD サーバーを使用する

  1. Microsoft Excel で新しいブックを開始します。

  2. セル A1 に次の数式を入力し、ENTER キーを押します。

    = RTD ("ExcelRTD. RTDFunctions",, "AAA", 5)

    最初の戻り値は "AAA: 0" です。 5秒後に、値は "AAA:10" に更新され、10秒後に値が更新され、"AAA:15" に更新されます。

  3. セル A2 に次の数式を入力し、enter キーを押します。

    = RTD ("ExcelRTD. RTDFunctions",, "BBB", 3)

    最初の戻り値は "BBB: 0" です。 5秒ごとにセル値は3ずつ増加します。

  4. セル A3 に次の数式を入力し、enter キーを押します。

    = RTD ("ExcelRTD. RTDFunctions",, "AAA", 5)

    最初の戻り値は、A1 で使用される "トピック" と同じなので、セル A1 の内容と一致します。

  5. セル A4 に次の数式を入力し、enter キーを押します。 = RTD ("ExcelRTD. RTDFunctions",, "AAA", 10)

    最初の戻り値は "AAA: 0" です。 5秒ごとに、セル値は他のセルと同じように増分します。 サーバーに渡されるパラメーターの組み合わせが異なるため、戻り値がセル A1 または A3 の内容と一致しないことに注意してください。

この図では、RTD サーバーがコンパイルされ、Excel がコンポーネントの実行時バージョンを使用しています。 デバッグを目的として、RTD サーバーを Visual Basic IDE から実行することができます。

デバッグモードで実行するには、次のようにします。

  1. Microsoft Excel を終了し、Visual Basic でプロジェクトに切り替えます。
  2. F5 キーを押してコンポーネントを開始します。 [プロジェクトのプロパティ] ダイアログボックスが表示されたら、[OK] をクリックして、コンポーネントが作成されるのを待機する既定のオプションを選択します。
  3. Visual Basic の [イミディエイト] ウィンドウが表示されていることを確認します。 セルに数式を入力し、セルが更新されたら、Visual Basic の [イミディエイト] ウィンドウの内容を調べて、さまざまなイベントをトリガーしているアクションを確認します。

注意

「データの切断」イベントについて

Excel は、RTD サーバーへのサブスクライバーですが、トピックが不要になった場合に、そのデータイベントをトリガーします (たとえば、セル内の RTD の数式を削除または消去した場合)。 ただし、Excel は、ブックが閉じられるか、または Excel が終了したときに、RTD サーバーの各トピックの無効なデータを呼び出しません。代わりに、Excel は ServerTerminate のみを呼び出します。 RTD サーバーを作成するときは、ServerTerminate イベントが発生したときに、トピックまたはその他のオブジェクトの必要なクリーンアップをコーディングする必要があります。

(c) Microsoft Corporation 2001、予約済みのすべての権利。 Lori Turner、Microsoft Corporation による貢献。