VC++MFC程序中的WinMain函数(二)

目录

为什么程序会首先调用CTestApp类的构造函数呢?

接上:VC++基于MFC的程序框架剖析(一)

接下:VC++基于MFC的程序框架剖析(三)CWinApp类的定义(afxwin.h*)


为什么程序会首先调用CTestApp类的构造函数呢?

原因:程序中定义了一个CTestApp类型的全局对象:theApp

提示: MFC程序的全局变量都放置在类视图窗口中的“全局函数和变量”分支下,单击该分支即可看到程序当前所有的全局函数和变量。双击某个全局变量,即可定位到该变量的定义处。

CTestApp定义文件(Test.h):

// CTestApp:
// 有关此类的实现,请参阅 Test.cpp
//

class CTestApp : public CWinApp
{
public:
	CTestApp() noexcept;


// 重写
public:
	virtual BOOL InitInstance();
	virtual int ExitInstance();

// 实现
	afx_msg void OnAppAbout();
	DECLARE_MESSAGE_MAP()
};

extern CTestApp theApp;

CTestApp构造函数,源文件(Test.cpp):

// CTestApp 构造

CTestApp::CTestApp() noexcept
{
	// 支持重新启动管理器
	m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_ALL_ASPECTS;
#ifdef _MANAGED
	// 如果应用程序是利用公共语言运行时支持(/clr)构建的,则: 
	//     1) 必须有此附加设置,“重新启动管理器”支持才能正常工作。
	//     2) 在您的项目中,您必须按照生成顺序向 System.Windows.Forms 添加引用。
	System::Windows::Forms::Application::SetUnhandledExceptionMode(System::Windows::Forms::UnhandledExceptionMode::ThrowException);
#endif

	// TODO: 将以下应用程序 ID 字符串替换为唯一的 ID 字符串;建议的字符串格式
	//为 CompanyName.ProductName.SubProduct.VersionInformation
	SetAppID(_T("Test.AppID.NoVersion"));

	// TODO: 在此处添加构造代码,
	// 将所有重要的初始化放置在 InitInstance 中
}

程序执行的顺序:theApp全局对象定义处、CTestApp构造函数、WinMain函数。

在程序入口main函数加载时,系统就已经为全局变量或全局对象分配了存储空间,并为它们赋了初始值。

小技巧: 在程序运行过程中,如果想要查看某个变量的当前值,那么方法一是把鼠标移到该变量上停留片刻,Visual Studio就会弹出一个小窗口,在此窗口中显示了该变量的当前值,如图所示:

为什么全局变量theApp的构造函数会在WinMain函数之前执行?为什么要定义一个全局对象theApp,让它在WinMain函数之前执行?该对象的作用是什么?

应用程序的实例是由实例句柄(WinMain函数的参数hInstance)来标识的。而对 MFC 程序来说,通过产生一个应用程序类的对象来唯一标识应用程序的实例。每一个MFC程序有且仅有一个从应用程序类(CWinApp)派生的类。每一个MFC程序实例有且仅有一个该派生类的实例化对象,也就是theApp全局对象。该对象就表示了应用程序本身。

当一个子类在构造之前会先调用其父类的构造函数。因此 theApp 对象的构造函数 CTestApp 在调用之前,会调用其父类CWinApp的构造函数,从而就把我们程序自己创建的类与Microsoft提供的基类关联起来了。CWinApp的构造函数完成程序运行时的一些初始化工作。

CWinApp构造函数代码(appcore.cpp):

CWinApp::CWinApp(LPCTSTR lpszAppName)
{
	if (lpszAppName != NULL)
		m_pszAppName = _tcsdup(lpszAppName);
	else
		m_pszAppName = NULL;

	// initialize CWinThread state
	AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE();
	ENSURE(pModuleState);
	AFX_MODULE_THREAD_STATE* pThreadState = pModuleState->m_thread;
	ENSURE(pThreadState);
	ASSERT(AfxGetThread() == NULL);
	pThreadState->m_pCurrentWinThread = this;
	ASSERT(AfxGetThread() == this);
	m_hThread = ::GetCurrentThread();
	m_nThreadID = ::GetCurrentThreadId();

	// initialize CWinApp state
	ASSERT(afxCurrentWinApp == NULL); // only one CWinApp object please
	pModuleState->m_pCurrentWinApp = this;
	ASSERT(AfxGetApp() == this);

	// in non-running state until WinMain
	m_hInstance = NULL;
	m_hLangResourceDLL = NULL;
	m_pszHelpFilePath = NULL;
	m_pszProfileName = NULL;
	m_pszRegistryKey = NULL;
	m_pszExeName = NULL;
	m_pszAppID = NULL;
	m_pRecentFileList = NULL;
	m_pDocManager = NULL;
	m_atomApp = m_atomSystemTopic = NULL;
	m_lpCmdLine = NULL;
	m_pCmdInfo = NULL;
	m_pDataRecoveryHandler = NULL;

	// initialize wait cursor state
	m_nWaitCursorCount = 0;
	m_hcurWaitCursorRestore = NULL;

	// initialize current printer state
	m_hDevMode = NULL;
	m_hDevNames = NULL;
	m_nNumPreviewPages = 0;     // not specified (defaults to 1)

	// initialize DAO state
	m_lpfnDaoTerm = NULL;   // will be set if AfxDaoInit called

	// other initialization
	m_bHelpMode = FALSE;
	m_eHelpType = afxWinHelp;
	m_nSafetyPoolSize = 512;        // default size

	m_dwRestartManagerSupportFlags = 0;    // don't support Restart Manager by default
	m_nAutosaveInterval = 5 * 60 * 1000;   // default autosave interval is 5 minutes (only has effect if autosave flag is set)

	m_bTaskbarInteractionEnabled = TRUE;

	// Detect the kind of OS:
	OSVERSIONINFO osvi;
	osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);

