User Tools

  • Vistasource Document Library

RTW COM Interface

The Vistasource RTW COM Interface allow you to access the Vistasource RTW real-time engines, RTSHARE, or a custom engine from within your own COM applications or from Microsoft Excel (including VBA), enabling you to collect, manipulate and publish data through the DDS of your choice.

Sample applications are provided in the Application Directory under Samples\COM. We utilize these examples throughout the documentation as we unlock the power of the RTW COM Interface.

See also:

Components

The COM interface requires the Installation of RTW.
In addition to the RTW and RTSHARE product files, the following COM-related files are installed in the product directory:

File name Type Description
rts.exe Application The RTW COM Server
VSRtdServer.dll Application Extension RTW COM Interface DLL which is loaded by the RTW COM Interface
VSRtdServer.h Include file Needed to write C or C++ COM-based clients to connect to the RTW COM Server
VSRtdServer.tlb Type Library File Needed if using “smart pointers” in Visual C++ 5.0 or higher
VSRtdServer_i.c C file Compile and link this into C or C++ client applications

To register and unregister the RTW COM Server manually

The RTW COM Server is automatically registered during installation. In order to manually register or unregister it, enter the following arguments at the command line:

C:/<installdir>/rts –RegServer To register the RTW COM Server as “VistaSource.RtdServer”
C:/<installdir>/rts –UnregServer To unregister the RTW COM Server

Creating a VB Application

This section illustrates how to write a custom Visual Basic application using the RTW COM Interface.

Assuming that the RTW is installed, the types associated with the COM Interface can be accessed in a COM-compliant language, such as Visual Basic, C++, MS J++ etc.

The RTW COM Interface provides the “VSRtdServer 1.0 Type Library.” The following three methods are exposed by the COM Interface for use by the COM-based client:

  • VSRTConnectData
  • VSRTDisconnectData
  • VSRTRefreshData

Here is a closer look at these methods and their arguments.

The following argument description assumes that Visual Basic is used as the programming language. If you use other languages, you may need to enter the variables according to the conventions used by that language.

VSRTConnectData(TopicID, inStrings, GetNewValues, Status)

whereby

TopicIDis some unique value to represent your data request, e.g. 1234.
inStringsis an array of topics. The order and nature of these topics is fixed and resembles those used in the RTD function for Excel: Command,Engine,Service, Record, Field1,…Field n

whereby:

topic1 (Command) = “rt” for subscribing to data or “rtinsert” for publishing data.(For additional commands and their corresponding arguments see Appendix A “Additional RTW COM Interface Commands.”)

topic2 (Engine) = Name of the specific RTW engine which manages the communication between the COM-based client and the data distribution system.

Note: If topic1 (Command) is “rtinsert,” then topic2 is the value to publish. Subsequent topics simply shift down.

Note: To publish multiple values, topic2 must be a string, e.g. {val1, val2,…valn}, whereby val1 corresponds to topic5 (Field), val2 corresponds to topic6 (Field) and so on.

topic3 (Service name) = Name of the data feed/service available from the data distribution system. In a Reuters environment, this feed name may be something like IDN_SELECTFEED or DDS. In Bloomberg, it may be TICKERX.

topic4 (Record) = Name of the record of data to which you would like to subscribe or publish.

topic5…n (Field) = The name(s) of the field(s) you are interested in within the record, such as BID or ASK. If only one field is specified, a single value is returned. If multiple fields are specified, multiple values are returned. If you choose “rtinsert” as topic1, this field represents the value within the record you would like to publish.

Note: For more information on how to code these topics, see the sample code later in this section.
GetNewValues A Boolean value that is set to True.
Status The return code. 0 indicates success

VSRTDisconnectData(TopicID)

whereby

TopicIDis the value that represents the arbitrary, unique value used in the VSRTConnectData method that identifies the topic.

VSRTRefreshData(TopicCount, outStrings)

whereby

TopicCountis the number of elements returned in the array of outStrings
outStringsis a 2 dimensional array of variant values. The first dimension represents the unique topic ID(s) which corresponds to the TopicIDparameter in the VSRTConnectData method. The second dimension reflects the data you have requested. If you requested more than one field, the data comes back as a comma separated string in the following format: {field1, field2, field3,…}.

Summary:

The COM-based application communicates with the RTW COM Interface via the method VSRTConnectData, where the required data is defined.

If new data arrives at the RTW COM Interface from the real-time engine, the RTW COM Interface triggers an event called “VSUpdateNotify” which the COM-based client must make available. Sometimes called a “callback function,” this event informs the client that new data is available and, if so desired, calls the method VSRTRefreshData to accept and refresh the data displayed in the client application.

The method VSRTDisconnectData is used to disconnect the data being received.

Example:

This example illustrates a simple COM-based client application written in Visual Basic that features a dialog with a button for requesting real time data and an entry field for the incoming data.

