User Tools

  • Vistasource Document Library

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
rtw_4.5:rtw_com_interface [2012/01/12 17:50]
cjaeger
rtw_4.5:rtw_com_interface [2018/08/04 20:09] (current)
Line 1: Line 1:
-=====RTW COM Interface=====+{{:​rtw_4.5:​flat-rtw-wiki.png?​direct|}} 
 +======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.
  
-The Vistasource RTW COM Interface allows you to connect to and receive real-time data from any  COM-based client application,​ including Microsoft Excel. ​ The RTW COM Interface is a piece of middleware between the installed RTW engines or a custom engine built with the RTW Toolkit, ​ and a COM-based application. You can use a variety of data distribution systems (DDS), collect data from different sources, and publish the results 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. ​
  
-To learn more about the RTW COM Interface, see [[Introducing the RTW COM Interface]].+See also:
  
-For supplementary commands that greatly help the COM client developer, see [[Additional ​RTW COM Interface Commands]].+  * [[rtw_overview|RTW]] 
 +  * [[rtshare_overview|RTSHARE]] 
 +=====Components=====
  
 +The COM interface requires the [[installation|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. ​
 +
 +<​note>​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. </​note>​
 +
 +**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. 
 +
 +<​note>​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</​note>​
 +
 + 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: ​
 +
 +<code vbnet>​Dim WithEvents vsrt_obj as VSRTDSERVERLib.VSControl</​code>​
 +
 +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: ​
 +
 +<code vbnet>
 +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
 +</​code> ​
 +=====Commands=====
 +
 +See: [[rtw_com_interface_commands|RTW COM Interface Commands]] and [[rtshare_com_interface_commands|RTSHARE COM Interface Commands]]
 +===== Sample Applications =====
 +
 +Below are some VB and C++ examples covering subscription and publishing
 +
 +  * [[#​quick_quote|VB Subscription example]]
 +  * [[#​Publishing|VB Publishing example]]
 +  * [[#​c_client|C++ Client]]
 +==== 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**
 +
 +{{com_1.jpg?​direct&​|}} ​
 +
 + 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**
 +
 +{{com_2.jpg?​direct&​|}}
 + 
 +
 +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**
 + 
 +{{com_3.jpg?​direct&​|}}
 +
 +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**
 +
 +{{com_4.jpg?​direct&​|}}
 + 
 +
 +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**
 +
 +{{:​rtw_4.4:​step7_com_guide_44.jpg?​direct&​|}}
 +
 +
 +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** 
 +
 +{{:​rtw_4.4:​step8_com_guide_44.jpg?​direct&​|}}
 +
 +
 +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:
 + 
 +<code vbnet>
 + Dim WithEvents vsrt As VSRTDSERVERLib.VSControl ​
 + Dim Topic_Id As Long 
 + Dim MyEngine As String ​
 +</​code>​
 +
 +10. To declare values for the form text boxes and labels, add the following code to the Private Sub Form_Load() procedure: ​
 +
 +<code vbnet>
 +
 +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
 +</​code>​
 +
 +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. ​
 +
 +<code vbnet>
 +Private Sub Close_Click() ​
 +Unload Me 'Exit Application ​
 +End Sub 
 +</​code>​
 +
 +12. Now double-click on the Quote button and enter the following ​ command inside the Sub Quote_Click( ) routine: ​
 +
 +<code vbnet>
 +Private Sub Quote_Click() ​
 +Call GetQuote ​
 +End Sub 
 +</​code>​
 +
 +13. Create a subroutine called GetQuote which gets the quote for the record that is entered. ​
 +
 +<code vbnet>
 +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 
 +</​code>​
 +
 +
 +14. Next, create a subroutine to update the entry box when new data arrives from the RTW COM Interface. ​
 +
 +<code vbnet>
 +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 
 +</​code>​
 +
 +
 +15. The final code sheet should look similar to this: 
 +
 +<code vbnet>
 +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 
 +
 +</​code>​
 +
 +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: ​
 +
 +<code vbnet>
 + ​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 
 +
 +</​code>​
 +
 +\\
 +\\
 +\\
 +==== 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. 
 +
 +<​note>​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 ​
 +</​note>​
 +
 +
 +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 ==
 +
 +<​note>​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. </​note>​
 +
 +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: ​
 +
 +<code cpp>
 + ​IVSControl *m_pSrc; ​
 + ​VSSink *m_pSink; ​
 + DWORD m_dwCookie; ​
 + long TopicID = 1; 
 +
 + bool is_connected = false; ​
 + ​CEdit* pEditData; ​
 +</​code>​
 +
 +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: 
 +
 +<code cpp>
 +#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; ​
 +
 +</​code>​
 +
 +**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: "
 +
 +<code cpp> ​
 + ​pEditData = (CEdit*)GetDlgItem(IDC_DATA); ​
 +</​code>​
 +
 +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: 
 +
 +<code cpp>
 + // 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; ​
 +</​code>​
 +
 +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: ​
 +
 +<code cpp>
 + //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); ​
 + ​} ​
 +</​code>​
 +
 +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: 
 +
 +<code cpp>
 + ​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; ​
 + ​} ​
 +</​code>​
 +
 +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: 
 +
 +<code cpp>
 + void CVSClientDlg::​OnDestroy() ​
 + ​{ ​
 + ​CDialog::​OnDestroy(); ​
 + ​DisconnectData(); ​
 + ​} ​
 +</​code>​
 +
 +== 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.
 +
 +<code cpp>
 + //​{{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_) ​
 +</​code>​
 +
 + 6. Compile the StdAfx.cpp file to make sure there are no errors. ​
 +
 + 7. Open the sink header file (VSSink.h) and change: ​
 +
 +<code cpp>
 + ​protected: ​
 + ​virtual ~VSSink() ​
 +</​code>​
 + ​to ​
 +<code cpp>
 + ​public: ​
 + ​virtual ~VSSink() ​
 +</​code>​
 +
 + 8. Open the sink object code (VSSink.cpp) and add the following #include directives: ​
 +
 +<code cpp>
 + #​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. */ 
 +</​code>​
 +
 + 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: 
 +
 +<code cpp>
 + ​BEGIN_INTERFACE_MAP(VSSink,​ CCmdTarget) ​
 + ​INTERFACE_PART(VSSink,​ DIID__IVSControlEvents, ​
 + ​Dispatch) ​
 + ​END_INTERFACE_MAP() ​
 +</​code>​
 +
 + 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: 
 +
 +<code cpp>
 + ​BEGIN_DISPATCH_MAP(VSSink,​ CCmdTarget) ​
 + //​{{AFX_DISPATCH_MAP(VSSink) ​
 + ​DISP_FUNCTION(VSSink,​ "​VSUpdateEvent",​VSUpdateEvent, ​
 + ​VT_EMPTY,​ VTS_NONE) ​
 + //​}}AFX_DISPATCH_MAP ​
 + ​END_DISPATCH_MAP() ​
 +</​code>​
 +
 + At the end of the file, write the code to handle incoming events from the server. The code should looks like: 
 +
 +<code cpp>
 + void VSSink::​VSUpdateEvent() ​
 +
 + ​{ ​
 + // TODO: Add your dispatch handler code here 
 + ​CVSClientDlg client; ​
 + ​client.UpdateEvent();​ //Calling the CVSClientDlg::​UpdateEvents ​
 + ​} ​
 +
 +</​code>​
 +
 +Finally, compile, build, and run the code. 
 +
 +\\
 +\\
 +\\