C#調用行情接口API 轉


C#調用行情接口API

          很早就已經通過了C#調用行情接口API的實現(見以前的日志),但是還是有人沒有搞明白,在這里就講講如何實現的。
首先,根據提供的stockdrv.h的信息,將數據結構移植到C#代碼中。
1.數據結構定義
   // <summary>
    // stockdrv.dll 的摘要說明。
    // </summary>
    //
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    public struct tagSTOCK_STRUCTEx
    {
       public byte m_type;     // stock's type, see enum StockType
       [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
       public char[] m_code;    // stock code
    }
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    public struct tagRCV_REPORT_STRUCTEx
    {
        public UInt16 m_cbSize;                                    // 結構大小
        public Int32 m_time;                                       // 交易時間
        public UInt16 m_wMarket;                                   // 股票市場類型
//m_szLabel,m_szName 的定義根據自己喜好可以定義成
         [MarshalAs(   UnmanagedType.ByValArray, SizeConst=10)]   
        public   char[]  m_szLabel; //   代碼,以'\0'結尾   數組大小為STKLABEL_LEN,在c++描述中為char[10]     
         [MarshalAs(   UnmanagedType.ByValArray,   SizeConst=32)]   
         public   char[]  m_szName;  //   名稱,以'\0'結尾   數組大小為STKNAME_LEN,在c++描述中為char[32]    
/*  也可以定義成
        [MarshalAs(UnmanagedType.ByValTStr,SizeConst = 10)]
        public string m_szLabel;                               // 代碼,以'\0'結尾  數組大小為STKLABEL_LEN,在c++描述中為char[10]    
        [MarshalAs(UnmanagedType.ByValTStr,SizeConst = 32)]
        public string m_szName;                                // 名稱,以'\0'結尾 組大小為STKNAME_LEN,在c++描述中為char[32]    
        */
        public Single m_fLastClose;                           // 昨收
        public Single m_fOpen;                                // 今開
        public Single m_fHigh;                                // 最高
        public Single m_fLow;                                 // 最低
        public Single m_fNewPrice;                            // 最新
        public Single m_fVolume;                              // 成交量
        public Single m_fAmount;                              // 成交額
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
        public Single[] m_fBuyPrice;                         // 申買價1,2,3
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
        public Single[] m_fBuyVolume;                        // 申買量1,2,3
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
        public Single[] m_fSellPrice;                        // 申賣價1,2,3
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
        public Single[] m_fSellVolume;                       // 申賣量1,2,3
        public Single m_fBuyPrice4;                          // 申買價4
        public Single m_fBuyVolume4;                         // 申買量4
        public Single m_fSellPrice4;                         // 申賣價4
        public Single m_fSellVolume4;                        // 申賣量4
        public Single m_fBuyPrice5;                          // 申買價5
        public Single m_fBuyVolume5;                         // 申買量5
        public Single m_fSellPrice5;                         // 申賣價5
        public Single m_fSellVolume5;                        // 申賣量5
       ......          其他項的定義
    };
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    public struct tagRCV_FILE_HEADEx
    {
        public int m_dwAttrib;                      // 文件子類型
        public int m_dwLen;                         // 文件長度
        public int m_dwSerialNoorTime;              //文件序列號或時間.
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 260)]
        char[] m_szFileName;                        // 文件名 or URL
    }
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi , Pack=1)]
    public struct tagRCV_DATA
    {
        public int m_wDataType;                     // 文件類型
        public int m_nPacketNum;                    // 記錄數,參見注一
        [MarshalAs(UnmanagedType.Struct)]
        public tagRCV_FILE_HEADEx m_File;          // 文件接口
        public int m_bDISK;                        // 文件是否已存盤的文件
        public IntPtr m_pData;
    } ;
 
  以上的定義關鍵點之一,是說明Pack,如果不說明,在后面的數據處理時,會遇到點問題。
 如在C#里定義的數據結構,取得結構長度,與C++的結構長度不一致。
