向tom_sh、bbbird886问好 向tom_sh、bbbird886问好 找了好长时间才找到这样的话题,看了tom_sh无私的解答,非常感动。我也用VB,接触时间不长。想法与bbbird886非常相近,水平却很相远,:-( 看贴的收益不小,愿经常能看到这样的讨论并得到指教
谢谢 不过我已经从你先前发布的dll文件中反编译找到了这些,现在的问题,是每次程序退出的时候,都会有异常信息“该内存不能read”,估计是 多线程造成的。 我只是接收行情,并保存在一个数据库中。你碰到过这类问题吗?
谁将代码里涉及到“D:\Program Files\FreeStar\stock.dll”的部分修改为取注册表里“HKEY_LOCAL_MACHINE\SOFTWARE\StockDrv\Driver”的值来确定,编译传上来,那就是使用所有类似符合“通视规范”的接口了。 而现在可以使用的HELLOWORLD接口和服务器地址我整理了30多个,而且有人最近放出不少数畅的帐户。
Re: 这个很容易 无所谓啊,因为我没开发编译系统,编译起来不方便,有编译好的用用就可以了。关于希望将代码里涉及到“D:\Program Files\FreeStar\stock.dll”的部分修改为读取注册表里“HKEY_LOCAL_MACHINE\SOFTWARE\StockDrv\Driver”的值来确定是为了方便使用其他的行情接口(如HELLOWORLD、王者、数畅等符合通视规范的,可以通过软通视来切换调用)
答复WJ2000:C#只能明确指定(用字符串常量)调用的外部DLL路径,无法通过变量来动态提取注册表或配置文件参数,所以只能硬编码。我建议还是装一个VS,编译起来就是一键的事。 答复byx45:每次程序退出时汇报异常可能是FREESTAR DLL的问题,换做HELLOWORLD就OK。
我使用这个,用同花顺的服务器,比较的结果有下面几个问题: 1、行情几乎是每分钟只有1到两笔,而同花顺基本上已经有9笔以上了。速度不及、数据量不及 2、如果不控制,每次收到的广播数据重复发送了8次,why? 3、这些问题是否由于广播方式和点播方式的区别造成的? 我修改了一下你的代码:只强调读取行情到某个接口,命名改了一下。若需要我将修改过的代码发给你。实际上我们大家可能更关注的是获取数据
仅处理行情接收的代码 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 { } } } }
如果速度这么慢,或者数据这么少,则这种方式将失去价值。 然后,用ExeScope可以看到速达接口中,提供了GetFromStockCode之类的 方式,当然还不能得到调用参数列表,那个需要时间分析汇编代码。 如果使用这个,是否会有区别呢? 使用Iquote接口(后面定义的那些属性),是因为要和手工转入的数据互换数据,这样,直接使用的时候也方便些。
如果你是用速达接口接收的,行情慢的原因是速达有每40秒发送一次行情的限制. 读取接收软件路径问题已在新版本解决了 http://www.hylt.net/club/viewtopic.php?t=5084