策略为王源代码-主程序启动原理分析-StkUI.cpp

Published

一、启动过程简介

主程序启动原理1:获取版本号

主程序启动原理2:加载配置文件,设置主目录 E:\Stock\Tsking\src\StkUI\StkUI.cpp

主程序启动原理3:根据加载的配置文件,设置主目录 AfxGetProfile().GetWorkDirectory()==E:\Stock\Tsking\src\Bin

程序启动原理4:设置注册表

程序启动原理5:Empty Temp Directory

程序启动原理:6,设置网络数据库

程序启动原理:7,设置本地数据库目录、设置主目录、指定使用SelfDB接口

 

程序启动原理:9 .从磁盘加载本地数据,写入到容器。

程序启动原理:10.启动“连接行情服务器”对话框,下载数据(从数据服务器下载,写入本地磁盘文件)

程序启动原理:11.下载数据后,本地磁盘数据有更新,便用LoadProgram((HWND)pMainFrame,0,1000);再次重新装载数据到容器。

 

二、启动代码如下:

BOOL CStkUIApp::InitInstance()
{
	// Standard initialization
	// If you are not using these features and wish to reduce the size
	//  of your final executable, you should remove from the following
	//  the specific initialization routines you do not need.
	AfxSocketInit();  //网路请求socket

	AfxOleInit();      //表格控件?

	// 程序只能启动一个实例
	m_pMutex = CreateMutex(NULL, FALSE, _T("TsKing"));
	if (m_pMutex != NULL)
	{
		if (GetLastError() == ERROR_ALREADY_EXISTS)
		{
			CloseHandle(m_pMutex);
			m_pMutex = NULL;
			AfxMessageBox("程序已经运行!"); //add by freeman 2019/06/08
			return FALSE;
		}
	}


	//step 1:主程序启动原理:获取版本号
	GetVersionNumber();

	//step 2:读取配置文件,获取配置参数
	//程序启动原理:1.StkUI.cpp中,加载配置文件,在E:\Stock\Tsking\src\StkLib\Src\Profile.cpp,配置文件名为:profile.set
	AfxGetProfile().LoadProfile();

	//step 3:设置主目录
	::SetCurrentDirectory(AfxGetProfile().GetWorkDirectory());  //AfxGetProfile().GetWorkDirectory()==E:\Stock\Tsking\src\Bin
	AfxGetSView().Load(AfxGetProfile().GetSViewFile());  //AfxGetProfile().GetSViewFile()==E:\Stock\Tsking\src\Bin\profile.dat

	// 修改注册表,保存路径和版本。Change the registry key under which our settings are stored.
	// TODO: You should modify this string to be something appropriate
	// such as the name of your company or organization.
	/**********设置注册表********
	* 前面定义的常量
	* TCHAR szRegKeyCompany[] = _T("Tsking Stock Software");
	* TCHAR szRegKeyApp[] = _T("Tsking");
	AfxGetProfile().GetWorkDirectory()=G:\stock\TskingVS2019\src\Client\Bin\
	 AfxGetProfile().GetVersion()=3.10
	***********************************/

	//程序启动原理:3.设置注册表
	// SetRegistryKey( szRegKeyCompany );
	AfxRegSetValue(szRegKeyCompany, szRegKeyApp, "Install", "Path", AfxGetProfile().GetWorkDirectory());
	AfxRegSetValue(szRegKeyCompany, szRegKeyApp, "Install", "Version", AfxGetProfile().GetVersion());

	// 修改INI文件名
	BOOL bEnable = AfxEnableMemoryTracking(FALSE);
	if (m_pszProfileName)	free((void*)m_pszProfileName);
	m_pszProfileName = _tcsdup(AfxGetProfile().GetWorkDirectory() + m_pszExeName + ".ini");
	AfxEnableMemoryTracking(bEnable);

	LoadStdProfileSettings(64);  // Load standard INI file options (including MRU)

	// Register the application's document templates.  Document templates
	//  serve as the connection between documents, frame windows and views.

	// Enable DDE Execute open
	EnableShellOpen();
	AfxUnregisterShellFileTypes();
	// AfxRegisterShellFileTypes(FALSE);

	
	AfxGetProfile().LoadProfile();
	//程序启动原理:4.Empty Temp Directory
	{
		CNetDatabase netdb;
		if (netdb.SetRootPath(AfxGetProfile().GetSelfDBPath(), IStStore::dbtypeSelfDB))
			netdb.EmptyTempDirectory();
	}

	////AfxGetNetDB()是一个静态的CNetDatabase类,* g_pdb指向此类,
	//程序启动原理:5,设置网络数据库
	AfxSetDB(&AfxGetNetDB());
	//*/

	//程序启动原理:6,设置本地数据库目录、设置主目录、指定使用钱龙接口
	// Load Data
	/*功能:从物理盘读取数据到本地数据库
	1.根据设定的主目录,如果不存在子目录,则创建子目录
	2.指定主用哪个自有数据库,这里指定的是selfdb。可选用selfdb,qianlong、shenglong中的哪个为主,取数时的时候,只有指定的IStStore::dbtypeSelfDB取不到数时,才会用循环从其他几个注册了的数据库接口来获取数据
	3.注册qianlong的实现,取数时的时候,只有指定的数据接口(如:IStStore::dbtypeSelfDB)取不到数时,才会用循环从其他几个注册了的数据库接口来获取数据
	*/
	char szErr[1024];
	if (!AfxInitializeDB(szErr, sizeof(szErr)))
	{
		AfxMessageBox(szErr, MB_OK | MB_ICONINFORMATION);
		return FALSE;
	}


	// 程序启动原理:7:初始化股票容器,把从本地数据库的数据填充到股票数组容器中
	AfxGetStockContainer().Load(&AfxGetDB(), NULL, NULL);				// 这里只读取证券代码表、财务。//调用OnDataChanged(),该函数里面设置财务数据、技术指标、股票均价等。
	AfxGetDomainContainer().Load(AfxGetProfile().GetDomainFile());		// 读取板块 ;AfxGetProfile().GetDomainFile()=GetWorkDirectory() + "data\\domain.dat" by freeman
	AfxGetGroupContainer().Load(AfxGetProfile().GetGroupFile());		// 读取自选板块。实际是自选股和省份板块。AfxGetProfile().GetGroupFile()=GetWorkDirectory() + "data\\group.dat" by freeman


	



	// 分析标准外壳命令、DDE、打开文件操作的命令行
	CCommandLineInfo cmdInfo;
	ParseCommandLine(cmdInfo);

#ifdef _TSK_MAINFRAME
	// 注册应用程序的文档模板。文档模板
	// 将用作文档、框架窗口和视图之间的连接
	CSingleDocTemplate* pDocTemplate;
	pDocTemplate = new CSingleDocTemplate(
		IDR_MAINFRAME,
		RUNTIME_CLASS(CStaticDoc),
		RUNTIME_CLASS(CMainFrame),       // 主 SDI 框架窗口
		RUNTIME_CLASS(CSListView));
	if (!pDocTemplate)
		return FALSE;
	AddDocTemplate(pDocTemplate);

	// 调度在命令行中指定的命令。如果
	// 用 /RegServer、/Register、/Unregserver 或 /Unregister 启动应用程序,则返回 FALSE。
	if (!ProcessShellCommand(cmdInfo))
		return FALSE;
#else
	// Create MainFrame and Static Doc and child frames and static views
	CStaticDoc* pStaticDoc = CStaticDoc::OpenDocumentFile(NULL);
	if (pStaticDoc == NULL)
	{
		AfxMessageBox(IDS_STATICDOC_FAILED, MB_OK | MB_ICONINFORMATION);
		return FALSE;
	}
	pStaticDoc->m_bAutoDelete = FALSE;
	CString	strAppTitle;
	strAppTitle.LoadString(AFX_IDS_APP_TITLE);
	pStaticDoc->SetTitle(strAppTitle);
	SetStaticDoc(pStaticDoc);

	// Create MainFrame
	CMainFrame* pMainFrame = CMainFrame::CreateNewFrame();

	//SendMessage(AfxGetMainFrame()->GetSafeHwnd(), WM_INPUTLANGCHANGEREQUEST, 1, 0x04090409);

	if (pMainFrame == NULL)
	{
		AfxMessageBox(IDS_STATICDOC_FAILED, MB_OK | MB_ICONINFORMATION);
		delete pStaticDoc;
		SetStaticDoc(NULL);
		return FALSE;
	}
	SetMainWnd(pMainFrame);
#endif

	// 股票行情接收
	AfxGetStkReceiver().CreateReceiver(m_pMainWnd);
	AfxGetStkReceiver().NetEngineSetAutoReport(FALSE);


	//程序启动原理:8,Show Startup Window  启动连接行情服务器对话框  by freeman
	//CStartupDlg startup;
	//CBitmap	bmp;
	//bmp.LoadBitmap(IDB_DLGLEFTLOGO);
	//startup.SetBitmap((HBITMAP)bmp.GetSafeHandle());
	//startup.SetLoadProgramFunc(LoadProgram);
	//if (IDOK != startup.DoModal())
	//{
	//	pMainFrame->SendMessage(WM_CLOSE);
	//	return FALSE;
	//}
	LoadProgram((HWND)pMainFrame, 0, 1000);

	//Show Splash Window
   /*CSplashDlg splash;
   CBitmap bmp;
   bmp.LoadBitmap(IDB_SPLASH);
   splash.SetBitmap(HBITMAP(bmp.GetSafeHandle()));
   splash.Create(NULL, 0, AfxGetSView().GetU(), AfxGetSView().GetS(), AfxGetVersionString(), FALSE, 0, STKLIB_MAX_PROGRESS);
   splash.ShowWindow(SW_SHOW);
   splash.UpdateWindow();
   LoadProgram(splash.GetSafeHwnd(), 0, STKLIB_MAX_PROGRESS);
   splash.DestroyWindow();*/
   //

   // //////////////////////////////////////////////////////////////

   // Open Simulation Strategy
	if (GetFirstStrategyPosition() == NULL)
	{
		if (OpenLastOpenedStrategy() == 0)
			OpenDefaultStrategy();
	}

	//if (!AfxGetStaticDoc()->GetViewIfExist(RUNTIME_CLASS(CSListView)))
	//	AfxGetStaticDoc()->ShowStaticView(RUNTIME_CLASS(CSListView), TRUE);

	//AfxSwitchToStaticView(RUNTIME_CLASS(CSListView));

	AfxGetProfile().SetCurrentStock(STKLIB_CODE_SZZS, FALSE);
	//装载键盘精灵数据
	((CMainFrame*)m_pMainWnd)->m_SearchBox.InitStocks(TRUE, TRUE, TRUE);
	((CMainFrame*)m_pMainWnd)->m_SearchBox.SetCurrentWindowText();

	//*//////////////////////////////////////////////////////////////

	// Dispatch commands specified on the command line
	if (CCommandLineInfo::AppUnregister == cmdInfo.m_nShellCommand)
	{
		AfxUnregisterShellFileTypes();
		if (!cmdInfo.m_bRunEmbedded)
			AfxMessageBox(AFX_IDP_UNREG_DONE, MB_OK | MB_ICONINFORMATION);
		if (m_pCmdInfo == NULL)
		{
			m_pCmdInfo = new CCommandLineInfo;
			m_pCmdInfo->m_nShellCommand = CCommandLineInfo::AppUnregister;
		}
		return FALSE;
	}

	// Dispatch commands specified on the command line
	if (cmdInfo.m_nShellCommand == CCommandLineInfo::FileOpen)
	{
		OpenStrategyFile(cmdInfo.m_strFileName);
		AfxSwitchToStaticView(RUNTIME_CLASS(CSimuView));
	}

	// 启动通视接收系统,不显示选择接收系统对话框
	//AfxGetStkReceiver().EngineBeginWorking(FALSE);

	// The one and only window has been initialized, so show and update it.
	// Load Last WindowPlacement
	WINDOWPLACEMENT wp;
	if (AfxGetProfile().GetWindowPlacement(&wp))
		m_pMainWnd->SetWindowPlacement(&wp);
	else
		m_pMainWnd->ShowWindow(SW_SHOWMAXIMIZED);

	// Enable drag/drop open
	//m_pMainWnd->DragAcceptFiles();

	// Check New Version
	m_pMainWnd->SetTimer(TIMER_AUTOUPDATE, 5000, NULL); //检查版本升级的定时器 by freeman

	return TRUE;
				}

 

