Webocreation

Tuesday, November 17, 2009

Chapter 1: Windows Fundamentals and Architecture

Chapter 1: Windows Fundamentals and Architecture

When you develop Windows-based applications, you can choose from a wide variety of programming environments depending on the requirements of your application. Many developers are choosing the C++ language for developing Windows-based applications because it is object-oriented in nature and provides a simplified approach to dealing with the complexity of Windows and the wide range of application programming interface (API) functions. Using C++, combined with a class library, further simplifies the development process by grouping the API functions into logical units and encapsulating the basic behavior of windows and other objects in reusable classes.


This course focuses on the Microsoft Foundation Class (MFC) Library, the class library created by Microsoft to be used in combination with Visual C++, the Microsoft version of C++. You can use these tools together to develop Windows-based C++ applications.

MFC extends the object-oriented programming model used in Windows-based applications. Since MFC is based on the Windows programming model, you need a basic understanding of Windows architecture before learning how to use the classes in your applications. If you're coming to MFC from a traditional Windows programming background, such as C and the Windows SDK, you're already familiar with these concepts. If you're new to Windows programming, then this chapter is for you.

This chapter provides an overview of the Windows programming architecture and briefly takes you behind the scenes to see how Windows-based applications work.

Objectives

At the end of this chapter, you will be able to:

® Define processes, threads, and multitasking.

® Describe the structure of memory management.

® Explain the purpose of messages and the concept of event-driven programming.

® Describe the minimum components of a simple Windows-based application.

® Explain how an application is initialized and windows are created.

Understanding Windows Architecture: Before you begin writing MFC applications, you should understand several key architectural features of Windows-based applications and the Windows operating system.

This section explains the run-time structure of Windows-based applications. Here you will learn about the differences between applications, processes, and threads of execution. You will also learn about how the Windows operating system manages processes and threads in order to maximize performance.
This section includes the following topics:


  1. Processes
The term "process" and the more common term "application" are sometimes used interchangeably. However, in the Windows environment, there is a distinction between a process and an application.

An application is a static sequence of instructions that makes up an executable file. A process is usually defined as an instance of a running application. A process has its own private address space, contains at least one thread, and owns certain resources, such as files, allocated memory, and pipes.

A process consists of:

® An executable program

® A private address space in memory

® System resources, such as files, pipes, communications ports, and semaphores

® At least one thread, where a thread is a path of execution


  1. The Virtual Memory System
In an operating system where multiple processes are allowed, each process must be protected against corruption by other processes in memory. The Windows operating system is designed to provide this protection.

There are two types of memory in the Windows operating system:
® Physical memory

Consists of the amount of physical RAM.

® Virtual memory

Consists of 4 gigabytes (GB) of addresses, or 232 bytes of addressable memory that is available to your application. This is not 4 GB of actual physical memory. Each application is given 2 GB of addresses while the operating system reserves 2 GB for its own use.

Note In Windows NT, an application may have up to 3 GB of addresses for its own use.

How the Virtual Memory System Works

When an application is started, the following process occurs:

1. The operating system creates a new process. Each process is assigned 2 GB of virtual addresses (not memory) for its own use.

2. The virtual memory manager maps the application code into a location in the application's virtual addresses, and loads currently needed code into physical memory. (The virtual address has no relationship to the location of the application code in physical memory.)

3. If your application uses any dynamic-link libraries, the DLLs are mapped into the process's virtual address space and loaded into physical memory when needed.

4. Space for items such as data and stacks is allocated from physical memory and mapped into the virtual address space.

5. The application begins execution by using the addresses in its virtual address space, and the virtual memory manager maps each memory access to a physical location.

The application never directly accesses physical memory. The virtual memory manager controls all access to physical memory through requests for access by using the virtual addresses.

To see an animation that explains how virtual memory and physical memory work, click this icon.

Benefits of Using a Virtual Memory System

A virtual memory system helps both to ensure robust application execution and to simplify memory management.

As mentioned earlier, one concern about running an application in a multitasking environment is protecting that application's execution from intrusion by other applications. Forcing applications to use virtual memory allows the operating system to provide strict physical memory partitioning between applications. If an application requests private memory space, the operating system will provide a map between that application and physical memory.

Virtual memory also allows applications to view memory as a flat, 2 GB of memory space without having to contend with the physical memory management architecture that is used by the operating system.

Threads and Multitasking

While a process can be thought of as a task that the operating system must perform, such as running a spreadsheet application, a thread represents one of possibly many tasks needed to accomplish the job. For example, controlling the user interface, printing, and calculating the spreadsheet may be tasks of the spreadsheet application that are assigned to individual threads. A thread runs in the address space of its process and uses the resources allocated to its process.

A process can have a single thread, or it can be "multithreaded.” A multithreaded process is useful when a task requires considerable time to process. The task can run within one thread, while another task runs within a separate thread. The threads can be scheduled for execution independently on the processor, which allows both operations to appear to occur at the same time. The benefit to the user is that work can continue while the first thread completes its task. Another benefit is that on a multiprocessor system running Windows NT, two or more threads can run concurrently, one on each processor.

Multitasking is the ability of an operating system to give the appearance of simultaneous running of multiple threads. The operating system achieves multitasking by allowing each thread to be active for a relatively short amount of time (tens of milliseconds), and then switching to the next scheduled thread. This process, called "context switching," is done by:

1. Running a thread until the thread's time slot is exhausted or until the thread must wait for a resource to become available.

2. Saving the thread's context.

3. Loading another thread's context.

4. Repeating this sequence as long as there are threads waiting to execute.

To see an illustration of context switching in a multitasking operating system, click this icon.




  1. Threads, Messages, and Message Queues
Each thread of execution has its own virtual input queue for processing messages from hardware, from other processes, or from the operating system. These queues operate asynchronously — that is, when one process posts a message to another thread's queue, the posting function returns without having to wait for the other thread to process the message. The thread that has received the message can access and process the message when it is ready.

Of special interest is the handling of keyboard and mouse events. A special system thread, known as the raw input thread (RIT), receives all key and mouse events. Whenever the RIT receives hardware events from the processor, its sole function is to place them on the virtual input queue of the appropriate thread. Thus, under normal circumstances, no application thread need wait for its hardware events.

To see an animation that shows how messages are handled by the system message queue, click this icon.

Event-Driven Programming
Central to understanding how Windows-based applications work is the concept of event-driven programming. To hear an expert in the field describe event-driven programming, click this icon.

The best way to understand event-driven programming is to contrast it with the procedural programming of MS-DOS. Under MS-DOS, users enter command-line parameters in order to control how an application runs. Under Windows, users start the application first, and then Windows waits until users express their choices by selecting items within a graphical user interface (GUI). A Windows-based application thus starts and then waits until the user clicks a button or selects a menu item before anything happens. This is known as event-driven programming.

Anatomy of a Windows-Based Application
Knowing the elements that make up a Windows-based application and how windows communicate information between the application and the user is important to writing effective MFC applications.

In this section, you will learn about the essential components of a Windows-based application and get a brief introduction to how messages are processed in the Windows environment.

This section includes the following topics:

Elements of a Windows-Based Application
The basic elements that make up a Windows-based application include code, user interface resources, and library modules invoked by the application through dynamic linking.


Code

The primary content of any application is executable code. Windows-based applications have two required functions. One, called WinMain, provides an entry point for the operating system. The second function, a window procedure, is needed to handle messages from the operating system.

User Interface Resources

Many application-defined elements of an application's graphical user interface (GUI), such as menus and dialog boxes, are stored as templates and references in a special read-only section of the corresponding executable or DLL file. When required, Windows reads from this resource section and constructs the GUI element dynamically.

Note that while resources are primarily used to store information about the GUI elements of an application, any read-only information could be placed in the resource section. The advantage is that resources are shipped as part of the executable file, minimizing the need for additional files to be shipped with an application.

The following table lists the common Win32 resources.

Resource type Description


Accelerator Stores the keystrokes and their command associations.

Bitmap Contains a graphical image in Windows-compatible format.

Dialog box Details the controls, layouts, and attributes for dialog boxes.

Icon Stores special sets of bitmaps for icons.

Menu Details the text and layout for menus and their items.

String table Stores character strings and an associated ID value.

Toolbar Details toolbar layouts and contains references to the special bitmaps that are used to draw the button faces.

Version information Maintains program status information, such as program name, author, copyright data, version number, and so on.

Cursor Contains the special bitmap that is used to draw the cursor.



Library Modules

Microsoft Windows, along with most modern operating systems, supports dynamic linking, a method for invoking library modules at run time. A library module is a binary file that contains the executable library routines. A library module that can be loaded in this manner is called a dynamic-link library, or DLL.


  1. ow an Application Is Started


For a Windows-based application to get up and running, several events must occur first. When a user starts an application, the following events occur in sequence:

1. The operating system creates a new process and an initial thread.

2. The application code is loaded into memory.

3. Dynamic-link libraries also are loaded into memory, if your application uses them.

4. Space for items, such as data and stacks, is allocated from physical memory and mapped into the virtual address space.

5. The application begins execution.


  1. How a Window Processes Messages
Most Windows users are familiar with the term “window” and the visual elements that characterize applications. From a developer's standpoint, windows take on a new meaning. In a Windows-based application, windows are the primary method of communicating information from the application to the user. Similarly, the user uses the window to communicate with the application, thus achieving the desired behavior to accomplish a task.

The following steps explain how a Windows-based application prepares itself to receive messages that are sent to it by the system queue.

1. When a Windows-based application is started, the operating system connects with the application at a predefined entry point. This entry point is defined in the WinMain function, a required function in all Windows-based applications.

2. The application then creates one or more windows. Each window contains a window procedure that is responsible for determining what the window displays and how the window responds to user input.

3. A section of code called a message loop retrieves messages from the message queue and gives them back to Windows to send to the appropriate window procedure. This gives the application a chance to preprocess messages before they are sent to a window.

The code to implement each of the steps in this process is presented in a sample application and described in detail in Analyzing a Simple Windows-Based Application later in this chapter.

The following illustration shows how messages passed from the system queue are processed by the application.


Analyzing a Simple Windows-Based Application

In this section, you will examine the source code for a simple SDK-level Windows-based application. Since MFC applications are based on the Windows programming model, this will help you better understand how an MFC application is initialized, how windows get created, and how messages are handled.

All Windows-based applications must contain two functions, at a minimum, to provide functionality for the application as follows:

® The WinMain function

This function defines the initial entry point to the application from the operating system. It is also used to create the initial window and to start a message pump.

® A window procedure function

This function processes all messages sent from the operating system to a window. Every window, no matter how simple or how complex, has an associated window procedure.

Let's look at a simple application so you can see what is needed to create a minimal Windows-based application. This sample application simply displays a window and draws "Hello, world!" in the center of its viewing area. To see the complete code for the sample application, click this icon.

// Standard Windows header file.

#include <windows.h>// Forward declaration for the message handler.

LRESULT CALLBACK MyWndProc(HWND, UINT, WPARAM, LPARAM);

// WinMain: required for all Windows applications.

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpszCmdLine, int nCmdShow)
{

char szApplicationName[] = "Simple Hello App";

HWND hwnd;
MSG msg;

// Window class data structure

WNDCLASS wc;

wc.style = CS_HREDRAW | CS_VREDRAW; // style: causes repaint when resizing

wc.lpfnWndProc = (WNDPROC) MyWndProc; // the window procedure
wc.cbClsExtra = 0; // number of extra bytes following the class structure
wc.cbWndExtra = 0; // number of extra bytes following the window instance
wc.hInstance = hInstance; // this instance that the window procedure is within
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); // the class icon
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // the class cursor
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);// background brush
wc.lpszMenuName = NULL; // the menu resource name
wc.lpszClassName = szApplicationName; // the app name

// Register the window.

RegisterClass(&wc);

// Now create the window.

hwnd = CreateWindow(
szApplicationName, // registered class name
szApplicationName, // window name
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // x position of window
CW_USEDEFAULT, // y position of window
CW_USEDEFAULT, // width of window
CW_USEDEFAULT, // height of window
HWND_DESKTOP, // handle to parent window
NULL, // handle to menu identifier
hInstance, // handle to application instance
NULL // pointer to window-creation data
);

// Display the window.

ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);

// Pump messages until a quit message is received.

while(GetMessage(&msg, NULL, 0,0))
{
TranslateMessage(&msg); // translates virtual-key messages into character messages
DispatchMessage(&msg); // dispatches a message to the window procedure
}

return msg.wParam;

}

// This function is called by Windows to handle messages for this application.

LRESULT CALLBACK MyWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
LPCTSTR text= "Hello, world!";
switch(message)
{
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);

// Draw the text approximately in the middle of the window.

// (The upper left corner of the string will be centered.)
RECT rect;
GetClientRect(hwnd, &rect);
TextOut(hdc, (rect.right-rect.left)/2, (rect.bottom-rect.top)/2, text, strlen(text));

EndPaint(hwnd, &ps);

return 0;

// Handle the Exit situation

case WM_DESTROY:
PostQuitMessage(0);
return 0;

}

// Call the default handler so that all messages are processed.
return DefWindowProc(hwnd, message, wParam, lParam);
}

Note To run this application, create a new Win32 application, and then add a new .cpp file. Cut and paste this code into it, and then build and run the application.

In this section, we will focus on the segments of code in the sample application that pertain to all Windows-based applications. This section includes the following topics:

The WinMain Function

Every Windows-based application must contain a WinMain function. WinMain is required to perform three basic tasks:

1. Register the class of the window with the operating system.

2. Create the window in memory and initialize its attributes so it can be displayed.

3. Create a message loop that checks to see if there are any messages for the window in its message queue.

Each of these tasks is described in detail below.

Registering the Window Class

The entry point for every window application is the WinMain function. The WinMain function creates and initializes a WNDCLASS data structure, which is then registered by calling the API function RegisterClass. This data structure defines characteristics of a window, such as the address of the message handler, the window's background color, the application icon, and the default cursor.

// Window structure

WNDCLASS wc;

wc.style = CS_HREDRAW | CS_VREDRAW; // style: causes repaint when resizing

wc.lpfnWndProc = (WNDPROC) MyWndProc; // the window procedure

wc.cbClsExtra = 0; // number of extra bytes following the class structure

wc.cbWndExtra = 0; // number of extra bytes following the window instance

wc.hInstance = hInstance; // this instance that the window procedure is within

wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); // the class icon

wc.hCursor = LoadCursor(NULL, IDC_ARROW); // the class cursor

wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1); // background brush

wc.lpszMenuName = NULL; // the menu resource name

wc.lpszClassName = szApplicationName; // the app name

// Register the window.

RegisterClass(&wc);

Creating and Displaying the Window

Once the window class is registered, WinMain calls the CreateWindow function to create the application's window. CreateWindow further defines the type of window by passing information about its name, location, and size.

// Now create the window.

hwnd = CreateWindow(

szApplicationName, // registered class name

szApplicationName, // window name

WS_OVERLAPPEDWINDOW, // window style

CW_USEDEFAULT, // x position of window

CW_USEDEFAULT, // y position of window

CW_USEDEFAULT, // width of window

CW_USEDEFAULT, // height of window

HWND_DESKTOP, // handle to parent window

NULL, // handle to menu identifier

hInstance, // handle to application instance

NULL // pointer to window-creation data

);

