分享
 
 
 

MFC Application

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

Your First MFC Application

It's time to build your first MFC application. And what better place to start than with one that displays "Hello, MFC" in a window? Based on the classic "Hello, world" program immortalized in Brian Kernighan and Dennis Ritchie's The C Programming Language (1988, Prentice-Hall), this very minimal program, which I'll call Hello, demonstrates the fundamental principles involved in using MFC to write a Windows application. Among other things, you'll get a close-up look at MFC's CWinApp and CFrameWnd classes and see firsthand how classes are derived from them and plugged into the application. You'll also learn about the all-important CPaintDC class, which serves as the conduit through which text and graphics are drawn in a window in response to WM_PAINT messages. Finally, you'll be introduced to message mapping, the mechanism MFC uses to correlate the messages your application receives with the member functions you provide to handle those messages.

Figure 1-3 lists the source code for Hello. Hello.h contains the declarations for two derived classes. Hello.cpp contains the implementations of those classes. Among C++ programmers, it's traditional to put class definitions in .h files and source code in .cpp files. We'll honor that tradition here and throughout the rest of this book. For large applications containing tens or perhaps hundreds of classes, it's also beneficial to put class declarations and implementations in separate source code files. That's overkill for the programs in the first few chapters of this book, but later on, when we begin working with documents and views, we'll give each class its own .h and .cpp files. On the CD in the back of the book, in the folder named Chap01, you'll find a folder with copies of Hello.h and Hello.cpp as well as a folder containing a copy of the compiled executable (Hello.exe).

Figure 1-3. The Hello application.

Hello.hclass CMyApp : public CWinApp

{

public:

virtual BOOL InitInstance ();

};

class CMainWindow : public CFrameWnd

{

public:

CMainWindow ();

protected:

afx_msg void OnPaint ();

DECLARE_MESSAGE_MAP ()

};

Hello.cpp#include <afxwin.h>

#include "Hello.h"

CMyApp myApp;

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

// CMyApp member functions

BOOL CMyApp::InitInstance ()

{

m_pMainWnd = new CMainWindow;

m_pMainWnd->ShowWindow (m_nCmdShow);

m_pMainWnd->UpdateWindow ();

return TRUE;

}

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

// CMainWindow message map and member functions

BEGIN_MESSAGE_MAP (CMainWindow, CFrameWnd)

ON_WM_PAINT ()

END_MESSAGE_MAP ()

CMainWindow::CMainWindow ()

{

Create (NULL, _T ("The Hello Application"));

}

void CMainWindow::OnPaint ()

{

CPaintDC dc (this);

CRect rect;

GetClientRect (&rect);

dc.DrawText (_T ("Hello, MFC"), -1, &rect,

DT_SINGLELINE ¦ DT_CENTER ¦ DT_VCENTER);

}

Figure 1-4 shows the output from Hello. When you run the application, notice that the window is entirely functional; you can move it, resize it, minimize it, maximize it, and close it. And when the window is resized, "Hello, MFC" is redrawn in the center of the window.

Most of Hello's functionality comes from Windows. Windows, for example, draws the exterior, or nonclient area, of the window: the title bar, the buttons on the title bar, and the window's border. It's your responsibility to create the window and process WM_PAINT messages indicating that all or part of the window's interior, or client area, needs updating. Let's examine the source code to see how Hello works.

Figure 1-4. The Hello window.

The Application Object

The heart of an MFC application is an application object based on the CWinApp class. CWinApp provides the message loop that retrieves messages and dispatches them to the application's window. It also includes key virtual functions that can be overridden to customize the application's behavior. CWinApp and other MFC classes are brought into your application when you include the header file Afxwin.h. An MFC application can have one—and only one—application object, and that object must be declared with global scope so that it will be instantiated in memory at the very outset of the program.

Hello's application class is named CMyApp. It is instantiated in Hello.cpp with the statement

CMyApp myApp;

CMyApp's class declaration appears in Hello.h:

class CMyApp : public CWinApp

{

public:

virtual BOOL InitInstance ();

};

CMyApp declares no data members and overrides just one function inherited from CWinApp. InitInstance is called early in the application's lifetime, right after the application starts running but before the window is created. In fact, unless InitInstance creates a window, the application doesn't have a window. That's why even a minimal MFC application must derive a class from CWinApp and override CWinApp::InitInstance.

The InitInstance Function

CWinApp::InitInstance is a virtual function whose default implementation contains just one statement:

return TRUE;

The purpose of InitInstance is to provide the application with the opportunity to initialize itself. The value returned by InitInstance determines what the framework does next. Returning FALSE from InitInstance shuts down the application. If initialization goes as planned, InitInstance should return TRUE in order to allow the program to proceed. InitInstance is the perfect place to perform initializations that need to be done each time the program starts. At the very least, this means creating the window that will represent the application on the screen.

CMyApp's implementation of InitInstance, which appears in Hello.cpp, creates the Hello window by instantiating Hello's CMainWindow class. The statement

m_pMainWnd = new CMainWindow;

