yashwant kanitker - vc++ gems

9
Chapter 1 The First MFC Application FC as we know is an object oriented interface to Windows API. As on date, we may still have a debate whether it’s worthwhile to continue to use C with API calls since you have more than a nodding acquaintance with API or to learn MFC and its use in programming Windows using C++. But believe me OLE (Object Linking and Embedding) and other components of API are evolving so quickly that it's nearly impossible to stay on top of all the latest developments. That's why it is helpful to have a class library as an insulating layer between you and API. It's also why, in future, programmers who use windows API could be looked upon the way assembly language programmers are today. M MFC is the C++ class library Microsoft provides to place an object-oriented wrapper around the Windows API. Out of the classes provided by MFC few classes you’ll use directly and others will serve primarily as base classes for classes of your own. Some of the classes are exceedingly simple, such as the CPoint class that encapsulates a point object (a location characterized by x and y coordinates). Others are complex, such as the CWnd class that encapsulates the functionality of a window. In an MFC program, you rarely need to call the Windows API directly. Instead, you create objects from MFC classes and call member functions belonging to those objects. Many of the hundreds of member functions defined in the class library are thin wrappers around the Windows API and 15

Upload: api-3708828

Post on 11-Apr-2015

1.076 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: Yashwant Kanitker - VC++ Gems

Chapter 1

The First MFC Application

FC as we know is an object oriented interface to Windows API. As on date, we may still have a debate whether it’s worthwhile to continue to use C with API calls since you have more than a nodding acquaintance

with API or to learn MFC and its use in programming Windows using C++. But believe me OLE (Object Linking and Embedding) and other components of API are evolving so quickly that it's nearly impossible to stay on top of all the latest developments. That's why it is helpful to have a class library as an insulating layer between you and API. It's also why, in future, programmers who use windows API could be looked upon the way assembly language programmers are today.

M

MFC is the C++ class library Microsoft provides to place an object-oriented wrapper around the Windows API. Out of the classes provided by MFC few classes you’ll use directly and others will serve primarily as base classes for classes of your own. Some of the classes are exceedingly simple, such as the CPoint class that encapsulates a point object (a location characterized by x and y coordinates). Others are complex, such as the CWnd class that encapsulates the functionality of a window. In an MFC program, you rarely need to call the Windows API directly. Instead, you create objects from MFC classes and call member functions belonging to those objects. Many of the hundreds of member functions defined in the class library are thin wrappers around the Windows API and even have the same names as the corresponding API functions. An obvious benefit of this naming convention is that it speeds the transition for C programmers making the move to MFC. Want to move a window? A C programmer would probably call the SetWindowPos( ) API function. Look up SetWindowPos( ) in an MFC reference, and you'll find that MFC supports SetWindowPos( ), too. It’s a member of the CWnd class, which makes sense when you think of a window as an object and SetWindowPos( ) as an operation you might want to perform on that object.

However, MFC is not only a library of classes. MFC is also an application framework. More than merely a collection of classes, MFC helps define the structure of an application and handles many routine chores on the application’s behalf. Starting with CWinApp, the class that represents the application itself, MFC encapsulates virtually every aspect of a program’s operation. The framework supplies the WinMain( ) function, and WinMain( ) in turn calls the application object’s member functions to make the program go. One of the CWinApp

15

Page 2: Yashwant Kanitker - VC++ Gems

16 VC++ Gemsmember functions called by WinMain( ) - Run( ) - encapsulates the message loop and literally runs the program. The framework also provides abstractions that go above and beyond what the Windows API has to offer. For example, MFC’s document/view architecture builds a powerful infrastructure on top of the API that separates a program’s data from graphical representations, or views, of that data. Such abstractions are totally foreign to the API and don’t exist outside the framework of MFC.

In fact not all of the functions that MFC offers are members of classes. MFC provides a set of functions whose names begin with ‘Afx’. Class member functions can be called only in the context of the objects to which they belong, but ‘Afx’ functions are available to everyone.

The First MFC Program

Let us now turn our attention to our first VC++ program. Almost all the VC++ programmers use AppWizard to create their applications. The AppWizard code generator is used to create a skeleton of an application. This includes the classes, variables and resources that every application is likely to have. Once the skeleton is built it can be maintained and updated using the ClassWizard code generator. The updating includes adding new variables, classes, message-handlers, member functions, etc. In this chapter we would use these wizards to create a simple SDI application.

Start VC++ 6.0 and select ‘File | New’ menu item. A Dialog Box would pop up. Select ‘MFC AppWizard (exe)’ from the ‘Project’ tab. Type project name as Sdi and select a location (directory) for it. Click on OK button. Another dialog would pop up. Select the ‘Single Document’ radio button since we intend to build an SDI (Single Document Interface). Uncheck the ‘Document/View architecture support?’ check box. Click on ‘Finish’. A dialog indicating the names of the classes that AppWizard is going to create would be popped up. When we click on OK, four classes— CAboutDlg, CChildView, CMainFrame and CSdiApp would get created.

The CSdiApp class is an application class and is derived from the CWinApp MFC class, whereas, CMainFrame is a frame window class and is derived from the CFrameWnd MFC class. The CChildView is the view window class. The application class represents the application itself. Its job is to do the initialization work and create a frame window. The frame window houses the caption bar, menu, toolbar, status bar etc. The frame window class creates a view window. The view window occupies the client area of the frame window.

How An SDI Application Works

Consider the following code:

class CChildView {} ;class CMainFrame