三、启动过程详细介绍

1.读取设置文件

//step 2:读取配置文件,获取配置参数
	//程序启动原理:1.StkUI.cpp中,加载配置文件,在E:\Stock\Tsking\src\StkLib\Src\Profile.cpp,配置文件名为:profile.set
	AfxGetProfile().LoadProfile();

	//step 3:设置主目录
	::SetCurrentDirectory(AfxGetProfile().GetWorkDirectory());  //AfxGetProfile().GetWorkDirectory()==E:\Stock\Tsking\src\Bin
	AfxGetSView().Load(AfxGetProfile().GetSViewFile());  //AfxGetProfile().GetSViewFile()==E:\Stock\Tsking\src\Bin\profile.dat

2.初始化本地数据库,主要功能:负责把物理盘上的文件读取到本地数据库中

char szErr[1024];
	if (!AfxInitializeDB(szErr, sizeof(szErr)))
	{
		AfxMessageBox(szErr, MB_OK | MB_ICONINFORMATION);
		return FALSE;
	}

/*功能:
1.根据设定的主目录,如果不存在子目录,则创建子目录
2.指定主用哪个自有数据库,这里指定的是selfdb。可选用selfdb,qianlong、shenglong中的哪个为主,取数时的时候,只有指定的IStStore::dbtypeSelfDB取不到数时,才会用循环从其他几个注册了的数据库接口来获取数据
3.注册qianlong的实现,取数时的时候,只有指定的数据接口(如:IStStore::dbtypeSelfDB)取不到数时,才会用循环从其他几个注册了的数据库接口来获取数据

*/