// Fix for warnings when building against WinBlue build 9444.0.130614-1739
// warning C4996: 'GetVersionExW': was declared deprecated
// externalapis\windows\8.1\sdk\inc\sysinfoapi.h(442)
// Deprecated. Use VerifyVersionInfo* or IsWindows* macros from VersionHelpers.
#pragma warning( disable : 4996 )
	::GetVersionEx(&osvi);
#pragma warning( default : 4996 )

	m_bIsWindows7 = (osvi.dwMajorVersion == 6) && (osvi.dwMinorVersion >= 1) || (osvi.dwMajorVersion > 6);

	// Taskbar initialization:
	m_bComInitialized = FALSE;

	m_pTaskbarList = NULL;
	m_pTaskbarList3 = NULL;
	m_bTaskBarInterfacesAvailable = TRUE;
}

CWinApp的构造函数中有这样两行代码:

pThreadState->m_pCurrentWinThread = this;
pModuleState->m_pCurrentWinApp = this;

m_pCurrentWinThread对象的类型是CWinThread,该类是CWinApp的父类。根据C++继承性原理,这个this对象代表的是子类CTestApp的对象,即theApp。

CWinApp的构造函数有一个LPCTSTR类型的形参:lpszAppName,但是CTestApp的构造函数没有参数。

如果基类的构造函数带有一个形参,那么子类构造函数需要显式地调用基类带参数的构造函数。

为什么我们程序中的CTestApp构造函数没有这么做呢?

如果某个函数的参数有默认值,那么在调用该函数时可以传递该参数的值,也可以不传递,直接使用默认值即可。

在CWinApp 类名上单击鼠标右键,利用【转到定义】命令,定位到CWinApp类的定义处,代码下:CWinApp构造函数的形参确实有一个默认值(NULL)。这样,在调用CWinApp类的构造函数时,就不用显式地去传递这个参数的值。

class CWinApp : public CWinThread
{
	DECLARE_DYNAMIC(CWinApp)
public:

// Constructor
	explicit CWinApp(LPCTSTR lpszAppName = NULL);     // app name defaults to EXE name
...
}

接上:VC++基于MFC的程序框架剖析(一)

接下:VC++基于MFC的程序框架剖析(三)CWinApp类的定义(afxwin.h*)

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
最简单的winmain程序 #include #include LRESULT CALLBACK WinSunProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam) { HDC hdc; switch(uMsg) { case WM_CHAR: char szChar[20]; sprintf(szChar,"char is %d",wParam); MessageBox(hwnd,szChar,"weixin",0); break; case WM_LBUTTONDOWN: MessageBox(hwnd,"mouse clicked","weixin",0); hdc=GetDC(hwnd); TextOut(hdc,0,50,"计算机编程语言培训",strlen("计算机编程语言培训")); ReleaseDC(hwnd,hdc); break; case WM_PAINT: PAINTSTRUCT ps; hdc=BeginPaint(hwnd,&ps); TextOut(hdc,0,0,"维新培训",strlen("维新培训")); EndPaint(hwnd,&ps); break; case WM_CLOSE: if(IDYES==MessageBox(hwnd,"是否真的结束?","weixin",MB_YESNO)) DestroyWindow(hwnd); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hwnd,uMsg,wParam,lParam); } return 0; } int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow) { WNDCLASS wndcls; wndcls.cbClsExtra=0; wndcls.cbWndExtra=0; wndcls.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH); wndcls.hCursor=LoadCursor(NULL,IDC_CROSS); wndcls.hIcon=LoadIcon(NULL,IDI_ERROR); wndcls.hInstance=hInstance; wndcls.lpfnWndProc=WinSunProc; wndcls.lpszClassName="Weixin2003"; wndcls.lpszMenuName=NULL; wndcls.style=CS_HREDRAW | CS_VREDRAW; RegisterClass(&wndcls); HWND hwnd=CreateWindow("Weixin2003","北京维新科学技术培训心",WS_OVERLAPPEDWINDOW,0,0,600,400,NULL,NULL,hInstance,NULL); DWORD dwStyle=GetWindowLong(hwnd, GWL_STYLE); dwStyle&=~(WS_SIZEBOX|WS_MAXIMIZEBOX|WS_MINIMIZEBOX); SetWindowLong(hwnd, GWL_STYLE, dwStyle); ShowWindow(hwnd,SW_SHOWNORMAL); UpdateWindow(hwnd); MSG msg; while(GetMessage(&msg,NULL,0,0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return 0; }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

米酒馆

鼓励鼓励,鼓励很重要啦~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值