constructs a CMainWindow object and copies its address to the application object's m_pMainWnd data member. After the window is created, InitInstance displays it—remember, a window is not initially visible unless it is created with a WS_VISIBLE attribute—by calling ShowWindow and UpdateWindow through the CMainWindow pointer:

m_pMainWnd->ShowWindow (m_nCmdShow);

m_pMainWnd->UpdateWindow ();

ShowWindow and UpdateWindow are CWnd member functions common to all window objects, including objects of the CFrameWnd class from which CMainWindow is derived. These functions are little more than wrappers around the API functions of the same name. To call a regular Windows API function from an MFC program, make it a practice to preface the function name with the global scope resolution operator ::, as in

::UpdateWindow (hwnd);

This notation will ensure that the API function is called even if the object that makes the call has a member function with the same name. In the remainder of this book, Windows API functions will be prefaced with :: to distinguish them from MFC member functions.

ShowWindow accepts just one parameter: an integer that specifies whether the window should initially be shown minimized, maximized, or neither minimized nor maximized. In accordance with Windows programming protocol, Hello passes ShowWindow the value stored in the application object's m_nCmdShow variable, which holds the nCmdShow parameter passed to WinMain. The m_nCmdShow value is usually SW_SHOWNORMAL, indicating that the window should be displayed in its normal unmaximized and unminimized state. However, depending on how the user starts an application, Windows will occasionally slip in a value such as SW_SHOWMAXIMIZED or SW_SHOWMINIMIZED. Unless there is a specific reason for it to do otherwise, InitInstance should always pass the m_nCmdShow variable instead of a hardcoded SW_ value to ShowWindow.

UpdateWindow completes the job that ShowWindow started by forcing an immediate repaint. Its work done, InitInstance returns TRUE to allow the application to proceed.

Other CWinApp Overridables

InitInstance is just one of several virtual CWinApp member functions you can override to customize the behavior of the application object. Look up the CWinApp overridables in your MFC documentation and you'll see a list of more than a dozen others with names such as WinHelp and ProcessWndProcException. Many of these functions are seldom overridden, but they're handy to have around nonetheless. For example, you can use ExitInstance to clean up when an application terminates. If you use InitInstance to allocate memory or other resources, ExitInstance is the perfect place to free those resources. The default implementation of ExitInstance performs some routine cleanup chores required by the framework, so you should be sure to call the base class version if you've overridden ExitInstance. Ultimately, the value returned by ExitInstance is the exit code returned by WinMain.

Other interesting CWinApp overridables include OnIdle, Run, and PreTranslateMessage. OnIdle is handy for performing background processing chores such as garbage collection. Because OnIdle is called when an application is "idle"—that is, when there are no messages waiting to be processed—it provides an excellent mechanism for performing low-priority background tasks without spawning a separate thread of execution. OnIdle is discussed at length in Chapter 14. You can override Run to customize the message loop, replacing it with a message loop of your own. If you just want to perform some specialized preprocessing on certain messages before they are dispatched, you can override PreTranslateMessage and save yourself the trouble of writing a whole new message loop.

How MFC Uses the Application Object

To someone who has never seen an MFC application's source code, one of the more remarkable aspects of Hello will be that it contains no executable code outside of the classes it defines. It has no main or WinMain function, for example; the only statement in the entire program that has global scope is the statement that instantiates the application object. So what actually starts the program running, and when does the application object come into the picture?

The best way to understand what goes on under the hood is to look at the framework's source code. One of the source code files provided with MFC—Winmain.cpp—contains an AfxWinMain function that is MFC's equivalent of WinMain. (That's right: when you purchase Visual C++, you get the source code for MFC, too.) AfxWinMain makes extensive use of the application object, which is why the application object must be declared globally. Global variables and objects are created before any code is executed, and the application object must be extant in memory before AfxWinMain starts.

Right after starting, AfxWinMain calls a function named AfxWinInit to initialize the framework and copy hInstance, nCmdShow, and other AfxWinMain function parameters to data members of the application object. Then it calls InitApplication and InitInstance. In 16-bit versions of MFC, InitApplication is called only if the hPrevInstance parameter passed to AfxWinMain is NULL, indicating that this is the only instance of the application currently running. In the Win32 environment, hPrevInstance is always NULL, so the framework doesn't bother to check it. A 32-bit application could just as easily use InitApplication to initialize itself as InitInstance, but InitApplication is provided for compatibility with previous versions of MFC and should not be used in 32-bit Windows applications. If AfxWinInit, InitApplication, or InitInstance returns 0, AfxWinMain terminates instead of proceeding further and the application is shut down.

Only if all of the aforementioned functions return nonzero values does AfxWinMain perform the next critical step. The statement

pThread->Run();

calls the application object's Run function, which executes the message loop and begins pumping messages to the application's window. The message loop repeats until a WM_QUIT message is retrieved from the message queue, at which point Run

breaks out of the loop, calls ExitInstance, and returns to AfxWinMain. After doing some last-minute cleaning up, AfxWinMain executes a return to end the application.

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有