CStDatabase & AfxGetDB()
{
	if( g_pdb )	return *g_pdb;

	static	CStDatabase	g_stdatabase;
	return g_stdatabase;
}

 

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

调用链条:StkUI.cpp调用StkLib.cpp中的AfxInitializeDB( LPSTR lpErr, UINT nMaxSize )初始化本地数据库->设置一个主用数据接口->注册其他数据接口

从本地数据库加载一些数据时,首先用主用接口获取,如没有则循环调用其它接口获取,如果其中某个接口能返回所需要的数据,则中断循环。

但加载另一些数据时,则直接循环获取,如果其中某个接口能返回所需要的数据,则中断循环。如加载分时线。所以自己写的数据接口要注册

/*功能:
	1.根据设定的主目录,如果不存在子目录,则创建子目录
	2.指定主用哪个自有数据库,这里指定的是selfdb。可选用selfdb,qianlong、shenglong中的哪个为主,取数时的时候,只有指定的IStStore::dbtypeSelfDB取不到数时,才会用循环从其他几个注册了的数据库接口来获取数据
	3.注册qianlong的实现,取数时的时候,只有指定的数据接口(如:IStStore::dbtypeSelfDB)取不到数时,才会用循环从其他几个注册了的数据库接口来获取数据
	*/
	char szErr[1024];
	if (!AfxInitializeDB(szErr, sizeof(szErr)))
	{
		AfxMessageBox(szErr, MB_OK | MB_ICONINFORMATION);
		return FALSE;
	}

 