The window is then made visible by calling the following functions:

// Display the window.

ShowWindow(hwnd, nCmdShow);

UpdateWindow(hwnd);

Processing Messages

Finally, the message loop retrieves and dispatches messages. This is accomplished by using a while loop.

// Pump messages until a quit message is received.

while(GetMessage(&msg, NULL, 0,0))

{

TranslateMessage(&msg); // translates virtual-key messages into character messages

DispatchMessage(&msg); // dispatches a message to the window procedure

}

The GetMessage function retrieves a message from the message queue and places it in the MSG data structure. The TranslateMessage function translates virtual-key messages into character messages. The DispatchMessage function dispatches a message to a window procedure.

On receiving a WM_QUIT message, the GetMessage function returns 0, the WinMain function ends, and the program terminates.

The Window Procedure

One of the primary purposes of registering a window class is to associate a window to a "window procedure." The window procedure determines what the window displays in its client area and how the window responds to user input. Window procedures can handle messages with code added by the developer, or by passing messages along to the default window procedure.

The default window procedure, DefWindowProc, is provided by the Windows system and implements many common Win32-based application behaviors, such as minimizing, restoring, or maximizing a window, displaying menu resources, and so on. If DefWindowProc does not handle a message, it is ignored.

In the sample program, the window procedure is called MyWndProc. A window procedure can have any name (as long as it doesn't conflict with some other name, of course). A Windows-based application can contain more than one window procedure, each with a different name.

Typically, you use a switch and case statement to handle the message as shown in the following code. The MyWndProc function handles two messages, WM_PAINT and WM_DESTROY. The DefWindowProc window procedure must be called to handle all other messages.

// This function is called by Windows to handle messages for this application.

LRESULT CALLBACK MyWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)

{

PAINTSTRUCT ps;

HDC hdc;
LPCTSTR text= "Hello, world!";

switch(message)
{
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);

// Draw the text approximately in the middle of the window.

// (The upper left corner of the string will be centered.)
RECT rect;
GetClientRect(hwnd, &rect);
TextOut(hdc, (rect.right-rect.left)/2, (rect.bottom-rect.top)/2, text, strlen(text));

EndPaint(hwnd, &ps);

return 0;

// Handle the Exit situation

case WM_DESTROY:
PostQuitMessage(0);
return 0;

}

// Call the default handler so that all messages are processed.
return DefWindowProc(hwnd, message, wParam, lParam);
}

Windows Functions and MFC

Since MFC applications are based on the Windows development model, they depend on the functionality provided by the WinMain function and window procedure functions.
The WinMain Function and MFC
As with all Windows-based programs, MFC applications have a WinMain function. In an MFC application, however, you don't write WinMain. It is supplied by the framework and is called when the application starts up. For more information, see Classes in a Minimal MFC Application in Chapter 4.

The Window Procedure and MFC

MFC has an internal messaging system that handles most messages generated by the classes. However, when a message cannot be handled within MFC, the application relies on the default window procedure, DefWindowProc, to handle messages. For more information, see How MFC Processes Messages in Chapter 6.

Self-Check Questions

1. Which of the following statements is true about Windows architecture?


d A. A process can have zero or more threads.

d B. Each process is allocated 1 MB of virtual memory on startup, and additional 64K blocks as required.

d C. Under Win32 multitasking, the highest priority thread will always have unconditional access to the

processor.

d D. Keyboard and mouse events are handled asynchronously.


2. Which of the following is not a standard Win32 GUI resource type?

d A. Version Information

d B. Device Context

d C. Accelerator

d D. Cursor


3. Which of the following is a required function for all Windows-based applications?

d A. WinMain

d B. WndMgr

dd C. MyWndProc

d D. GetMenu


4. When WinMain calls the API RegisterClass function, the following data structure is registered:

d A. MSG

d B. WNDCLASS

d C. PAINTSTRUCT

ddd D. RECT

No comments:

Post a Comment