For brevity, the code on how to create a dialog box with the button and entry field is skipped. If you are interested in stepping through an entire application, please see the Sample Application Quick Quote for more detailed information

1. In Visual Basic, click Project → References… to display a dialog box that contains a list of available type libraries. The list should contain the item “VSRtdServer 1.0 Type Library.” If it is toggled on, you can write the following:

Dim WithEvents vsrt_obj as VSRTDSERVERLib.VSControl

This line declares an “automation object” called 'vsrt_obj'. The 'WithEvents' identifier means that the object implements an event handler. After declaring the object and selecting it from the Object pull-down menu, you will see that the object implements the 'VSUpdateNotify event'. This event notifies the application of incoming data.

2. The following code example describes how real-time data is supplied in a dialog (called “form” in VB terminology) that has a button and an entry field. When the button is clicked, the record MSFT.O is subscribed with the field “ASK” using the vsRMDS2 engine and the IDN_SELECTFEED service. While the method VSRTConnectData simply subscribes to the data without returning it, the method VSRTRefreshData actually refreshes the data in the dialog:

Dim WithEvents vsrt_obj as VSRTDSERVERLib.VSControl
 
Private Sub Form_Load() 
' When the dialog loads, we create an 
' instance of the object. 
Set vsrt_obj = New VSRTDSERVERLib.VSControl 
End Sub
 
Private Sub Button_Click() 
Dim topic_id As Long 
Dim info(4) As Variant 
 
'NOTE to C Programmers: the number 4 
'represents the upper bound of the array, 
'not the number of elements! 
 
Dim new_vals As Boolean 
Dim result As Variant 
 
'When the button is clicked, subscribe to 
'the record MSFT.O with field 'ASK' 
'using the vsRMDS2 engine and the 
'IDN_SELECTFEED service. Note that the 
'VSRTConnectData call simply subscribes to 
'the data, nothing is returned. 
 
topic_id = 1234 
info(0) = "rt" 
info(1) = "vsRMDS2"
info(2) = "IDN_SELECTFEED"
info(3) = "MSFT.O" 
info(4) = "ASK" 
new_vals = True 
 
Call vsrt_obj.VSRTConnectData(topic_id, info, new_vals, result) 
End Sub 
 
'When the COM Server has retrieved some 
'data, it calls UpdateClient() which 
'triggers the following callback. We can 
'now decide whether we want to do 
'something with the data. In this case, we 
'stick it in the entry field. 
 
Private Sub vsrt_obj_VSUpdateNotify() 
Dim data() As Variant 
Dim topic_count as Long 
 
Call vsrt_obj.VSRTRefreshData(topic_count, data) 
If UBound(data) > 0 Then 
 TextBox.Text = data(1, 0) 
 End If 
End Sub

Commands

Sample Applications

Below are some VB and C++ examples covering subscription and publishing

Subscription

The following example of a VB application shows how to create a simple form with fields for real-time data supplied by one of the RTW engines.

It is similar to the example application is supplied in
[Application Directory]\Samples\ COM \Visual Basic\QuickQuote.

How to write a Sample Subscription Application

1. Open Visual Basic.

2. Create a new project with the type 'Standard Exe', by selecting the standard EXE icon (Figure A).

Figure A

3. Before you begin to program, you must reference the Vistasource RTD Server library (VSRtdServer 1.0 Type Library). See Figure B.

a. From the menu bar, select Project → References.
b. Scroll down the list and check the box that has VSRtdServer 1.0 Type Library

Figure B

4. Below is an example of a toolbox view. We will use a Label, TextBox, CommandButton, and Combo Box for the QuickQuote Visual Basic Application. See Figure C.

Figure C

5. Create a combo box on the form for the engine. Activate the Properties window: Select View → Properties, or F4 or right-click on Properties. Change the button's (Name) Property to ENGINE. See Figure D.

Figure D

Then change the style to the Engine ComboBox to 2 –Dropdown List.

6. Create a Label next to ComboBox and change the (Name) to EngineLabel and the Caption to Engine.

7. Create the following 5 text boxes and 5 labels as described in the table below. Align the Text Boxes and Labels as in Figure E. The text property for the Text Boxes and the caption property for the Labels will be set in the code.

DESCRIPTION TEXT BOX (NAME) LABEL (NAME)
1 To Enter a RICRICRICLabel
2 Name DSPLY_NAME DISPLAYNAME
3 BID BIDVALUE BID
4 ASK ASKVALUE ASK
5 TRADE PRICE TRDPRC_1 TRADEPRICE

Figure E

8. Create two Command Buttons. For the first button, set the (Name) to Quote and the Caption to Get Quote. For the second button, set both the (Name) and Caption to Close. Your final form should look like Figure F. You can add graphics to the form.

