The following is a few articles I learned to see VC ++: I don't have anything to write: If the author needs it: please cont

xiaoxiao2021-03-06  14

In-depth programming insider - Visual C

Walk into Visual C *

1 understand VC project *

2 MFC programming characteristics *

3 use wizard *

Two MFC program structure analysis *

1 Working principle of Windows program *

2 Establish an application *

3 Program Structure Analysis *

3.1 Class CMYAPP *

3.2 Class CMAINFRAME *

3.3 Class CMYVIEW and CMYDOC *

Three deep mfc class library *

1 handle user input *

1.1 Defining dialog resource *

1.2 Definition dialog box *

2 Related screen output *

2.1 Device Context Work Principle *

2.2 Analysis of instance drawing principle *

2.3 Drawing Operation Realization *

2.4 Related Screen Mapping Ways *

3 file processing *

3.1 Object Duration Brief Description *

3.2 instance analysis *

3.3 Class cfiles with file processing relationship *

4 DAO technology *

4.1 DAO and ODBC *

4.2 Implement DAO Technologies with MFC *

5 print *

5.1 Print and display *

5.2 Print Page *

5.3 Start and end of printing * *

5.4 Print Program Example *

Fourth, VC program debugging *

1.1 Establishment of the debugging environment *

1.2 General process of debugging *

1.3 How to set breakpoints *

1.4 Running of the control program *

1.5 View Tools *

2 Advanced Debug Technology *

2.1 Trace Macro Utilization *

2.2 ASSERT macro's utilization *

2.3 ASSERT_VALID Macro Utilization and Overload of the AssertValid () member letter *

2.4 Object's DUMP function utilization *

3 memory vulnerabilities check *

Five Visual C and Multimedia *

1 handling of sound *

1.1 Media Control Interface *

1.2 waveform mixer *

2 multimedia file I / o *

3 multimedia graphic image technology *

4 image synthesis *

5 FLC animation *

6 hot spot *

Walk into Visual C

Visual C as a very powerful visual application development tool is one of the best application development tools recognized by the computer world. Microsoft's basic class library MFC makes developing Windows applications easier than ever. The purpose of this disc's teaching software is to let you learn to develop a powerful Windows application with Microsoft's basic class library MFC in the Visual C environment. In this chapter, we will introduce you to some of the basic concepts that need to be used using VC development software, using MFC's basic features, and a series of programming aids provided by the Visual C integrated development environment - Wizard's use method.

1 understand VC project

Visual C as a programming language, which is also an integrated development tool that provides software code automatically generates and visualize resource editing features. During using the Visual C development application, the system generates a lot of various types of files for us, which will be described in detail in this section to do what kind of files doing in Visual C , in this basis There is a comprehensive understanding of how Visual C manages the various files used by the application.

The first thing to introduce is the file type named DSW. This type of file is the highest level in VC, called Workspace file. In the VC, the application exists in the form of Project, with a .dsp extension, in the Workspace file, can include multiple Project, which is uniformly coordinated and managed by the Workspace file. An important file type with the DSW type Workspace file is file with an OPT as an extension. This file contains configuration information about the local computer to be used in the Workspace file, so this file cannot be different. Sharing on the computer, when we open a Workspace file, if the system does not find the desired OPT type file, you will automatically create an OPT file that contains local computer information.

The extension of the Project file is DSP, which is stored in this file, which is the information about a specific application, and each project corresponds to a DSP type file.

With CLW to extension, files are information used to store classes and resources used in applications, which is the source of information in the VC's ClassWizard tool management and use.

Corresponding to each application has a readme.txt file, this file lists information on all files used in the application, open and view content, which can have a basic understanding of the application's file structure.

A large number of applications in the application is files with H and CPPs to be extension, refer to the files for the extension called header files. The file with CPP is called implementation files. Generally speaking that the file to the extension file with the CPP file is used in correspondence, in H, the H-Zhan's file is included, the main class Definition, and in the file containing the extension of the extension is the implementation code of the class member function.

In the application, some bitmaps, menu are often used, and the file in the VC is called a resource file in the VC, which contains all Windows resources used in the application. It is to point out The RC file can be edited and modified directly in VC integration environments.

Finally, it is to introduce the file with RC2 as an extension, it is also a resource file, but the resources in this file cannot be edited and modified directly in the VC's integrated environment, but we will edit this file by hand.

For files with ICO, BMP, etc. are specific resources, and there are many ways to generate such resources. The purpose of using the RC resource file is to manage unified management of a large number of resources used in the program.

2 MFC programming features

If you have used the traditional Windows programming method to develop applications, you will deeply understand that even if you develop a simple Windows application, you need to have a deep understanding of Windows programming, and you should also write a lot. Code. Because the error rate of the program is almost growing as the code length increases, this makes the debugger become very difficult. So traditional Windows programming is a great patience and extensive programming experience.

In recent years, object-oriented technologies have been rapidly developing in theory or practical. The most important thing for object-oriented technology is the "object" concept, which puts the objective entity in the real world, the objective entity such as bicycle abstract "object". This "object" has a certain attribute and method, and the property refers to the various characteristic parameters of the object itself. Such as the volume of the balloon, the length of the bicycle, etc. A specific object can have many properties and methods, an important feature of object-oriented technology is the encapsulation of objects. For the outside world, it does not need to know which attributes do, nor do you need to know how object itself is implemented. Only the method provided by the object is required to complete a specific function. From here we can see that when the object-oriented technology is applied to the programming design, the programmer only needs to care about the details of the object itself when writing the object method, and most of the time is in the call to the object. Organize these objects to work together. MFC's English full name is Microsoft Fundation Classes, that is, Microsoft's basic class library. The essence of MFC is a class library containing many Microsoft has defined a good object. We know, although the program we have to write is functional. However, in essence, it can be altributed as the design of the user interface, the operation of the document, the use of multimedia, the database access, etc. Some of the most important aspects. This is why Microsoft provides the most important reason for the MFC class library, which includes more than 100 most commonly used objects during development. When the program is designed, if an object in the class library can complete the required features, then we can simply call the method of an object. We can also use the "inheritance" method in object-oriented technology to derogate our own objects from the existing objects in the class library. At this time, the object is derived except for the characteristics and functions of the objects in the class library. It is also possible to add a more specialized, more powerful objects that we need to add as needed. Of course, you can also create a new object in the program and constantly improve the functionality of the object as needed.

It is because the MFC programming method takes advantage of the advantages of object-oriented technology, which makes us carefully need to care for the implementation details of the object method, and the powerful function of various objects in the class library is enough to complete the vast majority of our program. The desired function, which makes the code that the programmer needs to be written in the application, which effectively guarantees good adjustability of the program.

Finally, it is to point out that the various properties and methods of the objects provided in the MFC class are cautious and strict tests, which guarantees that the use of the MFC class library does not affect the reliability of the program and Positiveness.

3 use wizard

Visual C is a powerful generic programming language that provides a variety of wizards and tools to help us to achieve the features required, to a certain extent, to achieve software automatic generation and visualization programming. Below you will introduce you to several of the most important development tools in the VC integrated environment.

The first thing to introduce the AppWizard tool, the role of this tool is to help us generate a new application step by step and automatically generate the basic code required by the application. Below we will introduce specific steps to generate an application using AppWizard.

Click the File menu new menu item, the system pops up to let us choose the file type to be created, and the files here are divided into four large types of Files, Project, Workspaces, Other documents, each of which contains many specific file types. Select the Projects tab, listed in the workspace under the label is a variety of different application types, such as dynamic link libraries of the DLL type, Exe type executable, etc., hereby select the MFC AppWizard (EXE) option, indicating that you want Created a executable programming using the MFC Basic Class Library. As shown in Figure 1.1 below:

Figure 1.1

After choosing, you start a name for the program in the Project Name column. In the Location column, you are used for the program defined by the program, the win32 item in the lower right corner of the dialog is the program to be created. 32-bit Windows platforms basis. Click the OK button to initiate an AppWizard feature that uses the MFC mode development application.

Figure 1.2

Wizard allows us to choose the type of program and the language used by the resources in the program. Here you may choose the program type as a single document interface, language is English, and then click Next button.

Figure 1.3

Wizard let's choose whether to provide a database support, select None, then click Next button.

Figure 1.4

The support for the composite document is selected here in the following selection.

Figure 1.5

The other features of the program are then selected, such as providing support for Winsock, etc. Here, the default value of the system is not changed, as shown in Figure 1.6 below. Click the Next button.

Figure 1.6

In the fifth step, the upper part of the dialog box is selected to automatically generate a comment, and the lower part of the dialog is used to choose to use the MFC class library whether the dynamic link library or static link mode, use dynamic link library mode after generating The executable application does not really include objects in the MFC class library, while using a static link mode, the code in the MFC library is part of the application, and the generated application is relatively large. After selecting, click Next button.

Figure 1.7

Enter the last step in AppWizard, the prompt information in the dialog indicates the objects and related files that the system will automatically create, and the base class of the MFC that derives these objects. In this step, we can also choose the base class of the view class, click the Finish button.

Figure 1.8

Click the OK button after the description of the information about the program to be generated in the dialog box. The system automatically generates a basic framework for the application using the MFC Basic Class library, will be described in detail later.

Figure 1.9

Next, introduce a very important tool ClassWizard provided in the VC integration environment, which is mainly used to manage objects and messages in the program, which is especially important for MFC programming. Click the ClassWizard item for the View menu to run the MFC ClassWizard, which can manage objects and messages in the program in this dialog.

Figure 1.10

Under the Message Maps tab in the dialog, the contents of the Project column represent the name of the current program. The Classwname drop-down list box is listed is the name of all classes currently used, and in the Message column is all the messages that the selected class can receive, in the Windows programming, the message is an extremely important Concepts, users through the window interfaces are finally converted to various messages sent to objects in the program, and here will introduce some of the most commonly used messages in Windows programming:

1 Window message: WM_CREATE, WM_DESTROY, WM_CLOSE We create a window object, this window object is received during the creation process is the WM_CREATE message, which is generally used to set up some initialization work before the display window, such as Set the size, background color, etc. of the window, the WM_DESTROY message indication window is about to be revoked, during this message processing, we can do some of the work before the window is undo. WM_CLOSE WM_CLOSE messages occur before the window will be turned off, after receiving this message, the general operation is to recover all resources allocated to this window. The resources in the Windows system are very limited, so the work of recycling resources is still very important.

2 Keyboard message: wm_char, wm_keydown, wm_keyup

These three messages are used to handle the user's keyboard data. When the user presses a key on the keyboard, the WM_KEYDOWN message will generate the WM_KEYUP message when the button is released, so the WM_KeyDown and WM_KEYUP messages are always paired. As for the WM_CHAR message, it will happen when the user's keyboard input can generate a valid ASCII code. It is especially reminded here to note that the first two messages are different from the WM_CHAR message in use. In the first two messages, accompanying messages is a virtual key code of the button, so the two messages can handle non-print characters, such as arrow keys, function keys, and the like. The parameters accompanying the WM_CHAR message are the ASCII code pressed, the ASCII code is the case where the letter can be distinguished. The virtual key code cannot be case sensitive.

3 Mouse Message: WM_Mousemove, WM_LButtondown, WM_LButtonup, WM_LButtondbClick, WM_RButtondown, WM_RButtonup, WM_RB /RBCLICK

This set message is related to the mouse input. When the WM_MOUSEMOVE message occurs when the mouse moves, the remaining six messages correspond to the press, release, double-click the event, and point to the event, and point out that the Windows system is not in the mouse. Each time you move a pixel, you should pay special attention.

4 another set of windows: WM_MOVE, WM_SIZE, WM_PAINT

When the window moves, the WM_SIZE message is generated when the window is changed, and the WM_PAINT message will be generated when the content in the window workspace needs to be redrawn.

5 Focus message WM_SETFOCUS, WM_KILLFOCUS

When a window has changed from an inactive state to an active state of the input focus, it will receive a WM_SETFOCUS message, while it will receive a WM_KILLFOCUS message when the window loses input focus.

6 timer message: WM_TIMER

When we set a timer resource for a window, the system will send a WM_TIMER message according to the specified time interval. In this message, some things that need to be processed regularly can be processed.

Finally, it is to point out that in a Windows environment, the source of the message is multifaceted, the most common is that the user's operation generates a message, and the system will send a system message to the program when necessary, and other programs in operation are also You can send messages to the program. Further, in the inside of the program, a message can be actively generated as needed, such as active WM_PAINT messages to achieve the need for heavy draw functions.

The main message in the Message column is introduced above, and listed in the Member Function column is a member function that is currently selected. These member functions are generally corresponding to messages that can be received by this class. That is, a member function is always used to handle a particular message. If a message in the Message column needs to be handled in the program, there is currently no corresponding class member function, such as the WM_TIMER message here, there is currently no corresponding class member function, click the Add Function button ,

Figure 1.11

The system automatically adds a corresponding member function onTimer to the class, click the EditCode button, and you can find that the system has automatically generated the basic code required to complete the ONTIMER function. We only need to add a place on the basis of these basic code. The code you need is.

Note that the Add Class button in the dialog box is used to add a new class to the current application.

Click the new menu after clicking,

Figure 1.12

The New Class dialog box is used to generate a new class. In this dialog, you need to set a name for the class, set the name of the class file, and also select an existing class as a base class in the drop-down list box in the base class, and then click the information you need. OK generates a new class.

Figure 1.13

Class Wizard has some very powerful features, this is no longer detailed, you will slowly understand and master in constant learning.

Last introduction to an important tool for an integrated environment RESOUCR Editor, that is, the resource editor. In applications developed in VC, you should use a large number of bitmaps, menus, toolbars, dialogs, and more. These resources are relatively independent for programs, so they can be edited separately, and then in the program. Resouce Editor is a visual development method for editing resources. Greatly alleviate the burden of programmers.

Click the Open menu item of the File menu, and then select Open Test.rc file in the dialog box, you can start using the resource editor. On the left workspace lists all the resources used in the program, double-click some type, such as double-click Menu resources, the following list below is the resource of the system already available, selected One of them and doubles, listed this resource current look in the workspace on the right, we can perform the editing and modification of the resource in the workspace.

Figure 1.14

How to add a resource? Click the Insert menu, select the Resource menu item, and the Insert Resource dialog box will pop up. Figure 1.15.

Figure 1.15

In Figure 1.15, this dialog box is selected in this dialog, such as selecting the Cursor type, and then click the New button. The identifier of our newly generated resource appears in the workspace on the left, double-click this identifier, and the new pointer shape resource can be visually edited in the workspace on the right. As shown in Figure 1.16.

Through this part of the content, I believe that you have developed MFC applications to use Visual C .

Figure 1.16

Basic steps have aware of understanding. In the content of the next chapter, we will interpret the basic structure of the MFC class library in conjunction with Windows's working principle, and the basic framework of the MFC application - document / view structure.

Analysis of two MFC program structure

1 Working principle of Windows program

The Windows program is a programming method that is completely different from traditional DOS mode, which is an event-driven programming mode. There are many operable visual objects in the interface provided to the user. The user selects any of the possible operations, the selected operation generates some specific events, and the result is issued to some objects in the program, and then these object calls the corresponding message processing function to complete Specific operation. The biggest feature of Windows applications is that there is no fixed process, but only a specific subflow for processing for an event, and the Windows application is composed of many of such subflows. As can be seen from the discussion above, the Windows application is essentially object-oriented. The program provides a visual object to the user interface is generally an object within the program, and the user triggered the availability of the corresponding object through the operation of the visual object. The running process of the program is that the user's external operation is constantly generating events, and these events are processed by the corresponding object. Below is a schematic diagram of the working principle of Windows program.

2 Establish an application

When introducing AppWizard, we have established a project name Test, in fact, this framework program has been able to compile. Select the Rebuild All menu item in the Build menu, the system starts to compile the source code in all files in all files generated by AppWizard, and link to generate executable applications. In the Build menu, select the Execute menu item, the application starts to start running, although we do not write a line of code, but you can see that the interface automatically generated by the system has several standard Windows applications needed. Component, what we have to do is to add the necessary code to this application to complete the features we need.

Next, this application framework automatically generated by Windows has a detailed introduction to allow you to have a comprehensive understanding of the WIDOWS application of the MFC mode. Only if you will know how to add the code you need to add it in the program framework. .

Figure 2.1

3 profiling

In order for you have an overall understanding of the framework of the MFC mode, a chart of the relationship between the main classes in the program is designed:

This chart represents the relationship between the four major classes of the application using the MFC mode. It can be seen that the main role of the CMYAPP class is to process the message, and the unified manager receives all the messages received, and then put The message is assigned to the corresponding object. CMAINFRAME is the parent class of CMYVIEW, that is, Window View is displayed in the client area of ​​the main box mainframe. The role of class CMYVIEW is to display data, and the source of data is class CMYDOC. In the MFC program, the program's data is placed in the document, and the display data is used by the window, the advantages of documentation and window separation is one. Documents can have multiple windows at the same time, each window display only part of the data in the document, or display data in a document in a specific style. Another advantage of documentation and window separation is to handle multiple documents in the program, with the purpose of processing different documents by processing different window processing.

People who have used the traditional Windows programming method know that there is an important function WinMain () in the application, this function is the basis of the application, and the message generated by the user's operation is sent to the corresponding handle. Treatment in the object. In the Windows application in the MFC mode, the information used to process the message is the class CMYAPP in the MFC generated by the system. The following starts from this class to introduce the application's framework.

3.1 Class CMYAPP

Class CMYAPP is the basis of the application run, pay attention to this line of code, you can see that this class is derived from the class cwinApp in the MFC. In this class, in addition to the constructor having a general class, an important member function is InitInstance, we know, in the Windows environment, multiple instances of the same program can be run, the function of the function initInstance is a new instance of generating At the time, complete some initialization work. Pay attention to this line of code, its role is to generate a CMYAPP type object, and the system will actively call the InitInstance function to complete some of the necessary initialization work when generated. Below to study what the InitInstance function does, pay attention to this line of code, it defines a document template object pointer PDOCTemplate, dynamically generates this document template object with the New operator, and then use the AddDDOCTemplate function to add this document template object to the application. In the document template list maintained by the program, this document template PDOCTemplate uses the frame window, CMAINFRAME, Document CMYDOC, CMAINFRAME, Document CMYDOC, and Window CMYVIEW.

The CMYAPP class provides an interface that communicates with the Windows application. After generating this class, this object automatically connects itself to the Windows system, receives the message sent by Windows, and gives it to the corresponding object to deal with the corresponding object. C Windows program is simple and convenient.

3.2 Class CMAINFRAME

Class CMAINFRAME is derived from the cframewnd in the MFC, so it is also a frame window. As mentioned earlier, CMAINFRAME is the parent class of class CMYVIEW, that is, the object of the CMYVIEW class is displayed in the client area of ​​the main frame window. In class CMAINFRAME, the system has already inherited Windows messages for the general event of the window, such as the member function of changing the size of the window, the window minimization, etc., so the programmer does not need to care for such messages when programming Treatment, thereby reducing the burden of programmers. Of course, if you do need to rewrite a member function that processes such messages, you need to overload the original member function.

In the MFC program, we do not need to operate often, more of the CMAINFRAME class, more of the window category, to achieve the purpose of editing and modifying the data in the program.

Finally, it is to point out that in the program of the MFC mode, when an instance of the program is run, the system automatically generates the object of class CMAINFRAME, CMYVIEW, CMYDOC according to the document template object introduced in front of the CMYAPP class, without the need for a program. The staff actively creates these classes.

3.3 Class CMYVIEW and CMYDOC

The reason why the CMYVIEW class and the CMYDOC class is because these two classes are closely related.

The following block diagram can explain the relationship between the document and the window.

In this block diagram, the document is generated by the document template object, and manages the application object, and the user is stored by the window object associated with the document, and the management of the application's data, the user and the document interaction It is performed by the window object associated with the document.

When generating a new document, the MFC program simultaneously generates a frame window, and generates a window object as a sub-window of the Frame Window in the client area of ​​the Frame Window, which represents the content of the document in a visual manner. An important feature of the window is responsible for handling the user's mouse, keyboard, etc., through the purpose of processing the document object by processing the window object.

It is to point out that the Windows application is divided into document interface SDI and multi-document interface MDI. In a single document interface, the document window and the main frame window are the same concept. And the window object at this time is displayed in the client area of ​​the document window. What we previously generated Test programs is a single document interface. At this time, the document window is the main frame window, that is, the object of class CMAINFRAME. The relationship between these two classes will be described below.

As mentioned earlier, the document class is used to store data in the program, so we first add a member variable in the document class CMYDOC to store data.

Use the CMYDoc option with the right-click on the left to select the Add Member Variable menu item in the pop-up menu.

Figure 2.2

The system pops up the Add MEMBER VARIABLE dialog. Variable Type column is used to enter the type of member variable. It is set to cstring, namely a string type, and the Variable Declaration column is used to enter the name of the variable. Here you can enter the mystring, the Access Combination box is used to set access to the member variable, default is public, set up, click OK The button is closed and the dialog is closed. As shown in Figure 2.3 below:

Figure 2.3

At this time, if you open the class CMYDOC's header file, you can find that there is automatically joined our defined public variable mYString. This variable can be used as data storage space for our documentation, because MyString is a public member, which can be handled by the window corresponding to the document.

In the View menu, select the ClassWizard menu item, the system opens the MFC ClassWizard dialog box, then we want to add a member function that handles the keyboard event for the window class. Select Class CMYVIEW in the ClassName column, then select Message WM_CHAR in the Messages column, click the Add Function button to automatically add a framework for the member function of the WM_CHAR message to the CMYVIEW class. Click the Edit Code button to edit and modify the onchar function.

It can be seen that the system has automatically adds the process function of the WM_CHAR message of the CMYVIEW base class CView in this member function. Pay attention to this line of code:

Begin_MESSAGE_MAP (CMYVIEW, CVIEW)

// {{AFX_MSG_MAP (CMYVIEW)

ON_WM_CHAR ()

ON_WM_LBUTTONDOWN ()

ON_WM_CANCELMODE ()

//}} AFX_MSG_MAP

// Standard Printing CommANDS

ON_COMMAND (ID_FILE_PRINT, CView :: OnfilePrint)

ON_COMMAND (ID_FILE_PRINT_DIRECT, CView :: OnfilePrint)

ON_COMMAND (ID_FILE_PRINT_PREVIEW,

CView :: onfileprintpreview)

END_MESSAGE_MAP ()

It is placed in the MFC message mapping macro begin_message_map, its role is to connect the WM_CHAR message from the Windows system to the member function on the CMYVIEW class, that is, the process of handling this member function as the process of processing the WM_CHAR message. Next, we add specific code that handles the WM_CHAR message to this member function.

First add the following code to the onchar function:

Void CMYVIEW :: OnChar (uint nchar, uint nrepcnt, uint nflags)

{

// Todo: add your message handler code here and / or call default

CMYDOC * PDOC;

PDOC = getDocument ();

}

The role of this code is to first define a pointer PDOC to document class objects, and then use the CMYView class's member function getDocument () get a pointer to the document class object corresponding to the current window class, and assigns this button to the defined document. Type pointer PDOC, so that we can use "PDOC_> MyString" to access public data members in the document class to mystring. Then add the following code to the function onchar:

PDOC_> mystring = nchar;

CclientDC MYDC (this);

Mydc.textout (0, 0, pdoc_> mystring,

PDOC_> MyString.getLength ());

The role of the first line of code in this code is based on the parameter nchar from the message WM_CHAR, that is, the ASCII code of the character entered in the keyboard, add the input characters to the character string object in the document MyString.

Introduce the concept of the device description table before introducing the second line of code. Device Description Table is also referred to as device context, in a Windows environment, when an object, such as printers such as printers, screens, windows, etc., you must first get the device descriptor of this object, and then through this device description table Output. The maximum benefit of using the device description table is the consistency of the output format because the output is no longer directly for specific devices, but is indirectly realized by a device description table in a unified format. The second line of code is to define and generate a device description table object MYDC for a client area of ​​the current window, which is an important keyword in object-oriented language. Refers to the pointer of the object where the member function is located. After the device description of the client area of ​​the window, we can use it to output data in the client area of ​​the window.

The third line of this code is to call the device description table MYDC method Textout, and output the string mystring in the document in the client area of ​​the window.

We have pointed out in front that a document can correspond to multiple windows. If the user changed the data in the document through a window, as in the above code, we change the string object mystring in the document through the window CMYWIVE, so the system maintains the same as the different window displayed by the same document. What is it? We will then enter the following code in the onchar function:

PDOC_> UpdateAllViews (this, 0L, 0);

The role of this line of code is to inform all other windows of the documentation in this window, the data in the document has been updated, these windows should retrieve the data from the document to display, so that all the window of the same document is maintained. Consistency. This line is a typical statement that needs to be added after the data of the document is modified in the window class.

Next, run this program, select the Rebuild All menu item in the Build menu to compile the application, then click the EXECUTE menu item of the Build menu, enter some characters from the keyboard, you can find that these characters are displayed in the window. The customer area of ​​the window.

The actual location of these characters is to store the member variable of the document object MyString this string. Change the size of the window, you can find that the data displayed is not, because we did not re-output the data to the customer area of ​​the window when the window size changes. Close the app, find the member function of the CMYVIEW class onDraw, add the following code:

Void CMYVIEW :: ONDRAW (CDC * PDC)

{

CMYDOC * PDOC = getDocument ();

Ask_VALID (PDOC);

// Todo: Add Draw Code for Native Data HERE

PDC_> Textout (0, 0, PDOC_> MyString);

}

When the size of the window changes, the application calls the ONDRAW function. The role of this line of code we add is to re-display the string object mystring in the customer area of ​​the window, which is still displayed when the window size is changed. In the window customer area. Compile this program again, you can find that the change in the window size does no longer affect the display of the data.

In the previous content, we have introduced the basic structure of the MFC programming program. The content of the MFC is very rich. Here we will provide you with the MFC writing program for your software's basic tasks: accept user input, handler output, file processing, and database access technologies.

Three deep mfc class library

1 handle user input

The program gets data from the user. After your own processing, the program is processed, and then the calculated result is output to the screen, the printer, or other output devices, which is the basic model of software work. The message and keyboard message are the most basic input information. In addition, the MFC encapsulates a series of entries that can perform visualized input interface objects, for example, dialog, and edit boxes, buttons, list controls that can be arranged. , Tree control, etc. Make the program support users entered the means more abundant.

Figure 3.1

1.1 Defining dialog resources

Below we describe how to design a dialog-based interface, accept the data entered by the user, and display them in a graphical manner. We will make such a useful program. It visits a database of saving songs, users can let users define a track table by dialog box and select a background diagram, and then scroll through the name of the track on a window customer area without the system menu. We can see similar things on the big screen of many entertainment venues. In this part, we focus on how to get and process the user input data, in the later processing user output, we will use this example to explain how to operate on the screen.

Let's show how to define a dialog resource. On the Workspace window, the RESOURCE is right-click on the Dialog Small Icon, the menu is displayed, and the insert command is selected, as shown in Figure 3.2:

Figure 3.2

Next, select Dialog in the pop-up resource Type dialog, indicating that a dialog resource is added. Click the New button.

Figure 3.3

Next we start setting up this dialog. There are two buttons on the dialog: OK and Cancel. As shown in Figure 3.4 below. Their roles are to confirm the input and cancel the previous input work, respectively. Change their titles to certain and cancel. Arrange other controls. Each of the dialogs and each of the dialogs has an ID number, and their definitions are included in the resource.h of this file. For example, the ID number of this dialog is IDD_DIALOG2. The ID number of the confirmation button is IDOK. The ID number of the cancel button is IDCANCEL, and the MFC will access these resources through the ID number. Click the TEST button on the Dialog toolbar to test the effect of the dialog. It is important to note that we have defined the dialog box here is just a resource. If you want to make this dialog to really implement its function, you must define a dialog class that uses this resource in the program.

Figure 3.4

1.2 Defining Dialog Box Class

Let's define a dialog class class. In the View menu, select the Class Wizard command, click the Add Class button, select the new command when the pop-up menu is selected, enter the name of the new class in the name column, select which type of MFC in the base class list box . In the Dialog ID list box, select the ID number of the dialog resource, in this instance, we don't use Ole Automation, so choose NONE in this group box. In the File Name column, it is displayed in which file is written in this class.

Figure 3.5

Click on the Change button shown in Figure 3.5, knock in the new class, and define which file is written in Header File and Implementation File, which file is written, click OK button to confirm, so we completed the new dialog box class. Definition. Click the OK button, Class Wizard will work according to our request for the dialog class. Open Workspace, select the File View page, in the Source Files and Header Files groups, to the Class Wizard have newly created two files and add them into the project. Songdlg.h is the statement of CSONGDLG this class, and the content of Songdlg.cpp is the implementation of this class. However, the current program only contains code that implements the most basic functions of a dialog, and calls it after calling the Domodal function of this dialog class. But users will not be accepted by all input work through dialog boxes.

Below, we start to complete the work of the implementation dialog to accept the user's input function. The job here is the control of the control arranged in the dialog box. Control can also be divided into two types: The first is to exchange data with the controls on the interface, and write out the data entered in the dialog box in some response functions in the dialog box. For example, when the user clicks on the confirmation input button, we trigger the click event of the button, we have to remove the track string to the database from the editing box of the new song, and display it in the list of tracks. .

We can use a mechanism called dialog box data exchange (DDX) to remove data from the editing control. This mechanism has been encapsulated in the MFC dialog box class CDIALOG. Its work is to establish a connection between the edit box in the dialog resource and a member variable of the dialog class class. Then automatically complete data exchange between member variables and controls by MFC. First open ClassWizard, select the member variable page, select CSONGDLG when selecting Class Name list box, select the ID number IDC_EDIT1 of the track edit box, click the Add Variable button.

Figure 3.6

In the Member Variable Name column, type the name of the variable, in the Category list box, you can select the type of variable, Value means that a data variable is generated, and the Control type variable can be used to perform another type of control for the control resources. Its type depends on the previously selected control resources, for example, if a edit box control is a member variable of a Control type, then it can only be CEDIT type. We will specifically describe how to use the Control type member variables in the later content.

Figure 3.7

Generate a Value variable, its data type is a string. Click the OK button. At this time, Wizard automatically adds all the code to exchange all the code. Open the header file and implementation file of the dialog class, we found a member variable of a CString type:

// Dialog Data

// {{AFX_DATA (CSONGDLG)

ENUM {IDD = IDD_DIALOG2};

CString m_songname;

//}} AFX_DATA

And in the construction function, this variable is initialized:

Csongdlg :: csongdlg (cwnd * pparent / * = null * /)

: Cdialog (csongdlg :: IDd, pparent)

{

// {{AFX_DATA_INIT (CSONGDLG)

m_songname = _t ("");

//}} AFX_DATA_INIT

}

There is a virtual function in the newly-generated dialog box class csongdlg:

Virtual Void DodataExchange (CDataExchange * PDX);

// DDX / DDV SupportDodataExchange function is a function of dialog box class and dialog resource for DDX data exchange. This function will be called when the dialog is initialized or when the Updatedata () function is called in the program. DDX_Text This function can handle multiple types of data exchange between data member variables and control resources. This intermediate includes int, uint, long, dword, cstring, float, double, etc. PDX This parameter is a pointer to a cdataExchange object With it. We can set a method of data exchange. For example: the direction of data exchange. This code can determine the direction of the data exchange by PDX whether the direction of data exchange is from the variable to the control or from the control to the variable, and then performs different processing. After performing data exchange, the program can be entered by the user via the member variable.

Another type of control for control resources is to manipulate the appearance of the interface control. For example, we can control the list controls in the dialog box by generating a Control type member variable. Like the addition method of the Value type variable, we can generate a CLISTCONTROL type object using ClassWizard, adding such a code in DODATAExchange:

DDX_Control (PDX, IDC_LIST1, M_ListCtrl1);

DDX_Control is also a function provided by the dialog data exchange mechanism, which is the same as DDX_Text. Use the control objects M_ListCtrl1 just defined, you can manipulate the list box resource.

When the dialog begins to run, we need to remove the names of the entry that have been wrapped in the database in the list box. This job should be done when the dialog responds to the WM_INITDIALOG message. Use Class Wizard to add this message response function. Select the csongdlg this class in the list box on the left, select the dialog initialization message in the message list box, click the Add Function button, Wizard automatically overloads this member function of the base class in this class declaration and A function body is added when the implementation file is implemented. Click the Edit Code button to join our own code as in the function body.

Figure 3.8

Add the following paragraph with the following segment: OnInitDialog in response to the WM_INITDIALOG message.

Colevariant var;

LV_Item lvitem;

CString Name ("Song_Name");

Char Str [50];

Lvitem.iitem = 0;

IF (globalRS_> isopen ())

GLOBALRS_> Close ();

CSTRING STRQUERY = _T ("SELECT *");

STRQUERY = "Songs";

GlobalRS_> Open (dbopenDynaset, strquery);

GlobalRS_> M_BCHECKCACHEFORDIRTYFIELDS = FALSE;

IF (globalRS_> isopen ())

{

IF (! GlobalRS_> getRecordcount ())

Return 0;

GlobalRS_> MoveFirst ();

While (! GlobalRS_> ISEOF ())

{

VAR = GlobalRS_> getfieldValue (_t ("[")

Name _T ("]"));

LVItem.mask = lvif_text | lvif_image | lvif_di_setitem;

LVItem.iitem ;

Lvitem.isubitem = 0; strcpy (STR, (LPCTSTR) CString (v_bstrt (& var)));

Lvitem.psztext = STR;

lvitem.iimage = 0;

M_ORIGINSONGLIST.INSERTITEM (& lVItem);

GLOBALRS_> MOVENEXT ();

}

}

IF (globalRS_> isopen ())

GLOBALRS_> Close ();

This uses DAO technology to access the database and add an entry to the list control using the read string. With regard to the use of DAO technology, we will introduce in detail in other chapters. We care about the following code:

LVItem.mask = lvif_text | lvif_image | lvif_di_setitem;

LVItem.iitem ;

Lvitem.isubitem = 0;

STRCPY (STR, (LPCTSTR) CSTRING (V_BSTRT (& var)));

Lvitem.psztext = STR;

lvitem.iimage = 0;

M_ORIGINSONGLIST.INSERTITEM (& lVItem);

It performs the operation of adding an entries for the list control. A structure provided by WIN32 is required here: lv_item. We can find its definition from the Help of VC:

Typedef struct _lv_item {

Uint Mask;

IIITEM;

Int isubitem;

Uint State;

Uint Statemask;

LPTSTR PSZTEXT;

Int cchtextmax;

Int Iimage; // Index of the List View Item 抯 icon

LParam lParam; // 32_bit value to associate with item

Lv_item;

To add an entry, we first fill in the information information in this structure, and then send it to the list object to add an entry function insertItem.

The next code is deleted in the track list box in the Songs list box Click on the event. To achieve an operation of the entries from the list control, you can pass the index number of the entry you need to delete to the list of entries deleteItem.

Int Totalnum;

Totalnum = m_selsonglist.getItemcount ();

INT Step = 0;

LV_Item lvitem;

LVItem.mask = lvif_text | lvif_image | lvif_di_setitem;

Lvitem.isubitem = 0;

lvitem.iimage = 0;

While (Step <= Totalnum)

{

IF (m_selsonglist.getitemstate (step, lvis_selected))

{

m_selsonglist.deleteItem (STEP);

}

Step ;

}

We summarize the work required to control the controls above the dialog:

First define a member variable in the dialog class, then call the function of the member variable of the dialog to manipulate the interface control.

2 related screen output

2.1 Device context works

Both the vast majority of Windows applications need to display their own data on the screen. Since Windows is an operating system-independent operating system, it is done by indirectly through the objects that are output on the screen to complete the object called Device Context. We present the requirements of the screen output to the device context, and then call yourself to call the driver of the specific output device to complete the actual output. Around the device context, the MFC provides a series of drawing objects that work with them, including brush objects, brush objects, and font objects, and more. Their working model is this: first on the device context object - we are referred to as DC object - set, then select the tool required to perform screen output, and draw a graphic with the output function of the DC object. The target of the screen output is generally a customer area of ​​the window. It is an universal output area that accepts whether text, bitmaps, or other types of data (more OLE objects). 2.2 Analysis of the principle of instance drawing

In the content related to the user input section, we have introduced an example. It visits a database of saving songs, users can define a track table by dialog box, and select a background image, then in one without system The window customer area of ​​the menu scrolls the name of the track. We have already introduced the way to introduce the user input by the dialog, which focuses on how to display the information entered by the user on the screen.

We use the string of the user to scroll over the output on one background diagram. The basic model of using the device context has been described above. That is, first select the tool of the drawing, then call the DC's draw function to draw. In Windows, a WM_PAINT message will be issued when the appearance of each window changes, and the redrawing work of the window is in response to this message. You can use ClassWizard to add this message response function. Thereafter, the screen output can be performed in this function. When will there be a redraw event? When you call the CWnd's UpdateWindow and RedRawWindow number, you will trigger an event. We can also use the SendMessage function to send a redraw message to a specified window. In addition, the invalidate function that calls CWnd can indicate whether it needs to be wiped back, if you use the InvalIDateRect function, you can set the invalid area of ​​the client area. When the system is redrawn, it will only re-draw the content of the area, we first in the window The client area posts a bitmap and scrolls the output text. How to implement scrolling output? Our method is to set a timer in the program. When the timer is scheduled for the event WM_TIMER, call the RedRawWindow function, trigger the redraw event, we only need to re-regain it in its message response function onpain Draw a background, wipe it out of the original text, and then constantly changing the location of the text output to achieve the goal. You may re-draw a whole background, it takes too much system time and may flash the background. This fear is necessary. In Windows95, the system optimizes the mechanism of redrawing. Under the case where we don't specify invaracted areas, the system will choose a minimum invalid area, only redraw this area.

2.3 Drawing operation implementation

The source program of the drawing operation will make you a general understanding of the use of the device context.

First, it is generated into a device context. CPAINTDC is a class that is inherited from the CDC provided by the MFC. What is the benefit of using it? If you use the CDC directly, we need to first call the CWnd's BeginPaint function to do some preparations for the redrawing work, and use the Endpaint function to end the drawing work in completing the draw. All drawings must be done between these two functions. CPAINTDC encapsulates these two functions, automatically calls them, and users do not need to make these calls.

CPAINTDC DC (this);

Bitmap BM; M_Bitmap_> GetBitmap (& BM);

CDC DCIMAGE;

IF (! DCIMAGE.CREATECOMPALEDC (& DC))

Return;

CBitmap * Poldbitmap = DCIMAGE.SELECTOBJECT (m_bitmap);

DC.Bitblt (0, 0, Bm.Bmwidth, Bm.Bmheight,

& DCIMAGE, 0, 0, SRCCOPY;

The above code is completed to output a bitmap on the screen. First generate a bitmap object according to the resource, then generate a memory DC object consistent with the cpaintdc, select this bitmap in the memory DC. Bitmap is a bitmap structure provided by Win32, and we save the information of this bitmap in this structure. The reason for this is due to the location and size information of the bitmap. The definition of the Bitmap structure is as follows:

Typedef struct tagbitmap {/ * bm * /

Int bmtype;

Int bmwidth;

Int Bmheight;

Int bmwidthbytes;

BYTE BMPLANES;

BYTE BMBITSPIXEL;

LPVOID BMBITS;

} Bitmap;

Will these preparations. Call the Bitblt function of the DC object to attach the bitmap from the memory DC to the drawing DC. The first four parameters indicate the location and size of the bitmap on the DV. The fifth parameter is the address of the memory DC of the bitmap. The next two parameters are copied from which point of the bitmap. Finally, this parameter sets the interrelationship between the bitmap and the current content on the screen. Srccopy means that the copy is over from the original content. This parameter also has many other options to say to reverse operation or a different or operation, setting different parameters to get a rich effect.

The following describes how to output text. First set the DC object:

Dc.setbkmode (transparent);

Dc.SetTextColor (RGB (0, 155, NOWX * NOWX));

Here, the background of the text is placed transparent, then set the foreground color of the output text.

The following program means that the text is selected to output the text.

Logfont logfont;

MEMSET (& logfont, 0, sizeof (logfont));

Logfont.lfWeight = 50;

Logfont.lfheight = 50;

LSTRCPY (logfont.lffacename, "black body");

Nowfont.createFontIndirect (& Logfont);

Dc.selectObject (& NOWFONT);

First, a font information structure provided by Win32. To allocate memory space. Fill this font structure according to our requirements, set the width of the font, set the font, select the font type, generate a cfont font object according to this structure, let DC objects select this font object, and finally use the DC text output function to output A string.

All in all, the rules for the screen output are as follows:

The first must perform screen output by CDC object;

Second, set the output attribute of the DC object;

Third choice of drawing tools

Fourth the drawing function of the CDC object.

The content about the screen output is introduced here.

2.4 Related Screen Mapping Methods

Under normal circumstances, we all as a unit of drawings, we call it equipment coordinates. We are inevitable to use the equipment coordinate system when making drawing operations.

Windows provides several mapping methods, or called coordinate systems. You can contact them by them and the device context. For example, what kind of display device is said, if we need to display a 2 inches height, 2 inches wide rectangle, what should I do? This depends on the coordinate system we set. If we specify the mm_text mode, at this time, the coordinate origin is located in the upper left corner of the screen, points to the right and bottom of our face to the screen, and its drawing unit is pixel, if one inches correspond to 72 If you are pixel, we need to draw this rectangle: DC.Rectangle (CRECT (0, 0, 72 * 2, 72 * 2));

So if we specify the mm_loenglish method, then a plot unit is one percent, the coordinate original is still in the upper left corner of the screen, but the direction of the X-axis and the Y-axis is in contrary to the axial direction in the mm_text mode, and complete the drawing The rectangle of the above mentioned above, we need to write such code:

Dc.Rectangle (CRECT (0,0,200, _200);

It can be seen that the choice of coordinate system has a big impact on our writing procedures.

In addition, at some time, we need to work under several different coordinate systems, then it is necessary to work between these coordinate systems. So, we need to introduce the following Windows coordinate mapping method here.

In general, the most common way is WM_TEXT mode. In the WM_Text coordinate mode, the coordinate is mapped to the value of the pixel, and the value is incremented by the right, and the value of Y is incremented downward, and the coordinate origin can be changed by calling the CDC's setViewPotorg function. The following code sets the screen mapping mode to mm_text, and set the coordinate original (300, 300):

DC.SETMAPMODE (mm_text);

Dc.SetViewPortorg (CPOINT (300, 300));

In addition, Windows provides a set of very important proportional fixed mapping methods, below these mapping methods, we can change its coordinate original, but it is unable to change its proportion factor. For mm_loenglish mapping, we already know that its X value is reduced to right, Y's value is down, all fixed-scale mapping methods follow this principle. Their proportion factors are also different. Our list is as follows:

Mapping mode logic unit mm_loenglish0.01 inch mm_hienglish0.001 inch mm_lometric0.1 mm mm_himetric0.01 mm MM_TWIPS1 / 1440 inches

The last mapping mode mm_twips often uses the printer, one 'TWIP' unit is equivalent to 1/20 points (a little approximate to 1/72) inches. For example, if the specified MM_TWIPS is a community, the height of the character is 12x20 for the 12-point size word, ie 240 TWIP.

In addition to a fixed-scale mapping method, Windows also provides a scaled mapping mode in which we can change the proportional factor in addition to the proportional factors. With such a mapping method, when the user changes the size of the window, the size of the drawn graph can also change according to the proportion; the same, when we flip a shaft, the images they have drawn are also in addition. One axis is rotation of the axis. There are two modes of mapping: mm_isotropic and mm_aniotropic.

In MM_ISOTROPIC mode, the proportion of the vertical and horizontal is 1: 1, in other words, regardless of how the proportional factor changes, the graphics we draw will not change its shape. However, in the mm_aniostropic mode, the proportional factor of x and y can be independently changed, and the shape of the graph can vary. We analyze the following procedures:

Void Caview :: Ondraw (CDC * PDC)

{

CRECT ClientDC;

GetClientRect (ClientRect);

PDC_> SetMapMode (mm_anisotropic);

PDC_> Setwindowext (1000, 1000);

PDC_> SetViewPortext (ClientRect.right, _clientRect.bottom);

PDC_> SetViewportorg (ClientRect.Right / 2, ClientRect.bottom / 2);

PDC_> Ellipse (CRECT (_500, _500, 500, 500));

}

The function of this code is like this, first obtain the size of the rectangle of the window customer area, then use the setWindowext function to set the proportion, the size of the window size is set to 1000 logical units and 1000 logical unit wide, coordinate original The center of the window is set to the window, and an ellipse of a radius of 500 logical units is drawn.

Here, if you change the mapping method to mm_isotropic, a circle will be drawn. The circular diameter is the width and high minimum value of the window.

Below we give the formula of logical units to device units:

X proportional factor = x viewport range / X window range

Y proportion factor = yy viewport range / y window range

Device X = logic x * x proportional factor X coordinate original offset

Device Y = Logic Y * Y proportional factor Y coordinate original offset

When we set the mapping method of the device context, the logical coordinates can be used directly as their parameters, but the coordinate values ​​of the mouse obtained from the WM_MOMOVE message are the device coordinates. Many other MFC library functions, especially members of CRECT, only accept equipment coordinates. So we sometimes use the CDC's LPTODP and DPTOLP to convert between logical coordinates and device coordinates.

Below we list some of the rules to follow when working on the coordinate map:

All members of the CDC can be considered as a parameter in logical coordinates, but with CRECT-related functions. Members of CWnd can be considered as parameters in the unit. All Hit_Test operations should consider the equipment coordinates. Save data in the form of logical coordinates, otherwise the user is scrolling the window, this data is no longer valid.

3 file processing

Almost all software requires saving the information among the program in the disk memory. This information may be the initialization data of the program run, or the resulting result is calculated in the program, which may also be the information that the program is often used. Working from the disk memory is often done by file operation or database operation. With regard to the content of the database operation, we will introduce in a detailed introduction in the following chapters. In the following, we mainly discuss how VC implements data access work in general sense.

VC is an object-oriented development platform that uses MFC written programs, we define and generate a variety of objects, through the collaborative work completion of the program. So in the MFC, the core content of the program's access work is how to achieve the continuation of these objects. A object that can achieve a sustained object know how to save and load their own data. For example, when the program uses the MFC document / view structure, if the correct duration is provided for the document object, it will automatically save and restore their own data when you need, and keep the latest modification results. It should be noted that the continuation of the object is also saved to disk files. It is the advantage that the MFC encapsulates the binary access process, and the program code to achieve object access is simplified. Of course, if you prefer to have direct operating files to access data, MFC also provides a more direct channel. CFILE This class encapsulates all common operations for files, and uses the CFile object to handle files more simpler than using the API function.

3.1 Object Substation

Among the MFC, the sustaining function of the object is mainly implemented by the serialization mechanism of the document object in the document / view structure. Below, we will detail how to use serialization mechanisms to achieve the continuation of the object.

Serialization, simply, to a procedure for saving objects or reading objects to a persistent storage medium - such as disk files. You can realize serialized classes - that is, from cobject, there is a member function called Serialize, serialization is mainly in this function. We use a schematic diagram to illustrate the principle of serialization.

The MFC uses a type of archive object that is a CARCHIVE acts as an intermediary of the disk file and the object in the program. The archive object is always associated with a CFILE object, and some of the information needed to serialize sequence, such as file name, and access flag. The main job of the subject is to save your own member variables or current state. We can use the overloaded inflow and outflow operator to save or remove the value of the variable member directly to the archive object, while the work saved to the disk file is done by the CARCHIVE object to complete the CFILE object. When the user opens or saves files with document object data or use the Open of the document object,

When Save, the Save AS menu command, the MFC will automatically call the Serialize function.

Make the class to achieve sequencing, requiring five steps:

1. From the COBJECT class or its derived class;

2, use the Declare_Serial macro in the class declaration;

3, overload the serialize function;

4, define the constructor without variables;

5, use macro IMPLEMENT_SERIAL in class implementation file.

In the next section, we will explain how to implement the serialization of the class in detail in a specific example.

3.2 instance analysis

After describing the basic principles of class sequence, let us look at a specific serialization example Drawline. Start this instance.

Figure 3.9

In this example, we will complete a simple drawing of the straight line. Press the left button in the view, then drag the mouse to a new location to loosen the mouse, the program draws a straight line. Let's take a look at the basic composition of this program.

In addition to basic document classes and view classes, we have a straight-line CLINE. It has four int member variables m_x1, m_y1, m_x2, m_y2 to record the X-axis and Y-axis direction coordinates of the two endpoints of the line. In addition, there is a DRAW member function, which draws the straight line in the view client area based on the above four member variables of the straight line. Double-click the DRAW function of CLINE in Workspace, you can see the implementation of the DRAW.

Void Cline :: DRAW (CDC * PDC)

{

PDC_> MoveTo (M_X1, M_Y1);

PDC_> LINETO (M_X2, M_Y2);

}

We handled three messages of ONLBUTTONDOWN, ONMOMOVE, ONMOVE, ONMOTONUP, and in Workspace's ClassView, which can also be seen in its implementation. In addition, we have a member variable M_LineArray in the document class cdrawlinedoc, which is used to record our straight line drawing in the view client area. The function getLine is a straight line in M_LineArray according to the index, and GetNumlines is the total number of lines.

After understanding the basic program structure, the linear object is sequenced.

1 Delivered from the Object class and use macro Declare_Serial

Open the header files for definition CLINE, you can see this class is born from the COBJECT class. To implement serialization on the CLINE class, you need to add macro Declare_serial calls in the class declaration, and add macro IMPLEMENT_SERIAL in the implementation file of the class. The COBJECT class has basic serialization, and these functions can be obtained by inheriting such inheritance, and an unparalleled constructor is indispensable.

After we open Line.h, the first sentence in the CLINE class can be Declare__serial (Cline), this macro does not need to add dividends.

2 overloaded the Serialize member function

We want to realize serialization, first modify it, select the Cline class in the ClassView of Workspace, right-click, select Add Member Function Add a member function:

Figure 3.10

VC will jump out of the dialog box that adds a function shown in 3.11:

Figure 3.11

Enter Void in Function Type, enter Serialize (CARCHIVE & AR) in Function DeclareTion, then select Virtual, press OK. Then you can see this function in the ClassView.

Below we edit this function, double-click the Serialize function of the CLINE class displayed by Workspace, turn to Line.cpp. The implementation of this function is as follows:

Void Cline :: Serialize (CARCHIVE & A)

{

COBJECT :: Serialize (AR);

IF (ar.isstoring ())

{

Ar << m_x1 << m_y1;

Ar << m_x2 << m_y2;

}

Else

{

Ar >> m_x1 >> m_y1;

Ar >> m_x2 >> m_y2;

}

}

First call the class class's Serialize function, COBject :: serialize (ar); then determine whether saving data or load data, and then actually access according to the result of the judgment. Here AR is the archive object pointer that the framework is passed to the serialization function.

When the serialization function of the base class is called, the status of Ar is determined when ar.isstoring () returns true, and the data is saved at this time. When ar.isstoring () returns non-true, then the CARCHIVE object requires read data.

3 use operator access data

In the above code we use >> and <<, here for them, >> and << are an operator, used to indicate reading or save data to the CARCHIVE object, if we can Take a reset. Such as ar >> m_x1 >> m_y1; >> is denoted by reading data m_x1, m_y2, this symbol, and >> can be used separately, such as Ar >> m_x1; ar >> m_y1 The same ar << m_x1 << m_y1; <

After serializing the line object, we will rewrite the document class, first implement the serialization function of the document class. Double-click the CDRAWLINEDOC class serialize function in Workspace to open it. The Serialize function of the document class is a virtual member function, and its default implementation does not work.

Let's see the serialization function of the document class. The serialization function of the CDRawLinedoc class is mainly called to the serialization function of the CLINE class object. It is this generally like this: When saving, we first get the total number of straight lines - call GetNumlines function, then use a loop to call a serialization function for each linear object; when reading data, you can first get the number of straight lines - read from the file, and then use one loop, each time you read Straight line - call the sequence of the object, then add it to the member variable M_LineArray of the document class until the line is read straight. The source code for this function is as follows:

Void CDrawlinedoc :: Serialize (CARCHIVE & A)

{

INT LINENUM = GetNumlines ();

IF (ar.isstoring ())

{

Ar << linenum;

For (int i = 0; i

M_LineArray.getat (i) _> Serialize (AR);

}

Else

{

M_LineArray.removeAll ();

AR >> LINENUM;

Cline line;

For (int i = 0; i

{

Cline * pline = new cline ();

PLINE_> Serialize (AR);

M_LineArray.Add (PLINE);

}

UpdateAllViews (NULL);

}

}

5 connection view

Next, we have some must-hand of document classes and views: In ClassWizard, we add two member functions to CDRawLinedoc: OnnewDocument and onoPendocument. The call to ONNewDocument is when a newly generated document, so the member variable M_LineArray, which needs to handle the document class, and remove the straight line inside, and call UpdateAllViews (NULL), update the view, our code for this function Changed below:

Bool cdrawlinedoc :: onnewdocument ()

{

IF (! cdocument :: onnewdocument ())

Return False;

// Todo: Add reinitialization code here

// (SDI Documents Will Reuse this Document)

M_LineArray.removeAll ();

UpdateAllViews (NULL); RETURN TRUE;

}

The framework is called on the onopendocument. When we open the file, this time, before we read the data, you also want to clear the M_LineArray all the straight lines, our code for this function as follows:

Bool CDrawlineDoc :: onopendocument (lpctstr lpszpathname)

{

M_LineArray.removeAll ();

UpdateAllViews (NULL);

IF (! cdocument :: onopendocument (lpszpathname))

Return False;

// Todo: Add Your Specialized Creation Code Here

Return True;

}

We also need to rewrite the obsolete onDraw, so that it can achieve heavy paintings, here we only simply call the Draw member function for each linear class object, redraw, the code for each line, our code for this function Make the following changes:

Void CDrawlineView :: OnDraw (CDC * PDC)

{

CDrawlineDoc * pdoc = getDocument ();

Ask_VALID (PDOC);

// Todo: Add Draw Code for Native Data HERE

For (int i = 0; i getnumlines (); i )

{

(PDOC_> GetLine (i)) _> DRAW (PDC);

}

}

At this time, we have completed the serialization of the program, and the program is running.

3.3 Class CFILE with the relationship between file processing

The CFILE class is used to handle the I / O operation of the normal file, which is directly supplied, binary input / output services, and indirectly supports text files and memory files through their derived classes. Because the CFILE class is basically encapsulated in the CARCHIVE class, we only introduce this class.

The CFILE class has three constructor, and its prototype is shown in the figure.

Virtual Bool Open (LPCTSTSTSTSZFLILENAME, UINT NOPENFLAGS,

CfileException * perror = null)

Where: HFile is a handle that has been opened. LPSZFileName Specifies the string of the path you want. The path can be relative or absolute. NOPENFLAGS refers to sharing and access mode, and we have left a dedicated description for this logo.

The CFILE class creates and opens the file with open. Create a new file with Open, you must have a file name and select a certain open mode:

CFILE reads and write to disk files is made through functions read, write, and seek.

Virtual uint read (Void * LPBUF, UINT NCOUNT);

Virtual Void Write (Const Void * LPBUF, UINT NCOUNT);

Virtual Long Seek (long Loff, Uint NFROM);

Function READ: Returns the number of bytes transmitted to the buffer. If you read the file end, the return value may be less than the NCOUNT value. LPBUF: Pointing to the user-defined buffer to receive data; Ncount: To read the maximum number of bytes read from the file; function Write: write buffer data to the file; seek is used to position file pointer position, if If the requested location is legally, return a new byte offset from the file header.

The open and closing of the file is relative. After opening a file, you must turn it off, the file is closed is quite simple, and the CFILE object is called to call the Close function. The file sharing and access flags are described below. The following flags specify the action that can be performed when the file is opened. You can use OR to combine the options listed below. An access license and a shared option are required; ModecReate and ModenoInberit methods are optional.

ModeCreate Indicates that the constructor creates a new file, if the file already exists, the file is from 0.

ModeRead opens files for reading.

ModeReadWrite Opens the file for reading and writing.

ModeWrite Opens files to write only.

The MODENOINBERIT blocks the file from being inherited by the child process.

Sharednynone opens the file and does not allow other processes to read or write the file. If the file is opened by any other process with a compatible manner, Create will fail. Sharednywrite opens the file and does not allow other processes to write the file. If the file has been opened by any other process, CREATE will fail. SharednyRead opens the file and does not allow other processes to read the file. If the file is opened by any other process in a compatibility or reading mode, Create will fail. ShareExClusive is opened in exclusive ways and does not allow other processes to write the file. If the file has been opened in other read or write, even if the current process is turned on, the construct will fail. ShareCompat opens files in a compatible manner, allowing any processes on the given machine to open this file any time. If the file has been opened in any other shared mode, the construct will fail. Typetext sets text mode, special processing for the carriage return, it is only used to derive class. Typebinary sets binary, it is only used to derive class.

4 DAO technology

4.1 DAO and ODBC

Database Access jobs in a Windows environment You have two options: use DAO technology or use ODBC technology. ODBC (Open Database Connectivity), an open database interconnection, as an important part of the Windows open level, has been familiar with a lot of Windows programmers. DAO (Data Access Objects) is a data access object set (Data Access Objects) is a access technology based on a database object collection provided by Microsoft. They are all parts of the Windows API that can be accessed independently of DBMS. So where is the difference between ODBC and DAO? The mechanism of ODBC and DAO access to the database is completely different. ODBC's work relies on the drivers provided by the database manufacturer. When using the ODBC API, Windows's ODBC manager passes the request of database access to the correct driver, and the driver uses the SQL statement to indicate DBMS to complete database access. DAO is wrapped around the intermediate link, and the database access object set provided directly from the Microsoft Jet Database Engine (Microsoft Jet Database Engine) provided. The speed is faster than ODBC. The database engine has now reached 3.0. It is the basis for DAO, MS Access, MS Visual Basic, etc. The engine itself has a database format of MDB, which also supports access to most database formats currently popular, and of course MDB is the most efficient database in the database engine.

If you use the client / server model, it is recommended that you use the ODBC solution; if you wish to use the database of MDB format, or use the database engine speed, then DAO is better.

4.2 Using the MFC implementation DAO technology MFC has packaged all DAO objects. Use the MFC for DAO programming, first provide a database object to each open database file - CDAODATABASE, manage the connection of the database by this object. Generation of records - CDAORECORDSET, working in query, operation, update, etc. If you need to manage the structure of the database in the program, you need to use the table structure information object CDAOTableInfo and field definition object CDAOFIELDINFO in the DAO to obtain or change the work of the database table structure. CDAODATABASE, CDAORECORDSET, CDAOTABEDEFINFO, CDAOFIELDINFO are the most basic and most common class of DAO programming using MFC.

Below, we use an example to describe how to use the MFC's DAO class for database access. In this example, we will establish a student file management database in the program and add, delete, and browse records by dialog box. We first look at the following procedures.

We will introduce how to generate and use database objects, record set objects, and how to manipulate the database through a recordset. We will introduce how to use MFC to implement DAO technology by explaining the source program of the database.

Here's how to build a library:

First create a new database object.

NewDatabase = new cdaodatabase;

NewDatabase_> Create (_T ("stdfile.mdb"),

DBLANGGENERAL, DBVERSION30);

Use the database engine to create a Database file in a MDB format on the disk.

STDFILE.MDB is the name of the database file established on the disk,

DBLANGGeneral is the language option.

DBVersion30 This is the database engine version option.

Figure 3.12

Then create a new database table definition information object.

CDaotabledef * TableInfo;

TableInfo = New CDaotabledef (NewDatabase);

TableInfo_> Create (_T ("student"));

Create a new field definition information object.

Fill in the field to define the information object as required.

Define field name:

FieldInfo_> m_strname = cstring ("studentname");

Define field type:

FieldInfo_> m_ntype = dbtext;

The number of bytes occupying the field:

FieldInfo_> m_lsize = 10;

Define field features:

FieldInfo_> m_lattributes = dbvariablefield | DBUPDATABLEFIELD;

The DBVARIABLEFIELD parameter means that the number of bytes that this field is variable.

The DBUPDATABLEFIELD parameter means that the value of this field is variable.

Generate fields in the database table object depending on the field definition object.

TableInfo_> CreateField (* fieldInfo);

After generating all the fields, the definition of the new database table is in the database object.

TableInfo_> append ();

Here's how to perform database operations:

First generation record set objects:

Recordset = New CDaorecordSet (NewDatabase);

Then open the recordset object using the SQL statement. First, put the SQL statement into a string:

CSTRING STRQUERY = _T ("SELECT * from stay");

Use this string to open the recordset.

Recordset_> Open (DBOPENDYNASET, STRQUERY);

The DBOPENDYNASET parameter means that the type of recordset is opened. DBOPENDYNASET means to open a dynamic recordset that can scroll two-way scrolling. The record in this record is to query the database using the SQL statement we define. This parameter has another two options: DBOPENTABLE parameters indicate a recordset that opens a data table type, using this type of recordset, can only manipulate records in a single database.

If you use the DBOPENSNAPSHOT parameter to indicate the image recordset, it is actually a static copy of the selected recordset, when you only need to perform a query or want to make a report, use this recordset more appropriate, it is not The data in the database will be modified.

Next, a flag bit in the recordset is assigned, indicating whether it is required to automatically mark the changed records in Cache. When using the record set, DAO reads the recorded record into cache, all manipulation is performed for records in Cache, to implement the record update to the database, must write the value of the fields changed in the cache record Go back to the database file. The role of this flag is whether the data that needs to be written back in the record is required when the data changes in the cache.

Here is how to fill a record.

m_recordset _> addnew ();

m_recordset_> Update ();

Using the addNew () This function can add new records in the data sheet record set or the dynamic recordset, and then call UpdNew () to confirm this add action, save the new record to the database file. . The location of the new record in the database depends on the type of the current recordset: If it is a dynamic recordset, the new record will be inserted to the end of the recordset. If it is a data sheet recordset, when the primary key is defined in the database table, the new record will be inserted into the right place according to the sort rule of the library table; if the primary key is not defined, the new record will be inserted to the end of the recordset.

Use addNew () to change the current record of the record set. It can only be fill in its data only on the new record. So we use the MoveseT function to make the recorded records into the current record, then call the Edit function to edit the new record.

m_recordset_> movelast ();

M_RecordSet_> Edit ();

Assign the new recorded field:

Colevariant var1 (m_name, vt_bstrt);

m_recordset_> setfieldValue (_t ("studentname"), var1);

Colevariant var2 (m_id, vt_bstrt);

m_recordset_> setfieldValue (_t ("studentID"), var2);

Colevariant var3 (m_class, vt_bstrt);

m_recordset_> setfieldValue (_T ("StudentClass"), VAR3);

Colevariant var 4 (M_SID, VT_BSTRT);

m_recordset_> setfieldValue (_t ("studentsid"), var4);

Colevariant This class encapsulates the structure of the Variant provided by Win32 and the operation of it. A variety of types of data can be stored in this class. It should be noted that this inclusive ability is provided by Union in the C language, that is, a Colevariant object can only save one type of data. Let's take the value of the field into the OLE variant object, and then use this variant object to assign the fields in the record. The role of the VT_BSTRT parameter is to indicate the type of data to be blocked when generating the OLE variant object. When all the fields end assignments, the UPDATE function is called to save the current modification.

m_recordset_> Update (); Note that before calling the UPDATE function, if you perform the operation of changing the current record, then all assignment works will be lost, and no warning will be given.

This code takes out a record value from the recordset, which is also used to use the OLE variant object. The recent GetFieldValue will return a variant object, and we first take this variant object and then take it out of the required value.

Here V_BSTRT indicates the data of the string type from the variant object.

How to delete a record from the database? First, the record is to be recorded. Then use the Delete function to perform the delete operation.

M_RecordSet_> delete ();

After deleting, we must change the current record to another record to confirm this delete action.

The above is a method of using DAO in the MFC.

Understand the previous content, I believe that you have more in-depth understanding of the MFC class library, you can use the MFC to write a good program. Below, we will show you how to debug your own procedures under the Visual C integration development environment.

5 print

The print function is a basic feature that now almost all applications must have, which can be seen in the menu of the AppWizard's application framework. It can be seen in the print and print preview feature. However, if the implementation of printing functions If it only relies on the previous Windows API call to implement, it is a very complicated thing. In contrast, Microsoft's basic class library application framework greatly simplifies the implementation of the print function, and also provides print preview feature.

5.1 Print and display

Previously we conducted output work in a window area on the screen, and printing is a printer output something on the printing paper. Indeed, there is a lot of similarity between the two, for example, they can output text, and some graphics can be output. Based on these similarities, in Windows, the commonality between them is used in the device context. When you print and output, you can use the same output function (such as Textout) to output on the screen or on the paper. Windows will contact the output on the appropriate device in different situations. But this does not mean that we can completely regardless of the differences between the two, and think that we only have the corresponding print function to automatically implement the screen output function. After all, there are some differences that cannot be unified: when printing, the concept of page and paging, that is, data or output is organized on a piece of paper with a certain size; when the screen is output, there is no page. And paging features, at the same time, it is considered that the output area of ​​the screen output is not limited, exceeds the window range, we can scroll with the scroll bar.

CVIEW has three virtual functions: onpaint (), onDraw (CDC * PDC), onprint (). OnPaint () is called when the view class window needs to be output on the screen, responsible for completing the screen output display of the window; OnPrint () is called when printing a page, responsible for printing on a sheet of printing paper. The default implementation of these two functions contains calls to OnDRAW (CDC * PDC). In our previous procedures, we don't consider printing problems, so we are defendant to consider how to complete the screen output in OnDraw. But now it is different. When we add code to OnDraw, we must be careful that this may be printed, not to output it in a window. If the two cannot be unified in the program, it must be considered separately. There are two ways to separately consider: First, the screen output and print output work are completed in OnPaint and Onprint, without having to rely on ONDRAW. Second, in OnDraw, we can call PDC_> isprinting () to identify which output work is currently in progress. If you are printing, PDC_> isprinting () returns true. This way we can take the difference in OnDraw. 5.2 Print Page

As we told the printout, a very special place is that it is paged this. The content to be output is arranged on a different page. This way, when we have more than one page to be displayed, we must consider paging. To calculate where which is displayed, you must change it to the next page. This type of splitting calculation has certain troubles, we will discuss the examples given later. Now, it will be explained here that every call of OnPrint corresponds to print a page. Onprint (CDC * PDC, CPRINTINFO * PINFO) contains some information about pages we are interested in. The CPrintinfo type object has a public member property of M_NCurPage, which tells us which page is currently printing. We will apparently use it when calculating the page.

The application framework calls OnPreParedc (CDC * PDC, CPRINTINFO * PINFO) this virtual function before each call onprint printing a page. This virtual function will be called before each screen output is allowed to do some settings. In the latter case, the second parameter PINFO is equal to NULL. When printing, we can do some settings for some of the device contexts for a page. At the same time, there is another important setting, we can set the end of the print job, that is, tell the application framework, all the pages have been printed, the print can be over. This is done by setting the public member attribute of PINFO to False. After doing this, the application framework will not call Onprint to end the print job.

5.3 The beginning of printing work and the end

As we discussed for each page, we discussed the preparation of each page, and after each print task, the application framework also allows us to do some settings. At the beginning of each print job, the application will jump out of a print dialog as shown in Figure 3.13.

Application Frames calls OnPrePareprinting (CPRINTINFO * PINFO) before jumping out of this dialog, we can set the biggest minimum page in the dialog box by calling the Pinfo's SetMaxPage and SetMINPAGE.

ONBEGINPRINTING will be called after closing this dialog.

Once the print job is over, OneendPrinting will be called.

Figure 3.13

5.4 Print Program Instance

Here, we have made an example of a print function. It draws all records from a student information database, then appears in a CScrollView, when the user wants to print out, print these records in each page, print these records. This example uses DAO to access the database, which has been introduced in the previous chapter of this book, readers can review it first, in this chapter we do not explain the corresponding statement in detail. In this example, let's use AppWizard to generate an application framework. Note that the base class of CPRINTVIEW from CVIEW is changed from CView in the sixth step of the generation.

Figure 3.14

CscrollView, as shown in Figure 3.14.

In this example, we consider printing and displaying the output, that is, printed in OnPrint, consider displaying the output in OnPaint. And don't do anything on ONDRAW.

In CPrintView, we add a virtual function: onprepareprinting, its code is as follows: BOOL CPRINTVIEW :: OnPrepareprinting (CPrintInfo * Pinfo)

{

// Default preparation

PINFO_> SetMaxPage ((Recnumber 4) / 5);

Return doprepareprinting (pinfo);

}

This in which PINFO_> SETMAXPAGE ((RecNumber 4) / 5) is used to set the maximum number of pages of print. RecNumber is the number of records calculated by accessing the database. We have said before, every five records are recorded, (Recnumber 4) / 5 can get the number of pages.

Below is the code in OnBeginPrinting

m_bprintend = false;

SturecSet_> MoveFirst ();

IF (sturecset_> iesof ())

m_bprintend = true;

M_bprintend is a member we add to the CPRINTVIEW class to indicate whether to end the printed member.

Void CprintView :: OnPreparedc (CDC * PDC, CPrintInfo * Pinfo)

{

CscrollView :: onpreparedc (PDC, PINFO);

// Todo: Add Your Specialized Code Here and / or Call The Base Class

IF (Pinfo! = NULL)

PINFO_> M_BCONTINUEPRINTINTING =! m_bprintend;

}

The above is the code in the virtual function onpreparedc, pay attention to the judgment of if (pinfo! = Null), we have to identify whether it is preparing for printing.

Here is the most important code in Onprint:

Void CprintView :: OnPrint (CDC * PDC, CPrintInfo * Pinfo)

{

// Todo: add your specialized code here and / or

// Call the base class

INT CURPAGE = PINFO_> M_NCURPAGE;

SturecSet_> setabsoluteposition (CURPAGE_1) * 5);

// Assume to Print 5 Records Every Page

TextMetric TM;

Int ncolumnwidth [4];

INT I, J;

PDC_> SetMapMode (mm_twips);

PDC_> GetTextMetrics (& TM);

NHEIGHT = TM.TMHEIGHT TM.TMEXTERNALLEADING;

For (i = 0; i <4; i ) ncolumnwidth [i] = (pdc_> gettextextent (columnname [i])). cx;

Rect R;

R.right = r.left = 720;

R.TOP = _720;

R.BOTTOM = (R.TOP_NHEIGHT);

// print the colorn headers

For (i = 0; i <4; i )

{

R.right = r.left ncolumnwidth [i];

PDC_> EXTTEXTOUT (R.LEFT, R.TOP, ETO_CLIPPED,

& r, columnname [i], null;

R.LEFT = R.right;

}

R.TOP_ = NHEIGHT;

R.BOTTOM_ = NHEIGHT;

// Print Next 20 Student Records

For (j = 0; j <5; j )

{

R.right = r.left = 720;

For (i = 0; i <4; i )

{

R.right = r.left ncolumnwidth [i];

PDC_> ExtTextout (R.LEFT, R.TOP, ETO_CLIPPED, & R,

CString (V_BSTRT (& (SturecSet_> GetFieldValue (i))),

NULL);

R.LEFT = R.right;

}

// set for next record printing

R.TOP_ = NHEIGHT;

R.BOTTOM_ = NHEIGHT;

SturecSet_> MoveNext ();

IF (sturecset_> iesof ())

{

m_bprintend = true;

Break;

}

}

CscrollView :: OnPrint (PDC, PINFO);

}

PDC_> SetMapMode (mm_twips);

PDC_> GetTextMetrics (& TM);

NHEIGHT = TM.TMHEIGHT TM.TMEXTERNALLEADING;

The role of these sentences is to set the output mapping mode, then obtain some parameters related to the text output so that the output is performed later.

// print the colorn headers

For (i = 0; i <4; i )

{

R.right = r.left ncolumnwidth [i];

PDC_> EXTTEXTOUT (R.LEFT, R.TOP, ETO_CLIPPED,

& r, columnname [i], null;

R.LEFT = R.right;

}

These sentences are printed on each page to record the names of each domain so that each record is output below.

Next, it should be the output of five records (if there are five words), it is included in the loop in FOR (J = 0; J <5; J ).

For (i = 0; i <4; i )

{

R.right = r.left ncolumnwidth [i];

PDC_> ExtTextout (r.left, r.top,

Eto_Clipped, & R,

CString (V_BSTRT (& (StureCset_> GetFieldValue (i)))))))), NULL);

R.LEFT = R.right;

}

This FOR loop is embedded in front of the cycle, it is responsible for outputting each domain of a record in a certain line. SturecSet_> MoveNext ();

IF (sturecset_> iesof ())

{

m_bprintend = true;

Break;

}

Then move to the next record of the database, and determine if the last record has been reached, if it is jumped out, and the m_bprintend is true so that the next time the print can be correctly ended.

In this example we give, there is still a lot of consideration, especially in the calculation of the page, and we simply specify each five records, and a real utility is definitely the size of the paper. (This can be performed by the CDC class getDeviceCaps) and then calculate how many records can be output on one page.

Fourth, VC program debugging

During the development program, you often need to find errors in the program, which requires the debugging tool to help you make the program debugging, of course, there are many debugging tools, and the debugging tool integrated in the VC is in its powerful features. I must make you love. Let's first introduce the use of debugging tools in VC.

1 VC debugging tool

1.1 Establishment of the debugging environment

Whenever a project is established in the VC, VC will automatically create two versions: release version, and debug version, just as it is said, the Release version is used when the program is completed, ready to issue The version, and the Debug version is used in the version used during development.

Among the Debug version, it contains debugging information in the Microsoft format, not any code optimization, and optimizes the executable binary code in the Release version, but does not contain any debug information.

In the newly established project, you can see the debug version, to select the release version, you can select the setting command in the menu Project, then pop up the Project SetTeing dialog box, select Release in the Setting for drop-down list, press OK exits, as shown in Figure 4.1.

Figure 4.1

You must use the Debug version when debugging the program, we can set the debug options in the C / C page of the Project Setting dialog.

Figure 4.2

The meaning of each option is as follows:

Program Database indicates a data file (.pdb) that generates a storage program information, which contains type information and symbolic debugging information;

Line NumBers Only indicates that the program is generated and the link is generated .Obj or .exe file only contains global and external symbols and line number information;

C7 compatible represents a .Obj or .exe file line number information and symbolized debugging information;

None indicates that no debugging information is generated.

1.2 General process of debugging

Debugging, saying that is the state of a certain phase of the program's running process, and in general, the program is running continuously, so we must stop the program at a certain location. So the first job we do is to set up breakpoints. Second, the program is running, and when the program stops at the setup breakpoint, the status of various tool observation procedures is used. After the program stopped, sometimes we need to operate in our request to control the procedure to further observe the flow direction of the program, so we will introduce the setup of the breakpoint, how to control the operation of the program and the use of various observation tools. .

1.3 How to set breakpoints

In VC, you can set multiple types of breakpoints, we can divide these breakpoints into three categories according to the way of breakpoints: 1. Diffishes related to location; 2. Diffishes related to logical conditions 3. Let's introduce these three types of breakpoints in the breakpoint related to Windows Message. First we introduce the breakpoints related to the location.

The simplest is to set a general location breakpoint, you only need to move the cursor to the location you want to set up, this line must contain a valid statement; then press the Add / Remove BreakPoint button on the toolbar or press shortcut F9 At this time, you will see a red dot in the left side of this line indicating that this is set up a breakpoint.

Figure 4.3

2, sometimes you may not need a program to stop every time it is running here, but stop in the case of satisfying a certain condition, then you need to set a logical breakpoint related to location. To set this breakpoint, we only need to select the BREAKPOINT command from the EDIT menu, and the BreakPoint dialog will appear on the screen. Select the Location tab in the BreakPoint dialog, make the Location page pops up, as shown in Figure 4.4

Figure 4.4

Click the Condition button, pop up the BreakPoint dialog box, write your logical expression in the Expression editing box, such as x> = 3 or A B> 25, and finally press OK.

Figure 4.5

This breakpoint is mainly due to its position, but it also combines logical conditions to make it more flexible.

3. Sometimes we need more deeper debugging procedures, we need to enter the program's assembly code, so we need to set up breakpoints on the assembly code: To set up this breakpoint, we only need to select the debug window command from the View menu.

Figure 4.6

Then select the disassembly subcommand, and the assembly window will appear on the screen.

Figure 4.7

In the assembly window in Figure 4.7, you will see the assembly code corresponding to the source program, where the source program is displayed with the black body, and the following is the assembly code. To set up breakpoints, we only need to move the cursor to the INSERT / REMOVE BREAKPOINTS button on the toolbar, then you will see a red dot appears on the right side of the assembly code.

Figure 4.8

The breakpoint described above is mainly due to its position, that is, the program will stop when the program runs to the setup breakpoint. But sometimes we set up a breakpoint related to the logical conditions, and the location is independent. So here is described below with a breakpoint related to logical conditions.

(1) The setting of the logical condition triggers breakpoint:

Select the BreakPoint command from the Edit menu, and the BREAKPOINT dialog will appear on the screen.

Figure 4.9

Select the DATA tab in the BreakPoint dialog, the corresponding page will pop up

Figure 4.10

Write your logical expression in the Expression editing box in the DATA page of Figure 4.10, such as (x == 3);

Figure 4.11

Finally, press OK.

The methods of setting other breakpoints are similar. Let us explain one by one.

(2) Monitoring expressions changing breakpoints:

Select the BreakPoint command from the Edit menu, and the BREAKPOINT dialog will appear on the screen.

Select the DATA tab in the BreakPoint dialog, the corresponding page will pop up

Writing in the Expression Edit box You need to monitor the expression to finally press the OK button.

(3) Monitor the breakpoints of changes in arrays:

Select the BreakPoint command from the Edit menu, and the BREAKPOINT dialog will appear on the screen.

Select the DATA tab in the BreakPoint dialog, the corresponding page will pop up

Write you need to monitor the number of group names in the Expression Edit box; enter the number of you need to monitor the number of array elements in the Number of Elements; press the OK button. (4) Monitor the breakpoint that changes from the array pointed to by the pointer:

Select the BREAKPOINT command from the EDIT menu, and the BREAKPOINT dialog will appear on the screen. Select the DATA tab in the BreakPoint dialog; enter the shape in the Expression edit box, where * pointname is the pointer variable name; enter the number of you need to monitor array elements in the Number of Elements Edit box; press the OK button.

(5) Monitor the breakpoints of changes in external variables:

Select the BreakPoint command from the EDIT menu, the BreakPoint dialog will appear on the screen; select the DATA tab in the BreakPoint dialog; enter the variable name in the Expression Edit box; click the drop button on the right side of the Expression edit box; choose Advanced Option, then the Advanced BreakPoint dialog box appears; enter the corresponding function name and (if needed) in the Context box; press the OK button to close the Advanced BreakPoint dialog. Press the OK button to close the BreakPoints dialog.

(6) Let's talk about the breakpoint related to Windows messages after the location breakpoint and logical breakpoint.

Note: This type of breakpoint can only work on the X86 or Pentium system.

Select the BREAKPOINT command from the EDIT menu, and the BreakPoint dialog will appear on the screen;

Select the Message tab in the BreakPoint dialog, the corresponding page will pop up; enter the name of the Windows function in the Break At WndProc Edit box; select the corresponding message in the Set One Breakpoint from Each Message to Watch drop-down list box; press OK Back .

1.4 Control program operation

Above we talked about how to set various breakpoints, let's describe how to control the operation of the program. When we start running from the menu build to submenu Start debuging, start running in the debug state, the program will stop from the breakpoint, you can see there is a small arrow, which pointing to the upcoming code.

Figure 4.12

Subsequently, we can control the operations of the program as required: four commands: Step over, Step Into, Step Out, Run to Cursor.

Figure 4.13

In Figure 4.13:

The function of Step over is the code that runs the current arrow (only one code running).

The function of Step Into is that if the code referred to in the current arrow is a function of a function, use Step INTO to enter the function.

The function of Step Out is that the code pointed to by the current arrow is in a certain function, and it is used to run the program to the function.

The function of Run to Cursor is to make the program run to the code referred to in the cursor.

1.5 Viewing the use of tools

The most important thing during the debugging process is to observe the status of the program in the running process so that we can find out the error of the program. The state mentioned here includes the value of each variable, the value in the registration, the value in the memory, the value in the stack, to this we need to use a variety of tools to help us to view the status of the program.

Pop-up debugging information bubble (DATA TIPS POP_UP INFORMATION).

When the program stops in the breakpoint, the easiest way to observe the value of a variable or expression is to use debug information bubble. To see a value of a variable, just put the mouse on the source window, you will see an information bubble, which shows the value of the variable. Figure 4.14

To view the value of an expression, first select the expression, then place the mouse to select the selected expression, you will also see an information bubble pop-up to display the value of the expression, as shown in Figure 4.15.

Figure 4.15

Variable window.

On the View menu, Debug Window selection VARIABLES WINDOW; the variable window will appear on the screen. The variable name and its corresponding value are shown. You will see three tags in the lower part of the variable watch: Auto, Local, this selected different tags, and different types of variables will appear in this window.

Figure 4.16

Watch Window:

On the View menu, select the debug window command, Watch window subcommand. At this time, the variable window will appear on the screen.

Figure 4.17

Double-click a space line of the Name column in the observation window of Figure 4.17, and enter the variable name or expression you want to view.

Figure 4.18

You will see the corresponding value after the return service. The observation window can have multiple pages, respectively correspond to label Watch1, Watch2, Watch3, etc. If the expression you entered is a structure or an object, you can use the mouse point to take the shape of the right side of the expression such as to further observe the value of the member variables, as shown in Figure 4.19.

Figure 4.19

Quick View Variable Division (Quick Watch);

In the Quick View Variables dialog, you can view the values ​​of the variable or expression like the use of the viewing window. But we can also use it to change the variables during the run, the specific operation is as follows:

In the Debug menu, select the Quick Watch command, and the Quick Watch dialog will appear on the screen;

Figure 4.20

Enter a variable name in the Expression editing box, press Enter;

Figure 4.21

(3) The variable name and its current correspondence in the Current Value lattice are shown in Figure 4.22: Figure 4.22

(4) To change the value of this variable, simply double-click the NAME column corresponding to the variable, enter the value you want to change;

(5) To add this variable to the observation window, click the Add Watch button;

(6) Click the CLOSE button to return;

We can also directly view values ​​in memory

(1) Select the debug windows and memory subcommands from the View menu. Memory Window appeared;

Figure 4.23

(2) Enter the memory address you want to view in the Address Editing box and enter the bus. The value in the corresponding memory address will be displayed in the window of the Memory Window.

Figure 4.24

During the debugging process, sometimes we need to view the values ​​in the registers. We only need:

(1) Select the Debug Window and Registers sub-options from the View menu. The Registers window appears. In the Registers window, the information is displayed in the form of register = value, where the register represents the name of the register, VALUE represents the value in the register.

Figure 4.25

(2) If you want to modify the value of a register, use the TAB key, or the mouse to move the cursor to the right of the value you want to change, then enter the value you want. Enter back.

In the register, there is a class of special registers called a flag register, with eight flags: OV is overflow flag;

Up is the direction sign;

EI is an interrupt enable flag;

Sign is symbolic,

ZERO is zero sign.

Parity is a parity logo.

Carry is a carry mark.

2 Advanced Debug Technology

As we talked about the use of debugging tools, we can use it to conduct conventional debugging, even if the program stops at some place, then observe the current factor of the program. And these tools are also in its debugger. But we know that we know that these tools are not enough during the development of the VC program. In order to develop programs faster, we also need to take advantage of the more advanced debugging tools. We know that during the use of VC development, we will greatly facilitate application development, so developers often use MFC to develop applications, which is this reason for Microsoft offers some features in MFC to help you. Commissioning for programs.

We know that most classes are inherited from a class called COBJECT, although this is a virtual base class, but it defines many member functions, where many member functions are used to support programs. , Such as dump, assertvalid, etc. member functions. In addition, they all support macros such as Trace, Assert, and support memory vulnerabilities. We know that in order to support debugging, class libraries are definitely losses in performance, providing two different versions of the Category Library: Win32 Debug version and Win32 Release version. In the previous we have mentioned that whenever we build a project, we also have the corresponding two versions. In your debug version of the project, the compiler is connected to the Debug version of the MFC class; the compiler is connected to the Release version of the RELESE version of the MFC class library to get as fast as possible. Let's introduce the use of these tools.

2.1 Trace Macro

The Trace Macro is a bit like the Printf function we used in the C language so that the program outputs some debugging information during the run, so that we can understand some of the states. But a little difference is that the Trace macro only has output in the debug state, and the previously used Printf function has output in any case. Like the Printf function, the Trace function can accept multiple parameters such as:

INT x = 1;

INT Y = 16;

Float z = 32.0;

Trace ("This Is A TRACE STATEMENT / N");

TRACE ("The Value of X IS% D / N", X);

Trace ("x =% D and Y =% D / N", X, Y);

Trace ("x =% D and Y =% x and y, z);

Note that Trace macros only works on the project of the Debug version, in the RELEASE version of the project, the Trace Macro will be ignored.

2.2 Utilization of Assert Macro

In the development process we can suppose that one condition is certainly established as long as the program is running correctly. If it is not established, then we can assert the program to have failed. In this case we can use Assert to set the assertion. The parameter of the Assert Macro is a logical expression. During the program running, if the logical expression is true, no action will occur. If this expression is a false, the system will pop up a dialog warn you and stop the program. Execution. Also ask you to make a choice: Abort, Ignore, Retry. If you select Abort, the system will stop the execution of the program; if you choose the Ignore system to ignore the error, continue the program; if you select Retry, the system will recalculate the expression and activate the debugger. Like the TRACE macro, the Assert Macro only works in the Debug version, and the Assert Macro will be ignored in the Release version. 2.3 ASSERT_VALID Macro Utilization and Overload of the Assertvalid () member letter

Assert_Valid macro is used to check an internal legitimacy of an object at runtime, such as now there is a student object, we know that each student is more than zero, if the age is less than zero, the student object must have a problem. In fact, the Assert_Valid macro is a call to the member function assertvalid () of the converted to the object, but this method is safer. Its parameters are an object pointer that calls its assertvalid () member function via this pointer.

With this match, whenever we create a new class from the COBJECT class, we can overload the member function to perform a specific legitimacy check.

2.4 Utilization of DUMP functions of the object

The DUMP function is used to output an object's member variable in the specified format to help you diagnose an internal condition of an object. Like the AssertValid member function, DUMP is also a member function of the COBJECT class. The parameter of the dump function is a CDumpContext object that you can enter data in this object like this. When you create a new category that COBJECT inherits, you can reload your own DUMP function as follows:

(1) Call the DUMP function of the base class to output the content of the base class;

(2) Output the data of this class to the CDumpContest object.

For example, a typical DUMP function is defined as follows:

#ifdef _Debug

Void CPERSON :: Dump (CDumpContext & DC) Const

{

// Call Base Class Function First

COBJECT :: DUMP (DC);

// now do the stuff for u f c c c

DC << "Last Name:" << m_lastname << "/ n"

<< "" first name: "<< m_firstname <<" / n ";

}

#ENDIF

You may have noticed that the definition of the entire function is included in #IFDEF_Debug and #ENDIF, which makes the Dump member function only acts in the Debug version, and does not work for the Release version.

3 memory vulnerabilities

Maybe you already know that in the C and C language pointer questions is a headache, if you apply for memory, but not release, and your program needs to run for a long time, then system The resource will gradually decrease. When the resources of the system are all used, the system will crash. Therefore, in the development process, you must ensure complete release of resources. Let's introduce the inspection of memory vulnerabilities. Maybe you will ask, how does the system support the inspection of memory vulnerabilities? In fact, all the functions of memory allocation in your debug version are overloaded. The specific process is like this. When your program applies for memory, it first calls a general memory allocation function to allocate a slightly large memory. Piece. Divided into four small pieces in this memory block: Heap Information, Buffer, User Memory Block, Buffer. The first block is information about the heap, for example, the location of the memory (file name, line number) is applied, and the type of memory block (such as an integer, floating point, or some type of object), etc. The second block is a buffer for intercepting the user's application of memory usage. The third piece is true to the memory of the user, and the pointer returned is also pointing here. The fourth block is also a buffer, the same as the second block.

When your application is recorded, it is easier to check that the memory vulnerability is easier, roughly, if you want to check if there is a memory vulnerability, you only need to start the system in this block. For you to make a memory usage, record the memory usage at the beginning of the program, and then make the system to make a memory image for you at the end of the program segment, compare the image, to check if there is no release Memory, if there is unsealed memory, according to the information about the allocation situation, the memory is not released there.

Specifically, the following steps are required to check the memory vulnerability:

Create a cMemoryState object at the beginning of the program you detected, call its member function Checkpoint to get the snapshot of the current memory usage; build a cMemoryState object at the end of the program segment you detected, call its member function Checkpoint, to obtain a snapshot of current memory usage; then establish a third CMEMORYSTATE object, call its member function DIFCERENCE, use the first CMEMORYSTATE object and the second CMEMEORYSTATE object as its parameters. If the memory is different, the memory is different. The function returns non-zero, indicating that there is a memory vulnerability in this block. Let's take a typical example:

// Declare the variables needed

#ifdef _Debug

CMemoryState OldMemState, NewMemState, DiffMemState

OldMemState.checkpoint ();

#ENDIF

// do your memory allocations and deallocations ...

CString s = "this is a frame variable";

// the next object is a heap object

CPERSON * P = New CPERSON ("Smith", "ALAN", "581_0215");

#ifdef _Debug

NEWMEMSTATE.CHECKPOINT ();

IF (DiffMemState.diference (OldMemState, NewMemState))

{

Trace ("Memory Leaked! / N");

}

#ENDIF

Five Visual C and multimedia For general applications, Visual C can be said to be included, but unfortunately, have almost have heard of Visual C to provide multimedia support, and even some people say that Visual C is not suitable for multimedia programming . If we completely use the Visual C class library without wanting a trick, I am afraid that even the most simple RPG game can be coded. For a multimedia application that requires a lot of animation, the sound, Visual C provides a housing, and has a good voice, the task of the animation engine, has fallen to the programmer.

In the following chapters, you will introduce you how to develop this engine.

1 handling of sound

1.1 Media Control Interface

MCI (Media Control Interface Media Control) is a standard interface for a set of multimedia devices and files provided by mircrosoft. It is convenient to control most of the multimedia devices include multimedia devices such as audio, video, videos, video records, not Need to know their internal operating conditions. But the ancients said: It is also Xiao He, and it is also Xiao. Although MCI looks high, it is far less than some advanced applications. It is better than Visual C , but it is necessary to develop multimedia engines. For the MCI instruction set, we will only introduce, focus on the latter waveform filters.

MCI control method:

Generally speaking, programmers can use two functions to deal with MCI:

MCIROR MCISENDCOMMAND (McIDeviceID WDEviceID, UINT UMSG,

DWORD DWFLAGS, DWORD DWPARAM;

Command string mode, send control commands with close to daily life, suitable for advanced programming such as VB, Toolbook, etc.

McIrror McISendstring (LPTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTR LPSZRETURNSTR

ING, UINT CCHRETURN, HANDLE HWNDCALLBACK

);

Command message, use professional syntax to send control messages, suitable for language programming such as VC, which is directly derived from the MCI device.

For MCISendCommand, the first parameter specifies the device ID, which is provided by the system when the programmer opens the MCI device. The second parameter specifies how to control the device, please refer to the following "MCI Directive" column. The third parameter is an access identity, and the fourth parameter is generally a data structure, identifying some of the information when accessing MCI. For more information, please refer to the CD.

For McISendString, the first parameter is a string control string, the return information is filled in the second parameter by the system, and the third parameter indicates the maximum length of the return information. If the "Notify" flag is set to the MCI device, it is required. The fourth parameter fills the return window handle.

Example:

MCISENDCOMMAND (DeviceID, MCI_close, null, null); // Turns off an MCI device;

McIndstring ("Open Aaa.avi", 0, 0, 0); // Open the file "aaa.avi";

MCI's device type:

MCI's device types are:

DESCRIPTION MCI_ALL_DEVICE_ID device description string description of all audio devices MCI_DEVTYPE_ANIMATIONAnimation animation apparatus MCI_DEVTYPE_CD_AUDIOCdaudioCD MCI_DEVTYPE_DIGITAL_VIDEODigitalvideo MCI_DEVTYPE_DATDat digital audio digital video apparatus defined MCI_DEVTYPE_OTHEROther MCI_DEVTYPE_OVERLAYOverlay superimposed video MCI_DEVTYPE_SCANNERScanner scanner MCI_DEVTYPE_SEQUENCERSequencer MIDI sequencer MCI_DEVTYPE_VCRVcr fit laser disc recorder MCI_DEVTYPE_VIDEODISCVideodisc MCI_DEVTYPE_WAVEFORM_AUDIOwaveaudio Wave audio MCI is not defined above for Devices, users can view the [MCI] section of the System.ini file, for example:

[mci]

CDAUDIO = MCICDA.DRV

SEQUENCER = MCISEQ.DRV

Waveaudio = mciwave.drv

Avivideo = mciavi.drv

VideoDisc = MCIPIONR.DRV

Vcr = mcivisca.drv

ActiveMovie = mciqtz.drv

Qtwvideo = mciqtw.drv

MPEGVIDEO = C: /Progra ~ 1/xing/xingmp ~1/xmdrv95.dll

The last two sentences indicate the Apple's QuickTime device, and the device is named "QTWVIDIO", the MPEG image device, and the device is named "MPEGVIDEO".

In MCI programming, it is possible to describe the device name, or the character string as a device name, an extreme lazy method is that the programmer does not specify the device name in the program, and Windows will automatically recognize the device type according to the file extension. .

For example, open a multimedia file has the following three ways:

[1]: Automatic identification: Open a "WAV" file

MCI_open_parms mciopen;

Mciopen.lpstrDeviceType = 0;

Mciopen.lpstreamentname = "aaa.wav";

MCISENDCOMMAND (NULL, MCI_Open, MCI_Open_Element,

(DWORD) & mciopen;

[2]: Specify device description: Open CD player

MCI_open_parms mciopen;

Mciopen.lpstrDeviceType = (LPSTR) MCI_DEVTYPE_CD_AUDIO;

MCISENDCOMMAND (NULL, MCI_Open, MCI_Open_Type | MCI_Open_Type_ID,

(DWORD) & mciopen;

[3]: Specify a description string: Open an AVI file

MCI_open_parms mciopen;

Mciopen.lpstrDeviceType = "avivideo";

Mciopen.lpstreamentname = "aaa.avi";

MCISENDCOMMAND (NULL, MCI_Open, MCI_Open_Type | MCI_Open_Element,

(DWORD) & mciopen;

Note that in three open modes, the difference between the third parameter, which will be taken later.

MCI command

MCI uses the following instructions:

MCI_break Settings the interrupt key, the default is "Ctrl Break" MCI_capture grabs the current frame and store the specified file, only for digital video MCI_close Close Device MCI_Configure pop-up configuration dialog, only for digital video MCI_copy copies data to clipboard MCI_cue Delayed Play or Recording MCI_cut Delete Data MCI_Delete Delete Data MCI_ESCAPE Only for Laser Video MCI_Freeze Get Display Fixed MCI_GETDEVCAPS Get Device Information MCI_Index Current Screen Display Or No, only for VCR Device MCI_INFO Get String Information MCI_List Gets the number of input devices, support numbers Video and VCR device MCI_LOAD is loaded into a file MCI_mark cancels or makes a mark, cancels or makes a mark with MCI_seek MCI_Mark, and MCI_Seek supporting MCI_Monitor for digital video specifying reporting device MCI_open Open Device MCI_PASTE Paste MCI_PAUS Pause Current Action MCI_Play Play MCI_PUT setting source and destination, defines a rectangular frame device in the default quality MCI_QUALITY MCI_RECORD start recording MCI_RESERVE allocated disk space MCI_RESTORE bmp file to a copy of the frame buffer to make a suspension device MCI_RESUME restart MCI_SAVE data stored media position changes MCI_SEEK MCI_SET MCI_SETAUDIO information setting device to set the volume MCI_SETTIMECODE To activate or deactivate the device VCR VCR device set time code MCI_SETTUNER channel MCI_SETVIDEO set video parameter settings specify MCI_SIGNAL space on the workspace MCI_STATUS to obtain device information MCI_STEP the playback device skipping MCI_STOP stop playing MCI_SYSINFO return to MCI device information MCI_UNDO cancel the operation MCI_UNFREEZE make use MCI_UNFREE ZE video buffer recovery motion MCI_UPDATE Update Display Area MCI_where Get Device Cut Rate McI_Window Specifies Graphics Equipment Window and Window Features Where Comparable Instructions are MCI_Open, MCI_Close, MCISE, MCI_Status, and more.

Case Analysis

Take New on the Visual C 5.0 menu, click Projects, select the MFC AppWizard (EXE), create a new project file called "mcitest", OK is determined.

Note Select "Dialog Based" in the application type, then Finish is complete. This is a dialog-based application. In order to complete the MCI test task, we have to change the dialog resource. Take "Resource View" and select the "IDD_MCITEST_DIALOG" dialog box under Dialog, and then add Button as shown.

Complete the modification of the dialog. Right-click McITest Files, select Add Files To Project, join the "CommCI.cpp" and "CommCI.h" files provided in the supporting CD. Open ClassWizard, select CMCITestDLG under Class Name, join all button message processing functions.

In the "cmcitestdlg" class, the three member variables of WAV, MIDI, AVI are defined separately, and write the corresponding processing function open (), Play (), Close (), PLAY (), STOP (). In the Projoct menu, click Setting, pop up the Settings dialog box, add "Object / Library Modules" under "Link", add "WinMM.Lib", compile and run the program:

Figure 5.1

Source program introduction

// Commci.h: Interface for the commit.

//

//

#if! defined (AFX_COMMCI_H__90CEFD04_CC96_11D1_94F8_0000B431BBA1__INCLUDED_)

#define AFX_COMMCI_H__90CEFD04_CC96_11D1_94F8_0000B431BBA1__INCLUDED_

#iF _MSC_VER> = 1000

#pragma overce

#ENDIF / / _MSC_VER> = 1000

/ / # include

#include

Class Commmci

{

Private:

HWND HOWER; // owner of the window

MCI_open_parms mciopen;

PUBLIC:

COMMCI ();

~ Commci () {close ();

McIrror Open (LPCSTR DEVICETYPE, LPCSTR FileName);

// Open the device by describing strings

McIrror Open (int devicetype, lpcstr filename); // Open the device via device type

McIrror Open (LPCSTR FileName); // Automatic detection device

Void Play (hwnd hwnd); // Play MCI, hwnd is a callback window handle

Void Close (void); // Close device

Void stop (void); // Stop device

Void Pause (void); // Pause equipment

DWord query (); // detection device

}

/

// use the structure used in Commci.cpp

/

/// typef struct tagmci_open_parms {

// DWORD dwcallback;

// mcideviceid wdeviceID;

// Word WRESERVED0;

// lpcstr lpstrDeviceType;

// lpcstr lpstreamentname;

// LPCSTR LPSTRALIAS;

//} MCI_open_parms, FAR * LPMCI_Open_PARMS;

// typedef struct tagmci_play_parms {

// DWORD dwcallback;

// DWORD DWFROM;

// DWORD DWTO;

//} MCI_Play_Parms, * PMCI_Play_PARMS, FAR * LPMCI_PLAY_PARMS;

//. TypedEf struct tagmci_status_parms {

// DWORD dwcallback;

// DWORD dwreturn;

// DWORD DWITEM;

// DWORD DWTRACK;

//} MCI_STATUS_PARMS, * PMCI_STATUS_PARMS,

Far * lpmci_status_parms; //

// mci initialization method

//

//Commci.open ("waveaudio "; Wave; * .wav,

//Commci.open ("sequence "; MIDI; * .mid, * .rmi

//Commci.open ("reelmagic" ,filename); vcd; * .mpg,

//Commci.open ("Avivideo ", AVI; * .avi,

/

// MCI status return value

/

// Case MCI_Mode_not_ready:

// Case MCI_Mode_Stop:

// Case MCI_Mode_play:

// Case MCI_Mode_Record:

// Case MCI_Mode_seek:

// Case MCI_Mode_Pause:

// Case MCI_Mode_Open:

#ENDIF / /! Defined (AFX_COMMCI_H__90CEFD04_CC96_11D1_94F8_0000B431BBA1__INCLUDED_)

// Commci.cpp: Implementation of the commci class.

//

//

#include "stdafx.h"

/ / # include "mcitest.h"

#include "common"

#ifdef _Debug

#undef this_file

Static char this_file [] = __ file__;

#define new debug_new

#ENDIF

//

// construction / destruction

//

CommCI :: Commmci ()

{

MEMSET (this, 0, sizeof (commci));

}

McIrror Commmci :: Open (LPCSTR DeviceType, LPCSTR FileName)

{

// If there is an open device, turn it off

IF (mciopen.wdeviceid) close ();

// Initialize the MCI_Open_Parms structure

Mciopen.lpstrDeviceType = DeviceType;

Mciopen.lpstreamentname = filename;

/ / In addition to opening the device code is 0, any MCISENDCOMMAND statement below is specified

// 备.

IF (McISendCommand (NULL, MCI_Open,

MCI_open_type | mci_open_element,

(DWORD) & mciopen))

Return False;

Return True;

}

McIrror Commci :: Open (LPCSTR FileName)

{

IF (mciopen.wdeviceid) close ();

Mciopen.lpstreamentname = filename;

IF (McISendCommand (NULL, MCI_Open,

/ * Mci_open_type | * / mci_open_element,

(DWORD) & mciopen))

Return False;

Return True;

}

McIrror Commci :: Open (int Devicetype, LPCSTR Filename)

{

IF (mciopen.wdeviceid) close ();

Mciopen.lpstrDeviceType = (LPCSTR) DeviceType;

Mciopen.lpstreamentname = filename;

Return McISendCommand (NULL, MCI_Open, MCI_Open_Type | MCI_Open_Type_ID, (DWORD) & mciopen;

}

Void Commci :: Play (HWND HWND)

{

MCI_Play_Parms McIPlay;

HOWER = hWnd; // Toning window handle

// mci_play_parms structure only needs to set a callback window handle

McIPlay.dwcallback = (Word) HOWER;

MCIOpen.wdeviceID, MCI_Play, MCI_notify,

(DWORD) & mcIPlay);

}

Void CommCI :: Close (Void)

{

IF (Mciopen.wdeviceID)

MCIOpen.wdeviceID, MCI_Close, Null, NULL;

MEMSET (this, 0, sizeof (commci));

}

Void CommCI :: Stop (void)

{

IF (Mciopen.wdeviceID)

MCIOpen.wdeviceID, MCI_Stop, NULL, NULL;

}

Void Commmci :: Pause (void)

{

IF (Mciopen.wdeviceID)

McISendCommand (Mciopen.wdeviceID, MCI_pause, null, null);

}

DWORD COMMCI :: query ()

{

MCI_STATUS_PARMS MCISTATUS;

MCISTATUS.DWITEM = MCI_STATUS_MODE;

McIndcommand (Mciopen.wdeviceID, MCI_Status,

MCI_Status_Item, (LPARAM) & mcistatus;

Return mcistatus.dwreturn;

}

For class CommCI defines the following member functions:

A constructor and a destructor.

An open function, its parameters are to open the type and file name of the device.

Play function, its parameter is a callback function handle.

Close the function.

Stop function.

Pause function.

State detection function.

During an MCI process, the following procedures must be used:

Open an MCI device.

Then Open plays the MCI device, which can be suspended and stopped.

Finally close the MCI device.

In any of the above steps, the operating state can be detected by the status detection function.

Let's take a look at the implementation of MCI:

Open MCI

First, we initialize the structure of an MCI_Open_PARMS, where two values ​​are used.

The mciopen.lpStrDeviceType specifies the type of device to open, which can be selected from the previous "MCI device type". Can be identified or descriptated strings, such as statement mciopen.lpstrDeviceType = MCI_DEVTYPEVCR and statement mciopen.lpstrDeviceType = "vcr" is equivalent. If the type is not specified, the computer will automatically identify the device according to the file name, and then mciopen.lpStrelimmentName specifies the file name to open, and finally call McISendComand specifies that the computer will fill in the open device code in the WDEVICEID; after the application will be based later This device code accesses the MCI device.

Talk about the difference between three open modes:

[1]: Automatic identification: Open a "WAV" file

MCI_open_parms mciopen;

Mciopen.lpstrDeviceType = 0;

Mciopen.lpstreamentname = "aaa.wav";

MCISENDCOMMAND (NULL, MCI_Open, MCI_Open_Element,

(DWORD) & mciopen;

[2]: Specify device description: Open CD player

MCI_open_parms mciopen;

Mciopen.lpstrDeviceType = (LPSTR) MCI_DEVTYPE_CD_AUDIO;

MCISENDCOMMAND (NULL, MCI_Open, MCI_Open_Type | MCI_Open_Type_ID,

(DWORD) & mciopen;

[3]: Specify a description string: Open an AVI file

MCI_open_parms mciopen;

Mciopen.lpstrDeviceType = "avivideo";

Mciopen.lpstreamentname = "aaa.avi";

MCISENDCOMMAND (NULL, MCI_Open, MCI_Open_Type

| Mci_open_element,

(DWORD) & mciopen;

Note the difference between the third parameters of the MCISendCommand function:

MCI_open_type: Indicates the LPSTRDIVICETYPE parameters to use the MCI_Open_Parms structure, which distinguishes the difference between the specified device open mode and the automatic recognition method. In an automatic mode, there is no need to use the LPSTRDEVICEPE parameter. Therefore, you do not need to specify MCI_Open_Type.

MCI_open_element: Indicates that the device represents a string in the LPSTRDEVICEPE parameter.

MCI_open_type_id: Indicates that the device description is in the LPSTRDEVICEPE parameter.

2 Playmci:

In the Play function, you need a return window handle so that the application sends a message to this window after playback, telling the window to end. We first initialize a data structure of an MCI_Play_PARMS: assign the dwcallback parameter to the window handle. Then call McISendcommend, of course, the command sent is MCI_Play, tell the system to start playing, and the other third parameter specifies MCI_Notify, telling yourself after playing the system.

Querymci:

To detect the MCI playback state, you must send an MCI_STATUS, and mark the MCI_Status_ Item, and return the value on the dwreturn of MCI_Status_Parms.

Regarding further details of MCI, this section will no longer tell, about the commands used in the MCI, the data structure, please check the book support book.

1.2 waveform mixer

If you are a game enthusiast, I don't know if there is a difference between different game music and sound implementation. The earlier game generally uses MIDI plus a single WAV file, such as "Angel Empire", early "Three Kingdoms", etc., these games generally make MIDI background music. In the event of a person walking, fighting or natural disasters, I use some waveform files to use some waveform files, just the MIDI file is real in the early sound card, and it is unbearable to look at the eyes of a enthusiast. Later, using CD single WAV sound mode, the sound quality has improved significantly, such as "Xianjian Qi Chuan". But because WAV can only play one at the same time, after all, is thin. It's hard to imagine that the two have only one person issued "嘿" sound. Therefore, the multi-wavelength mix has become the mainstream of the game programming. Everyone looks at the "Red Alert", the roar of the tank, the character's cry, the roar of the plane, the tower of the electric tower is soluble with the excellent background music, It is impossible to complain. If you want to compose such a program, you must master the principle of waveform mixing. What is a WAV file:

The WAV file directly reflects a sound value at each time, such as the following waveform:

We take a point at 0.1 seconds per person, the value of the WAV file is 0, 1, 1, -1, 0, 1. Therefore, if we can add the data of many WAV files directly, you can hear all the sound, this is the principle of the mixer.

Let's analyze the WAV file structure:

We can open a WAV file directly to see its binary code:

C: /user/wave/22.wav

00000000 5249 4646 9CB6 1E00 5741 5645 666D 7420

00000010 1000 0000 0100 0200 2256 0000 44ac 0000

00000020 0200 0800 6461 7461 78B6 1E00 7F7F 7F7F

00000030.7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f

00000040.7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f

00000050.7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f

00000060.7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f

00000070.7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f

00000080.7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f

00000090.7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f

000000a0.7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f

You can see that the WAV file storage format is as follows:

"Riff"

×××× file size

"Wave"

"fmt"

×××× pcmwawformat - Data Structure Size

××××

...... Data structure "pcmwaveformat"

××××

Data

×××× data size

: Data

The first is a string "Riff", indicating that this file follows a standard format named "Resource Intercharge Format). The back is tight with the four bytes to specify the file size. Second, the string "Wave" and "FMT", followed by a structure called "PCMWAVEFORMAT", and finally the string "data", keeping up with data size and all data. The PIFF file is a tree structure. The basic components are "block", and in Figure 5.2 is a "block" relationship in the WAV file.

Figure 5.2

As shown, the WAV file structure is two layers, consisting of parent block "Riff" and two sub-block "FMT", "DATA". The "FMT" block contains WAV file format information, "DATA" block contains data information. 2 multimedia file I / O

Multimedia file I / O is similar to normal file I / O, but supports multimedia "Riff" format and provides buffer and non-buffer file I / O.

All multimedia file I / O function names are MMIO, and the message is prefixed for MMIO.

Low-level waveform audio function:

Low-level audio services allow users to deal directly with the audio device driver, directly control audio devices such as waveforms, MIDI playback and recording, low-level audio functions are unrelated interfaces.

The low-level audio function prefix is ​​Wave, press the input function, and the output function is divided into Wavein ×××× and Waveout ××××.

The playback process of waveform audio.

First, we want to call multimedia file I / O functions MMIO ×××× (), and generate the structure and data required in WAVE playback according to multimedia file I / O, and use these structures and data for Waveout ×××× () Function playback. The user can tamper with the WAVE file and "FMT" block according to the needs of encryption, and only the data block is retained. Or compress it, you can still have a data file in memory as long as you play back. And remember the file audio format and size, you can play up the audio.

Common MMIO functions and implementation process:

MmiOopen () Opens a Riff file

MmioDescend () enters block

Mmioread (); this RIFF file

Mmioascend (); jumping out

Mmioclose (); Turn off PIFF file

For blocks, entering blocks and jumping blocks are paired.

Read the read process of the WAV file:

MmioPen () Opens the file

MmioDescend ("Wave") enters "FMT" block

Mmioread () reads Wave file format information

MmiOascend () jumps out of the "FMT" block

MmioDescend ("DATA") enters "DATA" block

Mmioread () read WAVE data information

Mmioclose () Close the file.

The process of outputting the WAV file:

Waveoutopen () Opens an output device

WaveoutPrepareHeader () Prepare Wave Data Headers.

WaveoutWrite () Write the data into the device and start playing

WaveoutReset () stops playing and resets the manager

Waveoutclose () and close player

WaveoutunpareHeader () Clean WaveoutPrepareHeader prepared WaveoutPrepareHeader.

Example:

This instance implemented function is to open the background music and then join a dubble every five seconds. Background music will stop playing, you can listen to the background dubbing dubbing ... the actual effect generated by dubbing. In order to implement this function, we have packaged a class. Everyone can find these two files "Wavemix..h" and "Wavemix.cpp" on the CD.

First of all, let's take a look at "WAVMix.h", which defines a class called "mwave",

The member functions are: constructor, destructuring function, open (open file), play (play file), add (to buffer Mix Mix file), STOP (stop broadcast), Close (turn off output device, class reinitialization ).

Now we will build a dialog-based program in front. The two files are added to the "File View". Open "Wavemixdlg.h", add "#include" Wavemix.h "in front, add private data" MWAVE MWAVE "in class class cwavemixdlg, add member online onlnitdialog () and Ontime ()," in class "cwavemixdlg". ,

Add a timer in this function to open and play background music. Add a function MWAVE.ADD ("2.waw" to the buffer every five seconds in the direction of the timer.). Compile and run.

Source program analysis

// Wavemix.h: main header file for the Wavemix Application

//

#if! defined (AFX_WAVEMIX_H__54F4AF66_CE37_11D1_94F8_0000B431BBA1__INCLUDED_)

#define AFX_WAVEMIX_H__54F4AF66_CE37_11D1_94F8_0000B431BBA1__INCLUDED_

#iF _MSC_VER> = 1000

#pragma overce

#ENDIF / / _MSC_VER> = 1000

#ifndef __afxwin_h__

#error include 'stdafx.h' Before Including this file for pch

#ENDIF

#include "resource.h" // main symbols

/

#include "windows.h"

#include "mmsystem.h"

#ifdef Win32

#define Wavdata Byte

#ELSE

#define Wavdata Byte_huge

#define Waveformatex PCMWAVEFORMAT

#ENDIF

#ifdef Win32

#define WAV16Data Word

#ELSE

#define WAV16Data Word_huge

#ENDIF

Class Mwave

{

Private:

Bool OpenFlage;

DWORD DATASIZE;

Hglobal hdata;

Wavdata * LPDATA;

PCMWAVEFORMAT PFORMAT;

Wavehdr Wavehead;

Hwaveout hwaveout;

PUBLIC:

MWave () {MEMSET (this, 0, sizeof (mwave));

~ Mwave () {close ();

Int open (char *); // Open a WAV file

INT play (hwnd); // Play a WAV file

Int add (char *); // Add a WAV file to the WAV device played

INT stop (); // Stop playback

INTCOSE (); // Close device

}

#ENDIF / /! Defined (AFX_WAVEMIX_H__54F4AF66_CE37_11D1_94F8_0000B431BBA1__INCLUDED_)

// Wavemix.cpp: defines the class behaviors for the application.

//

#include "stdafx.h"

#include "Wavemix.h"

#include "wavemixdlg.h"

#ifdef _Debug

#define new debug_new

#undef this_file

Static char this_file [] = __file __; # ENDIF

///

// Wavemix Class

//

Int Mwave :: Open (char * name)

{

HMMIO HMMIO;

MmckInfo Pinfo;

Mmckinfo cinfo;

IF (hmmio) close ();

/ / Open the WAV file and return a HMMIO handle

Hmmio = mmioopen (name, null, mmio_read);

IF (! hmmio) Return False;

OpenFLAGE = 1;

// Find the parent block "Wave";

Pinfo.fcctype = mmiofourcc ('w', 'a', 'v', 'e');

IF (MmioDescend (HMMIO, & PINFO, NULL, MMIO_FINDRIFF) goto false_end;

/ / Find the "FMT" Parent "Riff";

Cinfo.ckid = mmiofourcc ('f', 'm', 't', '');

IF (MmioDescend (HMMIO, & CINFO, & PINFO, MMIO_FINDCHUNK)

Goto false_end;

Mmioread (HMMIO, (LPSTR) & PFormat, Sizeof (PCMWAVEFORMAT); // cinfo.cksize;

IF (PFORMAT.WF.WFORMATTAG! = Wave_FORMAT_PCM)

Goto false_end;

// Jump into the block "FMT"

MmiOascend (Hmmio, & Cinfo, 0);

/ / Find data block

Cinfo.ckid = mmiofourcc ('d', 'a', 't', 'a');

IF (MmioDescend (HMMIO, & CINFO, & PINFO, MMIO_FINDCHUNK)

Goto false_end;

DataSize = cinfo.cksize;

// read data

HDATA = GlobalAlloc (GMEM_MOVEABLE

| GMEM_SHARE, DATASIZE);

LPDATA = (Wavdata *) Globalock (HDATA);

IF (! hdata ||! lpdata) goto false_end;

IF (Mmioread (HMMIO, (HPSTR) LPDATA, DATASIZE

! = (LRESULT) DATASIZE

Goto false_end;

// Close and Return

Mmioclose (hmmio, mmio_fhopen);

Return True;

FALSE_END:

IF (hmmio) mmioclose (hmmio, mmio_fhopen);

IF (LPDATA) LocalUnlock (HDATA);

IF (HDATA) GlobalFree (HDATA);

MEMSET (this, 0, sizeof (mwave));

Return 0;

}

Int Mwave :: Play (HWND HP)

{

IF (! OpenFlage) Return False;

// Detect system playback function

IF (Waveoutopen (NULL, WAVE_MAPPER,

(Waveformatex *) & PFormat, NULL,

NULL, WAVE_FORMAT_QUERY)))

Return close ();

IF (Waveoutopen (& Hwaveout, Wave_Mapper,

(Waveformatex *) & pformat, (dWord) HP, 0, Callback_Window))

Return close ();

Wavehead.lpdata = (lpstr) lpdata;

Wavehead.dwbufferlength = DataSize;

Wavehead.dwflags = 0L;

Wavehead.dwloops = 0L;

Add data to the WAV device

IF (WaveoutPreparehead) (HWaveout, & Wavehead,

SIZEOF (WAVEHDR))))

Return close ();

IF (Waveoutwrite (Hwaveout, & Wavehead, Sizeof (WaveHDR)))

Return close ();

Return True;

}

/ / # Define min (A, b) (((a) <(b))? (a): (b))

INT MWAVE :: Add (char * name)

{

Register int x;

IF (! OpenFlage) Return Open (Name);

MWAVE WAV;

IF (! wav.open (name)) Return False;

Mmtime Time;

// Get the current play position of the WAV file

Time.wtype = Time_Bytes;

WaveoutgetPosition (Hwaveout, & Time, Sizeof (mmtime)))

Time.u.cb = 0;

DWORD START = ((Time.u.cb >> 1) << 1);

DWORD END = Min (DataSize_start, wav.datasize);

Register Wavdata * LPD = LPDATA START;

For (Register DWORD I = 0; I

{

// add two sets of WAV file data and detect if the data size is legal, if // data size offline, then take maximum and minimum

x = (((* (LPD I)) (* (Wav.lpdata i)))))))))

IF (x <0) x = 0;

IF (x> 255) x = 255;

* (LPD I) = (Byte) (x);

}

Return True;

}

INT mwave :: stop ()

{Return! WaveoutReset (hWaveout);

INT MWAVE :: Close ()

{

IF (hwaveout)

{

Waveoutreset (hwaveout);

Waveoutclose (hwaveout);

Waveoutunpreparehead (Hwaveout, & Wavehead,

Sizeof (WaveHDR);

}

IF (LPDATA) LocalUnlock (HDATA);

IF (HDATA) GlobalFree (HDATA);

MEMSET (this, 0, sizeof (mwave));

Return 0;

}

3 multimedia graphic image technology

Now we tell the most important and core technologies in Windows multimedia - graphics technology. For Windows graphic image technologies, including basic GDI draws pairs such as points, lines, rectangles, images, and bitmap files, which are broadcasted to use the movie files that use Windows image graphics technology.

We mainly tell the BMP file implementation process, palette applications, and some BMP image synthesis techniques, such as airmut technology, BMP animation technology, etc.

BMP file structure

The BMP file consists of several parts: file header, bitmap information head, palette, data area. Below this picture shows the BMP file structure:

The necessary conditions for Windows bitmap display: We analyze a Windows API function:

Int setDibitStodevice (HDC, UXDEST, UYDEST, UWIDTH, UHEIGHT, UXSRC, UYSRE,

USTARTSCAN, CSCANLINES, LPVBITS, LPBMI, FUCOLORUSE

Check out the tenth, eleven parameters of this function LPVBITS, LPBMI. Where lpvbits indicate the address of the BMP data in memory, LPBMI points to a BitmapInfo data structure, as long as there are two parameters, a BMP bitmap is determined. Everyone can see the vast majority of Windows graphic image browsing software can analyze the file format, such as JPG, GIF, PCX, TIF, etc., all build a data buffer in memory, and establish one according to graphic image format. BitmapInfo's data structure, then written on the screen with the SetDibitStodevice function. We will basically use this way.

Windows palette

Windows's display devices can be displayed thousands of colors, but the number of colors that can be displayed at the same screen is not thousands of species on the same screen. We divide the display device into monochrome, sixteen colors, two hundred Fifty-six colors, enhance color, true color, or divided into 1bit, 4bit, 8bit, 16bit, 24bit, according to the display bit area. Since Windows's theoretical display and actual display are not consistent, you need a solution to solve this problem, this is to use the palette. Why do we use a palette that we don't make a detailed discussion, just a little bit, only hexadecimal and 256 color bitmap need palette.

Below is a method using a palette

First read a bitmap file, then determine the number of color of this bitmap file, if this file is sixteen or two hundred and six colors, then there will be a palette information in this file, read this The palette information, converts this palette information into a logPalette structure, generates a logical palette according to this structure, and then use the SelectPalette function to select the logical palette in the device description table each time you want to display the bitmap. HDC, then use the realizepalette function to implement this palette, use the SelectPalette function after the display is complete, select the old palette, and a palette call process is completed.

Constructing Windows Image Processing Category Library

We assume that this class library contains the following features:

Treatment palette;

a. Generate a logical palette;

b. Implement palette;

2. Handling BMP files

a. Read the BMP image;

d. Display image;

c. Implement the function of the above "processing palette";

3. Handling FLC animation

a. Read the FLC animation file;

b. Play parameter settings;

c. Display image;

d. Implement the above "processing palette" function;

Through the above, we have some public characteristics of the class libraries we want to design:

1. Treat a palette;

2. In addition to "1", "2" and "3" contain the necessary conditions for Windows image display: structure

BitmapInfo and a Bitmap data area.

To this end, we first construct a class that handles the palette, which implements the above "processing palette" function. Why handle the palette separately without letting it attach "processing BMP files" or "handling FLC animation", why, in large-scale multimedia programming, there are often dozens or hundreds of BMP images or animations. Only one or two palettes, excessive flooding panels tend to flash during layout, and waste memory spaces, thus being processed separately. Second, we construct a class that handles DIB images: In this class, the core is two parameters (structural BitmapInfo and a Bitmap data area) and a display function show (). This class is inherited in the palette class because the processing image file must process the palette. And becoming the base class of other image files, as these two structures and functions must be handled by handling the image file.

With these two base classes, we construct other classes on the basis of these two base classes.

// mybmp.h: interface for the mybmp.

//

//

#if! defined (AFX_MYBMP_H___34151075_C57B_11D1_94F8_0000B431BBA1__INCLUDED_)

#define AFX_MYBMP_H__34151075_C57B_11D1_94F8_0000B431BBA1__INCLUDED_

#iF _MSC_VER> = 1000

#pragma overce

#ENDIF / / _MSC_VER> = 1000

#define falsereturn {_lclose (hfile); return 0;}

#define imagecolors (x, y) (1 << ((x) * (y))))))

/ / Single line BMP data bytes

#define dword_wbytes (x) ((((x) 31 ul >> 5) << 2)

#define min (a, b) (((a) <(b))? (a): (b))

#ifdef Win32

#define bmpdata byte

#ELSE

#define bmpdata byte _huge

#ENDIF

// #include "test.cpp"

#define palversion 0x0300

#define dib_StorageWidth (x) ((x 3) & ~ 3)

#define widthbytes (i) ((i 31) / 32 * 4)

#define maxpalette 256 / * max. # supported paste entries * /

#define maxloadflcnumber 255

Class Palette

{

Private:

HPALETTE HOLDPAL;

protected:

HPALETTE HPAL;

PUBLIC:

Palette () {memset (this, 0, sizeof (palette));

~ Palette () {if (hpal) deleteObject (hpal);

HPALETTE CREATEPAL (BitmapInfo *);

HPALETTE CREATEPAL (LPLOGPALETTE PAL);

HPALETTE getPal () {return hPal;}

UINT setPal (HDC);

Void ResetPal (HDC);

}

Class MyDib: Public Palette

{

protected:

Hglobal hdata;

Struct

{

BitmapInfoHeader B;

Rgbquad R [256];

PUBLIC:

LPbitmapInfo lpinfo;

LpbitmapInfoheader lpinfohead;

MYDIB ();

~ Mydib ();

Int show (HDC, INT, INT, INT, INT, INT, DWORD);

Inline Int Show (HDC HDC, INT X1, INT Y1, INT X2, INT Y2,

INT X3, INT Y3, INT X4, INT Y4)

{Return SHOW (HDC, X1, Y1, X2, Y2, X3, Y3, X4, Y4, SRCCOPY);

Inline Int Show (HDC HDC, INT X, INT Y)

{Return SHOW (HDC, X, Y, 0, 0, 0, 0, 0, 0, SRCCOPY);

Inline Int Show (HDC HDC)

{Return SHOW (HDC, 0, 0, 0, 0, 0, 0, 0, Srccopy);

Show (MyDIB *, Int, int, int, int, int, int, byte, byte, byte,

Byte, Byte, Byte;

Show (MyDIB *, int, int, int, int, int, register

Byte, register byte;

}

Class Bmp: Public MyDIB

{

PUBLIC:

INT OPEN (LPCSTR, INT);

INT inline open (lpcstr name) {return open (name, 0);}

}

#ndif //! defined (AFX_MYBMP_H___34151075_C57B_11D1_94F8_0000B431BBA1__INCLUDED_)

// mybmp.cpp: Implementation of the mybmp class.

//

//

#include "stdafx.h"

#include "mybmp.h"

#ifdef _Debug

#undef this_file

Static char this_file [] = __ file__;

#define new debug_new

#ENDIF

//

// construction / destruction

//

//

// Class Palette

//

UINT PALETTE :: SetPal (HDC HDC)

{

IF (HPAL)

{

SelectPalette (HDC, HPAL, 0);

RETURN REALIZEPALETTTE (HDC);

}

Else Return False;

}

Void Palette :: ResetPal (HDC HDC)

{

IF (Holdpal)

{

SelectPalette (HDC, Holdpal, 0);

Holdpal = 0;

}

}

HPALETTE PALETTE :: CreatePal (LPLOGPALETTE PAL)

{

IF (hpal) deleteObject (HPAL);

IF (PAL_> PALNUMENTRIES <= 256) HPAL = CREATEPALETTE (PAL);

Return HPAL;

}

//

// Class Dibpalette

//

HPALETTE PALETTE :: CreatePal (BitmapInfo * Info)

{

Struct

{

Word Palversion;

Word Palnumentries;

Paletteentry Palpalent [256];

} P;

LPLOGPALETTE PAL = (LPLOGPALETTE) & P;

PAL_> paRversion = 0x300;

PAL_> PALNUMENTRIES = / * min * / ((Word) ImageColors (Info_> Bmiheader.biBitcount, 1)); //, info_> bmiheader.biclrused;

For (int i = 0; i panelnutentries; i )

{

PAL_> PALPALENTRY [I] .pered = info_> bmicolors [i] .rgbred;

PAL_> Palpalent [i] .pegreen =

INFO_> Bmicolors [i] .rgbgreen;

PAL_> PALPALENTRY [I] .peblue = info_> bmicolors [i] .rgbblue;

PAL_> PALPALENTRY [I] .peflags = pc_nocollapse;

}

Return Palette :: CreatePal (PAL);

}

//

// mydib class

//

MYDIB :: MYDIB ()

{

MEMSET (this, 0, sizeof (bmp));

Lpinfo = (lpbitmapinfo) & p;

LPINFOHEAD = (lpbitmapinfohead) & p;

}

MYDIB :: ~ MYDIB ()

{

IF (HDATA) GlobalFree (HDATA);

}

INT MYDIB :: Show (HDC HDC, INT X1, INT Y1, INT X2, INT Y2, INT X3,

Int Y3, INT X4, INT Y4, DWORD ROP)

{

IF (x2 <= 0) x2 = (int) LPINFOHEAD_> BIWIDTH X2;

IF (Y2 <= 0) Y2 = (int) LPINFOHEAD_> BIHEIGHT Y2;

IF (x4 <= 0) x4 = (int) LPINFOHEAD_> BIWIDTH X4;

IF (Y4 <= 0) Y4 = (int) LPINFOHEAD_> BIHEIGHT Y4;

// if (w_hp) setPalette (HDC);

BMPDATA * DATA = (BMPDATA *) GlobalLock (HDATA);

// int i = stretchdibits (HDC, X1, Y1, X2, Y2, X3, Y3, X4, Y4,

Data, Info, DIB_RGB_COLORS, ROP

INT i = stretchdibits (HDC, X1, Y1, X2, Y2, X3,

(int) LPINFOHEAD_> Biheight_Y3_Y4, X4, Y4, DATA, LPINFO,

DIB_RGB_COLORS, ROP);

GlobalUnlock (HDATA);

Return I;

}

Int MyDib :: Show (MyDIB * DIB, INT X1, INT Y1, INT X2, INT Y2, INT X3, INT Y3,

BYTE R1, BYTE G1, BYTE B1, BYTE R2, BYTE G2, BYTE B2)

{

Register DWORD C1 = ((DWORD) R1) << 16) ((DWORD) G1) << 8) B1;

Register DWORD C2 = ((DWORD) R2) << 16) ((DWORD) G2) << 8) B2;

Register DWORD C;

Register DWORD * RQ = (DWORD *) P.R;

IF (! DIB_> HDATA)

{

Memcpy (DIB, this, sizeof (mydib));

DIB_> lpinfo = (lpbitmapinfo) & (dib_> p); dib_> lpinfohead = (lpbitmapinfoheader) & (dib_> p);

DIB_> LPINFOHEAD_> BIWIDTH = X2 X1;

DIB_> LPINFOHEAD_> BIHEIGHT = Y2 Y1;

DWORD SIZE = DIB_> LPINFOHEAD_> BIWIDTH

* DIB_> LPINFOHEAD_> BIHEIGHT

* ImageColors (DIB_> LPINFOHEAD_> BIBITCOUNT, 1) / 8;

DIB_> HDATA = GlobalAlloc (GMEM_FIXED, SIZE);

}

X2 = min (x2, (int) DIB_> LPINFOHEAD_> BIWIDTH _X1);

Y2 = min (Y2, (int) DIB_> LPINFOHEAD_> BIHEIGHT_Y1);

BMPDATA * DATA1 = (BMPDATA *) Globalock (HDATA);

BMPDATA * DATA2 = (BMPDATA *) GlobalLock (DIB_> HDATA);

DWORD W1 = DWORD_WBYTES (LPInfohead_> BIWIDTH

* LPINFOHEAD_> BIBITCOUNT);

DWORD W2 = DWORD_WBYTES (DIB_> LPINFOHEAD_> BIWIDTH

* DIB_> LPINFOHEAD_> BIBITCOUNT);

Data1 = (w1 * (lpinfohead_> biheight_y3_y2)

X3 * LPINFOHEAD_> BIBITCOUNT / 8);

DATA2 = (w2 * (dib_> lpinfohead_> biheight_y1_y2)

X1 * DIB_> LPINFOHEAD_> BIBITCUNT / 8);

For (int J = 0; j

{

For (Register Int i = 0; i

{

C = * (RQ * (DATA1 I));

IF ((C C2) || ((Word) C <(Word) C1)

|| (WORD) C> (Word) C2)

|| (BYTE) C <(byte) C1)

|| (BYTE) C> (Byte) C2)) * (DATA2 I) = * (DATA1 I);

}

DATA1 = W1;

DATA2 = W2;

}

GlobalUnlock (HDATA);

GlobalUnlock (DIB_> HDATA);

Return True;

}

Int MyDib :: Show (MyDib * Dib, Int x1, int y1, int x2, int y2, int x3,

Int Y3, Register Byte X, Register Byte Y)

{

Register BmpData D;

IF (! DIB_> HDATA)

{

Memcpy (DIB, this, sizeof (mydib));

DIB_> LPINFO = (LPbitMapInfo) & (DIB_> P);

DIB_> LPINFOHEAD = (LPbitmapInfoHeader) & (DIB_> P);

DIB_> LPINFOHEAD_> BIWIDTH = X2 X1;

DIB_> LPINFOHEAD_> BIHEIGHT = Y2 Y1; DWORD SIZE = (DIB_> LPINFOHEAD_> BIWIDTH 1)

* DIB_> LPINFOHEAD_> BIHEIGHT

* DIB_> LPINFOHEAD_> BIBITCOUNT / 8;

// ImageColors (DIB_> LPINFOHEAD_> BIBITCOUNT, 1) / 8;

DIB_> HDATA = GlobalAlloc (GMEM_FIXED, SIZE);

}

X2 = min (x2, (int) DIB_> LPINFOHEAD_> BIWIDTH _X1);

Y2 = min (Y2, (int) DIB_> LPINFOHEAD_> BIHEIGHT_Y1);

BMPDATA * DATA1 = (BMPDATA *) Globalock (HDATA);

BMPDATA * DATA2 = (BMPDATA *) GlobalLock (DIB_> HDATA);

DWORD W1 = DWORD_WBYTES (LPInfohead_> BIWIDTH

* LPINFOHEAD_> BIBITCOUNT);

DWORD W2 = DWORD_WBYTES (DIB_> LPINFOHEAD_> BIWIDTH

* DIB_> LPINFOHEAD_> BIBITCOUNT);

Data1 = (w1 * (lpinfohead_> biheight_y3_y2)

X3 * LPINFOHEAD_> BIBITCOUNT / 8);

DATA2 = (w2 * (dib_> lpinfohead_> biheight_y1_y2)

X1 * DIB_> LPINFOHEAD_> BIBITCUNT / 8);

For (int J = 0; j

{

For (Register Int i = 0; i

{

D = * (DATA1 I);

IF ((D y)) * (DATA2 I) = D;

}

DATA1 = W1;

DATA2 = W2;

}

GlobalUnlock (HDATA);

GlobalUnlock (DIB_> HDATA);

Return True;

}

//

// Class BMP

//

INT BMP :: Open (LPCSTR File, Int Sty) // style: 0: Enable Hpal 1: DISNABLE HPAL

{

BitmapfileHeader FileHead;

INT i; //, j, k;

Hfile Hfile;

DWORD ubytes;

DWORD size;

Hfile = _Lopen (file, of_read);

IF (hfile == hfile_error) return 0;

// read the file header

i = _lread (Hfile, & Filehead, Sizeof (BitmapfileHeader);

IF (i == hfile_error) falsereturn; // goto bmp_false_end;

// Type = filehead.bfType;

// read the information head

I = sizeof (BitmapInfoHeader) sizeof (rgbquad) * 256;

_Lread (HFile, Lpinfohead, i);

// Establish a palette

IF (! style "CREATEPAL (LPInfo);

Ubytes = _llseek (HFILE, 0, 2);

IF (FileHead.BFSize> ubytes) falsereturn; // goto bmp_false_end;

IF (HDATA) GlobalFree (HDATA);

SIZE = ubytes_filehead.bfoffbits;

HDATA = GlobalAlloc (GMEM_FIXED, SIZE);

BMPDATA * DATA = (BMPDATA *) GlobalLock (HDATA);

// read data

_llseek (Hfile, FileHead.Bfoffbits, 0);

For (; _ Lread (Hfile, Data, RBLOCK) == RBLOCK; DATA = RBLOCK;

GlobalUnlock (HDATA);

_lclose (hfile);

Return True;

}

In the MyBmp.h file, we define three classes: Class Palette,

Class Dibpalette, class mydib. Where Palette is the base class. Dibpalette inherited the class Palette, and the class MYDIB inherited the class Dibpalette.

Class Palette:

In this class, we define two member variables HPAL and HOLDPAL, seven member functions. These seven member function functions are as follows: two of them are constructor and destructive functions, two functions createpal, respectively.

(BitMapInfo *), createPal (LPLOGPALETTE) Complete the role of constructing palette according to the specified parameters, a function setpal (HDC) implements palette, a function resetpal (HDC) recovery palette, a function getPal () get coloring board.

Class mydib:

In this class, we define two core member variables P and HData, where P is a custom structure, which contains a bmpinfo header information and a palette, HDATA is a handle pointing to a piece of data in memory, two other The parameters LPINFO and LPINFOHEAD are actually pointing to the pointer to the structure P. The core of the four member functions show () is an API function setDibitStodevice (). Their functions are displayed on the screen based on the structural P and handle HDATA.

Class BMP:

In this class, we only define two member functions Open, and their function is to open a BMP file and fill the file content into the parameters of its base class. As we mentioned in the multimedia programming, we need to use a public palette, but sometimes you need private palette, so the second parameter in the open function specifies this difference, and if the parameter is 0, it constructs your own HPAL. Otherwise, your HPAL is invalid.

Case Analysis

In this example, we will transfer a BMP file and display it on the screen, and the program process is as follows:

Create a dialog attribute application, then join the source file "mybmp.h" and "mybmp.cpp" provided in the CD, and add "#include" mybmp.h "in the file" Showbmpdlg.h "," Add a member variable "BMP BMP" in the class "cshowbmpdlg" definition to read the file "1.BMP" in the member function of class "cshowbmpdlg" onnitdialog () "" bmp.open ("1.BMP") " Add the following palette to implement function and display function in OnPaint ().

bmp.setpal (dc.m_hdc)

bmp.show (dc.m_hdc)

bmp.resetpal (dc.m_hdc)

Note SetPal () and resetPal () To pair, setPal () is used before show (), resetpal () after Show (). Compile and run. 4 image synthesis

If you want to achieve an animation, such as a mouse run from the left side of the screen, the general book is called: First, make a mouse picture, and then draw a black and white mouse mask picture. First, the screen is processed by a mask diagram, and then processes the mouse picture with a mask, and finally put the treated mice on the screen, and the three Bitblt functions are handled before and after. And so that the process will flash significantly on the screen. To stop flashing, you must first make a compatible DC, first copy the screen picture to the compatible DC, and then copy the mouse after compatibility with the DC. It is necessary to use five Bitblt functions before and after. The picture is relatively small, if the picture is very big, that speed is simply "Today, this computer, the human face is red, and the people don't know where, the mouse is still slowly crawling." Is there any other solution?

How to achieve transparent bitmap

The most stupid approach: Directly draw a setpixel function by point on the screen. General method: use the Bitblt function to make at least three operations. The fastest way: write screen directly. The most cost-effective approach: write the data buffer directly.

Discussion in four ways:

For programmers who first engage in image processing, it seems that the way to draw past is the first choice. However, it is true that this is the slowest method in the world. It is the most ideal animation effect that it implements it. "Last year, tears Today, it streams to the mouth. " Bitblt: The previous introduction has been introduced here. Direct Write Screen: This method is more used in this way, programming in a Windows environment, only WING WING can only be implemented in Windows 3.1 environments, and functions CREATEDIBSECTION () or use MicrosoftDirectX functions in Win95 or NT. This way we will introduce them. Not discussed here. Write data buffer: This method is smaller for environmental requirements, no external software, compatible with 3.1 and 95, NT, speed can also, its principle is similar to the direct write screen, and can be easily ported to direct written mode Go in. We will introduce this method here.

Read and write data buffer:

Everyone may still remember the class mydib introduced in the previous, there are two parameters, one is the BMP information head, one is the BMP data area, whether everyone can imagine how to modify the BMP data area, then display the image? ? This data area is the data buffer we have to use.

Transparent bitmap

To achieve a transparent bitmap, you must first have two pictures, one as a source diagram, one as a destination bitmap, the programmer should post the source chart to the destination chart, and to indicate what color to block the off For this reason, we add a function on the class mydib (MyDIB * Dib, Int x1, int y1, int x2, int y2, int x3, int y3, byte r1, byte g1, byte b1, byte r2, byte G2, BYTE B2), this function is a bit similar to the Bitblt function, it means: copy the data in the self-buffer to the buffer of class DIB, where from RGB (R1, G1, B1) to RGB The color of (R2, G2, B2) is transparent color, X1, Y1, X2, Y2, X3, Y3 are the target coordinate, copy range, source coordinate, and the meaning is the same as Bitblt. During the implementation of the show function, we first calculate the source data to be changed, the target data address, and then analyze if the data color to be copied belongs to the color, if it is a screen color, no copy data, otherwise copy. Another transparent bitmap method

Transparent color is a relatively simple implementation, but sometimes there is another way of implementation, which is to specify the color index mode, we can specify a certain number to a certain number in a palette to a certain number transparent color . Therefore, in Class MyDIB, add a function show (MyDIB * DIB, INT X1, INT Y1, INT X2, INT Y2, INT X3, INT Y3, REGISTER BYTE X, Register Byte Y), the principle of this function and the previous The way is similar, but it is only four parameters than the previous way, and it is changed from color specified transparencies to specify transparent colors with color index.

Transparent bitmap refresh speed

Change the speed of the data buffer mode, or Bitblt speed fast? If the Bitblt is fast, the previous heart is not a rolling Yangtze River, for this, we must use an instance to analyze, establish a dialog-based program named TP, join the source program mybmp.cpp and mybmp. h Add #include "mybmp.h" in the TPDLG.H file header, add two member variables BMP1 and BMP2 in class CTPDLG. When the window is initialized, set the timer, open the file "1.BMP", "2.BMP", complete the copy and refresh process, compile and run the program during the timer message response process. We can see a "allTIME" parameter that shows that the refresh 256 bitmap needs to be about 20_21 seconds. Now Note Frequency Function BMP1.SHOW ((MYDIB *) & BMP2, 0, 0, 640, 480, 0, 0, 0, 0, 0, I, I, I), and then Refresh 256 positions It takes about 15_16 seconds, which is the time required to use the function StretchDibits. It can be seen that a transparent bitmap completion time is equivalent to a four bitblt time, the three Bitblt time (difference effects) of the Bitblt method, and the five Bitblt time (good effect) is much better. Of course, this is much better than the direct written screen.

Now replace the bottom function to BMP1.SHOW ((MyDib *) & bmp2, 0, 0, 640, 480, 0, 0, 0, i), we are not surprised to see the current time to refresh 256 bitmap is 16_17 seconds, almost Think, the buffer reading and writing time has been

It can be ignored.

Figure 5.3

Case Analysis

In this example, we have to achieve an animation, a background is a great good person, with a dog in front of it ran to run. The material needs five pictures, including one, four animation. We analyze its implementation: In class cmoviedlg, we first define five images with statement BMP BMP [5], and then define a temporary picture with statement MYDIB TEMP. After the dialog initialization process function, the five bitmaps are read, and the timer is one hundred milliseconds, and the operation procedure in the timer response function is as follows: First write the background to the temporary picture, and then the puppy penetrate white Write Into the temporary picture, and finally write the temporary picture on the screen.

Figure 5.4

5 FLC animation

FLC and FLI animation are the same as Autodesk, which uses the method of deterioration between frames and frames and single frame RLE encoding, which is characterized by easy decoding and encoding. Of course, they did not provide the audio to restrict its application range. Between FLC and FLI, FLI is limited to 320x200, with only 64 colors, up to 4000 frames, so that it has almost exited the historical stage. Therefore, we will no longer tell FLI here, only introduce the principle of FLC animation and implementation.

FLC file structure

The structure of the FLC file is shown below:

The FLC file header data structure is as follows:

Frame header data structure:

Block data structure:

The type and explanation of blocks:

FLC animation play source program introduction

We analyze the FLC animation source program: Open the file flcw.h, you can see the FLC file header, frame head, block, and block type macro in the file. In addition, we can find that the class FLCW is derived from the class MYDIB, because the FLC animation itself is complicated, as long as it is to draw on the screen, it is finally to convert into bitmap form in memory. In the FLC animation implementation, a size of the same size is generated with the FLC animation in the open phase. After reading the next frame, the data is written to the internal storage position, and then the memory position map is attached to the screen. .

// Flcw.h: interface for the flcw class.

//

//

#if! defined (AFX_FLCW_H__2A3B58A3_C964_11D1_94F8_0000B431BBA1__INCLUDED_)

#define AFX_FLCW_H__2A3B58A3_C964_1D1_94F8_0000B431BBA1__INCLUDED_

#iF _MSC_VER> = 1000

#pragma overce

#ENDIF / / _MSC_VER> = 1000

#ifdef __cplusplus

Extern "C" {

#ENDIF

/ * # ifNDef GlobalPtrHandle

#define globalptrhandle (lp) /

(Hglobal) "GlobalHandle (FP_SEG (LP)))))))

#ENDIF

#define isoversegalians (LP, OFF) /

((DWORD) FP_OFF ​​(LP) (Word) OFF> 0xffffl? 1: 0)

#include "mybmp.h"

// # Define paalversion 0x300

#define dib_StorageWidth (x) ((x 3) & ~ 3)

#define widthbytes (i) ((i 31) / 32 * 4)

#define maxpalette 256 / * max. # supported paste entries * /

#pragma pack (2)

转载请注明原文地址:https://www.9cbs.com/read-51034.html

New Post(0)