Page 3: Yashwant Kanitker - VC++ Gems

Chapter 1: The First MFC Application 17{

CChildView v ;int OnCreate( ){

v.Create( ) ;}

} ;

class CSdiApp {

BOOL InitInstance( ){

CMainFrame *f = new CMainFrame ;m_pMainWnd = f ;f-> LoadFrame ( IDR_MAINFRAME ) ;f->ShowWindow ( 1 ) ;

}} ;CSdiApp theApp ;

In C/C++ under DOS a program starts its execution from main( ). Likewise, in VC++, execution begins from a function called WinMain( ). But surprisingly you would not see the function definition of WinMain( ) in any of the files created by the AppWizard. This is because, WinMain( ) function already stands defined in the ‘Appmodul.cpp’ file and is linked into our application when we execute the program. Let us see the definition of WinMain( ).

_tWinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )

{AfxWinMain ( hInstance, hPrevInstance, lpCmdLine, nCmdShow ) ;

}

As you can see from the code, WinMain( ) delegates the processing to a function called AfxWinMain( ). This function is present in ‘Winmain.cpp’. Here is how AfxWinMain( ) looks like…

int AFXAPI AfxWinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )

{int nReturnCode = -1 ;

CWinApp* pApp = AfxGetApp( ) ;

// AFX internal initializationAfxWinInit ( hInstance, hPrevInstance, lpCmdLine, nCmdShow ) ;

// App global initializations (rare)pApp -> InitApplication( ) ;

// Perform specific initializationsif ( !pApp -> InitInstance( ) )

Page 4: Yashwant Kanitker - VC++ Gems

18 VC++ Gems{

if ( pApp -> m_pMainWnd != NULL ){

pApp -> m_pMainWnd -> DestoryWindow( ) ;}nReturncode = pApp -> ExitInstance( ) ;

goto InitFailure ;}

nRetturnCode = pApp -> Run( ) ;

InitFailure :AfxWinTerm( ) ;

return nReturnCode ;}

Here, at the beginning AfxWinMain( ) calls a function, AfxGetApp( ). This function returns the address of the global application object (theApp in our program). This address is assigned to a CWinApp pointer trough the statement,

CWinApp *pApp = AfxGetApp( ) ;

But how can it obtain the address of application object when the application has not been created? The answer is simple. C++ programs construct their global objects before anything else is done. So, The global object theApp gets created even before WinMain( ) function starts executing. Let us now see from where AfxGetApp( ) gets the address. When the following statement is executed

CSdiApp theApp ;

the constructor of CSdiApp class gets called. This in turn calls the base class’s (CWinApp’s) constructor. Following is the code of the CWinApp class’s constructor.

class CWinApp {

CWinApp( ){

m_pCurrentWinApp = this ;}

} ;

In this constructor if we use this it would contain the address of the global application object. This address is stored by the constructor in a global data member m_pCurrentWinApp of type CWinApp*. Thus, what the constructor has managed to do is—set up a pointer to base class’s object with the address of the derived class object. When we call AfxGetApp( ) it retrieves the address of the global application object from the m_pCurrentWinApp data member.

Page 5: Yashwant Kanitker - VC++ Gems

Chapter 1: The First MFC Application 19Once the global application object’s address is obtained, AfxWinMain( ) makes a call to AfxWinInit( ) function to initialise the framework. AfxWinInit( ) sets the parameters passed to it into the member variables of the CWinApp class.

The pointer retrieved using AfxGetApp( ) is now used by AfxWinMain( ) to call the CWinApp::InitApplication( ) function. This function is called only for providing backward compatibility with 16-bit Windows. In 32-bit Windows this function is of no importance.

Next, the InitInstance( ) function is called using the pointer pApp that contains address of the application object theApp. The InitInstance( ) function is declared as virtual in the CWinApp class. Since the address of CSdiApp object is stored in pApp and we are calling InitInstance( ) using pApp, it is the InitInstance( ) function of CSdiApp that gets called. In the CSdiApp::InitInstance( ) function an object of CMainFrame class is created. This object’s address is stored in m_pMainWnd, which is a public data member of the CWinApp class. Note that this is essential since MFC uses this data member internally. Next the CWnd::LoadFrame( ) function is called which creates the frame window and attaches the resources specified by the id IDR_MAINFRAME to the frame window. When the window is created OnCreate( ) function of CMainFrame class gets called. In this function a view window gets created by calling the CWnd::Create( ) function. This window gets attached to the frame window as its child. The control returns to the InitInstance( ) function and CWnd::ShowWindow( ) function is called. This function displays the window on the screen. Once InitInstance( ) has finished its job, control comes back to the AfxWinMain( ) function. From this function Run( ) function is called where the control goes in a message loop. (A message is an intimation sent to our application by OS whenever an event, like pressing a key, or clicking a mouse button, etc. occurs with regards to our application). This loop keeps collecting and keeps processing any messages sent to our application. This continues till the user doesn’t close the application. When the user closes an application the message loop is terminated). Control now reaches closing brace of WinMain( ), hence execution of the program comes to an end.

You can run this ‘Sdi’ program by pressing Ctrl+F5 or clicking on the exclamation mark on the ‘Build’ tool bar. You will see a fully functional window on the screen. You can move, resize, minimize, maximize it and close it. Following figure shows the output window and its various elements.

Page 6: Yashwant Kanitker - VC++ Gems

20 VC++ Gems

FrameWindow

Client Area

Menu BarTool Bar

Title bar Min Max Close

Status Bar