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


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


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


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

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

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

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

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

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

  • ServerTerminate: Excel で RealTimeData サーバーの RTD トピックが不要になったときに呼び出されます。

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

  • DisconnectData: Excel で特定のトピックが不要になったときに呼び出されます。

  • HeartBeat: Excel が RealTimeData サーバーからの更新を最後に通知してから、特定の間隔が経過した場合に Excel によって呼び出されます。

  • 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
            aUpdates(0, n) = oTopic.TopicID
            aUpdates(1, n) = oTopic.TopicValue
            n = n + 1
        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
    Debug.Print "ServerTerminate"
    End Sub
  5. [プロジェクト] メニューの [クラス モジュールの追加] をクリックします。 クラス モジュールの 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
            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
            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)
    End Sub
  7. [ファイル] メニューの [Make 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 で実行時バージョンのコンポーネントが使用されていました。 デバッグの目的で、VISUAL Basic IDE から RTD サーバーを実行できます。

デバッグ モードで実行するには:

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


DisconnectData イベントについて

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

(c) Microsoft Corporation 2001、All Rights reserved。 Lori B. Turner(Microsoft Corporation) による寄稿。