究其原因,就是沒有對齊處理或二者對齊處理方式不一致。
 
 2.API借口定義
    public class Stockdrv
    {
// 宏定義直接根據C++的改寫過來即可
        public const int RCV_WORK_SENDMSG = 4;     // 工作方式類型定義-窗口消息方式
        public const int RCV_MSG_STKDATA = 0x8001; //指定使用的消息
        public const int RCV_REPORT    = 0x3f001234; //股票行情 
        public const UInt32 EKE_HEAD_TAG = 0xffffffff; //數據頭結構標記
         。。。。。。
 
// 接口函數的定義,根據提供stockdrv.h 按照如下改寫即可
// 偶提供的是UNICODE版本的DLL,如果不是CharSet 改為 CharSet.Ansi 即可
// 顯式說明,可以避免一些不必要的麻煩
        [DllImport("stockdrv.dll")]
        public static extern int Stock_Init(IntPtr nHwnd, int nMsg, int nWorkMode);
        [DllImport(@"stockdrv.dll",CharSet = CharSet.Unicode) ]
        public static extern int GetStockByCodeEx (string strCode,int nMarket,ref tagRCV_REPORT_STRUCTEx sRcvReort);
        [DllImport("stockdrv.dll")]
        public static extern int SetupReceiver(bool bSetup);
        [DllImport("stockdrv.dll")]
        public static extern int GetTotalNumber();
        [DllImport("stockdrv.dll")]
        public static extern int Stock_Quit(int hWnd);
        [DllImport(@"stockdrv.dll" ,CharSet = CharSet.Unicode)]
        public static extern int Stock_Init_Nodialog(IntPtr hWnd, int Msg, int nWorkMode, string szAddress, int nPort, string  szUser, string  szPasswd,string szSecAddress, int nSecPort,int nAuth );
        [DllImport("stockdrv.dll")]
        public static extern int  IsEngineWorking( );
        [DllImport("stockdrv.dll")]
        public static extern int SetAutoReport( int bAutoReport );
        [DllImport("stockdrv.dll")]
        public static extern int RequestStockData(int nDataType, tagSTOCK_STRUCTEx [] pStocks, int nSize, int nKType, int nDataCount);
。。。。。。。。 // 余下的按此方式寫就是了,用不到的也可以不寫哦!
 
        public Stockdrv()
        {
            //
            // TODO: 在此處添加構造函數邏輯
            //
        }
    }
///---------------------------------------------------------------------------------------
}
 
3. 調用API
   采用數據共享引用時
    // 數據共享引用,調用 C++ 中的接口函數
     Stockdrv.Stock_Init(this.Handle, Stockdrv.RCV_MSG_STKDATA, Stockdrv.RCV_WORK_SENDMSG);
     Stockdrv.SetupReceiver(false);
     這種方式一般不使用了,提供該方式主要為了兼容的緣故
 
   網絡直接連接
    int lResult = Stockdrv.Stock_Init_Nodialog(this.Handle, Stockdrv.RCV_MSG_STKDATA, Stockdrv.RCV_WORK_SENDMSG,.......);
    Stockdrv.SetupReceiver(false);
    接下來請求數據
           tagSTOCK_STRUCTEx[] pStocks = new tagSTOCK_STRUCTEx[1];
            string s = "999999;
            pStocks[0].m_code = s.ToCharArray(0, s.Length);
            pStocks[0].m_type = 0x10;
            Stockdrv.RequestStockData(Stockdrv.RCV_REPORT, pStocks, 1, 0, 0);
 
4.數據接收
    只要對數據接收,重載 WndProc 即可,代碼如下:
  /// //////////////////////////////////////////////////////////
        /// 重載虛擬 WndProc 接收消息的窗口的消息處理過程,以截獲任何消息
        /// /////////////////////////////////////////////////////////       
        protected override void WndProc(ref Message m)
        {
            if ((int)m.Msg == Stockdrv.RCV_MSG_STKDATA)
            {           
                tagRCV_DATA recvData = (tagRCV_DATA)Marshal.PtrToStructure(m.LParam, typeof(tagRCV_DATA));
                if ((int)m.WParam == Stockdrv.RCV_REPORT) //行情數據
                {
                    m_bInitOK = true;                
                    tagRCV_REPORT_STRUCTEx ReprotData;
                    int recLength ;
                    recLength = Marshal.SizeOf(typeof(tagRCV_REPORT_STRUCTEx))  // 需要實際長度
                    for (int i = 0; i < recvData.m_nPacketNum; i++)
                    {
                        //結構中如果沒有說明 Pack =1,需要前移 -2
                       // 這也是許多人感覺為啥差-2原因, 在 VB6.0 也是如此,VB.NET如果沒有說明Pack =1,也是同樣的問題
                        //ReprotData = (tagRCV_REPORT_STRUCTEx)Marshal.PtrToStructure(new IntPtr((int)recvData.m_pData + i * recLength-2), typeof(tagRCV_REPORT_STRUCTEx));

                        //結構中需要說明 Pack =1
                        ReprotData = (tagRCV_REPORT_STRUCTEx)Marshal.PtrToStructure(new IntPtr((int)recvData.m_pData + i * recLength ), typeof(tagRCV_REPORT_STRUCTEx));
                           //  數據計算與分析 省略                        
                            。。。。。。。。。
                        }
                    }
                }
                return;
            }         
            base.WndProc(ref m); // 調用基類成員函數!   
        }
   至此,已經完成說明了如何在C#中調用API,相信大家可以開發出適合自己的股軟分析軟件!
   如有不對之處,請大家多指教!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM