Miyerkules, Marso 21, 2012

examples of Visual C++ using MFC AppWizard application


Program Examples 1

Let go straight to the program example using MFC. This is a Single Document Interface (SDI) "Hello, world!" classic example. The application has only one window, an object of a class derived from CFrameWnd. All drawing occurs inside the frame window and all messages are handled there. This just a warm up session and we are using AppWizard that can automate most of our task in building Windows application. Follow the steps one-by-one.

Launch your Visual C++, click the File menu and click the New… sub menu. Click the Projects tab for the AppWizard as shown below. Select the MFC AppWizard (exe), type your project name and set the project location as needed. Leave other setting as default and click the OK button.

AppWizard dialog

Figure 19: AppWizard dialog.

The wizard has 6 steps and you can exit at any step. Select the Single document radio button and uncheck the Document/View architecture support then click Next button.

Visual C++ AppWizard step 1 of 6

Figure 20: Visual C++ AppWizard step 1 of 6.

Select the None radio button for database support. Click the Next button. We are going to create the simplest project.

Visual C++ AppWizard step 2 of 6

Figure 21: Visual C++ AppWizard step 2 of 6.

Uncheck the ActiveX Controls. Just to make our code simpler.

Visual C++ AppWizard step 3 of 6

Figure 22: Visual C++ AppWizard step 3 of 6.

Accept the defaults and click the Next button.

Visual C++ AppWizard step 4 of 6

Figure 23: Visual C++ AppWizard step 4 of 6.
 


Accept the defaults and click Next button.

Visual C++ AppWizard step 5 of 6

Figure 24: Visual C++ AppWizard step 5 of 6.

The following are the classes that will be generated (also the related files created) for our project. Click the Next button.

Visual C++ AppWizard step 6 of 6

Figure 25: Visual C++ AppWizard step 6 of 6.

Finally the summary of the project settings. Click the OK button.

Visual C++ AppWizard project summary

Figure 26: Visual C++ AppWizard project summary.

Expand all folders in the FileView and double click the ChildView.cpp. FileView displays all the project files that can be edited, logically. Physically, there are more projects’ files.

Visual C++ FileView

Figure 27: Visual C++ FileView.

Add code to paint in the dialog. Add the following code to the CChildView::OnPaint function in the ChildView.cpp source code file:
void CChildView::OnPaint()
{
    CPaintDC dc(this); // device context for painting

    dc.TextOut(0, 0, "Hello, world!");

    // Do not call CWnd::OnPaint() for painting messages
}

MFC, Visual C++ code segment

Listing 1.

Compile and run. You now have a complete SDI application that has no dependencies on the document-view architecture.

Visual C++ "Hello world" output

Figure 28: Visual C++ "Hello world" output.

Program Examples 2

The following is another classic example using MFC AppWizard, and Visual C++ to create, build, and run a simple MFC-based single document interface (SDI) Scribble application. We just dealing with the View part of the Document/View architecture. We will learn more detail about the Document/View architecture later.

Use MFC AppWizard to create a new project
  1. In Visual C++/Visual Studio, on the File menu, click New.
  2. In the New dialog box, click the Projects tab, and then do the following:
  • For the project type, select MFC AppWizard (exe).
  • For the project name, type myscribble.
  • Set the location for your project as needed.
  • Accept the default platform Win32.
  • Click OK to create the new project workspace. MFC AppWizard starts.
  1. In MFC AppWizard Step 1, click Single document and English, leave the Document/View architecture support checkbox selected, and then click Next to go to Step 2.
  2. Because this project does not need database support, accept the default None for database support and click Next to go to Step 3.
  3. In Step 3, accept None for the document support, because we are not going to create a compound document that using Object Linking and Embedding (OLE), clear the ActiveX Controls check box, and then click Next to go to Step 4.
  4. In Step 4, clear the Printing and print preview check box, accept the defaults (Docking toolbar, Initial status bar, 3D controls, and 4 files for the recent file list) and then click Next to go to Step 5.
  5. In Step 5, leave the project style as MFC Standard, click Yes, please for generating source file comments and select As a shared DLL for MFC support. Click Next to go to Step 6.
  6. In Step 6, click Finish to display the New Project Information dialog box summarizing your choices.
  7. To create the application files with MFC AppWizard, click OK.