Figure F

9. To start programming, double-clicked anywhere in the form. You will get a code sheet. Before all the procedures, at the top of the code sheet, enter the following three lines:

 Dim WithEvents vsrt As VSRTDSERVERLib.VSControl 
 Dim Topic_Id As Long 
 Dim MyEngine As String 

10. To declare values for the form text boxes and labels, add the following code to the Private Sub Form_Load() procedure:

Private Sub Form_Load() 
On Error Goto nocom 
Set vsrt = New VSRTDSERVERLib.VSControl 
 
'Define Engine Combo Box 
 
engine.AddItem ("mktdemo") 
engine.AddItem ("RMDS ssl") 
engine.AddItem ("Bloomberg") 
engine.AddItem ("WebData via Yahoo") 
Engine.Text = "mktdemo" 
 
'Define Labels Captions 
RIC.ToolTipText = "Record name" 
EngineLabel.Caption = "ENGINE" 
RICLabel.Caption = "RECORD" 
DISPLAYNAME.Caption = "COMPANY" 
BID.Caption = "BID" 
ASK.Caption = "ASK" 
TRADEPRICE.Caption = "TRADE PRICE" 
Form1.Caption = "VistaSource RealTime QuickQuote" 
Topic_Id = 1 'Global Identifier 
Exit Sub 
nocom: 
MsgBox "An error has occured. You may not have connection a COM license" & _
Chr(13) & "or you do not have a connection to RMDS ",vbCritical, _ 
"Error in Application headlines." 
End Sub

11. Go back to the form, double-click on the CLOSE button. Type the command Unload Me inside the Sub Close_Click() routine. This routine will performed when the user clicks on this button. Unload statement removes the named object from memory.

Private Sub Close_Click() 
Unload Me 'Exit Application 
End Sub 

12. Now double-click on the Quote button and enter the following command inside the Sub Quote_Click( ) routine:

Private Sub Quote_Click() 
Call GetQuote 
End Sub 

13. Create a subroutine called GetQuote which gets the quote for the record that is entered.

Private Sub GetQuote() 
'Declared Variables 
 
 Dim info() As Variant 
 Dim new_vals As Boolean 
 Dim result As Variant 
 Dim RIC_STR As String 
 
 'Getting the Quote for the record entered. 
 ' If no record was entered, then display error message 
 'Else 
 ' Get QUOTE from the appropriate Engine. 
 
 DSPLY_NAME.Text = "" 
 BIDVALUE.Text = "" 
 ASKVALUE.Text = "" 
 TRDPRC_1.Text = "" 
 
 If RIC.Text = "" Then 
 MsgBox "No record was entered" 
 RIC.SetFocus 
 Else 
 RIC_STR = UCase(RIC.Text) 
 
 Select Case LCase(engine.Text) 
 Case "mktdemo" 
    info = Array("rt", "mktdemo","IDN_SELECTFEED", RIC_STR, "DSPLY_NAME", "BID", "ASK", "TRDPRC_1") 
 
 Case "rmds ssl" 
    info = Array("rt", "vsrmds", "IDN_SELECTFEED", RIC_STR, "DSPLY_NAME", "BID", "ASK", "TRDPRC_1") 
 
 Case "webdata via yahoo" 
    info = Array("rt", "rthttp", "Yahoo", RIC_STR, "NAME", "BID", "ASK", "LAST") 
 
 Case "bloomberg" 
    Index = InStr(1, RIC_STR, "EQUITY") 
    If Index = 0 Then 
       RIC_STR = RIC_STR & " Equity" 
    Else 
       RIC_STR = Replace(RIC_STR, "EQUITY", "Equity") 
    End If 
    info = Array("rt", "axbloom", "TICKERX", RIC_STR, "Name", "Bid Price", "Ask Price", "Last Trade") 
    RIC.Text = "" 
 End Select 
 
 RIC.Text = RIC_STR 
 new_vals = True 
 
 'Check to see if the same engine is being used. If 
 'so, do not restart engine. 
 
 If MyEngine = LCase(engine.Text) Then 
    Topic_Id = Topic_Id + 1 
    Call vsrt.VSRTConnectData(Topic_Id, info, new_vals, result) 
    Call vsrt.VSRTDisconnectData(Topic_Id - 1) 
    'disconnect the old record 
 Else 
    Call vsrt.VSRTDisconnectData(Topic_Id) 'disconnect the old record 
    Topic_Id = 1 
    Call vsrt.VSRTConnectData(Topic_Id, info, new_vals, result) 
    MyEngine = LCase(engine.Text) 
 End If 
 End If 
End Sub 

14. Next, create a subroutine to update the entry box when new data arrives from the RTW COM Interface.

Private Sub vsrt_VSUpdateNotify() 
Dim TOPIC_COUNT As Long 
Dim data() As Variant 
 
