策略为王源代码分析-StkNet工程

Published
G:\stock\TskingVS2019\src\Client ---------- root
├── StkNet/                     ----------一个MFC dll 类,负责管理通视驱动和行情服务器.
│   ├── Include/
│   │      ├── NetDB.h----------
│   │      ├── NetDB.h----------
│   │      └── plugin.min.js
│   ├── Receiver Files/
│   │      ├── SelectEngineDlg.cpp----------
│   │      └── StkReceiver.cpp----------
│   ├── SMailer

这个工程向外提供了几个类:

CStkReceiver类:负责管理通视驱动和行情服务器NetTS.DLL.

1.加载、初始化、退出上面的驱动。

2.通过上面两者发起数据请求。

3.接收上面两者发送的消息并进行处理。即把收到的RCV_DATA格式转换为COMMPACKET。并发送消息和数据给各窗口。

发起请求的函数

//请求行情,向行情服务器发去请求
int CStkReceiver::RequestStockData(int nDataType/*CStock::DataType*/, CStockInfo * pStockInfo, int nSize, int nKType, int nDataCount) //向行情服务器发起分笔数据请求

int CStkReceiver::RequestKData(CStock *pstock, int period)

/CStkReceiver::RefreshStockContainer返回的股票数量>0 才会接收数据并处理,所以行情服务器端和通视驱动端必须有这个函数
//功能:从行情服务器或通视驱动获取最新分笔数据,更新股票信息的最新成交信息字段。
int CStkReceiver::RefreshStockContainer(CStockContainer & container, BOOL bAddIfNotExist)

/从通视驱动读取分笔数据 2019/06/08 by freeman
int CStkReceiver::GetReport(CStockInfo &info, CReport &aReport)

 

// 此函数负责通视驱动推送过来的数据。对于分笔数据,会存入缓存变量g_aptrCommPacket。
//由线程StkProcessReceiveReport(LPVOID pParam)读出,更新股票容器,发送至各窗口,发送到预警窗口。
//行情服务器NetTS.DLL中由TSDispatchThreadMain线程发送消息及数据
LRESULT CStkReceiver::OnStkReceiverTsdata(UINT wFileType,LONG lPara)

 

 处理CStkReceiver类中的g_aptrCommPacket中的Report数据的线程,由通视或NetTS.DLL发出,被TS消息处理函数存入CStkReceiver类中的g_aptrCommPacket
UINT StkProcessReceiveReport(LPVOID pParam)

调用此函数将会根据成交明细处理主力大单和盘中预警处理计算,并将处理结构 发送到预警窗口 
void CStkReceiver::OnReceiveReport(REPORT * pReport)

 

//给各窗口发送WM_APP_STKRECEIVER_DATA消息
void CStkReceiver::NotifyWndRcvData(WPARAM wParam, LPARAM lParam)

 

一、CStkReceiver:行情服务器和通视驱动的数据包在这个类里面处理。

(一)通视驱动处理部分

通视驱动推送的数据由CStkReceiver::OnStkReceiverTsdata() 负责处理。

1.此函数负责通视驱动推送过来的数据。对于分笔数据,会存入缓存变量g_aptrCommPacket

1.1收到分笔数据包,存入缓存变量g_aptrCommPacket.Add(pCommPacket);//存入全局变量

g_aptrCommPacket.Add(pCommPacket);//存入全局变量

2.开启的线程StkProcessReceiveReport(LPVOID pParam)负责处理存入缓存变量g_aptrCommPacket的数据


由线程StkProcessReceiveReport(LPVOID pParam)读出,更新股票容器,发送至各窗口,发送到预警窗口。

 

 

LRESULT CStkReceiver::OnStkReceiverTsdata(

UINT wFileType, // 文件类型, 参见 StockDrv.H

 

LONG lPara)

 

 

 

CNetDatabase:用来连接数据服务器并下载数据.功能:获取数据服务列表;选定其中一个数据服务器;登陆数据服务器;下载股票代码表、日K线数据、财务表、除权表、F10资料等

static CNetSTKDRV gNetTSDLL;用来加载NetTS.DLL从而用来连接行情服务器,因为NetTS.DLL就是用作连接行情服务器的。

static CSTKDRVContainer gSTOCKDLL; 用来加载通视驱动获取行情数据,具体包括通视驱动容器和某个通视驱动

 

1.CStkReceiver:行情服务器和通视驱动的数据包在这个类里面处理。

//创建处理分笔数据的线程