When MFC AppWizard is finished, you will be returned to Visual C++/Visual Studio. To see the classes that MFC AppWizard created, click the ClassView tab in the Project Workspace window.

Add message handlers that will handle several mouse clicking and dragging events. This just the skeleton, we will add the real codes later – myscribbleView.cpp file.
  1. On the View menu, click ClassWizard. The MFC ClassWizard property page appears.
  2. In the Message Maps tab, in the combo boxes provided on the property page, select the myscribble project, the CMyscribbleView class, and the CMyscribbleView Object ID.
  3. We are going to add member functions in the CMyscribbleView class. In the Messages list box, select the WM_LBUTTONDOWN message and click Add Function.
  4. Repeat Step 3 for the WM_MOUSEMOVE and WM_LBUTTONUP messages.
  5. Click OK to close ClassWizard.

Implement OnLButtonDown, OnMouseMove, and OnLButtonUp handlers. This is the real codes that will implement the mouse clicking and dragging events.
  1. Declaring variables in the declaration part. Open MyscribbleView.h (or use the ClassView).
  2. In the public attributes section of the CMyscribbleView class declaration, define startpt and endpt variables as follows:

CPoint startpt, endpt;

Or by using the ClassView, select the CMyscribbleView and right click, select the Add Member Variable:

Adding a member variable through the ClassView

Figure 29: Adding a member variable through the ClassView.

Add member variable dialog

Figure 30: Add member variable dialog.

  1. Save MyscribbleView.h.
  2. Then, the implementation codes in the implementation part. Open MyscribbleView.cpp.
  3. In the constructor, initialize startpt and endpt coordinates to  –1 as follows:

startpt = -1;
endpt = -1;

Scribble code segment           
Figure 31: Scribble code segment.
  1. Scroll to the OnLButtonDown handler.
  2. In the OnLButtonDown handler, save the point where the mouse button is pressed as the start point:

startpt.x = point.x;
startpt.y = point.y;
  1. Scroll to the OnMouseMove handler.
  2. In the OnMouseMove handler, add the following code to draw a line from the previous detected point in the mouse drag to the current point:

CClientDC dc(this);
endpt.x = point.x;
endpt.y = point.y;
if (startpt.x != -1)
{
   dc.MoveTo(startpt.x, startpt.y);
   dc.LineTo(endpt.x, endpt.y);
   startpt.x = endpt.x;
   startpt.y = endpt.y;
}
  1. In the OnLButtonUp handler, add code to reinitialize the variable startpt as follows:

startpt = -1;

Scribbles’ C++ code segment         

Listing 3: Scribbles’ C++ code segment.

Build and run the project
  1. On the Build menu, click Build Myscribble.exe. Visual Studio displays the status of the build process as it builds your project.
  2. After the build is complete, on the Build menu, click Execute Myscribble.exe. The Scribble application starts. Try writing something using your mouse.

Visual C++’s Scribble program output

Figure 32: Visual C++’s Scribble program output.


Since its introduction in 2002, people’s attention has focused on the many new features that have formed part of Microsoft .NET, such as the major changes to Microsoft Visual Basic (Visual Basic .Net), the introduction of C#, the new ASP.NET and ADO.NET models, and the increased use of XML. So, from application framework we are introduced the next level, .Net framework (currently version 2.0). C++ developers need not feel left out, however, because a lot of the new features in Microsoft Visual C++ .NET make C++ a first-class member of the .NET family of programming languages. This new functionality is called the Managed Extensions for C++, and as well as providing C++ programmers with access to all the functionality in the .NET class libraries, it also lets you interoperate with existing C++ code, COM objects, and the Win32 API.

Managed vs. Unmanaged Code

Code and data that live in the .NET world are called managed because locations and lifetimes are managed by the common language runtime (CLR). Code and data that exist outside of .NET are called unmanaged, because there is no central mechanism for managing their lifetimes.

Enabling/disabling the /clr for managed/unmanaged code in Visual C++ .Net through the project properties.

Figure 33: Enabling/disabling the /clr for managed/unmanaged code in Visual C++ .Net through the project properties.

Enabling/disabling the /clr in Visual C++ .Net.

Figure 34: Enabling/disabling the /clr in Visual C++ .Net.

Sometimes you have to mix the two, calling existing unmanaged code from within .NET. The .NET Framework is the new library of classes that you use to build Windows applications. It is large, quite complex, and far-reaching in its scope. For MFC programming we do not use the /clr (can be enabled in the Visual C++ .Net: Project menu your_project_name Properties General Use Managed Extensions Yes/No, as shown in the above Figures), that is unmanaged. The managed code will be used in the .Net programming and don’t confused that .Net framework is not compiler, it is framework. All program examples used in this Tutorial series are unmanaged and we are using Visual C++ 6.0. The managed code used in Visual C++ .Net provided that the /clr is used.


| Tenouk C & C++ | MFC Home | MFC AppWizard 1 | Event Handling, Mapping Modes, and a Scrolling View 1 | Download | Site Index |







Module 2:

Getting Started with Visual C++ 6.0 AppWizard 2







This is a continuation from the previous module... Program examples compiled using Visual C++ 6.0 (MFC 6.0) compiler on Windows XP Pro machine with Service Pack 2. Topics and sub topics for this Tutorial are listed below:
  1. Drawing Inside the View Window: The Windows Graphics Device Interface

  2. The OnDraw() Member Function

  3. The Windows Device Context

  4. Adding Draw Code to the MYMFC Program

  5. A Preview of the Resource Editors

  6. The Contents of mymfc.rc file

  7. Running the Dialog Resource Editor

  8. Enabling the Diagnostic Macros

  9. Two Ways to Run a Program

  10. AFX Functions

  11. Precompiled Headers Story



 

Compile and link the generated code. AppWizard, in addition to generating code, creates custom project and workspace files for your application. The project file, mymfc.dsp, specifies all the file dependencies together with the compile and link option flags. Because the new project becomes Visual C++'s current project, you can now build the application by choosing Build mymfc.exe from the Build menu (or by clicking the Build toolbar button) shown here.

Building mymfc.exe

Figure 14: Building mymfc.exe.

If the build is successful, an executable program named mymfc.exe is created in a new Debug subdirectory underneath \mfcproject\mymfc. The OBJ files and other intermediate files are also stored in Debug.

Files generated after the building process under the Debug directory

Figure 15: Files generated after the building process under the Debug directory.

Compare the file structure on disk with the structure in the Workspace window's FileView page shown here. The FileView page contains a logical view of your project. The header files show up under Header Files, even though they are in the same subdirectory as the CPP files. The resource files are stored in the \res subdirectory.

mymfc project FileView

Figure 16: mymfc project FileView.

Test the resulting application. Choose Execute mymfc.exe from the Build menu. Experiment with the program. It doesn't do much because there is no coding yet. Actually, as you might guess, the program has a lot of features - you simply haven't activated them yet. Close the program window when you've finished experimenting.

Executing the mymfc.exe program
Figure 17: Executing/running the mymfc.exe program.
mymfc program output

Figure 18: mymfc program output.

The most important CMymfcView base classes are CWnd and CView. CWnd provides CMymfcView's "windowness," and CView provides the hooks to the rest of the application framework, particularly to the document and to the frame window.


Now you're ready to write code to draw inside the view window. You'll be making a few changes directly to the MYMFC source code.

The OnDraw() Member Function

Specifically, you'll be fleshing out OnDraw() in mymfcView.cpp. OnDraw() is a virtual member function of the CView class that the application framework calls every time the view window needs to be repainted. A window needs to be repainted if the user resizes the window or reveals a previously hidden part of the window, or if the application changes the window's data. If the user resizes the window or reveals a hidden area, the application framework calls OnDraw(), but if a function in your program changes the data, it must inform Windows of the change by calling the view's inherited Invalidate() (or InvalidateRect()) member function. This call to Invalidate() triggers a later call to OnDraw().
Even though you can draw inside a window at any time, it's recommended that you let window changes accumulate and then process them all together in the OnDraw() function. That way your program can respond both to program-generated events and to Windows-generated events such as size changes.

The Windows Device Context

Windows doesn't allow direct access to the display hardware but communicates through an abstraction called a "device context" that is associated with the window. In the MFC library, the device context is a C++ object of class CDC that is passed (by pointer) as a parameter to OnDraw(). After you have the device context pointer, you can call the many CDC member functions that do the work of drawing.

Adding Draw Code to the MYMFC Program

Now let's write the code to draw some text and a circle inside the view window. Be sure that the project MYMFC is open in Visual C++. You can use the Workspace window's ClassView to locate the code for the function and double-clicking the file to edit the OnDraw() function in mymfcView.cpp. So, find the AppWizard-generated OnDraw() function in mymfcView.cpp:


















-----------------------------------------------------------------------------------------------
mymfc C++ code segment.

Listing 1: mymfc C++ code segment.

The following code replaces the previous code:

void CMymfcView::OnDraw(CDC* pDC)
{
// TODO: add draw code for native data here
       // prints in default font and size, top left corner
       pDC->TextOut(5, 0, "Hello MFC world!");
       // selects a brush for the circle interior
       pDC->SelectStockObject(GRAY_BRUSH);
       // draws a gray circle 100 units in diameter
       pDC->Ellipse(CRect(0, 20, 100, 120));
}

You can safely remove the call to GetDocument() because we're not dealing with documents yet. The functions TextOut(), SelectStockObject() and Ellipse() are all member functions of the application framework's device context class CDC. The Ellipse() function draws a circle if the bounding rectangle's length is equal to its width. The MFC library provides a handy utility class, CRect, for Windows rectangles. A temporary CRect object serves as the bounding rectangle argument for the ellipse drawing function.

Recompile and test MYMFC. Choose Build mymfc.exe sub menu from Build menu and if there are no compile errors, test the application again. Now you have a program that visibly does something!

mymfc program output

Figure 19: mymfc program output.

A Preview of the Resource Editors

Now that you have a complete application program, it's a good time for a quick look at the resource editors. Although the application's resource script, mymfc.rc, is an ASCII file, modifying it with a text editor is not a good idea. That's the resource editors' job.

The Contents of mymfc.rc

The resource file determines much of the MYMFC application's "look and feel." The file mymfc.rc contains (or points to) the Windows resources listed here. You can open the rc file with text editor.

Resource
Description
Accelerator
Definitions for keys that simulate menu and toolbar selections.
Dialog
Layout and contents of dialog boxes. MYMFC has only the About dialog box.
Icon
Icons (16-by-16-pixel and 32-by-32-pixel versions), such as the application icon you see in Microsoft Windows Explorer and in the application's About dialog box. MYMFC uses the MFC logo for its application icon.
Menu
The application's top-level menu and associated pop-up menus.
String table
Strings that are not part of the C++ source code.
Toolbar
The row of buttons immediately below the menu.
Version
Program description, version number, language, and so on.

Table 3: Project resources.

mymfc files in ResourceView

Figure 20: mymfc files in ResourceView.

mymfc resource file (RC)

Figure 21: mymfc resource file (RC).

In addition to the resources listed above, mymfc.rc contains the statements:

#include  "afxres.h"
#include  "afxres.rc"

Which bring in some MFC library resources common to all applications. These resources include strings, graphical buttons, and elements needed for printing and OLE. If you're using the shared DLL version of the MFC library, the common resources are stored inside the MFC DLL. The mymfc.rc file also contains the statement:

#include  "resource.h"

This statement brings in the application's three #define constants, which are:

Object ID
Meaning
IDR_MAINFRAME
Identifying the menu, icon, string list, and accelerator table.
IDR_MYMFCTYPE
Identifying the default document icon, which we won't use in this program.
IDD_ABOUTBOX
Identifying the About dialog box.

Table 4.

This same resource.h file is included indirectly by the application's source code files. If you use a resource editor to add more constants (symbols), the definitions ultimately show up in resource.h. Be careful if you edit this file in text mode because your changes might be removed the next time you use a resource editor.

Running the Dialog Resource Editor

Open the project's RC file. Click the ResourceView button in the Workspace window. If you expand each item, you will see the following in the resource editor window.

mymfc's resources in ResourceView

Figure 22: mymfc's resources in ResourceView
 


Examine the application's resources. Now take some time to explore the individual resources. When you select a resource by double-clicking on it, another window opens with tools appropriate for the selected resource. If you open a dialog resource, the control palette should appear. If it doesn't, right-click inside any toolbar, and then check Controls.

IDD_ABOUTBOX dialog in resource editor

Figure 23: IDD_ABOUTBOX dialog in resource editor.

Modify the IDD_ABOUTBOX dialog box by making some changes to the About mymfc dialog box, shown here.

Changing the About dialog properties

Figure 24: Changing the About dialog properties.

You can change the size of the window by dragging the right and bottom borders, move the OK button, change the text, and so forth. Simply click on an element to select it, and then right-click to change its properties.

Rebuild the project with the modified resource file. In Visual C++, choose Build mymfc.exe from the Build menu. Notice that no actual C++ recompilation is necessary. Visual C++ saves the edited resource file, and then the Resource Compiler (rc.exe) processes mymfc.rc to produce a compiled version, mymfc.res, which is fed to the linker. The linker runs quickly because it can link the project incrementally.

Test the new version of the application. Run the MYMFC program again, and then choose About from the application's Help menu to confirm that your dialog box was changed as expected.

mymfc program output

Figure 25: mymfc program output.

Win32 Debug Target vs Win32 Release Target

If you open the drop-down list on the Build toolbar, you'll notice two items: Win32 Debug and Win32 Release. The Build toolbar is not present by default, but you can choose Customize from the Tools menu to display it.

Release vs Debug target

Figure 26: Release vs Debug target.

These items are targets that represent distinct sets of build options. When AppWizard generates a project, it creates two default targets with different settings. These settings are summarized in the following table.

Option
Release Build
Debug Build
Source code debugging
Disabled
Enabled for both compiler and linker
MFC diagnostic macros
Disabled (NDEBUG defined)
Enabled (_DEBUG defined)
Library linkage
MFC Release library
MFC Debug libraries
Compiler optimization
Speed optimization (not available in Learning Edition)
No optimization (faster compile)

Table 5.

You develop your application in Debug mode, and then you rebuild in Release mode prior to delivery. The Release build EXE will be smaller and faster because of the optimization and assuming that you have fixed all the bugs. You select the configuration from the build target window in the Build toolbar or Build minibar.

Build toolbar and minibar

Figure 27: Build toolbar and minibar.

By default, the Debug output files and intermediate files are stored in the project's Debug subdirectory; the Release files are stored in the Release subdirectory. You can change these directories (and other project settings as well) on the General tab in the Project Settings dialog box.

Visual C++ project settings

Figure 28: Visual C++ project settings.

You can create your own custom configurations if you need to by choosing Configurations from Visual C++'s Build menu.

Enabling the Diagnostic Macros

The application framework TRACE macros are particularly useful for monitoring program activity. They require that tracing be enabled, which is the default setting. If you're not seeing TRACE output from your program, first make sure that you are running the debug target from the debugger and then run the TRACER utility. If you check the Enable Tracing checkbox, TRACER will insert the statement:

TraceEnabled = 1

in the [Diagnostics] section of a file named Afx.ini. (No, it's not stored in the Registry.) You can also use TRACER to enable other MFC diagnostic outputs, including message, OLE, database, and Internet information.

AFX Functions

Not all of the functions that MFC offers are members of classes. MFC provides an API of sorts all its own in the form of global 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 anytime and anywhere.
The following table lists some of the more commonly used AFX functions. AfxBeginThread() simplifies the process of creating threads of execution. AfxMessageBox() is the global equivalent of the Windows MessageBox() function and, unlike CWnd::MessageBox, can be called just as easily from a document class as from a window class. AfxGetApp() and AfxGetMainWnd() return pointers to the application object and the application's main window and are useful when you want to access a function or data member of those objects but don't have a pointer readily available. AfxGetInstanceHandle() is handy when you need an instance handle to pass to a Windows API function. Even MFC programs call API functions every now and then! The following Table list the commonly use Afx functions.

Function Name
Description
AfxAbort()
Unconditionally terminates an application; usually called when an unrecoverable error occurs.
AfxBeginThread()
Creates a new thread and begins executing it.
AfxEndThread()
Terminates the thread that is currently executing.
AfxMessageBox ()
Displays a Windows message box.
AfxGetApp()
Returns a pointer to the application object.
AfxGetAppName()
Returns the name of the application.
AfxGetMainWnd()
Returns a pointer to the application's main window.
AfxGetInstanceHandle()
Returns a handle identifying the current application instance.
AfxRegisterWndClass()
Registers a custom WNDCLASS for an MFC application.

Table 6

Precompiled Headers Story




Invoking the Visual C++ project settings dialog

Figure 29: Invoking the Visual C++ project settings dialog.

Visual C++ project settings dialog

Figure 30: Visual C++ project settings dialog.

When AppWizard generates a project, it generates switch settings and files for precompiled headers. You must understand how the make system processes precompiled headers in order to manage your projects effectively. Visual C++ has two precompiled header "systems:" automatic and manual. Automatic precompiled headers, activated with the /Yx compiler switch, store compiler output in a "database" file. Manual precompiled headers are activated by the /Yc and /Yu switch settings and are central to all AppWizard-generated projects. Precompiled headers represent compiler "snapshots" taken at a particular line of source code. In MFC library programs, the snapshot is generally taken immediately after the following statement:

#include  "StdAfx.h"

The file StdAfx.h contains #include statements for the MFC library header files. The file's contents depend on the options that you select when you run AppWizard, but the file always contains these statements:

#include <afxwin.h>
#include <afxext.h>

If you're using compound documents, StdAfx.h also contains the statement:

#include <afxole.h>

And if you're using Automation or ActiveX Controls, it contains:

#include <afxdisp.h>

If you're using Internet Explorer 4 Common Controls, StdAfx.h contains the statement:

#include <afxdtctl.h>

Occasionally you will need other header files - for example, the header for template-based collection classes that is accessed by the statement:

#include <afxtempl.h>

The source file StdAfx.cpp contains only the statement:

#include  "StdAfx.h"

And is used to generate the precompiled header file in the project directory. The MFC library headers included by StdAfx.h never change, but they do take a long time to compile. The compiler switch /Yc, used only with StdAfx.cpp, causes creation of the precompiled header (PCH) file. The switch /Yu, used with all the other source code files, causes use of an existing PCH file. The switch /Fp specifies the PCH filename that would otherwise default to the project name (with the PCH extension) in the target's output files subdirectory. Figure 31 illustrates the whole process.
AppWizard sets the /Yc and /Yu switches for you, but you can make changes if you need to. It's possible to define compiler switch settings for individual source files. On the C/C++ tab in the Project Settings dialog box, if you select only StdAfx.cpp, you'll see the /Yc setting. This overrides the /Yu setting that is defined for the target.
Be aware that PCH files are big - 5 MB is typical. If you're not careful, you'll fill up your hard disk. You can keep things under control by periodically cleaning out your projects' Debug directories, or you can use the /Fp compiler option to reroute PCH files to a common directory.

The Visual C++ precompiled header process

Figure 31: The Visual C++ precompiled header process.

Two Ways to Run a Program

Visual C++ lets you run your program directly (by pressing Ctrl-F5) or through the debugger (by pressing F5). Running your program directly is much faster because Visual C++ doesn't have to load the debugger first. If you know you don't want to see diagnostic messages or use breakpoints, start your program by pressing Ctrl-F5 or use the "exclamation point" button on the Build toolbar.


First: C++ Using MFC

C++ programs that use the Microsoft Foundation Class (MFC) application framework can be easily created with Fastgraph's MFC AppWizard for Visual C++ 5.0 or later. To use Fastgraph's MFC AppWizard, copy the file FGwiz.awx from the Fastgraph utilities directory to your Visual C++ Template directory. Once installed, "Fastgraph MFC AppWizard" will be one of the options listed when you create a new Visual C++ project. If you wish to uninstall the AppWizard, just delete FGwiz.awx from the Template directory.
MFC programs consist of application and window class declarations (both derived from MFC base classes), a global application object, message response functions (event handlers), and possibly your own additional functions. Like programs that use the Windows API, MFC programs have a WinMain() function, a WindowProc() function, and a message loop, but they are hidden inside MFC.
Our first example is a single-window program without a menu (such programs are called simple frame window applications in MFC). For this example, Fastgraph's MFC AppWizard created First.cpp, First.h, MainFrame.cpp, MainFrame.h, and other files. First.cpp instantiates the application object theApp from the CFirstApp class (CFirstApp is derived from MFC's CWinApp base class). MainFrame.cpp contains "canned" message response functions for the Windows events we typically must handle in a Fastgraph program. We can, of course, modify these message response functions as needed.
On program startup, Windows calls MFC's built-in WinMain() function, which in turn calls the CFirstApp::InitInstance() and CWinApp::Run() member functions. The CFirstApp::InitInstance() function instantiates the frame window object pFrame from the CMainFrame class (CMainFrame is derived from MFC's CFrameWnd base class). The pFrame object's Create() member function creates the program's main window (this also generates the WM_CREATE message), while its ShowWindow() and UpdateWindow() member functions initially display and paint the main window. CWinApp::Run() is hidden in MFC's CWinApp base class and implements the Windows message loop. The message loop retrieves messages Windows sends to the program and in turn sends these to the message response functions for processing. The message loop executes until the user exits the program. Here is the First.cpp file for our first example program:
/****************************************************************************\
*                                                                            *
*  First.cpp                                                                 *
*                                                                            *
*  This is the first Fastgraph for Windows example program. It demonstrates  *
*  tasks common to most Fastgraph for Windows programs and serves as a       *
*  template for building the other examples.                                 *
*                                                                            *
\****************************************************************************/
// First.cpp : Defines the class behaviors for the application.
//
#include "stdafx.h"
#include "First.h"
#include "MainFrame.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CFirstApp
BEGIN_MESSAGE_MAP(CFirstApp, CWinApp)
   //{{AFX_MSG_MAP(CFirstApp)
   //}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CFirstApp construction
CFirstApp::CFirstApp()
{
}
/////////////////////////////////////////////////////////////////////////////
// The one and only CFirstApp object
CFirstApp theApp;
/////////////////////////////////////////////////////////////////////////////
// CFirstApp initialization
BOOL CFirstApp::InitInstance()
{
   // Standard initialization
   // Change the registry key under which our settings are stored.
   SetRegistryKey(_T("Local AppWizard-Generated Applications"));
   m_pMainWnd = NULL;
   CMainFrame* pFrame = new CMainFrame;
   if (!pFrame->Create(NULL,"First Fastgraph for Windows Program"))
      return FALSE;
   m_pMainWnd = pFrame;
   pFrame->ShowWindow(m_nCmdShow);
   pFrame->UpdateWindow();
   return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CFirstApp message handlers
The message response functions, where most of the action takes place, provide our first look at some Fastgraph functions. Note that our program does not explicitly call the message response functions. Instead, they are called by CWinApp::Run() in response to events such as creating or resizing the window. Our program's MainFrame.cpp file includes message response functions for the WM_CREATE, WM_PAINT, WM_SETFOCUS, WM_SIZE, and WM_DESTROY messages, among others. MainFrame.cpp is shown here:
// MainFrame.cpp : implementation of the CMainFrame class
//
#include "stdafx.h"
#include "First.h"
#include "MainFrame.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CMainFrame
IMPLEMENT_DYNAMIC(CMainFrame, CFrameWnd)
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
   //{{AFX_MSG_MAP(CMainFrame)
   ON_WM_SIZE()
   ON_WM_SETFOCUS()
   ON_WM_QUERYNEWPALETTE()
   ON_WM_PALETTECHANGED()
   ON_WM_PAINT()
   //}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CMainFrame construction/destruction
CMainFrame::CMainFrame()
{
   m_hDC = NULL;
   m_hPal = NULL;
   m_hVB = -1;
   m_cxClient = 0;
   m_cyClient = 0;
}
CMainFrame::~CMainFrame()
{
   if (m_hVB >= 0)
   {
      fg_vbclose();
      fg_vbfree(m_hVB);
   }
   fg_vbfin();
   if (m_hPal)
   {
      DeleteObject(m_hPal);
      m_hPal = NULL;
   }
   if (m_hDC)
   {
      ::ReleaseDC(m_hWnd, m_hDC);
      m_hDC = NULL;
   }
}
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
   if (!CFrameWnd::PreCreateWindow(cs))
      return FALSE;
   cs.style = WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE;
   cs.dwExStyle &= ~WS_EX_CLIENTEDGE;
   cs.lpszClass = AfxRegisterWndClass(CS_OWNDC|CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS,
      LoadCursor(NULL,IDC_ARROW), NULL, NULL);
   return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CMainFrame diagnostics
#ifdef _DEBUG
void CMainFrame::AssertValid() const
{
   CFrameWnd::AssertValid();
}
void CMainFrame::Dump(CDumpContext& dc) const
{
   CFrameWnd::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CMainFrame message handlers
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
   BOOL bRet = CFrameWnd::OnCreateClient(lpcs, pContext);
   if (bRet)
   {
      m_hDC = ::GetDC(m_hWnd);
      fg_setdc(m_hDC);
      m_hPal = fg_defpal();
      fg_realize(m_hPal);
      fg_vbinit();
      m_hVB = fg_vballoc(640,480);
      fg_vbopen(m_hVB);
      fg_vbcolors();
      fg_setcolor(19);
      fg_fillpage();
   }
   return bRet;
}
void CMainFrame::OnPaint()
{
   CPaintDC dc(this); // device context for painting
   fg_vbscale(0,fg_getmaxx(),0,fg_getmaxy(),0,m_cxClient-1,0,m_cyClient-1);
}
void CMainFrame::OnSize(UINT, int cx, int cy)
{
   m_cxClient = cx;
   m_cyClient = cy;
}
void CMainFrame::OnSetFocus(CWnd* pOldWnd)
{
   OnQueryNewPalette();
}
BOOL CMainFrame::OnQueryNewPalette()
{
   fg_realize(m_hPal);
   Invalidate();
   return TRUE;
}
void CMainFrame::OnPaletteChanged(CWnd* pFocusWnd)
{
   if ((pFocusWnd != this) && (!IsChild(pFocusWnd)))
      OnQueryNewPalette();
}
Windows generates a WM_CREATE message when it first creates the program's window. Only one WM_CREATE message typically occurs per program instance, so it is a good place for any application-specific initialization code. In an MFC program, the CMainFrame::OnCreateClient() message response function serves as the WM_CREATE handler. Our OnCreateClient() function begins by calling the base class OnCreateClient() function:
BOOL bRet = CFrameWnd::OnCreateClient(lpcs, pContext);
If successful, it calls the Windows API function GetDC() to obtain a device context to the window's client area, and then fg_setdc() to make the device context available to other Fastgraph functions:
m_hDC = ::GetDC(m_hWnd);
fg_setdc(m_hDC);
Note how we use the :: global scope resolution operator to guarantee that we call the Windows API version of GetDC(). We'll use this technique whenever we call a Windows API function in an MFC program. Next, CMainFrame::OnCreateClient() creates and realizes the default logical palette:
m_hPal = fg_defpal();
fg_realize(m_hPal);
CMyWindow::OnCreate() then initializes Fastgraph's virtual buffer environment, creates a 640x480 virtual buffer and makes it the active virtual buffer, and assigns the logical palette colors to the virtual buffer:
fg_vbinit();
m_hVB = fg_vballoc(640,480);
fg_vbopen(m_hVB);
fg_vbcolors();
Finally, we fill the virtual buffer with blue pixels (color 19 is blue when using Fastgraph's default 256-color virtual buffers with the default logical palette):
fg_setcolor(19);
fg_fillpage();
Windows generates a WM_PAINT message when the window's client area must be repainted. In an MFC program, the CMainFrame::OnPaint() message response function serves as the WM_PAINT handler. Our CMainFrame::OnPaint() function does little more than call fg_vbscale() to display the contents of the 640x480 virtual buffer scaled to the size of the client area.
Windows generates a WM_SETFOCUS message when the window gains the input focus. This most often happens when the window becomes the active or top-level window. In an MFC program, the CMainFrame::OnSetFocus() message response function serves as the WM_SETFOCUS handler. Our CMainFrame::OnSetFocus() function merely calls CMainFrame::OnQueryNewPalette(), which first calls fg_realize() to activate the program's logical palette (in case another program has changed the logical palette colors), then calls the Invalidate() member function to force a WM_PAINT message to redraw the client area.
Windows generates a WM_SIZE message whenever the size of the window changes, and also upon creation of a window. In an MFC program, the CMainFrame::OnSize() message response function serves as the WM_SIZE handler. Our CMainFrame::OnSize() function simply saves the new width and height of the client area (in pixels) in the member variables m_cxClient and m_cyClient. These quantities are passed to fg_vbscale() in CMainFrame::OnPaint().
Windows generates a WM_DESTROY message after removing a window to signal a program exit. In an MFC program, the CMainFrame destructor serves as the WM_DESTROY handler. The destructor first closes the virtual buffer, releases its memory, and terminates virtual buffer processing:
if (m_hVB >= 0)
{
   fg_vbclose();
   fg_vbfree(m_hVB);
}
fg_vbfin();
It then calls the DeleteObject() member function to delete the logical palette created with fg_defpal(), and the Windows API function ReleaseDC() to release the device context created with GetDC():
if (m_hPal)
{
   DeleteObject(m_hPal);
   m_hPal = NULL;
}
if (m_hDC)
{
   ::ReleaseDC(m_hWnd, m_hDC);
   m_hDC = NULL;
}


Walang komento:

Mag-post ng isang Komento