Call vsrt.VSRTRefreshData(TOPIC_COUNT, data) 
 
If TOPIC_COUNT > 0 Then 
'Parse data to put into entry box 
result = data(1, 0) 
result = Replace(result, "{", "") 
result = Replace(result, "}", "") 
result = Replace(result, Chr(34), "") 
SPLITSTR = Split(result, ",", 4) 
DSPLY_NAME.Text = SPLITSTR(0) 
BIDVALUE.Text = SPLITSTR(1) 
ASKVALUE.Text = SPLITSTR(2) 
TRDPRC_1.Text = SPLITSTR(3) 
End If 
End Sub 

15. The final code sheet should look similar to this:

Dim WithEvents vsrt As VSRTDSERVERLib.VSControl 
Dim Topic_Id As Long 
Dim MyEngine As String 
 
Private Sub Close_Click() 
 Unload Me 'Exit Application 
End Sub 
 
Private Sub engine_Change() 
 
End Sub 
 
Private Sub Form_Load() 
 On Error GoTo nocom 
 Set vsrt = New VSRTDSERVERLib.VSControl 
 
 'Define Engine Combo Box 
 
 engine.AddItem ("mktdemo") 
 engine.AddItem ("RMDS ssl") 
 engine.AddItem ("Bloomberg") 
 engine.AddItem ("WebData via Yahoo") 
 
 engine.Text = "mktdemo" 
 RIC.Text = "MSFT.O" 
 engine.ToolTipText = "Select Engine to Connect" 
 
 'Define Labels Captions 
 RIC.ToolTipText = "Record name" 
 EngineLabel.Caption = "ENGINE" 
 RICLabel.Caption = "RECORD" 
 DISPLAYNAME.Caption = "COMPANY" 
 BID.Caption = "BID" 
 ASK.Caption = "ASK" 
 TRADEPRICE.Caption = "TRADE PRICE" 
 Form1.Caption = "VistaSource RealTime QuickQuote" 
 Topic_Id = 1 'Global Identifier 
 Exit Sub 
nocom: 
 MsgBox "An error has occured. You may not have connection 
 a COM license" & _ Chr(13) & "or you do not have a 
 connection to RMDS", vbCritical, _"Error in Application 
 headlines." 
 End 
End Sub 
 
Private Sub GetQuote() 
'Declared Variables 
 
 Dim info() As Variant 
 Dim new_vals As Boolean 
 Dim result As Variant 
 Dim RIC_STR As String 
 
 'Getting the Quote for the record entered. 
 ' If no record was entered, then display error message 
 'Else 
 ' Get QUOTE from the appropriate Engine. 
 
 DSPLY_NAME.Text = "" 
 BIDVALUE.Text = "" 
 ASKVALUE.Text = "" 
 TRDPRC_1.Text = "" 
 
 If RIC.Text = "" Then 
 MsgBox "No record was entered" 
 RIC.SetFocus 
 Else 
 RIC_STR = UCase(RIC.Text) 
 
 Select Case LCase(engine.Text) 
 Case "mktdemo" 
    info = Array("rt", "mktdemo","IDN_SELECTFEED", RIC_STR, "DSPLY_NAME", "BID", "ASK", "TRDPRC_1") 
 
 Case "rmds ssl" 
    info = Array("rt", "vsrmds", "IDN_SELECTFEED", RIC_STR, "DSPLY_NAME", "BID", "ASK", "TRDPRC_1") 
 
 Case "webdata via yahoo" 
    info = Array("rt", "rthttp", "Yahoo", RIC_STR, "NAME", "BID", "ASK", "LAST") 
 
 Case "bloomberg" 
    Index = InStr(1, RIC_STR, "EQUITY") 
    If Index = 0 Then 
       RIC_STR = RIC_STR & " Equity" 
    Else 
       RIC_STR = Replace(RIC_STR, "EQUITY", "Equity") 
    End If 
    info = Array("rt", "axbloom", "TICKERX", RIC_STR, "Name", "Bid Price", "Ask Price", "Last Trade") 
    RIC.Text = "" 
 End Select 
 
 RIC.Text = RIC_STR 
 new_vals = True 
 
 'Check to see if the same engine is being used. If 
 'so, do not restart engine. 
 
 If MyEngine = LCase(engine.Text) Then 
    Topic_Id = Topic_Id + 1 
    Call vsrt.VSRTConnectData(Topic_Id, info, new_vals, result) 
    Call vsrt.VSRTDisconnectData(Topic_Id - 1) 
    'disconnect the old record 
 Else 
    Call vsrt.VSRTDisconnectData(Topic_Id) 'disconnect the old record 
    Topic_Id = 1 
    Call vsrt.VSRTConnectData(Topic_Id, info, new_vals, result) 
    MyEngine = LCase(engine.Text) 
 End If 
 End If 