int CStkReceiver::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CWnd::OnCreate(lpCreateStruct) == -1)
		return -1;

	CStkReceiver::m_hEventKillProcessThread = CreateEvent(NULL,FALSE,FALSE,NULL);
	CStkReceiver::m_hEventProcessThreadKilled = CreateEvent(NULL,FALSE,FALSE,NULL);
	//创建处理分笔数据的线程 by freeman
	AfxBeginThread(StkProcessReceiveReport, NULL, THREAD_PRIORITY_NORMAL);

	return 0;
}

从全局变量取数据并进行处理

// 处理接收到的Report数据的线程
UINT StkProcessReceiveReport(LPVOID pParam)
{
	while (TRUE)
	{
		COMMPACKET * pCommPacket = NULL;
		{
			CSingleLock		lock(&g_mutexCommPacket,TRUE);
			if (g_aptrCommPacket.GetSize() > 0)
			{
				//从全局变量取数据
				pCommPacket = (COMMPACKET *)g_aptrCommPacket.ElementAt(0);
				g_aptrCommPacket.RemoveAt(0);
			}
		}

		if (NULL != pCommPacket && CStock::dataReport == pCommPacket->m_dwDataType)
		{
			// 修改AfxGetStockContainer()
			for(DWORD i=0; i<pCommPacket->m_dwCount; i++)
				AfxGetStkReceiver().OnReceiveReport(&(pCommPacket->m_pReport[i]));

			// 保存至本地文件
			AfxGetDB().StoreReport(pCommPacket->m_pReport, pCommPacket->m_dwCount, FALSE);

			// 通知各股票信息显示窗口,刷新行情数据
			AfxGetStkReceiver().NotifyWndRcvData(CStock::dataReport, (LPARAM)pCommPacket);

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

		Sleep(1);

		// User wants to quit program
		if (WAIT_OBJECT_0 == WaitForSingleObject(CStkReceiver::m_hEventKillProcessThread,0))
		{
			{
				CSingleLock		lock(&g_mutexCommPacket,TRUE);
				for(int i=0; i<g_aptrCommPacket.GetSize(); i++)
				{
					pCommPacket = (COMMPACKET *)g_aptrCommPacket.ElementAt(i);
					FreeCommPacket(pCommPacket);
				}
				g_aptrCommPacket.RemoveAll();
			}
			SetEvent(CStkReceiver::m_hEventProcessThreadKilled);
			AfxEndThread(0, TRUE);
			return 0;
		}
	}
}

给各窗口发送WM_APP_STKRECEIVER_DATA消息

//给各窗口发送WM_APP_STKRECEIVER_DATA消息
void CStkReceiver::NotifyWndRcvData(WPARAM wParam, LPARAM lParam)
{
	for(int i=0; i<m_awndRcvData.GetSize(); i++)
		::SendMessage(m_awndRcvData[i], WM_APP_STKRECEIVER_DATA , wParam, lParam);
}

 

数据来源:

通视驱动推送的数据由CStkReceiver::OnStkReceiverTsdata()   处理

// 通视处理数据,收到的数据存入了队列。行情服务器NetTS.DLL没有找到发送WM_APP_STKRECEIVER_TSDATA消息的代码
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;
}

二、请求行情的几个类

1.AfxGetStkReceiver().RefreshStockContainer( AfxGetStockContainer(), TRUE )类

功能:
//CStkReceiver::RefreshStockContainer返回的股票数量>0 才会接收数据并处理,所以行情服务器端和通视驱动端必须有这个函数
//功能:从行情服务器或通视驱动获取最新分笔数据,更新股票信息的最新成交信息字段。

