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);
}