End Sub 
 
Private Sub Quote_Click() 
 Call GetQuote 
 
End Sub 
 
Private Sub QuoteCommand_Click() 
 Call GetQuote 
End Sub 
 
Private Sub vsrt_VSUpdateNotify() 
 Dim TOPIC_COUNT As Long 
 Dim data() As Variant 
 
 Call vsrt.VSRTRefreshData(TOPIC_COUNT, data) 
 
 If TOPIC_COUNT > 0 Then 
 'Parse data to put into entry box 
 result = data(1, 0) 
 result = Replace(result, "{", "") 
 result = Replace(result, "}", "") 
 result = Replace(result, Chr(34), "") 
 SPLITSTR = Split(result, ",", 4) 
 DSPLY_NAME.Text = SPLITSTR(0) 
 BIDVALUE.Text = SPLITSTR(1) 
 ASKVALUE.Text = SPLITSTR(2) 
 TRDPRC_1.Text = SPLITSTR(3) 
 End If 
End Sub

16. Save the Visual Basic Application by selecting File → Save Project. The first dialog box is the Save Form dialog box. Name the form as VistaSource_QuickQuote_Form. Note the file has the .frm extension

A second dialog box Save Project is displayed. Name the project as VistaSource_QuickQuote. This will have the .vbp extension.

17. Optionally, you can make an executable file, by selecting File → Make VistaSource_QuickQuote.exe.

18. To run the program, either from the menu by selecting Run → Start or pressing F5 key or the icon.

Publishing

The following sample code illustrates how to create a simple form with two text boxes for publishing with the RTW COM Interface. In the first text box, enter the value you would like to publish. The second text box displays the confirmation “OK”, if the publishing was successful or the error message “NA”, if it failed. This sample was created using VB 6.0.

1. Start a new Standard EXE project in Visual Basic. Form1 is created by default.

2. Before you begin to program, you must reference the Vistasource RTD Server library (VSRtdServer 1.0 Type Library).

a. From the menu bar, select Project →References.
b. Scroll down the list and check the box that has VSRtdServer 1.0 Type Library.

3. Add 2 TextBoxes and CommandButton to Form1. The Text1 object represents the publishing value, Text2 displays the result after the CommandButton is pressed. Text2 will display OK if publishing succeeded or NA if it failed.

4. Copy the following code to the Code window of Form1:

 Option Explicit 
 Dim WithEvents vsrt As VSRTDSERVERLib.VSControl 
 
 Private Sub Form_Load() 
 Set vsrt = New VSRTDSERVERLib.VSControl 
 End Sub 
 
 Private Sub Command1_Click() 
 
 'Declared Variables - You will need to change these 
 'The Engine is vsrmds2 - RMDS RFA engine 
 'The Service is DTS 
 'The Record is TestRic
 'The Field is ASK 
 
 Dim info(5) As Variant 
 Dim new_vals As Boolean 
 Dim result As Variant 
 Dim Value As String 
 
 info(0) = "rtinsert" 'publish mode 
 info(1) = Text1.Text 'insert value 
 info(2) = "vsrmds2" 'engine 
 info(3) = "DTS" 'service 
 info(4) = "MEWTEST" 'record 
 info(5) = "ASK" 'published field 
 new_vals = True 
 Call vsrt.VSRTConnectData(1, info, new_vals, result) 
End Sub 
 
Private Sub vsrt_VSUpdateNotify() 
 Dim TOPIC_COUNT As Long 
 Dim data() As Variant 
 Dim result As Integer 
 Call vsrt.VSRTRefreshData(TOPIC_COUNT, data) 
 
 If TOPIC_COUNT > 0 Then 
 'Parse data to put into entry box 
 On Error GoTo NA 
 
 Text2.Text = data(1, 0) 
 Exit Sub 
NA: 
 Text2.Text = "NA" 
 End If 
End Sub




C++ Client

This sample illustrates how to build a C++ client application (using MFC) that connects to the Pre-Recorded Playback “mktdemo” engine for retrieving the trade price (TRDPRC_1) of a particular record. The incoming data is displayed in an entry field in a dialog box. This sample was created using Microsoft Visual C++ 6.0.

For information on how to write a C++ COM client application, refer to the following links:

http://www.microsoft.com/com/default.mspx

http://www.vistasource.com/doc/drgui/drgui.html

The easiest way to build a C++ application that uses the RTW COM Interface is to use the MFC AppWizard. There are four main steps to consider when building a MFC client.

  • Create a project (Advanced users may want to skip to Step 2).
  • Create a dialog box.
  • Write the code that drives the dialog box.
  • Create a sink object that will receive update notifications from the COM server.
Step 1: Create a Project

To create a MFC AppWizard (exe) project in C++:

1. Open Visual C++.

