策略为王源代码分析-构建通视驱动源代码

Published

策略为王源代码分析-构建数据服务器源代码

流程:

1.各行情显示窗口向StkReceiver注册自己的窗口句柄,定义消息WM_APP_STKRECEIVER_DATA及处理函数OnStkReceiverData(),等待接收消息。

2.stknet对话框直接向通视注册自己的窗口句柄。(可以弹出窗口显示通视驱动接收情况?)

3.stkreceiver向通视注册自己的窗口句柄。

4.stkreceiver收到消息后向各窗口分发消息及数据。

5.各窗口处理数据。

 

 

参考写法

G:\stock\Tskingfromgoogle\src\NetTS\Stockdrv.cpp

1.打开通视驱动选择窗口后,点击连接,向通视驱动注册了窗口句柄和消息WM_APP_STKRECEIVER_TSDATA

G:\stock\TskingVS2019\src\Client\StkNet\Src\SelectEngineDlg.cpp

//通视驱动初始化
void CSelectEngineDlg::OnSetupreceiver() 
{
	int	nSel = m_listEngine.GetCurSel();
	if( LB_ERR == nSel )
	{
		AfxMessageBox( AfxModuleLoadString(IDS_SELECTENGINE_ERRSELECT), MB_OK );
		return;
	}

	int	nData = (int)m_listEngine.GetItemData(nSel);
	if( nData >= 0 && nData<m_astrDriver.GetSize() )
	{
		m_drv.Stock_Quit(GetSafeHwnd());
		m_drv.UnloadDriver();

		if( m_drv.LoadDriver( m_astrDriver[nData] )
			&& m_drv.Stock_Init(GetSafeHwnd(),WM_APP_STKRECEIVER_TSDATA,RCV_WORK_SENDMSG) )
		{
			m_drv.SetupReceiver(TRUE);
		}
		else
			AfxMessageBox( AfxModuleLoadString(IDS_SELECTENGINE_ERRLOAD), MB_OK );
	}
	m_btnSetup.EnableWindow( FALSE );
}

 

这里也有,应该是发送初始化消息后执行这里?待定

G:\stock\TskingVS2019\src\Client\StkNet\Src\StkReceiver.cpp

LRESULT CStkReceiver::OnStkReceiverInit(WPARAM wParam, LPARAM lParam)
{
	// 通视及兼容设备
	{
		CStringArray astrProvider, astrDriver;
		if (!wParam)
		{
			CSelectEngineDlg	dlg;
			if (IDOK != dlg.DoModal())
				return -1L;
			dlg.GetSelectedDriver(astrProvider, astrDriver);
		}
		
		if (astrDriver.GetSize() <= 0)
		{
			CSPStringArray	aProDefault, aDrvDefault;
			AfxGetProfile().GetRcvDriverDefault(aProDefault, aDrvDefault);
			for(int i=0; i<aProDefault.GetSize(); i++)	astrProvider.Add(aProDefault[i]);
			for(int i=0; i<aDrvDefault.GetSize(); i++)		astrDriver.Add(aDrvDefault[i]);
		}

		if (astrDriver.GetSize() <= 0)
		{
			// AfxRegQueryString(HKEY_LOCAL_MACHINE, _T("Software"), _T("stockdrv"), _T("兼容设备"), astrProvider, astrDriver);
			astrProvider.InsertAt(0, AfxRegQueryString(HKEY_LOCAL_MACHINE, _T("Software"), _T("stockdrv"), "", "", _T("Provider"), "Tongshi"));
			astrDriver.InsertAt(0, AfxRegQueryString(HKEY_LOCAL_MACHINE, _T("Software"), _T("stockdrv"), "", "", _T("Driver"), "Stock.dll"));
		}
		
		// 数据共享引用
		gSTOCKDLL.Stock_Quit(m_hWnd);
		gSTOCKDLL.UnloadDriver();
		if (gSTOCKDLL.LoadDriver(astrDriver)
			&& gSTOCKDLL.GetStockDrvInfo(RI_SUPPORTEXTHQ, NULL)
			&& gSTOCKDLL.Stock_Init(m_hWnd,WM_APP_STKRECEIVER_TSDATA,RCV_WORK_SENDMSG) > 0)
			m_bTongshiRunning	=	TRUE;
		else if (!wParam)
			AfxMessageBox(AfxModuleLoadString(IDS_SELECTENGINE_ERRLOAD), MB_OK | MB_ICONINFORMATION);
	}

	return TRUE;
}

 

G:\stock\TskingVS2019\src\Client\StkNet\Src\StkReceiver.cpp

定义了     消息的处理函数

BEGIN_MESSAGE_MAP(CStkReceiver, CWnd)
	//{{AFX_MSG_MAP(CStkReceiver)
	ON_WM_CREATE()
	ON_WM_DESTROY()
	//}}AFX_MSG_MAP
	ON_MESSAGE(WM_APP_STKRECEIVER_CONNECTSERVER,OnStkReceiverConnectserver)
	ON_MESSAGE(WM_APP_STKRECEIVER_DISCONNECTSERVER,OnStkReceiverDisconnectserver)
	ON_MESSAGE(WM_APP_STKRECEIVER_INIT,OnStkReceiverInit)
	ON_MESSAGE(WM_APP_STKRECEIVER_SETUP,OnStkReceiverSetup)
	ON_MESSAGE(WM_APP_STKRECEIVER_QUIT,OnStkReceiverQuit)
	ON_MESSAGE(WM_APP_STKRECEIVER_TSDATA,OnStkReceiverTsdata)  //收到消息的处理函数
END_MESSAGE_MAP()

 

消息处理函数

G:\stock\TskingVS2019\src\Client\StkNet\Src\StkReceiver.cpp
// 通视处理数据
LRESULT CStkReceiver::OnStkReceiverTsdata(
		UINT wFileType,				// 文件类型, 参见 StockDrv.H
		LONG lPara)
{
	int	i = 0;
	PBYTE pFileBuf = NULL;
	PBYTE pBuffx = NULL;
	PGZLXBINDATA pGZLX = NULL;
	RCV_DATA *	pHeader = (RCV_DATA *) lPara;

	// 检查参数
	ASSERT(pHeader && pHeader->m_pData);
	if (!pHeader || !pHeader->m_pData)
		return -1L;
	// ASSERT(pHeader->m_nPacketNum > 0 || pHeader->m_bDISK);
	if (pHeader->m_nPacketNum <= 0 && !pHeader->m_bDISK)
		return -1L;

	//	对于处理较慢的数据类型,建议将数据备份,另创建一线程处理
	switch(wFileType)
	{
	case RCV_REPORT:
		{
			// 检查参数
			//ASSERT(pHeader->m_nPacketNum > 0 && !pHeader->m_bDISK);
			if (pHeader->m_nPacketNum <= 0 || pHeader->m_bDISK)
				return -1L;
			
			// 分配备份数据存储空间
			COMMPACKET * pCommPacket = AllocCommPacket(CStock::dataReport, pHeader->m_nPacketNum);
			if (NULL == pCommPacket)
				return -1L;

			// 修改AfxGetStockContainer()
			int nBufSize = pHeader->m_pReport[0].m_cbSize;
			PBYTE pBaseBuf = (PBYTE)&pHeader->m_pReport[0];
			for(i=0; i<pHeader->m_nPacketNum; i++)
			{
				PRCV_REPORT_STRUCTEx pReport = (PRCV_REPORT_STRUCTEx)(pBaseBuf + nBufSize*i);
				if (convert_TSREPORT_to_REPORT(pReport, &(pCommPacket->m_pReport[i])))
				{
					/* 以下代码转移到新建线程中执行 */
					// AfxGetStkReceiver().OnReceiveReport(&(pCommPacket->m_pReport[i]));
				}
			}
			
			{
				CSingleLock		lock(&g_mutexCommPacket,TRUE);
				g_aptrCommPacket.Add(pCommPacket);
			}

			/* 以下代码转移到新建线程中执行
			// 保存至本地文件
			AfxGetDB().StoreReport(pCommPacket->m_pReport, pCommPacket->m_dwCount, FALSE);

			// 通知各股票信息显示窗口,刷新行情数据
			for(i=0; i<m_awndRcvData.GetSize(); i++)
				::SendMessage(m_awndRcvData[i], WM_APP_STKRECEIVER_DATA, CStock::dataReport, (LPARAM)pCommPacket);

			// 释放备份数据存储空间
			FreeCommPacket(pCommPacket);
			*/ 
		}
		break;
	
	case RCV_FILEDATA:
		switch(pHeader->m_wDataType)
		{
		case FILE_HISTORY_EX:						// 补日线数据
			{
				RCV_HISTORY_STRUCTEx * pDay = pHeader->m_pDay;
				int	nPacketNum	=	pHeader->m_nPacketNum;
				CKData	kdata(CKData::ktypeDay);
				CString	sCode;
				DWORD	dwMarket = CStock::marketUnknown;

				// 读取文件
				if (pHeader->m_bDISK)
				{
					pDay	=	NULL;
					CFile	file;
					if (file.Open(pHeader->m_File.m_szFileName,CFile::modeRead))
					{
						ASSERT(file.GetLength() == pHeader->m_File.m_dwLen);
						nPacketNum	=	(int)(file.GetLength()/sizeof(RCV_HISTORY_STRUCTEx));
						if (nPacketNum > 0)
							pDay = new RCV_HISTORY_STRUCTEx[nPacketNum];
						if (pDay)
							file.Read(pDay, sizeof(RCV_HISTORY_STRUCTEx)*nPacketNum);
						file.Close();
					}
				}

				// 分配备份数据存储空间
				COMMPACKET * pCommPacket = AllocCommPacket(CStock::dataK, nPacketNum);
				if (NULL == pCommPacket)
					return -1L;

				// 处理数据
				DWORD	dwCount	=	0;
				for(i=0; i<nPacketNum && pDay; i++)
				{
					if (pDay[i].m_head.m_dwHeadTag == EKE_HEAD_TAG)
					{
						if (kdata.GetSize() > 0)
						{
							kdata.AutoSetKType();
							UpdateStockContainerByKData(AfxGetStockContainer(), sCode, kdata);
							AfxGetDB().InstallKData(kdata);
							kdata.RemoveAll();
						}
						sCode		=	pDay[i].m_head.m_szLabel;
						dwMarket	=	TSMarket_to_Market(pDay[i].m_head.m_wMarket);
						continue;
					}
					convert_TSHISTORY_to_KDATA(dwMarket, sCode, &(pDay[i]), &(pCommPacket->m_pKdata[dwCount]));
					kdata.Add(pCommPacket->m_pKdata[dwCount]);
					dwCount	++;
				}
				pCommPacket->m_dwCount	=	dwCount;
				if (pHeader->m_bDISK && pDay)
					delete [] pDay;
				if (kdata.GetSize() > 0)
				{
					kdata.AutoSetKType();
					UpdateStockContainerByKData(AfxGetStockContainer(), sCode, kdata);
					AfxGetDB().InstallKData(kdata);
				}

				// 通知各股票信息显示窗口,刷新行情数据
				for(i=0; i<m_awndRcvData.GetSize(); i++)
					::SendMessage(m_awndRcvData[i], WM_APP_STKRECEIVER_DATA, CStock::dataK, (LPARAM)pCommPacket);
	
				// 释放备份数据存储空间
				FreeCommPacket(pCommPacket);
			}
			break;

		case FILE_MINUTE_EX:						// 补分钟线数据
		case 83:	// 补分笔数据
			{
				RCV_MINUTE_STRUCTEx * pMin = pHeader->m_pMinute;
				ASSERT(pMin->m_head.m_dwHeadTag == EKE_HEAD_TAG);
				CMinute	minute;
				BOOL bAutoSaveKDataMin = AfxGetProfile().GetAutoSaveKDataMin(); // 作为分钟K线保存
				CString	sCode;
				DWORD	dwMarket = CStock::marketUnknown;
				
				// 分配备份数据存储空间
				COMMPACKET * pCommPacket = AllocCommPacket(CStock::dataMinute, pHeader->m_nPacketNum);
				if (NULL == pCommPacket)
					return -1L;

				DWORD	dwCount	=	0;
				for(i=0; i<pHeader->m_nPacketNum; i++)
				{
					if (pMin[i].m_head.m_dwHeadTag == EKE_HEAD_TAG)
					{
						if (minute.GetSize() > 0)
						{
							CKData	kdMin(CKData::ktypeMin5);
							if (minute.ToKData(kdMin))
								AfxGetDB().InstallKData(kdMin);
							minute.RemoveAll();
						}
						sCode		=	pMin[i].m_head.m_szLabel;
						dwMarket	=	TSMarket_to_Market(pMin[i].m_head.m_wMarket);
						continue;
					}
					convert_TSMINUTE_to_MINUTE(dwMarket, sCode, &(pMin[i]), &(pCommPacket->m_pMinute[dwCount]));
					if (bAutoSaveKDataMin)
						minute.Add(pCommPacket->m_pMinute[dwCount]);
					dwCount	++;
				}
				pCommPacket->m_dwCount	=	dwCount;
				if (minute.GetSize() > 0)
				{
					CKData	kdMin(CKData::ktypeMin5);
					if (minute.ToKData(kdMin))
						AfxGetDB().InstallKData(kdMin);
				}

				// 保存至本地文件
				AfxGetDB().StoreMinute(pCommPacket->m_pMinute, pCommPacket->m_dwCount);

				// 通知各股票信息显示窗口,刷新行情数据
				for(i=0; i<m_awndRcvData.GetSize(); i++)
					::SendMessage(m_awndRcvData[i], WM_APP_STKRECEIVER_DATA, CStock::dataMinute, (LPARAM)pCommPacket);

				// 释放备份数据存储空间
				FreeCommPacket(pCommPacket);
			}
			break;

		case FILE_POWER_EX:							// 补充除权数据
			{
				RCV_POWER_STRUCTEx * pPower = pHeader->m_pPower;
				int	nPacketNum	=	pHeader->m_nPacketNum;
				CDRData	drdata;
				CString	sCode;
				DWORD	dwMarket = CStock::marketUnknown;

				if (pHeader->m_bDISK)
				{
					pPower	=	NULL;
					CFile	file;
					if (file.Open(pHeader->m_File.m_szFileName,CFile::modeRead))
					{
						ASSERT(file.GetLength() == pHeader->m_File.m_dwLen);
						nPacketNum	=	(int)(file.GetLength()/sizeof(RCV_POWER_STRUCTEx));
						if (nPacketNum > 0)
							pPower = new RCV_POWER_STRUCTEx[nPacketNum];
						if (pPower)
							file.Read(pPower, sizeof(RCV_POWER_STRUCTEx)*nPacketNum);
						file.Close();
					}
				}

				// 分配备份数据存储空间
				COMMPACKET * pCommPacket = AllocCommPacket(CStock::dataDR, nPacketNum);
				if (NULL == pCommPacket)
					return -1L;

				DWORD	dwCount	=	0;
				for(i=0; i<nPacketNum && pPower; i++)
				{
					if (pPower[i].m_head.m_dwHeadTag == EKE_HEAD_TAG)
					{
						if (drdata.GetSize() > 0)
							AfxGetDB().InstallDRData(drdata);
						drdata.RemoveAll();
						sCode		=	pPower[i].m_head.m_szLabel;
						dwMarket	=	TSMarket_to_Market(pPower[i].m_head.m_wMarket);
						continue;
					}
					convert_TSPOWER_to_DRDATA(dwMarket, sCode, &(pPower[i]), &(pCommPacket->m_pDrdata[dwCount]));
					drdata.Add(pCommPacket->m_pDrdata[dwCount]);
					dwCount	++;
				}
				if (pHeader->m_bDISK && pPower)
					delete [] pPower;
				if (drdata.GetSize() > 0)
					AfxGetDB().InstallDRData(drdata);
				pCommPacket->m_dwCount	=	dwCount;

				// 通知各股票信息显示窗口,刷新行情数据
				for(i=0; i<m_awndRcvData.GetSize(); i++)
					::SendMessage(m_awndRcvData[i], WM_APP_STKRECEIVER_DATA, CStock::dataDR, (LPARAM)pCommPacket);

				// 释放备份数据存储空间
				FreeCommPacket(pCommPacket);
			}
			break;

		case FILE_MULTISORT_EX:					// 综合排名
			{
				RCV_MULTISORT_STRUCTEx * pMultisort = pHeader->m_pMultisort;
				
				// 分配备份数据存储空间
				COMMPACKET * pCommPacket = AllocCommPacket(CStock::dataMultisort, pHeader->m_nPacketNum);
				if (NULL == pCommPacket)
					return -1L;

				for(i=0; i<pHeader->m_nPacketNum; i++)
				{
					convert_TSMULTISORT_to_MULTISORT(&(pMultisort[i]), &(pCommPacket->m_pMultisort[i]));
				}
				pCommPacket->m_dwCount	=	pHeader->m_nPacketNum;

				// 通知各股票信息显示窗口,刷新行情数据
				for(i=0; i<m_awndRcvData.GetSize(); i++)
					::SendMessage(m_awndRcvData[i], WM_APP_STKRECEIVER_DATA, CStock::dataMultisort, (LPARAM)pCommPacket);

				// 释放备份数据存储空间
				FreeCommPacket(pCommPacket);
			}
			break;

		case FILE_BASE_EX:						// 钱龙兼容基本资料文件,m_szFileName仅包含文件名
			{
				if (pHeader->m_bDISK)
				{
					AfxGetDB().InstallBaseText(pHeader->m_File.m_szFileName, AfxGetFileTitle(pHeader->m_File.m_szFileName));
				}
				else
				{
					AfxGetDB().InstallBaseText(LPCTSTR(pHeader->m_pData), pHeader->m_File.m_dwLen, AfxGetFileTitle(pHeader->m_File.m_szFileName));
				}

				// 分配备份数据存储空间
				COMMPACKET * pCommPacket = AllocCommPacket(CStock::dataCode, 1);
				if (NULL == pCommPacket)
					return -1L;
				CString	sTemp	=	AfxGetFileTitleNoExt(pHeader->m_File.m_szFileName);
				strncpy(pCommPacket->m_pStockcode[0].m_szCode, sTemp, min(sizeof(pCommPacket->m_pStockcode[0].m_szCode)-1,sTemp.GetLength()));
				pCommPacket->m_pStockcode[0].m_dwMarket	=	CStock::marketUnknown;

				// 通知各股票信息显示窗口,刷新行情数据
				for(i=0; i<m_awndRcvData.GetSize(); i++)
					::SendMessage(m_awndRcvData[i], WM_APP_STKRECEIVER_DATA, CStock::dataBasetext, (LPARAM)pCommPacket);

				// 释放备份数据存储空间
				FreeCommPacket(pCommPacket);
			}
			break;

		case FILE_NEWS_EX:						// 新闻类,其类型由m_szFileName中子目录名来定
			if (pHeader->m_bDISK)
			{
				AfxGetDB().InstallNewsText(pHeader->m_File.m_szFileName, AfxGetFileTitle(pHeader->m_File.m_szFileName));
			}
			else
			{
				AfxGetDB().InstallNewsText(LPCTSTR(pHeader->m_pData), pHeader->m_File.m_dwLen, AfxGetFileTitle(pHeader->m_File.m_szFileName));
			}
			// 通知各股票信息显示窗口,刷新行情数据
			for(i=0; i<m_awndRcvData.GetSize(); i++)
				::SendMessage(m_awndRcvData[i], WM_APP_STKRECEIVER_DATA, CStock::dataNews, NULL);
			break;

		case FILE_HTML_EX:						// HTML文件,m_szFileName为URL
			AfxGetProfile().AddHTMLURLToExplorer(pHeader->m_File.m_szFileName);
			break;

		case FILE_SOFTWARE_EX:
			TRACE("%s\n",pHeader->m_File.m_szFileName);
			TRACE("%d\n",pHeader->m_File.m_dwLen);
			pBuffx = (PBYTE)pHeader->m_pData;
			break;

		case FILE_SHAZQDATA_EX:		//h上海国债净价交易
			break;
		case FILE_TYPE_RES:
			TRACE("MSG: CStkReceiver::OnStkDataOK, Replaced data \n");
			break;
		default:
			TRACE("Msg: CStkReceiver::OnStkReceiverData,Unkonw data type\n");
		}
		break;
	}

	return 0L;
}

 

上面是中心点,然后发送WM_APP_STKRECEIVER_DATA消息和数据给各窗口,由各窗口自行处理。

// 通知各股票信息显示窗口,刷新行情数据
				for(i=0; i<m_awndRcvData.GetSize(); i++)
					::SendMessage(m_awndRcvData[i], WM_APP_STKRECEIVER_DATA, CStock::dataDR, (LPARAM)pCommPacket);

 

如:行情实时窗口

G:\stock\TskingVS2019\src\Client\StkUI\View\RealTimeView.cpp

ON_MESSAGE(WM_APP_STKRECEIVER_DATA, OnStkReceiverData)

G:\stock\TskingVS2019\src\Client\StkUI\View\RealTimeView.cpp

//有数据传过来
LRESULT CRealTimeView::OnStkReceiverData(WPARAM wParam, LPARAM lParam)
{
	for(int i = 0; i < m_nMultiStockCount && i < RTV_MAX_MULTICOUNT; i++)
		m_realtime[i].OnStkReceiverData(wParam,lParam);
	return 0;
}