通视实时服务器源码

Discussion in 'General Topics on Software and Data' started by tom_sh, Sep 18, 2005.

  1. 向tom_sh、bbbird886问好

    向tom_sh、bbbird886问好
    找了好长时间才找到这样的话题,看了tom_sh无私的解答,非常感动。我也用VB,接触时间不长。想法与bbbird886非常相近,水平却很相远,:-( 看贴的收益不小,愿经常能看到这样的讨论并得到指教
     
  2. 楼主提供的代码无法编译啊,RCV_DATA在哪里呢?
     
  3. 答复byx45
    已修改添加RCV_DATA,在TONGSHIWINDOW的WNDPROC方法后增加了一些结构定义(不是都需要)。
     
  4. 谢谢

    不过我已经从你先前发布的dll文件中反编译找到了这些,现在的问题,是每次程序退出的时候,都会有异常信息“该内存不能read”,估计是
    多线程造成的。
    我只是接收行情,并保存在一个数据库中。你碰到过这类问题吗?
     
  5. Re: 谢谢

    呵呵,另外,我也是使用C#编程,对证卷软件兴趣浓厚。这点来看,咱们倒有许多共同的兴趣。今后多多请教。
    我的Msn是Bidanjun@gmail.com,你也留个联系方式?
    有空可以聊聊。
     
  6. 谁将代码里涉及到“D:\Program Files\FreeStar\stock.dll”的部分修改为取注册表里“HKEY_LOCAL_MACHINE\SOFTWARE\StockDrv\Driver”的值来确定,编译传上来,那就是使用所有类似符合“通视规范”的接口了。
    而现在可以使用的HELLOWORLD接口和服务器地址我整理了30多个,而且有人最近放出不少数畅的帐户。
     
  7. 这个很容易

    不过,你是指最初的C#代码还是后来那些?
    对注册表的操作很简单的,看看Msdn就行。

    楼主的控件,每次程序退出时汇报异常,不知何故?
     
  8. Re: 这个很容易

    无所谓啊,因为我没开发编译系统,编译起来不方便,有编译好的用用就可以了。关于希望将代码里涉及到“D:\Program Files\FreeStar\stock.dll”的部分修改为读取注册表里“HKEY_LOCAL_MACHINE\SOFTWARE\StockDrv\Driver”的值来确定是为了方便使用其他的行情接口(如HELLOWORLD、王者、数畅等符合通视规范的,可以通过软通视来切换调用)
     
  9. 答复WJ2000:C#只能明确指定(用字符串常量)调用的外部DLL路径,无法通过变量来动态提取注册表或配置文件参数,所以只能硬编码。我建议还是装一个VS,编译起来就是一键的事。
    答复byx45:每次程序退出时汇报异常可能是FREESTAR DLL的问题,换做HELLOWORLD就OK。
     
  10. 我使用这个,用同花顺的服务器,比较的结果有下面几个问题:
    1、行情几乎是每分钟只有1到两笔,而同花顺基本上已经有9笔以上了。速度不及、数据量不及
    2、如果不控制,每次收到的广播数据重复发送了8次,why?
    3、这些问题是否由于广播方式和点播方式的区别造成的?

    我修改了一下你的代码:只强调读取行情到某个接口,命名改了一下。若需要我将修改过的代码发给你。实际上我们大家可能更关注的是获取数据
     
  11. 仅处理行情接收的代码

    using System;
    using System.Runtime.InteropServices;
    using System.Collections;
    using System.Drawing;
    using System.ComponentModel;
    using System.Windows.Forms;
    using System.Data;
    using System.IO;
    using System.Threading;
    using System.Text;

    namespace Stock.Business
    {
    //1、非交易时间,每次重复发送了前一天15:00的记录,共发8次,这个看交易时间如何。交易时间也是
    //如此
    //2、速达接口,访问同花顺的服务器,效果很好。这说明天网和同花顺服务器结构并未改变。
    //3、驱动所给的分笔数据,用结构的方式定义,但我们同样可以为其实现Iquote接口,和我们的业务对象交换数据
    //4、中途中断的情形,则数据会丢失。分笔能否补充?分时如何点播?这个需要看通视卡的规范。
    //5、结构应保存为五档行情

    public partial class QuoteServer : UserControl
    {
    public QuoteServer()
    {
    InitializeComponent();
    }

    #region 常数
    //驱动程序的路径,不过只能够使用常数?
    private const string driveLocation = "StockDrive\\StockDrv.dll";

    public string DriveLocation
    {
    get { return driveLocation; }
    }

    public bool Drvloaded = false;
    private const short fProviderID = 102;

    private const int TSMSG = 55;
    private const int RCV_WORK_SENDMSG = 4;
    private const int QuoteMessageType = 0x3f001234;//消息类型为这个的时候,传递的是分笔数据
    private const int FileMessageType = 0x3f001235;//消息类型为这个的时候,表示传递的是历史行情数据文件
    private const int StockCodeLength = 10; // 股号数据长度,国内市场股号编码兼容钱龙
    private const int StockNameLength = 32; // 股名长度
    public const uint ShanHaiMarketFlag = 18515;//上海市场标记
    public const uint ShenZhenMarketFlag = 23123;//深圳市场标记

    #endregion

    public event QuoteServerEventHandler OnQuote;//定义一个事件

    #region 行情处理
    [DllImport(driveLocation, CharSet = CharSet.Auto)]
    public static extern int Stock_Init(int hWnd, uint Msg, int nWorkMode);

    [DllImport(driveLocation, CharSet = CharSet.Auto)]
    public static extern int Stock_Quit(int hWnd);

    public void DrvInit()
    {
    Drvloaded = true;
    Stock_Init(this.Handle.ToInt32(), TSMSG, RCV_WORK_SENDMSG);

    }
    public void DrvQuit()
    {
    if (Drvloaded)
    {
    Stock_Quit(this.Handle.ToInt32());
    Drvloaded = false;
    }
    }


    protected override void WndProc(ref Message m)
    {
    RCV_DATA data;
    QuoteServerEventArgs qtarg;

    if (m.Msg == TSMSG && Drvloaded)
    {
    data = (RCV_DATA)m.GetLParam(typeof(RCV_DATA));

    // Listen for operating system messages.
    switch (m.WParam.ToInt32())
    {
    case QuoteMessageType:
    if (OnQuote != null)
    {
    for (int i = 0; i < data.m_nPacketNum; i++)
    {
    QuoteStruct report = (QuoteStruct)Marshal.PtrToStructure
    (new IntPtr((int)data.ptr + 158 * i), typeof(QuoteStruct));

    string symbol = report.StockCode;
    qtarg = new QuoteServerEventArgs(symbol, report);
    OnQuote(this, qtarg);
    }
    }
    break;
    case FileMessageType:
    // RCV_HISTORY_STRUCTEx history=(RCV_HISTORY_STRUCTEx)Marshal.PtrToStructure(data.ptr,typeof(RCV_HISTORY_STRUCTEx));
    // RCV_HISTORY_STRUCTEx_tag taginfo= (RCV_HISTORY_STRUCTEx_tag)Marshal.PtrToStructure(data.ptr,typeof(RCV_HISTORY_STRUCTEx_tag));
    // RCV_HISTORY_STRUCTEx_data hdata= (RCV_HISTORY_STRUCTEx_data)Marshal.PtrToStructure(new IntPtr((int)data.ptr+Marshal.SizeOf(typeof(RCV_HISTORY_STRUCTEx_data))),typeof(RCV_HISTORY_STRUCTEx_data));
    //
    // Console.WriteLine("data received + ");
    break;
    }
    }
    base.WndProc(ref m);
    }

    #endregion

    #region 数据结构
    [StructLayout(LayoutKind.Sequential)]
    public struct RCV_DATA
    {
    public System.Int32 m_wDataType; // 文件类型
    public System.Int32 m_nPacketNum; // 记录数,参见注一
    public RCV_FILE_HEADEx m_File; // 文件接口
    public System.Int32 m_bDISK;
    // [ MarshalAs( UnmanagedType.LPArray)]
    // public RCV_REPORT_STRUCTExV3[] rpt;
    // [ MarshalAs( UnmanagedType.AsAny)]
    public IntPtr ptr;
    // public rcvdata data;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct RCV_FILE_HEADEx
    {
    public System.UInt32 m_dwAttrib; // 文件子类型
    public System.UInt32 m_dwLen; // 文件长度
    public System.UInt32 m_dwSerialNo; // 序列号
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
    public string m_szFileName; // 文件名 or URL
    }

    #endregion

    }


    #region 事件委托和事件参数
    public delegate void QuoteServerEventHandler(object sender, QuoteServerEventArgs e);

    public class QuoteServerEventArgs : EventArgs
    {
    public string Symbol;
    public DateTime TimeStamp;
    public QuoteStruct QuoteData;

    public QuoteServerEventArgs(string symbol, QuoteStruct qt)
    {
    Symbol = symbol;
    QuoteData = qt;
    TimeStamp = QuoteData.QuoteTime;
    }
    }
    #endregion



    //由通视卡驱动程序传来的分笔数据的结构
    [StructLayout(LayoutKind.Explicit)]
    public struct QuoteStruct:IQuote
    {
    [FieldOffset(0)]
    public System.UInt16 structLength; // 结构大小
    [FieldOffset(2)]
    public System.UInt32 quoteTime; // 成交时间
    [FieldOffset(6)]
    public System.UInt16 stockMarket; // 股票市场类型
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 42)]
    [FieldOffset(8)]
    public char[] stockCode; // 股票代码,以'\0'结尾
    [FieldOffset(50)]
    public System.Single prevClosePrice; // 昨收
    [FieldOffset(54)]
    public System.Single openPrice; // 今开
    [FieldOffset(58)]
    public System.Single highPrice; // 最高
    [FieldOffset(62)]
    public System.Single lowPrice; // 最低
    [FieldOffset(66)]
    public System.Single currentPrice; // 最新
    [FieldOffset(70)]
    public System.Single volume; // 成交量
    [FieldOffset(74)]
    public System.Single money; // 成交额
    [FieldOffset(78)]
    public System.Single buy1; // 申买价1
    [FieldOffset(82)]
    public System.Single buy2; // 申买价2
    [FieldOffset(86)]
    public System.Single buy3; // 申买价3
    [FieldOffset(90)]
    public System.Single buyVolume1; // 申买量1
    [FieldOffset(94)]
    public System.Single buyVolume2; // 申买量2
    [FieldOffset(98)]
    public System.Single buyVolume3; // 申买量3
    [FieldOffset(102)]
    public System.Single sale1; // 申卖价1
    [FieldOffset(106)]
    public System.Single sale2; // 申卖价2
    [FieldOffset(110)]
    public System.Single sale3; // 申卖价3
    [FieldOffset(114)]
    public System.Single saleVolume1; // 申卖量1
    [FieldOffset(118)]
    public System.Single saleVolume2; // 申卖量2
    [FieldOffset(122)]
    public System.Single saleVolume3; // 申卖量3
    [FieldOffset(126)]
    public System.Single buy4; // 申买价4
    [FieldOffset(130)]
    public System.Single buyVolume4; // 申买量4
    [FieldOffset(134)]
    public System.Single sale4; // 申卖价4
    [FieldOffset(138)]
    public System.Single saleVolume4; // 申卖量4
    [FieldOffset(142)]
    public System.Single buy5; // 申买价5
    [FieldOffset(146)]
    public System.Single buyVolume5; // 申买量5
    [FieldOffset(150)]
    public System.Single sale5; // 申卖价5
    [FieldOffset(154)]
    public System.Single saleVolume5;

    //接口

    //
    public sbyte StockMarket
    {
    get
    {
    if (stockMarket == QuoteServer.ShanHaiMarketFlag)
    return (sbyte)1;
    if (stockMarket == QuoteServer.ShenZhenMarketFlag)
    return (sbyte)2;
    return (sbyte)0;
    }
    set { }
    }

    public sbyte StockType
    {
    get
    {
    return StockUtil.GetStockType(StockCode, StockMarket);
    }
    set { }
    }

    public string StockCode
    {
    get { return new string(stockCode, 0, 6).Trim(); }
    set { }
    }

    public DateTime QuoteTime
    {
    get
    {
    return DateTime.FromFileTimeUtc(10000000 * (long)quoteTime + 116444736000000000).ToLocalTime();
    }
    set { }
    }

    public float CurrentPrice
    {
    get
    {
    return currentPrice;
    }
    set { }
    }

    public float Volume
    {
    get
    {
    return volume;
    }
    set { }
    }

    public float Money
    {
    get
    {
    return money;
    }
    set { }
    }


    public UInt16 BuyVolume1
    {
    get
    {
    return (UInt16)buyVolume1;
    }
    set { }
    }

    public UInt16 BuyVolume2
    {
    get
    {
    return (UInt16)buyVolume2;
    }
    set { }
    }

    public UInt16 BuyVolume3
    {
    get
    {
    return (UInt16)buyVolume3;
    }
    set { }
    }

    public UInt16 SaleVolume1
    {
    get
    {
    return (UInt16)saleVolume1;
    }
    set { }
    }

    public UInt16 SaleVolume2
    {
    get
    {
    return (UInt16)saleVolume2;
    }
    set { }
    }

    public UInt16 SaleVolume3
    {
    get
    {
    return (UInt16)saleVolume3;
    }
    set { }
    }

    public sbyte Buy1
    {
    get
    {
    return (sbyte)(buy1 - currentPrice);
    }
    set { }
    }

    public sbyte Buy2
    {
    get
    {
    return (sbyte)(buy2 - currentPrice);
    }
    set { }
    }

    public sbyte Buy3
    {
    get
    {
    return (sbyte)(buy3 - currentPrice);
    }
    set { }
    }

    public sbyte Sale1
    {
    get
    {
    return (sbyte)(sale1 - currentPrice);
    }
    set { }
    }

    public sbyte Sale2
    {
    get
    {
    return (sbyte)(sale2 - currentPrice);
    }
    set { }
    }

    public sbyte Sale3
    {
    get
    {
    return (sbyte)(sale3 - currentPrice);
    }
    set { }
    }

    //todo:是上涨、下跌还是平盘
    public UInt16 ActiveFlag
    {
    get
    {
    return (UInt16)0;
    }
    set { }
    }

    public UInt16 BuyVolume4
    {
    get
    {
    return (UInt16)buyVolume4;
    }
    set { }
    }

    public UInt16 BuyVolume5
    {
    get
    {
    return (UInt16)buyVolume5;
    }
    set { }
    }

    public UInt16 SaleVolume4
    {
    get
    {
    return (UInt16)saleVolume4;
    }
    set { }
    }

    public UInt16 SaleVolume5
    {
    get
    {
    return (UInt16)saleVolume5;
    }
    set { }
    }

    public sbyte Buy4
    {
    get
    {
    return (sbyte)(buy4 - currentPrice);
    }
    set { }
    }

    public sbyte Buy5
    {
    get
    {
    return (sbyte)(buy5 - currentPrice);
    }
    set { }
    }

    public sbyte Sale4
    {
    get
    {
    return (sbyte)(sale4 - currentPrice);
    }
    set { }
    }

    public sbyte Sale5
    {
    get
    {
    return (sbyte)(sale5 - currentPrice);
    }
    set { }
    }

    }
    }
     
  12. 如果速度这么慢,或者数据这么少,则这种方式将失去价值。
    然后,用ExeScope可以看到速达接口中,提供了GetFromStockCode之类的
    方式,当然还不能得到调用参数列表,那个需要时间分析汇编代码。
    如果使用这个,是否会有区别呢?

    使用Iquote接口(后面定义的那些属性),是因为要和手工转入的数据互换数据,这样,直接使用的时候也方便些。
     
  13. vb 版本的问题
     
  14. 请问:如何在vb中使用这个组件?谢谢。
     
  15. 这个东西只能在EXCEL里面用,不能在别的环境里调用。另外,我只在.net1.0和EXCEL2002下开发运行成功,曾试图移植到.net2.0和EXCEL2003下,没有成功。
     
  16. 我试了一下,2003可以搞掂啊
     
  17. 2003可以运行用net1.0和excel2002COM组件开发的版本,但net2.0和excel2003组件开发的版本就不行。
     
  18. 明白了,谢谢。