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:
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 |
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 |
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:
Here is a closer look at these methods and their arguments.
VSRTConnectData(TopicID, inStrings, GetNewValues, Status)
whereby
TopicID | is some unique value to represent your data request, e.g. 1234. |
inStrings | is 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
TopicID | is the value that represents the arbitrary, unique value used in the VSRTConnectData method that identifies the topic. |
VSRTRefreshData(TopicCount, outStrings)
whereby
TopicCount | is the number of elements returned in the array of outStrings |
outStrings | is 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.
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
Below are some VB and C++ examples covering subscription and publishing
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.
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 RIC | RIC | RICLabel |
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.
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
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.
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.
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
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.
Writing the code behind the dialog box consists of two phases:
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:
The last two variables are used to check for server connection and for the placement of the incoming data:
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(); }
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.
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.