2. Choose File →New.

3. Select MFC App Wizard (exe) in the Projects tab.

4. Type a project name. This sample uses the name VSClient.

5. Click OK.

The dialog box MFC AppWizard - Step 1 is displayed, asking what type of application would you like to create?

6. Select Dialog based and click Next.

The dialog box MFC AppWizard - Step 2 is displayed, asking what other support would you like to include?

7. Make sure both Automation and ActiveX Controls are selected.

8. Click Finish.

After clicking the Finish button, the App Wizard will create a skeleton project and display a starter dialog box

Step 2: Create a Dialog Box
If you skipped Step 1, make sure the project name is VSClient, the MFC project is a Dialog Based application and supports Automation and ActiveX Controls.

In the dialog box, you need to do the following:

1. Create two Edit Box controls and one Button control.

2. Change one Edit Box control ID to IDC_DATA and give it a read-only style. This is the entry field that will receive the incoming data. To do so, right-click on the Edit Control and select Properties. In the Properties dialog box, select the General tab and change ID to IDC_DATA. On the Styles tab, select Read-Only. Close the dialog box.

3. Similarly, change the other Edit Box control ID to IDC_RECORD. This is the entry field in which the record name will be typed.

4. Change the Button control ID to IDC_CONNECT and change the Caption to “Connect”. This button needs to be a default button which initiates the connection to the COM server and makes the request. To do so, select the General tab in the Properties dialog box and change ID to IDC_CONNECT and the Caption to “Connect”. On the Styles tab, select “Default Button”. Close the dialog box.

5. Create a function for the Connect button by double-clicking on it. The member function name should be OnConnect. Press OK. Information on how to create the function will follow later in this document.

6. Delete the OK button.

The dialog box is now complete and the code behind it can now be written.

Step 3: The Code behind the dialog box

Writing the code behind the dialog box consists of two phases:

  • Create header files and global variables
  • Fill out the member functions.

Create header files and global variables

To create the header files and global variables:

1. Open the source file VSClientDlg.cpp via the FileView button on the left.

2. Add the following global variables:

 IVSControl *m_pSrc; 
 VSSink *m_pSink; 
 DWORD m_dwCookie; 
 long TopicID = 1; 
 
 bool is_connected = false; 
 CEdit* pEditData; 

The first four variables are necessary to connect to the server:

  • m_pSrc is a pointer to an instance of the COM object.
  • m_pSink is a pointer to the sink object VSSink (which will be created later).
  • m_dwCookie stores the number of connections that have been established.
  • TopicID is a unique ID for the data request.

The last two variables are used to check for server connection and for the placement of the incoming data:

  • is_connected is used to check for an already established connection to the server.
  • pEditData is a pointer to the IDC_DATA Edit Box for incoming data placement.

3. In addition, the following files need to be included: ATLBASE.H, afxctl.h, VSSink.h, and VSRtdServer_i.c (the latter file contains the COM object declarations):

The top of the VSClientDlg.cpp source file should look like this:

#include "stdafx.h" 
#include <ATLBASE.H> 
#include "VSClient.h" 
#include "VSClientDlg.h" 
#include "VSSink.h" 
#include "DlgProxy.h" 
#include "VSRtdServer_i.c" 
#include <afxctl.h> 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
IVSControl *m_pSrc; 
MFCSink *m_pSink; 
DWORD m_dwCookie; 
long TopicID = 1; 
bool is_connected = false; 
CEdit* pEditData;

Fill out the member functions

To fill out the member functions, complete the following steps:

1. Assign the pEditData pointer to the IDC_DATA edit box. This is necessary to be able to insert values into the entry field. In the function CVSClientDlg::OnInitDialog() insert the following statement below the line “TODO: Add extra initialization here: ”

 pEditData = (CEdit*)GetDlgItem(IDC_DATA); 

