C#中的RTD服务器-从何处开始

C#中的RTD服务器-从何处开始,c#,excel,rtd,C#,Excel,Rtd,我在Excel中有RTD服务器,它从thinkorswim应用程序中提取数据。我想将数据拉入C#。我的编程经验有限,所以阅读了多篇关于RTD服务器在C#中实现的教程,但其中大多数对我来说都是高级的。所以我想知道是否有人能推荐一些介绍性的阅读材料。下面是我尝试实现的示例代码: 我将其复制并粘贴到Visual Studio(VS)中,并调用类RtdClient.cs。VS立即突出显示了以下行: ComImport, TypeLibType((short)0x1040) MarshalAs Meth

我在Excel中有RTD服务器,它从thinkorswim应用程序中提取数据。我想将数据拉入C#。我的编程经验有限,所以阅读了多篇关于RTD服务器在C#中实现的教程,但其中大多数对我来说都是高级的。所以我想知道是否有人能推荐一些介绍性的阅读材料。下面是我尝试实现的示例代码:

我将其复制并粘贴到Visual Studio(VS)中,并调用类RtdClient.cs。VS立即突出显示了以下行:

ComImport, TypeLibType((short)0x1040)
MarshalAs
MethodImpl
未能找到类型和命名空间

我是否遗漏了任何参考资料? 我在COM类型Tos.RTD上添加了引用,但没有帮助

在注册表中,我还找到了带有Tos.RTD和CLSID的文件夹。我假设CSLID指向COM类型

在VS Tos中,RTD有两个接口。在上面的链接中,我没有看到这些接口方法的实现。怎么了

我也读了下面的文章,我知道第二个链接依赖于反射。这两种方法的优点/缺点是什么?哪一个在概念上更有意义


你可能会觉得我迷路了,所以任何建议都将不胜感激。

RTD服务器是专门为Excel设计的,在C#中对你没有帮助。我想你可以对它进行反编译,看看它是如何从ThinkOrSwim获取数据的,但如果你多看看,我想他们已经有了一个API,你可以使用它了;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Threading;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;


namespace MyRTD
{
     class Program
    {
     static void Main(string[] args)
        {
        //Based off of http://awkwardcoder.com/2014/01/24/excel-rtd-client-in-c/
        //and http://stackoverflow.com/questions/26726430/r6025-pure-virtual-function-call


            //var tosClassId = new Guid(Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Tos.RTD\CLSID", "", null).ToString());
            var tosClassId=new Guid("{1B415BA9-E543-41BD-8EB1-CB12A5B7678F}");
            var rtdClient = new RtdClient(tosClassId);

            var date = DateTime.Now.Date;

            List<string> tos_sym = new List<string>();
            tos_sym.Add(".AAPL160819C106");
            tos_sym.Add(".AAPL160819C107");
            tos_sym.Add(".AAPL160819C108");
            tos_sym.Add(".AAPL160819C109");

            foreach (var optSym in tos_sym)
              {
                var optBid = GetDouble(rtdClient, optSym, "BID");
                var optAsk = GetDouble(rtdClient, optSym, "ASK");
                var optDelt = GetDouble(rtdClient, optSym, "DELTA");

                Console.WriteLine(optSym + " BID: " + optBid + " ASK: " + optAsk + " DELTA: " + optDelt);

                }
          }

            static double GetDouble(IRtdClient client, string symbol, string topic) {
                object value;
                if (client.GetValue2(TimeSpan.FromSeconds(3), out value, topic, symbol)) {
                    try { return double.Parse(value.ToString()); } catch { return 0; }
                }
                return 0;
             }

        public interface IRtdClient
        {

            bool GetValue2(TimeSpan timeout, out object value, params object[] args);
        }

        public class RtdClient : IRtdClient
        {

            readonly Guid ServerId;
            static readonly Dictionary<Guid, IRtdServer> servers = new Dictionary<Guid, IRtdServer>();
            static readonly Dictionary<Guid, int> topicIds = new Dictionary<Guid, int>();

            public RtdClient(Guid serverId)
            {
                ServerId = serverId;
            }

            public bool GetValue2(TimeSpan timeout, out object value, params object[] args)
            {

                value = null;
                var server = GetRtdServer();
                var topicId = GetTopicId();

                var sw = Stopwatch.StartNew();
                var delay = 200;

                try
                {
                    server.ConnectData(topicId, args, true);
                    while (sw.Elapsed < timeout)
                    {
                        Thread.Sleep(delay);
                        delay *= 2;
                        var alive = server.Heartbeat();
                        if (alive != 1)
                        {
                            // TODO: What should be done here?
                            return false;
                        }
                        var refresh = server.RefreshData(1);
                        if (refresh.Length > 0)
                        {
                            if (refresh[0, 0].ToString() == topicId.ToString())
                            {
                                value = refresh[1, 0];
                                return true;
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    // TODO: Log exception
                    return false;
                }
                finally
                {
                    server.DisconnectData(topicId);
                    sw.Stop();
                }
                return false;
            }


            IRtdServer GetRtdServer()
            {
                IRtdServer server;
                if (!servers.TryGetValue(ServerId, out server))
                {
                    Type rtd = Type.GetTypeFromCLSID(ServerId);
                    server = (IRtdServer)Activator.CreateInstance(rtd);
                    servers[ServerId] = server;
                }
                return server;
            }

            int GetTopicId()
            {
                int topicId = 0;
                if (topicIds.TryGetValue(ServerId, out topicId))
                {
                    topicId++;
                }
                topicIds[ServerId] = topicId;
                return topicId;
            }
        }
        [ComImport, TypeLibType((short)0x1040), Guid("EC0E6191-DB51-11D3-8F3E-00C04F3651B8")]
        public interface IRtdServer
        {
            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(10)]
            int ServerStart([In, MarshalAs(UnmanagedType.Interface)] IRTDUpdateEvent callback);

            [return: MarshalAs(UnmanagedType.Struct)]
            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(11)]
            object ConnectData([In] int topicId, [In, MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)] ref object[] parameters, [In, Out] ref bool newValue);