/CStkReceiver::RefreshStockContainer返回的股票数量>0 才会接收数据并处理,所以行情服务器端和通视驱动端必须有这个函数
//功能:从行情服务器或通视驱动获取最新分笔数据,更新股票信息的最新成交信息字段。
int CStkReceiver::RefreshStockContainer(CStockContainer & container, BOOL bAddIfNotExist)
{
	//条件:行情服务器返回的股票数量>0 才会接收数据并处理
	if (gNetTSDLL.IsEngineWorking() || gNetTSDLL.GetTotalNumber() > 0)
	{
		//调用流程: 
		int	nMaxNumber	=	gNetTSDLL.GetTotalNumber();
		ASSERT(nMaxNumber >= 0);
		if (nMaxNumber <= 0)
			return 0;

		int	nNO	=	0;
		while (TRUE)
		{
			RCV_REPORT_STRUCTEx	tsreport;
			memset(&tsreport,0,sizeof(tsreport));
			int	nRet	=	gNetTSDLL.GetStockByNoEx(nNO, &tsreport);
			if (nRet <= 0)
				break;
			REPORT	report;
			if (convert_TSREPORT_to_REPORT(&tsreport, &report))
				UpdateStockContainerByREPORT(container, &report, bAddIfNotExist);

			nNO	++;
		}
		return nNO;
	}

	//条件:通视驱动返回的股票数量>0 才会接收数据并处理
	if (m_bTongshiRunning)
	{
		int	nMaxNumber	=	gSTOCKDLL.GetTotalNumber();
		ASSERT(nMaxNumber >= 0);
		if (nMaxNumber <= 0)
			return 0;

		int	nNO	=	0;
		while (TRUE)
		{
			RCV_REPORT_STRUCTEx	tsreport;
			memset(&tsreport,0,sizeof(tsreport));
			int	nRet	=	gSTOCKDLL.GetStockByNoEx(nNO, &tsreport);
			if (nRet <= 0)
				break;
			REPORT	report;
			if (convert_TSREPORT_to_REPORT(&tsreport, &report))
				UpdateStockContainerByREPORT(container, &report, bAddIfNotExist);

			nNO	++;
		}
		return nNO;
	}

	return 0;
}

查到只有G:\stock\TskingVS2019\src\Client\StkUI\StkUI.cpp里有两处调用此函数。

UINT LoadKDataCacheMain(LPVOID pParam)
{
	AfxGetDB().LoadKDataCache( AfxGetStockContainer(), NULL, NULL, 0, STKLIB_MAX_PROGRESS ); //保存最近AfxGetProfile().GetCacheDays()天K线数据
	AfxGetStockContainer().OnDataChanged( );

	//先从数据行情服务器获取最新成交明细。如无则从通视驱动获最新取成交明细。这里面有更新stockINfo中的成交信息的语句
	AfxGetStkReceiver().RefreshStockContainer( AfxGetStockContainer(), TRUE );

	//重新加载数据
	AfxReloadStockMain( );

	::PostMessage( AfxGetMainWnd()->GetSafeHwnd(), WM_USER_UPDATESLISTVIEW,0, 0 );
	::PostMessage( AfxGetMainWnd()->GetSafeHwnd(), WM_USER_INITDATES, 0, 0 );

	AfxEndThread( 0, TRUE );
	return 0;
}

 

BOOL CStkUIApp::OnDBChanged( BOOL bRecalculate )
{
	CWaitCursor	waitcursor;

	// Reload DB
	AfxGetStockContainer().Load( &AfxGetDB(), NULL, NULL );
	AfxGetDomainContainer().Load( AfxGetProfile().GetDomainFile() );
	AfxGetGroupContainer().Load( AfxGetProfile().GetGroupFile() );
	AfxGetDB().LoadKDataCache( AfxGetStockContainer(), NULL, NULL, 0, STKLIB_MAX_PROGRESS );
	AfxGetStockContainer().OnDataChanged( );
	//请求行情:分笔数据 by freeman
	AfxGetStkReceiver().RefreshStockContainer( AfxGetStockContainer(), TRUE );

	// Reload AfxGetStockMain()
	AfxReloadStockMain( );

	// Recalcuate Yield
	if( bRecalculate && IDYES == AfxMessageBox( IDS_INSTALLPAC_IFRECALCULATE, MB_YESNO|MB_ICONINFORMATION ) )
	{
		AfxRecalculateYield( AfxGetProfile().GetYieldAverageDays(), TRUE );
		AfxGetStockContainer().ReloadBase( &AfxGetDB() );
	}

	// Update SListBar
	CMainFrame	* pMainFrame	=	AfxGetMainFrame();
	if( pMainFrame )
	{
		pMainFrame->m_SearchBox.InitStocks( TRUE, TRUE, TRUE );
		pMainFrame->m_SearchBox.SetCurrentWindowText( );
		//pMainFrame->m_DateBox.InitDates( );
		//pMainFrame->m_DateBox.SetCurrentWindowText( );
	}

	// Update Views
	AfxGetSListStockContainer().ReRetrieveFromStatic( AfxGetActiveStrategy(), TRUE );
	AfxGetStaticDoc()->UpdateAllViews( NULL, UPDATE_HINT_SLISTVIEW, NULL );
	AfxGetStaticDoc()->UpdateAllViews( NULL, UPDATE_HINT_GRAPHVIEW, NULL );
	AfxGetStaticDoc()->UpdateAllViews( NULL, UPDATE_HINT_BASEVIEW, NULL );
	AfxGetStaticDoc()->UpdateAllViews( NULL, UPDATE_HINT_SIMUVIEW_REREALRUN, NULL );
	AfxGetStaticDoc()->UpdateAllViews( NULL, UPDATE_HINT_SELECTORVIEW, NULL );
	::PostMessage( AfxGetGroupView()->GetSafeHwnd(), WM_USER_UPDATEGROUPS, 0, 0 );

	return TRUE;
}

 

