Excel용 RealTimeData 서버를 만드는 방법

요약

Microsoft Excel은 데이터를 실시간으로 검색하기 위해 COM(구성 요소 개체 모델) 자동화 서버를 호출할 수 있는 새로운 워크시트 함수 RTD를 제공합니다. 이 문서에서는 Visual Basic을 사용하여 Excel의 RTD 함수에 사용할 RealTimeData 서버를 만드는 방법을 설명합니다.

추가 정보

RTD 워크시트 함수에는 다음 구문이 있습니다.

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

첫 번째 인수인 ProgID는 RealTimeData 서버의 ProgID(Programmatic Identifier)를 나타냅니다. 서버 인수는 RealTimeData 서버가 실행되는 컴퓨터의 이름을 나타냅니다. 이 인수는 Null 문자열이거나 RealTimeData 서버가 로컬로 실행되는 경우 생략할 수 있습니다. 나머지 인수는 RealTimeData 서버로 보낼 매개 변수만 나타냅니다. 이러한 매개 변수의 각 고유 조합은 연결된 "토픽 ID"가 있는 하나의 "토픽"을 나타냅니다. 매개 변수는 대/소문자를 구분합니다. 예를 들어 다음에서는 세 개의 개별 토픽 ID가 발생하는 RTD 서버에 대한 호출을 보여 줍니다.

=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 서버에서 업데이트를 수집해야 할 때 Excel에 알리는 데 사용하는 콜백 개체입니다.

  • ServerTerminate: Excel에서 RealTimeData 서버의 RTD 토픽이 더 이상 필요하지 않을 때 호출됩니다.

  • ConnectData: Excel에서 RealTimeData 서버에서 새 RTD 토픽을 요청할 때마다 호출됩니다.

  • DisconnectData: Excel에 특정 항목이 더 이상 필요하지 않을 때마다 호출됩니다.

  • 하트비트: 지정된 간격이 RealTimeData 서버의 업데이트 알림을 마지막으로 받은 이후 경과된 경우 Excel에서 호출됩니다.

  • RefreshData: Excel에서 토픽에 대한 새로 고침을 요청할 때 호출됩니다. RefreshData는 서버가 업데이트가 있음을 Excel에 알리고 각 토픽의 토픽 ID 및 값과 함께 업데이트할 항목 수를 반환한 후에 호출됩니다.

샘플 RealTimeData 서버 만들기

다음 샘플에서는 Microsoft Excel 2002에서 RealTimeData 서버를 만들고 사용하는 방법을 보여 줍니다. 이 서버는 워크시트에서 10초마다 업데이트되는 카운터를 제공합니다. 서버는 최대 두 개의 토픽 문자열을 허용합니다. 첫 번째 항목 문자열은 AAA, BBB 및 CCC일 수 있습니다. 다른 항목 문자열은 잘못된 것으로 간주되며 서버는 #VALUE! RTD 함수에 연결합니다. 두 번째 문자열은 반환 값을 증가시키는 방법을 나타내는 숫자 값입니다. 두 번째 문자열을 생략하면 증분 값은 기본적으로 1로 설정됩니다. 두 번째 문자열이 숫자가 아니면 서버는 #NUM! RTD 함수에 연결합니다.

  1. Visual Basic에서 새 ActiveX DLL 프로젝트를 시작합니다.

  2. 프로젝트 메뉴에서 참조를 클릭하고 Excel 버전에 대한 개체 라이브러리를 선택한 다음 확인을 클릭합니다. 예를 들어 다음 중 하나를 선택합니다.

    • 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로 변경한 다음 확인을 클릭합니다.

  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. 프로젝트 메뉴에서 클래스 모듈 추가를 클릭합니다. 클래스 모듈 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
    
  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에서 구성 요소의 런타임 버전을 사용하고 있었습니다. 디버깅을 위해 Visual Basic IDE에서 RTD 서버를 실행할 수 있습니다.

디버그 모드에서 실행하려면 다음을 수행합니다.

  1. Microsoft Excel을 종료하고 Visual Basic에서 프로젝트로 전환합니다.
  2. F5 키를 눌러 구성 요소를 시작합니다. 프로젝트 속성 대화 상자가 나타나면 [확인]을 클릭하여 구성 요소를 만들 때까지 대기의 기본 옵션을 선택합니다.
  3. Visual Basic의 직접 실행 창이 표시되는지 확인합니다. 셀에 수식을 입력하고 셀이 업데이트되면 Visual Basic에서 직접 실행 창의 내용을 검사하여 다른 이벤트를 트리거하는 작업을 확인합니다.

참고

DisconnectData 이벤트 관련

Excel은 RTD 서버의 구독자이지만 항목이 더 이상 필요하지 않을 때 DisconnectData 이벤트를 트리거합니다(예: 셀에서 RTD 수식을 삭제하거나 지우는 경우). 그러나 통합 문서가 닫혀 있거나 Excel이 종료되면 RTD 서버에 대한 각 항목에서 DisconnectData를 호출하지 않습니다. 대신 Excel에서는 ServerTerminate만 호출합니다. RTD 서버를 만들 때 ServerTerminate 이벤트가 발생할 때 필요한 토픽 또는 기타 개체 정리를 코딩해야 합니다.

(c) Microsoft Corporation 2001, All Rights Reserved. 기여: 로리 비 터너, Microsoft Corporation.