            [return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)]
            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(12)]
            object[,] RefreshData([In, Out] ref int topicCount);

            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(13)]
            void DisconnectData([In] int topicId);

            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(14)]
            int Heartbeat();

            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(15)]
            void ServerTerminate();
        }

        [ComImport, TypeLibType((short)0x1040), Guid("A43788C1-D91B-11D3-8F39-00C04F3651B8")]
        public interface IRTDUpdateEvent
        {
            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(10), PreserveSig]
            void UpdateNotify();

            [DispId(11)]
            int HeartbeatInterval
            {
                [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(11)]
                get;
                [param: In]
                [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(11)]
                set;
            }

            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(12)]
            void Disconnect();

        }


    }
}
使用System.Collections.Generic; 使用System.Linq; 使用系统文本; 使用系统诊断; 使用系统线程; 使用System.Runtime.InteropServices; 使用System.Runtime.CompilerServices; 名称空间MyRTD { 班级计划 { 静态void Main(字符串[]参数) { //基于http://awkwardcoder.com/2014/01/24/excel-rtd-client-in-c/ //及http://stackoverflow.com/questions/26726430/r6025-pure-virtual-function-call //var tosClassId=新Guid(Registry.GetValue(@“HKEY\U LOCAL\U MACHINE\SOFTWARE\Classes\Tos.RTD\CLSID”,“”,null).ToString(); var tosClassId=新Guid({1B415BA9-E543-41BD-8EB1-CB12A5B7678F}); var rtdClient=新的rtdClient(tosClassId); var date=DateTime.Now.date; List tos_sym=新列表(); tos_sym.Add(“.AAPL160819C106”); tos_sym.Add(“.AAPL160819C107”); tos_sym.Add(“.AAPL160819C108”); tos_sym.Add(“.AAPL160819C109”); foreach(tos_sym中的var optSym) { var optBid=GetDouble(rtdClient,optSym,“BID”); var opttask=GetDouble(rtdClient,optSym,“ASK”); var optDelt=GetDouble(rtdClient,optSym,“DELTA”); 控制台写入线(optSym+“BID:+optBid+”ASK:+opttask+“DELTA:+optDelt”); } } 静态double GetDouble(IRtdClient客户端、字符串符号、字符串主题){ 目标价值; if(client.GetValue2(TimeSpan.FromSeconds(3)、out值、主题、符号)){ 尝试{return double.Parse(value.ToString());}catch{return 0;} } 返回0; } 公共接口IRtdClient { bool GetValue2(TimeSpan超时,out对象值,params对象[]args); } 公共类RtdClient:IRtdClient { 只读Guid服务器ID; 静态只读字典服务器=新建字典(); 静态只读字典topicIds=新字典(); 公共RTD客户端(Guid服务器ID) { ServerId=ServerId; } public bool GetValue2(TimeSpan超时,输出对象值,参数对象[]args) { 值=空; var server=GetRtdServer(); var topicId=GetTopicId(); var sw=Stopwatch.StartNew(); 无功延迟=200; 尝试 { ConnectData(topicId,args,true); 同时(软件运行<超时) { 睡眠(延迟); 延迟*=2; var alive=server.Heartbeat(); 如果(活动!=1) { //TODO:这里应该做什么? 返回false; } var refresh=server.RefreshData(1); 如果(refresh.Length>0) { if(刷新[0,0].ToString()==topicId.ToString()) { 值=刷新[1,0]; 返回true; } } } } 捕获(例外情况除外) { //TODO:日志异常 返回false; } 最后 { 服务器。断开数据连接(topicId); sw.Stop(); } 返回false; } IRtdServer GetRtdServer() { IRtdServer; 如果(!servers.TryGetValue(ServerId,out server)) { 类型rtd=Type.GetTypeFromCLSID(服务器ID); server=(IRtdServer)Activator.CreateInstance(rtd); 服务器[ServerId]=服务器; } 返回服务器; } int GetTopicId() { int-topicId=0; if(topicIds.TryGetValue(ServerId,out-topicId)) { topicId++; } topicIds[ServerId]=topicId; 回到