c 语言学习笔记,C 语言学习笔记之四——MFC学习

Win32应用程序有条明确的主线:

(1) 进入WinMain函数

(2) 设计一个Window

(3) 注册这个Window

(4) 建立这个Window

(5) 显示和更新这个Window

(6) 进入消息循环

好,我就先找WinMain函数吧。

我在C:\Program Files\Microsoft Visual Studio

9.0\VC\atlmfc\src\mfc的appmodul.cpp的23行中找到了以下代码:

extern "C" int WINAPI

_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

_In_ LPTSTR lpCmdLine, int nCmdShow)

#pragma warning(suppress: 4985)

{

// call shared/exported WinMain

return AfxWinMain(hInstance, hPrevInstance, lpCmdLine,

nCmdShow);

}

_tWinMain是一个宏,详细为: #define _tWinMain WinMain

所以这个确实是我们要找的WinMain函数

从代码中看出,WinMain将参数全部交给AfxWinMain,来处理。

好,我又找AfxWinMain这个函数。

我在winmain.cpp的19行找到了AfxWinMain函数。

代码:

int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE

hPrevInstance,

_In_ LPTSTR lpCmdLine, int nCmdShow)

{

ASSERT(hPrevInstance == NULL); //

ASSERT在程序运行时它计算括号内的表达式,如果表达式为FALSE (0),

// 程序将报告错误,并终止执行。如果表达式不为0,则继续执行后面的语句。

// ASSERT只有在Debug版本中才有效,如果编译为Release版本则被忽略。

// assert()的功能类似,它是ANSI

C标准中规定的函数,它与ASSERT的一个重要区别是可以用在Release版本中。

int nReturnCode = -1;

// AfxGetThread和 AfxGetApp 都是全局函数

CWinThread* pThread = AfxGetThread(); // 获得正在执行的线程,Must be

called from within the desired thread.

CWinApp* pApp = AfxGetApp(); // 获得A pointer to the single

CWinApp object for the application

// AFX internal initialization

// This function is called by the MFC-supplied WinMain function,

as part of the CWinApp initialization of a GUI-based

// application, to initialize MFC.

if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine,

nCmdShow))

goto InitFailure;

// App global initializations (rare)

if (pApp != NULL && !pApp->InitApplication())

//InitApplication已经过时,用InitInstance代替,完成MFC内部管理方面的工作

goto InitFailure;

// Perform specific initializations

if (!pThread->InitInstance()) // 初始化Instance,在每个 a copy of

the program runs的时候,虚函数

{

if (pThread->m_pMainWnd != NULL)

{

TRACE(traceAppMsg, 0, "Warning: Destroying non-NULL

m_pMainWnd\n");

pThread->m_pMainWnd->DestroyWindow(); // m_pMainWnd holds

a pointer to the application's main window.返回一个CWnd.

// cWnd Destroys the attached Windows window.

}

nReturnCode = pThread->ExitInstance(); // to exit this

instance of the thread

goto InitFailure;

}

nReturnCode = pThread->Run();

InitFailure:

#ifdef _DEBUG

// Check for missing AfxLockTempMap calls

if (AfxGetModuleThreadState()->m_nTempMapLock != 0)

{

TRACE(traceAppMsg, 0, "Warning: Temp map lock count non-zero

(%ld).\n",

AfxGetModuleThreadState()->m_nTempMapLock);

}

AfxLockTempMaps();

AfxUnlockTempMaps(-1);

#endif

AfxWinTerm();

return nReturnCode;

}

找到了WinMain函数后,看了下MFC为我生成的类:

1. CTestApp 2. CTestView 3. CMainFrame 4. CTestDoc 5.

CAboutDlg

查看CTestApp.cpp,发现了一个全局的CTestApp

theApp,因为全局对象必须在main函数之前产生并初始化,所以应用程序调用的顺序应该是

CTestApp的构造函数 -> WinMain函数

又发现class CTestApp : public

CWinApp,子类的构造函数在父类的构造函数调用之后调用,所以就搜索CWinApp吧。

在appcore.cpp的368行发现以下代码:

CWinApp::CWinApp(LPCTSTR lpszAppName) //

此处的lpszAppName有个默认参数NULL

{

if (lpszAppName != NULL)

m_pszAppName = _tcsdup(lpszAppName); // 为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; // 如果有子类继承了CWinApp,

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; // 如果有子类继承了CWinApp,

this就是子类

ASSERT(AfxGetApp() == this);

// in non-running state until WinMain

m_hInstance = NULL;

m_hLangResourceDLL = NULL;v

m_pszHelpFilePath = NULL;

m_pszProfileName = NULL;

m_pszRegistryKey = NULL;

m_pszExeName = NULL;

m_pRecentFileList = NULL;

m_pDocManager = NULL;

m_atomApp = m_atomSystemTopic = NULL;

m_lpCmdLine = NULL;

m_pCmdInfo = 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

}

然后是CTestApp的构造函数的调用。

在CTestApp的声明中,它重写了InitInstance函数,如下:

BOOL CTestApp::InitInstance()

{

AfxEnableControlContainer(); //Call this function in your

application object's InitInstance function

//to enable support for containment of ActiveX controls

// 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.

// In MFC 5.0, Enable3dControls and Enable3dControlsStatic are

obsolete because their functionality is incorporated

// into Microsoft's 32-bit and 64-bit operating systems.

#ifdef _AFXDLL

Enable3dControls(); // Call this when using MFC in a shared

DLL

#else

Enable3dControlsStatic(); // Call this when linking to MFC

statically

#endif

// 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.

SetRegistryKey(_T("Local AppWizard-Generated

Applications"));

LoadStdProfileSettings(); // 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.

CSingleDocTemplate* pDocTemplate; // 单文档程序的模板生成

pDocTemplate = new CSingleDocTemplate(

IDR_MAINFRAME,

RUNTIME_CLASS(CTestDoc),

RUNTIME_CLASS(CMainFrame), // main SDI frame window

RUNTIME_CLASS(CTestView));

AddDocTemplate(pDocTemplate);

// Parse command line for standard shell commands, DDE, file

open

CCommandLineInfo cmdInfo; // 对命令查询分析

ParseCommandLine(cmdInfo);

// Dispatch commands specified on the command line

if (!ProcessShellCommand(cmdInfo))

return FALSE;

// The one and only window has been initialized, so show and

update it.

m_pMainWnd->ShowWindow(SW_SHOW); //显示和更新窗口

m_pMainWnd->UpdateWindow();

return TRUE;

}

有了WinMain函数,也找到了显示和更新窗口的语句,但是从哪里开始设计窗口,注册窗口,建立窗口呢?

我又搜索了WNDCLASS,在wincore.cpp的4495行发现了与设计窗口时很像的函数BOOL AFXAPI

AfxEndDeferRegisterClass(LONG fToRegister)

发现MS已经在里面为我注册了一些窗口,我只要选择自己想要的样式就可以了。

那么如何建立一个窗口呢?我又搜索了CreateWindow,在wincore.cpp的675行中有个BOOL

CWnd::CreateEx函数。

里面有调用CreateWindowEx。这个函数还调用了一个叫PreCreateWindow的函数,这个函数主要是确定在建立窗口之前,确保要建立的窗口已经注册了。

好了,一切都准备好了。最后就是进入消息循环。

你可能感兴趣的:(c,语言学习笔记)