G:\stock\TskingVS2019\src\Client\StkLib\Src\AfxCore.cpp

 

//////////////////////////////////////////////////////////////////////////////////
// database functions 功能://设置本地数据库目录、设置主目录、指定使用钱龙接口
BOOL AfxInitializeDB( LPSTR lpErr, UINT nMaxSize )
{
	if( lpErr && nMaxSize > 0 )
		memset( lpErr, 0, nMaxSize );
	//根据设定的主目录,如果不存在子目录,则创建子目录
	if( !CStDatabase::CreateSelfDB( AfxGetProfile().GetSelfDBPath() ) )
	{
		if( lpErr )	strncpy( lpErr, db_errcreateselfdb, min(nMaxSize-1,strlen(db_errcreateselfdb)) );
		return FALSE;
	}

	//指定主用哪个自有数据库,这里指定的是selfdb。可选用selfdb,qianlong、shenglong中的哪个为主,取数时的时候,只有指定的IStStore::dbtypeSelfDB取不到数时,才会用循环从其他几个注册了的数据库接口来获取数据
	if( !AfxGetDB().SetRootPath( AfxGetProfile().GetSelfDBPath(), IStStore::dbtypeSelfDB ) )
	{
		if( lpErr )	strncpy( lpErr, db_errrootpath, min(nMaxSize-1,strlen(db_errrootpath)) );
		return FALSE;
	}

	//注册qianlong的实现,取数时的时候,只有指定的数据接口(如:IStStore::dbtypeSelfDB)取不到数时,才会用循环从其他几个注册了的数据库接口来获取数据
	CSPString	strQianlongPath	=	AfxGetProfile().GetQianlongPath();
	if( strQianlongPath.GetLength() > 0
		&& !AfxGetDB().AddAssistantRootPath( strQianlongPath, IStStore::dbtypeQianlong ) )
	{
		if( lpErr )	strncpy( lpErr, db_errqianlongpath, min(nMaxSize-1,strlen(db_errqianlongpath)) );
		return FALSE;
	}

	return TRUE;
}

 