2. Fill out the OnConnect function that was assigned to the Connect button. The connection to the RTW COM Interface and the request for data happen here. In the function CVSClientDlg::OnConnect(), add the following code:

 // Check to see if a record is entered in the Record Edit Box. 
 // If there is a record then assign a pointer to the Record Edit Box. 
 
 CEdit* pEditRecord = (CEdit*)GetDlgItem(IDC_RECORD); 
 CString strRecord; //Declare a variable to hold the entered text; 
 pEditRecord->GetWindowText(strRecord); 
 
 if(strRecord.IsEmpty() == TRUE) 
 { 
 
 MessageBox("No record is entered"); 
 return; 
 } 
 // Trim the blanks to the right and left of the record. 
 // Convert CString to char * 
 
 strRecord.TrimLeft(" "); 
 strRecord.TrimRight(" "); 
 pEditRecord->SetWindowText(strRecord); 
 
 LPTSTR lpszRecord = new TCHAR[strRecord.GetLength()+1]; 
 _tcscpy(lpszRecord, strRecord); 
 
 HRESULT hr; 
 
 // Declare variables needed for VSRtdServer VSRTConnectData 
 VARIANT varResult; 
 VARIANT_BOOL GetNewValues = -1; 
 varResult.vt = VT_I2; //needed to make the VSRtdConnect; 
 
 SAFEARRAY * psa = NULL; 
 SAFEARRAYBOUND rgsabound[1]; 
 rgsabound[0].lLbound = 0; 
 
 rgsabound[0].cElements = 5; 
 psa = SafeArrayCreate(VT_VARIANT, 1, rgsabound); 
 
 if(psa == NULL) 
 
 { 
 AfxMessageBox("Error in initializing array"); 
 exit(-1); 
 } 
 
 long Idx=0; 
 
 char *items[] = {"rt","mktdemo","IDN_SELECTFEED",lpszRecord,"TRDPRC_1"}; 
 
 CComVariant name; 
 for (Idx=0; Idx<5; Idx++) 
 { 
 name = items[Idx]; 
 hr = SafeArrayPutElement(psa, &Idx, (void *) &name); 
 if (FAILED(hr)) 
 { 
 AfxMessageBox("Error in array elements"); 
 exit(-1); 
 } 
 } 
 
 // check if we have all ready connected to the engine. 
 // If you have multiple engines, you can put your codes here. 
 
 if(is_connected) 
 { 
 TopicID++;hr = m_pSrc->VSRTConnectData(TopicID,&psa, 
 &GetNewValues,&varResult); 
 if(FAILED(hr)) 
 { 
 AfxMessageBox("Failed to connect to engine"); 
 CoUninitialize(); 
 return; 
 } 
 m_pSrc->VSRTDisconnectData(TopicID-1); 
 return; 
 } 
 
 // Begin COM connection to VSRtdServer. 
 
 CoInitialize(NULL); //initialize COM system 
 m_pSink=new VSSink; //create an instance of the sink object 
 
 //Create the COM object 
 
 hr=CoCreateInstance(CLSID_VSControl,NULL, 
 CLSCTX_ALL,IID_IVSControl, 
 reinterpret_cast<void **>(&m_pSrc)); 
 if(FAILED(hr)) 
 { 
 AfxMessageBox("Unable to create control"); 
 return; 
 } 
 
 m_dwCookie=1; 
 
 //Establish the connection to the engine. 
 
 hr = m_pSrc->VSRTConnectData(TopicID,&psa,&GetNewValues,&varResult); 
 if(FAILED(hr)) 
 { 
 AfxMessageBox("Failed to connect to engine"); 
 CoUninitialize(); 
 return; 
 } 
 
 //Establish the sink (this is our update events) 
 
 LPUNKNOWN m_pUnk=m_pSink->GetIDispatch(FALSE); 
 if(AfxConnectionAdvise(m_pSrc,DIID__IVSControlEvents,m_pUnk, 
 FALSE,&m_dwCookie)) 
 
 { 
 is_connected = true; 
 pEditData->SetWindowText(""); 
 return; 
 } 
 else 
 return; 

3. Now you can write the function that will retrieve the data and display it in the dialog box.

When the RTW COM Interface receives data, it will trigger an event, which will be captured by the sink object we write in Step 4 (see below). The sink object will then have to call into the dialog box for the data to be retrieved and displayed.

a. Using the Class View tab, right-click on the CVSClientDlg interface and select Add Member Function.

b. The Function Type: void

c. The Function Declaration: UpdateEvent

d. Access: Public

e. Press OK.

f. Now you should be in the UpdateEvent function. Add the following code to the UpdateEvent function:

 //Get call when update arrived from file VSSink.cpp 
 
 SAFEARRAY * psa; 
 long TopicCount; 
 long aiIndex[2]; //Declare array equal to the number of bounds 
 long idx = -1; 
 CString str; 
 
 SAFEARRAYBOUND rgsabound[2]; 
 psa=SafeArrayCreate(VT_VARIANT, 2, rgsabound); 
 
 HRESULT hr = m_pSrc->VSRTRefreshData(&TopicCount,&psa); 
 if(SUCCEEDED(hr)) 
 { 
 
 CComVariant variant; 
 VariantInit(&variant); 
 
 aiIndex[0] = 0; 
 aiIndex[1] = 0; 
 hr = SafeArrayGetElement(psa,aiIndex,&variant); 
 
 if(variant.intVal = TopicID) 
 { 
 aiIndex[0] = 1; 
 aiIndex[1] = 0; 
 
 hr = SafeArrayGetElement(psa,aiIndex,&variant); 
 
 if(variant.dblVal < 0) 
 goto CLEARVARIANT; 
 str.Format("%f",variant.dblVal); pEditData->SetWindowText(str); 
} 
 
 CLEARVARIANT: 
 
VariantClear(&variant); 
 } 