查到只有在安装数据时里有两处地方调用BOOL CStkUIApp::OnDBChanged( BOOL bRecalculate )函数。

void CInstallPacDlg::OnCompleted( )
{
	AfxReleaseDB();
	char	szErr[1024];
	if( !AfxInitializeDB( szErr, sizeof(szErr) ) )	AfxMessageBox( szErr, MB_OK|MB_ICONINFORMATION );

	if( m_bDBModified )
	{
		BOOL	bRecalculate	=	FALSE;
		CSPTime	tmLatest	=	0;
		if( m_bCodetableInstalled ||
			( m_netdb.SetRootPath( AfxGetProfile().GetSelfDBPath(), IStStore::dbtypeSelfDB )
			&& m_netdb.GetTimeLocalRange( &tmLatest, NULL, NULL )
			&& tmLatest.GetTime() > m_tmLatestOld.GetTime() ) )
		{
			bRecalculate	=	TRUE;
		}
		AfxGetStkUIApp()->OnDBChanged( FALSE /*bRecalculate*/ );
		m_bDBModified	=	FALSE;
	}
}

 

void CDownloadDlg::OnCancel() 
{
	// TODO: Add extra cleanup here
	m_btnCancel.EnableWindow( FALSE );
	AfxGetStkReceiver().RemoveRcvDataWnd( GetSafeHwnd() );

	AfxReleaseDB();
	char	szErr[1024];
	if( !AfxInitializeDB( szErr, sizeof(szErr) ) )	AfxMessageBox( szErr, MB_OK|MB_ICONINFORMATION );

	CDialog::OnCancel( );

	if( m_bDBModified )
	{
		BOOL	bRecalculate	=	FALSE;
		CSPTime	tmLatest	=	0;
		if( ( m_netdb.SetRootPath( AfxGetProfile().GetSelfDBPath(), IStStore::dbtypeSelfDB )
			&& m_netdb.GetTimeLocalRange( &tmLatest, NULL, NULL )
			&& tmLatest.GetTime() > m_tmLatestOld.GetTime() ) )
		{
			bRecalculate	=	TRUE;
		}
		if( m_bAutoRun )
			bRecalculate	=	FALSE;
		AfxGetStkUIApp()->OnDBChanged( FALSE /*bRecalculate*/ );
	}

	if( !m_bAutoRun )
	{
		CNetInfoDlg	dlg;
		dlg.DoModal( );

		if( AfxGetProfile().HasNewVersion()
			&& IDYES == AfxMessageBox( IDS_DOWNLOAD_UPGRADENOW, MB_YESNO ) )
		{
			CUpgradeDlg	dlg;
			dlg.SetAutoRun( TRUE );
			dlg.DoModal();
		}
	}

	CXFDialog::PostNcDestroy();
}

 

预警窗口

预警窗口句柄注册

G:\stock\TskingVS2019\src\Client\StkUI\MainFrm.cpp

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
...
// StkReceiver Alarm 预警窗口句柄加入 by freeman
	AfxGetStkReceiver().AddRcvAlarmWnd(GetSafeHwnd());
...
}

预警窗口消息定义

G:\stock\TskingVS2019\src\Client\StkNet\Include\StkReceiver.h

#define	WM_APP_STKRECEIVER_ALARM			WM_APP+7  //预警消息定义 by freeman

G:\stock\TskingVS2019\src\Client\StkUI\MainFrm.cpp

//用定时器发送预警窗口刷新消息 by freeman
		PostMessage(WM_APP_STKRECEIVER_ALARM, STKRCV_ALARM_REFRESH, 0);
/向预警窗口发送消息 by free满
void CStkReceiver::NotifyWndRcvAlarm(WPARAM wParam, LPARAM lParam)
{
	for(int i=0; i<m_awndRcvAlarm.GetSize(); i++)
		::PostMessage(m_awndRcvAlarm[i], WM_APP_STKRECEIVER_ALARM, wParam, lParam);
}