2.从本地加载股票代码表、财务数据、K线数据等

// 初始化,装在本地盘上的股票数据 2019/06/09 by freeman
	AfxGetStockContainer().Load(&AfxGetDB(), NULL, NULL);				// 读取证券信息,代码表、财务、除权、K线数据、计算其他指标等
	AfxGetDomainContainer().Load(AfxGetProfile().GetDomainFile());		// 读取板块
	AfxGetGroupContainer().Load(AfxGetProfile().GetGroupFile());		// 读取自选板块

2.1 AfxGetStockContainer().Load(&AfxGetDB(), NULL, NULL);

step 2.1.1 从本地文件读取股票代码表,添加到全局变量

//加载代码表
	int	nLen	=	pDB->LoadCodetable( *this );

step 2.1.2 建立一张股票代码的哈希索引表

格式:股票代码,股票位置

SetMap( );

 

//加载代码表、加载财务数据 by freeman
BOOL CStockContainer::Load( CStDatabase * pDB, PROGRESS_CALLBACK fnCallback, void *cookie, int nProgStart, int nProgEnd )
{
	CSPMutex::Scoped	l(m_mutex);

	SP_ASSERT( nProgStart <= nProgEnd );
	SP_ASSERT( pDB );
	if( nProgStart > nProgEnd || NULL == pDB )
		return FALSE;

	Clear( );
	//加载代码表
	int	nLen	=	pDB->LoadCodetable( *this );
	SetMap( );

	//加载财务数据
	pDB->LoadBasetable( *this );
	// pDB->LoadKDataCache( *this, fnCallback, cookie, nProgStart, nProgEnd );

	m_nType		=	typeAll;
	m_dwDate	=	-1;

	//数据发生变化,函数里面设置财务数据、技术指标、股票均价等。
	OnDataChanged( );
	return TRUE;
}

//数据发生变化,函数里面设置财务数据、技术指标、股票均价等。
void CStockContainer::OnDataChanged( )
{
	CSPMutex::Scoped	l(m_mutex);

	DWORD	dateLatest = m_dwDate;
	if( -1 == dateLatest )
		AfxGetStockContainer().GetLatestTechDate( &dateLatest );

	for( int i=0; i<GetSize(); i++ )
	{
		CStockInfo	& info	=	ElementAt(i);
		//设置财务数据
		info.StatBaseIndex( dateLatest );
		//设置技术指标
		info.StatTechIndex( dateLatest );
	}

	//设置股票均价
	SetAverage( );
}

3.加载完成后计算相关技术指标

 

4.启动行情刷新程序