4. Next, we will write a disconnect function, which will run when the dialog box is destroyed. A proper disconnect from the RTW COM Interface is required. To do so:

a. Using the ClassView tab, right-click on the CVSClientDlg interface and select Add Member Function.

b. The Function Type: void

c. The Function Name: DisconnectData

d. Access: Public

e. Press OK.

f. In DisconnectData function, add the following code:

 if(m_pSrc==NULL) return; 
 
 LPUNKNOWN m_pUnk=m_pSink->GetIDispatch(FALSE); 
 
 AfxConnectionUnadvise(m_pSrc,DIID__IVSControlEvents,m_pUnk, 
 FALSE,m_dwCookie); 
 if(m_pSink!=NULL) 
 { 
 m_pSrc->Release(); 
 delete m_pSink; /* the m_pSink destructor must be a public 
 variable */ 
 m_pSink=NULL; 
 m_pSrc=NULL; 
 CoUninitialize(); 
 
 is_connected = false; 
 } 

5. Finally, add a message handler to disconnect the data when the dialog box is destroyed:

a. Using the ClassView tab, right-click on the CVSClientDlg interface and select Adds Windows Message Handler.

b. In the New Windows Message and Event Handlers for class CVSClientDlg window, select WM_DESTROY and click on Add Handler. Then click OK. You should now see OnDestroy in the Class View tab.

c. Using the Class View tab, double-click on the OnDestroy function. This should bring you to the code.

d. Add the DisconnectData(); statement to the CVSClientDlg::OnDestroy () function. Now the OnDestroy() function should looks like:

 void CVSClientDlg::OnDestroy() 
 { 
 CDialog::OnDestroy(); 
 DisconnectData(); 
 } 
Step 4: Create a sink object to connect to the VSRtdServer update events

To create a sink object that will receive update notifications from the RTW COM Interface, complete the following steps:

1. Use the ClassWizard (Ctrl+W) to create a new class by selecting Add Class →New in this dialog.

2. Give it a name (i.e. VSSink).

3. For the Base Class, use the drop-down list to select the CCmdTarget.

4. Select the Automation radio button and the click OK in this dialog.

5. Import the VSRtdServer.dll in the StdAfx.h file, as below. (If VSRtdServer.dll is not part of the project, the full path must be specified.) To access StdAfx.h, click on the File View tab and open StdAfx.h.

 //{{AFX_INSERT_LOCATION}} 
 // Microsoft Visual C++ will insert additional declarations immediately 
 before #the previous line. 
 #import "VSRtdServer.dll" rename_namespace("VSClient")
 using namespace VSClient; 
 #endif // !defined(AFX_STDAFX_H__EA983678_D844_4452_ 
 A409_E9370926109E__INCLUDED_) 

6. Compile the StdAfx.cpp file to make sure there are no errors.

7. Open the sink header file (VSSink.h) and change:

 protected: 
 virtual ~VSSink() 

to

 public: 
 virtual ~VSSink() 

8. Open the sink object code (VSSink.cpp) and add the following #include directives:

 #include "VSClientDlg.h" 
 #include "VSRtdServer_i.c" 
 /* don’t forget the directory path (directory path can be a relative path) if this file is not in the same directory as your project. */ 

9. Modify the INTERFACE_PART macro so that the second parameter (IID) is the DIID (DispInterfaceID) of the event source, in our case DIID_ _IVSControlEvents, the interface map should looks like:

 BEGIN_INTERFACE_MAP(VSSink, CCmdTarget) 
 INTERFACE_PART(VSSink, DIID__IVSControlEvents, 
 Dispatch) 
 END_INTERFACE_MAP() 

10. Using the ClassView tab, right-click on the IVSSink interface and select Add Method. Use the following parameters for the added method.

  • External Name:VSUpdateEvent.
  • Internal Name: VSUpdateEvent.
  • Return Type: void.

11. Press OK.

Now in the VSSink.cpp source file, the DISPATCH_MAP code looks like:

 BEGIN_DISPATCH_MAP(VSSink, CCmdTarget) 
 //{{AFX_DISPATCH_MAP(VSSink) 
 DISP_FUNCTION(VSSink, "VSUpdateEvent",VSUpdateEvent, 
 VT_EMPTY, VTS_NONE) 
 //}}AFX_DISPATCH_MAP 
 END_DISPATCH_MAP() 

At the end of the file, write the code to handle incoming events from the server. The code should looks like:

 void VSSink::VSUpdateEvent() 
 
 { 
 // TODO: Add your dispatch handler code here 
 CVSClientDlg client; 
 client.UpdateEvent(); //Calling the CVSClientDlg::UpdateEvents 
 }

Finally, compile, build, and run the code.