You are on page 1of 296

VISUAL PROGRAMMING

NOTES
1 ANNA UNIVERSITY CHENNAI
UNIT I
WINDOWS PROGRAMMING
1.1 INTRODUCTION
This unit aims to be a comprehensive source for any developer who is interested in
programming for the Windows platform (Microsoft Windows 98, Microsoft Windows NT
4.0, and Windows NT 5.0). It starts at the lowest level, with the Win32 API (C and VB
Classic) and then goes over to MFC (C++).
There are two prerequisites for using this material. The programs are written in the C
programming language and use the native Windows application programming interfaces
(APIs). Hence, the reader is assumed to have a previous knowledge of the programming
languages involved. Specifically, prior knowledge in C, C++, and Visual Basic is required.
Secondly you should have installed on your machine a 32-bit C compiler and
development environment suitable for doing Windows programming (Microsoft Visual C++
6.0).
1.2 LEARNING OBJECTIVES
1. Understand the choices presented to users when installing Visual C++6.0.
2. Know the essentials of windows programming model.
3. Understand the various windows data types.
4. Writing simple window programs.
5. Know how to handle GDIs and to program using various GDI objects.
1.3 INSTALLING THE VISUAL C++ DEVELOPMENT TOOLS
In this section, you will learn about the options offered by Microsoft Visual Studio
6.0 when installing the Enterprise Edition of Visual C++6.0 using a custom installation.
The installation setup program is a good place to gain an overview of the features offered
by the Visual C++development environment, as it groups together all the installable options
that are available to you in one logically organized, browsable location.
DMC 1944
NOTES
2 ANNA UNIVERSITY CHENNAI
1.3.1 Microsoft Visual C++ Installation
Visual C++comes as part of the Visual Studio development suite or as a stand-alone
product. In either case, you start the installation process by running the Setup.exe file from
the root directory of the CD.
NOTE: If you are using Windows NT 4.0, you will need to install the Windows NT
Service Pack 3 before you can install Visual C++.
First you will be presented with a dialog box providing you with the opportunity to
browse the Readme file. This file contains important information that will likely impact your
development effort, so you should at least scan its contents.
Figure 1.1 The Visual Studio Custom Setup screen
Next, you will be presented with the user license agreement. Once you have read and
accepted the user license agreement and entered your product number and user ID, you
will be taken to a dialog box that presents you with setup options. At this point, choose a
Custom setup and click Next.
On the screen that appears, accept the default installation location by clicking Next.
The setup process will begin. Read the information screens and click Next until you arrive
at the Custom Setup screen, shown in Figure 1.1. (This figure displays the Visual Studio
version of this screen, which shows options to install the other products in the Visual
Studio suite.)
If you already have Visual C++installed, youll want to get to the maintenance dialog
box that allows you to add or remove components for your current installation. You access
this dialog box by selecting the Workstation option. This maintenance dialog box is identical
to the setup screen, so you can use it to explore the installation options.
VISUAL PROGRAMMING
NOTES
3 ANNA UNIVERSITY CHENNAI
The custom setup screen appears with a default set of installation options selected,
which you can change as required. A check mark next to an installation option means that
the option will be installed. Many of the options are arranged in a hierarchical order. If one
of the items in the Options list is selected and the Change Option button is made available,
you can click it to reveal further sub-options beneath the currently selected option. OK
and Cancel can be used to move up the option hierarchy, saving or discarding the changes
you have made to the option selection on each screen.
If an option check box is selected but shaded, only some of its suboptions are selected,
meaning that only some of its options will be installed.
The following exercise shows you how to use the Custom Setup or Maintenance
screen to configure your installation options:
1. In the Options list of the Custom Setup or Maintenance screen, select the
Microsoft Visual C++ 6.0 option as shown in Figure 1.1.
2. Click the Change Option button.
3. In the Options list, select the VC++ Runtime Libraries option. Click the Change
Option button.
4. If you would like to have the CRT library source code available, and you can
spare the half-megabyte of disk space that this option requires, select the check
box next to that option.
5. If you have changed any of the options that are currently displayed in the Options
list and you want to save the changes, click OK to revert to the previous screen in
the hierarchy. Otherwise, click Cancel to leave the options as they were.
6. When you have finished configuring the options, return to the main Custom Setup
or Maintenance screen, and proceed with the installation by clicking the Continue
button. To abandon the installation, click Cancel.
1.3.2 Completing the Installation
After you have configured your installation by selecting the appropriate options from
the main and sub installation screens, you click the button labeled Continue to start installing
the software. You will be prompted to reboot your computer to complete the installation.
After the reboot, you will be prompted to install the version of the Microsoft Developers
Network (MSDN) library that comes with your copy of Visual C++. You should do this,
as the MSDN library is the means by which online Help and documentation are provided
for Visual C++.
1.4 THE WINDOWS ENVIRONMENT
Windows is a Graphical User Interface (GUI). It uses graphics to organize the users
workspace. Users choose items and execute programs by pointing and clicking with a
mouse. The program that run from within Windows also have a Graphical User Interface
DMC 1944
NOTES
4 ANNA UNIVERSITY CHENNAI
(GUI); for example, MS-Excel and MS-Word. Moreover these programs can run only
within Windows. This is because Windows provides these programs with a number of built
in functions and data which are not available in other environments. The functions that are
provided by windows include functions with the functionality to draw text in different sizes
and styles using font data. Windows provides a broad range of graphical functions for
drawing lines and geometric shapes and changing color. Windows program make use of
these built in functions and do not have to be coded to perform these tasks. These system
defined functions that an application can call are provided by an interface known as the
Application Program Interface (API) Every Windows environment has its unique API. For
example, the API that Windows 95 supports (also called the Win32 interface) is a 32-bit
API. All the functions supported by the API can work with 32 bits of information at any
given time. Writing programs for the Windows environment using the API functions is
referred to as SDK programming where SDK stands for Software Development Kit.
1.5 THE WINDOWS PROGRAMMING MODEL EVENT DRIVEN
PROGRAMMING
Programs written for traditional operating environments use a procedural programming
model in which programs execute from top to bottom in an orderly fashion. The path taken
from start to finish may vary with each invocation of the program depending on the input it
receives or the conditions under which it is run, but the path remains fairly predictable. In
a C program, execution begins with the first line in the function named main and ends
when main returns. In between, main might call other functions and these functions might
call even more functions, but ultimately it is the programnot the operating systemthat
determines what gets called and when.
Windows programs operate differently. They use the event-driven programming model
illustrated in Figure 1.2, in which applications respond to events by processing messages
sent by the operating system. An event could be a keystroke, a mouse click, or a command
for a window to repaint itself, among other things. The entry point for a Windows program
is a function named WinMain, but most of the action takes place in a function known as the
window procedure. The window procedure processes messages sent to the window.
WinMain creates that window and then enters a message loop, alternately retrieving
messages and dispatching them to the window procedure. Messages wait in a message
queue until they are retrieved. A typical Windows application performs the bulk of its
processing in response to the messages it receives, and in between messages, it does little
except wait for the next message to arrive.
VISUAL PROGRAMMING
NOTES
5 ANNA UNIVERSITY CHENNAI
Figure 1.2 The Windows programming model.
The message loop ends when a WM_QUIT message is retrieved from the message
queue, signaling that its time for the application to end. This message usually appears
because the user selected Exit from the File menu, clicked the close button (the small
button with an X in the windows upper right corner), or selected Close from the windows
system menu. When the message loop ends, WinMain returns and the application terminates.
The window procedure typically calls other functions to help process the messages it
receives. It can call functions local to the application, or it can call API functions provided
by Windows. API functions are contained in special modules known as dynamic-link
libraries, or DLLs. The Win32 API includes hundreds of functions that an application can
call to perform various tasks such as creating a window, drawing a line, and performing file
input and output. In C, the window procedure is typically implemented as a monolithic
function containing a large switch statement with cases for individual messages. The code
provided to process a particular message is known as a message handler. Messages that
an application doesnt process are passed on to an API function named DefWindowProc,
which provides default responses to unprocessed messages.
Incoming messages
WM_PAINT
WM_SIZE WM_KEYDOWN
WM_COMMAND
Message queue
Retrieved messages
Application
Winmain
Message
loop
Window
procedure
Dispatched messages
Message handler Message handler
Message handler Message handler
Message handler Message handler
DefWindowProc
Unprocessed messages
WM_LBUTTONDOWN
DMC 1944
NOTES
6 ANNA UNIVERSITY CHENNAI
1.5.1 Messages
Windows defines hundreds of different message types. Most messages have names
that begin with the letters WM and an underscore, as in WM_CREATE and
WM_PAINT. These messages can be classified in various ways, but for the moment
classification is not nearly as important as realizing the critical role messages play in the
operation of an application. The following table shows 10 of the most common messages.
A window receives a WM_PAINT message, for example, when its interior needs repainting.
One way to characterize a Windows program is to think of it as a collection of message
handlers. To a large extent, it is a programs unique way of responding to messages that
gives it its personality.
Table 1.1 Common Windows Messages
A message manifests itself in the form of a call to a windows window procedure.
Bundled with the call are four input parameters: the handle of the window to which the
message is directed, a message ID, and two 32-bit parameters known as wParam and
lParam. The window handle is a 32-bit value that uniquely identifies a window. Internally,
the value references a data structure in which Windows stores relevant information about
the window such as its size, style, and location on the screen. The message ID is a numeric
value that identifies the message type: WM_CREATE, WM_PAINT, and so on. wParam
and lParam contain information specific to the message type. When a
WM_LBUTTONDOWN message arrives, for example, wParam holds a series of bit
flags identifying the state of the Ctrl and Shift keys and of the mouse buttons. lParam
holds two 16-bit values identifying the location of the mouse pointer when the click occurred.
Together, these parameters provide the window procedure with all the information it needs
to process the WM_LBUTTONDOWN message.
1.5.2 Windows Programming, SDK-Style
To understand the programming for Windows lets see what the source code for a
simple Windows program looks like. The program 1.1 creates a window and responds to
Message Sent When
WM_CHAR A character is input from the keyboard.
WM_COMMAND The user selects an item from a menu, or a control
sends a notification to its parent.
WM_CREATE A window is created.
WM_DESTROY A window is destroyed.
WM_LBUTTONDOWN The left mouse button is pressed.
WM_LBUTTONUP The left mouse button is released.
WM_MOUSEMOVE The mouse pointer is moved.
WM_PAINT A window needs repainting.
WM_QUIT The application is about to terminate.
WM_SIZE A window is resized.
VISUAL PROGRAMMING
NOTES
7 ANNA UNIVERSITY CHENNAI
WM_PAINT messages by drawing an ellipse in the windows upper left corner. This code
is similar to the source code youll find in courses such as Charles Petzolds Programming
Windows (1998, Microsoft Press) and other courses that teach Windows programming in
C.
Program 1.1. C source code for a simple Windows program.
#include <windows.h>
LONG WINAPI WndProc (HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpszCmdLine, int nCmdShow)
{
WNDCLASS wc;
HWND hwnd;
MSG msg;
wc.style =0; // Class style
wc.lpfnWndProc =(WNDPROC) WndProc; // Window procedure address
wc.cbClsExtra =0; // Class extra bytes
wc.cbWndExtra =0; // Window extra bytes
wc.hInstance =hInstance; // Instance handle
wc.hIcon =LoadIcon (NULL, IDI_WINLOGO); // Icon handle
wc.hCursor =LoadCursor (NULL, IDC_ARROW); // Cursor handle
wc.hbrBackground =(HBRUSH) (COLOR_WINDOW +1); // Background color
wc.lpszMenuName =NULL; // Menu name
wc.lpszClassName =MyWndClass; // WNDCLASS name
RegisterClass (&wc);
hwnd =CreateWindow (
MyWndClass, // WNDCLASS name
SDK Application, // Window title
WS_OVERLAPPEDWINDOW,// Window style
CW_USEDEFAULT, // Horizontal position
CW_USEDEFAULT, // Vertical position
CW_USEDEFAULT, // Initial width
CW_USEDEFAULT, // Initial height
HWND_DESKTOP, // Handle of parent window
NULL, // Menu handle
hInstance, // Applications instance handle
NULL // Window-creation data
);
DMC 1944
NOTES
8 ANNA UNIVERSITY CHENNAI
ShowWindow (hwnd, nCmdShow);
UpdateWindow (hwnd);
while (GetMessage (&msg, NULL, 0, 0)) {
TranslateMessage (&msg);
DispatchMessage (&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam,
LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
switch (message) {
case WM_PAINT:
hdc =BeginPaint (hwnd, &ps);
Ellipse (hdc, 0, 0, 200, 100);
EndPaint (hwnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage (0);
return 0;
}
return DefWindowProc (hwnd, message, wParam, lParam);
}
WinMain begins by calling the API function RegisterClass to register a window
class. The window class defines important characteristics of a window such as its window
procedure address, its default background color, and its icon. These and other properties
are defined by filling in the fields of a WNDCLASS structure, which is subsequently passed
to RegisterClass. An application must specify a window class when it creates a window,
and a class must be registered before it can be used. Thats why RegisterClass is called at
the outset of the program. Keep in mind that a WNDCLASS-type window class is not the
same as a C++window class. The term window class will refer to C++classes derived
from MFCs CWnd class.
The WNDCLASS structure includes two fields that are pointers to character strings,
so the structure is defined two different ways in the WINUSER.H header file.
Once the WNDCLASS is registered, WinMain calls the all-important CreateWindow
function to create the applications window. The first parameter to CreateWindow is the
VISUAL PROGRAMMING
NOTES
9 ANNA UNIVERSITY CHENNAI
name of the WNDCLASS from which the window will be created. The second parameter
is the text that will appear in the windows title bar. The third specifies the window style.
WS_OVERLAPPEDWINDOW is a commonly used style that creates a top-level window
with a resizing border, a title bar, a system menu, and buttons for minimizing, maximizing,
and closing the window.
The next four parameters specify the windows initial position and size.
CW_USEDEFAULT tells Windows to use default values for both. The final four parameters
specify, in order, the handle of the windows parent window (HWND_DESKTOP for an
applications main window); the handle of the menu associated with the window, if any; the
applications instance handle (a value that lets the programmer differentiate between the
program itself and the modulesthat is, DLLsthat it loads); and a pointer to application-
specific window-creation data.
The window that CreateWindow creates is not initially visible on the screen because
it was not created with the WS_VISIBLE style. (Had it been used, WS_VISIBLE would
have been combined with WS_OVERLAPPEDWINDOW in the call to CreateWindow.)
Therefore, WinMain follows CreateWindow with calls to ShowWindow and
UpdateWindow, which make the window visible and ensure that its WM_PAINT handler
is called immediately.
Next comes the message loop. In order to retrieve and dispatch messages, WinMain
executes a simple while loop that calls the GetMessage, TranslateMessage, and
DispatchMessage API functions repeatedly. GetMessage checks the message queue. If
a message is available, it is removed from the queue and copied to msg; otherwise,
GetMessage blocks on the empty message queue until a message is available. msg is an
instance of the structure MSG, whose fields contain pertinent message parameters such as
the message ID and the time at which the message was placed in the queue.
TranslateMessage converts a keyboard message denoting a character key to an easier-
to-use WM_CHAR message, and DispatchMessage dispatches the message to the
window procedure. The message loop executes until GetMessage returns 0, which happens
only when a WM_QUIT message is retrieved from the message queue. When this occurs,
WinMain ends and the program terminates.
Messages dispatched with DispatchMessage generate calls to the window procedure
WndProc. The sample program 1.1 processes just two message types, WM_PAINT and
WM_DESTROY; all other messages are passed to DefWindowProc for default processing.
A switch-case block inspects the message ID passed in themessage parameter and
executes the appropriate message handler. The WM_PAINT handler calls the BeginPaint
API function to obtain a device context handle before painting begins and the EndPaint
API function to release the handle when painting is finished. In between, the Ellipse API
function draws an ellipse that is 200 pixels wide and 100 pixels high. A device context
handle permits a Windows application to draw on the screen. Without it, functions such as
Ellipse wont work.
DMC 1944
NOTES
10 ANNA UNIVERSITY CHENNAI
The WM_DESTROY handler calls the PostQuitMessage API function to post a
WM_QUIT message to the message queue and ultimately cause the program to terminate.
The WM_DESTROY message is sent to a window just before it is destroyed. A top-level
window must call PostQuitMessage when it receives a WM_DESTROY message, or
else the message loop will not fall through and the program will never end.
1.6 HUNGARIAN NOTATION
Another aspect of program 1.1 is the variable naming convention, which it uses called
as Hungarian notation, in which each variable name begins with one or more lowercase
characters identifying the variables type: h for handle, n for integer, and so on. The table
1.2 below lists some of the commonly used Hungarian prefixes. Prefixes are often combined
to form other prefixes, as when p and sz are joined to form psz, which stands for pointer
to zero-terminated string.
Table 1.2 Common Hungarian Notation Prefixes
Many of the data types shown in the table 1.2 arent standard C/C++data types but
rather are special data types defined in the Windows header files. COLORREF, for
example, is the Windows data type for 24-bit RGB color values. A BOOL is a Boolean
data type that stores TRUE/FALSE values, while a DWORD is a 32-bit unsigned integer.
1.7 CREATING AND DISPLAYING THE WINDOW
There are three types of programming in VC++:
1. SDK programming
2. MFC based programming
3. Programming using Application Wizard
1.7.1 Creating a Simple Window
Lets start with the first type of programming and see how a simple window can be
created and hence learn the steps involved.
Prefix Data Type
b BOOL
c or ch char
clr COLORREF
cx, cy Horizontal or vertical distance
dw DWORD
h Handle
l LONG
n int
p Pointer
sz Zero-terminated string
w WORD
VISUAL PROGRAMMING
NOTES
11 ANNA UNIVERSITY CHENNAI
Program 1.2: Creating a simple window Using Microsoft Visual C++
1. Start the Microsoft Development Environment by clicking Start Programs
Microsoft Visual Studio 6.0 Microsoft Visual C++.
2. On the main menu, click File ->New... or File ->New ->Project...
3. In the New or New Project dialog box as shown in Figure1.3, click Win32
Application.
Figure 1.3. New Project Dialog Window
4. In the location, type the path where the application should be stored, such as
C:\Programs\MSVC
5. In the Name edit box, type the name of the application as Win32A and click OK.
6. In the next dialog box of the wizard (Figure1.4), click the An Empty Project
radio button.
7. Click Finish. You will be presented with another dialog box; in this case click OK
.
8. To create the first needed file of the program, on the main menu (refer Figure1.5),
click File ->New.
9. Click either C++Source File or C++File (.cpp)
10. In the Name edit box, replace the contents with a name for a file. In the case,
replace it with Main and press Enter.
DMC 1944
NOTES
12 ANNA UNIVERSITY CHENNAI
Figure 1.4. Step1 of 1 during Win32Application creation
Figure 1.5. Creating a new C++ Source file
11. Enter the following lines of code in the code window area:
#include windows.h
LRESULT CALLBACK WinProc(HWND, UINT, WPARAM, LPARAM);
TCHAR szAppName[] =TEXT(SDI Frame);
TCHAR szWinClass[] =TEXT(WIN_CLASS);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR lpCmdLine, int nCmdShow)
VISUAL PROGRAMMING
NOTES
13 ANNA UNIVERSITY CHENNAI
{
MSG msg; // a struct used in the passing of messages
WNDCLASS wc; // a window class struct, see below
HWND hwnd; // a handle-to-a-window, see below
wc.cbClsExtra =0; // specify how many bytes extra space is required for
// every window derived from this window class
wc.cbWndExtra=0; // specify how many bytes extra space is required for this
// window
wc.hbrBackground=(HBRUSH) GetStockObject(WHITE_BRUSH);
// background colour
wc.hCursor=LoadCursor(NULL, IDC_ARROW);
// cursor, this is usually the default
wc.hIcon=LoadIcon(NULL, IDI_APPLICATION);
// icon, this can be changed using resources
wc.hInstance=hInstance;
// the current instance of the program is passed to the
// instance of the class
wc.lpfnWndProc=WinProc;
// the window procedure used by this class, usually
// has a more distinguishing name
wc.lpszClassName=szWinClass;
// the name of this class
wc.lpszMenuName=NULL;
// the name of the menu to be attached to the window
wc.style=CS_HREDRAW | CS_VREDRAW;
// these class styles mean that the window will be
// redrawn whenever it is resized vertically or horizontally
if( !RegisterClass(&wc)) // register the class, and test if it fails
{
MessageBox(NULL, TEXT(Error registering class), TEXT(ERROR),
MB_OK);
return 0;
}
hwnd =CreateWindow(szWinClass,
// the class as specified in the one we just registered
szAppName,
// the title of the window
WS_OVERLAPPEDWINDOW,
// the window style (there are usually a lot more of these
CW_USEDEFAULT,
// the left co-ord of the window
CW_USEDEFAULT,
DMC 1944
NOTES
14 ANNA UNIVERSITY CHENNAI
// the top co-ord of the window
CW_USEDEFAULT,
// the width of the window
CW_USEDEFAULT,
// the height of the window
(HWND) NULL,
// a handle to the parent window
(HMENU) NULL,
// a handle to the windows menu
(HINSTANCE) hInstance,
// the instance of the window
(void *) NULL); // any extra information
// WM_CREATE message has been sent to the window
ShowWindow(hwnd, nCmdShow);
// shows the window, using the specified command
// (Maximised, Minimised, etc)
UpdateWindow(hwnd);
// the window is updated (a WM_PAINT message is sent
// to the window
while (GetMessage(&msg, (HWND) NULL, 0, 0))
// while there is a message to retrieve, and that message
// is not WM_QUIT
{
TranslateMessage(&msg); // some messages need translating
DispatchMessage(&msg); // send the message to the window
}
return msg.wParam; // return the message structs wParam
}
LRESULT CALLBACK WinProc(HWND hwnd, UINT msg, WPARAM wParam,
LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
switch(msg)
{
case WM_PAINT:
hdc =BeginPaint(hwnd, &ps);
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
/* takes care of all of the messages that we didnt catch
in our Window Procedure */
return DefWindowProc(hwnd, msg, wParam, lParam);
}
VISUAL PROGRAMMING
NOTES
15 ANNA UNIVERSITY CHENNAI
12. To execute the program first you must compile the program by pressing
Ctrl +F7.
13. Then build the EXE by pressing F7.
14. Finally when you execute the EXE by pressing Ctrl +F5, you can see an output as
given in Figure1.6:
Figure 1.6 Output Window for Program1.2
15. To close the window, click its system Close button and return to your
programming environment.
1.7.2 Display of a window
Once a window has been created and if this was done successfully, you can display
it to the user. This is done by calling the ShowWindow function. Its syntax is:
BOOL ShowWindow(HWND hWnd, int nCmdShow);
The hWnd argument is a handle to the window that you want to display. It could be
the window returned by the CreateWindow or the CreateWindowEx function.
The nCmdShow specifies how the window must be displayed. Its possible values are:
SW_SHOW Displays a window and makes it visible
SW_SHOWNORMAL Displays the window in its regular size. In most
circumstances, the operating system keeps track of
the last location and size a window such as Internet
Explorer or My Computer had the last time it was
displaying. This value allows the OS to restore it.
DMC 1944
NOTES
16 ANNA UNIVERSITY CHENNAI
SW_SHOWMINIMIZED Opens the window in its minimized state,
representing it as a button on the taskbar
SW_SHOWMAXIMIZED Opens the window in its maximized state
SW_SHOWMINNOACTIVE Opens the window but displays only its icon. It
does not make it active
SW_SHOWNA As previous
SW_SHOWNOACTIVATE Retrieves the windows previous size and location
and displays it accordingly
SW_HIDE Used to hide a window
SW_MINIMIZE Shrinks the window and reduces it to a button on the
taskbar
SW_MAXIMIZE Maximizes the window to occupy the whole screen
area
SW_RESTORE If the window was minimized or maximized, it
would be restored to its previous location and size
1.7.3 The Message Loop
After the UpdateWindow call, the window is fully visible on the video display. The
program must now make itself ready to read keyboard and mouse input from the user.
Windows maintains a message queue for each Windows program currently running under
Windows. When an input event occurs, Windows translates the event into a message
that it places in the programs message queue.
A program retrieves these messages from the message queue by executing a block of
code known as the message loop:
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
The GetMessage call that begins the message loop retrieves a message from the message
queue:
GetMessage (&msg, NULL, 0, 0)
VISUAL PROGRAMMING
NOTES
17 ANNA UNIVERSITY CHENNAI
This call passes to Windows a pointer to a MSG structure named msg. The second,
third, and fourth arguments are set to NULL or 0 to indicate that the program wants all
messages for all windows created by the program. Windows fills in the fields of the message
structure with the next message from the message queue. The fields of this structure are:
Hwnd - The handle to the window which the message is directed to. In the
HELLOWIN program, this is the same as the hwnd value returned from
CreateWindow, because thats the only window the program has.
message - The message identifier. This is a number that identifies the message. For
each message, there is a corresponding identifier defined in the Windows header
files (most of them in WINUSER.H) that begins with the identifier WM (window
message).
wParam - A 32-bit message parameter, the meaning and value of which depend
on the particular message.
lParam - Another 32-bit message parameter dependent on the message.
time - The time the message was placed in the message queue.
pt - The mouse coordinates at the time the message was placed in the message
queue.
If the message field of the message retrieved from the message queue is anything
except WM_QUIT, GetMessage returns a nonzero value. A WM_QUIT message causes
GetMessage to return 0.
The statement:
TranslateMessage (&msg) ;
passes the msg structure back to Windows for some keyboard translation. The statement
DispatchMessage (&msg) ;
again passes the msg structure back to Windows. Windows then sends the message to the
appropriate window procedure for processing. What this means is that Windows calls the
window procedure. In program1.2, the window procedure is WndProc. After WndProc
processes the message, it returns control to Windows, which is still servicing the
DispatchMessage call. When Windows returns to HELLOWIN following the
DispatchMessage call, the message loop continues with the next GetMessage call.
1.7.4 The Window Procedure
Till the previous section we witnessed how the window class has been registered, the
window has been created, the window has been displayed on the screen, and the program
has entered a message loop to retrieve messages from the message queue.
DMC 1944
NOTES
18 ANNA UNIVERSITY CHENNAI
The window procedure determines what the window displays in its client area and
how the window responds to user input.
In program1.2 the window procedure is the function named WndProc. A Windows
program can contain more than one window procedure. A window procedure is always
associated with a particular window class that you register by calling RegisterClass. The
CreateWindow function creates a window based on a particular window class. More than
one window can be created based on the same window class.
A window procedure is always defined like this:
LRESULT CALLBACK WndProc (HWND hwnd, UINT msg, WPARAM wParam,
LPARAM lParam)
The four parameters to the window procedure are identical to the first four fields of
the MSG structure. The first parameter is hwnd, the handle to the window receiving the
message. This is the same handle returned from the CreateWindow function.
The second parameter is the same as the msg field in the MSG structure. Its a
number that identifies the message. The last two parameters are 32-bit message parameters
that provide more information about the message. What these parameters contain is specific
to each type of message. Sometimes a message parameter is two 16-bit values stuck
together, and sometimes a message parameter is a pointer to a text string or to a data
structure.
Programs generally dont call window procedures directly. The window procedure is
almost always called from Windows itself. A program can indirectly call its own window
procedure by calling a function named SendMessage, which well examine in later.
1.7.5 Processing the Messages
Every message that a window procedure receives is identified by a number, which is
the message parameter to the window procedure. The Windows header file WINUSER.H
defines identifiers beginning with the prefix WM (window message) for each type of
message.
Generally, Windows programmers use a switch and case construction to determine
what message the window procedure is receiving and how to process it accordingly. When
a window procedure processes a message, it should return 0 from the window procedure.
All messages that a window procedure chooses not to process must be passed to a
Windows function named DefWindowProc. The value returned from DefWindowProc
must be returned from the window procedure.
In program1.2, WndProc chooses to process only two messages: WM_PAINT,
and WM_DESTROY. The window procedure is structured like this:
VISUAL PROGRAMMING
NOTES
19 ANNA UNIVERSITY CHENNAI
switch (msg)
{
case WM_PAINT:
hdc =BeginPaint(hwnd, &ps);
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc (hwnd, msg, wParam, lParam) ;
The BeginPaint and EndPaint functions are necessary for painting the window which
will be explored in the next subsection of this chapter. It is important to call DefWindowProc
for default processing of all messages that your window procedure does not process.
Otherwise behavior regarded as normal, such as being able to terminate the program, will
not work.
1.7.5.1 The WM_PAINT Message
The first message that WndProc processes is WM_PAINT. This message is extremely
important in Windows programming. It informs a program when part or all of the windows
client area is invalid and must be updated, which means that it must be redrawn or
painted.
How does a client area become invalid? When the window is first created, the entire
client area is invalid because the program has not yet drawn anything on the window. The
first WM_PAINT message (which normally occurs when the program calls UpdateWindow
in WinMain) directs the window procedure to draw something on the client area.
When you move windows around the screen so that they overlap, Windows does not
save the area of a window covered by another window. When that area of the window is
later uncovered, it is flagged as invalid. The window procedure receives a WM_PAINT
message to repaint the contents of the window.
WM_PAINT processing almost always begins with a call to BeginPaint:
hdc =BeginPaint (hwnd, &ps) ;
and ends with a call to EndPaint:
EndPaint (hwnd, &ps) ;
DMC 1944
NOTES
20 ANNA UNIVERSITY CHENNAI
In both cases, the first argument is a handle to the programs window, and the second
argument is a pointer to a structure of type PAINTSTRUCT. The PAINTSTRUCT structure
contains some information that a window procedure can use for painting the client area.
The fields of this structure will be discussed later in this unit; for now, well just use it in the
BeginPaint and EndPaint functions.
During the BeginPaint call, Windows erases the background of the client area if it
hasnt been erased already. It erases the background using the brush specified in the
hbrBackground field of the WNDCLASS structure used to register the window class. In
the case of HELLOWIN, this is a stock white brush, which means that Windows erases
the background of the window by coloring it white. The BeginPaint call validates the
entire client area and returns a handle to a device context. A device context refers to a
physical output device (such as a video display) and its device driver. You need the device
context handle to display text and graphics in the client area of a window. Using the device
context handle returned from BeginPaint, you cannot draw outside the client area, even if
you try. EndPaint releases the device context handle so that it is no longer valid.
If a window procedure does not process WM_PAINT messages (which is very
rare), they must be passed on to DefWindowProc. DefWindowProc simply calls
BeginPaint and EndPaint in succession so that the client area is validated.
After WndProc calls BeginPaint, it calls GetClientRect:
GetClientRect (hwnd, &rect) ;
The first argument is the handle to the programs window. The second argument is a
pointer to a rectangle structure of type RECT. This structure has four LONG fields named
left, top, right, and bottom. The GetClientRect function sets these four fields to the
dimensions of the client area of the window. The left and top fields are always set to 0.
Thus, the right and bottom fields represent the width and height of the client area in pixels.
Whenever the client area becomes invalid (as it does when you change the size of the
window), WndProc receives a new WM_PAINT message. WndProc obtains the updated
window size by calling GetClientRect and again displays the window.
1.7.5.2 The WM_DESTROY Message
The WM_DESTROY message is another important message. This message indicates
that Windows is in the process of destroying a window based on a command from the
user. The message is a result of the user clicking on the Close button or selecting Close
from the programs system menu.
Program1.2 responds to the WM_DESTROY message in a standard way by calling
PostQuitMessage(0) ;
VISUAL PROGRAMMING
NOTES
21 ANNA UNIVERSITY CHENNAI
This function inserts a WM_QUIT message in the programs message queue. I
mentioned earlier that GetMessage returns nonzero for any message other than WM_QUIT
that it retrieves from the message queue. When GetMessage retrieves a WM_QUIT
message, GetMessage returns 0. This causes WinMain to drop out of the message loop.
The program then executes the following statement:
return msg.wParam ;
The wParam field of the structure is the value passed to the PostQuitMessage
function (generally 0). The return statement exits from WinMain and terminates the program.
1.8 DATA TYPES
The data types supported by Microsoft Windows are used to define function return
values, function and message parameters, structure members and variables. They define
the size and meaning of these elements. The following list is a few but the most frequently
used data types:
ATOM - Atom. This type is declared in windef.h as follows:
typedef WORD ATOM;
BOOL - Boolean variable (should be TRUE or FALSE). This type
is declared in windef.h as follows: typedef int BOOL;
BOOLEAN - Boolean variable (should be TRUE or FALSE). This type
is declared in winnt.h as follows: typedef
BYTE BOOLEAN;
BYTE - Byte (8 bits). This type is declared in windef.h as follows:
typedef unsigned char BYTE;
CHAR - 8-bit Windows (ANSI) character. This type is declared
in winnt.h as follows: typedef char CHAR;
DWORD - 32-bit unsigned integer. This type is declared in
windef.h as follows: typedef unsigned long DWORD;
FLOAT - Floating-point variable. This type is declared in
windef.h as follows: typedef float FLOAT;
HANDLE - Handle to an object. This type is declared in winnt.h
as follows: typedef PVOID HANDLE;
HDC - Handle to a device context (DC). This type is
declared in windef.h as follows: typedef
HANDLE HDC;
HWND - Handle to a window. This type is declared in windef.h
as follows: typedef HANDLE HWND;
DMC 1944
NOTES
22 ANNA UNIVERSITY CHENNAI
INT - 32-bit signed integer. This type is declared in
windef.h as follows: typedef int INT;
LONG - 32-bit signed integer. This type is declared in winnt.h
as follows: typedef long LONG;
LONG_PTR - A signed long type for pointer precision. Use when casting
a pointer to a long to perform pointer arithmetic.
LRESULT - Signed result of message processing.
This type is declared in WinDef.h as follows:
typedef LONG_PTR LRESULT;
TCHAR - A WCHAR if UNICODE is defined, a CHAR otherwise.
This type is declared in WinNT.h
UINT - An unsigned INT. The range is 0 through 4294967295
decimal. This type is declared in WinDef.h as follows:
typedef unsigned int UINT;
WINAPI - The calling convention for system functions. This type is
declared in WinDef.
WPARAM - A message parameter. This type is declared in WinDef.h as
follows: typedef UINT_PTR WPARAM;
The exhaustive list of data types are given in http://msdn.microsoft.com/ . Readers
can refer to this official web page for more information.
1.9 RESOURCES
Resources are data that you can add to the applications executable file. Resources
can be:
standard - icon, cursor, menu, dialog box, bitmap, enhanced metafile, font,
accelerator table, message-table entry, string-table entry, or version.
custom - any kind of data that doesnt fall into the previous category (for example
a mp3 file or a dictionary database).
In Microsoft Windows, resources are read-only data embedded in EXE, DLL,
CPL or (beginning with Windows Vista) MUI files.
1.10 AN INTRODUCTION TO GDI
The Microsoft Windows graphics device interface (GDI) enables applications to use
graphics and formatted text on both the video display and the printer. Windows-based
applications do not access the graphics hardware directly. Instead, GDI interacts with
device drivers on behalf of applications.
VISUAL PROGRAMMING
NOTES
23 ANNA UNIVERSITY CHENNAI
There are functions to format and draw text in an applications client area and on a
page of printer paper. These functions can be divided into two categories: those that format
the text (or prepare it for output) and those that actually draw the text. The formatting
functions align text, set the intercharacter spacing, set the text and text-background colors,
and justify text. The drawing functions draw individual characters (or symbols) or entire
strings of text.
1.10.1 The Device Context
A handle, youll recall, is simply a number that Windows uses for internal reference to
an object. You obtain the handle from Windows and then use the handle in other functions.
The device context handle is your windows passport to the GDI functions. With that
device context handle you are free to paint your client area and make it as beautiful or as
ugly as you like.
The device context (also called simply the DC) is really just a data structure maintained
internally by GDI. A device context is associated with a particular display device, such as
a video display or a printer. For a video display, a device context is usually associated with
a particular window on the display.
Some of the values in the device context are graphics attributes. These attributes
define some particulars of how GDI drawing functions work. When a program needs to
paint, it must first obtain a handle to a device context. When you obtain this handle, Windows
fills the internal device context structure with default attribute values.
After a program has finished painting its client area, it should release the device context
handle. When a program releases the handle, the handle is no longer valid and must not be
used. The program should obtain the handle and release the handle during the processing
of a single message. Except for a device context created with a call to CreateDC, you
should not keep a device context handle around from one message to another.
Windows applications generally use two methods for getting a device context handle
in preparation for painting the screen.
1.10.1.1 Getting a Device Context Handle: Method One
You use this method when you process WM_PAINT messages. Two functions are
involved: BeginPaint and EndPaint. These two functions require the handle to the window,
which is passed to the window procedure as an argument, and the address of a structure
variable of type PAINTSTRUCT, which is defined in the WINUSER.H header file. Windows
programmers usually name this structure variable ps and define it within the window
procedure like so:
PAINTSTRUCT ps ;
DMC 1944
NOTES
24 ANNA UNIVERSITY CHENNAI
While processing a WM_PAINT message, the window procedure first calls
BeginPaint. The BeginPaint function generally causes the background of the invalid region
to be erased in preparation for painting. The function also fills in the fields of the ps structure.
The value returned from BeginPaint is the device context handle. This is commonly saved
in a variable named hdc. You define this variable in your window procedure like so:
HDC hdc ;
The HDC data type is defined as a 32-bit unsigned integer. The program may then
use GDI functions, such as TextOut, that require the handle to the device context. A call to
EndPaint releases the device context handle.
Typically, processing of the WM_PAINT message looks like this:
case WM_PAINT:
hdc =BeginPaint (hwnd, &ps) ;
[use GDI functions]
EndPaint (hwnd, &ps) ;
return 0 ;
The window procedure must call BeginPaint and EndPaint as a pair while processing
the WM_PAINT message. If a window procedure does not process WM_PAINT
messages, it must pass the WM_PAINT message to DefWindowProc, which is the default
window procedure located in Windows. DefWindowProc processes WM_PAINT
messages with the following code:
case WM_PAINT:
BeginPaint (hwnd, &ps) ;
EndPaint (hwnd, &ps) ;
return 0 ;
The sequence of BeginPaint and EndPaint calls with nothing in between validates
the previously invalid region.
Windows places a WM_PAINT message in the message queue because part of the
client area is invalid. Unless you call BeginPaint and EndPaint (or ValidateRect), Windows
will not validate that area. Instead, Windows will send you another WM_PAINT message,
and another, and another, and another.
1.10.1.2 The Paint Information Structure
The paint information structure is defined as PAINTSTRUCT structure, which
contains information that can be used to paint the client area of a window. The structure is
defined as follows:
VISUAL PROGRAMMING
NOTES
25 ANNA UNIVERSITY CHENNAI
typedef struct tagPAINTSTRUCT
{
HDC hdc ;
BOOL fErase ;
RECT rcPaint ;
BOOL fRestore ;
BOOL fIncUpdate ;
BYTE rgbReserved[32] ;
} PAINTSTRUCT ;
Windows fills in the fields of this structure when your program calls BeginPaint. Your
program can use only the first three fields. The others are used internally by Windows. The
hdc field is the handle to the device context. In a redundancy typical of Windows, the value
returned from BeginPaint is also this device context handle. In most cases, fErase will be
flagged FALSE (0), meaning that Windows has already erased the background of the
invalid rectangle. This happens earlier in the BeginPaint function. (If you want to do some
customized background erasing in your window procedure, you can process the
WM_ERASEBKGND message.) Windows erases the background using the brush specified
in the hbrBackground field of the WNDCLASS structure that you use when registering
the window class during WinMain initialization. Many Windows programs specify a white
brush for the window background. This is indicated when the program sets up the fields of
the window class structure with a statement like this:
wndclass.hbrBackground =(HBRUSH) GetStockObject (WHITE_BRUSH) ;
However, if your program invalidates a rectangle of the client area by calling
InvalidateRect, the last argument of the function specifies whether you want the background
erased. If this argument is FALSE (that is, 0), Windows will not erase the background and
the fErase field of the PAINTSTRUCT structure will be TRUE (nonzero) after you call
BeginPaint.
The rcPaint field of the PAINTSTRUCT structure is a structure of type RECT. The
RECT structure defines a rectangle with four fields named left, top, right, and bottom.
The rcPaint field in the PAINTSTRUCT structure defines the boundaries of the invalid
rectangle, as shown in Figure 1.7. The values are in units of pixels relative to the upper left
corner of the client area. The invalid rectangle is the area that you should repaint.
DMC 1944
NOTES
26 ANNA UNIVERSITY CHENNAI
Figure 1.7. The boundaries of the invalid rectangle.
The rcPaint rectangle in PAINTSTRUCT is not only the invalid rectangle; it is also a
clipping rectangle. This means that Windows restricts painting to within the clipping
rectangle. More precisely, if the invalid region is not rectangular, Windows restricts painting
to within that region.
To paint outside the update rectangle while processing WM_PAINT messages, you
can make this call:
InvalidateRect (hwnd, NULL, TRUE) ;
before calling BeginPaint. This invalidates the entire client area and causes BeginPaint
to erase the background. A FALSE value in the last argument will not erase the background.
Whatever was there will stay.
1.10.1.3 Getting a Device Context Handle: Method Two
Although it is best to structure your program so that you can update the entire client
area during the WM_PAINT message, you may also find it useful to paint part of the client
area while processing messages other than WM_PAINT. Or you may need a device
context handle for other purposes, such as obtaining information about the device context.
To get a handle to the device context of the client area of the window, you call
GetDC to obtain the handle and ReleaseDC after youre done with it:
hdc =GetDC (hwnd) ;
[use GDI functions]
ReleaseDC (hwnd, hdc) ;
Like BeginPaint and EndPaint, the GetDC and ReleaseDC functions should be
called in pairs. When you call GetDC while processing a message, you should call
ReleaseDC before you exit the window procedure. Do not call GetDC in one message
and ReleaseDC in another.
VISUAL PROGRAMMING
NOTES
27 ANNA UNIVERSITY CHENNAI
Unlike the device context handle returned from BeginPaint, the device context handle
returned from GetDC has a clipping rectangle equal to the entire client area. You can paint
on any part of the client area, not merely on the invalid rectangle. Unlike BeginPaint,
GetDC does not validate any invalid regions. If you need to validate the entire client area,
you can call
ValidateRect (hwnd, NULL) ;
Generally, youll use the GetDC and ReleaseDC calls in response to keyboard
messages (such as in a word processing program) or mouse messages (such as in a drawing
program). This allows the program to draw on the client area in prompt reaction to the
users keyboard or mouse input without deliberately invalidating part of the client area to
generate WM_PAINT messages. However, even if you paint during messages other than
WM_PAINT, your program must still accumulate enough information to be able to update
the display whenever you do receive a WM_PAINT message.
A function similar to GetDC is GetWindowDC. While GetDC returns a device context
handle for writing on the client area of the window, GetWindowDC returns a device context
handle that lets you write on the entire window. For example, your program can use the
device context handle returned from GetWindowDC to write on the windows title bar.
However, your program would also have to process WM_NCPAINT (nonclient paint)
messages as well.
1.11 TEXT OUTPUT
Windows provides several GDI functions for writing text strings to the client area of
the window. The most commonly used text output function is TextOut. Text output is the
most common type of graphic output found within the client area. This function has the
following format:
TextOut (hdc, x, y, psText, iLength) ;
TextOut writes a character string to the client area of the window. The first argument
to TextOut function is the handle to the device contexteither the hdc value returned
from GetDC or the hdc value returned from BeginPaint during processing of a
WM_PAINT message.
The psText argument is a pointer to a character string, and iLength is the number of
characters in the string. If psText points to a Unicode character string, then the number of
bytes in the string is double the iLength value. The string should not contain any ASCII
control characters such as carriage returns, linefeeds, tabs, or backspaces. Windows displays
these control characters as boxes or solid blocks. TextOut does not recognize a zero byte
(or for Unicode, a zero short integer) as denoting the end of a string. The function uses the
iLength argument to determine the strings length.
DMC 1944
NOTES
28 ANNA UNIVERSITY CHENNAI
The x and y arguments to TextOut define the starting point of the character string
within the client area. The x value is the horizontal position; the y value is the vertical
position. The upper left corner of the first character is positioned at the coordinate point
(x, y). In the default device context, the origin (that is, the point where x and y both equal
0) is the upper left corner of the client area. If you use zero values for x and y in TextOut,
the character string starts flush against the upper left corner of the client area.
Now let us examine a program that uses TextOut function to draw text inside the client
area of the window.
Program 1.3: To draw a Text on the client area of the window.
1. Start the Microsoft Development Environment by clicking Start Programs
Microsoft Visual Studio 6.0 Microsoft Visual C++.
2. On the main menu, click File ->New... or File ->New ->Project...
3. In the New or New Project dialog box, click either Win32 Application.
4. In the location, type the path where the application should be stored, such as
C:\Programs\MSVC
5. In the Name edit box, type the name of the application as TextDraw and click
OK.
6. In the next dialog box of the wizard, click the An Empty Project radio button.
7. Click Finish. You will be presented with another dialog box; in this case click OK.
8. To create the first needed file of the program, on the main menu, click File ->
New.
9. In the Name edit box, replace the contents with a name for a file. In the case,
replace it with Main and press Enter.
10. Enter the following lines of code in the code window area:
#include <windows.h>
LRESULT CALLBACK WindProcedure(HWND hWnd, UINT Msg,
WPARAM wParam, LPARAM lParam);
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX WndCls;
static char szAppName[] =GDI Suite;
MSG Msg;
WndCls.cbSize =sizeof(WndCls);
WndCls.style =CS_OWNDC | CS_VREDRAW | CS_HREDRAW;
WndCls.lpfnWndProc =WindProcedure;
WndCls.cbClsExtra =0;
WndCls.cbWndExtra =0;
WndCls.hInstance =hInstance;
VISUAL PROGRAMMING
NOTES
29 ANNA UNIVERSITY CHENNAI
WndCls.hIcon =LoadIcon(NULL, IDI_APPLICATION);
WndCls.hCursor =LoadCursor(NULL, IDC_ARROW);
WndCls.hbrBackground =(HBRUSH)GetStockObject(WHITE_BRUSH);
WndCls.lpszMenuName =NULL;
WndCls.lpszClassName =szAppName;
WndCls.hIconSm =LoadIcon(hInstance, IDI_APPLICATION);
RegisterClassEx(&WndCls);
CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
szAppName,
GDI Drawing Text,
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
while( GetMessage(&Msg, NULL, 0, 0) )
{
TranslateMessage(&Msg);
DispatchMessage( &Msg);
}
return static_cast<int>(Msg.wParam);
}
LRESULT CALLBACK WindProcedure(HWND hWnd, UINT Msg,
WPARAM wParam, LPARAM lParam)
{
HDC hDC;
PAINTSTRUCT Ps;
COLORREF clrRed =RGB(255, 25, 5);
COLORREF clrBlue =RGB(12, 25, 255);
switch(Msg)
{
case WM_DESTROY:
PostQuitMessage(WM_QUIT);
break;
DMC 1944
NOTES
30 ANNA UNIVERSITY CHENNAI
case WM_PAINT:
hDC =BeginPaint(hWnd, &Ps);
SetTextColor(hDC, clrRed);
TextOut(hDC, 50, 42, Anna University, 15);
SetTextColor(hDC, clrBlue);
TextOut(hDC, 50, 80, One Among the top ten Universities
in India, 43);
EndPaint(hWnd, &Ps);
break;
default:
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
return 0;
}
12. To execute the program first you must compile the program by pressing Ctrl +F7.
13. Then build the EXE by pressing F7.
14. Finally when you execute the EXE by pressing Ctrl +F5, you can see an output as
given in Figure 1.8.
Figure1.8 Drawing Text
15. To close the window, click its system Close button and return to your
programming environment.
1.12 SCROLL BARS
Scroll bars are one of the best features of a graphical user interface. They are easy to
use and provide excellent visual feedback.
A window can display a data object, such as a document or a bitmap, that is larger
than the windows client area. When provided with a scroll bar, the user can scroll a data
object in the client area to bring into view the portions of the object that extend beyond the
borders of the window.
VISUAL PROGRAMMING
NOTES
31 ANNA UNIVERSITY CHENNAI
Scroll bars should be included in any window for which the content of the client area
extends beyond the windows borders. A scroll bars orientation determines the direction
in which scrolling occurs when the user operates the scroll bar. A horizontal scroll bar
enables the user to scroll the content of a window to the left or right. A vertical scroll bar
enables the user to scroll the content up or down.
1.12.1 Parts of a Scroll Bar
A scroll bar consists of a shaded shaft with an arrow button at each end and a scroll
box (sometimes called a thumb) between the arrow buttons. A scroll bar represents the
overall length or width of a data object in a windows client area; the scroll box represents
the portion of the object that is visible in the client area. The position of the scroll box
changes whenever the user scrolls a data object to display a different portion of it. The
system also adjusts the size of a scroll bars scroll box so that it indicates what portion of
the entire data object is currently visible in the window. If most of the object is visible, the
scroll box occupies most of the scroll bar shaft. Similarly, if only a small portion of the
object is visible, the scroll box occupies a small part of the scroll bar shaft.
The user scrolls the content of a window by clicking one of the arrow buttons, by
clicking the area in the shaded scroll bar shaft, or by dragging the scroll box. When the
user clicks an arrow button, the application scrolls the content by one unit (typically a
single line or column). When the user clicks the shaded areas, the application scrolls the
content by one window. The amount of scrolling that occurs when the user drags the scroll
box depends on the distance the user drags the scroll box and on the scrolling range of the
scroll bar.
The following figure 1.9 shows a rich edit control with vertical and horizontal scroll
bars, as they might appear in Windows Vista. The vertical scroll bar is currently hot
because the mouse pointer was hovering over it when the screen shot was taken.
Figure 1.9 Rich edit control with scroll bars
DMC 1944
NOTES
32 ANNA UNIVERSITY CHENNAI
1.12.2 Standard Scroll Bars and Scroll Bar Controls
A scroll bar is included in a window either as a standard scroll bar or as a scroll bar
control. A standard scroll bar is located in the non-client area of a window. It is created
with the window and displayed when the window is displayed. The sole purpose of a
standard scroll bar is to enable the user to generate scrolling requests for viewing the entire
content of the client area. You can include a standard scroll bar in a window by specifying
WS_HSCROLL, WS_VSCROLL, or both styles when you create the window. The
WS_HSCROLL style creates a horizontal scroll bar positioned at the bottom of the client
area. The WS_VSCROLL style creates a vertical scroll bar positioned at the right of the
client area. A standard scroll bar is part of its associated window and therefore does not
have a window handle of its own.
A scroll bar control is a control window that belongs to the SCROLLBAR window
class. A scroll bar control appears and functions like a standard scroll bar, but it is a
separate window. As a separate window, a scroll bar control takes direct input focus.
Unlike a standard scroll bar, a scroll bar control also has a built-in keyboard interface.
You can use as many scroll bar controls as needed in a single window. When you
create a scroll bar control, you must specify the scroll bars size and position. However, if
a scroll bar controls window can be resized, adjustments to the scroll bars size must be
made whenever the size of the window changes.
The advantage of using a standard scroll bar is that the system creates the scroll bar
and automatically sets its size and position. However, standard scroll bars are sometimes
too restrictive. For example, suppose that you want to divide a client area into quadrants
and use a separate set of scroll bars to control the content of each quadrant. You cannot
use standard scroll bars because you can only create one set of scroll bars for a particular
window. Use scroll bar controls instead, because you can add as many of them to a
window as you want.
To create a scroll bar control using the CreateWindow or CreateWindowEx function
specify the SCROLLBAR class, appropriate window style constants, and a combination
of the following scroll bar control styles. A scroll bar control can have a number of styles
that serves to control the orientation and position of the scroll bar. You specify the styles
that you want when you call the CreateWindow function to create a scroll bar control.
Some of the styles create a scroll bar control that uses a default width or height. However,
you must always specify the x- and y-coordinates and the other dimensions of the scroll
bar when you call CreateWindow or CreateWindowEx. Few scrollbar styles are given
below
VISUAL PROGRAMMING
NOTES
33 ANNA UNIVERSITY CHENNAI
1.12.3 Scroll Box Position and Scrolling Range
The position of the scroll box is represented as an integer; it is relative to the left or
upper end of the scroll bar, depending on whether the scroll bar is horizontal or vertical.
The position must be within the minimum and maximum values of the scrolling range. For
example, in a scroll bar with a range of 0 through 100, position 50 is in the middle, with the
Constant Description
SBS_BOTTOMALIGN Aligns the bottom edge of the scroll bar with the
bottom edge of the rectangle defined by the x, y,
nWidth, and nHeight parameters of
CreateWindowEx function. The scroll bar has the
default height for system scroll bars. Use this style
with the SBS_HORZ style.
SBS_HORZ Designates a horizontal scroll bar. If neither the
SBS_BOTTOMALIGN nor SBS_TOPALIGN style
is specified, the scroll bar has the height, width, and
position specified by the x, y, nWidth, and nHeight
parameters of CreateWindowEx.
SBS_LEFTALIGN Aligns the left edge of the scroll bar with the left
edge of the rectangle defined by the x, y, nWidth, and
nHeight parameters of CreateWindowEx. The scroll
bar has the default width for system scroll bars. Use
this style with the SBS_VERT style.
SBS_RIGHTALIGN Aligns the right edge of the scroll bar with the right
edge of the rectangle defined by the x, y, nWidth, and
nHeight parameters of CreateWindowEx. The scroll
bar has the default width for system scroll bars. Use
this style with the SBS_VERT style.
SBS_SIZEBOX Designates a size box. If you specify neither the
SBS_SIZEBOXBOTTOMRIGHTALIGN nor the
SBS_SIZEBOXTOPLEFTALIGN style, the size box
has the height, width, and position specified by the x,
y, nWidth, and nHeight parameters of
CreateWindowEx.
SBS_SIZEGRIP Same as SBS_SIZEBOX, but with a raised edge.
SBS_TOPALIGN Aligns the top edge of the scroll bar with the top edge
of the rectangle defined by the x, y, nWidth, and
nHeight parameters of CreateWindowEx. The scroll
bar has the default height for system scroll bars. Use
this style with the SBS_HORZ style.
SBS_VERT Designates a vertical scroll bar. If you specify neither
the SBS_RIGHTALIGN nor the SBS_LEFTALIGN
style, the scroll bar has the height, width, and
position specified by the x, y, nWidth, and nHeight
parameters of CreateWindowEx.
DMC 1944
NOTES
34 ANNA UNIVERSITY CHENNAI
remaining positions distributed equally along the scroll bar. The initial range depends on the
scroll bar. Standard scroll bars have an initial range of 0 through 100; scroll bar controls
have an empty range (both minimum and maximum values are zero), unless you supply an
explicit range when the control is created. You can change the range at any time. You can
use the SetScrollInfo function to set the range values, and the GetScrollInfo function to
retrieve the current range values.
The SetScrollInfo function sets the parameters of a scroll bar, including the minimum
and maximum scrolling positions, the page size, and the position of the scroll box (thumb).
The function also redraws the scroll bar, if requested.
int SetScrollInfo(HWND hwnd, int fnBar, LPCSCROLLINFO lpsi, BOOL fRedraw);
where, hwnd is handle to a scroll bar control or a window with a standard scroll bar,
depending on the value of the fnBar parameter, fnBar specifies the type of scroll bar
(SB_CTL, SB_HORZ, SB_VERT) for which to set parameters. lpsi is a pointer to a
SCROLLINFO structure and fRedraw specifies whether the scroll bar is redrawn to
reflect the changes to the scroll bar. If this parameter is TRUE, the scroll bar is redrawn,
otherwise, it is not redrawn. The return value of the SetScrollInfo is the current position of
the scroll box which is an integer.
The GetScrollInfo function retrieves the parameters of a scroll bar, including the
minimum and maximum scrolling positions, the page size, and the position of the scroll box
(thumb).
1.12.4 Scroll Bar Range and Position
Every scroll bar has an associated range and position. The scroll bar range is a
pair of integers representing a minimum and maximum value associated with the scroll bar.
The position is the location of the thumb within the range. When the thumb is at the top (or
left) of the scroll bar, the position of the thumb is the minimum value of the range. At the
bottom (or right) of the scroll bar, the thumb position is the maximum value of the range.
By default, the range of a scroll bar is 0 (top or left) through 100 (bottom or right),
but its easy to change the range to something that is more convenient for the program:
SetScrollRange (hwnd, iBar, iMin, iMax, bRedraw) ;
VISUAL PROGRAMMING
NOTES
35 ANNA UNIVERSITY CHENNAI
Figure 1.10. Scroll bars with five thumb positions
The iBar argument is either SB_VERT or SB_HORZ, iMin and iMax are the new
minimum and maximum positions of the range, and you set bRedraw to TRUE if you want
Windows to redraw the scroll bar based on the new range. (If you will be calling other
functions that affect the appearance of the scroll bar after you call SetScrollRange, youll
probably want to set bRedraw to FALSE to avoid excessive redrawing.)
The thumb position is always a discrete integral value. For instance, a scroll bar with
a range of 0 through 4 has five thumb positions, as shown in Figure 1.10.
You can use SetScrollPos to set a new thumb position within the scroll bar range:
SetScrollPos (hwnd, iBar, iPos, bRedraw) ;
The iPos argument is the new position and must be within the range of iMin and
iMax. Windows provides similar functions (GetScrollRange and GetScrollPos) to obtain
the current range and position of a scroll bar.
When you use scroll bars within your program, you share responsibility with Windows
for maintaining the scroll bars and updating the position of the scroll bar thumb. These are
Windows responsibilities for scroll bars:
Handle all processing of mouse messages to the scroll bar.
Provide a reverse-video flash when the user clicks the scroll bar.
Move the thumb as the user drags the thumb within the scroll bar.
Send scroll bar messages to the window procedure of the window containing the
scroll bar.
These are the responsibilities of your program:
Initialize the range and position of the scroll bar.
Process the scroll bar messages to the window procedure.
Update the position of the scroll bar thumb.
Change the contents of the client area in response to a change in the scroll bar.
Lets take a look at the various scroll bar messages.
DMC 1944
NOTES
36 ANNA UNIVERSITY CHENNAI
1.12.5 Scroll Bar Messages
Windows sends the window procedure WM_VSCROLL (vertical scroll) and
WM_HSCROLL (horizontal scroll) messages when the scroll bar is clicked with the mouse
or the thumb is dragged. Each mouse action on the scroll bar generates at least two messages,
one when the mouse button is pressed and another when it is released.
Like all messages, WM_VSCROLL and WM_HSCROLL are accompanied by the
wParam and lParam message parameters. For messages from scroll bars created as
part of your window, you can ignore lParam; thats used only for scroll bars created as
child windows, usually within dialog boxes.
The wParam message parameter is divided into a low word and a high word. The
low word of wParam is a number that indicates what the mouse is doing to the scroll bar.
This number is referred to as a notification code. Notification codes have values
defined by identifiers that begin with SB (defined in WINUSER.H), which stands for
scroll bar as shown below:
#define SB_LINEUP 0
#define SB_LINELEFT 0
#define SB_LINEDOWN 1
#define SB_LINERIGHT 1
#define SB_PAGEUP 2
#define SB_PAGELEFT 2
#define SB_PAGEDOWN 3
#define SB_PAGERIGHT 3
#define SB_THUMBPOSITION 4
#define SB_THUMBTRACK 5
#define SB_TOP 6
#define SB_LEFT 6
#define SB_BOTTOM 7
#define SB_RIGHT 7
#define SB_ENDSCROLL 8
You use the identifiers containing the words LEFT and RIGHT for horizontal scroll
bars, and the identifiers with UP, DOWN, TOP, and BOTTOM with vertical scroll bars.
The notification codes associated with clicking the mouse on various areas of the scroll bar
are shown in Figure 1.11.
VISUAL PROGRAMMING
NOTES
37 ANNA UNIVERSITY CHENNAI
Figure 1.11. Identifiers for the wParam values of scroll bar messages.
If you hold down the mouse button on the various parts of the scroll bar, your program
can receive multiple scroll bar messages. When the mouse button is released, youll get a
message with a notification code of SB_ENDSCROLL. You can generally ignore messages
with the SB_ENDSCROLL notification code. Windows will not change the position of the
scroll bar thumb. Your application does that by calling SetScrollPos.
When you position the mouse cursor over the scroll bar thumb and press the mouse
button, you can move the thumb. This generates scroll bar messages with notification
codes of SB_THUMBTRACK and SB_THUMBPOSITION. When the low word of
wParam is SB_THUMBTRACK, the high word of wParam is the current position of the
scroll bar thumb as the user is dragging it. This position is within the minimum and maximum
values of the scroll bar range. When the low word of wParam is SB_THUMBPOSITION,
the high word of wParam is the final position of the scroll bar thumb when the user released
the mouse button. For other scroll bar actions, the high word of wParam should be ignored.
1.12.6 Keyboard Interface for a Scroll Bar
A scroll bar control provides a built-in keyboard interface that enables the user to
issue scrolling requests by using the keyboard; a standard scroll bar does not. When a
scroll bar control has the keyboard focus, it sends WM_HSCROLL and
WM_VSCROLL messages to its parent window when the user presses the arrow keys.
The request code is sent with each message corresponding to the arrow key the user has
pressed. Following are the arrow keys and their corresponding request codes.
Arrow key Request code
DOWN SB_LINEDOWN or SB_LINERIGHT
END SB_BOTTOM
HOME SB_TOP
LEFT SB_LINEUP or SB_LINELEFT
PGDN SB_PAGEDOWN or SB_PAGERIGHT
PGUP SB_PAGEUP or SB_PAGELEFT
RIGHT SB_LINEDOWN or SB_LINERIGHT
UP SB_LINEUP or SB_LINELEFT
DMC 1944
NOTES
38 ANNA UNIVERSITY CHENNAI
If you want a keyboard interface for a standard scroll bar, you can create one yourself
by processing the WM_KEYDOWN message in your window procedure and then
performing the appropriate scrolling action based on the virtual-key code that accompanies
the message.
1.13 THE KEYBOARD
The keyboard and the mouse are the two standard sources of user input in Microsoft
Windows. Keyboard input is delivered to your programs window procedures in the form
of messages. Indeed, the keyboard is an obvious example of the type of information that
messages might deliver to applications.
1.13.1 Receiving Keyboard Input
At the lowest level, each key on the keyboard generates a scan code when the key
is pressed and released. The scan code is a hardware-dependent number that identifies
the key. Unlike Windows-based desktop operating systems, Your application should rely
only on scan codes that are supported on the target device.
The keyboard driver translates or maps each scan code to a virtual-key code. The
virtual-key code is a hardware-independent number that identifies the key. Because
keyboard layouts vary from language to language, Windows offers only the core set of
virtual-key codes that are found on all keyboards. This core set includes English characters,
numbers, and a few critical keys, such as the function and arrow keys. Keys that are not
included in the core set also have virtual-key code assignments, but their values vary from
one keyboard layout to the next. You should depend only on the virtual-key codes that are
in the core set.
In addition to mapping, the keyboard driver determines which characters the virtual
key generates. A single virtual key generates different characters depending on the state of
other keys, such as the SHIFT and CAPS LOCK keys. Do not confuse virtual-key codes
with characters. Although many of the virtual-key codes have the same numeric value as
one of the characters that the key generates, the virtual-key code and the character are
two different elements. For example, the same virtual key generates the uppercase A
character and the lowercase a character.
After translating the scan code into a virtual-key code, the device driver posts a
keyboard message that contains the virtual-key code to the message queue for the
application. The main user input thread for the application then calls back to the driver for
each key event to obtain the characters that correspond to the key. The driver posts these
characters with the key event to the foreground message queue for the application. When
the application retrieves this keyboard message from the message queue, the message is
stored. When the application later calls TranslateMessage, the driver places the characters
that were posted with the key on the queue for retrieval.
VISUAL PROGRAMMING
NOTES
39 ANNA UNIVERSITY CHENNAI
Figure 1.12 Keyboard-input model
Each thread maintains its own active window and focus window. The active window
is a top-level window. The focus window is either the active window or one of its descendant
windows. The active window of this thread is considered the foreground window. The
device driver places keyboard messages in the message queue of the foreground thread.
The thread message loop pulls the message from the queue and sends it to the window
procedure of the thread focus window. If the focus window is NULL, the window procedure
of the active window receives the message. Figure 1.12 shows the keyboard-input model.
1.13.2 Keyboard Messages
There are eight different messages that Windows uses to indicate various keyboard
events. The messages that an application receives from Windows about keyboard events
distinguish between keystrokes and characters.
A window receives keyboard input in the form of keystroke messages and character
messages. Keystroke messages control window behavior and character messages determine
the text that is displayed in a window.
Windows generates a WM_KEYDOWN or a WM_SYSKEYDOWN message
when the user presses a key. If the user holds a key down long enough to start automatic
repeat functionality, the system generates repeated WM_KEYDOWN or
WM_SYSKEYDOWN messages. When the user releases a key, the system generates a
WM_KEYUP or a WM_SYSKEYUP message.
The system makes a distinction between system keystrokes and nonsystem keystrokes.
System keystrokes produce system keystroke messages, such as WM_SYSKEYDOWN
and WM_SYSKEYUP. Nonsystem keystrokes produce nonsystem keystroke messages,
such as WM_KEYDOWN and WM_KEYUP.
A system keystroke message is generated when the user types a key in combination
with the ALT key or when the user types a key and the focus is NULL. If the focus is
NULL, the keyboard event is delivered to the active window. A system keystroke message
has the WM_SYS prefix in the message name. A system keystroke message is used primarily
by the system rather than by an application. The system uses such a message to provide its
DMC 1944
NOTES
40 ANNA UNIVERSITY CHENNAI
built-in keyboard interface to menus and to enable the user to control which window is
active. If a window procedure processes a system keyboard message, the window
procedure should pass the message to the DefWindowProc function. Otherwise, all system
operations that involve the ALT key are disabled whenever that window has the keyboard
focus.
The window procedure of the window that has the keyboard focus receives all
keystroke messages. However, an application that responds to keyboard input typically
processes WM_KEYDOWN messages only.
When the window procedure receives the WM_KEYDOWN message, it should examine
the virtual-key code that accompanies the message to determine how to process the
keystroke. The virtual-key code is contained in the wParam parameter of the message.
1.13.2.1 Virtual Key Codes
The virtual key code is stored in the wParam parameter of the WM_KEYDOWN,
WM_KEYUP, WM_SYSKEYDOWN, and WM_SYSKEYUP messages. This code
identifies the key being pressed or released.
The virtual key codes you use most often have names beginning with VK_ defined in
the WINUSER.H header file. Three of the first four virtual key codes refer to mouse
buttons as given below:
The lParam parameter of a keystroke message contains additional data about the
keystroke that generated the message. The following table 1.3 shows the additional
keystroke data that is required by the lParam parameter.
Table 1.3 lParam parameter for keystroke data
Decimal Hex WINUSER.H Identifier IBM-Compatible Keyboard
1 01 VK_LBUTTON Mouse Left Button
2 02 VK_RBUTTON Mouse Right Button
3 03 VK_CANCEL Ctrl-Break
4 04 VK_MBUTTON Mouse Middle Button
Data Description
Context
code
The value is 1 if the ALT key was pressed or 0 if the pressed
key was released.
Previous
key state
The value is 1 if the pressed key was previously down or 0 if
the pressed key was previously up. The value is 1 for
WM_KEYDOWN and WM_SYSKEYDOWN keystroke
messages that were generated by automatic repeat functionality.
Repeat
count
Specifies the number of times that the keystroke was repeated
as a result of the user holding down the key.
Scan code Gives the hardware-dependent key scan code.
Transition
state
The value is 1 if the key was released or if the key was pressed.
VISUAL PROGRAMMING
NOTES
41 ANNA UNIVERSITY CHENNAI
Typically, an application processes only the keystrokes that are generated by
noncharacter keys. The following code example shows the window procedure framework
that a typical application uses to receive and process keystroke messages.
case WM_KEYDOWN:
switch (wParam)
{
case VK_HOME:
// Insert code here to process the HOME key
// ...
break;
case VK_END:
// Insert code here to process the END key
// ...
break;
case VK_INSERT:
// Insert code here to process the INS key
// ...
break;
case VK_F2:
// Insert code here to process the F2 key
// ...
break;
case VK_LEFT:
// Insert code here to process the LEFT ARROW key
// ...
break;
case VK_RIGHT:
// Insert code here to process the RIGHT ARROW key
// ...
break;
case VK_UP:
// Insert code here to process the UP ARROW key
// ...
break;
case VK_DOWN:
// Insert code here to process the DOWN ARROW key
// ...
break;
DMC 1944
NOTES
42 ANNA UNIVERSITY CHENNAI
case VK_DELETE:
// Insert code here to process the DELETE key
// ...
break;
default:
// Insert code here to process other noncharacter keystrokes
// ...
break;
}
1.13.3 The Four Character Messages
There are four character messages:
The WM_CHAR and WM_DEADCHAR messages are derived from
WM_KEYDOWN messages. The WM_SYSCHAR and WM_SYSDEADCHAR
messages are derived from WM_SYSKEYDOWN messages.
Because the character messages are generated by the TranslateMessage function
from WM_KEYDOWN and WM_SYSKEYDOWN messages, the character messages
are delivered to your window procedure sandwiched between keystroke messages. For
instance, if Caps Lock is not toggled on and you press and release the A key, the window
procedure receives the following three messages:
If you type an uppercase A by pressing the Shift key, pressing the A key, releasing the
A key, and then releasing the Shift key, the window procedure receives five messages:
The Shift key by itself does not generate a character message.
Characters Dead Charac
Nonsystem Characters: WM_CHAR WM_DEADCHA
System Characters: WM_SYSCHAR WM_SYSDEAD
Message Key or Code
WM_KEYDOWN Virtual key code for `A' (0x41)
WM_CHAR Character code for `a' (0x61)
WM_KEYUP Virtual key code for `A' (0x41)
Message Key or Code
WM_KEYDOWN Virtual key code VK_SHIFT (0x10)
WM_KEYDOWN Virtual key code for `A' (0x41)
WM_CHAR Character code for `A' (0x41)
WM_KEYUP Virtual key code for `A' (0x41)
WM_KEYUP Virtual key code VK_SHIFT (0x10)
VISUAL PROGRAMMING
NOTES
43 ANNA UNIVERSITY CHENNAI
1.13.4 Control Character Processing
The basic rule for processing keystroke and character messages is this: If you need to
read keyboard character input in your window, you process the WM_CHAR message. If
you need to read the cursor keys, function keys, Delete, Insert, Shift, Ctrl, and Alt, you
process the WM_KEYDOWN message.
WM_CHAR processing often looks something like this:
case WM_CHAR:
[other program lines]
switch (wParam)
{
case \b: // backspace
[other program line
break ;
case \t: // tab
[other program lines]
break ;
case \n: // linefeed
[other program lines]
break ;
case \r: // carriage return
[other program lines]
break ;
default: // character codes
[other program lines]
break ;
}
return 0 ;
1.14 CREATING AND DISPLAYING A CARET
A window that receives keyboard input typically displays the characters that the user
types in the window client area. A window should use a caret to indicate the position in the
client area where the next character will appear. The window should create and display the
caret when it receives the keyboard focus, and it should hide and destroy the caret when
it loses the focus. A window can perform these operations when the WM_SETFOCUS
and WM_KILLFOCUS messages are processed, respectively.
Various methods like the CreateCaret, ShowCaret, DestroyCaret, and HideCaret
functions may be used for controlling the visibility of the caret. Use the SetCaretPos function
to change the position of the caret as the user types.
DMC 1944
NOTES
44 ANNA UNIVERSITY CHENNAI
1.15 THE MOUSE
The mouse is a pointing device with one or more buttons. Similar to keyboard mouse
events generate mouse messages which can be broadly classified into client and non-client
area messages.
1.15.1 Client area mouse messages
A window procedure receives mouse messages whenever the mouse passes over the
window or is clicked within the window, even if the window is not active or does not have
the input focus. Windows defines 21 messages for the mouse. However, 11 of these
messages do not relate to the client area. These are called nonclient-area messages, and
Windows applications usually ignore them.
When the mouse is moved over the client area of a window, the window procedure
receives the message WM_MOUSEMOVE. When a mouse button is pressed or released
within the client area of a window, the window procedure receives the messages in table
1.4.
Table 1.4 Client area mouse messages
Your window procedure receives MBUTTON messages only for a three-button
mouse and RBUTTON messages only for a two-button mouse. The window procedure
receives DBLCLK (double-click) messages only if the window class has been defined to
receive them
For all these messages, the value of lParam contains the position of the mouse. The
low word is the x-coordinate, and the high word is the y-coordinate relative to the upper
left corner of the client area of the window. You can extract these values using the LOWORD
and HIWORD macros:
x =LOWORD (lParam) ;
y =HIWORD (lParam) ;
The value of wParam indicates the state of the mouse buttons and the Shift and Ctrl
keys. You can test wParam using these bit masks defined in the WINUSER.H header file.
The MK prefix stands for mouse key.
MK_LBUTTON Left button is down
MK_MBUTTON Middle button is down
MK_RBUTTON Right button is down
MK_SHIFT Shift key is down
MK_CONTROL Ctrl key is down
Button Pressed Released Pressed (Second Click)
Left WM_LBUTTONDOWN WM_LBUTTONUP WM_LBUTTONDBLCLK
Middle WM_MBUTTONDOWN WM_MBUTTONUP WM_MBUTTONDBLCLK
Right WM_RBUTTONDOWN WM_RBUTTONUP WM_RBUTTONDBLCLK
VISUAL PROGRAMMING
NOTES
45 ANNA UNIVERSITY CHENNAI
For example, if you receive a WM_LBUTTONDOWN message, and if the value
wparam & MK_SHIFT
is TRUE (nonzero), you know that the Shift key was down when the left button was
pressed.
To understand mouse messages lets take a look at a program 1.4 that allows the user
to click the mouse left button and move around inside the client area and then when the
user releases the left button the program connects those points which were touched by the
mouse cursor when the user moved the mouse by holding the left button.
Program 1.4: Program that handles mouse messages
#include <windows.h>
#define MAXPOINTS 1000
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] =TEXT (Connect) ;
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
wndclass.style =CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc =WndProc ;
wndclass.cbClsExtra =0 ;
wndclass.cbWndExtra =0 ;
wndclass.hInstance =hInstance ;
wndclass.hIcon =LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor =LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground =(HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName =NULL ;
wndclass.lpszClassName =szAppName ;
if (!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT (Program requires Windows NT!),
szAppName, MB_ICONERROR) ;
return 0 ;
}
DMC 1944
NOTES
46 ANNA UNIVERSITY CHENNAI
hwnd =CreateWindow (szAppName, TEXT (Connect-the-Points Mouse Demo),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL) ;
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM
lParam)
{
static POINT pt[MAXPOINTS] ;
static int iCount ;
HDC hdc ;
int i, j ;
PAINTSTRUCT ps ;
switch (message)
{
case WM_LBUTTONDOWN:
iCount =0 ;
InvalidateRect (hwnd, NULL, TRUE) ;
return 0 ;
case WM_MOUSEMOVE:
if (wParam & MK_LBUTTON && iCount <1000)
{
pt[iCount ].x =LOWORD (lParam) ;
pt[iCount++].y =HIWORD (lParam) ;
hdc =GetDC (hwnd) ;
SetPixel (hdc, LOWORD (lParam), HIWORD (lParam), 0) ;
ReleaseDC (hwnd, hdc) ;
}
VISUAL PROGRAMMING
NOTES
47 ANNA UNIVERSITY CHENNAI
return 0 ;
case WM_LBUTTONUP:
InvalidateRect (hwnd, NULL, FALSE) ;
return 0 ;
case WM_PAINT:
hdc =BeginPaint (hwnd, &ps) ;
SetCursor (LoadCursor (NULL, IDC_WAIT)) ;
ShowCursor (TRUE) ;
for (i =0 ; i <iCount - 1 ; i++)
for (j =i +1 ; j <iCount ; j++)
{
MoveToEx (hdc, pt[i].x, pt[i].y, NULL) ;
LineTo (hdc, pt[j].x, pt[j].y) ;
}
ShowCursor (FALSE) ;
SetCursor (LoadCursor (NULL, IDC_ARROW)) ;
EndPaint (hwnd, &ps) ;
return 0 ;
case WM_DESTROY:
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
1.15.2 Nonclient-Area Mouse Messages
If the mouse is outside a windows client area but within the window, Windows sends
the window procedure a nonclient-area mouse message. The nonclient area of a window
includes the title bar, the menu, and the window scroll bars.
The programmer do not usually need to process nonclient-area mouse messages.
Instead, you simply pass them on to DefWindowProc so that Windows can perform system
functions. In this respect, the nonclient-area mouse messages are similar to the system
keyboard messages WM_SYSKEYDOWN, WM_SYSKEYUP, and WM_SYSCHAR.
The mouse buttons generate these messages:
Button Pressed Released Pres
Left WM_NCLBUTTONDOWN WM_NCLBUTTONUP WM_N
Middle WM_NCMBUTTONDOWN WM_NCMBUTTONUP WM_N
Right WM_NCRBUTTONDOWN WM_NCRBUTTONUP WM_N
DMC 1944
NOTES
48 ANNA UNIVERSITY CHENNAI
The wParam and lParam parameters for nonclient-area mouse messages are
somewhat different from those for client-area mouse messages. The wParam parameter
indicates the nonclient area where the mouse was moved or clicked. It is set to one of the
identifiers beginning with HT (standing for hit-test) that are defined in the WINUSER.H.
The lParam parameter contains an x-coordinate in the low word and a y-coordinate
in the high word. However, these are screen coordinates, not client-area coordinates as
they are for client-area mouse messages.
Now lets take a look at another mouse program 1.5, which enables the user to
perfrom a free hand drawing inside the client area of a simple window.
Program 1.5: Draw a free hand drawing as Mouse is Drag
1. Create a new Win32Application project and enter the following lines of code:
#include<windows.h>
long _stdcall func(HWND,UINT,UINT,long);
WNDCLASS a;
int flag=0,x1,y1,x2,y2;
int _stdcall WinMain(HINSTANCE i,HINSTANCE j,char *k,int l)
{
HWND h;
MSG m;
a.hInstance=i; //instance handle
a.lpszClassName=SimpleWnd; //long pointer to class name
a.lpfnWndProc=func; //long pointer to Window procedure
a.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
//set background color of Window Client area
RegisterClass(&a); // Register the Window Class before use
h=CreateWindow(SimpleWnd,Title,WS_OVERLAPPEDWINDOW,20,20,300,200,0,0,i,
0); // Create Window Application
ShowWindow(h,3);
while(GetMessage(&m,0,0,0)) // extracts message from Message Queue
DispatchMessage(&m); // dispatches the message received
return 0;
}
long _stdcall func(HWND w,UINT x,UINT y,long z)
{
HDC d;
VISUAL PROGRAMMING
NOTES
49 ANNA UNIVERSITY CHENNAI
switch(x)
{
case WM_LBUTTONDOWN:
if(flag==0)
{
x1=LOWORD(z);
y1=HIWORD(z);
flag=1;
}
break;
case WM_MOUSEMOVE:
if(flag==1)
{
x2=LOWORD(z);
y2=HIWORD(z);
d=GetDC(w);
MoveToEx(d,x1,y1,0); // current position is updated to (x1,y1)
LineTo(d,x2,y2); // draw line from current pos to (x2,y2)
ReleaseDC(w,d);
x1=x2;
y1=y2;
}
break;
case WM_LBUTTONUP:
flag=0;
break;
case WM_DESTROY:
PostQuitMessage(0); // used to terminate while loop in WinMain()
break;
default:
return DefWindowProc(w,x,y,z);
}
return 0L;
}
DMC 1944
NOTES
50 ANNA UNIVERSITY CHENNAI
2. Build and Test the program to find a window similar to one shown in Figure 1.13.
Figure 1.13 Free hand mouse drawing
1.16 WINDOWS MENUS
A Microsoft Windows menu is a familiar application element that consists of a top-
level horizontal list of items with associated pop-up menus that appear when the user
selects a top-level item. Most of the time, you define for a frame window a default menu
resource that loads when the window is created. You can also define a menu resource
independent of a frame window. In that case, your program must call the functions necessary
to load and activate the menu.
A menu resource completely defines the initial appearance of a menu. Menu items
can be grayed or have check marks, and bars can separate groups of menu items. Multiple
levels of pop-up menus are possible. If a first-level menu item is associated with a subsidiary
pop-up menu, the menu item carries a right-pointing arrow symbol.
Visual C++includes an easy-to-use menu-resource editing tool. This tool lets you
edit menus in a wysiwyg environment. Each menu item has a properties dialog that defines
all the characteristics of that item. The resulting resource definition is stored in the applications
resource script (RC) file. Each menu item is associated with an ID, such as
ID_FILE_OPEN, that is defined in the resource.h file.
The MFC library extends the functionality of the standard menus for Windows. Each
menu item can have a prompt string that appears in the frames status bar when the item is
highlighted. These prompts are really Windows string resource elements linked to the menu
item by a common ID. From the point of view of the menu editor and your program, the
prompts appear to be part of the menu item definition.
VISUAL PROGRAMMING
NOTES
51 ANNA UNIVERSITY CHENNAI
1.16.1 Keyboard Accelerators
Youve probably noticed that most menu items contain an underlined letter. In Visual
C++(and most other applications), pressing Alt-F followed by S activates the File Save
menu item. This shortcut system is the standard Windows method of using the keyboard to
choose commands from menus. If you look at an applications menu resource script (or
the menu editors properties dialog), you will see an ampersand (&) preceding the character
that is underlined in each of the applications menu items.
Windows offers an alternative way of linking keystrokes to menu items. The keyboard
accelerator resource consists of a table of key combinations with associated command
IDs. The Edit Copy menu item (with command ID ID_EDIT_COPY), for example, might
be linked to the Ctrl-C key combination through a keyboard accelerator entry. A keyboard
accelerator entry does not have to be associated with a menu item. If no Edit Copy menu
item were present, the Ctrl-C key combination would nevertheless activate the
ID_EDIT_COPY command.
The process of creating a menu depends on the environment you are using. In Microsoft
Visual C++, you can use the built-in menu editor. In this case, the actual text that defines
and describes the menu would be automatically added to the rc file.
Program 1.6: Creating a Menu resource and attaching it with the window.
1. Create an empty project as mentioned in the previous programs.
2. On the main menu, click Insert Resource and in the dialog box, click Menu
and click New. This will insert a new menu resource in your project.
3. While the first menu item is selected, type &File.
4. Click the next empty item under File. Type &New.
5. In the Properties window, click the ID edit box, type IDM_FILE_NEW and
press Enter.
6. Click the next empty item under New and type &Open.
7. In the Properties window, click the ID edit box, type IDM_FILE_OPEN and
press Enter.
8. Click the next empty item under Open and in the properties check the Separator
option to include a separator bar.
9. Click the next empty item under the new separator and type E&xit.
10. In the Properties window, click the ID edit box, type IDM_FILE_EXIT and
press Enter.
11. Click the next empty item on the right side of File. Type &Help.
12. Click the next empty item under Help and type &About.
13. In the Properties window, click the ID edit box, type IDM_HELP_ABOUT and
press Tab. In the Caption edit box, and press Enter.
DMC 1944
NOTES
52 ANNA UNIVERSITY CHENNAI
14. In the ResourceView tab of the Workspace, under the Menu node, click
I DR_MENU1. I n the Menu Properties window, change the I D to
IDR_MAINFRAME.
15. Open the Exercise.cpp source file and change the lpszMenuName member of the
WndClsEx variable as follows: WndClsEx.lpszMenuName =
MAKEINTRESOURCE(IDR_MAINFRAME);
16. To test the application, press Ctrl +F5 and press Enter and youll find a window
with the menu that you have created as shown in Figure 1.14.
Figure 1.14 A Window with a Menu
Try creating new windows applications by using other menu items in your program.
1.17 EXERCISES
1. Write a short note on windows programming model.
2. List few windows messages and give their significance.
3. Explain the various components of a windows program using a sample program.
4. How message handling is done in a windows program?
5. Give the significance of Hungarian notations.
6. Write a program to create a simple window.
7. List a few data types in windows programming environment.
8. Define GDI.
9. Discuss about the various ways of acquiring a device context.
10. Write a program that displays a simple text at the center of a window.
11. Explain how a scrollbar may be embedded in a window and handled.
12. What are virtual key codes? Give examples.
13. Explain with a program how keyboard messages are handled.
14. Write a short note on various mouse messages.
15. Differentiate between client and non-client area mouse messages.
16. How non-client area mouse messages are handled?
17. Write a program that creates a window with few user defined menu options
***
VISUAL PROGRAMMING
NOTES
53 ANNA UNIVERSITY CHENNAI
UNIT II
VISUAL BASIC PROGRAMMING
2.1 INTRODUCTION
This unit about programming in Visual Basic which is a high level programming language
evolved from the earlier DOS version called BASIC. BASIC means Beginners All-purpose
Symbolic Instruction Code. It is a very easy programming language to learn. Now, there
are many versions of VB exist in the market, the most popular one and still widely used by
many VB programmers is none other than Visual Basic 6. Most recently we have VB.net,
VB2005, VB2008 and the latest VB2010. Both Vb2008 and VB2010 are fully object
oriented programming (OOP) language.
Microsoft Visual Basic development system version 6.0 is the most productive tool
for creating high-performance components and applications. Visual Basic 6.0 offers
developers the ability to create robust applications that reside on the client or server, or
operate in a distributed n-tier environment. Visual Basic 6.0 is the Rapid Application
Development (RAD) tool available either as a stand-alone product or as a part of the
Visual Studio 6.0 suite of tools.
2.2 LEARNING OBJECTIVES
Understand the benefits of using Microsoft Visual Basic 6.0 for Windows as an
application tool
Understand the Visual Basic event-driven programming concepts, terminology,
and available tools
Learn the fundamentals of designing and implementing a Visual Basic application
Learn to use the Visual Basic toolbox
Use the menu design window
Get a basic understanding of database access and management using databound
controls
2.3 THE INTEGRATED DEVELOPMENT ENVIRONMENT
Visual Basic is a tool that allows you to develop Windows (Graphic User Interface -
GUI) applications. The applications have a familiar appearance to the user.
DMC 1944
NOTES
54 ANNA UNIVERSITY CHENNAI
Visual Basic is event-driven, meaning code remains idle until called upon to respond
to some event (button pressing, menu selection, etc.). Visual Basic is governed by an
event processor. Nothing happens until an event is detected. Once an event is detected,
the code corresponding to that event (event procedure) is executed. Program control is
then returned to the event processor.
Some Features of Visual Basic are:
1. Full set of objects
2. Response to mouse and keyboard actions
3. Full array of mathematical, string handling, and graphics functions
4. Can handle fixed and dynamic variable and control arrays
5. Sequential and random access file support
6. Useful debugger and error-handling facilities
7. Powerful database access tools
8. ActiveX support
9. Package & Deployment Wizard makes distributing your applications simple
Visual Basic comes with its Integrated Development Environment (IDE). The IDE
gives you everything you need to create great applications, to write code for them, to test
and fine-tune them, and, finally, to produce executable files.
2.3.1 Running the IDE
You can choose from several ways to launch the Visual Basic IDE, as is true for any
Windows executable:
You can run the Visual Basic 6 environment from the Start Menu (as given in
Figure 2.1); the exact path to the menu command depends on whether you have
installed Visual Basic as part of the Microsoft Visual Studio suite.
Figure 2.1 Selecting Microsoft Visual Basic 6.0 from Start
VISUAL PROGRAMMING
NOTES
55 ANNA UNIVERSITY CHENNAI
You can create a shortcut to the IDE on your desktop and run it by simply double-
clicking on it.
When Visual Basic is installed, it registers the .vbp, .frm, .bas, and a few other
extensions with the operating system. Therefore, you can run the environment by
double-clicking on any Visual Basic file.
If you have installed Microsoft Active Desktop, you can create a shortcut to the
Visual Basic IDE on the system taskbar. This is probably the fastest way to run the
IDE: its similar to a desktop shortcut, but you dont have to minimize other windows
to uncover it.
2.3.2 Selecting the Project Type
The first time you run the Visual Basic IDE, youre asked to select the type of project
you want to create, as you can see in Figure 2.2.
Some of the project types that Visual Basic supports are:
Standard Windows EXE programs
ActiveX EXE files
ActiveX DLLs
ActiveX controls
Programs written by the Visual Basic Application Wizard
Data projects
IIS (the Microsoft Internet Information Server) applications
Visual Basic add-ins
ActiveX document DLLs
ActiveX document EXE files
DHTML applications
VB Enterprise Edition controls
Figure 2.2 Types of projects in VB6.0
DMC 1944
NOTES
56 ANNA UNIVERSITY CHENNAI
This list of project types indicates some of the ways Visual Basic has grown over the
years. Select Standard EXE from the new project dialog (as in Figure 2.2) and what
youll be confronted with is shown in Figure 2.3, which is the main programming environment.
You do all your form design and coding from this window. The main programming
environment has the following windows:
2.3.3 Form Design Window
This is where you design your form. A form is what you will present to a user of your
application. A form could be an introduction screen, it could be a dialog box giving the user
options, and it could be a box containing a warning. All of your VB programs will revolve
around a number of forms.
The form window - When you start Visual Basic, a default form (Form1) with a
standard grid (a window as shown in figure 2.4, consisting of regularly spaced dots) appears
in a pane called the Form window. You can use the Form window grid to create the user
interface and to line up interface elements.
Figure 2.3 The Visual Basic 6 environment
Menu Bar
Code View
Object View
Project Contents
Currentl y Selected Object
Properties & Descripti on
Form Design Window
Control Toolbar
Tool Bar
Uhhh, yeah, menus. :)
This will open up (if it exists)
the code window for the
currently selected project
component
Click this to get to the design
window (if one exists) for the
currently selected project
component.
This includes forms, modules,
classes, etc... The highlighted one
is the currently selected / active one.
A list of the components available
in the current project module,
selectable.
The list of properties for the currently
selected object. in this picture, the form
is the currently selected object. The
description underneath the table gives
a description of the currently selected
property.
You can visually add controls and
components to your form, and adjust
what the layout looks like just like you
are using a paint program.
You choose controls from
here to add them to your
form... just draw them on!
Save project, new project
add forms or modules to
project, run the program,
etc... (The little play button
in the middle will run your
program)
VISUAL PROGRAMMING
NOTES
57 ANNA UNIVERSITY CHENNAI
Figure 2.4 Form Window
The Toolbar provides quick access to commonly used commands. These will be
explained later in the document.
The Toolbox (Control Bar) is a floating window (Figure 2.5) which provides the
tools for designing/creating an application on your form. They can create buttons, text
boxes, labels, scroll bars and other commonly used windows items.
To build the interface elements, you click an interface control in the Visual Basic
toolbox, and then you draw the user interface element on your form by using the mouse.
This process is usually a simple matter of clicking to position one corner of the element and
then dragging to create a rectangle the size you want. After you create the element say,
a text box you can refine it by setting properties for the element. In a text box, for
example, you can set properties to make the text boldface, italic, or underlined.
Figure 2.5 Tool Box (Control Bar) Figure 2.6 Property Window


DMC 1944
NOTES
58 ANNA UNIVERSITY CHENNAI
The Property Window - With the Properties window (figure 2.6), you change the
characteristics (property settings) of the user interface elements on a form. A property
setting is a characteristic of a user interface object. For example, you can change the text
displayed by a text box control to a different font, point size, or alignment.
The Project Window (figure 2.7) includes all the forms, programming code and
other files needed and provides access to them with two special buttons: View Code and
View Object.
Figure 2.7 Project Window
To display the Project window, click the Project Explorer button on the Visual Basic
toolbar. If the window is currently docked, you can enlarge it by double-clicking the title
bar. To re-dock the Project window, double-click its title bar again.
The project file maintains a list of all the supporting files in a Visual Basic programming
project. You can recognize project files by their .vbp file name extension. You can add
individual files to and remove them from a project by using commands on the Project
menu. The changes that you make will be reflected in the Project window.
If you load additional projects into Visual Basic with the File menu Add Project
command, outlining symbols appear in the Project window to help you organize and switch
between projects.
2.4 STEPS FOR BUILDING A VISUAL BASIC APPLICATION
After designing the application, for building an application in Visual Basic following
steps are to be taken:
Draw the Interface - Create the form and the various objects on the
form using toolbox.
Set the Properties - Set the properties of the various objects on the
form with the help of properties window.
Write the events code - In the code window, write the code associated
with each object on the form and then run the
application.
VISUAL PROGRAMMING
NOTES
59 ANNA UNIVERSITY CHENNAI
Lets take a look at a sample program that helps you to start with a new VB6.0
application and understand the various steps involved in creating an application.
Program 2.1: A sample program highlighting the steps in creating a project and running it.
1. Start the visual basic by clicking Start>>Programs>>Microsoft Visual
Studio6.0>>Microsoft Visual Basic
2. Choose Standard EXE from the available screen
3. Click Open.
4. A blank form will appear on the screen with Project Explorer Window,
Properties Window and Tool Box as shown in figure 2.8 (a) & (b).
(a) (b)
Figure 2.8 (a) Project Explorer Window & (b) Properties Window
5. With the help of Tool Box given on the left side of the interface, draw the interface
as shown in Figure 2.9.
Figure 2.9 Sample interface
DMC 1944
NOTES
60 ANNA UNIVERSITY CHENNAI
6. Set the properties of the objects on the form as given in the table below:
Object Name Property Value
Text Box Text1 Text <Blank>
Command Button Command1 Caption Click here
Command Button Command2 Caption Stop
7. Double click First Command Button and write the following lines of code:
Private Sub Command1_Click()
Text1.Text =Welcome to Visual Basic
End Sub
8. Click View Object to come back at the form.
9. Double click Second Command Button and write the following lines of code:
Private Sub Command2_Click()
End
End Sub
10. Run the project by clicking Run>>Start or Press F5 and youll see an output as
shown in Figure 2.10.
Figure 2.10 Snapshot of the Output for Program 2.1
11. Save the project by clicking File>>Save Project.
12. Specify the folder in which all the files like form, reports etc. related with the
project along with the project name are to be saved.
Note: It is advised that one folder for each project should be created.
VISUAL PROGRAMMING
NOTES
61 ANNA UNIVERSITY CHENNAI
2.5 FORM AND PROPERTIES
The Form is where the user interface is drawn. It is central to the development of
Visual Basic applications.
Form Properties:
Appearance Selects 3-D or flat appearance.
BackColor Sets the form background color.
BorderStyle Sets the form border to be fixed or sizeable.
Caption Sets the form window title.
Enabled If True, allows the form to respond to mouse and
keyboard events; if False, disables form.
Font Sets font type, style, size.
ForeColor Sets color of text or graphics.
Picture Places a bitmap picture in the form.
Visible If False, hides the form.
Form Events:
Activate Form_Activate event is triggered when form
becomes the active window.
Click Form_Click event is triggered when user clicks
on form.
DblClick Form_DblClick event is triggered when user
double-clicks on form.
Load Form_Load event occurs when form is loaded.
This is a good place to initialize variables and set
any run-time properties.
Form Methods:
Cls Clears all graphics and text from form. Does not
clear any objects.
Print Prints text string on the form.
Examples
frmExample.Cls clears the form
frmExample.Print This will print on the form
2.5.1 The Show and Hide Methods
The Show method of a form displays that form on the screen. If the form to be shown
is not already loaded into memory, the Show method will load it before showing it. The
Show method is typically used to transfer control from one form to another. The syntax is:
formname.Show
DMC 1944
NOTES
62 ANNA UNIVERSITY CHENNAI
For example, if you are in Form1 and you want to display Form2, the syntax would be:
Form2.Show
When you display one form from another, you may want the user to complete work
on that form before returning to the first one. This does not happen automatically. By
default, VB will display the second form and then continue executing code from the first
form. To suspend execution of the first form until after the second form is done with, add
the keyword constant vbModal as an argument to the Show method. The syntax is:
Form2.Show vbModal
The Hide method of a form removes the form from the screen (makes it invisible),
but the form still remains in memory. The syntax is:
formname.Hide
To refer to the form in which code is currently running (i.e. the current form, or the
active form), you can of course refer to the form by its name, as in the example above:
Form1.Hide
As an alternative, you can use the keyword Me. The keyword Me refers to the form in
which code is currently running:
Me.Hide
Finally, any time you want to execute a method of the form on itself, you can simply code
the method name, omitting the formname. or the Me., as in:
Hide
2.5.2 The Load and Unload Statements
The Load statement loads a form into memory, but does not display it. When you
code the Load statement for a form, the Form_Load event of that form will be triggered.
The syntax is:
Load formname
The Unload statement removes a form from memory and from the screen. When you
code the Unload statement for a form, the Form_Unload event of that form will be triggered.
The syntax is:
Unload formname
A form can unload itself, as in:
Unload Me
The Unload event is also triggered with the user clicks the Windows close button
(X) on the form.
VISUAL PROGRAMMING
NOTES
63 ANNA UNIVERSITY CHENNAI
Program 2.2: A program using form unload event
1. Place a command button named cmdExit with the caption Exit on a form.
2. In the Click event for the command button, instead of coding End, code:
Private Sub cmdExit_Click( )
Unload Me
End Sub
3. For the Form_Unload event, code the following:
Private Sub Form_Unload(Cancel As Integer)
If MsgBox(Are you sure you want to quit?, vbYesNo +_ vbQuestion,
Unload Test) =vbNo Then Cancel =1
End Sub
4. Run the program and observe what happens either when you click the Exit button,
or when you try to close the form by clicking on the X button.
The program will prompt you with a message box as shown in Figure 2.11 which is a
snapshot of the program output when you try to click the Exit button, or when you try to
close the form by clicking on the X button.
Note that VB supplies the Unload event with a built-in argument called Cancel. If,
in the Unload event procedure, you set the Cancel argument to any non-zero value, the
Unload event will be cancelled (i.e., the form will not be unloaded) and processing will
continue. This event is where you might ask the user if they are sure they want to quit. If
they respond Yes, let the Unload event do its thing; if No, set Cancel to non-zero value.
Figure 2.11 Snapshot of the Output for Program 2.2
DMC 1944
NOTES
64 ANNA UNIVERSITY CHENNAI
Note: When all forms of a VB project are unloaded, the application ends. The End statement
automatically unloads all forms in a project, but will not trigger the Unload event (so any
code you have in the Unload event will not execute) therefore, ending an application with
End does not give the user a second chance to keep working with the program. The End
statement ends the program abruptly.
2.6 VARIABLES AND CONSTANTS
2.6.1 Variables
As objects are added to the form, Visual Basic automatically builds a framework of
all event procedures. We simply add code to the event procedures we want our application
to respond to. But before we do this, we need to discuss variables.
Variables are used by Visual Basic to hold information needed by your application.
Rules used in naming variables:
1. No more than 40 characters
2. They may include letters, numbers, and underscore (_)
3. The first character must be a letter
4. You cannot use a reserved word (word needed by Visual Basic)
2.6.1.1 Visual Basic Data Types
Data Type Suffix
Boolean None
Integer %
Long (Integer) &
Single (Floating) !
Double (Floating) #
Currency @
Date None
Object None
String $
Variant None
2.6.1.2 Variable Declaration and Scope
There are three ways for a variable to be typed (declared): 1) Default, 2) Implicit and
3) Explicit.
If variables are not implicitly or explicitly typed, they are assigned the variant type by
default. The variant data type is a special type used by Visual Basic that can contain
numeric, string, or date data.
VISUAL PROGRAMMING
NOTES
65 ANNA UNIVERSITY CHENNAI
To implicitly type a variable, use the corresponding suffix shown above in the data
type table. For example,
TextValue$ =This is a string
creates a string variable, while
Amount% =300
creates an integer variable.
There are many advantages to explicitly typing variables. Primarily, we insure all
computations are properly done, mistyped variable names are easily spotted, and Visual
Basic will take care of insuring consistency in upper and lower case letters used in variable
names. Because of these advantages, and because it is good programming practice, we
will explicitly type all variables.
To explicitly type a variable, you must first determine its scope. There are four
levels of scope:
1. Procedure level
2. Procedure level, static
3. Form and module level
4. Global level
Within a procedure, variables are declared using the Dim statement:
Dim MyInt as Integer
Dim MyDouble as Double
Dim MyString, YourString as String
Procedure level variables declared in this manner do not retain their value once a
procedure terminates.
To make a procedure level variable retain its value upon exiting the procedure, replace
the Dim keyword with Static:
Static MyInt as Integer
Static MyDouble as Double
Form (module) level variables retain their value and are available to all procedures
within that form (module). Form (module) level variables are declared in the declarations
part of the general object in the forms (modules) code window. The Dim keyword is
used:
Dim MyInt as Integer
Dim MyDate as Date
DMC 1944
NOTES
66 ANNA UNIVERSITY CHENNAI
Global level variables retain their value and are available to all procedures within an
application. Module level variables are declared in the declarations part of the general
object of a modules code window. (It is advisable to keep all global variables in one
module.) Use the Global keyword:
Global MyInt as Integer
Global MyDate as Date
What happens if you declare a variable with the same name in two or more places?
More local variables shadow (are accessed in preference to) less local variables. For
example, if a variable MyInt is defined as Global in a module and declared local in a
routine MyRoutine, while in MyRoutine, the local value of MyInt is accessed. Outside
MyRoutine, the global value of MyInt is accessed.
Example of Variable Scope:
Module1
Procedure Routine1 has access to X, Y, and A (loses value upon termination)
Procedure Routine2 has access to X, Y, and B (retains value)
Procedure Routine3 has access to X, Z, and C (loses value)
Global X as Integer
Form1

Form2
Dim Y as Integer
Sub Routine1()
Dim A as Double
-
-
End Sub

Sub Routine2()
Static B as Double
-
-
End Sub



Dim Z as Single
Sub Routine3()
Dim C as String


End Sub



VISUAL PROGRAMMING
NOTES
67 ANNA UNIVERSITY CHENNAI
Program 2.3: Stopwatch Application
1. Start the visual basic by clicking Start>>Programs>>Microsoft Visual Studio
6.0>>Microsoft Visual Basic.
2. Choose Standard EXE from the available screen.
3. Double-click anywhere on the form to open the code window. Or, select View
Code from the project window.
4. Click the down arrow in the Object box and select the object named (general).
The Procedure box will show (declarations). Here, you declare three form level
variables:
Option Explicit
Dim StartTime As Variant
Dim EndTime As Variant
Dim ElapsedTime As Variant
The Option Explicit statement forces us to declare all variables. The other lines
establish StartTime, EndTime, and ElapsedTime as variables global within the form.
5. Select the cmdStart object in the Object box. If the procedure that appears is not
the Click procedure, choose Click from the procedure box. Type the following
code which begins the timing procedure. Note the Sub and End Sub statements
are provided for you:
Sub cmdStart_Click ()
Set and print starting time
StartTime =Now
lblStart.Caption =Format(StartTime, hh:mm:ss)
lblEnd.Caption =
lblElapsed.Caption =
End Sub
In this procedure, once the Start Timing button is clicked, we read the current time
and print it in a label box. We also blank out the other label boxes. In the code above (and
in all code in these notes), any line beginning with a single quote () is a comment. You
decide whether you want to type these lines or not. They are not needed for proper
application operation.
6. Now, code the cmdEnd button.
Sub cmdEnd_Click ()
Find the ending time, compute the elapsed time
Put both values in label boxes
EndTime =Now
ElapsedTime =EndTime - StartTime
lblEnd.Caption =Format(EndTime, hh:mm:ss)
lblElapsed.Caption =Format(ElapsedTime, hh:mm:ss)
End Sub
DMC 1944
NOTES
68 ANNA UNIVERSITY CHENNAI
Here, when the End Timing button is clicked, we read the current time (End Time),
compute the elapsed time, and put both values in their corresponding label boxes.
7. And, finally the cmdExit button.
Sub cmdExit_Click ()
End
End Sub
This routine simply ends the application once the Exit button is clicked.
8. Did you notice that as you typed in the code, Visual Basic does automatic syntax
checking on what you type?
9. Run your application by clicking the Run button on the toolbar, or by pressing
<f5>.
10. Save your application. Use the Save Project As option under the File menu.
Make sure you save both the form and the project files.
2.6.1.3 Arrays
Up to now, weve only worked with regular variables, each having its own unique
name. Visual Basic has powerful facilities for handling multi-dimensional variables, or
arrays. For now, well only use single, fixed-dimension arrays.
Arrays are declared in a manner identical to that used for regular variables. For
example, to declare an integer array named Items, with dimension 9, at the procedure
level, we use:
Dim Items(9) as Integer
If we want the array variables to retain their value upon leaving a procedure, we use the
keyword Static:
Static Items(9) as Integer
At the form or module level, in the general declarations area of the Code window, use:
Dim Items(9) as Integer
And, at the module level, for a global declaration, use:
Global Items(9) as Integer
The index on an array variable begins at 0 and ends at the dimensioned value. For
example, the Items array in the above examples has ten elements, ranging from Items(0)
to Items(9). You use array variables just like any other variable - just remember to include
its name and its index.
VISUAL PROGRAMMING
NOTES
69 ANNA UNIVERSITY CHENNAI
2.7 CONTROL STATEMENTS
Visual Basic procedures can test conditions and then, depending on the results of that
test, perform different operations. The decision structures that Visual Basic supports include:
If...Then
If...ThenEnd If
If...Then...ElseEnd If
Select Case
2.7.1 If Statements
Branching statements are used to cause certain actions within a program if a certain
condition is met.
The simplest is the If/Then statement:
If Balance - Check <0 Then Print You are overdrawn
Here, if and only if Balance - Check is less than zero, the statement You are
overdrawn is printed.
You can also have If/Then/End If blocks to allow multiple statements:
If Balance - Check <0 Then
Print You are overdrawn
Print Authorities have been notified
End If
In this case, if Balance - Check is less than zero, two lines of information are printed.
The same balance chencking logic may be implemented using If/Then/Else/End If
blocks:
If Balance - Check <0 Then
Print You are overdrawn
Print Authorities have been notified
Else
Balance =Balance - Check
End If
Here, the same two lines are printed if you are overdrawn (Balance - Check <0),
but, if you are not overdrawn (Else), your new Balance is computed.
DMC 1944
NOTES
70 ANNA UNIVERSITY CHENNAI
We can also add the ElseIf statement:
If Balance - Check <0 Then
Print You are overdrawn
Print Authorities have been notified
ElseIf Balance - Check =0 Then
Print Whew! You barely made it
Balance =0
Else
Balance =Balance - Check
End If
Now, one more condition is added. If your Balance equals the Check amount (ElseIf
Balance - Check =0), a different message appears.
In using branching statements, make sure you consider all viable possibilities in the If/
Else/End If structure. Also, be aware that each If and ElseIf in a block is tested sequentially.
The first time an If test is met, the code associated with that condition is executed and the
If block is exited. If a later condition is also True, it will never be considered.
2.7.2 Select Case - Another Way to Branch
Visual Basic provides the Select Case structure as an alternative to If...Then...Else
for selectively executing one block of statements from among multiple blocks of statements.
A Select Case statement provides capability similar to the If...Then...Else statement, but it
makes code more readable when there are several choices.
A Select Case structure works with a single test expression that is evaluated once, at
the top of the structure. Visual Basic then compares the result of this expression with the
values for each Case in the structure. If there is a match, it executes the block of statements
associated with that Case:
Select Case testexpression
[Case expressionlist1
[statementblock-1]]
[Case expressionlist2
[statementblock-2]]
.
.
.
[Case Else
[statementblock-n]]
End Select
VISUAL PROGRAMMING
NOTES
71 ANNA UNIVERSITY CHENNAI
Each expressionlist is a list of one or more values. If there is more than one value in
a single list, the values are separated by commas. Each statementblock contains zero or
more statements. If more than one Case matches the test expression, only the statement
block associated with the first matching Case will execute. Visual Basic executes statements
in the Case Else clause (which is optional) if none of the values in the expression lists
matches the test expression.
Say weve written this code using the If statement:
If Age =5 Then
Category =Five Year Old
ElseIf Age >=13 and Age <=19 Then
Category =Teenager
ElseIf (Age >=20 and Age <=35) Or Age =50 Or (Age >=60 and Age <=65) Then
Category =Special Adult
ElseIf Age >65 Then
Category =Senior Citizen
Else
Category =Everyone Else
End If
The corresponding code with Select Case would be:
Select Case Age
Case 5
Category =Five Year Old
Case 13 To 19
Category =Teenager
Case 20 To 35, 50, 60 To 65
Category =Special Adult
Case Is >65
Category =Senior Citizen
Case Else
Category =Everyone Else
End Select
Notice there are several formats for the Case statement. Consult on-line help for discussions
of these formats.
DMC 1944
NOTES
72 ANNA UNIVERSITY CHENNAI
2.7.3 The GoTo Statement
Another branching statement, and perhaps the most hated statement in programming,
is the GoTo statement. However, we will need this to do Run-Time error trapping. The
format is GoTo Label, where Label is a labeled line. Labeled lines are formed by typing
the Label followed by a colon.
GoTo Example:
When the code reaches the GoTo statement, program control transfers to the line
labeled Line10.
2.7.4 Visual Basic Looping
Loop structures allow you to execute one or more lines of code repetitively. The loop
structures that Visual Basic supports include:
Do...Loop
For...Next
For Each...Next
Looping is done with the Do/Loop format. Loops are used for operations are to be
repeated some number of times. The loop repeats until some specified condition at the
beginning or end of the loop is met.
Do While/Loop Example:
Counter =1
Do While Counter <=1000
Debug.Print Counter
Counter =Counter +1
Loop
This loop repeats as long as (While) the variable Counter is less than or equal to
1000. Note a Do While/Loop structure will not execute even once if the While condition
is violated (False) the first time through. Also note the Debug.Print statement. What this
does is print the value Counter in the Visual Basic Debug window. Well learn more about
this window later in the course.
Do Until/Loop Example:
Counter =1
Do Until Counter > 1000
Debug.Print Counter
Counter =Counter +1
Loop
Line:10
.
.
GoTo Line10
VISUAL PROGRAMMING
NOTES
73 ANNA UNIVERSITY CHENNAI
This loop repeats Until the Counter variable exceeds 1000. Note a Do Until/Loop
structure will not be entered if the Until condition is already True on the first encounter.
Do/Loop While Example:
Sum =1
Do
Debug.Print Sum
Sum =Sum +3
Loop While Sum <=50
This loop repeats While the Variable Sum is less than or equal to 50. Note, since the
While check is at the end of the loop, a Do/Loop While structure is always executed at
least once.
Do/Loop Until Example:
Sum =1
Do
Debug.Print Sum
Sum =Sum +3
Loop Until Sum >50
This loop repeats Until Sum is greater than 50. And, like the previous example, a Do/
Loop Until structure always executes at least once.
Make sure you can always get out of a loop! Infinite loops are never nice. If you get
into one, try Ctrl+Break. That sometimes works - other times the only way out is rebooting
your machine!
The statement Exit Do will get you out of a loop and transfer program control to the
statement following the Loop statement.
For/Next Loop
Do loops work well when you dont know how many times you need to execute the
statements in the loop. When you know you must execute the statements a specific number
of times, however, a ForNext loop is a better choice. Unlike a Do loop, a For loop uses
a variable called a counter that increases or decreases in value during each repetition of the
loop. The syntax is:
For counter =start To end [Step increment]
statements
Next [counter]
DMC 1944
NOTES
74 ANNA UNIVERSITY CHENNAI
The arguments counter, start, end, and increment are all numeric.
The increment argument can be either positive or negative. If increment is positive,
start must be less than or equal to end or the statements in the loop will not execute. If
increment is negative, start must be greater than or equal to end for the body of the loop
to execute. If Step isnt set, then increment defaults to 1.
In executing the For loop, Visual Basic:
1. Sets counter equal to start.
2. Tests to see if counter is greater than end. If so, Visual Basic exits the loop.
3. (If increment is negative, Visual Basic tests to see if counter is less than end.)
4. Executes the statements.
5. Increments counter by 1 or by increment, if its specified.
6. Repeats steps 2 through 4.
Counting is accomplished using the For/Next loop.
Example
For I =1 to 50 Step 2
A =I * 2
Debug.Print A
Next I
In this example, the variable I initializes at 1 and, with each iteration of the For/Next
loop, is incremented by 2 (Step). This looping continues until I becomes greater than or
equal to its final value (50). If Step is not included, the default value is 1. Negative values
of Step are allowed.
You may exit a For/Next loop using an Exit For statement. This will transfer program
control to the statement following the Next statement.
2.7.5 Nested Control Structures
You can place control structures inside other control structures (such as an If...Then
block within a For...Next loop). A control structure placed inside another control structure
is said to be nested.
Control structures in Visual Basic can be nested to as many levels as you want. Its
common practice to make nested decision structures and loop structures more readable
by indenting the body of the decision structure or loop.
For example, this procedure prints all the font names that are common to both the
Printer and Screen:
VISUAL PROGRAMMING
NOTES
75 ANNA UNIVERSITY CHENNAI
Private Sub Form_Click()
Dim SFont, PFont
For Each SFont In Screen.Fonts()
For Each PFont In Printer.Fonts()
If SFont =PFont Then
Print SFont
End If
Next PFont
Next SFont
End Sub
Notice that the first Next closes the inner For loop and the last For closes the outer
For loop. Likewise, in nested If statements, the End If statements automatically apply to
the nearest prior If statement. Nested Do...Loop structures work in a similar fashion, with
the innermost Loop statement matching the innermost Do statement.
Exiting a Control Structure
The Exit statement allows you to exit directly from a For loop, Do loop, Sub procedure,
or Function procedure. The syntax for the Exit statement is simple: Exit For can appear as
many times as needed inside a For loop, and Exit Do can appear as many times as needed
inside a Do loop:
For counter = start To end [Step increment]
[statementblock]
[Exit For]
[statementblock]
Next [counter[, counter] [,...]]
Do [{While | Until} condition]
[statementblock]
[Exit Do]
[statementblock]
Loop
The Exit Do statement works with all versions of the Do loop syntax.
Exit For and Exit Do are useful because sometimes its appropriate to quit a loop
immediately, without performing any further iterations or statements within the loop. For
example, in the previous example that printed the fonts common to both the Screen and
Printer, the code continues to compare Printer fonts against a given Screen font even when
a match has already been found with an earlier Printer font. A more efficient version of the
function would exit the loop as soon as a match is found:
DMC 1944
NOTES
76 ANNA UNIVERSITY CHENNAI
Private Sub Form_Click()
Dim SFont, PFont
For Each SFont In Screen.Fonts()
For Each PFont In Printer.Fonts()
If SFont =PFont Then
Print Sfont
Exit For Exit inner loop.
End If
Next PFont
Next SFont
End Sub
As this example illustrates, an Exit statement almost always appears inside an If
statement or Select Case statement nested inside the loop.
When you use an Exit statement to break out of a loop, the value of the counter
variable differs, depending on how you leave the loop:
When you complete a loop, the counter variable contains the value of the upper
bound plus the step.
When you exit a loop prematurely, the counter variable retains its value subject to
the usual rules on scope.
When you iterate off the end of a collection, the counter variable contains Nothing
if its an Object data type, and contains Empty if its a Variant data type.
2.8 CONTROL ARRAYS
With some controls, it is very useful to define control arrays - it depends on the
application. For example, option buttons are almost always grouped in control arrays.
Control arrays are a convenient way to handle groups of controls that perform a
similar function. All of the events available to the single control are still available to the
array of controls, the only difference being an argument indicating the index of the selected
array element is passed to the event. Hence, instead of writing individual procedures for
each control (i.e. not using control arrays), you only have to write one procedure for each
array.
Another advantage to control arrays is that you can add or delete array elements at
run-time. You cannot do that with controls (objects) not in arrays. Refer to the Load and
Unload statements in on-line help for the proper way to add and delete control array
elements at run-time.
Two ways to create a control array:
Create an individual control and set desired properties. Copy the control using the
editor, then paste it on the form. Visual Basic will pop-up a dialog box that will ask you if
you wish to create a control array. Respond yes and the array is created.
VISUAL PROGRAMMING
NOTES
77 ANNA UNIVERSITY CHENNAI
Create all the controls you wish to have in the array. Assign the desired control array
name to the first control. Then, try to name the second control with the same name. Visual
Basic will prompt you, asking if you want to create a control array. Answer yes. Once the
array is created, rename all remaining controls with that name.
Once a control array has been created and named, elements of the array are referred
to by their name and index. For example, to set the Caption property of element 6 of a
label box array named lblExample, we would use:
lblExample(6).Caption =This is an example
2.9 CREATING AND USING CONTROLS
2.9.1 Command Buttons
Command button is probably the most widely used control. It is used to begin,
interrupt, or end a particular process.
Command Button Properties:
Appearance Selects 3-D or flat appearance.
Cancel Allows selection of button with Esc key (only one button
on a form can have this property True).
Caption String to be displayed on button.
Default Allows selection of button with Enter key (only one button
on a form can have this property True).
Font Sets font type, style, size.
Command Button Events:
Click Event triggered when button is selected either by clicking
on it or by pressing the access key.
2.9.2 Label Boxes
A label box is a control you use to display text that a user cant edit directly. The text
of a label box can be changed at run-time in response to events.
Label Properties:
Alignment Aligns caption within border.
Appearance Selects 3-D or flat appearance.
AutoSize If True, the label is resized to fit the text specifed by the
caption property. If False, the label will remain the size
defined at design time and the text may be clipped.
BorderStyle Determines type of border.
Caption String to be displayed in box.
Font Sets font type, style, size.
DMC 1944
NOTES
78 ANNA UNIVERSITY CHENNAI
WordWrap Works in conjunction with AutoSize property. If AutoSize
=True, WordWrap =True, then the text will wrap and
label will expand vertically to fit the Caption. If AutoSize
=True, WordWrap =False, then the text will not wrap
and the label expands horizontally to fit the Caption. If
AutoSize =False, the text will not wrap regardless of
WordWrap value.
Label Events:
Click Event triggered when user clicks on a label.
DblClick Event triggered when user double-clicks on a label.
2.9.3 Text Boxes
A text box is used to display information entered at design time, by a user at run-
time, or assigned within code. The displayed text may be edited.
Text Box Properties:
Appearance Selects 3-D or flat appearance.
BorderStyle Determines type of border.
Font Sets font type, style, size.
MaxLength Limits the length of displayed text (0 value indicates
unlimited length).
MultiLine Specifies whether text box displays single line or multiple
lines.
PasswordChar Hides text with a single character.
ScrollBars Specifies type of displayed scroll bar(s).
SelLength Length of selected text (run-time only).
SelStart Starting position of selected text (run-time only).
SelText Selected text (run-time only).
Tag Stores a string expression.
Text Displayed text.
Text Box Events:
Change Triggered every time the Text property changes.
LostFocus Triggered when the user leaves the text box. This is a
good place to examine the contents of a text box after
editing.
KeyPress Triggered whenever a key is pressed. Used for key
trapping, as seen in last class.
Text Box Methods:
SetFocus Places the cursor in a specified text box.
VISUAL PROGRAMMING
NOTES
79 ANNA UNIVERSITY CHENNAI
Program 2.4: Password Application that gets a password from the user. If correct, a
message box appears to validate the user. If incorrect, other options are provided.
1. Start a new project.
2. Place a two command buttons, a label box, and a text box on your form as shown
in figure 2.12.
Figure 2.12 Form Design
3. Set the properties of the form and each object.
Form1:
BorderStyle 1-Fixed Single
Caption Password Validation
Name frmPassword
Label1:
Alignment 2-Center
BorderStyle 1-Fixed Single
Caption Please Enter Your Password:
FontSize 10
FontStyle Bold
Text1:
FontSize 14
FontStyle Regular
Name txtPassword
PasswordChar *
Tag [Whatever you choose as a password, e.g.
ABC]
Text [Blank]
DMC 1944
NOTES
80 ANNA UNIVERSITY CHENNAI
Command1:
Caption &Validate
Default True
Name cmdValid
Command2:
Cancel True
Caption E&xit
Name cmdExit
4. Attach the following code to the cmdValid_Click event.
Private Sub cmdValid_Click()
This procedure checks the input password
Dim Response As Integer
If txtPassword.Text =txtPassword.Tag Then
If correct, display message box
MsgBox Youve passed security!, vbOKOnly +vbExclamation, Access
Granted
Else
If incorrect, give option to try again
Response =MsgBox(Incorrect password, vbRetryCancel +vbCritical,
Access Denied)
If Response =vbRetry Then
txtPassword.SelStart =0
txtPassword.SelLength =Len(txtPassword.Text)
Else
End
End If
End If
txtPassword.SetFocus
End Sub
This code checks the input password to see if it matches the stored value. If so, it
prints an acceptance message. If incorrect, it displays a message box to that effect and
asks the user if they want to try again. If Yes (Retry), another try is granted. If No
(Cancel), the program is ended. Notice the use of SelLength and SelStart to highlight an
incorrect entry. This allows the user to type right over the incorrect response.
VISUAL PROGRAMMING
NOTES
81 ANNA UNIVERSITY CHENNAI
5. Attach the following code to the Form_Activate event.
Private Sub Form_Activate()
txtPassword.SetFocus
End Sub
6. Attach the following code to the cmdExit_ Click event.
Private Sub cmdExit_Click()
End
End Sub
7. Try running the program. Try both options: input correct password (note it is case
sensitive) and input incorrect password. Save your project.
2.9.4 Check Boxes
Check boxes provide a way to make choices from a list of potential candidates.
Some, all, or none of the choices in a group may be selected.
Check Box Properties:
Caption Identifying text next to box.
Font Sets font type, style, size.
Value Indicates if unchecked (0, vbUnchecked), checked (1,
vbChecked), or grayed out (2, vbGrayed).
Check Box Events:
Click Triggered when a box is clicked. Value property is automatically
changed by Visual Basic.
2.9.5 Option Buttons
Option buttons provide the capability to make a mutually exclusive choice among a
group of potential candidate choices. Hence, option buttons work as a group, only one of
which can have a True (or selected) value.
Option Button Properties:
Caption Identifying text next to button.
Font Sets font type, style, size.
Value Indicates if selected (True) or not (False). Only one option button
in a group can be True. One button in each group of option buttons
should always be initialized to True at design time.
Option Button Events:
Click Triggered when a button is clicked. Value property is automatically
changed by Visual Basic.
DMC 1944
NOTES
82 ANNA UNIVERSITY CHENNAI
2.9.6 Frames
Frames provide a way of grouping related controls on a form. And, in the case of
option buttons, frames affect how such buttons operate.
To group controls in a frame, you first draw the frame. Then, the associated controls
must be drawn in the frame. This allows you to move the frame and controls together.
And, once a control is drawn within a frame, it can be copied and pasted to create a
control array within that frame. To do this, first click on the object you want to copy.
Copy the object. Then, click on the frame. Paste the object. You will be asked if you
want to create a control array. Answer Yes.
Drawing the controls outside the frame and dragging them in, copying them into a
frame, or drawing the frame around existing controls will not result in a proper grouping. It
is perfectly acceptable to draw frames within other frames.
As mentioned, frames affect how option buttons work. Option buttons within a
frame work as a group, independently of option buttons in other frames. Option buttons
on the form, and not in frames, work as another independent group. That is, the form is
itself a frame by default. Well see this in the next example.
It is important to note that an independent group of option buttons is defined by
physical location within frames, not according to naming convention. That is, a control
array of option buttons does not work as an independent group just because it is a control
array. It would only work as a group if it were the only group of option buttons within a
frame or on the form. So, remember physical location, and physical location only, dictates
independent operation of option button groups.
Frame Properties:
Caption Title information at top of frame.
Font Sets font type, style, size.
2.9.7 List Boxes
A list box displays a list of items from which the user can select one or more items. If
the number of items exceeds the number that can be displayed, a scroll bar is automatically
added.
List Box Properties:
Appearance Selects 3-D or flat appearance.
List Array of items in list box.
ListCount Number of items in list.
ListIndex The number of the most recently selected item in list. If
no item is selected, ListIndex =-1.
VISUAL PROGRAMMING
NOTES
83 ANNA UNIVERSITY CHENNAI
MultiSelect Controls how items may be selected (0-no multiple
selection allowed, 1-multiple selection allowed, 2-group
selection allowed).
Selected Array with elements set equal to True or False, depending
on whether corresponding list item is selected.
Sorted True means items are sorted in Ascii order, else items
appear in order added.
Text Text of most recently selected item.
List Box Events:
Click Event triggered when item in list is clicked.
DblClick Event triggered when itemin list is double-clicked. Primary
way used to process selection.
List Box Methods:
AddItem Allows you to insert item in list.
Clear Removes all items from list box.
RemoveItem Removes item from list box, as identified by index of item
to remove.
Examples
lstExample.AddItem This is an added item adds text string to list
lstExample.Clear clears the list box
lstExample.RemoveItem 4 removes lstExample.List(4) from list box
Items in a list box are usually initialized in a Form_Load procedure. Its always a
good idea to Clear a list box before initializing it.
2.9.8 Combo Boxes
The combo box is similar to the list box. The differences are a combo box includes
a text box on top of a list box and only allows selection of one item. In some cases, the
user can type in an alternate response.
Combo Box Properties:
Combo box properties are nearly identical to those of the list box, with the deletion of
the MultiSelect property and the addition of a Style property.
Appearance Selects 3-D or flat appearance.
List Array of items in list box portion.
ListCount Number of items in list.
ListIndex The number of the most recently selected item in list. If
no item is selected, ListIndex =-1.
DMC 1944
NOTES
84 ANNA UNIVERSITY CHENNAI
Sorted True means items are sorted in Ascii order, else items
appear in order added.
Style Selects the combo box form.
Style =0, Dropdown combo; user can change selection.
Style =1, Simple combo; user can change selection.
Style =2, Dropdown combo; user cannot change
selection.
Text Text of most recently selected item.
Combo Box Events:
Click Event triggered when item in list is clicked.
DblClick Event triggered when itemin list is double-clicked. Primary
way used to process selection.
Combo Box Methods:
AddItem Allows you to insert item in list.
Clear Removes all items from list box.
RemoveItem Removes item from list box, as identified by index of item
to remove.
Examples
cboExample.AddItem This is an added item adds text string to list
cboExample.Clear clears the combo box
cboExample.RemoveItem 4 removes cboExample.List(4) from list box
Program 2.5: Flight Planner An application in which the user can select a destination
city, a seat location and a meal preference for airline passengers.
1. Start a new project.
2. Place a list box, two combo boxes, three label boxes and two command buttons
on the form as shown in figure 2.13.
Figure 2.13 Form Design
VISUAL PROGRAMMING
NOTES
85 ANNA UNIVERSITY CHENNAI
3. Set the form and object properties:
Form1:
BorderStyle 1-Fixed Single
Caption Flight Planner
Name frmFlight
List1:
Name lstCities
Sorted True
Combo1:
Name cboSeat
Style 2-Dropdown List
Combo2:
Name cboMeal
Style 1-Simple
Text [Blank]
(After setting properties for this combo box, resize it until it is large enough to hold
4 to 5 entries.)
Label1:
Caption Destination City
Label2:
Caption Seat Location
Label3:
Caption Meal Preference
Command1:
Caption &Assign
Name cmdAssign
Command2:
Caption E&xit
Name cmdExit
DMC 1944
NOTES
86 ANNA UNIVERSITY CHENNAI
Now, the form should look like the one shown in figure 2.14.
Figure 2.14 Form Design after step 3
4. Attach this code to the Form_Load procedure:
Private Sub Form_Load()
Add city names to list box
lstCities.Clear
lstCities.AddItem Chennai
lstCities.AddItem Trichy
lstCities.AddItem Coimbatore
lstCities.AddItem Bangalore
lstCities.AddItem Trivandrum
lstCities.AddItem Cochin
lstCities.AddItem Madurai
lstCities.AddItem Hyderabad
lstCities.ListIndex =0
Add seat types to first combo box
cboSeat.AddItem Aisle
cboSeat.AddItem Middle
cboSeat.AddItem Window
cboSeat.ListIndex =0
Add meal types to second combo box
cboMeal.AddItem Mini-Tiffin
cboMeal.AddItem Executive Lunch (Veg)
cboMeal.AddItem Executive Lunch (Non-Veg)
cboMeal.AddItem Sandwich
cboMeal.AddItem Fruit Plate
cboMeal.Text =No Preference
End Sub
This code simply initializes the list box and the list box portions of the two combo
boxes.
VISUAL PROGRAMMING
NOTES
87 ANNA UNIVERSITY CHENNAI
5. Attach this code to the cmdAssign_Click event:
Private Sub cmdAssign_Click()
Build message box that gives your assignment
Dim Message As String
Message =Destination: +lstCities.Text +vbCr
Message =Message +Seat Location: +cboSeat.Text +vbCr
Message =Message +Meal: +cboMeal.Text +vbCr
MsgBox Message, vbOKOnly +vbInformation, Your Assignment
End Sub
When the Assign button is clicked, this code forms a message box message by
concatenating the selected city (from the list box lstCities), seat choice (from cboSeat),
and the meal preference (from cboMeal).
6. Attach this code to the cmdExit_Click event:
Private Sub cmdExit_Click()
End
End Sub
7. Run the application. Save the project.
2.10 MENUS AND DIALOGS
2.10.1 Menus
Windows applications provide groups of related commands in Menus. These
commands depend on the application, but some-such as Open and Save are frequently
found in applications. Menus are intrinsic controls. On the other hand, menus behave
differently from other controls. For example, you dont drop menu items on a form from
the Toolbox; rather, you design them in the Menu Editor window, as you can see in the
figure 2.15. You invoke this tool from the Menu Editor button on the standard toolbar or
by pressing the Ctrl+E shortcut key. Theres also a Menu Editor command in the Tools
menu.
Figure 2.15 Menu Editor
DMC 1944
NOTES
88 ANNA UNIVERSITY CHENNAI
Visual Basic provides an easy way to create menus with the modal Menu Editor
dialog. The Menu Editor command is grayed unless the form is visible. And also you can
display the Menu Editor window by right clicking on the Form and selecting Menu Editor.
Basically, each menu item has a Caption property (possibly with an embedded &
character to create an access key) and a Name. Each item also exposes three Boolean
properties, Enabled, Visible, and Checked, which you can set both at design time and at
run time. At design time, you can assign the menu item a shortcut key so that your end
users dont have to go through the menu system each time they want to execute a frequent
command.
Building a menu is a simple job. All you need is to enter the items Caption and Name,
set other properties (or accept the default values for those properties), and press Enter to
move to the next item. When you want to create a submenu, you press the Right Arrow
button (or the Alt+R hot key). When you want to return to work on top-level menus
those items that appear in the menu bar when the application runsyou click the Left
Arrow button (or press Alt+L). You can move items up and down in the hierarchy by
clicking the corresponding buttons or the hot keys Alt+U and Alt+B, respectively.
You can insert a separator bar using the hypen (-) character for the Caption property.
But even these separator items must be assigned a unique value for the Name property. If
you forget to enter a menu items Name, the Menu Editor complains when you decide to
close it.
Program 2.6: Program highlighting steps to create menu.
1. Open a new Project and save the form as menu.frm and save the project as
menu.vbp.
2. Choose Tools Menu Editor and type the menu items given in table 2.1 and as
shown in figure 2.16.
Figure 2.16 Using Menu Editor to create Menu items given in table 2.1
VISUAL PROGRAMMING
NOTES
89 ANNA UNIVERSITY CHENNAI
Table 2.1 Menu Items
3. Run the application by pressing F5. You can see that you can select a menu
2.10.1.1 Accessing Menus at Run Time in Visual Basic 6
Menu controls expose only one event, Click. As you expect, this event fires when the
user clicks on the menu. For example consider the menu item Exit in program 2.6. Insert
the following code in the previous previous program 2.6.
Private Sub mnuFileExit_Click()
Unload Me
End Sub
When the user clicks the exit menu in the form at run time, the form unloads and the
application terminates.
You can manipulate menu items at run time through their Checked, Visible, and Enabled
properties. For example, you can easily implement a menu item that acts as a switch and
displays or hides a status bar:
Private Sub mnucopy_Click()
mnucopy.Checked =TRUE
End Sub
While menu items can be responsible for their own Checked status, you usually set
their Visible and Enabled properties in another region of the code. You make a menu item
invisible or disabled when you want to make the corresponding command unavailable to
the user. You can choose from two different strategies to achieve this goal: You can set the
menu properties as soon as something happens that affects that menu command, or you
can set them one instant before the menu is dropped down.
2.10.1.2 Creating Pop-up Menus in Visual Basic 6
Visual Basic also supports pop-up menus, those context-sensitive menus that most
commercial applications show when you right-click on an user interface object. In Visual
Basic, you can display a pop-up menu by calling the forms PopupMenu method, typically
from within the MouseDown event procedure of the object:
Caption Name
File mnuFile
Open mnuOpen
Save mnuSave
Exit mnuExit
Edit mnuEdit
Copy mnuCopy
Cut mnuCut
Paste mnuPaste
DMC 1944
NOTES
90 ANNA UNIVERSITY CHENNAI
Private Sub List1_MouseDown(Button As Integer, Shift As Integer, _
X As Single, Y As Single)
If Button And vbRightButton Then
User right-clicked the list box.
PopupMenu mnuListPopup
End If
End Sub
The argument you pass to the PopupMenu method is the name of a menu that you
have defined using the Menu Editor. This might be either a submenu that you can reach
using the regular menu structure or a submenu thats intended to work only as a pop-up
menu. In the latter case, you should create it as a top-level menu in the Menu Editor and
then set its Visible attribute to False. If your program includes many pop-up menus, you
might find it convenient to add one invisible top-level entry and then add all the pop-up
menus below it. The complete syntax of the PopupMenu method is:
PopupMenu Menu, [Flags], [X], [Y], [DefaultMenu]
By default, pop-up menus appear left aligned on the mouse cursor, and even if you
use a right-click to invoke the menu you can select a command only with the left button.
You can change these defaults using the Flags argument. The following constants control
the alignment: 0-vbPopupMenuLeftAlign (default), 4-vbPopupMenuCenterAlign, and 8-
vbPopupMenuRightAlign. The following constants determine which buttons are active during
menu operations: 0-vbPopupMenuLeftButton (default) and 2-vbPopupMenuRightButton.
The x and y arguments, if specified, make the menu appear in a particular position on
the form, rather than at mouse coordinates. The last optional argument is the name of the
menu thats the default item for the pop-up menu. This item will be displayed in boldface.
This argument has only a visual effect; If you want to offer a default menu item, you must
write code in the MouseDown event procedure to trap double-clicks with the right button.
Program 2.7: Program to create a popup menu to do text formatting.
1. Start a new VB project and place a label on the form. Name the label lblTestText.
Set the Caption to Test Text and the form looks as shown in figure 2.17.
Figure 2.17 From Design
VISUAL PROGRAMMING
NOTES
91 ANNA UNIVERSITY CHENNAI
Figure 2.18 Menu Items in Menu Editor
2. Open the Menu Editor, and create a top-level item with a Caption value of
PopUpFormat and the Name mnuPopuUpFormat. Also importantly uncheck
the Visible checkbox. In order for a menu to be a pop-up menu, it must be
invisible.
3. Create the following level-two menu items below the PopUpFormat top-level
menu. (When creating these level-two items, keep the Visible box checked.)
When done, your Menu Editor should look like the one shown in figure 2.18.
4. Click OK to save your changes. Note: When you return to the IDE, you will NOT
see this menu on the form (remember its a pop-up menu, and it will only be visible
when invoked through code).
5. Code the lblTestText_MouseDown event as shown below. Note that the Button
parameter is tested for vbRightButton as is conventional, we only want to pop
up the menu if the user right-clicks on the label. If the user clicks the right mouse
button, the PopupMenu statement is executed. It is this statement that makes the
pop-up menu appear.
Caption Name
Bold mnuBold
Italic mnuItalic
Underline mnuUnderline
- (hyphen) mnuFormatSep
Cancel mnuCancel
DMC 1944
NOTES
92 ANNA UNIVERSITY CHENNAI
Private Sub lblTestText_MouseDown(Button As Integer, Shift As Integer, _
X As Single, Y As Single)
If Button =vbRightButton Then
PopupMenu mnuPopUpFormat, vbPopupMenuRightButton
End If
End Sub
6. Code the mnuBold_Click event as shown below. Note that the Checked property
of the menu item is used. When set to True, this causes a checkmark to appear to
the left of the menu item. The Checked property is typically used as a toggle.
Private Sub mnuBold_Click()
If mnuBold.Checked Then
lblTestText.FontBold =False
mnuBold.Checked =False
Else
lblTestText.FontBold =True
mnuBold.Checked =True
End If
End Sub
7. Code the mnuItalic_Click and mnuUnderline_Click events in a similar fashion
as shown below.
Private Sub mnuItalic_Click()
If mnuItalic.Checked Then
lblTestText.FontItalic =False
mnuItalic.Checked =False
Else
lblTestText.FontItalic =True
mnuItalic.Checked =True
End If
End Sub
Private Sub mnuUnderline_Click()
If mnuUnderline.Checked Then
lblTestText.FontUnderline =False
mnuUnderline.Checked =False
Else
lblTestText.FontUnderline =True
mnuUnderline.Checked =True
End If
End Sub
VISUAL PROGRAMMING
NOTES
93 ANNA UNIVERSITY CHENNAI
8. Run the program to see a form as shown in figure 2.19 and check out the various
options you have coded.
Figure 2.19 Output Screen
9. Save the program and exit VB.
2.10.2 Dialog Boxes
Dialog boxes in VB are used for getting input from the user or to display information
to the user. Dialog boxes are of two types: Input box and Message box.
2.10.2.1 Input Box
The InputBox displays a prompt in a dialog box, waits for the user to input text or
click a button, and returns a string containing the contents of the text box.
Syntax:
stringvariable =InputBox(prompt[, title] [, default] [, xpos] [, ypos] [, helpfile, context])
The arguments to the InputBox function are described below:
Argument Description
prompt Required. String expression displayed a
the dialog box. The maximum lengt
approximately 1024 characters, depend
of the characters used.
title Optional. String expression displayed i
the dialog box. If you omit title, the app
placed in the title bar.
default Optional. String expression displayed in
the default response if no other input is
omit default, the text box is displayed e
xpos and ypos Both optional. Numeric expressions tha
positioning of the box on screen (by de
displayed in the center of the screen, w
desired).
helpfile and
context
Both optional. Can be used if a help file
for the application. If either one of thes
used, they both must be used.
DMC 1944
NOTES
94 ANNA UNIVERSITY CHENNAI
If the user clicks OK or presses ENTER , the InputBox function returns whatever is
in the text box. If the user clicks Cancel, the function returns a zero-length string ().
A simple example given below uses an InputBox to obtain the users name. A string
variable (strName) has been declared and used to store the result of the InputBox function:
Dim strName As String
strName =InputBox(Enter your name:, Input Test)
Note that the InputBox function in this example used Enter your name: as the required
prompt argument, and Input Test as the optional title argument (which caused that text
to be displayed in the title bar of the dialog box). When you run the program, the InputBox
looks as shown in figure 2.20.
When the user then enteres his name into the text area of the InputBox (figure 2.21)
and when the user clicks OK, the string Harry is stored in the variable strName. Had the
user clicked Cancel, the zero-length string () would have been stored in strName.
Figure 2.20 Input box at run time
Figure 2.21 Input box when the user inputs a text
The next example shows how the default argument is used.
Lets say you need the user to enter an account number, but the majority of the time
the program will be processing account ABC-123. You could provide the string ABC-
123 as the third argument to InputBox:
strAcctID =InputBox(Enter account ID:, Input Test, ABC-123)
When the program is run, the text entered as the default argument shows up pre-filled
and highlighted in the text entry area of the InputBox as shown in figure 2.22.
VISUAL PROGRAMMING
NOTES
95 ANNA UNIVERSITY CHENNAI
Figure 2.22 Input Box with default text
The user can either accept that and click OK, or they can type the ABC-123 to
enter whatever is required and then click OK.
2.10.2.2 Message Box
The MsgBox function displays a message in a dialog box, waits for the user to click
a button, and returns an Integer indicating which button the user clicked.
Syntax:
MsgBox(prompt[, buttons] [, title] [, helpfile, context])
The MsgBox function syntax has these parts:
The first group of values (0 - 5) describes the number and type of buttons displayed
in the dialog box; the second group (16, 32, 48, 64) describes the icon style; the third
group (0, 256, 512, 768) determines which button is the default; and the fourth group (0,
4096) determines the modality of the message box. When adding numbers to create a final
value for the buttons argument, use only one number from each group.
Part Description
prompt Required. String expression displayed as the message in the
dialog box. The maximum length of prompt is
approximately 1024 characters, depending on the width of
the characters used.
buttons Optional. Numeric expression that is the sum of values
specifying the number and type of buttons to display, the
icon style to use, the identity of the default button, and the
modality of the message box. If omitted, the default value
for buttons is 0 (which causes only an OK button to be
displayed with no icon). The buttons argument is explained
in more detail below.
title Optional. String expression displayed in the title bar of the
dialog box. If you omit title, the application name is placed
in the title bar.
helpfile and
context
Both optional. These arguments are only applicable when a
Help file has been set up to work with the application.
DMC 1944
NOTES
96 ANNA UNIVERSITY CHENNAI
First Group - Determines which buttons to display:
Second Group - Determines which icon to display:
Third Group - Determines which button is the default:
There is a fifth group of constants that can be used for the buttons argument which
would only be used under special circumstances:
Constant Value Description
vbOKOnly 0 Display OK button only.
vbOKCancel 1 Display OK and Cancel buttons.
vbAbortRetryIgnore 2 Display Abort, Retry, and Ignore
buttons.
vbYesNoCancel 3 Display Yes, No, and Cancel buttons.
vbYesNo 4 Display Yes and No buttons.
vbRetryCancel 5 Display Retry and Cancel buttons.
Constant Value Description Icon
vbCritical 16 Display Critical Message
icon.

vbQuestion 32 Display Warning Query
(question mark) icon.

vbExclamation 48 Display Warning Message
icon.

vbInformation 64 Display Information Message
icon.

Constant Value Description
vbDefaultButton1 0 First button is default.
vbDefaultButton2 256 Second button is default.
vbDefaultButton3 512 Third button is default.
vbDefaultButton4 768 Fourth button is default (applicable
only if a Help button has been added).
Constant Value Description
vbApplicationModal 0 Application modal; the user must
respond to the message box before
continuing work in the current
application.
vbSystemModal 4096 System modal; all applications are
suspended until the user responds to
the message box.
Constant Value Description
vbMsgBoxHelpButton 16384 Adds Help button to the message box
VbMsgBoxSetForeground 65536 Specifies the message box window
as the foreground window
vbMsgBoxRight 524288 Text is right aligned
vbMsgBoxRtlReading 1048576 Specifies text should appear as right-
to-left reading on Hebrew and Arabic
systems
Fourth Group Determines the modality of the message box.
VISUAL PROGRAMMING
NOTES
97 ANNA UNIVERSITY CHENNAI
When you use MsgBox to with the option to display more than one button (i.e., from
the first group, anything other than vbOKOnly), you can test which button the user
clicked by comparing the return value of the Msgbox function with one of these values:
Message Box Example: Type the following statement in any of your application
and find the message box displayed like the one given in figure 2.23.
MsgBox This is an example of a message box, vbOKCancel +vbInformation,
Message Box Example
Figure 2.23 Example Message Box
Youve seen message boxes if youve ever used a Windows application. Think of all
the examples youve seen. For example, message boxes are used to ask you if you wish
to save a file before exiting and to warn you if a disk drive is not ready.
2.11 DEBUGGING IN VISUAL BASIC
Visual Basic offers a powerful suite of debugging options like the following and as
shown in figure 2.24:
1. Runtime Error Message
2. Break Mode
3. The Immediate Window
4. Using Step Into, Step Over and Step Out
5. Run to Cursor & Set/Show Next Statement
6. The Locals Window
7. The Watch Window
8. Call Stack
Constant Value Description
vbOK 1 The OK button was pressed
vbCancel 2 The Cancel button was pressed
vbAbort 3 The Abort button was pressed
vbRetry 4 The Retry button was pressed
vbIgnore 5 The Ignore button was pressed
vbYes 6 The Yes button was pressed
vbNo 7 The No button was pressed
DMC 1944
NOTES
98 ANNA UNIVERSITY CHENNAI
Figure 2.24 Debugging options in Vb6.0
2.11.1 Runtime Error
These occur while your application is running, when Visual Basic finds a statement
that is impossible to carry out, such as multiplying the contents of TextBox1 by 10 when
textbox1 contains Hello. If this error occurs when running Visual Basic, a dialog is displayed
like the one below. You are given the error number along with its message as shon in figure
2.25. You have the option to End the current program, Debug the program which pauses
the code, or to get help on that error. Projects must handle these.
Figure 2.25 Runtime Error
2.11.2 The break mode
The standard way to debug is to place a breakpoint at a particular line in your code,
and when execution reaches that line, it will halt and Visual Basic will enter the Debug
state, giving you access to your code and variables. You can examine the contents of those
variables and work through your code line by line, watching program execution behind the
scenes.

VISUAL PROGRAMMING
NOTES
99 ANNA UNIVERSITY CHENNAI
For example, we might write the following code, which is meant to increment the
value in a text box, Text1, each time you click a button:
Private Sub Command1_Click()
Dim intCounter As Integer
intCounter =intCounter +1
Text1.Text =intCounter
End Sub
What actually happens is that the value 1 appears in the text box each time you click
the button. You place a breakpoint in code by moving the text insertion caret to that line
and either selecting Toggle Breakpoint in the Debug menu or pressing F9. (Breakpoints
toggle, so to remove the breakpoint, select Toggle Breakpoint in the Debug menu or press
F9 again.)
Now when you run the program and press the button, execution halts at the breakpoint,
and the code window appears. You can examine the contents of variables by selecting
them on the screen with the mouse and clicking the Quick Watch item in the Debug menu
(besides individual variables, you can select an entire expression). This opens a window
displaying the current value of the variable or expression youve selected.
You place a breakpoint in code by moving the text insertion caret to that line and
either selecting Toggle Breakpoint in the Debug menu or pressing F9. To remove the
breakpoint, select Toggle Breakpoint in the Debug menu or press F9 again. When you
place a breakpoint in code, it appears at design time in red. To check the value of a
variable or constant, leave the mouse cursor over the variable or constant and after a few
seconds a tooltip will appear giving the value as shown in figure 2.26. To continue code
execution, simply press the Play button, or press F5.
Figure 2.26 Checking value of variable or constant in break mode
2.11.3 The Immediate Window
Use the immediate window in VB to get the current values of variables and to run
other code. To open the immediate window Click the View menu and the Immediate
submenu. You can only use the immediate window when code execution is paused. Right
click and select hide to remove window.
DMC 1944
NOTES
100 ANNA UNIVERSITY CHENNAI
Figure 2.27 Immediate Window
Entering a ? and then the variable name or property will return its value, press
RETURN to execute the query. Use the immediate window to instantiate an object of a
class and run business object projects without a user interface.
2.11.4 Using Step Into, Step Over and Step Out
2.11.4.1 Step Into
Stepping is the process of running one statement at a time. After stepping through a
statement, you can see its effect in the other Debugging windows. To step through code
one statement at a time, choose Step Into from the Debug menu (F8), or press the step
into button on the tool bar
When stepping into a procedure, Visual Basic executes the current statement and
then enters Break mode. You can then edit any code and use the debugging tools. If the
statement executed calls another procedure, Visual Basic will step into that procedure.
Even if the procedure is in another module or referenced project. Once all the statements
in the procedure are run, VB will jump back to the next statement of the procedure it was
called from. To go onto the the next statement, press the Step Into (F8) button again. If
you press the play button (F5) code execution will continue as normal.
2.11.4.2 Step Over
Step Over is the same as Step Into, except that when it reaches a call for another
procedure, it will not step into the procedure. The procedure will run, and you will be
brought to the next statement in the current procedure.
2.11.4.3 Step Out
If you are using Step Into and have been moved to a called procedure, you can
automatically run the current procedure, and return to the procedure it was called from by
pressing the Step Out (Ctrl+SHIFT+F8) on the Debug menu, or pressing the Step Out
button.
VISUAL PROGRAMMING
NOTES
101 ANNA UNIVERSITY CHENNAI
2.11.5 Run to Cursor & Set/Show Next Statement
2.11.5.1 Run to Cursor
This option will run the code to the insertion point, and then enter Break Mode. It is
useful for one time stops, instead of always breaking at that point. To run to the cursor
point, enter break mode (press Ctrl+Break), insert the cursor where you want it to run to,
and click Run To Cursor from the Debug Menu (it is also on the Popup Menu).
2.11.5.2 Set/Show Next Statement
If in break mode, to skip a few lines of code (in the same procedure only), use the
Set Next Statement. Position cursor to where you want to skip to and press Set Next
Statement on the Debug Menu. Or drag the yellow arrow to the line you want. To return
to the yellow line (next statement to be executed), press Show Next Statement on the
Debug Menu.
2.11.6 The Locals Window
The locals window shows all the current variables and their values during Break
Mode. Also shows all the controls and their properties. The Locals window is useful for
checking values and properties. Consider the following procedure for a command Button
click event:
Sub Command1_Click()
Dim gNum As Long
Dim gString As String
gNum =1
gString =Text1.Text
Stop
End Sub
Figure 2.28 Locals Window
We can enable the Locals Window by selecting Locals Window from the View
Window and watch the current variables and their values as shown in figure 2.28. The
locals window highlights the following about the procedure:
DMC 1944
NOTES
102 ANNA UNIVERSITY CHENNAI
Me - This refers to the current form. You will notice that there is a +sign next to it.
If you press this, you will see a list of all the current forms properties, along with
any controls that are on the form. To see the properties of these controls, press the
+sign next to them.
gNum - This is the variable that is declared inside the Command1_Click()
procedure. Next to it will be its value. If in Break Mode outside of this procedure,
this variable would not be listed. It can only be accessed in the Command1_Click()
procedure.
gString - This is the other variable in the Command1_Click() procedure. Next to
it you will see its value, which will be the contents of Text1
2.11.7 The Watch Window
The Watch Window allows you to watch certain expressions, in certain modules and/
or procedures, and then stop code execution when it changes. To show the Watch Window,
select Watch Window from the View menu.
To add a watch, select Add Watch from the Debug Menu. The Add Watch dialog
will be displayed as shown in figure 2.29.
Figure 2.29 Add Watch Window
Next, enter a Variable name or expression into the Expression Box. For example:
gNum (or)
gNum =True (or)
gNum <10
VISUAL PROGRAMMING
NOTES
103 ANNA UNIVERSITY CHENNAI
Next select the context in the watch window by selecting a procedure where that
expression is to be tested in, or select (All Procedures). Then select the module, or select
(All Modules). And finally select the project, if more than one is open.
Then in the add watch window finally select any one of the below mentioned watch
type:
1. Watch Expression - Code will not be stopped, but when you enter break mode
the value of the expression will be displayed in the Watch Window
2. Break When Value Is True - Enters Break Mode when the expression is True (a
non-zero value)
3. Break When Value Changes - Enters Break Mode whenever the value of the
expression changes.
2.11.8 Call Stack
The Call Stack window will show the procedure where the code execution stopped
and what called the procedure.
Figure 2.30 Call Stack Window
Call Stack example: Create a new project with a command button, and enter the
following code:
Public gTest As Integer
Sub Command1_click()
Call SubRoutine1
End Sub
Sub SubRoutine1()
Call SubRoutine2
End Sub
Sub SubRoutine2()
gTest =1
Stop Code stops here
End Sub
DMC 1944
NOTES
104 ANNA UNIVERSITY CHENNAI
Run the project and press Command1. The project during run time enters Break
Mode when it reaches Stop. Now to see the stack window, select Call Stack from View
menu. The listbox lists all the procedures that have been called to get to the current
procedure bottom.
Example:
Project1.Form1.SubRoutine2 This procedure was called.
Project1.Form1.SubRoutine1 This procedure was called, and in turn called the above
procedure
Project1.Form1.Command1_Click This event occurred, which called the above
procedure
The information before the Procedure name (Project1.Form1) shows what project
and what module the procedure belongs to. To go to the selected procedure, click Show.
2.12 MOUSE AND KEYBOARD EVENTS
Your Visual Basic applications can respond to a variety of mouse events and keyboard
events. For example, forms, picture boxes, and image controls can detect the position of
the mouse pointer, can determine whether a left or right mouse button is being pressed,
and can respond to different combinations of mouse buttons and SHIFT, CTRL, or ALT
keys. Using the key events, you can program controls and forms to respond to various key
actions or interpret and process ASCII characters.
In addition, Visual Basic applications can support both event-driven drag-and-drop
and OLE drag-and-drop features. You can use the Drag method with certain properties
and events to enable operations such as dragging and dropping controls. OLE drag and
drop gives your applications all the power you need to exchange data throughout the
Windows environment and much of this technology is available to your application
without writing code.
You can also use the mouse or keyboard to manage the processing of long background
tasks, which allows your users to switch to other applications or interrupt background
processing.
Other actions and events that involve the mouse or keyboard are the Click and
DblClick events, the Focus events, and the Scroll event.
2.12.1 MouseDown, MouseMove and MouseUp Events
MouseDown is the most frequently used of the three mouse events. It can be used to
reposition controls on a form at run time or to create graphical effects, for instance. The
MouseDown event is triggered when a mouse button is pressed. The MouseUp event
occurs when the user releases the mouse button. The MouseMove event occurs when the
user moves the mouse.
VISUAL PROGRAMMING
NOTES
105 ANNA UNIVERSITY CHENNAI
The above mentioned three events takes the following 4 parameters as arguments:
Button As Integer, Shift As Integer, X As _ Single, Y As Single
The Button parameter tells us which mouse button went down. The predefined Visual
Basic Button parameter constants are:
vbLeftButton =1
vbRightButton =2
vbMiddleButton =4
Shift parameter is an integer that corresponds to the state of the SHIFT, CTRL, and
ALT keys when the button specified in the button argument is pressed or released. A bit is
set if the key is down. The shift argument is a bit field with the least-significant bits
corresponding to the SHIFT key (bit 0), the CTRL key (bit 1), and the ALT key (bit 2 ).
These bits correspond to the values 1, 2, and 4, respectively. The shift argument indicates
the state of these keys. For example, if both CTRL and ALT were pressed, the value of
shift would be 6.
X and Y specifies the current location of the mouse pointer.
Now lets look at few programs that uses mouse events. The following program
(program 2.8) illustrates the movement of objects responding to move events. it makes
use of two OptionButton Controls, two image controls and a CommandButton. The
application is designed in such a way that when an OptionButton is selected, the
corresponding image control is placed anywhere in the form whenever it is clicked.
Program 2.8: Program using mouse_down event.
1. Open a new standard EXE project and save the Form as Move.frm and save the
project as Move.vbp
2. Design the Form as shown below:
Object Property Setting
Form Caption MouseDown
Name frmMouseDown
OptionButton Caption Credit card is selected
Name optCredit
Value True
OptionButton Caption Cash is selected
Name optCash
Image Name imgCredit
Picture c:/credit.jpg
Image Name imgCash
Picture c:/cash.jpg
DMC 1944
NOTES
106 ANNA UNIVERSITY CHENNAI
3. Enter he follwoing code in the general declarations section of the Form.
Option Explicit
4. The following code is entered in the Form_MouseDown( ) event
Private Sub Form_MouseDown(Button As Integer, Shift As Integer, X As Single,
_ Y As Single)
If optCredit =True Then
imgCredit.Move X, Y
Else
imgCash.Move X, Y
End If
End Sub
5. Run the application by keying in F5.
Figure 2.31 Output for Program 2.8
You can notice that when the mouse is clicked on the form somewhere, the selected
image moves to that clicked location. This is shown in the figure 2.31.
Program 2.9: Program that changes the position of a control on the form during the
MouseDown event.
1. Create a StandardEXE project file.
2. Add a command button to the form.
3. Enter following lines of code inside the MouseDown event of the Form object.
Private Sub Form_MouseDown (Button As Integer, _
Shift As Integer, X As Single, Y As Single)
Command1.Move X, Y
End Sub
4. Run the program and observe what happens when you click randomly on
the form.
VISUAL PROGRAMMING
NOTES
107 ANNA UNIVERSITY CHENNAI
Program 2.10: Drawing lines in the MouseDown event
1. Create a StandardEXE project file.
2. Enter following lines of code inside the MouseDown event of the Form object.
Private Sub Form_MouseDown (Button As Integer, Shift As Integer, X As Single,
_Y As Single)
Line -(X, Y)
End Sub
3. Run the program and click randomly on the form.
The mouse events can be combined with graphics methods and any number of
customized drawing or paint applications can be created. The following application combines
MouseMove and MouseDown events, and illustrates a drawing program.
Program 2.11: Combining mouse events with graphics methods.
1. Open a new Standard EXE project and save the Form as Draw.frm and save the
Project as Draw.vbp.
2. Name the caption of the form as Drawing.
3. Add command button control and name the caption of it as Clear.
4. Enter the following code in the Form_MouseDown ( ) procedure,
Form_MouseMove ( ) procedure and cmdClear_Click ( ) procedures respectively.
Private Sub cmdClear_Click()
frmDraw.Cls
End Sub
Private Sub Form_MouseDown(Button As Integer, Shift As Integer, X As Single,
_Y As Single)
frmDraw.CurrentX =X
frmDraw.CurrentY =Y
End Sub
Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single,
_Y As Single)
If Button =1 Then
Line (frmDraw.CurrentX, frmDraw.CurrentY)-(X, Y)
End If
End Sub
Button value 1 indicates that the left mouse button is clicked. The code written in the
MouseDown event changes the CurrentX and CurrentY to the coordinates where the
mouse button was just clicked.
DMC 1944
NOTES
108 ANNA UNIVERSITY CHENNAI
5. Run the application.
Figure 2.32 Line drawing as per mouse movement
6. You can notice that when the mouse is clicked and moved in the Form a line is
drawn corresponding to the mouse movement. Figure 2.32 illustrates the combined
action of MouseDown and MouseMove.
Visual Basic does not generate a MouseMove event for every pixel the mouse moves
over and a limited number of mouse messages are generated per second by the operating
environment. The following application illustrates how often the Form_MouseMove ( )
event is executed.
Program 2.12: Program using Mouse_move event.
1. Open a new standard EXE project and save the form as MouseMove.frm and
save the Project as MouseMOve.vbp.
2. Place a CommandButton control and name the caption as Clear and set the name
as cmdClear.
3. Enter the following code in the cmdClear_Click ( ) and Form_MouseMove ( )
events respectively.
Private Sub cmdClear_Click()
frmMouseMove.Cls
End Sub
Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As
Single,_ Y As Single)
Circle (X, Y), 70
End Sub
The above procedure simply draws small circles at the mouses current location using
the Circle method. The parameter x, y represent the centre of the circle, and the second
parameter represents the radius of the circle.
VISUAL PROGRAMMING
NOTES
109 ANNA UNIVERSITY CHENNAI
4. Save the application and run.
Figure 2.33 Drawing circles in form
You can notice that when the mouse is moved inside the Form, circles are drawn
along the path of the mouse movement as shown in below figure. And also you can notice
the circles are widely spaced when the mouse is moved quickly. Each small circle is an
indication that the MouseMove event occured and the Form_MouseMove ( ) procedure
was executed.
2.12.2 KeyUp, KeyDown and KeyPress Events
The KeyDown and KeyUp events happen when the user respectively presses and
releases a key on the keyboard. Their event procedures take the following two parameters:
KeyCode and Shift.
KeyCode contains an integer code for the physical key that the user pressed. You
can check for a particular key by comparing KeyCode with one of the special VB internal
constants for physical key codes. Each constant name begins with the string vbKey
followed by an obvious name for the key (the letter of the key if its an alphabetic key or
some other obvious name for other keys). Examples of vbKey constants would be vbKeyA,
vbKeyW, vbKeyF1, vbKeyPgUp, and so forth.
Shift parameter works in the same way as the Shift parameter for the MouseDown
and MouseUp event procedures.
The KeyPress event happens after the KeyDown event but before the KeyUp event.
It detects the ASCII value of the character generated by the pressed key. The KeyPress
event procedures single parameter is KeyAscii. KeyAscii is an integer representing the
ASCII value of the character generated by the users key press.
For instance, if the user keys an uppercase A, then the KeyPress event fires and
the KeyAscii parameter will have a value of 65 (since 65 is the ASCII code for uppercase
A). If you write code in the KeyPress event that changes the value of KeyAscii, then the
system will see the newly assigned character as the character that the user has just typed.
If you change the value of KeyAscii to 0, then the system will not see a keystroke, and you
have in effect discarded the keystroke.
DMC 1944
NOTES
110 ANNA UNIVERSITY CHENNAI
Program 2.13: Detecting a shifted keystroke in the KeyDown event procedure of text
box control.
1. Open a new project and add the variable ShiftKey to the Declarations section
of the form:
Dim ShiftKey as Integer
2. Add a Textbox control to the form and this procedure in the KeyDown event:
Private Sub Text1_KeyDown(KeyCode As Integer, Shift As Integer)
ShiftKey =Shift And 7
Select Case ShiftKey
Case 1 or vbShiftMask
Print You pressed the SHIFT key.
Case 2 or vbCtrlMask
Print You pressed the CTRL key.
Case 4 or vbAltMask
Print You pressed the ALT key.
Case 3
Print You pressed both SHIFT and CTRL.
Case 5
Print You pressed both SHIFT and ALT.
Case 6
Print You pressed both CTRL and ALT.
Case 7
Print You pressed SHIFT, CTRL, and ALT.
End Select
End Sub
3. Run the application and observe the results when you press the SHIFT, CTRL,
ALT and their combinations.
Program 2.14: Changing the case of a character in the keypress( ) event procedure.
1. Open a new project.
2. Add a Textbox control named txtPassword to the form and add the following
lines of code in the KeyPress event:
Private Sub txtPassword_KeyPress(KeyAscii As Integer)
Dim KeyChar As String
KeyChar =LCase(KeyChar) change to lowercase
End Sub
VISUAL PROGRAMMING
NOTES
111 ANNA UNIVERSITY CHENNAI
3. Run the application and type some upper case character in the textbox and observe
the result.
You can use the KeyDown event procedure to allow users to increase and decrease
the current value using Up and Down arrow keys, as you see here:
Private Sub Text1_KeyDown(KeyCode As Integer, Shift As Integer)
Select Case KeyCode
Case vbKeyUp
Text1.Text =CDbl(Text1.Text) +1
Case vbKeyDown
Text1.Text =CDbl(Text1.Text) -1
End Select
End Sub
2.13 GRAPHICS CONTROLS
Well look at our first graphic type controls: line tools and shape tools. And, with this
introduction, we need to discuss the idea of display layers.
Items shown on a form are not necessarily all on the same layer of display. A forms
display is actually made up of three layers as shown in figure 2.34. All information displayed
directly on the form (by printing or drawing with graphics methods) appears on the bottom-
layer. Information from label boxes, image boxes, line tools, and shape tools, appears on
the middle-layer. And, all other objects are displayed on the top-layer.
What this means is you have to be careful where you put things on a form or something
could be covered up. For example, text printed on the form would be hidden by a command
button placed on top of it. Things drawn with the shape tool are covered by all controls
except the image box.
The next question then is what establishes the relative location of objects in the same
layer. That is, say two command buttons are in the same area of a form - which one lies on
top of which one? The order in which objects in the same layer overlay each other is
called the Z-order. This order is first established when you draw the form.
Figure 2.34 Three Layers of form display
Bottom-layer: form
Middl e-layer: lable,
image, shape, line
Top-l ayer: other controls
and objects
DMC 1944
NOTES
112 ANNA UNIVERSITY CHENNAI
Items drawn last lie over items drawn earlier. Once drawn, however, the Z-order
can be modified by clicking on the desired object and choosing Bring to Front from
Visual Basics Edit menu. The Send to Back command has the opposite effect. Note
these two commands only work within a layer; middle-layer objects will always appear
behind top-layer objects and lower layer objects will always appear behind middle-layer
objects.
2.13.1 Line Tool
The line tool creates simple straight line segments of various width and color. Together
with the shape tool discussed next, you can use this tool to dress up your application.
Line Tool Properties:
BorderColor Determines the line color.
BorderStyle Determines the line shape. Lines can be transparent,
solid, dashed, dotted, and combinations.
BorderWidth Determines line width.
There are no events or methods associated with the line tool. Since the line tool lies in
the middle-layer of the form display, any lines drawn will be obscured by all controls
except the shape tool or image box.
2.13.2 Shape Tool
The shape tool can create circles, ovals, squares, rectangles, and rounded squares
and rectangles. Colors can be used and various fill patterns are available.
Shape Tool Properties:
BackColor Determines the background color of the shape (only used
when FillStyle not Solid.
BackStyle Determines whether the background is transparent or
opaque.
BorderColor Determines the color of the shapes outline.
BorderStyle Determines the style of the shapes outline. The border
can be transparent, solid, dashed, dotted, and
combinations.
BorderWidth Determines the width of the shape border line.
FillColor Defines the interior color of the shape.
FillStyle Determines the interior pattern of a shape. Some choices
are: solid, transparent, cross, etc.
Shape Determines whether the shape is a square, rectangle, circle,
or some other choice.
VISUAL PROGRAMMING
NOTES
113 ANNA UNIVERSITY CHENNAI
Like the line tool, events and methods are not used with the shape tool. Shapes are
covered by all objects except perhaps line tools and image boxes (depends on their Z-
order) and printed or drawn information. This is a good feature in that you usually use
shapes to contain a group of control objects and youd want them to lie on top of the
shape.
2.14 FILE SYSTEM CONTROLS
File system controls are three of the controls on the ToolBox that let you access the
computers file system. They are DriveListBox, DirListBox and FileListBox controls, which
are the basic blocks for building dialog boxes that display the host computers file system.
Using these controls, user can traverse the host computers file system, locate any folder
or files on any hard disk, even on network drives. The files are controls are independent of
one another, and each can exist on its own, but they are rarely used separately. In a
nutshell, the DriveListBox control is a combobox-like control thats automatically filled
with your drives letters and volume labels. The DirListBox is a special list box that displays
a directory tree. The FileListBox control is a special-purpose ListBox control that displays
all the files in a given directory, optionally filtering them based on their names, extensions,
and attributes.
2.14.1 Drive List Box
The drive list box control allows a user to select a valid disk drive at run-time. It
displays the available drives in a drop-down combo box. No code is needed to load a
drive list box; Visual Basic does this for us. We use the box to get the current drive
identification.
Drive List Box Properties:
Drive Contains the name of the currently selected drive.
Drive List Box Events:
Change Triggered whenever the user or program changes the drive selection.
2.14.2 Directory List Box
The directory list box displays an ordered, hierarchical list of the users disk directories
and subdirectories. The directory structure is displayed in a list box. Like, the drive list
box, little coding is needed to use the directory list box - Visual Basic does most of the
work for us.
Directory List Box Properties:
Path Contains the current directory path.
Directory List Box Events:
Change Triggered when the directory selection is changed.
DMC 1944
NOTES
114 ANNA UNIVERSITY CHENNAI
2.14.3 File List Box
The file list box locates and lists files in the directory specified by its Path property at
run-time. You may select the types of files you want to display in the file list box.
File List Box Properties:
FileName Contains the currently selected file name.
Path Contains the current path directory.
Pattern Contains a string that determines which files will be displayed. It
supports the use of * and ? wildcard characters. For example,
using *.dat only displays files with the .dat extension.
File List Box Events:
DblClick Triggered whenever a file name is double-clicked.
PathChange Triggered whenever the path changes in a file list box.
You can also use the MultiSelect property of the file list box to allow multiple file
selection.
2.14.4 Synchronizing the Drive, Directory, and File List Boxes
The drive, directory, and file list boxes are almost always used together to obtain a
file name. As such, it is important that their operation be synchronized to insure the displayed
information is always consistent.
When the drive selection is changed (drive box Change event), you should update
the directory path. For example, if the drive box is named drvExample and the directory
box is dirExample, use the code:
dirExample.Path =drvExample.Drive
When the directory selection is changed (directory box Change event), you should
update the displayed file names. With a file box named filExample, this code is:
filExample.Path =dirExample.Path
Once all of the selections have been made and you want the file name, you need to
form a text string that correctly and completely specifies the file identifier. This string
concatenates the drive, directory, and file name information. This should be an easy task,
except for one problem. The problem involves the backslash (\) character. If you are at
the root directory of your drive, the path name ends with a backslash. If you are not at the
root directory, there is no backslash at the end of the path name and you have to add one
before tacking on the file name.
Example code for concatenating the available information into a proper file name and
then loading it into an image box is:
VISUAL PROGRAMMING
NOTES
115 ANNA UNIVERSITY CHENNAI
Dim YourFile as String
If Right(filExample.Path,1) =\ Then
YourFile =filExample.Path +filExample.FileName
Else
YourFile =filExample.Path +\ +filExample.FileName
End If
imgExample.Picture =LoadPicture(YourFile)
Note we only use properties of the file list box. The drive and directory box properties
are only used to create changes in the file list box via code.
2.15 COMMON DIALOG CONTROLS
The Common Dialog control provides a standard set of dialog boxes for operations
such as opening, saving, and printing files, as well as selecting colors and fonts and displaying
help. Any six of the different dialog boxes can be displayed with just one Common Dialog
control.
Figure 2.35 Components Dialog Box
DMC 1944
NOTES
116 ANNA UNIVERSITY CHENNAI
Figure 2.36 Toolbox after adding Microsoft Common Dialog Control 6.0
The Common Dialog control is not an intrinsic control; rather, it is an Active X
control that must be added to the toolbox via the Components dialog box, as shown
below. This dialog box is accessed via the Project menu, Components item. Once you
check Microsoft Common Dialog Control 6.0 and click OK (figure 2.35), the control is
added to your toolbox (circled and shown figure 2.36).
Then you can double-click it to make it appear on your form, as you would with any
other control. The Common Dialog control is not visible at run-time.
The primary use for the drive, directory, and file name list boxes is to develop custom
file access routines. Two common file access routines in Windows-based applications are
the Open File and Save File operations. Fortunately, you dont have to build these
routines.
To give the user a standard interface for common operations in Windows-based
applications, Visual Basic provides a set of common dialog boxes, two of which are the
Open and Save As dialog boxes. Such boxes are familiar to any Windows user and give
your application a professional look. And, with Windows 95, some context-sensitive help
is available while the box is displayed. Appendix II lists many symbolic constants used
with common dialog boxes.
The Common Dialog control is a custom control which means we have to make
sure some other files are present to use it. In normal setup configurations, Visual Basic
does this automatically. If the common dialog box does not appear in the Visual Basic
toolbox, you need to add it. This is done by selecting Components under the Project
menu. When the selection box appears, click on Microsoft Common Dialog Control,
then click OK.
VISUAL PROGRAMMING
NOTES
117 ANNA UNIVERSITY CHENNAI
The common dialog tool, although it appears on your form, is invisible at run-time.
You cannot control where the common dialog box appears on your screen. The tool is
invoked at run-time using one of five Show methods. These methods are:
Method Common Dialog Box
ShowOpen Open dialog box
ShowSave Save As dialog box
ShowColor Color dialog box
ShowFont Font dialog box
ShowPrinter Printer dialog box
The format for establishing a common dialog box named cdlExample so that an
Open box appears is:
cdlExample.ShowOpen
Control to the program returns to the line immediately following this line, once the
dialog box is closed in some manner. Common dialog boxes are system modal.
2.15.1 Open Common Dialog Box
The Open common dialog box provides the user a mechanism for specifying the
name of a file to open. The box is displayed by using the ShowOpen method. Heres an
example of an Open common dialog box given in figure 2.37:
Figure 2.37 Open Dialog Box
DMC 1944
NOTES
118 ANNA UNIVERSITY CHENNAI
Open Dialog Box Properties:
CancelError If True, generates an error if the Cancel button is clicked.
Allows you to use error-handling procedures to
recognize that Cancel was clicked.
DialogTitle The string appearing in the title bar of the dialogbox.
Default is Open. In the example, the DialogTitle is
Open Example.
FileName Sets the initial file name that appears in the File name
box. After the dialog box is closed, this property can be
read to determine the name of the selected file.
Filter Used to restrict the filenames that appear in the file list
box. Complete filter specifications for forming a Filter
can be found using on-line help. In the
example, the Filter was set to allow Bitmap
(*.bmp), Icon (*.ico), Metafile (*.wmf), GIF (*.gif),
and JPEG (*.jpg) types (only the Bitmap choice is seen).
FilterIndex Indicates which filter component is default. The example
uses a 1 for the FilterIndex (the default value).
Flags Values that control special features of the Opendialog
box (see Appendix II). The example uses no Flags
value.
When the user closes the Open File box, you should check the returned file name to
make sure it meets the specifications your application requires before you try to open the
file.
Program 2.15: Programming the Open Dialog Box
1. Start a new project. Place a common dialog control, a label box, and a command
button on the form. Set the following properties:
Form1:
Caption Common Dialog Examples
Name frmCommon
CommonDialog1:
DialogTitle Open Example
Filter Bitmaps (*.bmp)|*.bmp|
Icons (*.ico)|*.ico|Metafiles (*.wmf)|*.wmf
GIF Files (*.gif)|*.gif|JPEG Files (*,jpg)|*.jpg
(all on one line)
Name cdlExample
VISUAL PROGRAMMING
NOTES
119 ANNA UNIVERSITY CHENNAI
Label1:
BorderStyle 1-Fixed Single
Caption [Blank]
Name lblExample
Command1:
Caption &Display Box
Name cmdDisplay
When done, the form should look like the one shown in figure 2.38 (make sure your
label box is very long):
Figure 2.38 Form during design
2. Attach this code to the cmdDisplay_Click procedure.
Private Sub cmdDisplay_Click()
cdlExample.ShowOpen
lblExample.Caption =cdlExample.filename
End Sub
This code brings up the Open dialog box when the button is clicked and shows the
file name selected by the user once it is closed.
3. Save the application. Run it and try selecting file names and typing file names.
Notice names can be selected by highlighting and clicking the OK button or just
by double-clicking the file name. In this example, clicking the Cancel button is
not trapped, so it has the same effect as clicking OK.
4. Notice once you select a file name, the next time you open the dialog box, that
selected name appears as default, since the FileName property is not affected in
code.
DMC 1944
NOTES
120 ANNA UNIVERSITY CHENNAI
2.15.2 Save As Common Dialog Box
The Save As common dialog box (figure 2.39) provides the user a mechanism for
specifying the name of a file to save. The bzox is displayed by using the ShowSave method.
Figure 2.39 Save As Dialog Box
Save As Dialog Box Properties (mostly the same as those for the Open box):
CancelError If True, generates an error if the Cancel button is clicked.
Allows you to use error-handling procedures to recognize
that Cancel was clicked.
DefaultExt Sets the default extension of a file name if a file is listed
without an extension.
DialogTitle The string appearing in the title bar of the dialogbox.
Default is Save As. In the example, theDialogTitle is
Save As Example.
FileName Sets the initial file name that appears in the File name
box. After the dialog box is closed, this property can be
read to determine the name of the selected file.
Filter Used to restrict the filenames that appear in the file
list box.
FilterIndex Indicates which filter component is default.
Flags Values that control special features of the dialogbox (see
Appendix II).
The Save File box is commonly configured in one of two ways. If a file is being saved
for the first time, the Save As configuration, with some default name in the FileName
property, is used. In the Save configuration, we assume a file has been previously opened
with some name. Hence, when saving the file again, that same name should appear in the
FileName property. Youve seen both configuration types before.
VISUAL PROGRAMMING
NOTES
121 ANNA UNIVERSITY CHENNAI
When the user closes the Save File box, you should check the returned file name to
make sure it meets the specifications your application requires before you try to save the
file. Be especially aware of whether the user changed the file extension to something your
application does not allow.
Program 2.16: Programming the Save As Dialog Box
1. Lets just modify the program 2.15 a bit. Change the DialogTitle property of the
common dialog control to Save As Example and set the DefaultExt property
equal to bmp.
2. In the cmdDisplay_Click procedure, change the method to ShowSave (opens
Save As box).
3. Save the application and run it. Try typing names without extensions and note how
.bmp is added to them. Notice you can also select file names by double-clicking
them or using the OK button. Again, the Cancel button is not trapped, so it has
the same effect as clicking OK.
2.16 WORKING WITH FILES
There are three main ways to access files in Visual Basic: as sequential files, as random
access files, and as binary files.
2.16.1 Sequential Access Files
Sequential files are like tape cassettesyou read data from them in a sequential
manner. Here are the Visual Basic statements and functions you use with sequential files
(the #symbol refers to an open file):
Open
Line Input #
Print #
Write #
Input$
Input #
Close
In addition, Visual Basic supports TextStream objects to make working with sequential
files easier, as well see later in this chapter. Here are the major TextStream methods:
Read
ReadAll
ReadLine
Write
WriteBlankLines
WriteLine
Close
DMC 1944
NOTES
122 ANNA UNIVERSITY CHENNAI
When do you use sequential files? If youve got a text file full of variable-length
strings, you usually treat that file as sequential. You can also use sequential files to store
binary-format items like numbers.
2.16.2 Random Access Files
If sequential files are like cassettes, random access files are more like CDs. Random
files are organized into records (usually of the same length), and you can read a particular
record without having to read all the intervening datayou can move to that record in a
file directly, just as you can move to a CD track.
Here are the Visual Basic statements and functions you use with random access files:
TypeEnd Type (to create and format records)
Open
Put #
Len
Seek
LOC
Get #
Close
When do you use random access files? If you want to create your own database files,
formatted as you want them, youd organize them into records. In fact, any file that you
want to organize into records is best formatted as a random access file.
2.16.3 Binary Files
Binary files are simply unformatted binary data, and Visual Basic does not interpret
(such as looking for text strings) or organize the contents (into records) of such files at all.
These files are just bytes to Visual Basic, and the statements and functions you usually use
with these files include the following:
Open
Get
Put
Seek
Close
Binary files include EXE files, graphics files, and so on.
2.16.4 The FileSystemObject
Besides the preceding file types, Visual Basic includes the FileSystemObject for
easy file manipulation on disk. This object includes a number of methods for copying,
moving, and deleting files such as these:
VISUAL PROGRAMMING
NOTES
123 ANNA UNIVERSITY CHENNAI
GetFile
CopyFile
DeleteFile
MoveFile
FileExists
CreateFolder
CreateTextFile
OpenTextFile
Now lets see an example. Here, well allow the user to type a text in a text box.
When the user presses a command button the textbox contents may be written into a file.
Because file operations are prone to error (we might run into missing diskettes, locked
files, and so on), we start by checking for errors. Next, we create file.txt as file #1. Then
write the text in to the file with the Print # method and finally we close the file.
Program 2.17: Writing contents in a text box to a file.
1. Create a new StandardEXE project.
2. Add a text box to it and a command button.
3. Double click on the command button with a caption Write to File and add the
code below to its click event handler.
Private Sub Command1_Click()
On Error GoTo FileError
Open c:\file.txt For Output As #1
Print #1, Text1.Text
Close #1
MsgBox The file is & Str(FileLen(c:\file.txt)) & bytes long.
Exit Sub
FileError:
MsgBox File Error!
End Sub
4. Run the application and youll find the file size in bytes displayed in a message box.
Now lets try out a program involving FileSystemObject. This program displays the
drives available in your system and also indicates the free space available in the selected
drive.
DMC 1944
NOTES
124 ANNA UNIVERSITY CHENNAI
Program 2.18: Working with FileSystemObject.
1. Create a new StandardEXE project.
2. Design the form as shown in figure 2.40.
Figure 2.40 Form Design
3. The form has the following controls:
Object Control Name Property Value
Label Label1 Caption System Drives:
Lable Label2 Caption Click a Drive in the list
above to find out how
much disk space is free:
Label Label 2Border Style 1 Fixed Single
ListBox List 1
4. Write following lines of code in the form_load event:
Private Sub Form_Load( )
Dim fso As New FileSystemObject
Dim dr As Drive
Dim drs As Drives
Dim s As String
Dim n As String
Set drs =fso.Drives
Form1.MousePointer =vbHourglass
Show
DoEvents
Form1.Caption =Search Environment
For Each dr In drs
Form1.Caption =Form1.Caption & ..
s =dr.DriveLetter & -
If dr.DriveType =3 Then
VISUAL PROGRAMMING
NOTES
125 ANNA UNIVERSITY CHENNAI
n =dr.ShareName
ElseIf dr.IsReady Then
n =dr.VolumeName
End If
List1.AddItem s & n
Next
Form1.MousePointer =vbDefault
Form1.Caption =Search Complete
End Sub
5. Now include the below lines of code in the click event of the list box:
Private Sub List1_Click( )
Dim strDrive As String
Dim fso As New FileSystemObject
Dim dr As Drive
Dim strAvail As String
Get the drive letter from the list box
strDrive =Left(List1.List(List1.ListIndex), 1) & :
Get a drive object using the GetDrive method of the FileSystemObject
Set dr =fso.GetDrive(strDrive)
If the drive is ready
If dr.IsReady Then
Make a string that reports how many kilo bytes are free on the disk
strAvail =Format(CStr(dr.AvailableSpace _/ 1024), ###,###)
If strAvail = Then strAvail =0
Label3.Caption =strAvail & Kbytes
Else
If the drive is not ready, the send a message
MsgBox Drive not ready, vbCritical, Drive Error
End If
End Sub
6. Run the application and check the free spaces in the drives in your system.
2.17 ACCESSING DATABASES WITH THE DATA CONTROLS
Data Controls provides access to data stored in databases using any one of three
types of the following Recordset objects:
i) Table
ii) Dyanset
iii) Snapshot
DMC 1944
NOTES
126 ANNA UNIVERSITY CHENNAI
The Data control enables you to move from record to record and to display and
manipulate data from the records in bound controls. Without a Data control or an equivalent
data source control like the RemoteData control, data-aware (bound) controls on a form
cant automatically access data.
You can perform most data access operations using the Data control without writing
any code at all. Data-aware controls bound to a Data control automatically display data
from one or more fields for the current record or, in some cases, for a set of records on
either side of the current record. The Data control performs all operations on the current
record.
If the Data control is instructed to move to a different record, all bound controls
automatically pass any changes to the Data control to be saved in the database. The Data
control then moves to the requested record and passes back data from the current record
to the bound controls where its displayed.
2.17.1 Bound Controls
The DataList, DataCombo, DataGrid, and MSHFlexGrid controls are all capable of
managing sets of records when bound to a Data control. All of these controls permit
several records to be displayed or manipulated at once.
The intrinsic Picture, Label, TextBox, CheckBox, Image, OLE, ListBox and
ComboBox controls are also data-aware and can be bound to a single field of a Recordset
managed by the Data control.
The intrinsic Data control is geared toward MS-Access 97 and earlier databases,
although a later VB service pack added connectivity for Access 2000 databases. The
programs discussed in this chapter use the two sample Access databases provided with
Visual Basic (BIBLIO.MDB and NWIND.MDB). These databases are provided in
Access 97 format. On a default installation of VB6, these databases can be found in the
folder: C:\Program Files\Microsoft Visual Studio\VB98.
To do these exercises, you should make a folder into which you will copy the two
database files mentioned above. Then, within the folder you have created, make separate
subfolder for each exercise, one level below the root of your folder. The DatabaseName
property for the Data control in these exercises assumes that the database file resides one
directory level above the folder in which the exercise project files reside.
Program 2.19: Connecting and updating records to an Access Database Using the
VB Data Control.
1. Open a new Visual Basic project.
2. Put a data control (an intrinsic control, located in the VB toolbox) on the form and
set the properties as follows:
VISUAL PROGRAMMING
NOTES
127 ANNA UNIVERSITY CHENNAI
Notes: When you use the Data Control in a project, the properties that must be set
are DatabaseName and RecordSource, in that order. DatabaseName is the name of
the database you want to use, and the RecordSource is the name of the table in that
database that you want to use.
3. On your form, create a text box for each field in the Authors table, with labels. (If
you were to open the database in Access, you would see that the three fields of
the Authors table are Au_ID, Author, and Year Born.) Set the properties of the
three textboxes as follows:
In addition, set the Enabled property of txtAuthID to False.
When you want a control (such as a text box) to display data from a database, the
properties that must be set are DataSource and Datafield. The DataSource is the name
of the data control on the form (it should already be configured), and the DataField is the
name of the particular field in the database that should be displayed in the control (this field
will be in the table that was chosen for the RecordSource of the data control).
At this point, your form should resemble the screen-shot shown in figure 2.41.
Figure 2.41 Using Data Control
4. Save and run the project. Use the arrows on the data control to scroll through the
data.
Property Value
(Name) datAuthors
Caption Use the arrows to view the data
Connect Access (default)
DatabaseName ..\biblio.mdb
DefaultType UseJ et (default)
RecordSource Authors (choose from list)
Name DataSource DataField
txtAuthID datAuthors Au_ID
txtAuthor datAuthors Author
txtYearBorn datAuthors Year Born
DMC 1944
NOTES
128 ANNA UNIVERSITY CHENNAI
5. On any record, change the data in the author name or year born field. Move
ahead, then move back to the record you changed. Note that your changes remain
in effect. The data control automatically updates a record when you move off of
the record.
Note: EOF (End Of File) is a Boolean property of the recordset object that becomes
true when an attempt is made to move forward past the last record in a recordset.
BOF (Beginning Of File) is a Boolean property of the recordset object that becomes
true when an attempt is made to move backward past the first record in a recordset.
6. Click once on the data control and make sure that the following properties are set:
BOFAction = 0 - Move First
EOFAction = 0 - Move Last
7. Run the program and notice what happens when you use the arrows to move
previous when you are on the first record already, or move next when you are
already on the last record.
8. End the program, and set the data control properties as follows:
BOFAction = 1 - BOF
EOFAction = 1 EOF
9. Notice what happens to the arrows on the data control when you try to move past
the last or first record.
10. Now set the EOFAction property to 2 - AddNew.
11. Run the program; click the>| arrow on the data control to move to the end of the
records; then click on the >arrow to move to the next record (which does not
exist).
12. A blank record should appear. Type some data in all the fields (the author ID will
be entered automatically), then move to a previous record. Move back to the last
record to verify that your data is still there.
13. End the program, then start it again. Verify that the data you entered is still in the
database.
The above program demonstrated that you can create a simple but functional
application that not only allows the user to browse through the rows of a database table
and to update rows in that table, but also allows the user to add a new record to that table
without writing any code.
In the previous program, you saw that by clicking specific buttons of the data control,
you could move to the first, previous, next, or last record. What is happening is that the
data control is automatically invoking specific methods of the recordset object: namely the
MoveFirst, MovePrevious, MoveNext, and MoveLast methods. You can also invoke
these methods through code, which is what program 2.20 demonstrates.
VISUAL PROGRAMMING
NOTES
129 ANNA UNIVERSITY CHENNAI
Program 2.20: Using Navigation Buttons with a Data Control.
1. Copy the files from Program6.1 into a new folder and open the VBP file in the new
folder.
2. Set the Visible property of the data control (datAuthors) to False.
3. Make four command buttons with the following properties:
At this point, your form should resemble the figure 2.42:
Figure 2.42 Using Button controls to navigate
4. Put the following four lines of code in the appropriate Click events for the buttons:
5. Save and run your program.
6. Move to the last record and then click the Move Next button twice. What
happens?
7. When the user clicks on the MoveNext button, and there is no next record, your
code should stay on the same record (the last one). Put the following code in the
cmdMoveNext_Click() event:
Name Caption
cmdMoveNext Next Record
cmdMoveLast Last Record
cmdMovePrevious Previous Record
cmdMoveFirst First Record
Event Code
cmdMoveNext_Click datAuthors.Recordset.MoveNext
cmdMoveLast_Click datAuthors.Recordset.MoveLast
cmdMovePrevious_Click datAuthors.Recordset.MovePrevious
cmdMoveFirst_Click datAuthors.Recordset.MoveFirst
DMC 1944
NOTES
130 ANNA UNIVERSITY CHENNAI
datAuthors.Recordset.MoveNext
If datAuthors.Recordset.EOF =True Then
datAuthors.Recordset.MoveLast
End If
Note: Instead of Recordset.MoveLast, you could use MoveFirst to let the user loop
around to the first record.
8. Put similar code in the cmdMovePrevious_Click() event. In this case, you will
be checking for Recordset.BOF = True.
9. Save and run the project and test it thoroughly.
In program 2.20, you saw that with the data control, changes to a record are
automatically updated when the user moves off of that record which is done by the Update
method of the recordset object of the data control. You also saw that, by setting the
EOFAction of the data control to 2 - AddNew, the data control will invoke the AddNew
method of the recordset object, which causes all the bound controls to be cleared so that
the user can enter data. In addition to being invoked automatically through the data control,
the Update and AddNew methods can also be invoked through code. The recordset
object also has a Delete method, which can only be invoked through code, but it cannot
be accessed automatically through the data control.
Now lets see how to invoke the Update, AddNew, and Delete methods of the
recordset object through code.
Program 2.21: Update, Add and Delete records of the recordset object through code.
1. Add three more buttons to the form designed in program6.2 and set their properties
as follows:
Your form should resemble the figure 2.43:
Figure 2.43 Updating DB through Code
Name Caption Enabled
cmdNewRecord New Record True
cmdSaveRecord Save Record False
cmdDeleteRecord Delete Record True
VISUAL PROGRAMMING
NOTES
131 ANNA UNIVERSITY CHENNAI
2. When the user clicks on New Record, your program should enable the Save
Data button and disable the others. Put the following code in the
cmdNewRecord_Click( ) event:
datAuthors.Recordset.AddNew
cmdSaveRecord.Enabled =True
cmdMoveFirst.Enabled =False
cmdMoveLast.Enabled =False
cmdMovePrevious.Enabled =False
cmdMoveNext.Enabled =False
cmdDeleteRecord.Enabled =False
cmdNewRecord.Enabled =False
3. Save and run the program to make sure the buttons are enabled and disabled
correctly.
4. When the user clicks on the Save button to save the data that was entered, the
Update method should be called and the buttons should be redisplayed. Place the
following code in the cmdSaveRecord_Click() event:
datAuthors.Recordset.Update
cmdSaveRecord.Enabled =False
cmdMoveFirst.Enabled =True
cmdMoveLast.Enabled =True
cmdMovePrevious.Enabled =True
cmdMoveNext.Enabled =True
cmdDeleteRecord.Enabled =True
cmdNewRecord.Enabled =True
5. Something to watch out for with the Delete method is that when a record is deleted,
the recordset is no longer pointing to a valid record, but the data from the deleted
record still remains in the controls. If the user attempted to update the record at
that point, a run-time error would occur. To prevent this from happening, you
should move the user to a valid record immediately following the delete.
Another issue is that if you attempt to delete a record that has a related record in
another table, the Jet (Access) database engine will not allow the delete, and a run-time
error will occur. If you dont trap the error, the program will crash.
Finally, it is good programming practice to ask the user to confirm any destructive
action.
Place the following code, which addresses the above-mentioned issues, in the
cmdDelete_Click( ) event:
DMC 1944
NOTES
132 ANNA UNIVERSITY CHENNAI
On Error GoTo Delete_Error
If MsgBox(Are you sure you want to delete this record?, _
vbQuestion +vbYesNo +vbDefaultButton2, Confirm) =vbNo Then
Exit Sub
End If
delete the current record
datAuthors.Recordset.Delete
move to a valid record
cmdMoveNext_Click
Exit Sub
Delete_Error:
This error will occur if you attempt to delete an author that is related to
another table in the biblio.mdb database ...
MsgBox This record cannot be deleted. Error code = & Err.Number & vbCrLf
& _ Err.Description, vbCritical, Cannot Delete
6. Save and test your program to make sure all functions work.
2.18 GRID CONTROLS
So far we were working with control that allows the user to work with records one
by one. But Visual Basic offers special data bound controls called grid controls to work
with multiple records.
2.18.1 Using the MSFlexGrid Control
The Microsoft FlexGrid (MSFlexGrid) can be used to display multiple records in a
grid. This control displays and operates on tabular data. It allows complete flexibility to
sort, merge, and format tables containing strings and pictures. When bound to a Data
control, MSFlexGrid displays read-only data.
You can put text, a picture, or both, in any cell of an MSFlexGrid. The Row and Col
properties specify the current cell in an MSFlexGrid. You can specify the current cell in
code, or the user can change it at run time using the mouse or the arrow keys. The Text
property references the contents of the current cell.
If the text in a cell is too long to display in the cell, and the WordWrap property is set
to True, the text wraps to the next line within the same cell. To display the wrapped text,
you may need to increase the cells column width (ColWidth property) or row height
(RowHeight property).
Use the Col and Row properties to determine the number of columns and rows in an
MSFlexGrid.
VISUAL PROGRAMMING
NOTES
133 ANNA UNIVERSITY CHENNAI
Note: Before you can use an MSFlexGrid in your application, you must add the
MSFlxGrd.ocx file to your project. To automatically include the file in your project, put it
in the Autoload file. When distributing your application, you should install the MSFlxGrd.ocx
file in the users Microsoft Windows System directory.
Program 2.22: Using MSFlexGrid control.
1. Create a new project.
2. Place two data controls on the form and set their properties as follows:
3. Set the Caption property of datCategories to Use Arrow Buttons to Navigate
Records.
4. Place three textboxes and one OLE control on the form. Set the DataSource
property for each of these four controls to datCategories.
Set the DataField property for these controls to CategoryID, CategoryName,
Description, and Picture respectively.
Set the Enabled property of the Category ID textbox to False. For the
Description text box, set its MultiLine property to True and set its ScrollBars
property to 2 - Vertical.
Add appropriate label controls to accompany the textboxes, and group these four
controls into a frame, as shown in figure 2.44.
Figure 2.44 Using MSFlexGrid Control
Name DatabaseName RecordSource Visible
datCategories ..\NWIND.MDB Categories True
datProducts ..\NWIND.MDB (leave blank) False
DMC 1944
NOTES
134 ANNA UNIVERSITY CHENNAI
5. If necessary, add the MSFlexGrid to your toolbox from the Components item of
the Project menu. Place an MSFlexGrid control on your form, and set its properties
as follows:
Enclose the grid in a frame, as shown in figure 2.44.
6. Place the following line of code in the Form_Load event:
datCategories.Refresh
This will force the controls bound to datCategories to be populated sooner than
they would otherwise, and will also trigger the Reposition event of the
datCategories control. (The Reposition event of a data control occurs whenever
a Move method is executed against that control.)
7. Place the following code in the datCategories_Reposition event:
datProducts.RecordSource =SELECT * FROM Products _
& WHERE CategoryID = & txtCatID
datProducts.Refresh
8. Save and run the program.
As we have discussed earlier MSFlexGrid does not allow us to add, update or
delete records. Now lets discuss about another control named DBGrid which allows the
user to add, update, and delete records.
2.18.2 DBGrid Control
The DBGrid control does not install automatically when you install Visual Basic 6.0,
but it is available on the VB 6/VS 6 CD. To install the DBGrid control, perform the
following steps:
1. Locate these three files on your VB6 installation CD: DBGRID32.OCX,
DBGRID32.DEP, and DBGRID.REG. All three files should be located in this
folder: D:\COMMON\TOOLS\VB\CONTROLS (where D: is the drive letter
of your CD-ROM drive). If you cannot locate your installation CD, you may
download these three files from WWW.
2. Copy these three files to your Windows System directory (the default system
directory varies depending on the OS being used: On Windows 2000 and NT the
default is WINNT\SYSTEM32; on XP the default is WINDOWS\SYSTEM32,
and on 95, 98, and ME it is WINDOWS\ SYSTEM).
Property Value
AllowUserResizing 1 - flexResizeColumns
DataSource datProducts
FixedCols 0
VISUAL PROGRAMMING
NOTES
135 ANNA UNIVERSITY CHENNAI
3. Double-click on DBGRID.REG to register the DBGRID32.OCX. You should
now see the control (under the name Microsoft Data Bound Grid Control 5.0
(SP3)) when you access the Components dialog by selecting
ProjectComponents within VB. (If not, click on the Browse button in the
Components dialog and locate the DBGRID32.OCX file by browsing to the folder
in which you copied it previously.)
Program 2.23: Using the DBGrid Control.
1. Copy your files from Program 2.22 to a new folder and open the project.
2. Delete the MSFlexGrid control.
3. From the menu Project Components, include the Microsoft Data Grid
Control 6.0 (OLEDB). Now the DBGrid will be available in your control box.
4. Place a DBGrid on your form in the position previously occupied by the flex grid.
5. Set the DBGrids properties as follows:
6. The code can remain as is. Save and run the program; experiment by using the
grid to add, update, and delete records. Youll find that built-in error-checking will
prevent most illegal actions attempted by the user (such as trying to change the
primary key, changing a foreign key to a non-existent value, or deleting a record with
a related record in another table).
2.19 EXERCISES
1. Write a short note on the various components of VB6.0 IDE.
2. Discuss about the various data types in VB6.0.
3. What is variant data type? Give its significance.
4. Explain the various control statements in VB6.0.
5. Differentiate between while and dowhile looping statements.
6. Explain variable declarations and their scope in VB6.0.
7. What are constants? Give Examples.
8. Discuss about the various form events and methods.
9. With a suitable program explain how to create menus using menu editors in
VB6.0.
10. Write a short note on various debugging options available in visual basic.
11. Write simples programs and explain the various mouse events.
Property Value
AllowAddNew True
AllowDelete True
AllowUpdate True
DataSource datProducts
DMC 1944
NOTES
136 ANNA UNIVERSITY CHENNAI
12. List the various keyboard events.
13. Write a program using keyboard events, that captures user input and validates
them.
14. How file processing may be achieved in VB6.0? Explain with suitable codes.
15. Discuss about the various file system controls with a sample program.
16. What are data controls?
17. Write a program in VB6.0 to access students information from database.
18. Give the significance of data bound controls.
19. Write a short note on any two grid controls.
***
VISUAL PROGRAMMING
NOTES
137 ANNA UNIVERSITY CHENNAI
UNIT III
VISUAL C++ PROGRAMMING
3.1 INTRODUCTION
This unit is aimed towards introducing the reader the Visual C++IDE and various
features/components available in the IDE. It also provides the readers a clear idea of how
to program using Application and class wizards. The latter half of this unit provides
information about how to program with Graphical Device Interface (GDI) objects.
3.2 LEARNING OBJECTIVES
1. Learn the various VC++components
2. Understand the VC++build process
3. Understand the fundamentals of MFC
4. Learn to use Application wizard based programming
5. Understand and program GDI objects
6. Know about SDI and MDI types of applications
3.3 THE VISUAL C++ COMPONENTS
Microsoft Visual C++is two complete Windows application development systems in
one product. Many tasks can be achieved using VC++and a few are listed below:
1. Develop C-language Windows programs using only the Win32 API.
2. You can use many Visual C++tools, including the resource editors, to make low-
level Win32 programming easier.
3. You can do C++programming using the MFC library application framework thats
part of Visual C++. The C++classes are documented in the Microsoft Visual
C++ MFC Library Reference, and youll also be using application framework-
specific Visual C++tools such as AppWizard and ClassWizard.
4. Visual C++also includes the ActiveX Template Library (ATL), which you can use
to develop ActiveX controls for the Internet. ATL programming is neither Win32
C-language programming nor MFC programming.
DMC 1944
NOTES
138 ANNA UNIVERSITY CHENNAI
The various Visual C++components are as follows:
1. The Source Code Editor
2. The Resource EditorsWorkspace ResourceView
3. AppWizard
4. ClassWizard
5. The Source Browser
6. The C/C++Compiler
7. The Resource Compiler
8. The Linker
9. The Debugger
10. Online Help
11. Windows Diagnostic Tools
12. Source Code Control
13. The Gallery
14. The Microsoft Foundation Class Library Version 6.0
15. The Microsoft Active Template Library
Lets take a look into the Visual C++application build process to know more about
the various VC++components.
3.4 VISUAL C++ APPLICATION BUILD PROCESS
A project is a collection of interrelated source files that are compiled and linked to
make up an executable Windows-based program or a DLL. Source files for each project
are generally stored in a separate subdirectory. A project depends on many files outside
the project subdirectory too, such as include files and library files.
A makefile stores compiler and linker options and expresses all the interrelationships
among source files. (A source code file needs specific include files, an executable file
requires certain object modules and libraries, and so forth.) A make program reads the
makefile and then invokes the compiler, assembler, resource compiler, and linker to produce
the final output, which is generally an executable file. The make program uses built-in
inference rules that tell it, for example, to invoke the compiler to generate an OBJ file from
a specified CPP file. The above process is shown in figure 3.1.
VISUAL PROGRAMMING
NOTES
139 ANNA UNIVERSITY CHENNAI
Figure 3.1 The Visual C++ application build process.
3.4.1 The Resource EditorsWorkspace Resourceview
When you click on the ResourceView tab in the Visual C++Workspace window,
you can select a resource for editing. The main window hosts a resource editor appropriate
for the resource type. Each project usually has one text-format resource script (RC) file
that describes the projects menu, dialog, string, and accelerator resources. The RC file
also has #include statements to bring in resources from other subdirectories. These resources
include project-specific items, such as bitmap (BMP) and icon (ICO) files, and resources
common to all Visual C++programs, such as error message strings. Editing the RC file
outside the resource editors is not recommended. The resource editors can also process
EXE and DLL files, so you can use the clipboard to steal resources, such as bitmaps and
icons, from other Windows applications.
3.4.2 The C/C++ Compiler
The Visual C++compiler can process both C source code and C++source code. It
determines the language by looking at the source codes filename extension. A C extension
indicates C source code, and CPP or CXX indicates C++source code. The compiler is
Visual C++
Resource.h
Executable
(EXE)
Windows, runtime, and
MFC libraries
Linker
OBJ files
Compiler
MFC header
files
Runtime header
files
Windows header
files
Source
files
Code compilation
Resource compilation
Resource
script file (RC)
Bitmaps, icons, and
other resources
Resource compiler
Resource file
(RES)
DMC 1944
NOTES
140 ANNA UNIVERSITY CHENNAI
compliant with all ANSI standards, including the latest recommendations of a working
group on C++libraries, and has additional Microsoft extensions. Templates, exceptions,
and runtime type identification (RTTI) are fully supported in Visual C++version 6.0. The
C++Standard Template Library (STL) is also included, although it is not integrated into
the MFC library.
3.4.3 The Source Code Editor
Visual C++6.0 includes a sophisticated source code editor that supports many features
such as dynamic syntax coloring, auto-tabbing, keyboard bindings, AutoComplete etc.
Using the Visual C++6.0 AutoComplete feature, all you have to do is type the beginning
of a programming statement and the editor will provide you with a list of possible completions
to choose from. This feature is extremely handy when you are working with C++objects
and have forgotten an exact member function or data member namethey are all there in
the list for you.
3.4.4 The Resource Compiler
The Visual C++resource compiler reads an ASCII resource script (RC) file from the
resource editors and writes a binary RES file for the linker.
3.4.5 The Linker
The linker reads the OBJ and RES files produced by the C/C++compiler and the
resource compiler, and it accesses LIB files for MFC code, runtime library code, and
Windows code. It then writes the projects EXE file. An incremental link option minimizes
the execution time when only minor changes have been made to the source files. The MFC
header files contain #pragma statements (special compiler directives) that specify the
required library files, so you dont have to tell the linker explicitly which libraries to read.
3.4.6 The Debugger
The debugger works closely with Visual C++to ensure that breakpoints are saved
on disk. Toolbar buttons insert and remove breakpoints and control single-step execution.
There are Variables and Watch windows which can expand an object pointer to show all
data members of the derived class and base classes. If you position the cursor on a simple
variable, the debugger shows you its value in a little window. To debug a program, you
must build the program with the compiler and linker options set to generate debugging
information.
Edit And Continue features in the debugger lets you debug an application, change the
application, and then continue debugging with the new code. This feature dramatically
reduces the amount of time you spend debugging because you no longer have to manually
leave the debugger, recompile, and then debug again. To use this feature, simply edit any
code while in the debugger and then hit the continue button. Visual C++6.0 automatically
compiles the changes and restarts the debugger for you.
VISUAL PROGRAMMING
NOTES
141 ANNA UNIVERSITY CHENNAI
3.4.7 AppWizard
AppWizard is a code generator that creates a working skeleton of a Windows
application with features, class names, and source code filenames that you specify through
dialog boxes. AppWizard code is minimalist code; the functionality is inside the application
framework base classes. AppWizard gets you started quickly with a new application.
3.4.8 ClassWizard
ClassWizard is a program (implemented as a DLL) thats accessible from Visual
C++s View menu. ClassWizard helps on maintaining Visual C++class code. When we
need a new class, a new virtual function, or a new message-handler function, ClassWizard
writes the prototypes, the function bodies, and (if necessary) the code to link the Windows
message to the function. ClassWizard can update class code that you write.
3.4.9 The Source Browser
The Visual C++Source Browser (the browser, for short) lets you examine (and edit)
an application from the class or function viewpoint instead of from the file viewpoint.
If you rearrange the lines in any source code file, Visual C++regenerates the browser
database when you rebuild the project. This increases the build time.
In addition to the browser, Visual C++has a ClassView option that does not depend
on the browser database. You get a tree view of all the classes in your project, showing
member functions and data members. Double-click on an element, and you see the source
code immediately. The ClassView does not show hierarchy information, whereas the
browser does.
3.4.10 Online Help
In Visual C++6.0, the help system has been moved to a separate application named
the MSDN Library Viewer. This help system is based on HTML. Each topic is covered in
an individual HTML document; then all are combined into indexed files. MSDN Library
can access the help files from the Visual C++CD-ROM (the default installation option) or
from your hard disk, and it can access HTML files on the Internet.
3.4.11 Windows Diagnostic Tools
Visual C++6.0 contains a number of useful diagnostic tools. SPY++gives you a tree
view of your systems processes, threads, and windows. It also lets you view messages
and examine the windows of running applications. Youll find PVIEW useful for killing
errant processes that arent visible from the Windows task list. Visual C++also includes a
whole suite of ActiveX utilities, an ActiveX control test program, the help workshop (with
compiler), a library manager, binary file viewers and editors, a source code profiler, and
other utilities.
DMC 1944
NOTES
142 ANNA UNIVERSITY CHENNAI
3.4.12 Source Code Control
During development of Visual C++5.0, Microsoft bought the rights to an established
source code control product named SourceSafe. This product has since been included in
the Enterprise Edition of Visual C++and Visual Studio Enterprise, and it is integrated into
Visual C++so that you can coordinate large software projects. The master copy of the
projects source code is stored in a central place on the network, and programmers can
check out modules for updates. These checked-out modules are usually stored on the
programmers local hard disk. After a programmer checks in modified files, other team
members can synchronize their local hard disk copies to the master copy. Other source
code control systems can also be integrated into Visual C++.
3.4.13 The Gallery
The Visual C++Components and Controls Gallery lets you share software components
among different projects. The Gallery manages three types of modules:
1. ActiveX controlsWhen you install an ActiveX control (OCXformerly OLE
control), an entry is made in the Windows Registry. All registered ActiveX controls
appear in the Gallerys window, so you can select them in any project.
2. C++ source modulesWhen you write a new class, you can add the code to the
Gallery. The code can then be selected and copied into other projects. You can
also add resources to the Gallery.
3. Visual C++ componentsThe Gallery can contain tools that let you add features
to your project. Such a tool could insert new classes, functions, data members,
and resources into an existing project. Some component modules are supplied by
Microsoft as part of Visual C++. Others will be supplied by third-party soft-ware
firms.
If you decide to use one of the prepackaged Visual C++components, try it out first
in a dummy project to see if its what you really want. Otherwise, it might be difficult to
remove the generated code from your regular project.
All user-generated Gallery items can be imported from and exported to OGX files.
These files are the distribution and sharing medium for Visual C++components.
3.4.14 The Microsoft Foundation Class Library Version 6.0
The Microsoft Foundation Class Library (also Microsoft Foundation Classes or MFC)
is a library that wraps portions of the Windows API in C++classes, including functionality
that enables them to use a default application framework. Classes are defined for many of
the handle-managed Windows objects and also for predefined windows and common
controls.
VISUAL PROGRAMMING
NOTES
143 ANNA UNIVERSITY CHENNAI
At the time of its introduction, MFC provided C++macros for Windows message-
handling (via Message Maps), exceptions, run-time type identification (RTTI), serialization
and dynamic class instantiation.
The macros for message-handling aimed to reduce memory consumption by avoiding
gratuitous virtual table use and also to provide a more concrete structure for various Visual
C++-supplied tools to edit and manipulate code without parsing the full language. The
message-handling macros replaced the virtual function mechanism provided by C++.
The macros for serialization, exceptions, and RTTI predated availability of these
features in Microsoft C++by a number of years. 32-bit versions of MFC, for Windows
NT 3.1 and later Windows operating systems, used compilers that implemented the language
features and updated the macros to simply wrap the language features instead of providing
customized implementations, realizing upward compatibility.
3.4.15 The Microsoft Active Template Library
The Active Template Library (ATL) is a set of template-based C++classes
developed by Microsoft, intended to simplify the programming of Component Object
Model (COM) objects. The COM support in Microsoft Visual C++allows developers to
create a variety of COM objects, OLE Automation servers, and ActiveX controls. ATL
includes an object wizard that sets up primary structure of the objects very quickly with a
minimum of hand coding. On the COM client side ATL provides smart pointers that deal
with COM reference counting.
Controls for the Internet market could have been made with the Microsoft
Foundation Classes (MFC), but the market requires controls to be small and compact for
downloading over the network from Web servers. MFC applications tend to be large and
require support DLLs. ATL allows creating smaller controls without support DLLs, so
ATL is in a sense a lightweight alternative to MFC for the COM control environment. A
common use of ATL in Active Server Pages (ASP) is to construct objects that can be
called from a script. On July 28, 2009, Microsoft released a patch to ATL to fix a bug that
could allow ActiveX controls created using ATL to be vulnerable to a remote code execution
security flaw.
3.5 INTRODUCTION TO MICROSOFT FOUNDATION CLASSES
LIBRARY
The Microsoft Foundation Class Library (MFC Library) is a C++class library released
with Microsoft Visual C++ to support application development on Microsoft Windows.
Although MFC is most often used in GUI applications, it can be used to develop any type
of application. The MFC Library consists of numerous classes that are thin wrappers for
high level Application Programming Interfaces (APIs) such as WinSock and ODBC. All
the Win32 Kernel, GDI, and User Objects have associated MFC classes. The MFC
DMC 1944
NOTES
144 ANNA UNIVERSITY CHENNAI
library is called a vertical library, as it uses class inheritance heavily with very little C++
templates. When the MFC 1.0 library was first released in 1992(with Microsoft C++
7.0), back when Microsoft was touting their 16 bit Windows 3.1, the class library did not
have templates. The recent version of MFC is version 10.0 (mfc10.dll) If you do use
MFC, your applications will not have to be modified much when moving between different
platforms. For instance, many MFC applications written for Windows 3.1(Win16) were
simply recompiled for Win32 platforms such Windows 95 and NT. When Win64 comes
out, you do not have to rewrite your whole MFC again. You will just
The MFC library can either be linked statically or dynamically into your application.
If it is linked dynamically, then your application is very small. At runtime, your application
uses MFC classes through the MFC dynamic link libraries. These DLLs are usually found
in the SYSTEM subdirectory. If many applications are MFC based and use MFC
dynamically, you can save a tremendous amount of hard drive space. Also, if the library is
already loaded when one application is running, then the next application that uses MFC
dynamically loads faster.
Although MFC seems simple, it does require one to have a background in Win32
and C++programming For instance, a scroll bar in Visual Basic is simple enough. But, a
scroll bar that changes its color is not to be found in Visual Basic. If one needs to have
such a control, you will need to create an ActiveX control with either raw C++with Win32
calls, Active Template Library(ATL), or using MFC. For this problem, because of its
simplicity, ATL would be the fastest most reliable method of development. After the
control is built, it can then be used by a VB programmer on his forms.
For instance, you need to write an application with Multi threading, sockets, and
database interactions. You could write your program in straight C using Win32, WinSock
and ODBC.
All the MFC Classes have a capital C prefix. For instance, CString, CFile, CSocket,
CMutex are classes found in the MFC library. The standard MFC classes are declared
in the header file afxwin.h. If you do not use the App Wizard, you will have to turn on the
MFC by modifying the project settings in Visual C++to either static or dynamic MFC
linking.
Program 3.1: Create Window of your own class (MFC).
1. Follow steps 1 to 10 given in program 1.2.
2. This is very important if you go for MFC based programming. In the main menu
bar go to Project Settings
VISUAL PROGRAMMING
NOTES
145 ANNA UNIVERSITY CHENNAI
Figure 3.2 Project Settings Dialog Window
3. The project settings dialog window as shown in Figure 3.2 will be shown. Select
Use MFC in Shared DLL from the list box and click OK.
4. Type the following code in the Code window:
#include<afxwin.h>
class myframe:public CFrameWnd
{
public : myframe()
{
CString mywindowclass; //MFC declared string class
HBRUSH mybrush;
mybrush=(HBRUSH)::GetStockObject(WHITE_BRUSH);
mywindowclass=AfxRegisterWndClass(CS_HREDRAW| CS_VREDRAW,
AfxGetApp()->LoadStandardCursor(IDC_CROSS),
mybrush,AfxGetApp() ->LoadStandardCursor(
IDI_EXCLAMATION));
//register class with windows
Create(mywindowclass,Hello ! Welcome to MFC Classes);
}
};
class myapp:public CWinApp
{
public:
int InitInstance()
{
DMC 1944
NOTES
146 ANNA UNIVERSITY CHENNAI
myframe *p;
p=new myframe;
p->ShowWindow(3);
m_pMainWnd=p;
return 1;
}
};
myapp a;
5. Build and test the application.
3.6 GETTING STARTED WITH APPWIZARD
Application wizard generates a new, fully functional application from which you build
a more complex application.
The Application Wizard lets you generate an application using one of the predefined
visual interfaces Multiple Document Interface (MDI), Single Document Interface (SDI),
or Explorer-style.
The application you generate:
Contains a toolbar and a status bar. The default toolbar for SDI and MDI forms is
similar to a Microsoft Office toolbar. It includes the New, Open, Save, Print, Cut,
Copy, Paste, Bold, Italic, Underline, Align Left, Align Right, and Center buttons.
Explorer-style applications have a default toolbar with the Navigation Buttons,
Cut, Copy, Paste, Delete, Properties, View Large Icon, View Small Icon, View
List, and View Details buttons. You can customize the toolbar. The status bar
includes information about the status of the application and the date and time.
Can contain forms with objects bound to a local or remote data source. You can
bind your form using an ADO Data control, ADO code, or a Data Class. A variety
of form types, including Single record, Data Grid, Master/Detail, MsHFlexGrid,
and MSChart, can be created.
Once the application is created, you can view and edit the code behind the functionality
built into your new application to customize it to your needs. In addition, the code has
comments that can help you as you build other applications. Look for ToDo in the
comments for more information on customizing the code.
You cannot use the Application Wizard to modify existing projects. You can also
save the Application Wizard savings, mainly the Toolbar and Menus settings, in a profile
file (.rwp). The next time you run the Application Wizard, you can use the settings.
VISUAL PROGRAMMING
NOTES
147 ANNA UNIVERSITY CHENNAI
Use the Application Wizard:
As a starting point for developing your application.
To eliminate the redundancy in creating applications and still maintain your ability
to customize your application.
To provide a common look and feel to your applications.
3.7 CLASS WIZARD
ClassWizard is a program (implemented as a DLL) thats accessible from Visual
C++s View menu. ClassWizard takes the drudgery out of maintaining Visual C++class
code. It can be access through the View menu and ClassWizard sub menu as shown in
figure 3.3 (a) and 3.3 (b) provides a picture of the MFC ClassWizard dialog box.
(a) (b)
Figure 3.3 (a) Invoking the ClassWizard through the View menu; (b)
ClassWizard dialog
When you need a new class, a new virtual function, or a new message-handler function
(Message maps), ClassWizard writes the prototypes, the function bodies, and (if necessary)
the code to link the Windows message to the function. ClassWizard can update class code
that you write, so you avoid the maintenance problems common to ordinary code
generators.
Program 3.2: Creating a simple window using application wizard.
1. Run AppWizard to generate SDI application source code. Choose New
from Visual C++s File menu, and then click the Projects tab in the resulting New
dialog box, as shown in figure 3.4.
DMC 1944
NOTES
148 ANNA UNIVERSITY CHENNAI
Figure 3.4 Application creation using application Wizard
Make sure that MFC AppWizard (exe) is highlighted. Type Program1 as shown in
the Project Name edit box, and then click the OK button. Now you will step through a
sequence of AppWizard screens, the first of which is shown in figure 3.5.
Figure 3.5 Step 1 MFC AppWizard
VISUAL PROGRAMMING
NOTES
149 ANNA UNIVERSITY CHENNAI
2. Select the Single Document option. Accept the defaults in the next four screens.
The last screen should look like the following figure 3.6.
Figure 3.6 Step 6 of 6 MFC AppWizard
3. Notice that the class names and source-file names have been generated based on
the project name EX03A. You could make changes to these names at this point if
you wanted to. Click the Finish button. Just before AppWizard generates your
code, it displays the New Project Information dialog box, shown in figure 3.7.
Figure 3.7 Summary of the Application created using AppWizard
4. When you click the OK button, AppWizard begins to create your applications
subdirectory (ex03a under \vcpp32) and a series of files in that subdirectory. When
AppWizard is finished, look in the applications subdirectory. The following files
are created by the AppWizard.
DMC 1944
NOTES
150 ANNA UNIVERSITY CHENNAI
5. Compile and link the generated code. AppWizard, in addition to generating
code, creates custom project and workspace files for your application. The project
file, Program1.dsp, specifies all the file dependencies together with the compile
and link option flags. Because the new project becomes Visual C++s current
project, you can now build the application by choosing Build Program1.exe from
the Build menu or by clicking the Build toolbar button and you can find a simple
window created as show in figure 3.8.
Figure 3.8 Simple window created using AppWizard
File Description
Program1.dsp A project file that allows Visual C++to build your
application
Program1.dsw A workspace file that contains a single entry for
Program1.dsp
Program1.rc An ASCII resource script file
Program1View.cpp A view class implementation file that contains
C Program1View class member functions
Program1View.h A view class header file that contains the
C Program1View class declaration
Program1.opt A binary file that tells Visual C++which files are
open for this project and how the windows are
arranged (This file is not created until you save the
project.)
ReadMe.txt A text file that explains the purpose of the generated
files
resource.h A header file that contains #define constant
definitions
VISUAL PROGRAMMING
NOTES
151 ANNA UNIVERSITY CHENNAI
Now lets see how to use AppWizard for creating a simple window and then to draw
inside that window in the mouse events.
Program 3.3 Drawing inside the View Window
1. Run AppWizard to generate SDI application source code. Choose New
from Visual C++s File menu, and then click the Projects tab in the resulting New
dialog box as shown in Figure 3.9. Type a project name (for e.g.
Mouse_Event_Exercise) in the Project Name edit box, and then click the OK
button. Now you will step through a sequence of AppWizard screens, the first of
which is shown in Figure 3.10.
2. Be sure to select the Single Document option. Accept the defaults in the next five
screens.
3. Click the Finish button. Just before AppWizard generates your code, it displays
the New Project Information dialog box, shown in Figure 3.11.
Figure 3.9 New Dialog Window
Figure 3.10 Step1 of 6 in AppWizard
DMC 1944
NOTES
152 ANNA UNIVERSITY CHENNAI
Figure 3.11 New Project Information Dialog Window
4. Add the m_rectEllipse and m_nColor data members to
CMouse_Event_ExerciseView. With the Workspace window set to ClassView,
right-click the CMouse_Event_ExerciseView class, select Add Member
Variable, and then insert the following two data members:
private:
CRect m_rectEllipse;
int m_nColor;
If you prefer, you could type the above code inside the class declaration in the file
Mouse_Event_ExerciseView.h.
5. Use ClassWizard to add a CMouse_Event_ExerciseView class message
handler. Choose ClassWizard from the View menu of Visual C++, or right-click
inside a source code window and choose ClassWizard from the context menu.
When the MFC ClassWizard dialog appears, be sure that the
CMouse_Event_ExerciseView class is selected, as shown in the Figure 3.12.
Now click on CMouse_Event_ExerciseView at the top of the Object IDs list
box, and then scroll down past the virtual functions in the Messages list box and
double-click on WM_LBUTTONDOWN. The OnLButtonDown function name
should appear in the Member Functions list box, and the message name should be
displayed in bold in the Messages list box.
VISUAL PROGRAMMING
NOTES
153 ANNA UNIVERSITY CHENNAI
Figure 3.12 Class Wizard Dialog Box
6. Edit the OnLButtonDown code in Mouse_Event_ExerciseView.cpp. Click
the Edit Code button. ClassWizard opens an edit window for
Mouse_Event_ExerciseView.cpp in Visual C++and positions the cursor on the
newly generated OnLButtonDown member function. The following boldface code
(that you type in) replaces the previous code:
void CMouse_Event_ExerciseView::OnLButtonDown (UINT nFlags,
CPoint point)
{
if (m_rectEllipse.PtInRect(point))
{
if (m_nColor == GRAY_BRUSH)
{
m_nColor = WHITE_BRUSH;
}
else {
m_nColor = GRAY_BRUSH;
}
InvalidateRect(m_rectEllipse);
}
}
7. Edit the constructor and the OnDraw function in
Mouse_Event_ExerciseView .cpp. The following boldface code (that you type
in) replaces the previous code:
DMC 1944
NOTES
154 ANNA UNIVERSITY CHENNAI
CMouse_Event_ExerciseView:: CMouse_Event_ExerciseView () :
m_rectEllipse(0, 0, 200, 200)
{
m_nColor = GRAY_BRUSH;
}
.
.
.
void CMouse_Event_ExerciseView::OnDraw(CDC* pDC)
{
pDC->SelectStockObject(m_nColor);
pDC->Ellipse(m_rectEllipse);
}
8. Build and run the Mouse_Event_Exercise program. Choose Build
Mouse_Event_Exercise.exe from the Build menu, then choose Execute
Mouse_Event_Exercise.exe from the Build menu.
9. The resulting program responds to presses of the left mouse button by changing
the color of the circle in the view window. (Dont press the mouses left button
quickly in succession; Windows interprets this as a double click rather than two
single clicks.)
3.8 THE GRAPHICS DEVICE INTERFACE, COLORS, AND FONTS
Anytime your program draws to the display or the printer, it must use the GDI functions.
The GDI provides functions for drawing points, lines, rectangles, polygons, ellipses, bitmaps,
and text. GDI uses a device context to store data that it requires to display text and
graphics on a specified device. The graphics objects stored in a device context include a
pen for line drawing, a brush for painting and filling, a font for text output, a bitmap for
copying or scrolling, a palette for defining the available colors, and a clipping region. Windows
supports printer device contexts for drawing on printers, display device contexts for drawing
on video displays, and memory device contexts for drawing into memory.
3.8.1 Getting a Handle to a Device Context
Windows provides several methods for obtaining a device context handle, depending
on whether the device is a display, printer, or memory device.
You use a display device context to draw in the client area of a screen.
You use a memory device context to store bitmapped images in memory rather than
sending it to an output device. A memory device context enables Windows CE to treat a
portion of memory as a virtual device.
VISUAL PROGRAMMING
NOTES
155 ANNA UNIVERSITY CHENNAI
You use a printer device context to send output to a printer.
It is important when using a device context that you release or delete it when it is no
longer in use. Releasing a device context frees the device for use by other applications.
Each C++device context object has an associated Windows device context, identified
by a 32-bit handle of type HDC.
Microsoft Foundation Class (MFC) Library version 6.0 provides a number of device
context classes. The base class CDC has all the member functions (including some virtual
functions) that youll need for drawing. Except for the oddball CMetaFileDC class, derived
classes are distinct only in their constructors and destructors. If you (or the application
framework) construct an object of a derived device context class, you can pass a CDC
pointer to a function such as OnDraw. For the display, the usual derived classes are
CClientDC and CWindowDC. For other devices, such as printers or memory buffers,
you construct objects of the base class CDC.
3.8.2 Obtaining a Display Device Context
To get a handle to a display device context, call the BeginPaint or GetDC function
and supply a handle to a window. Windows returns a handle to a display device context
with default objects, attributes, and graphic modes. Newly created device contexts start
with default brush, palette, font, pen, and region objects. You can begin drawing using
these defaults, or you can choose a new object, change the attributes of an existing object,
or choose a new mode.
You can examine a default objects attributes by calling the GetCurrentObject and
GetObject functions. The GetCurrentObject function returns a handle identifying the
current pen, brush, palette, bitmap, or font, and the GetObject function initializes a structure
containing the object attributes.
The following table 3.1 shows the object-specific creation functions you can call to
replace a default object.
Table 3.1 Graphics Objects
Graphics
object
Creation function
Bitmap CreateBitmap, CreateCompatibleBitmap, CreateDIBSection
Brush CreateDIBPatternBrushPt, CreatePatternBrush,
CreateSolidBrush
Palette CreatePalette
Font CreateFontIndirect
Pen CreatePen, CreatePenIndirect
DMC 1944
NOTES
156 ANNA UNIVERSITY CHENNAI
Each of these functions returns a handle identifying the new object. After you retrieve
a handle, you can call the SelectObject function to select the new object into the device
context. However, you should save the SelectObject return value because it is the handle
to the default object. When you finish using the new object, use SelectObject to restore
the default object, and delete the new object with the DeleteObject function.
When you have finished drawing in the display area, you must release the device
context by calling the EndPaint or ReleaseDC function. If you called BeginPaint to
create the device context, then call EndPaint to release it. If you called GetDC to create
the device context, then call ReleaseDC to release it.
Call BeginPaint and EndPaint while processing WM_PAINT messages in your
window procedure. Otherwise, call GetDC and ReleaseDC to obtain and release a device
context.
The following code example shows how to call GetDC and ReleaseDC to obtain
and release a device context and how to call SelectObject to get a new object.
HDC hDC; // Handle to a display device context
HBRUSH hBrush, // Handle to the new brush object
hOldBrush; // Handle to the old brush object
// Retrieve the handle to the display device context.
if (!(hDC =GetDC (hwnd)))
return;
// Create a solid brush and select it into the device context.
hBrush =CreateSolidBrush (RGB(0, 255, 255));
hOldBrush =SelectObject (hDC, hBrush);
// Draw a rectangle.
Rectangle (hDC, 0, 0, 100, 200);
// Select the old brush back into the device context.
SelectObject (hDC, hOldBrush);
// Delete the new brush object.
DeleteObject (hBrush);
// Release the device context.
ReleaseDC (hwnd, hDC);
VISUAL PROGRAMMING
NOTES
157 ANNA UNIVERSITY CHENNAI
3.8.3 GDI Objects
A Windows GDI object type is represented by an MFC library class. CGdiObject is
the abstract base class for the GDI object classes. A Windows GDI object is represented
by a C++object of a class derived from CGdiObject. Heres a list of the GDI derived
classes:
CBitmapA bitmap is an array of bits in which one or more bits correspond to
each display pixel. You can use bitmaps to represent images, and you can use
them to create brushes.
CBrushA brush defines a bitmapped pattern of pixels that is used to fill areas
with color.
CFontA font is a complete collection of characters of a particular typeface
and a particular size. Fonts are generally stored on disk as resources, and some
are device-specific.
CPaletteA palette is a color mapping interface that allows an application to
take full advantage of the color capability of an output device without interfering
with other applications.
CPenA pen is a tool for drawing lines and shape borders. You can specify a
pens color and thickness and whether it draws solid, dotted, or dashed lines.
CRgnA region is an area whose shape is a polygon, an ellipse, or a combination
of polygons and ellipses. You can use regions for filling, clipping, and mouse hit-
testing.
3.8.4 SDI and MDI
MFC makes it easy to work with both single-document interface (SDI) and multiple-
document interface (MDI) applications.
SDI applications allow only one open document frame window at a time. MDI
applications allow multiple document frame windows to be open in the same instance of an
application. An MDI application has a window within which multiple MDI child windows,
which are frame windows themselves, can be opened, each containing a separate document.
In some applications, the child windows can be of different types, such as chart windows
and spreadsheet windows. In that case, the menu bar can change as MDI child windows
of different types are activated.
3.8.4.1 Document/View Architecture
By default, the MFC Application Wizard creates an application skeleton with a
document class and a view class. MFC separates data management into these two classes.
The document stores the data and manages printing the data and coordinates updating
multiple views of the data. The view displays the data and manages user interaction with it,
including selection and editing.
DMC 1944
NOTES
158 ANNA UNIVERSITY CHENNAI
The document/view model lets a separate view object represent each view of the
data, while code common to all views (such as a calculation engine) can reside in the
document. The document also takes on the task of updating all views whenever the data
changes.
The MFC document/view architecture makes it easy to support multiple views, multiple
document types, splitter windows, and other valuable user-interface features.
At the heart of document/view are four key classes:
The CDocument (or COleDocument) class supports objects used to store or control
your programs data and provides the basic functionality for programmer-defined document
classes. A document represents the unit of data that the user typically opens with the Open
command on the File menu and saves with the Save command on the File menu.
The CView (or one of its many derived classes) provides the basic functionality for
programmer-defined view classes. A view is attached to a document and acts as an
intermediary between the document and the user: the view renders an image of the document
on the screen and interprets user input as operations upon the document. The view also
renders the image for both printing and print preview.
CFrameWnd (or one of its variations) supports objects that provides the frame around
one or more views of a document.
CDocTemplate (or CSingleDocTemplate or CMultiDocTemplate) supports an
object that coordinates one or more existing documents of a given type and manages
creating the correct document, view, and frame window objects for that type.
The following figure 3.13 shows the relationship between a document and its view.
Figure 3.13 Document and View
Part of document
currently visible
Document
Vi ew
VISUAL PROGRAMMING
NOTES
159 ANNA UNIVERSITY CHENNAI
The document/view implementation in the class library separates the data itself from
its display and from user operations on the data. All changes to the data are managed
through the document class. The view calls this interface to access and update the data.
Documents, their associated views, and the frame windows that frame the views are
created by a document template. The document template is responsible for creating and
managing all documents of one document type.
3.8.4.2 Documents, Views, and the Framework
At the heart of the MFC framework are the concepts of document and view. A
document is a data object with which the user interacts in an editing session. It is created
by the New or Open command on the File menu and is typically saved in a file. A view is
a window object through which the user interacts with a document.
The key objects in a running application are:
The document or documents.
Your document class (derived from CDocument) specifies your applications data.
The view or views.
Your view class (derived from CView) is the users window on the data. The
view class controls how the user sees your documents data and interacts with it.
In some cases, you may want a document to have multiple views of the data.
The frame windows
Views are displayed inside document frame windows. In an SDI application, the
document frame window is also the main frame window for the application. In
an MDI application, document windows are child windows displayed inside a
main frame window. Your derived main frame-window class specifies the styles
and other characteristics of the frame windows that contain your views. If you
need to customize frame windows, derive from CFrameWnd to customize the
document frame window for SDI applications. Derive from CMDIFrameWnd to
customize the main frame window for MDI applications. Also derive a class from
CMDIChildWnd to customize each distinct kind of MDI document frame windows
that your application supports.
The document template or templates
A document template orchestrates the creation of documents, views, and frame
windows. A particular document-template class, derived from class
CDocTemplate, creates and manages all open documents of one type. Applications
that support more than one type of document have multiple document templates.
Use class CSingleDocTemplate for SDI applications, or use class
CMultiDocTemplate for MDI applications.
DMC 1944
NOTES
160 ANNA UNIVERSITY CHENNAI
The application object
Your application class (derived from CWinApp) controls all of the objects above
and specifies application behavior such as initialization and cleanup. The applications
one and only application object creates and manages the document templates for
any document types the application supports.
Thread objects
If your application creates separate threads of execution for example, to perform
calculations in the background youll use classes derived from CWinThread.
CWinApp itself is derived from CWinThread and represents the primary thread
of execution (or the main process) in your application. You can also use MFC in
secondary threads.
In a running application, these objects cooperatively respond to user actions, bound
together by commands and other messages. A single application object manages one or
more document templates. Each document template creates and manages one or more
documents (depending on whether the application is SDI or MDI). The user views and
manipulates a document through a view contained inside a frame window. The following
figure 3.14 shows the relationships among these objects for an SDI application.
Figure 3.14 Objects in a Running SDI Application
3.9 READING AND WRITING DOCUMENTS SERIALIZATION
Serialization is the process of saving the state of an object by converting it to a stream
of bytes. The object can then be persisted to file, database, or even memory. The reverse
process of serialization is known as deserialization.
In the Microsoft Foundation Class (MFC) library, designated classes have a member
function named Serialize. When the application framework calls Serialize for a particular
objectfor example, an object of class CStudentthe data for the student is either saved
on disk or read from disk.
Application Object
Document Template
Document
Mai n Frame Wi ndow
Arrows show directions
of communication flow.
Toolbar
View
Status Bar
VISUAL PROGRAMMING
NOTES
161 ANNA UNIVERSITY CHENNAI
3.9.1 The CArchive and CFile Classes
Serialization in Visual C++applications is accomplished through the CArchive class.
The CArchive class is designed to act as an input/output (I/O) stream for a CFile object,
as shown in Figure 3.15.
It uses C++streams to enable efficient data flow to and from the file that is the
storage of the application data. The CArchive class cannot exist without a CFile class
object to which it is attached.
The CArchive class can store data in a number of types of files, all of which are
descendants of the CFile class. By default, the AppWizard includes all the functionality to
create and open regular CFile objects for use with CArchive. If you want or need to work
with one of these other file types, you might need to add additional code to your application
to enable the use of these different file types.
Figure 3.15 The CArchive class stores application data in a CFile object
3.9.2 The Serialize Function
The CArchive class is used in the Serialize function on the document and data objects
in Visual C++applications. When an application is reading or writing a file, the document
objects Serialize function is called, passing the CArchive object that is used to write to or
read from the file. In the Serialize function, the typical logic to follow is to determine whether
the archive is being written to or read from by calling the CArchive IsStoring or IsLoading
functions. The return value from either of these two functions determines if your application
needs to be writing to or reading from the CArchive classs I/O stream.
Serialize
Function
CArchive
CFile
Application
Application
Object
DMC 1944
NOTES
162 ANNA UNIVERSITY CHENNAI
Program 3.4: Serializing your own objects and classes.
1. Open Visual C++and click the New item in the File menu, opening the New
dialog box.
2. Now select the MFC AppWizard(exe) entry in the New dialog box.
3. Give the new program the name Serialize in the Project name box.
4. Click OK to starts the Visual C++AppWizard.
5. Click the option marked Single Document in the AppWizard, click Finish.
6. Here, the AppWizard indicates four classes will be created : CSerializeApp,
CMainFrame, CSerializeDoc, CSerializeView .
7. Click ProjectAdd to ProjectNew. A list of file types appear in the dialog box.
Choose C/C++ Header File (be sure that Add to Project checkbox is checked.
Type file name CData.h in the Edit Box.
8. Open the CData.h file and place the code:
class CData
{
private:
CString data;
public:
CData( )
{
data=CString( );
}
void AddText(CString text)
{
data+=text;
}
void DrawText(CDC* pDC)
{
pDC->TextOut(0,0,data);
}
void ClearText()
{
data= ;
}
};
VISUAL PROGRAMMING
NOTES
163 ANNA UNIVERSITY CHENNAI
CData( ) Constructor to initialize the string to empty .
AddText( ) to add more text to the end of string.
DrawText( ) to draw string in the device context.
ClearText( ) to clear the string.
9. Include this new file in the documents header & create a new object of CData
class named DataObject.
10. Now we add code to OnChar( ), which adds the newly typed character to internal
data in DataObject using the AddText( ) method.
void CSerializeView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
CSerializeDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pDoc->DataObject.AddText(CString(nChar));
Invalidate();
CView::OnChar(nChar, nRepCnt, nFlags);
}
11.We draw the text in the DataObject object using the DrawText( ) method in the
OnDraw( ) method.
void CSerializeView::OnDraw(CDC* pDC)
{
CSerializeDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pDoc->DataObject.DrawText(pDC);
}
12. To make class serializable, add code to CData class
(i) make it derived from MFC CObject class.
(ii) also include DECLARE_SERIAL macro to add the declarations of the
methods use for serialization.
(iii) Override CObjects Serialize( ) method.
class CData : public CObject //to achieve 12(i)
{
private:
CString data;
DECLARE_SERIAL(CData); //to achieve 12 (ii)
DMC 1944
NOTES
164 ANNA UNIVERSITY CHENNAI
public:
CData( )
{
data=CString( );
}
void AddText(CString text)
{
data+=text;
}
void DrawText(CDC* pDC)
{
pDC->TextOut(0,0,data);
}
void ClearText( )
{
data= ;
}
void Serialize(CArchive& archive); //to achieve 12 (iii)
};
13. To write new version of Serialize, add new file CData.cpp to the project.
(i) Call base classs Serialize( ) method.
(ii) Serialize our CString data member using <<& >>
(iii) Include IMPLEMENT_SERIAL macro, which adds additional methods
for serialization.
void CData::Serialize(CArchive& archive) //to achieve 13(i)
{
CObject::Serialize(archive);
if(archive.IsStoring())
{
archive<<data; //to achieve 13 (ii)
}
else
{
archive>>data;
}
}
IMPLEMENT_SERIAL(CData,CObject,0); //to achieve 13 (iii)
VISUAL PROGRAMMING
NOTES
165 ANNA UNIVERSITY CHENNAI
14. To serialize our DataObject object, we have to call its Serialize( ) method in
documents Serialize( ) method :
void CSerializeDoc::Serialize (CArchive& ar)
{
DataObject.Serialize(ar);
}
15. Execute and Test the application and youll find output windows as shown in Figure
3.16 and 3.17.
Figure 3.16 Serializing own class and objects
Figure 3.17 Serializing custom class
DMC 1944
NOTES
166 ANNA UNIVERSITY CHENNAI
3.10 Multiple Document Interface
The Document/View architecture is the foundation used to create applications based
on the Microsoft Foundation Classes library. It allows you to make distinct the different
parts that compose a computer program including what the user sees as part of your
application and the document a user would work on. This is done through a combination
of separate classes that work as an ensemble.
The parts that compose the Document/View architecture are a frame, one or more
documents, and the view. Put together, these entities make up a usable application.
3.10.1 The view
A view is the platform the user is working on to do his or her job. For example, while
performing word processing, the user works on a series of words that compose the text. If
a user is performing calculations on a spreadsheet application, the interface the user is
viewing is made of small boxes called cells. Another user may be in front of a graphic
document while drawing lines and other geometric figures. The thing the user is starring at
and performing changes is called a view. The view also allows the user to print a document.
To let the user do anything on an application, you must provide a view, which is an
object based on the CView class. You can either directly use one of the classes derived
from CView or you can derive your own custom class from CView or one of its child
classes.
3.10.2 The Document
For a computer application, a document holds the users data. For example, after
working on a text processor, the user may want to save the file. Such an action creates a
document and this document must reside somewhere. In the same way, to use an existing
file, the user must locate it, open it, and make it available to the application. These two jobs
and many others are handled behind the scenes as a document.
To create the document part of this architecture, you must derive an object from the
CDocument class.
3.10.3 The Frame
As its name suggests, a frame is a combination of the building blocks, the structure (in
the English sense), and the borders of an item. A frame gives physical presence to a
window. A frame defines the location of an object with regards to the Windows desktop.
A frame provides borders to a window, borders that the user can grab to move, size, and
resize the object. The frame is also a type of desk that holds the tools needed on an
application.
An application cannot exist without a frame. As we saw in previous lessons, to provide
a frame to an application, you can derive a class from CFrameWnd.
VISUAL PROGRAMMING
NOTES
167 ANNA UNIVERSITY CHENNAI
3.10.4 Overview of the Single Document Interface (SDI)
The expression Single Document Interface or SDI refers to a document that can
present only one view to the user. This means that the application cannot display more than
one document at a time. If the user wants to view another type of document of the current
application, he or she must another instance of the application. Notepad and WordPad are
examples of SDI applications.
Notepad can be used to open only one document such as an HTML file, to view
another file, the user would either replace the current document or launch another copy
of Notepad.
To create an SDI, Microsoft Visual C++provides the MFC wizard which provides
all the basic functionality that an application needs, including the resources and classes.
3.10.5 Overview of the Multiple Document Interface (MDI)
An application is referred to as Multiple Document Interface, or MDI, if the user can
open more than one document in the application without closing it. To provide this
functionality, the application provides a parent frame that acts as the main frame of the
computer program.
Inside of this frame, the application allows creating views that each uses its own
frame, making it distinct from the other. Microsoft Word 97 as shown in Figure 3.18
displays as a classic MDI application.
The separation of the parent and the child frames allows the user to close one child
document or all documents. This would still leave the main frame of the application but the
user cannot use it as a document. Still, the main frame allows the user to either create
a new document or open an existing one.
To manage the differentiation between the parent and its children, the application uses
two different menus: one for the main frame and one for a (or each) child. Both menus use
the same menu bar, meaning that the application cannot display two frame menus at one
time. It displays either the parent menu or a (the) child menu. When at least one document
is displaying, the menu applies to the document. If no document is displaying, the main
frame is equipped with a simplified menu with limited but appropriate operations. The user
can only create a new document, only open an existing document, or simply close the
application.
DMC 1944
NOTES
168 ANNA UNIVERSITY CHENNAI
Figure 3.18 MSWord Application
Program 3.5: Creating a Multiple Document Interface
1. Open Visual C++and click the New item in the File menu, opening the New
dialog box.
2. Now select the MFC AppWizard(exe) entry in the New dialog box.
3. Give the new program the name Multiview in the Project name box.
4. Click OK to starts the Visual C++AppWizard.
5. Click the option marked Multiple Document in the AppWizard, click Finish.
6. Here, the AppWizard indicates four classes will be created : CKeystrokesApp,
CMainFrame, CKeystrokesDoc, CKeystrokesView .
7. Declare the StringData variable on the documents header file, MultiviewDoc.h,
in the protected part.
class CMultiviewDoc : public CDocument
{
CString StringData;
.
.
.
};
8. Initialize that string to an empty string in the documents constructor, which
we find in MultiviewDoc.cpp.
CMultiviewDoc::CMultiviewDoc()
{
StringData= ;
}
VISUAL PROGRAMMING
NOTES
169 ANNA UNIVERSITY CHENNAI
9. We have to store data on the disk:
void CMultiviewDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
ar << StringData;
}
else
{
ar >> StringData;
}
}
10. Add a new event handler OnChar( ) to our view class which is called every time
the user types the character.
11. The character the user typed is now in the nChar parameter, which we store in the
data string object, StringData. We need a pointer (pDoc) to our document object.
12. Add the character nChar to the string StringData. Steps 10, 11 and 12 will result
in the following lines of code in the OnChar( ) event handler:
void CMultiviewView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) //step 10
{
CMultiviewDoc* pDoc=GetDocument(); //step11
ASSERT_VALID(pDoc);
pDoc->StringData+=nChar; //step 12

}
13. Well handle the display of our data in the views OnDraw( ). We need to draw
the text string, which we do with TextOut( ).
void CMultiviewView::OnDraw(CDC* pDC)
{
CMultiviewDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pDC->TextOut(0,0,pDoc->StringData);
}
DMC 1944
NOTES
170 ANNA UNIVERSITY CHENNAI
14. Modify the OnChar( ) event handler according to the following steps:
a. Using UpdateAllViews( ) method, were able to refresh all the views into this
document now that user has typed a new character.
b. Set the documents modified flag using SetModifiedFlag( ),means that if user
tries to close the current document without saving it, the program will ask if
they want to save it before the data in it is lost.
void CMultiviewView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
CMultiviewDoc* pDoc=GetDocument();
ASSERT_VALID(pDoc);
pDoc->StringData+=nChar;
Invalidate();
pDoc->UpdateAllViews(this,0L,NULL); //step 14a
pDoc->SetModifiedFlag(); //step 14b
CView::OnChar(nChar, nRepCnt, nFlags);
}
15. Test the above program to see the outputs as shown in the below Figure 3.19.
Figure 3.19 Multiple Document Interface
VISUAL PROGRAMMING
NOTES
171 ANNA UNIVERSITY CHENNAI
3. 11 BITMAPS
A bitmap is a series of points (bits) arranged like a map so that, when put together,
they produce a picture that can be written to, copied from, re-arranged, changed,
manipulated, or stored as a a computer file. Bitmaps are used to display pictures on
graphical applications, word processors, database files, or audience presentations.
To display its product on a device such as a monitor or a printer, a bitmap holds some
properties and follows a set of rules.
There are various types of bitmaps, based on the number of colors that the
bitmap can display. First of all, a bitmap can be monochrome, in which case each
pixel corresponds to 1 bit. A bitmap can also be colored. The number of colors that
a bitmap can display is equal to 2 raised to the number of pits/pixel. For example, a
simple bitmap uses only 4 bits/pixel or 4 bpp can handle only 24 =16 colors. A more
enhanced bitmap that requires 8 bpp can handle 28 =256 colors. Bitmaps are divided
in two categories that control their availability to display on a device.
A device-independent bitmap (DIB) is a bitmap that is designed to be loaded on
any application or display on any device and produce the same visual effect. To make
this possible, such a bitmap contains a table of colors that describes how the colors of
the bitmap should be used on pixels when displaying it. The characteristics of a DIB
are defined by the BITMAPINFO structure.
A device-dependent bitmap (DDB) is a bitmap created from the BITMAP
structure using the dimensions of the bitmap.
3.11.1 Bitmap Creation
Unlike the other GDI tools, creating a bitmap usually involves more steps. For
example, you may want to create a bitmap to display on a window. You may create
another bitmap to paint a geometric area, in which case the bitmap would be used as
a brush.
Before creating a bitmap as a GDI object, you should first have a bitmap. You
can do this by defining an array of unsigned hexadecimal numbers. Such a bitmap
can be used for a brush. Once your bitmap is ready, call the LoadBitmap function. Its
syntax is:
HBITMAP LoadBitmap(HINSTANCE hInstance, LPCTSTR lpBitmapName);
The hInstance argument is the instance of the application that contains the
bitmap you want to use.
The lpBitmapName argument is the string that determines where the bitmap file is
located. If you had imported the bitmap, you can use the MAKEINTRESOURCE
macro to convert this string.
Before selecting the newly created bitmap object, allocate a block of computer
memory that would hold the bitmap. You can then copy it to the actual device. This
job can be taken care of by the CreateCompatibleDC function. Its syntax is:
DMC 1944
NOTES
172 ANNA UNIVERSITY CHENNAI
HBITMAP CreateCompatibleBitmap(HDC hdc, int nWidth, int nHeight);
This function takes a pointer to a device context. If it is successful, it returns
TRUE or a non-zero value. If it is not, it returns FALSE or 0.
3.11.2 Displaying Bitmaps
The simplest drawing operations on a window occur by handling WM_PAINT.
When your window is first displayed, restored from being minimised, or uncovered
from having another window on top of it, Windows sends the WM_PAINT message
to the window to let it know that it needs to redraw its contents. When you draw
something on the screen it is NOT permanent, its only there untill something else
draws over it, and you will need to redraw it when that part of your window becomes
visible to the user again.
First to initialize the bitmap insert the following lines of code:
HBITMAP g_hbmBall =NULL;
Then do the following in the windows procedure:
case WM_CREATE:
g_hbmBall =LoadBitmap(GetModuleHandle(NULL),
MAKEINTRESOURCE(IDB_BALL));
if(g_hbmBall ==NULL)
MessageBox(hwnd, Could not load IDB_BALL!, Error, MB_OK|
MB_ICONEXCLAMATION);
break;
The first step is of course loading the bitmap, this is quite simple with a bitmap
resource, there are no significant differences from loading other resource types. Then
use the following code to draw:
case WM_PAINT:
{
BITMAP bm;
PAINTSTRUCT ps;
HDC hdc =BeginPaint(hwnd, &ps);
HDC hdcMem =CreateCompatibleDC(hdc);
HBITMAP hbmOld =SelectObject(hdcMem, g_hbmBall);
GetObject(g_hbmBall, sizeof(bm), &bm);
BitBlt (hdc, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0,
SRCCOPY);
SelectObject(hdcMem, hbmOld);
DeleteDC(hdcMem);
EndPaint(hwnd, &ps);
}
break;
VISUAL PROGRAMMING
NOTES
173 ANNA UNIVERSITY CHENNAI
3.11.3 Getting the Window DC
To start off we declare a couple of variables we need. Notice that the first one is a
BITMAP, not an HBITMAP. BITMAP is a struct that holds information about an
HBITMAP which is the actual GDI object. We need a way to get the height and width of
the HBITMAP so we use GetObject() which contrary to its name doesnt really get an
object, but rather information about an existing one. GetObjectInfo would have been a
more appropriate label. GetObject() works for various GDI object types which it can
distinguish based on the value of the second parameter, the size of the structure.
The PAINTSTRUCT is a structure that contains information about the window being
painted and what exactly is going on with the paint message. For most simple tasks, you
can simply ignore the information it contains, but its required for the call to BeginPaint().
BeginPaint() as its name suggests is designed specifically for handling the WM_PAINT
message. When not handling a WM_PAINT message you would use GetDC() which we
will see in the timer animation examples in a while... but in WM_PAINT, its important to
use BeginPaint() and EndPaint().
BeginPaint() returns us an HDC that represents the HWND that we pass to it, the
one that WM_PAINT is being handled for. Any drawing operation we perform on this
HDC will immediately display on the screen.
3.11.4 Setting up a Memory DC for the Bitmap
In order to draw on or with bitmaps, we need to create a DC in memory... the
easiest way to do that here is to CreateCompatibleDC() with the one we already
have. This gives us a Memory DC that is compatible with the color depth and display
properties of the HDC for the window.
Now we call SelectObject() to select the bitmap into the DC being careful to store
the default bitmap so that we can replace it later on and not leak GDI objects.
3.11.5 Drawing
Once weve gotten the dimentions of the bitmap filled into the BITMAP struct, we
can call BitBlt() to copy the image from our Memory DC to the Window DC, thus displaying
on the screen. As always, you can look up each parameter in MSDN, but in short they are:
The destination, the position and size, the source and source position, and finally the Raster
Operation (ROP code), which specifies how to do the copy. In this case, we want a simple
exact copy of the source made, no fancy stuff.
BitBlt() is probably the all time happiest function in all of the Win32 API and is
the staple diet of anyone learning to write games or other graphics applications in
windows. It was probably the first API that I memorised all the parameters to.
DMC 1944
NOTES
174 ANNA UNIVERSITY CHENNAI
3.11.6 Cleanup
At this point the bitmap should be on the screen, and we need to clean up after
ourselves. The first thing to do is restore the Memory DC to the state it was when we
got it, which means replacing our bitmap with the default one that we saved. Next we
can delete it altogether with DeleteDC().
Finally we release the Window DC we got from BeginPaint() using EndPaint().
Destroying an HDC is a little confusing sometimes because there are at least 3
ways to do it depending on how you got it in the first place. Heres a list of the
common methods of gaining an HDC, and how to release it when youre done.
GetDC() - ReleaseDC()
BeginPaint() - EndPaint()
CreateCompatibleDC() - DeleteDC()
And finally, at the termination of our program, we want to free any resources
that we allocated. Technically speaking this isnt absolutely required, since modern
Windows platforms are pretty good at freeing everything when your program exists,
but its always a good idea to keep track of your own objects because if get lazy and
dont delete them they have a habit of getting loose. And no doubt, there are still bugs
in windows especially older versions that wont clean up all of your GDI objects if
you dont do a thorough job.
case WM_DESTROY:
DeleteObject(g_hbmBall);
PostQuitMessage(0);
break;
Now let us see how a bitmap image can be used in your windows program.
Program 3.6: Embedding bitmap resource in a window.
1. Start Microsoft VC++to create a new Win32 Project and name it Bitmap1.
2. Create it as a Windows Application and Empty Project.
3. Save any bitmap image in your computer as penguin.bmp. For this program let us
make use of the following bitmap image in the below Figure 3.20.
Figure 3.20 Penguin Bitmap image
VISUAL PROGRAMMING
NOTES
175 ANNA UNIVERSITY CHENNAI
4. On the main menu, click Insert ->Resource... and select Bitmap resource
5. Then click the Import... button
6. Locate the above picture from your computer and import it
7. In the Properties window, change its ID to IDB_PENGUIN
8. Save the resource. Save the resource script as Penguin.rc then add it to your
project (Project ->Add To Project ->Files... and select the file Penguin.rc)
9. Add a new C++(Source) File named Penguin and implement it as follows:
#include <windows.h>
#include Resource.h
HINSTANCE hInst;
LRESULT CALLBACK WindProcedure(HWND hWnd, UINT Msg, WPARAM wParam,
LPARAM lParam);
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX WndCls;
static char szAppName[] =BitmapIntro;
MSG Msg;
hInst =hInstance;
WndCls.cbSize =sizeof(WndCls);
WndCls.style =CS_OWNDC | CS_VREDRAW | CS_HREDRAW;
WndCls.lpfnWndProc =WindProcedure;
WndCls.cbClsExtra =0;
WndCls.cbWndExtra =0;
WndCls.hInstance =hInst;
WndCls.hIcon =LoadIcon(NULL, IDI_APPLICATION);
WndCls.hCursor =LoadCursor(NULL, IDC_ARROW);
WndCls.hbrBackground =(HBRUSH)GetStockObject(WHITE_BRUSH);
WndCls.lpszMenuName =NULL;
WndCls.lpszClassName =szAppName;
WndCls.hIconSm =LoadIcon(hInstance, IDI_APPLICATION);
RegisterClassEx(&WndCls);
DMC 1944
NOTES
176 ANNA UNIVERSITY CHENNAI
CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
szAppName,
Bitmaps Fundamentals,
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
while( GetMessage(&Msg, NULL, 0, 0) )
{
TranslateMessage(&Msg);
DispatchMessage( &Msg);
}
return static_cast<int>(Msg.wParam);
}
LRESULT CALLBACK WindProcedure(HWND hWnd, UINT Msg,
WPARAM wParam, LPARAM lParam)
{
HDC hDC, MemDCPenguin;
PAINTSTRUCT Ps;
HBITMAP bmpPenguin;
switch(Msg)
{
case WM_DESTROY:
PostQuitMessage(WM_QUIT);
break;
case WM_PAINT:
hDC =BeginPaint(hWnd, &Ps);
// Load the bitmap from the resource
bmpPenguin =LoadBitmap(hInst,
VISUAL PROGRAMMING
NOTES
177 ANNA UNIVERSITY CHENNAI
MAKEINTRESOURCE(IDB_PENGUIN));
// Create a memory device compatible with the above DC variable
MemDCPenguin =CreateCompatibleDC(hDC);
// Select the new bitmap
SelectObject(MemDCPenguin, bmpPenguin);
// Copy the bits from the memory DC into the current dc
BitBlt(hDC, 10, 10, 450, 400, MemDCPenguin, 0, 0, SRCCOPY);
// Restore the old bitmap
DeleteDC(MemDCPenguin);
DeleteObject(bmpPenguin);
EndPaint(hWnd, &Ps);
break;
default:
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
return 0;
}
10. Test the application and youll find an output window as shown in below Figure
3.21.
Figure 3.21 Using bitmap resources
DMC 1944
NOTES
178 ANNA UNIVERSITY CHENNAI
3.12 EXERCISES:
1. Write a short note on VC++build process.
2. Discuss about the various VC++IDE components and give their significances.
3. Give the significances of Application and class wizards.
4. What is a device context?
5. Give the various steps involved in creating an application using application
wizard.
6. Write a program to create a window with a specific background color and
display a text using ARIAL font.
7. Write a program to create a single document interface and display a text in
different font sizes and colors.
8. Write a short note on Document-View architecture.
9. Differentiate between SDI and MDI type of applications.
10. Create an MDI type of application and display a text WELCOME with
different fonts and colors in the respective client windows.
11. With a suitable program explain how to use bitmaps in windows applications.
VISUAL PROGRAMMING
NOTES
179 ANNA UNIVERSITY CHENNAI
UNIT IV
CONTROLS
4.1 INTRODUCTION
This unit explores the most common types of dialog window applications: the modal
dialog and modelss dialog based applications. It also provides an overview of the various
controls and their usage in windows applications.
Almost every Windows-based program uses a dialog window to interact with the
user. The dialog might be a simple OK message box, or it might be a complex data entry
form. A dialog is truly a window that receives messages, that can be moved and closed,
and that can even accept drawing instructions in its client area.
4.2 LEARNING OBJECTIVES
1. Understand the fundamentals of Dialog based applications and program dialog
windows
2. Know the various controls and their usage in dialog based applications
3. Learn to program Modeless dialogs and the fundamentals of windows common
dialogs.
4.3 DIALOG BASED APPLICATIONS
Applications for Windows frequently communicate with the user through dialog boxes.
Class CDialog provides an interface for managing dialog boxes, the Visual C++dialog
editor makes it easy to design dialog boxes and create their dialog-template resources,
and Code wizards simplify the process of initializing and validating the controls in a dialog
box and of gathering the values entered by the user.
Dialog boxes contain controls, including:
Windows common controls such as edit boxes, pushbuttons, list boxes, combo
boxes, tree controls, list controls, and progress indicators.
ActiveX controls.
Owner-drawn controls: controls that you are responsible for drawing in the dialog
box.
DMC 1944
NOTES
180 ANNA UNIVERSITY CHENNAI
There are two kinds of dialogs: Modal and Modeless. Most dialog boxes are modal,
which require the user to close the dialog box before using any other part of the program.
But it is possible to create modeless dialog boxes, which let users work with other windows
while the dialog box is open. MFC supports both kinds of dialog box with class CDialog.
The controls are arranged and managed using a dialog-template resource, created with the
dialog editor.
Property sheets, also known as tab dialog boxes, are dialog boxes that contain pages
of distinct dialog-box controls. Each page has a file folder tab at the top. Clicking a tab
brings that page to the front of the dialog box.
You can use class CDialog to manage two kinds of dialog boxes:
Modal dialog boxes, which require the user to respond before continuing the
program
Modeless dialog boxes, which stay on the screen and are available for use at any
time but permit other user activities
The resource editing and procedures for creating a dialog template are the same for
modal and modeless dialog boxes.
4.3.1 Steps in creating a dialog box
Creating a dialog box for your program requires the following steps:
1. Use the dialog editor to design the dialog box and create its dialog-template
resource.
2. Create a dialog class.
3. Connect the dialog resources controls to message handlers in the dialog class.
4. Add data members associated with the dialog boxs controls and to specify dialog
data exchange and dialog data validations for the controls.
During the life cycle of a di alog box, the user invokes the dialog box, typically inside
a command handler that creates and initializes the dialog object, the user interacts with the
dialog box, and the dialog box closes.
For modal dialog boxes, your handler gathers any data the user entered once the
dialog box closes. Since the dialog object exists after its dialog window has closed, you
can simply use the member variables of your dialog class to extract the data.
For modeless dialog boxes, you may often extract data from the dialog object while
the dialog box is still visible. At some point, the dialog object is destroyed; when this
happens depends on your code.
VISUAL PROGRAMMING
NOTES
181 ANNA UNIVERSITY CHENNAI
4.3.2 Modal dialog
With a modal dialog, such as the Open File dialog, the user cannot work elsewhere in
the same application (more correctly, in the same user interface thread) until the dialog is
closed. Lets examine the program 4.1 and understand the steps involved in creating a
modal dialog.
Program 4.1: Program to create a new Dialog based Project
1. To create a new project, start by clicking on File in the menu of the Visual C++6
window then on New.
2. Write Dialog1 in the project name and choose an MFC AppWizard (exe) from
the list of the available Wizards, then click OK. The MFC Application Wizard will
start.
3. In Step 1 of the Wizard, click on Dialog based option, then click Next.
4. In Steps 2 and 3 accept the default settings, just click Next to do this.
5. In Step 4 click Finish, then you will get the project information. Click OK.
Now the Wizard has created for you a simple empty Dialog Based application as
shown in figure 4.1. You will need to make few changes and write the necessary
code for your application to customise it to your specifications.
6. Designing the Dialog: Click on the text TODO : Place dialog controls here,
then press Delete. This will remove the unwanted text label.
Figure 4.1 An empty dialog window during design phase
7. Click on bottom right edge of the dialog box. A rectangle appears around the
edges of the box itself. Resize the dialog box using the sizing points as shown
below.
DMC 1944
NOTES
182 ANNA UNIVERSITY CHENNAI
8. Click on the sizing point on the bottom-right corner, keeping the mouse button
pressed. Move the mouse, keeping the button pressed. An outline of the new
dialog box size is shown as the mouse is moved. Release the mouse button when
the dialog box size is 230 x 126.
9. Click on the Cancel button and press Delete to remove the Cancel button, then
right click the mouse on the OK button and a context menu will appear as shown
in figure 4.2.
10. Select Properties from the context menu.
11. The Push Button Properties dialog box appears. Select the General tab; then
in Caption box replace the word OK with Close as shown in figure
Figure 4.2 Context menu
Figure 4.3 Push button properties
12. On the controls toolbar, select the static text control. Click the dialog box near the
upper left corner. A static text control appears on the dialog box, with the default
text Static.
VISUAL PROGRAMMING
NOTES
183 ANNA UNIVERSITY CHENNAI
13. Static text controls can be used to display some information (we going to use few
of them as labels). You need three static text controls. Therefore, you need to
repeat the process of dropping static text control on to the dialog box make sure
to drop each control next to each other.
14. On the controls toolbar, select the edit control and as you did before with text
control. Drop two edit controls. Select Combo Box from the controls toolbar and
drop it into the dialog box. Then select List Box control and drop it to the dialog
box. Select button control from the controls toolbar and drop it into the dialog
box.
15. Change the Caption of the new button to Add and its ID to IDC_ADD, then
arrange the controls on the dialog box as show below. Right click static text control
and change its properties change Caption to Title as shown in figure 4.4.
Figure 4.4 Text Properties
16. Change the Caption for each static text control as shown in figure 4.5. Change the
ID in Edit Properties for first Edit Box control to IDC_FIRSTNAME and the
second edit control to IDC_LASTNAME.
Figure 4.5 Changing the Caption for each static text control
DMC 1944
NOTES
184 ANNA UNIVERSITY CHENNAI
17. Change the ID in List Box Properties to IDC_NAMELIST and the ID Combo
Box Properties to IDC_TITLE.
18. Click on Data in Combo Box Properties and populate the Data as shown in figure
4.6. After each entry is added in the list remember to press Ctrl + Enter to go to
a new line.
Figure 4.6 Combo Box Properties
19. On the Styles tab, change the Combo Boxs Type to Drop List. Position your
mouse over the Combo Box dropdown button then left-click. Another rectangle
will appear (see figure 4.7) that allows you to specify the size of the open Combo
Boxs List.
Figure 4.7 Dialog box in between the design
20. Assigning Member variables to Controls: Press Ctrl + W to start
ClassWizard, or from the View menu select ClassWizard. The MFC ClassWizard
dialog box appears as shown below. Select the Member Variables tab, then
select the dialog class in the Class name : combo box; use CDialog1Dlg. Select
IDC_FIRSTNAME, click Add Variable button. The dialog box appears (see
figure 4.8). Select Value from Category and select CString from Member
variable type.
21. Type m_strFirstName for Member variable name.
22. Repeat the same process to add CString member variable m_strLastName for
IDC_LASTNAME, and m_strTitle for IDC_TITLE.
VISUAL PROGRAMMING
NOTES
185 ANNA UNIVERSITY CHENNAI
Figure 4.8 Adding member variables using class wizard
23. For IDC_NAMELIST add a Member variable of Category Control and Variable
Type CListBox as shown in figure 4.9. Select the ClassView tab from the project
workspace pane. The class list will appear as shown below. Right click
CDialog1Dlg class and select add member variable. The Add Member Variable
dialog box will appear. Type CString in the variable and m_strFullName in
Variable Name.
Figure 4.9 Add Member variable dialog window
24. Adding message handlers for the controls: Press Ctrl + W to start the
ClassWizard, or right click the Add button and select ClassWizard from the
context menu. Open ClassWizard, select Message Maps tab. In Class name
select CDialog1Dlg, on Object IDs select IDC_ADD , then choose
BN_CLICKED from the Messages list as shown in figure 4.10.
25. Click on Add Function. Click OK, then click Edit Code. The ClassWizard will
write a new empty function called Add() with the proper prototype in the class
header.
DMC 1944
NOTES
186 ANNA UNIVERSITY CHENNAI
Figure 4.10 Using class wizard to add message handlers
26. Add the code in bold - just below //TODO: Add your control notification handler
code here:
void CDialog1Dlg::OnAdd()
{
// TODO: Add your control notification handler code here
CString strTitle ;
int nIndex;
UpdateData(); // Transfer data from controls to variables
//get currently selected text
nIndex =GetDlgItemText(IDC_TITLE, strTitle); //assigning selected
m_strFullName =strTitle + +m_strFirstName + +m_strLastName;
m_NameList.AddString(m_strFullName); //Add string to list
UpdateData(FALSE); // Transfer data from variables to controls
}
27. Building and running the program: Click on the Title Combo Box and choose
a Title. Write your first name in first name edit box and last name in last name edit
box then click Add. If everything goes as planned, then you will get your full name
and correct title in the list box as shown in figure 4.11.
VISUAL PROGRAMMING
NOTES
187 ANNA UNIVERSITY CHENNAI
Figure 4.11 Dialog window during execution
4.4 CONTROLS
A dialog contains a number of elements called controls. Dialog controls include edit
controls (also known as text boxes), buttons, list boxes, combo boxes, static text (aka
labels), tree views, progress indicators, sliders, and so forth. Windows manages these
controls using special grouping and tabbing logic, and that relieves you of a major
programming burden. The dialog controls can be referenced either by a CWnd pointer
(because they are really windows) or by an index number (with an associated #define
constant) assigned in the resource. A control sends a message to its parent dialog in response
to a user action such as typing text or clicking a button.
The Microsoft Foundation Class (MFC) Library and ClassWizard work together to
enhance the dialog logic that Windows provides. ClassWizard generates a class derived
from CDialog and then lets you associate dialog class data members with dialog controls.
You can specify editing parameters such as maximum text length and numeric high and low
limits. ClassWizard generates statements that call the MFC data exchange and data validation
functions to move information back and forth between the screen and the data members.
Use the control palette to add each control. (If the control palette is not visible, right-
click any toolbar and choose Controls from the list.) Drag controls from the control
palette to the new dialog, and then position and size the controls. The control palette in
VC++environment is shown in Figure 4.12.
Figure 4.12 Control palette and standard controls
DMC 1944
NOTES
188 ANNA UNIVERSITY CHENNAI
The following subsection gives the readers a detailed perspective of various controls
that are most commonly used in windows applications.
4.4.1 Animate control
The Animation control allows you to create buttons which display animations, such
as .avi files, when clicked. The control can play only AVI files that have no sound. In
addition, the Animation control can display only uncompressed .avi files or .avi files that
have been compressed using Run-Length Encoding (RLE). Animate control
The animator control is based on the CAnimatorCtrl class. Therefore, if you want to
programmatically create an animation, you must first declare a variable of type, or a pointer
to, CAnimationCtrl. You can do this in the source code of the dialog class. After declaring
the variable or pointer, to initialize the object, call its Create() member function. Here is an
example:
class CControlsDlg : public CDialog
{
// Construction
public:
CControlsDlg(CWnd* pParent =NULL); // standard constructor
~CControlsDlg();
. . .
private:
CAnimateCtrl *Player;
};
CControlsDlg::CControlsDlg(CWnd* pParent /*=NULL*/)
: CDialog(CControlsDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CControlsDlg)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
Player =new CAnimateCtrl;
}
CControlsDlg::~CControlsDlg()
{
delete Player;
}
. . .
VISUAL PROGRAMMING
NOTES
189 ANNA UNIVERSITY CHENNAI
BOOL CControlsDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// TODO: Add extra initialization here
RECT Recto ={ 5, 5, 360, 360 };
Player->Create(WS_CHILD | WS_VISIBLE,
Recto, this, 0x1884);
return TRUE; // return TRUE unless you set the focus to a
control
// EXCEPTION: OCX Property Pages should return FALSE
}
4.4.1.1 Opening an Animate control
After creating the control, you must provide a video to play. This is done by opening
a video file using the CAnimateCtrl::Open() member function. It is overloaded with two
versions as follows:
BOOL Open(LPCTSTR lpszFileName);
BOOL Open(UINT nID);
The first version expects the path of the video file. Alternatively, you can first add the
file as a resource to your project and use its identifier as argument to the second version.
Here is an example:
BOOL CControlsDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// TODO: Add extra initialization here
RECT Recto ={ 5, 5, 360, 360 };
Player->Create(WS_CHILD | WS_VISIBLE | ACS_TRANSPARENT,
Recto, this, 0x1884);
Player->Open(res\\clock.AVI);
return TRUE; // return TRUE unless you set the focus to a
control
// EXCEPTION: OCX Property Pages should return FALSE
}
DMC 1944
NOTES
190 ANNA UNIVERSITY CHENNAI
4.4.1.2 Playing an animation
To play the animation, you can call the CAnimateCtrl::Play() member function. Its
syntax is:
BOOL Play(UINT nFrom, UINT nTo, UINT nRep);
The nFrom argument specifies the index number of the first frame to play. The
frames are stored as a zero-based array. The first frame is 0, the second is 1, etc
The nTo argument is the last frame to play from the list of frames. If you want to
play the video to the end, pass this argument with a value of -1
The nRep is the number of times the video should be played before stopping. If
you want the video to play until you explicitly decide to stop it, pass this argument
as -1
4.4.1.3 Seek
Suppose you have a long video or one made of various special pictures, if you want
to display just one particular frame of the video, you can call the CAnimateCtrl::Seek()
member function whose syntax is:
BOOL Seek(UINT nTo);
This member function allows the animation to just straight to the nTo frame number.
4.4.1.4 Stop
At any time, you can stop the video playing by calling the C Animate Ctrl::Stop()
member function. Its syntax is:
BOOL Stop();
This member function simply stops the animation.
4.4.1.5 Close
Furthermore, when it comes to the Animator control, after using it, to free the memory
space it space, you should call the CAnimateCtrl::Close() member function. Its syntax
is:
BOOL Close();
4.4.2 Image List Control
An image list is a collection of same-sized images, each of which can be referred to
by its zero-based index. Image lists are used to efficiently manage large sets of icons or
bitmaps. All images in an image list are contained in a single, wide bitmap in screen device
format. An image list may also include a monochrome bitmap that contains masks used to
VISUAL PROGRAMMING
NOTES
191 ANNA UNIVERSITY CHENNAI
draw images transparently (icon style). The Microsoft Win32 application programming
interface (API) provides image list functions that enable you to draw images, create and
destroy image lists, add and remove images, replace images, merge images, and drag
images.
This control (and therefore the CImageList class) is available only to programs
running under Windows 95/98 and Windows NT version 3.51 and later.
Image lists are not themselves controls since they are not windows; however, they are
used with several different types of controls, including list controls (CListCtrl), tree controls
(CTreeCtrl), and tab controls (CTabCtrl).
All images in an image list are contained in a single, wide bitmap in screen-device
format. An image list may also include a monochrome bitmap that contains masks used to
draw images transparently (icon style). CImageList provides member functions that enable
you to draw images, create and destroy image lists, add and remove images, replace
images, merge images, and drag images.
4.4.2.1 Types of Image list
There are two types of image lists (CImageList): nonmasked and masked. A
nonmasked image list consists of a color bitmap that contains one or more images. A
masked image list consists of two bitmaps of equal size. The first is a color bitmap that
contains the images, and the second is a monochrome bitmap that contains a series of
masks one for each image in the first bitmap.
4.4.2.2 Creating an image list
Construct a CImageList object and call one of the overloads of its Create function
to create an image list and attach it to the CImageList object.
You construct a CImageList in two steps. First, call the constructor and then call
Create, which creates the image list and attaches it to the CImageList object. The Create
function syntax is:
BOOL Create(int cx,int cy,UINT nFlags,int nInitial,int nGrow);
Where, cx - dimensions of each image, in pixels, cy - dimensions of each image, in
pixels, nFlags - specifies the type of image list to create, nInitial - number of images that
the image list initially contains, nGrow - number of images by which the image list can grow
when the system needs to resize the list to make room for new images. This parameter
represents the number of new images the resized image list can contain.
Example:
// The pointer to my image list.
extern CImageList* pmyImageList;
pmyImageList->Create(32, 32, ILC_COLOR8, 0, 4);
DMC 1944
NOTES
192 ANNA UNIVERSITY CHENNAI
4.4.2.3 Adding images to an image list
Add images to the image list by calling the Add or Read member function. The syntax
is:
int Add(
CBitmap* pbmImage,
COLORREF crMask
);
where, pbmImage - pointer to the bitmap containing the image or images, crMask -
color used to generate the mask. Each pixel of this color in the given bitmap is changed to
black and the corresponding bit in the mask is set to one.
Example:
// The pointer to my image list.
extern CImageList* pmyImageList;
// Add my icons.
pmyImageList->Add(AfxGetApp()->LoadIcon(IDI_ICON1));
pmyImageList->Add(AfxGetApp()->LoadIcon(IDI_ICON2));
// Add my bitmap, make all black pixels transparent.
CBitmap bm;
bm.LoadBitmap(IDB_BITMAP1);
pmyImageList->Add(&bm, RGB(0, 0, 0));
4.4.2.4 Draw member function
Associate the image list with a control by calling the appropriate member function of
that control, or draw images from the image list yourself using the image lists Draw member
function. The syntax is:
BOOL Draw(CDC* pDC, int nImage, POINT pt, UINT nStyle);
Where, pDC - Pointer to the destination device context, nImage - Zero-based index
of the image to draw, pt - Location at which to draw within the specified device context,
nStyle - Flag specifying the drawing style.
Example:
// The pointer to my image list.
extern CImageList* pmyImageList;
// The position of where to draw the image.
VISUAL PROGRAMMING
NOTES
193 ANNA UNIVERSITY CHENNAI
extern CPoint myPoint;
// The DC to draw the image on.
extern CDC* pmyDC;
// Add a new image to the image list.
int nIndex =pmyImageList->Add(AfxGetApp()-
>LoadStandardIcon(IDI_QUESTION));
if (nIndex !=-1)
{
// Make the new image an overlay image.
pmyImageList->SetOverlayImage(nIndex, 1);
// Draw the first image in the image list with an overlay image.
pmyImageList->Draw(pmyDC,0,myPoint,
INDEXTOOVERLAYMASK(1));
}
4.4.3 CRECTTRACKER CONTROL
Allows an item to be displayed, moved, and resized in different fashions. The associated
class is CRectTracker. CRectTracker does not have a base class.
Although the CRectTracker class is designed to allow the user to interact with OLE
items by using a graphical interface, its use is not restricted to OLE-enabled applications.
It can be used anywhere such a user interface is required.
CRectTracker borders can be solid or dotted lines. The item can be given a hatched
border or overlaid with a hatched pattern to indicate different states of the item. You can
place eight resize handles on either the outside or the inside border of the item. (For an
explanation of the resize handles, see GetHandleMask.) Finally, a CRectTrackerallows
you to change the orientation of an item during resizing.
To use CRectTracker, construct a CRectTracker object and specify which display
states are initialized. You can then use this interface to give the user visual feedback on the
current status of the OLE item associated with theCRectTracker object.
4.4.3.1 CRectTracker Members
m_nHandleSizeDetermines size of resize handles.
m_nStyle Current style(s) of the tracker.
m_rect Current position (in pixels) of the rectangle.
m_sizeMin Determines minimum rectangle width and height.
DMC 1944
NOTES
194 ANNA UNIVERSITY CHENNAI
4.4.3.2 Constructing a CRectTracker object
CRectTracker Constructs a CRectTracker object.
4.4.3.3 Operations on CRectTracker object
Draw Renders the rectangle.
GetTrueRect Returns width and height of rectangle, including resize
handles.
HitTest Returns the current position of the cursor related to the
CRectTracker object.
NormalizeHit Normalizes a hit-test code.
SetCursor Sets the cursor, depending on its position over the rectangle.
Track Allows the user to manipulate the rectangle.
TrackRubberBand Allows the user to rubber-band the selection.
4.4.3.4 Overridables
AdjustRect Called when the rectangle is resized.
DrawTrackerRect Called when drawing the border of a CRectTracker object.
GetHandleMask Called to get the mask of a CRectTracker items resize handles.
OnChangedRect Called when the rectangle has been resized or moved.
4.4.4 Tree Control
A tree control is an object that displays a hierarchical list of items arranged as a
physical tree but a little upside down. The items display in a parent-child format to show
those that belong to interrelated categories, such as parent to child and child to grandchild,
etc; or folder to subfolder to file.
The starting item of the tree is sometimes called the root and represents the beginning
of the tree. While most tree list have one root, it is not unusual to have a tree list that has
many roots, as long as the tree creator judges it necessary. Here is an example given in
figure 4.13:
Figure 4.13 Tree Control
Each item, including the root, that belongs to the tree is referred to as a node. An item
that belongs to, or depends on, another can also be called a leaf.
VISUAL PROGRAMMING
NOTES
195 ANNA UNIVERSITY CHENNAI
The concept of a tree list is implemented in the MFC library by the CTreeCtrl class.
Use CTreeCtrl when you need a plain child window control; for instance, in a dialog
box. Youd especially want to use CTreeCtrl if there will be other child controls in the
window, as in a typical dialog box.
Use CTreeView when you want the tree control to act like a view window in document/
view architecture as well as a tree control. A CTreeView will occupy the entire client area
of a frame window or splitter window. It will be automatically resized when its parent
window is resized, and it can process command messages from menus, accelerator keys,
and toolbars. Since a tree control contains the data necessary to display the tree, the
corresponding document object does not have to be complicated you could even use
CDocument as the document type in your document template.
4.4.4.1 Creating a Tree control
The control is created. If the control is specified in a dialog box template or if youre
using CTreeView, creation is automatic when the dialog box or view is created. If you
want to create the tree control as a child window of some other window, use the Create
member function, whose syntax is as given below. The function returns Nonzero if
initialization was successful; otherwise 0.
virtual BOOL Create(
DWORD dwStyle,
const RECT& rect,
CWnd* pParentWnd,
UINT nID
);
where,
dwStyle - Specifies the tree view controls style. Apply window styles
rect - Specifies the tree view controls size and position. It can be
either a CRect object or a RECT structure
pParentWnd - Specifies the tree view controls parent window, usually a
CDialog. It must not be NULL
nID - Specifies the tree view controls ID.
If you want to create the tree control as a child window of some other window, use
the Create member function. If you create the tree control using Create, you must pass it
WS_VISIBLE, in addition to other tree view styles.
DMC 1944
NOTES
196 ANNA UNIVERSITY CHENNAI
You construct a CTreeCtrl in two steps. First call the constructor, then call Create,
which creates the tree view control and attaches it to the CTreeCtrl object. To create a
tree control with extended window styles, call CreateEx instead of Create.
Example:
// Assuming your window has a CTreeCtrl member named m_TreeCtrl,
// you can create the tree control window with a child ID of
// 0x1005 using a call like this:
m_TreeCtrl->Create(WS_VISIBLE | WS_TABSTOP | WS_CHILD |
WS_BORDER | TVS_HASBUTTONS | TVS_LINESATROOT |
TVS_HASLINES | TVS_DISABLEDRAGDROP,
CRect(10, 10, 300, 100), this, 0x1005);
// The control will have the appropiate window styles, and the
// tree control styles specified are those most commonly used.
4.4.4.2 Set an image list
If you want your tree control to use images, set an image list by calling SetImageList.
Call this function to set the normal or state image list for a tree view control and redraw the
control using the new images. The syntax is:
CImageList* SetImageList(
CImageList * pImageList,
int nImageListType
);
where,
pImageList - Pointer to the image list to assign. If pImageList is
NULL, all images are removed from the tree view
control.
nImageListType - Type of image list to set. The image list can be one of the
following values:
TVSIL_NORMAL Sets the normal image list, which contains the selected and
nonselected images for the tree view item.
TVSIL_STATE Sets the state image list, which contains the images for tree
view items that are in a user-defined state.
The SetImageList function returns apointer to the previous image list, if any; otherwise
NULL.
You can also change the indentation by calling SetIndent. A good place to do this is
in OnInitDialog (for controls in dialog boxes) or OnInitialUpdate (for views).
VISUAL PROGRAMMING
NOTES
197 ANNA UNIVERSITY CHENNAI
4.4.4.3 Insert into image list
Put data into the control by calling the CTreeCtrls InsertItem function once for
each data item. InsertItem returns a handle to the item you can use to refer to it later, such
as when adding child items. A good time to initialize the data is in OnInitDialog (for
controls in dialog boxes) or OnInitialUpdate (for views).
The syntax for InsertItem function is:
HTREEITEM InsertItem(
LPCTSTR lpszItem,
HTREEITEM hParent =TVI_ROOT,
HTREEITEM hInsertAfter =TVI_LAST
);
where,
lpszItem - Address of a string containing the items text.
hParent - Handle of the inserted items parent.
hInsertAfter - Handle of the item after which the new item is to be inserted.
Example:
// Gain a pointer to our tree control
CTreeCtrl* pCtrl =(CTreeCtrl*) GetDlgItem(IDC_TREE1);
ASSERT(pCtrl !=NULL);
// Insert a root item using the structure. We must
// initialize a TVINSERTSTRUCT structure and pass its
// address to the call.
TVINSERTSTRUCT tvInsert;
tvInsert.hParent =NULL;
tvInsert.hInsertAfter =NULL;
tvInsert.item.mask =TVIF_TEXT;
tvInsert.item.pszText =_T(INDIA);
HTREEITEM hCountry =pCtrl->InsertItem(&tvInsert);
// Insert subitems of that root. TamilNadu is a state in India, // so its item will be a child of the India
item
HTREEITEM hTN =pCtrl->InsertItem(TVIF_TEXT,
_T(Tamilnadu), 0, 0, 0, 0, 0, hCountry, NULL);
DMC 1944
NOTES
198 ANNA UNIVERSITY CHENNAI
// Insert the Kerala item and assure that it is
// inserted after the Tamilnadu item. This override is
// more appropriate for conveniently inserting items with
// images.
HTREEITEM hKE =pCtrl->InsertItem(_T(Kerala),
0, 0, hCountry, hTN);
// Well add some cities under each of the states.
// The override used here is most appropriate
// for inserting text-only items.
pCtrl->InsertItem(_T(Chennai), hTN, TVI_SORT);
pCtrl->InsertItem(_T(Trichy), hTN, TVI_SORT);
pCtrl->InsertItem(_T(Trivandrum), hKE, TVI_SORT);
pCtrl->InsertItem(_T(Cochin), hKE, TVI_SORT);
There are various Set member functions to set values for the control and Get functions
to examine the contents of the control. You can also traverse the contents of the tree
control with functions that allow you to retrieve handles to parents, children, and siblings of
a specified item. You can even sort the children of a particular node.
When youre done with the control, make sure its properly destroyed. If the tree
control is in a dialog box or if its a view, it and the CTreeCtrl object will be destroyed
automatically. If not, you need to ensure that both the control and the CTreeCtrl object
are properly destroyed.
4.4.5 CtabControl
A tab control is analogous to the dividers in a notebook or the labels in a file cabinet.
By using a tab control, an application can define multiple pages for the same area of a
window or dialog box. Each page consists of a set of information or a group of controls
that the application displays when the user selects the corresponding tab. A special type of
tab control displays tabs that look like buttons. Clicking a button should immediately perform
a command instead of displaying a page.
This control is associated with a base class CTabCtrl and is available only to programs
running under Windows 95/98 and Windows NT version 3.51 and later.
The following screen shot in figure 4.14 shows a simple tab control that contains three
tabs. The first tab (named Tab One) has been selected.
VISUAL PROGRAMMING
NOTES
199 ANNA UNIVERSITY CHENNAI
Figure 4.14 Tab Control
4.4.5.1 Creating Tab Controls
You can create a tab control by calling the CreateWindow function, specifying the
WC_TABCONTROL window class. This window class is registered when the common
controls DLL is loaded. To ensure that the DLL is loaded, use the InitCommonControls
function. In Microsoft Visual Studio, you can create a tab control by using the Toolbox.
You send messages to a tab control to add tabs and otherwise affect the controls
appearance and behavior. Each message has a corresponding macro that you can use
instead of sending the message explicitly. You cannot disable an individual tab in a tab
control. However, you can disable a tab control in a property sheet by disabling the
corresponding page.
4.4.5.2 Tab Control Styles
You can apply certain characteristics to tab controls by specifying tab control styles
when the control is created. For example, you can specify the alignment and general
appearance of the tabs in a tab control. Few tab control styles and their usage are given
below:
TCS_BUTTONS - Tabs look like buttons
TCS_FOCUSONBUTTONDOWN - Tab receives the input focus
when clicked. This style is typically
used only with the TCS_BUTTONS
style.
TCS_FOCUSNEVER - Tab does not receive input focus
when clicked
TCS_MULTILINE - Causes a tab control to display
multiple rows of tabs
DMC 1944
NOTES
200 ANNA UNIVERSITY CHENNAI
4.4.5.3 Tabs and Tab Attributes
Each tab in a tab control consists of an icon, a label, and application-defined data.
This information is specified by a TCITEM structure. You can add tabs to a tab control,
retrieve the number of tabs, retrieve and set the contents of a tab, and delete tabs. Tabs are
identified by their zero-based index.
To add tabs to a tab control, use the TCM_INSERTITEM message, specifying the
position of the item and the address of a TCITEM structure. You can retrieve and set the
contents of an existing tab by using the TCM_GETITEM and TCM_SETITEM
messages. For each tab, you can specify an icon, a label, or both. You can also specify
application-defined data to associate with the tab.
You can retrieve the current number of tabs by using the TCM_GETITEMCOUNT
message delete a tab by using the TCM_DELETEITEM message, and delete all tabs in
a tab control by using the TCM_DELETEALLITEMS message.
4.4.5.4 Tab Size and Position
Each tab in a tab control has a size and position. You can set the size of tabs, retrieve
the bounding rectangle of a tab, or determine which tab is at a specified position.
For fixed-width and owner-drawn tab controls, you can set the exact width and
height of tabs by using the TCM_SETITEMSIZE message. You can set the thickness of
the margin by using the TCM_SETPADDING message.
In a tab control with the TCS_MULTILINE style, you can determine the current
number of rows of tabs by using the TCM_GETROWCOUNT message.
4.5 DYNAMIC CONTROLS
The Windows Common Controls are the new Windows controls, introduced for
Microsoft Windows 95 and available in Microsoft Windows NT. These include the progress
indicator, trackbar, spin button control, list control, and tree control as shown in Figure
4.15.
The Progress Indicator Control (CProgressCtrl) - is the easiest common control
to program and is generally used only for output.
Figure 4.15 Windows Common Controls
VISUAL PROGRAMMING
NOTES
201 ANNA UNIVERSITY CHENNAI
The Trackbar Control (CSliderCtrl) - sometimes called a slider, allows the user to
set an analog value. If you specify a large range for this control0 to 100 or more, for
examplethe trackbars motion appears continuous. If you specify a small range, such as
0 to 5, the tracker moves in discrete increments. You can program tick marks to match the
increments. In this discrete mode, you can use a trackbar to set such items as the display
screen resolution, lens f-stop values, and so forth. The trackbar does not have a default
range.
The Spin Button Control (CSpinButtonCtrl) - is often used in conjunction with an
edit control. The edit control, located just ahead of the spin control in the dialogs tabbing
order, is known as the spin controls buddy. The idea is that the user holds down the left
mouse button on the spin control to raise or lower the value in the edit control. The spin
speed accelerates as the user continues to hold down the mouse button.
The List Control (CListCtrl) - used to display a list that contains images as well as
text. The elements are arranged in a grid, and the control includes horizontal scrolling.
When the user selects an item, the control sends a notification message, which you map in
your dialog class. That message handler can determine which item the user selected. Items
are identified by a zero-based integer index.
The Tree Control (CTreeCtrl) - Youre already familiar with tree controls if youve
used Microsoft Windows Explorer or Visual C++s Workspace view. The user can expand
and collapse elements by clicking the +and - buttons or by double-clicking the elements.
The icon next to each item is programmed to change when the user selects the item with a
single click.
The code for these controls is in the Windows COMCTL32.DLL file. This code
includes the window procedure for each control, together with code that registers a window
class for each control. The registration code is called when the DLL is loaded. When your
program initializes a dialog, it uses the symbolic class name in the dialog resource to connect
to the window procedure in the DLL. Thus your program owns the controls window, but
the code is in the DLL. Except for ActiveX controls, most controls work this way.
4.5.1 Slider control (The Trackbar Control)
The trackbar control (class CSliderCtrl), sometimes called a slider, allows the user to
set an analog value. If you specify a large range for this control0 to 100 or more, for
examplethe trackbars motion appears continuous. If you specify a small range, such as
0 to 5, the tracker moves in discrete increments. You can program tick marks to match the
increments. In this discrete mode, you can use a trackbar to set such items as the display
screen resolution, lens f-stop values, and so forth. The trackbar does not have a default
range.
DMC 1944
NOTES
202 ANNA UNIVERSITY CHENNAI
The trackbar is easier to program than the scroll bar because you dont have to map
the WM_HSCROLL or WM_VSCROLL messages in the dialog class. As long as you
set the range, the tracker moves when the user slides it or clicks in the body of the trackbar.
You might choose to map the scroll messages anyway if you want to show the position
value in another control. The GetPos member function returns the current position value.
4.5.1.2 Creating a Slider
To provide a slider to an application, from the Toolbox, click the Slider Control
button and click the desired area on the dialog box or the form.
To programmatically create a slider, declare a pointer to CSliderCtrl using the new
operator. To initialize the control, call its Create() member function. Here is an example:
BOOL CDlgSlide::OnInitDialog()
{
CDialog::OnInitDialog();
// TODO: Add extra initialization here
CSliderCtrl *TrackBar =new CSliderCtrl;
TrackBar->Create(WS_CHILD | WS_VISIBLE, CRect(20, 20, 60, 280),
this, IDC_SLIDER_CONTROL);
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
4.5.2 Progress Indicator control
The progress indicator is the easiest common control to program and is represented
by the MFC CProgressCtrl class. It is generally used only for output. This control, together
with the trackbar, can effectively replace the scroll bar controls you saw in the previous
example. To initialize the progress indicator, call the SetRange and SetPos member functions
in your OnInitDialog function, and then call SetPos anytime in your message handlers. The
progress indicator has a range of 0 to 100, which is the default range.
To program the progress control add a public integer data member named
m_nProgress in the Dialog class header, and set it to 0 in the constructor. Also, add the
following code in the OnInitDialog member function:
CProgressCtrl* pProg =
(CProgressCtrl*) GetDlgItem(IDC_PROGRESS1);
pProg->SetRange(0, 100);
pProg->SetPos(m_nProgress);
Now lets take a look at programs which uses progress bar and slider control.
VISUAL PROGRAMMING
NOTES
203 ANNA UNIVERSITY CHENNAI
Program 4.2: Creating an equalizer with Progress bar controls.
1. Start Microsoft Visual C++and create a new MFC AppWizard (exe) application
named Equalizer.
2. Create the project as a Dialog Based and set the Dialog Title as Sound Equalizer
without the About Box
3. Delete the TODO line and move the buttons to the bottom section of the dialog.
4. Right-click anywhere on the dialog box and click Insert ActiveX Control.
5. In the ActiveX Control list of the Insert ActiveX Control dialog box, click Microsoft
ProgressBar Control, version 6.0 as shown in Figure 4.16.
Figure 4.16 Insert ActiveX Control dialog box
6. Click OK.
7. Right-click the newly added control and click Properties. In the Properties window,
click the Control tab and change the Orientation property to 1
ccOrientationVertical.
8. On the dialog box, right-click the ProgressBar and click Copy. Right-click anywhere
on the dialog box and click Paste many times until you get 10 ProgressBar controls.
9. Design the dialog box as shown in Figure 4.17 (only the top labels and the
ProgressBar controls need IDs):
Figure 4.17 Dialog Design for Sound Equalizer
DMC 1944
NOTES
204 ANNA UNIVERSITY CHENNAI
10. Press Ctrl +W to access the ClassWizard. Add a CString Value Variable for
each label that has an ID and Add a CProgressBar Control Variable for each
ProgressBar control as follows:
11. Click OK
12. Using the Resource Symbols dialog box, add four new identifiers as
IDT_TWOFIVE, IDT_FIVE, IDT_ONE, and IDT_TEN as shown in Figure
4.18.
Figure 4.18 Resource Symbols Dialog Box
13. Click Close.
14. In the OnInitDialog( ) event of the dialog class, create the following timers and
generate a random seed:
BOOL CEqualizerDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Set the icon for this dialog. The framework does this automatically
// when the applications main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
SetTimer(IDT_TWO, 650, NULL);
Control ID Caption Additional Properties
Static Text

IDC_VAL_250 000 Align Text: Center
Static Text

IDC_VAL_500 000 Align Text: Center
Static Text

IDC_VAL_1 000 Align Text: Center
Static Text

IDC_VAL_10 000 Align Text: Center
ProgressBar IDC_PRGR_250 000 Align Text: Center
ProgressBar IDC_PRGR_500
ProgressBar IDC_PRGR_1
ProgressBar IDC_PRGR_10
Identifier Value Variable Control Variable
IDC_VAL_250 m_ValTwo
IDC_VAL_500 m_ValFive
IDC_VAL_1 m_ValOne
IDC_VAL_10 m_ValTen
IDC_PRGR_250 m_two
IDC_PRGR_500 m_five
IDC_PRGR_1 m_one
IDC_PRGR_10 m_ten
VISUAL PROGRAMMING
NOTES
205 ANNA UNIVERSITY CHENNAI
SetTimer(IDT_FIVE, 200, NULL);
SetTimer(IDT_ONE, 450, NULL);
SetTimer(IDT_TEN, 1000, NULL);
srand(static_cast<unsigned>(time(NULL)));
return TRUE; // return TRUE unless you set the focus to a control
}
15. Save All.
16. Generate a WM_TIMER message for the dialog box and implement it as follows:
void CEqualizerDlg::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
float two =static_cast<float>(rand( ) % 100);
float five =static_cast<float>(rand( ) % 100);
float one =static_cast<float>(rand( ) % 100);
float ten =static_cast<float>(rand( ) % 100);
if( nIDEvent ==IDT_TWO )
{
m_two.put_Value(two);
// Make a sound if the value of the bass is too high
if( two >=85 )
MessageBeep(MB_ICONEXCLAMATION);
}
if( nIDEvent ==IDT_FIVE )
m_five.SetValue(five);
if( nIDEvent ==IDT_ONE )
m_one.SetValue(one);
if( nIDEvent ==IDT_TEN )
m_ten.SetValue(ten);
m_ValTwo.Format(%.f.%d, m_two.GetValue( ), rand( )%99);
m_ValFive.Format(%.f\260, m_five.GetValue( ));
m_ValOne.Format(%.f\045, m_one.GetValue( ));
m_ValTen.Format(<%.f, m_ten.GetValue( ));
UpdateData(FALSE);
CDialog::OnTimer(nIDEvent);
}
17. Test the application.
DMC 1944
NOTES
206 ANNA UNIVERSITY CHENNAI
Program 4.3: Displaying different pictures of a car using Slider Control.
1. Start a new Dialog-based application named CarInventory with no About Box
and set the Dialog Title to Car Inventory.
2. Delete the TODO line and the OK button
3. Collect ten pictures of automobiles or any ten pictures (or even ten different images
of you or your friend) available in your system and save it in your drive. For this
program the following pictures were used:
4. On the main menu, click Insert ->Resource or Project ->Add Resource
5. On the Add Resource dialog box, click Import and import the above pictures.
If you are using MSVC 6, you may receive a message box when you import each
picture, simply click OK.
6. Change the ID of the new bitmap to IDB_CIVIC, IDB_ELANTRA,
I DB_ESCAPE, I DB_ESCORT, I DB_FOCUS, I DB_MARQUI S,
IDB_MYSTIQUE, IDB_NAVIGATOR, IDB_SENTRA, and IDB_SEPHIA
respectively.
7. Add a Picture control to the top side of the dialog box and change its ID to
IDC_PREVIEW.
8. Type to Bitmap and set its Bitmap to IDB_CIVIC.
9. Add a Control variable for the picture control and name it m_Preview.
10. To store the values for the controls on the dialog box, in the header file of the
dialog box, declare a private UINT array named CarPicture[10].










VISUAL PROGRAMMING
NOTES
207 ANNA UNIVERSITY CHENNAI
11. To initialize the array, type the following in the OnInitDialog event:
BOOL CSlider1Dlg::OnInitDialog()
{
CDialog::OnInitDialog();
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
CarPicture[0] =IDB_CIVIC;
CarPicture[1] =IDB_ELANTRA;
CarPicture[2] =IDB_ESCAPE;
CarPicture[3] =IDB_ESCORT;
CarPicture[4] =IDB_MARQUIS;
CarPicture[5] =IDB_MYSTIQUE;
CarPicture[6] =IDB_NAVIGATOR;
CarPicture[7] =IDB_SENTRA;
CarPicture[8] =IDB_FOCUS;
CarPicture[9] =IDB_SEPHIA;
return TRUE; // return TRUE unless you set the focus to a control
}
12. To display default values in the dialog box, on top of its OnPaint( ) event, type the
following:
void CSlider1Dlg::OnPaint()
{
CBitmap Bmp;
Bmp.LoadBitmap(CarPicture[0]);
m_Preview.SetBitmap(Bmp);
UpdateData(FALSE);
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM)
dc.GetSafeHdc(), 0);
// Center icon in client rectangle
int cxIcon =GetSystemMetrics(SM_CXICON);
int cyIcon =GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x =(rect.Width() - cxIcon +1) / 2;
int y =(rect.Height() - cyIcon +1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
DMC 1944
NOTES
208 ANNA UNIVERSITY CHENNAI
13. Test the application and return to MSVC.
14. On the Controls toolbox, click the Slider button and click in lower-left section
of the dialog box.
15. While the slider control is selected on the dialog box, on the Properties window,
change its ID to IDC_SLIDER.
16. Check its Auto Ticks check box or set it to True.
17. Check its Tick Marks check box or set it to True.
18. Set its Point property to Top/Left. Set to True the Tooltips property of the slider
control.
19. Add a CSliderCtrl Control variable for the slider and name it m_CarSlider.
20. In the OnInitDialog event of the dialog class, set the range of values of the slider to
0 to 9 and the frequency of its ticks to:
BOOL CControlsDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// TODO: Add extra initialization here
m_CarSlider.SetRange(1, 10);
m_CarSlider.SetTicFreq(1);
return TRUE; // return TRUE unless you set the focus to a control
}
21. Save all and Test the application.
22. Change the OnPaint( ) event of the dialog class as follows:
void CCarInventoryDlg::OnPaint()
{
int CurPos =m_CarSlider.GetPos() - 1;
CBitmap Bmp;
Bmp.LoadBitmap(CarPicture[CurPos]);
m_Picture.SetBitmap(Bmp);
UpdateData(FALSE);
. . .
}
23. Using either the ClassWizard (MSVC 6) or the Messages button , for the dialog,
generate the WM_HSCROLL message and implement it as follows:
VISUAL PROGRAMMING
NOTES
209 ANNA UNIVERSITY CHENNAI
void CCarInventoryDlg::OnHScroll(UINT nSBCode, UINT nPos,
CScrollBar* pScrollBar)
{
// TODO: Add your message handler code here and/or call default
CRect RectPicture;
// Get the location and dimensions of the picture area
m_Preview.GetWindowRect(&RectPicture);
// Convert the current coordinates from
// the monitor (Screen) to the dialog box (Client)
ScreenToClient(&RectPicture);
// Repaint the picture area
InvalidateRect(&RectPicture);
CDialog::OnHScroll(nSBCode, nPos, pScrollBar);
}
24. Test the application and youll find an output similar to the one shown in Figure
4.19.
Figure 4.19 Car Inventory Application
25. Finally close your application and return to MSVC.
4.5.3 CRicheditView Control
A rich edit control is a window in which the user can enter and edit text. The text
can be assigned character and paragraph formatting, and can include embedded OLE
objects. Rich edit controls provide a programming interface for formatting text. However,
an application must implement any user interface components necessary to make formatting
operations available to the user.
Windows itself supplies two text editing tools: edit control and Windows rich edit
common control. Both can be used as controls within dialogs, but both can also be made
to look like view windows. The MFC library supports this versatility with the CEditView
and CRichEditView classes.


DMC 1944
NOTES
210 ANNA UNIVERSITY CHENNAI
4.5.3.1 The CEditView Class
This class is based on the Windows edit control, so it inherits all the edit controls
limitations. Text size is limited to 64 KB, and you cant mix fonts. AppWizard gives you the
option of making CEditView the base class of your view class. When the framework gives
you an edit view object, it has all the functionality of both CView and CEdit. Theres no
multiple inheritance here, just some magic that involves window subclassing. The CEditView
class implements and maps the clipboard cut, copy, and paste functions, so they appear
active on the Edit menu.
4.5.3.2 The CRichEditView Class
This class uses the rich edit control, so it supports mixed formats and large quantities
of text. The CRichEditView class is designed to be used with the CRichEditDoc and
CRichEditCntrItem classes to implement a complete ActiveX container application.
4.5.3.3 The CRichEditCtrl Class
This class wraps the rich edit control, and you can use it to make a fairly decent text
editor. The CRichEditCtrl class has many useful member functions, and it picks up other
functions from its CWnd base class. The functions associated with the control are given in
table 4.1:
Table 4.1 CRichEditCtrl s Member functions
Rich edit controls provide a programming interface for formatting text. However, an
application must implement any user interface components necessary to make formatting
operations available to the user. That is, the rich edit control supports changing the character
or paragraph attributes of the selected text. Some examples of character attributes are
Function Description
Create Creates the rich edit control win
the parent's WM_CREATE handl
SetWindowPos Sets the size and position of the e
the control to cover the view's clie
GetWindowText Retrieves plain text from the
functions available to retrieve th
text formatting codes)
SetWindowText Stores plain text in the control
GetModify Gets a flag that is TRUE if th
modified (text modified if the u
control or if the program calls Set
SetModify Sets the modify flag to TRUE or F
GetSel Gets a flag that indicates whet
selected text
SetDefaultCharFormat Sets the control's default format ch
SetSelectionCharFormat Sets the format characteristics of t
VISUAL PROGRAMMING
NOTES
211 ANNA UNIVERSITY CHENNAI
bold, italics, font family, and point size. Examples of paragraph attributes include alignment,
margins, and tab stops. However, it is up to you to provide the user interface, whether that
is toolbar buttons, menu items, or a format character dialog box. There are also functions
to query the rich edit control for the attributes of the current selection. Use these functions
to display the current settings for the attributes, for example, setting a check mark on the
command UI if the selection has the bold character formatting attribute.
4.6 MODELESS DIALOGS
In the Microsoft Foundation Class (MFC) Library version 6.0, modal and modeless
dialogs share the same base class, CDialog, and they both use a dialog resource that you
can build with the dialog editor.
4.6.1 Creating Modeless Dialogs
To create a modeless dialog, you start by invoking the CDialog default constructor
to construct the dialog object, but then to create the dialog window you need to call the
CDialog::Create member function instead of DoModal. Create takes the resource ID as
a parameter and returns immediately with the dialog window still on the screen. You must
worry about exactly when to construct the dialog object, when to create the dialog window,
when to destroy the dialog, and when to process user-entered data.
The differences between creating a modal dialog and a modeless dialog are as given
below:
Suppose you want the modeless dialog window to be destroyed when the user clicks
the dialogs OK button. The dialog could send the view a user-defined message as the
result of a call to the OK button message-handling function. When the view gets the message,
it can destroy the dialog window (but not the object). This sets the stage for the creation of
a new dialog.
You have two options for sending Windows messages: the CWnd::SendMessage
function or the PostMessage function. The former causes an immediate call to the message-
handling function, and the latter posts a message in the Windows message queue. Because
theres a slight delay with the PostMessage option, its reasonable to expect that the
handler function has returned by the time the view gets the message.
Now lets take a look at a sample program that explains how to work with modeless
dialogs.
Modal Dialog Mode
Constructor used Constructor with
resource ID param
Defau
(no pa
Function used to create
window
DoModal Creat
ID pa

DMC 1944
NOTES
212 ANNA UNIVERSITY CHENNAI
Program 4.4: Program that displays a modeless dialog when the user interacts with the
window.
1. Run the AppWizard and accept all the defaults but two: select Single Document
and deselect Printing And Print Preview.
2. Choose Resource from Visual C++s Insert menu, and then select Dialog. The
dialog editor assigns the ID IDD_DIALOG1 to the new dialog. Change the dialog
caption to Modeless Dialog. Accept the default OK and Cancel buttons with IDs
IDOK and IDCANCEL, and then add a static text control and an edit control
with the default ID IDC_EDIT1. Change the static text controls caption to Edit
1. The completed dialog looks as the one shown in figure 4.20.
Figure 4.20 Dialog at design time
3. Choose ClassWizard from Microsoft Visual C++s View menu. Fill in the New
Class dialog as shown in figure 4.21, and then click the OK button.
Figure 4.21 Using Class Wizard to create new Dialog Class
Add the message-handling functions, by first clicking on an object ID, then on a
message, and finally by clicking the Add Function button. The Add Member Function
dialog box appears. Edit the function name if necessary, and click the OK button.
Object ID Message Member Function
IDCANCEL BN_CLICKED OnCancel
IDOK BN_CLICKED OnOK
VISUAL PROGRAMMING
NOTES
213 ANNA UNIVERSITY CHENNAI
4. While in ClassWizard, click on the Member Variables tab, choose the IDC_EDIT1
control, and then click the Add Variable button to add the CString variable
m_strEdit1.
5. Type in the following boldface code in the CModelessDialog class declaration:
private: CView* m_pView;
Also, add the function prototypes as follows:
public:
CModelessDialog(CView* pView);
BOOL Create();
6. Edit modelessDialog.h to define the WM_BYE message ID. Add the following
line of code:
#define WM_BYE WM_USER +5
The Windows constant WM_USER is the first message ID available for user-
defined messages. The application framework uses a few of these messages, so
well skip over the first five messages.
7. Add the modeless constructor in the file modelessDialog.cpp. You could modify
the existing CModelessDialog constructor, but if you add a separate one, the
dialog class can serve for both modal and modeless dialogs. Add the lines shown
below.
CModelessDialog::CModelessDialog(CView* pView) // modeless constructor
{
m_pView =pView;
}
You should also add the following line to the AppWizard-generated modal constructor:
m_pView =NULL;
8. Add the Create function in modelessDialog.cpp. This derived dialog class Create
function calls the base class function with the dialog resource ID as a parameter.
Add the following lines:
BOOL CModelessDialog::Create()
{
return CDialog::Create(CModelessDialog::IDD);
}
DMC 1944
NOTES
214 ANNA UNIVERSITY CHENNAI
9. Edit the OnOK and OnCancel functions in modelessDialog.cpp. These virtual
functions generated by ClassWizard are called in response to dialog button clicks.
Add the following boldface code:
void CModelessDialog::OnCancel( )
{
if (m_pView != NULL) {
// modeless case do not call base class OnCancel
m_pView->PostMessage(WM_BYE, IDCANCEL);
}
else {
CDialog::OnCancel(); // modal case
}
}
void CModelessDialog::OnOK( )
{
if (m_pView != NULL) {
// modeless case do not call base class OnOK
UpdateData(TRUE);
m_pView->PostMessage(WM_BYE, IDOK);
}
else {
CDialog::OnOK(); // modal case
}
}
If the dialog is being used as a modeless dialog, it sends the user-defined message
WM_BYE to the view.
10. Edit the modelessView.h header file. You need a data member to hold the dialog
pointer:
private:
CModelessDialog* m_pDlg;
If you add the forward declaration:
class CModelessDialog;
at the beginning of modelessView.h, you wont have to include modelessDialog.h
in every module that includes modelessView.h.
VISUAL PROGRAMMING
NOTES
215 ANNA UNIVERSITY CHENNAI
11. Modify the CModelessView constructor and destructor in the file
modelessView.cpp. The CModlessView class has a data member m_pDlg that
points to the views CModelessDialog object. The view constructor constructs
the dialog object on the heap, and the view destructor deletes it. Add the following
boldface code:
CModelessView::CModelessView()
{
m_pDlg = new CModelessDialog(this);
}
CModelessView::~CModelessView()
{
delete m_pDlg; // destroys window if not already destroyed
}
12. Add code to the virtual OnDraw function in the ModelessView.cpp file.
The CModelessView OnDraw function (whose skeleton was generated by
AppWizard) should be coded as follows in order to prompt the user to press the
mouse button:
void CModelessView::OnDraw(CDC* pDC)
{
pDC->TextOut(0, 0, Press the left mouse button here.);
}
13. Use ClassWizard to add CModelessView mouse message handlers. Add handlers
for the WM_LBUTTONDOWN and WM_RBUTTONDOWN messages. Now
edit the code in file modelessView.cpp as follows:
void CModelessView::OnLButtonDown(UINT nFlags, CPoint point)
{
// creates the dialog if not created already
if (m_pDlg->GetSafeHwnd() == 0) {
m_pDlg->Create(); // displays the dialog window
}
}
void CModlessView::OnRButtonDown(UINT nFlags, CPoint point)
{
m_pDlg->DestroyWindow();
// no problem if window was already destroyed
}
DMC 1944
NOTES
216 ANNA UNIVERSITY CHENNAI
14. Add the dialog header include statement to file modelessView.cpp. While youre
in modelssView.cpp, add the following dialog header include statement after the
view header include statement:
#include modelessView.h
#include modelessDialog.h
15. Add your own message code for the WM_BYE message. Because ClassWizard
does not support user-defined messages, you must write the code yourself.
16. In modelessView.cpp, add the following line after the BEGIN_MESSAGE_MAP
statement but outside the AFX_MSG_MAP brackets:
ON_MESSAGE(WM_BYE, Onbye)
17. Also in modelessView.cpp, add the message handler function itself:
LRESULT CModelessView::Onbye(WPARAM wParam, LPARAM lParam)
{
// message received in response to modeless dialog OK
// and Cancel buttons
TRACE(CModelessView::Onbye %x, %lx\n, wParam, lParam);
TRACE(Dialog edit1 contents =%s\n,
(const char*) m_pDlg->m_strEdit1);
m_pDlg->DestroyWindow();
return 0L;
}
18. In modelessView.h, add the following function prototype before the
DECLARE_MESSAGE_MAP( ) statement but outside the AFX_ MSG brackets:
afx_msg LRESULT Onbye(WPARAM wParam, LPARAM lParam);
19. Build and run Modeless application. Press the left mouse button, and then press
the right button. (Be sure the mouse cursor is outside the dialog window when you
press the right mouse button.) Press the left mouse button again and enter some
data, and then click the dialogs OK button.
4.7 WINDOWS COMMON DIALOGS
In addition to class CDialog, MFC supplies several classes derived from CDialog
that encapsulate commonly used dialog boxes, as shown in the following table. The dialog
boxes encapsulated are called the common dialog boxes and are part of the Windows
common dialog library (COMMDLG32.DLL). The dialog-template resources and code
for these classes are provided in the Windows common dialog boxes that are part of
Windows versions 3.1 and later.
VISUAL PROGRAMMING
NOTES
217 ANNA UNIVERSITY CHENNAI
The common dialog classes are the C++programming interface to the group of
Windows utility dialogs that include File Open, Page Setup, Color, etc.
All the common dialog classes are derived from a common base class,
CCommonDialog. A list of the COMMDLG32 classes is shown in the following table.
Derived dialog class Purpose
CColorDialog Lets user select or create a color
CFileDialog Lets user select a filename to open or to save.
CFindReplaceDialog Lets user initiate a find or replace operation in a text
file.
CFontDialog Lets user specify a font.
CPrintDialog Lets user specify information for a print job.
CPrintDialogEx Windows 2000 print property sheet. Allows the user
to set up the printer and print a document
4.7.1 The File Dialog
The file dialog is one common entity which most of the applications have. The file
dialog can help the user select a file to open, by providing your program with the pathname
your program must make the call that opens the file. Similarly, a font dialog fills in a structure
that describes a font, but it doesnt create the font.
The CFileDialog class encapsulates the Windows common file dialog box. Common
file dialog boxes provide an easy way to implement File Open and File Save As dialog
boxes (as well as other file-selection dialog boxes) in a manner consistent with Windows
standards.
You can use CFileDialog as is with the constructor provided, or you can derive
your own dialog class from CFileDialog and write a constructor to suit your needs. In
either case, these dialog boxes will behave like standard Microsoft Foundation class dialog
boxes because they are derived from the CCommonDialog class.
To use a CFileDialog object, first create the object using the CFileDialog constructor.
After the dialog box has been constructed, you can set or modify any values in the m_ofn
structure to initialize the values or states of the dialog boxs controls. The m_ofn structure
is of type OPENFILENAME.
After initializing the dialog boxs controls, call the DoModal member function to
display the dialog box and allow the user to enter the path and file. DoModal returns
whether the user selected the OK (IDOK) or the Cancel (IDCANCEL) button.
If DoModal returns IDOK, you can use one of CFileDialogs public member
functions to retrieve the information input by the user.
DMC 1944
NOTES
218 ANNA UNIVERSITY CHENNAI
CFileDialog includes several protected members that enable you to do custom
handling of share violations, filename validation, and list-box change notification. These
protected members are callback functions that most applications do not need to use, since
default handling is done automatically. Message-map entries for these functions are not
necessary because they are standard virtual functions.
You can use the Windows CommDlgExtendedError function to determine whether
an error occurred during initialization of the dialog box and to learn more about the error.
The destruction of CFileDialog objects is handled automatically. It is not necessary
to call CDialog::EndDialog.
To allow the user to select multiple files, set the OFN_ALLOWMULTISELECT
flag before calling DoModal. You need to supply your own filename buffer to accommodate
the returned list of multiple filenames. Do this by replacing m_ofn.lpstrFile with a pointer
to a buffer you have allocated, after constructing the CFileDialog, but before calling
DoModal. Additionally, you must set m_ofn.nMaxFile with the number of characters in
the buffer pointed to by m_ofn.lpstrFile.
CFileDialog relies on the COMMDLG.DLL file that ships with Windows versions
3.1 and later.
If you derive a new class from CFileDialog, you can use a message map to handle
any messages. To extend the default message handling, derive a class from CWnd, add a
message map to the new class, and provide member functions for the new messages. You
do not need to provide a hook function to customize the dialog box.
To customize the dialog box, derive a class from CFileDialog, provide a custom
dialog template, and add a message map to process the notification messages from the
extended controls. Any unprocessed messages should be passed to the base class.
4.7.1.1 Using file Dialog class to open a file
Using the CFileDialog class to open a file is easy. The following code opens a file that
the user has selected through the dialog:
CFileDialog dlg(TRUE, bmp, *.bmp);
if (dlg.DoModal() ==IDOK) {
CFile file;
VERIFY(file.Open(dlg.GetPathName(), CFile::modeRead));
}
The first constructor parameter (TRUE) specifies that this object is a File Open
dialog instead of a File Save dialog. The default file extension is bmp, and *.bmp appears
first in the filename edit box. The CFileDialog::GetPathName function returns a CString
object that contains the full pathname of the selected file.
VISUAL PROGRAMMING
NOTES
219 ANNA UNIVERSITY CHENNAI
4.7.1.2 Member functions of CFileDialog class
4.7.2 The Color Dialog
A color dialog window allows you to incorporate a color-selection dialog box into
your application. The color dialog is associated with the class CColorDialog:
class CColorDialog : public CCommonDialog
A CColorDialog object is a dialog box with a list of colors that are defined for the
display system. The user can select or create a particular color from the list, which is then
reported back to the application when the dialog box exits.
To construct a CColorDialog object, use the provided constructor or derive a new class
and use your own custom constructor.
Once the dialog box has been constructed, you can set or modify any values in the
m_cc structure to initialize the values of the dialog boxs controls. The m_cc structure is of
type CHOOSECOLOR.
After initializing the dialog boxs controls, call the DoModal member function to
display the dialog box and allow the user to select a color. DoModal returns the users
selection of either the dialog boxs OK (IDOK) or Cancel (IDCANCEL) button.
If DoModal returns IDOK, you can use one of CColorDialogs member functions
to retrieve the information input by the user.
You can use the Windows CommDlgExtendedError function to determine whether an
error occurred during initialization of the dialog box and to learn more about the error.
CColorDialog relies on the COMMDLG.DLL file that ships with Windows versions
3.1 and later.
DoModal Displays the dialog box and allows the user to make a
selection.
GetFileExt Returns the file extension of the selected file.
GetFileName Returns the filename of the selected file.
GetFileTitle Returns the title of the selected file.
GetFolderPath Retrieves the path of the currently open folder or
directory for an Explorer-style Open or Save As common
dialog box.
GetNextPathName Returns the full path of the next selected file.
GetOFN Retrieves the OPENFILENAME structure of the
CFileDialog object.
GetPathName Returns the full path of the selected file.
GetReadOnlyPref Returns the read-only status of the selected file.
GetStartPosition Returns the position of the first element of the filename
list.
HideControl Hides the specified control in an Explorer-style Open or
Save As common dialog box.
DMC 1944
NOTES
220 ANNA UNIVERSITY CHENNAI
4.7.2.1 Member functions of CColorDialog class
To customize the dialog box, derive a class from CColorDialog, provide a custom
dialog template, and add a message map to process the notification messages from the
extended controls. Any unprocessed messages should be passed to the base class.
4.8 EXERCISE
1. Differentiate between Modal and modeless dialogs.
2. Explain with a suitable example how to create and use a modal dialog with your
application.
3. Write a program that uses model dialog to get user inputs in the form of string and
display them inside the client window.
4. Write a short note on various dynamic controls.
5. Discuss with a sample program how to use a modeless dialog in your application.
6. Write a short note on windows common controls.
***
VISUAL PROGRAMMING
NOTES
221 ANNA UNIVERSITY CHENNAI
UNIT V
ADVANCED CONCEPTS
5.1 INTRODUCTION
This unit introduces the readers with advanced concepts and programming. This unit
starts with a primer on the Domain Name System and the working of HyperText Transport
Protocol (HTTP). Then its time to get something running. Also this unit enables the readers
to understand and work with status bars, splitter windows and dynamic link libraries. The
unit provides an introduction to client-side database access systems: Open Database
Connectivity (ODBC) and Data Access Objects (DAO). Finally it helps the readers to
understand and program the Winsock and WinInet classes.
5.2 LEARNING OBJECTIVES
1. Learn the fundamentals to internet programming
2. Programming the status bars and splitter window
3. Learn to create DLL and embedding them to regular windows programs
4. Write C++database applications for Microsoft Windows
5. Study an HTTP client-server program based on Winsock and WinInet
6. Learn about the Microsofts ActiveX technology
5.3 THE DOMAIN NAME SYSTEM
Domain Name System (DNS) is an industry-standard protocol used to locate
computers on an IP-based network. Users can remember display names, such as
www.microsoft.com easier than number-based addresses, such as 207.46.131.137.
IP networks, such as the Internet and Windows networks, rely on number-based
addresses to transmit data throughout the network; therefore, it is necessary to translate
display names (such as www.microsoft.com) into numeric addresses that the network can
recognize (such as 207.46.131.137). DNS is the service of choice in Windows to locate
such resources and translate them into IP addresses.
DNS is the primary locator service for Active Directory, and therefore, DNS can be
considered a base service for both Windows and Active Directory. Windows provides
functions that enable application programmers to use DNS functions such as
programmatically making DNS.
DMC 1944
NOTES
222 ANNA UNIVERSITY CHENNAI
Although TCP/IP uses IP addresses to locate and connect to hosts (computers and
other TCP/IP network devices), users typically prefer to use friendly names. For example,
users prefer the friendly name ftp.reskit.com, instead of its IP address, 172.16.23.55. The
Domain Name System (DNS), defined in RFCs 1034 and 1035, is used on the Internet to
provide a standard naming convention for locating IP-based computers.
On the Internet, before the implementation of DNS, the use of names to locate
resources on TCP/IP networks was supported by a file called Hosts. Network
administrators entered names and IP addresses into Hosts, and computers used the file for
name resolution.
Both the Hosts file and DNS use a namespace. A namespace is a grouping in which
names can be used to symbolically represent another type of information, such as an IP
address, and in which specific rules are established that determine how names can be
created and used. Some namespaces, such as DNS, are hierarchically structured and
provide rules that allow for the namespace to be divided into subsets of names for distributing
and delegating parts of the namespace. Other namespaces, such as the Hosts namespace
cannot be divided and must be distributed in their entirety. Because of this, using the Hosts
file posed a problem for network administrators. As the number of computers and users
on the Internet grew, the task of updating and distributing the Hosts file became
unmanageable.
DNS replaces the Hosts file with a distributed database that implements a hierarchical
naming system. This naming system allows for growth on the Internet and the creation of
names that are unique throughout the Internet and private TCP/IP-based intranets.
5.3.1 Elements of the DNS
The DNS has three major components: 1) DOMAIN NAME SPACE and
RESOURCE RECORDS, 2) NAME SERVERS and 3) RESOLVERS. These three
components roughly correspond to the three layers or views of the domain system.
5.3.1.1 The DOMAIN NAME SPACE and RESOURCE RECORDS
The DOMAIN NAME SPACE and RESOURCE RECORDS, which are
specifications for a tree structured name space and data associated with the names.
Conceptually, each node and leaf of the domain name space tree names a set of
information, and query operations are attempts to extract specific types of information
from a particular set. A query names the domain name of interest and describes the type of
resource information that is desired. For example, the Internet uses some of its domain
names to identify hosts; queries for address resources return Internet host addresses.
The following figure 5.1 shows a part of the current domain name space. Note that
the tree is a very small subset of the actual name space.
VISUAL PROGRAMMING
NOTES
223 ANNA UNIVERSITY CHENNAI
|
|
+++
| | |
MIL EDU ARPA
| | |
| | |
+++ | ++++
| | | | | | |
BRL NOSC DARPA | IN-ADDR SRI-NIC ACC
|
+++++
| | | | |
UCI MIT | UDEL YALE
| ISI
| |
+++ |
| | |
LCS ACHILLES +++++
| | | | | |
XX A C VAXA VENERA Mockapetris
Figure 5.1 Name Space
In this example, the root domain has three immediate subdomains: MIL, EDU, and
ARPA. The LCS.MIT.EDU domain has one immediate subdomain named
XX.LCS.MIT.EDU. All of the leaves are also domains.
A domain name identifies a node. Each node has a set of resource information, which
may be empty. The set of resource information associated with a particular name is
composed of separate resource records (RRs). The order of RRs in a set is not significant,
and need not be preserved by name servers, resolvers, or other parts of the DNS. RRs
are represented in binary form in the packets of the DNS protocol, and are usually
represented in highly encoded form when stored in a name server or resolver.
5.3.1.2 Name Servers
Name Servers are server programs which hold information about the domain trees
structure and set information. A name server may cache structure or set information about
any part of the domain tree, but in general a particular name server has complete information
about a subset of the domain space, and pointers to other name servers that can be used
to lead to information from any part of the domain tree.
DMC 1944
NOTES
224 ANNA UNIVERSITY CHENNAI
While name servers can have several optional functions and sources of data, the
essential task of a name server is to answer queries using data in its zones. By design,
name servers can answer queries in a simple manner; the response can always be generated
using only local data, and either contains the answer to the question or a referral to other
name servers closer to the desired information.
Name servers know the parts of the domain tree for which they have complete
information; a name server is said to be an AUTHORITY for these parts of the name
space. Authoritative information is organized into units called ZONEs, and these zones
can be automatically distributed to the name servers which provide redundant service for
the data in a zone.
A given zone will be available from several name servers to insure its availability in
spite of host or communication link failure. By administrative fiat, we require every zone to
be available on at least two servers, and many zones have more redundancy than that.
A given name server will typically support one or more zones, but this gives it
authoritative information about only a small section of the domain tree. It may also have
some cached non-authoritative data about other parts of the tree. The name server marks
its responses to queries so that the requester can tell whether the response comes from
authoritative data or not.
5.3.1.3 Resolvers
Resolvers are programs that extract information from name servers in response to
client requests. Resolvers must be able to access at least one name server and use that
name servers information to answer a query directly, or pursue the query using referrals to
other name servers. A resolver will typically be a system routine that is directly accessible
to user programs; hence no protocol is necessary between the resolver and the user program.
In the simplest case, a resolver receives a request from a user program (e.g., mail
programs, TELNET, FTP) in the form of a subroutine call, system call etc., and returns the
desired information in a form compatible with the local hosts data formats.
The resolver is located on the same machine as the program that requests the resolvers
services, but it may need to consult name servers on other hosts. Because a resolver may
need to consult several name servers, or may have the requested information in a local
cache, the amount of time that a resolver will take to complete can vary quite a bit, from
milliseconds to several seconds.
A very important goal of the resolver is to eliminate network delay and name server
load from most requests by answering them from its cache of prior results. It follows that
caches which are shared by multiple processes, users, machines, etc., are more efficient
than non-shared caches.
VISUAL PROGRAMMING
NOTES
225 ANNA UNIVERSITY CHENNAI
5.4. WORLD WIDE WEB (HTTP)
HTTP stands for Hypertext Transfer Protocol. Its the network protocol used to
deliver virtually all files and other data (collectively called resources) on the World Wide
Web, whether theyre HTML files, image files, query results, or anything else. Usually,
HTTP takes place through TCP/IP sockets.
A browser is an HTTP client because it sends requests to an HTTP server (Web server),
which then sends responses back to the client. The standard (and default) port for HTTP
servers to listen on is 80, though they can use any port.
HTTP is used to transmit resources, not just files. A resource is some chunk of
information that can be identified by a URL (its the R in URL). The most common kind of
resource is a file, but a resource may also be a dynamically-generated query result, the
output of a CGI script, a document that is available in several languages, or something else.
While learning HTTP, it may help to think of a resource as similar to a file, but more
general. As a practical matter, almost all HTTP resources are currently either files or server-
side script output.
5.4.1 Structure of HTTP Transactions
Like most network protocols, HTTP uses the client-server model: An HTTP client
opens a connection and sends a request message to an HTTP server; the server then
returns a response message, usually containing the resource that was requested. After
delivering the response, the server closes the connection (making HTTP a stateless protocol,
i.e. not maintaining any connection information between transactions).
The formats of the request and response messages are similar, and English-oriented.
Both kinds of messages consist of:
an initial line,
zero or more header lines,
a blank line (i.e. a CRLF by itself), and
an optional message body (e.g. a file, or query data, or query output).
Put another way, the format of an HTTP message is:
<initial line, different for request vs. response>
Header1: value1
Header2: value2
Header3: value3
<optional message body goes here, like file contents or query data;
it can be many lines long, or even binary data $&*%@!^$@>
DMC 1944
NOTES
226 ANNA UNIVERSITY CHENNAI
Initial lines and headers should end in CRLF, though you should gracefully handle
lines ending in just LF. (More exactly, CR and LF here mean ASCII values 13 and 10,
even though some platforms may use different characters.)
5.4.1.1 Initial Request Line
The initial line is different for the request than for the response. A request line has three
parts, separated by spaces: a method name, the local path of the requested resource, and
the version of HTTP being used. A typical request line is:
GET /path/to/file/index.html HTTP/1.0
GET is the most common HTTP method; it says give me this resource. Other
methods include POST and HEAD. Method names are always uppercase.
The path is the part of the URL after the host name, also called the request URI (a
URI is like a URL, but more general).
The HTTP version always takes the form HTTP/x.x, uppercase.
5.4.1.2 Initial Response Line (Status Line)
The initial response line, called the status line, also has three parts separated by
spaces: the HTTP version, a response status code that gives the result of the request, and
an English reason phrase describing the status code. Typical status lines are:
HTTP/1.0 200 OK
or
HTTP/1.0 404 Not Found
The HTTP version is in the same format as in the request line, HTTP/x.x.
The status code is meant to be computer-readable; the reason phrase is meant to
be human-readable, and may vary.
The status code is a three-digit integer, and the first digit identifies the general
category of response:
o 1xx indicates an informational message only
o 2xx indicates success of some kind
o 3xx redirects the client to another URL
o 4xx indicates an error on the clients part
o 5xx indicates an error on the servers part
The most common status codes are:
200 OK
The request succeeded, and the resulting resource (e.g. file or script output) is returned
in the message body.
VISUAL PROGRAMMING
NOTES
227 ANNA UNIVERSITY CHENNAI
404 Not Found
The requested resource doesnt exist.
301MovedPermanently
302MovedTemporarily
The resource has moved to another URL (given by the Location: response header),
and should be automatically retrieved by the client. This is often used by a CGI script to
redirect the browser to an existing file.
500 Server Error
An unexpected server error. The most common cause is a server-side script that has
bad syntax, fails, or otherwise cant run correctly.
5.4.1.3 Header Lines
Header lines provide information about the request or response, or about the object
sent in the message body.
The header lines are in the usual text header format, which is: one line per header, of
the form Header-Name: value, ending with CRLF. Its the same format used for email
and news postings, defined in RFC 822, section 3. Details about RFC 822 header lines:
As noted above, they should end in CRLF, but you should handle LF correctly.
The header name is not case-sensitive (though the value may be).
Any number of spaces or tabs may be between the : and the value.
Header lines beginning with space or tab are actually part of the previous header
line, folded into multiple lines for easy reading.
Thus, the following two headers are equivalent:
Header1: some-long-value-1a, some-long-value-1b
HEADER1: some-long-value-1a,
some-long-value-1b
HTTP 1.0 defines 16 headers, though none are required. HTTP 1.1 defines 46 headers,
and one (Host:) is required in requests. Also consider including these headers in your
requests:
The From: header gives the email address of whoevers making the request, or
running the program doing so. (This must be user-configurable, for privacy
concerns.)
The User-Agent: header identifies the program thats making the request, in the
form Program-name/x.xx, where x.xx is the (mostly) alphanumeric version of
the program. For example, Netscape 3.0 sends the header User-agent: Mozilla/
3.0Gold.
DMC 1944
NOTES
228 ANNA UNIVERSITY CHENNAI
These headers help webmasters troubleshoot problems. They also reveal information
about the user. When you decide which headers to include, you must balance the
webmasters logging needs against your users needs for privacy.
If youre writing servers, consider including these headers in your responses:
The Server: header is analogous to the User-Agent: header: it identifies the server
software in the form Program-name/x.xx. For example, one beta version of
Apaches server returns Server: Apache/1.2b3-dev.
The Last-Modified: header gives the modification date of the resource thats
being returned. Its used in caching and other bandwidth-saving activities. Use
Greenwich Mean Time, in the format
Last-Modified: Fri, 31 Dec 1999 23:59:59 GMT
5.4.1.4 The Message Body
An HTTP message may have a body of data sent after the header lines. In a response,
this is where the requested resource is returned to the client (the most common use of the
message body), or perhaps explanatory text if theres an error. In a request, this is where
user-entered data or uploaded files are sent to the server.
If an HTTP message includes a body, there are usually header lines in the message
that describe the body. In particular,
The Content-Type: header gives the MIME-type of the data in the body, such as
text/html or image/gif.
The Content-Length: header gives the number of bytes in the body.
5.4.1.5 Sample HTTP Exchange
To retrieve the file at the URL http://www.somehost.com/path/file.html, first open a
socket to the host www.somehost.com, port 80 (use the default port of 80 because none
is specified in the URL). Then, send something like the following through the socket:
GET /path/file.html HTTP/1.0
From: someuser@jmarshall.com
User-Agent: HTTPTool/1.0
[blank line here]
The server should respond with something like the following, sent back through the
same socket:
HTTP/1.0 200 OK
Date: Fri, 31 Dec 1999 23:59:59 GMT
Content-Type: text/html
Content-Length: 1354
VISUAL PROGRAMMING
NOTES
229 ANNA UNIVERSITY CHENNAI
<html>
<body>
<h1>Happy New Millennium!</h1>
(more file contents)
.
.
.
</body>
</html>
After sending the response, the server closes the socket.
5.4.2 Other HTTP Methods, Like HEAD and POST
Besides GET, the two most commonly used methods are HEAD and POST.
5.4.2.1 The HEAD Method
A HEAD request is just like a GET request, except it asks the server to return the
response headers only, and not the actual resource (i.e. no message body). This is useful to
check characteristics of a resource without actually downloading it, thus saving bandwidth.
Use HEAD when you dont actually need a files contents.
The response to a HEAD request must never contain a message body, just the status
line and headers.
5.4.2.2 The POST Method
A POST request is used to send data to the server to be processed in some way, like
by a CGI script. A POST request is different from a GET request in the following ways:
Theres a block of data sent with the request, in the message body. There are
usually extra headers to describe this message body, like Content-Type: and
Content-Length:.
The request URI is not a resource to retrieve; its usually a program to handle the
data youre sending.
The HTTP response is normally program output, not a static file.
The most common use of POST, by far, is to submit HTML form data to CGI scripts.
In this case, the Content-Type: header is usually application/x-www-form-urlencoded,
and the Content-Length: header gives the length of the URL-encoded form data (heres
a note on URL-encoding). The CGI script receives the message body through STDIN,
and decodes it. Heres a typical form submission, using POST:
DMC 1944
NOTES
230 ANNA UNIVERSITY CHENNAI
POST /path/script.cgi HTTP/1.0
From: frog@jmarshall.com
User-Agent: HTTPTool/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 32
home=Cosby&favorite+flavor=flies
You can use a POST request to send whatever data you want, not just form
submissions. Just make sure the sender and the receiving program agree on the format.
The GET method can also be used to submit forms. The form data is URL-encoded
and appended to the request URI.
5.4.3 HTTP Proxies
An HTTP proxy is a program that acts as an intermediary between a client and a
server. It receives requests from clients, and forwards those requests to the intended servers.
The responses pass back through it in the same way. Thus, a proxy has functions of both
a client and a server.
Proxies are commonly used in firewalls, for LAN-wide caches, or in other situations.
When a client uses a proxy, it typically sends all requests to that proxy, instead of to
the servers in the URLs. Requests to a proxy differ from normal requests in one way: in the
first line, they use the complete URL of the resource being requested, instead of just the
path.
For example,
GET http://www.somehost.com/path/file.html HTTP/1.0
That way, the proxy knows which server to forward the request to (though the proxy
itself may use another proxy).
5.5 SIMPLE STATUS BARS
A status bar is a horizontal window at the bottom of a parent window in which an
application can display various kinds of status information. The status bar can be divided
into parts to display more than one type of information. The following screen shot in figure
5.2 shows the status bar in the Microsoft Windows Paint application. In this case, the
status bar contains the text For Help, click Help Topics on the Help Menu. The status
bar is the area at the bottom of the window that contains Help text and coordinate
information.
VISUAL PROGRAMMING
NOTES
231 ANNA UNIVERSITY CHENNAI
Figure 5.2 Status bar in the Microsoft Windows Paint application
The status bar window neither accepts user input nor generates command messages.
Its job is simply to display text in panes under program control. The status bar supports
two types of text panesmessage line panes and status indicator panes.
5.5.1 Status bar and indicator array
The AppWizard generates the static indicators array in the implementation file which
defines the panes for the applications status bar. The constant ID_SEPARATOR identifies
a message line pane; the other constants are string resource IDs that identify indicator
panes. Figure 5.3 shows the indicators array and its relationship to the standard framework
status bar.
Figure 5.3 The status bar and the indicators array
The CStatusBar::SetIndicators member function, called in the applications derived
frame class, configures the status bar according to the contents of the indicators array.
5.5.1.1 The Message Line
A message line pane displays a string that the program supplies dynamically. To set
the value of the message line, you must first get access to the status bar object and then you
must call the CStatusBar::SetPaneText member function with a zero-based index
parameter. Pane 0 is the leftmost pane, 1 is the next pane to the right, and so forth.
Static UNIT indicators[] =
{
ID_SEPARATOR
ID_INDICATOR_CAPS
ID_INDICATOR_NUM
ID_INDICATOR_SCRL
}
Message pane (subscript 0) CAP NUM SCRL
DMC 1944
NOTES
232 ANNA UNIVERSITY CHENNAI
The following code fragment is part of a view class member function:
CMainFrame* pFrame =(CMainFrame*) AfxGetApp()->m_pMainWnd;
CStatusBar* pStatus =&pFrame->m_wndStatusBar;
pStatus->SetPaneText(0, message line for first pane);
Normally, the length of a message line pane is exactly one-fourth the width of the display.
5.5.1.2 The Status Indicator
A status indicator pane is linked to a single resource-supplied string that is displayed
or hidden by logic in an associated update command UI message handler function. An
indicator is identified by a string resource ID, and that same ID is used to route update
command UI messages. The Caps Lock indicator is handled in the frame class by a message
map entry and a handler function equivalent to those shown below. The Enable function
turns on the indicator if the Caps Lock mode is set.
ON_UPDATE_COMMAND_UI(ID_INDICATOR_CAPS, OnUpdateKeyCapsLock)
void CMainFrame::OnUpdateKeyCapsLock(CCmdUI* pCmdUI)
{
pCmdUI->Enable(::GetKeyState(VK_CAPITAL) & 1);
}
The status bar update command UI functions are called during idle processing so that
the status bar is updated whenever your application receives messages.
The length of a status indicator pane is the exact length of the corresponding resource
string.
5.5.1.3 Taking Control of the Status Bar
In the standard application framework implementation, the status bar has the child
window ID AFX_IDW_STATUS_BAR. The application framework looks for this ID when
it wants to display a menu prompt. The update command UI handlers for the keyboard
state indicators, embedded in the frame window base class, are linked to the following
string I Ds: ID_INDICATOR_CAPS, ID_INDICATOR_NUM, and
ID_INDICATOR_SCRL. To take control of the status bar, you must use a different child
window ID and you must use different indicator ID constants.
The status bar window ID is assigned in the CStatusBar::Create function called by
the derived frame class OnCreate member function. That function is contained in the
MainFrm.cpp file that AppWizard generates. The window ID is the third Create parameter,
and it defaults to AFX_IDW_STATUS_BAR.
VISUAL PROGRAMMING
NOTES
233 ANNA UNIVERSITY CHENNAI
To assign your own ID, you must replace this call
m_wndStatusBar.Create(this);
with this call
m_wndStatusBar.Create(this, WS_CHILD | WS_VISIBLE | CBRS_BOTTOM,
ID_MY_STATUS_BAR);
You must also, of course, define the ID_MY_STATUS_BAR constant in the resource.h
file.
5.5.2 Types and Styles
The default position of a status bar is along the bottom of the parent window, but you
can specify the CCS_TOP style to have it appear at the top of the parent windows client
area. You can specify the SBARS_SIZEGRIP style to include a sizing grip at the right
end of the status bar.
5.5.3 Size and Height
The window procedure for the status bar automatically sets the initial size and position
of the window, ignoring the values specified in the CreateWindowEx function. The width
is the same as that of the parent windows client area. The height is based on the metrics of
the font that is currently selected into the status bars device context and on the width of
the windows borders. The window procedure automatically adjusts the size of the status
bar whenever it receives a WM_SIZE message. When the size of the parent window
changes, the parent sends a WM_SIZE message to the status bar.
An application can set the minimum height of a status bars drawing area by sending
the window an SB_SETMINHEIGHT message, specifying the minimum height, in pixels.
The drawing area does not include the windows borders. A minimum height is useful for
drawing in an owner-drawn status bar.
The widths of the borders of a status bar may be retrieved by sending the window an
SB_GETBORDERS message. The message includes the address of a three-element
array that receives the widths.
5.5.4 Multiple-Part Status Bars
A status bar can have many different parts, each displaying a different line of text. A
status bar may be divided into parts by sending the window an SB_SETPARTS message,
specifying the number of parts to create and the address of an integer array. The array
contains one element for each part, and each element specifies the client coordinate of the
right edge of a part.
A status bar can have a maximum of 256 parts, although applications typically use far
fewer than that. The count of the parts in a status bar, as well as the coordinate of the right
edge of each part, may be retrieved by sending the window an SB_GETPARTS message.
DMC 1944
NOTES
234 ANNA UNIVERSITY CHENNAI
5.5.5 Status Bar Text Operations
Text may be set in any part of a status bar by sending the SB_SETTEXT message,
specifying the zero-based index of a part, an address of the string to draw in the part, and
the technique for drawing the string. The drawing technique determines whether the text
has a border and, if it does, the style of the border. It also determines whether the parent
window is responsible for drawing the text.
To retrieve text from a status bar, use the SB_GETTEXTLENGTH and
SB_GETTEXT messages.
If your application uses a status bar that has only one part, you can use the
WM_SETTEXT, WM_GETTEXT, and WM_GETTEXTLENGTH messages to
perform text operations. These messages deal only with the part that has an index of zero,
allowing you to treat the status bar much like a static text control.
To display a line of status without creating a status bar, use the DrawStatusText
function. The function uses the same techniques to draw the status as the window procedure
for the status bar, but it does not automatically set the size and position of the status
information. When calling the function, you must specify the size and position of the status
information as well as the device context of the window in which to draw it. The syntax for
the DrawStatusText is as given below:
void DrawStatusText(HDC hdc, LPCRECT lprc, LPCTSTR pszText, UINT uFlags);
where, hdc - Handle to the display context for the window
lprc - Pointer to a RECT structure that contains the position, in client
coordinates, of the rectangle in which the text is drawn. The
function draws the borders just inside the edges of the specified
rectangle.
pszText - Pointer to a null-terminated string that specifies the text to display.
Tab characters in the string determine whether the string is left-
aligned, right-aligned, or centered.
uFlags - Text drawing flags. This parameter can be a combination of these
values:
Value Meaning
SBT_NOBORDERS Prevents borders from being drawn around the
specified text.
SBT_POPOUT Draws highlighted borders that make the text stand out.
SBT_RTLREADING Indicates that the string pointed to by pszText will be
displayed in the opposite direction to the text in the
parent window.
VISUAL PROGRAMMING
NOTES
235 ANNA UNIVERSITY CHENNAI
5.5.6 Owner-Drawn Status Bars
Individual parts of a status bar may be defined as owner-drawn parts. For example,
you can display a bitmap rather than text or draw text using a different font.
To define a window part as owner-drawn, send the SB_SETTEXT message to the
status bar, specifying the part and the SBT_OWNERDRAW drawing technique. When
SBT_OWNERDRAW is specified, the lParam parameter is a 32-bit application-defined
value that the application can use when drawing the part. For example, you can specify a
font handle, a bitmap handle, an address of a string, and so on.
When a status bar needs to draw an owner-drawn part, it sends the
WM_DRAWITEM message to the parent window. The wParam parameter of the
message is the child window identifier of the status bar, and the lParam parameter is the
address of a DRAWITEMSTRUCT structure. The parent window uses the information
in the structure to draw the part. For an owner-drawn part of a status bar,
DRAWITEMSTRUCT contains the following information:
5.5.7 Simple Mode Status Bars
You put a status bar in simple mode by sending it an SB_SIMPLE message. A
simple mode status bar displays only one part. When the text of the window is set, the
window is invalidated, but it is not redrawn until the next WM_PAINT. Waiting for the
message reduces screen flicker by minimizing the number of times the window is redrawn.
A simple mode status bar is useful for displaying Help text for menu items while the user is
scrolling through the menu.
The string that a status bar displays while in simple mode is maintained separately
from the strings that it displays while in nonsimple mode. This means you can put the
window in simple mode, set its text, and switch back to nonsimple mode without the
nonsimple mode text being changed.
Member Description
CtlType Undefined; do not use.
CtlID Child window identifier of the status bar.
itemID Zero-based index of the part to be drawn.
itemAction Undefined; do not use.
itemState Undefined; do not use.
hwndItem Handle to the status bar.
hDC Handle to the device context of the status bar.
rcItem Coordinates of the window part to be drawn. The
coordinates are relative to the upper left corner of the
status bar.
itemData Application-defined 32-bit value specified in the
lParam parameter of the SB_SETTEXT message.
DMC 1944
NOTES
236 ANNA UNIVERSITY CHENNAI
When setting the text of a simple mode status bar, you can specify any drawing
technique except SBT_OWNERDRAW. A simple mode status bar does not support owner
drawing.
5.5.8 Default Status Bar Message Processing
The messages handled by the window procedure for the predefined
STATUSCLASSNAME class are given in table 5.1 below:
Table 5.1 Status bar Messages
Now lets look at a sample program that helps you understand how to work with
status bar.
Message Default processing
WM_CREATE Initializes the status bar.
WM_DESTROY Frees resources allocated for the status bar.
WM_GETFONT Returns the handle to the current font with
which the status bar draws its text.
WM_GETTEXT Copies the text from the first part of a status
bar to a buffer. It returns a 32-bit value that
specifies the length, in characters, of the
text and the technique used to draw the text.
WM_GETTEXTLENGTH Returns a 32-bit value that specifies the
length, in characters, of the text in the first
part of a status bar and the technique used
to draw the text.
WM_NCHITTEST Returns the HTBOTTOMRIGHT value if
the mouse cursor is in the sizing grip,
causing the system to display the sizing
cursor. If the mouse cursor is not in the
sizing grip, the status bar passes this
message to the DefWindowProc function.
WM_PAINT Paints the invalid region of the status bar. If
the wParam parameter is non-NULL, the
control assumes that the value is an HDC
and paints using that device context.
WM_SETFONT Selects the font handle into the device
context for the status bar.
WM_SETTEXT Copies the specified text into the first part
of a status bar, using the default drawing
operation (specified as zero). It returns
TRUE if successful, or FALSE otherwise.
WM_SIZE Resizes the status bar based on the current
width of the parent window's client area
and the height of the current font of the
status bar.
VISUAL PROGRAMMING
NOTES
237 ANNA UNIVERSITY CHENNAI
Program 5.1: Program to display the mouse co-ordinates in the status bar.
1. Run AppWizard to generate a project named Status. Accept all default settings
but two: select Single Document and deselect Printing and Print Preview.
2. Use the string editor to edit the applications string table resource. Double-click
on the String Table icon in the String Table folder on the ResourceView page to
bring up the string editor. Then double-click on the empty entry at the end of the
list. A dialog allows you to assign the ID and the string value as shown in Figure
5.4.
Figure 5.4 String Table
Add two strings as follows:
3. Use Visual C++to edit the applications symbols. Choose Resource Symbols
from the View menu. Add the new status bar identifier, ID_MY_STATUS_BAR,
and accept the default value.
4. Use ClassWizard to add View menu command handlers in the class CMainFrame.
Add the following command message handlers.
5. Add the following function prototypes to MainFrm.h. You must add these
CMainFrame message handler prototypes manually because ClassWizard doesnt
recognize the associated command message IDs.
afx_msg void OnUpdateLeft(CCmdUI* pCmdUI);
afx_msg void OnUpdateRight(CCmdUI* pCmdUI);
String ID String Caption
ID_INDICATOR_LEFT LEFT
ID_INDICATOR_RIGHT RIGHT
Object ID Message Member Function
ID_VIEW_STATUS_BAR COMMAND OnViewStatusBar
ID_VIEW_STATUS_BAR UPDATE_COMMAND_UI OnUpdateViewStatusBar
DMC 1944
NOTES
238 ANNA UNIVERSITY CHENNAI
Add the message handler statements inside the AFX_MSG brackets so that
ClassWizard will let you access and edit the code later. While MainFrm.h is open, make
m_wndStatusBar public rather than protected.
6. Edit the MainFrm.cpp file. Replace the original indicators array with the following
boldface code:
static UINT indicators[] =
{
ID_SEPARATOR, // first message line pane
ID_SEPARATOR, // second message line pane
ID_INDICATOR_LEFT,
ID_INDICATOR_RIGHT,
};
Next edit the OnCreate member function. Replace the following statement:
if (!m_wndStatusBar.Create(this) ||
!m_wndStatusBar.SetIndicators(indicators,
sizeof(indicators)/sizeof(UINT)))
{
TRACE0(Failed to create status bar\n);
return -1; // fail to create
}
with the statement shown here:
if (!m_wndStatusBar.Create(this,
WS_CHILD | WS_VISIBLE | CBRS_BOTTOM,
ID_MY_STATUS_BAR) ||
!m_wndStatusBar.SetIndicators(indicators,
sizeof(indicators)/sizeof(UINT)))
{
TRACE0(Failed to create status bar\n);
return -1; // fail to create
}
The modified call to Create uses our own status bar ID, ID_MY_STATUS_BAR,
instead of AFX_IDW_STATUS_BAR (the application frameworks status bar object).
Now add the following message map entries for the class CMainFrame. ClassWizard
cant add these for you because it doesnt recognize the string table IDs as object IDs.
VISUAL PROGRAMMING
NOTES
239 ANNA UNIVERSITY CHENNAI
ON_UPDATE_COMMAND_UI(ID_INDICATOR_LEFT, OnUpdateLeft)
ON_UPDATE_COMMAND_UI(ID_INDICATOR_RIGHT, OnUpdateRight)
Next add the following CMainFrame member functions that update the two status
indicators:
void CMainFrame::OnUpdateLeft(CCmdUI* pCmdUI)
{
pCmdUI->Enable(::GetKeyState(VK_LBUTTON) < 0);
}
void CMainFrame::OnUpdateRight(CCmdUI* pCmdUI)
{
pCmdUI->Enable(::GetKeyState(VK_RBUTTON) < 0);
}
Note that the left and right mouse buttons have virtual key codes like keys on the
keyboard have. You dont have to depend on mouse-click messages to determine the
button status.
Finally, edit the following View menu functions that ClassWizard originally generated
in MainFrm.cpp:
void CMainFrame::OnViewStatusBar()
{
m_wndStatusBar.ShowWindow((m_wndStatusBar.GetStyle() &
WS_VISIBLE) == 0);
RecalcLayout();
}
void CMainFrame::OnUpdateViewStatusBar(CCmdUI* pCmdUI)
{
pCmdUI SetCheck((m_wndStatusBar.GetStyle() & WS_VISIBLE) != 0);
}
These functions ensure that the View menu Status Bar command is properly linked to
the new status bar.
7. Edit the OnDraw function in StatusView.cpp. The OnDraw function displays
a message in the view window. Add the following boldface code:
void CStatusView::OnDraw(CDC* pDC)
{
pDC->TextOut(0, 0,
Watch the status bar while you move and click the mouse.);
}
DMC 1944
NOTES
240 ANNA UNIVERSITY CHENNAI
8. Add a WM_MOUSEMOVE handler in the CStatusView class. Use
ClassWizard to map the message to OnMouseMove, and then edit the function as
shown below. This function gets a pointer to the status bar object and then calls
the SetPaneText function to update the first and second message line panes.
void CStatusView::OnMouseMove(UINT nFlags, CPoint point)
{
CString str;
CMainFrame* pFrame = (CMainFrame*) AfxGetApp() m_pMainWnd;
CStatusBar* pStatus = &pFrame->m_wndStatusBar;
if (pStatus)
{
str.Format(x = %d, point.x);
pStatus->SetPaneText(0, str);
str.Format(y = %d, point.y);
pStatus->SetPaneText(1, str);
}
}
Finally, add the statement #include MainFrm.h near the top of the file
StatusView.cpp.
9. Build and test the STATUS application. Move the mouse, and observe that
the left two status bar panes accurately reflect the mouse cursors position as
shown in Figure 5.5.
Figure 5.5 Status bar application
VISUAL PROGRAMMING
NOTES
241 ANNA UNIVERSITY CHENNAI
5.6 SPLITTER WINDOWS AND MULTIPLE VIEWS
A splitter window appears as a special type of frame window that holds several views
in panes. The application can split the window on creation, or the user can split the window
by choosing a menu command or by dragging a splitter box on the windows scroll bar.
After the window has been split, the user can move the splitter bars with the mouse to
adjust the relative sizes of the panes. Splitter windows can be used in both SDI and MDI
applications.
An object of class CSplitterWnd represents the splitter window. As far as Windows
is concerned, a CSplitterWnd object is an actual window that fully occupies the frame
window (CFrameWnd or CMDIChildWnd) client area. The view windows occupy the
splitter window pane areas. The splitter window does not take part in the command dispatch
mechanism. The active view window (in a splitter pane) is connected directly to its frame
window
5.6.1 View Options
When you combine multiview presentation methods with application models, you get
a number of permutations. Here are some of them:
SDI application with splitter window, single view class.
SDI application with splitter window, multiple view classes.
SDI application with no splitter windows, multiple view classes.
MDI application with no splitter windows, single view class.
MDI application with no splitter windows, multiple view classes A small change
to the standard MDI application allows the use of multiple views.
MDI application with splitter child windows.
5.6.2 Dynamic and Static Splitter Windows
A dynamic splitter window allows the user to split the window at any time by choosing
a menu item or by dragging a splitter box located on the scroll bar. The panes in a dynamic
splitter window generally use the same view class. The top left pane is initialized to a
particular view when the splitter window is created. In a dynamic splitter window, scroll
bars are shared among the views. In a window with a single horizontal split, for example,
the bottom scroll bar controls both views. A dynamic splitter application starts with a single
view object. When the user splits the frame, other view objects are constructed. When the
user unsplits the frame, view objects are destroyed.
The panes of a static splitter window are defined when the window is first created
and they cannot be changed. The user can move the bars but cannot unsplit or resplit the
window. Static splitter windows can accommodate multiple view classes, with the
configuration set at creation time. In a static splitter window, each pane has separate scroll
bars. In a static splitter window application, all view objects are constructed when the
frame is constructed and they are all destroyed when the frame is destroyed.
DMC 1944
NOTES
242 ANNA UNIVERSITY CHENNAI
A CSplitterWnd supports two different styles of splitting windows:
1. In static splitters, the panes are created when the splitter window is created, and
the order and number of panes never change. Splitter bars are used to resize the
different panes, and the different panes are usually of different view classes. The
Visual C++graphics editor and the Windows File Manager are examples of
programs that use this splitter style. Splitter boxes are not used by this style of
splitter.
2. In Dynamic splitters, additional panes are created and destroyed as the user
splits and un-splits new views. This splitter starts out with a single view, and splitter
boxes are provided to initiate splitting. If the view is split in one direction, an
additional view object is dynamically created to represent the new pane. If the
view is split in two directions (possible with the keyboard interface), then three
new views are created to represent the three new panes. When the split is active,
the splitter box is drawn as a splitter bar between the panes. Additional view
objects are destroyed when the user removes a split, but the original view (row 0,
column 0) remains until the splitter window itself is destroyed. Microsoft Excel
and Microsoft Word are examples of the dynamic splitter style.
When creating either kind of splitter window, you must specify the maximum number
of rows and columns that the splitter will manage. For a static splitter, panes must be
created to fill all the rows and columns. For a dynamic splitter, the first pane is automatically
created when the CSplitterWnd is created.
The maximum number of panes you can specify for static splitters is 16 rows by 16
columns. The recommended configurations are:
1 row x 2 columns : usually with dissimilar panes
2 rows x 1 column : usually with dissimilar panes
2 rows x 2 columns : usually with similar panes
The maximum number of panes you can specify for dynamic splitters is 2 rows by 2
columns. The recommended configurations are:
1 row x 2 columns : for columnar data
2 rows x 1 column : for textual or other data
2 rows x 2 columns : for grid or table oriented data
5.6.3 Creating a Single View Class SDI Dynamic Splitter
The user can dynamically split the view into four panes with four separate view objects,
all managed by a single view class. AppWizard lets you add a dynamic splitter window to
a new application. Create an SDI project. Click the Advanced button in the AppWizard
Step 4 dialog. Click on the Window Styles tab, and select Use Split Window as shown in
figure 5.6:
VISUAL PROGRAMMING
NOTES
243 ANNA UNIVERSITY CHENNAI
Figure 5.6 Creating a splitter window using AppWizard
When you check the Use Split Window check box, AppWizard adds code to your
CMainFrame class. Of course, you could add the same code to the CMainFrame class of
an existing application to add splitter capability.
When AppWizard generates an application with a splitter frame, it includes a Split option
in the projects View menu. The ID_WINDOW_SPLIT command ID is mapped in the
CView class within the MFC library.
The applications main frame window class needs a splitter window data member
and a prototype for an overridden OnCreateClient function. Here are the additions that
AppWizard makes to the MainFrm.h file:
protected:
CSplitterWnd m_wndSplitter;
public:
virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext);
The application framework calls the CFrameWnd::OnCreateClient virtual member
function when the frame object is created. The base class version creates a single view
window as specified by the document template. The AppWizard-generated OnCreateClient
override shown here (in MainFrm.cpp) creates a splitter window instead, and the splitter
window creates the first view:
DMC 1944
NOTES
244 ANNA UNIVERSITY CHENNAI
BOOL CMainFrame::OnCreateClient( LPCREATESTRUCT /*lpcs*/,
CCreateContext* pContext)
{
return m_wndSplitter.Create( this,
2, 2, // TODO: adjust the number of rows, columns
CSize(10, 10), // TODO: adjust the minimum pane size
pContext);
}
Figure 5.7 A single view window with a four-way split.
The CSplitterWnd Create member function creates a dynamic splitter window, and
the CSplitterWnd object knows the view class because its name is embedded in the
CCreateContext structure thats passed as a parameter to Create.
The second and third Create parameters (2, 2) specify that the window can be split
into a maximum of two rows and two columns. If you changed the parameters to (2, 1),
you would allow only a single horizontal split. The parameters (1, 2) allow only a single
vertical split. The CSize parameter specifies the minimum pane size.
When the application starts, you can split the window by choosing Split from the
View menu or by dragging the splitter boxes at the left and top of the scroll bars. Figure 5.7
shows a typical single view window with a four-way split. Multiple views share the scroll
bars.
5.7 DYNAMIC LINK LIBRARY
A dynamic-link library (DLL) is a module that contains functions and data that can
be used by another module (application or DLL).
VISUAL PROGRAMMING
NOTES
245 ANNA UNIVERSITY CHENNAI
A DLL can define two kinds of functions: exported and internal. The exported functions
are intended to be called by other modules, as well as from within the DLL where they are
defined. Internal functions are typically intended to be called only from within the DLL
where they are defined. Although a DLL can export data, its data is generally used only by
its functions. However, there is nothing to prevent another module from reading or writing
that address.
DLLs provide a way to modularize applications so that their functionality can be
updated and reused more easily. DLLs also help reduce memory overhead when several
applications use the same functionality at the same time, because although each application
receives its own copy of the DLL data, the applications share the DLL code.
The Windows application programming interface (API) is implemented as a set of
DLLs, so any process that uses the Windows API uses dynamic linking.
5.7.1 Types of Dynamic Linking
There are two methods for calling a function in a DLL:
In load-time dynamic linking, a module makes explicit calls to exported DLL
functions as if they were local functions. This requires you to link the module with
the import library for the DLL that contains the functions. An import library supplies
the system with the information needed to load the DLL and locate the exported
DLL functions when the application is loaded.
In run-time dynamic linking, a module uses the LoadLibrary or LoadLibraryEx
function to load the DLL at run time. The LoadLibrary loads the specified module
into the address space of the calling process. The specified module may cause
other modules to be loaded. The function returns a handle to the module if successful
otherwise, NULL.
Syntax: HMODULE WINAPI LoadLibrary( _In_ LPCTSTR lpFileName);
where, lpFileName is the name of the module. This can be either a library module
(a .dll file) or an executable module (an .exe file). The name specified is the file
name of the module and is not related to the name stored in the library module
itself, as specified by the LIBRARY keyword in the module-definition (.def) file.
After the DLL is loaded, the module calls the GetProcAddress function to get the
addresses of the exported DLL functions. The module calls the exported DLL
functions using the function pointers returned by GetProcAddress. This eliminates
the need for an import library.
The GetProcAddress function retrieves the address of an exported function or
variable from the specified dynamic-link library (DLL) if successful, else, returns
NULL. The syntax is:
FARPROC WINAPI GetProcAddress( _In_ HMODULE hModule,
_In_ LPCSTR lpProcName);
DMC 1944
NOTES
246 ANNA UNIVERSITY CHENNAI
where,
hModule is a handle to the DLL module that contains the function or variable. The
LoadLibrary or GetModuleHandle function returns this handle. The
GetProcAddress function does not retrieve addresses from modules that were
loaded using the LOAD_LIBRARY_AS_DATAFILE flag.
lpProcName is the function or variable name, or the functions ordinal value. If
this
parameter is an ordinal value, it must be in the low-order word; the high-order
word must be zero.
5.7.2 Pros and Cons
Dynamic linking has the following advantages over static linking:
Multiple processes that load the same DLL at the same base address share a
single copy of the DLL in physical memory. Doing this saves system memory and
reduces swapping.
When the functions in a DLL change, the applications that use them do not need to
be recompiled or relinked as long as the function arguments, calling conventions,
and return values do not change. In contrast, statically linked object code requires
that the application be relinked when the functions change.
A DLL can provide after-market support. For example, a display driver DLL can
be modified to support a display that was not available when the application was
initially shipped.
Programs written in different programming languages can call the same DLL function
as long as the programs follow the same calling convention that the function uses.
The calling convention (such as C, Pascal, or standard call) controls the order in
which the calling function must push the arguments onto the stack, whether the
function or the calling function is responsible for cleaning up the stack, and whether
any arguments are passed in registers. For more information, see the documentation
included with your compiler.
A potential disadvantage to using DLLs is that the application is not self-contained; it
depends on the existence of a separate DLL module. The system terminates processes
using load-time dynamic linking if they require a DLL that is not found at process startup
and gives an error message to the user. The system does not terminate a process using run-
time dynamic linking in this situation, but functions exported by the missing DLL are not
available to the program.
5.7.3 DLLs and Memory Management
Every process that loads the DLL maps it into its virtual address space. After the
process loads the DLL into its virtual address, it can call the exported DLL functions.
VISUAL PROGRAMMING
NOTES
247 ANNA UNIVERSITY CHENNAI
The system maintains a per-process reference count for each DLL. When a thread
loads the DLL, the reference count is incremented by one. When the process terminates,
or when the reference count becomes zero (run-time dynamic linking only), the DLL is
unloaded from the virtual address space of the process.
Like any other function, an exported DLL function runs in the context of the thread
that calls it. Therefore, the following conditions apply:
The threads of the process that called the DLL can use handles opened by a DLL
function. Similarly, handles opened by any thread of the calling process can be
used in the DLL function.
The DLL uses the stack of the calling thread and the virtual address space of the
calling process.
The DLL allocates memory from the virtual address space of the calling process.
5.7.4 Dynamic-Link Library Creation
To create a Dynamic-Link Library (DLL), you must create one or more source code
files, and possibly a linker file for exporting the functions. If you plan to allow applications
that use your DLL to use load-time dynamic linking, you must also create an import library.
5.7.4.1 Creating Source Files
The source files for a DLL contain exported functions and data, internal functions and
data, and an optional entry-point function for the DLL. You may use any development
tools that support the creation of Windows-based DLLs.
If your DLL may be used by a multithreaded application, you should make your DLL
thread-safe. You must synchronize access to all of the DLLs global data to avoid data
corruption. You must also ensure that you link only with libraries that are thread-safe as
well. For example, Microsoft Visual C++contains multiple versions of the C Run-time
Library, one that is not thread-safe and two that are.
5.7.4.2 Exporting Functions
How you specify which functions in a DLL should be exported depends on the tools
that you are using for development. Some compilers allow you to export a function directly
in the source code by using a modifier in the function declaration. Other times, you must
specify exports in a file that you pass to the linker.
For example, using Visual C++, there are two possible ways to export DLL functions:
with the __declspec(dllexport) modifier or with a module-definition (.def) file. If you use
the __declspec(dllexport) modifier, it is not necessary to use a .def file.
DMC 1944
NOTES
248 ANNA UNIVERSITY CHENNAI
5.7.4.3 Creating an Import Library
An import library (.lib) file contains information the linker needs to resolve external
references to exported DLL functions, so the system can locate the specified DLL and
exported DLL functions at run time. You can create an import library for your DLL when
you build your DLL.
To build an import library and export file, use the following syntax:
LIB /DEF[:deffile] [options] [objfiles] [libraries]
When /DEF is specified, LIB creates the output files from export specifications that
are passed in the LIB command. There are three methods for specifying exports, listed in
recommended order of use:
1. A __declspec(dllexport) definition in one of the objfiles or libraries
2. A specification of /EXPORT:name on the LIB command line
3. A definition in an EXPORTS statement in a deffile
These are the same methods you use to specify exports when linking an exporting
program. A program can use more than one method. You can specify parts of the LIB
command (such as multiple objfiles or /EXPORT specifications) in a command file in the
LIB command, just as you can in a LINK command.
The following options apply to building an import library and export file:
/OUT: import
Overrides the default output file name for the import library being created. When
/OUT is not specified, the default name is the base name of the first object file or
library in the LIB command and the extension .lib. The export file is given the same
base name as the import library and the extension .exp.
/EXPORT: entryname[=internalname][,@ ordinal[, NONAME]][, DATA]
Exports a function from your program to allow other programs to call the function.
You can also export data (using the DATA keyword). Exports are usually defined
in a DLL.
The entryname is the name of the function or data item as it is to be used by the
calling program. Optionally, you can specify the internalname as the function
known in the defining program; by default, internalname is the same as entryname.
The ordinal specifies an index into the export table in the range 1 through 65,535;
if you do not specify ordinal, LIB assigns one. The NONAME keyword exports
the function only as an ordinal, without an entryname. The DATA keyword is
used to export data-only objects.
VISUAL PROGRAMMING
NOTES
249 ANNA UNIVERSITY CHENNAI
/INCLUDE: symbol
Adds the specified symbol to the symbol table. This option is useful for forcing the
use of a library object that otherwise would not be included.
Note that if you create your import library in a preliminary step, before creating your .dll,
you must pass the same set of object files when building the .dll, as you passed when
building the import library.
5.7.4.4 Using an Import Library
For example, to call the CreateWindow function, you must link your code with the
import library User32.lib. The reason is that CreateWindow resides in a system DLL
named User32.dll, and User32.lib is the import library used to resolve the calls to exported
functions in User32.dll in your code. The linker creates a table that contains the address of
each function call. Calls to functions in a DLL will be fixed up when the DLL is loaded.
While the system is initializing the process, it loads User32.dll because the process depends
on exported functions in that DLL, and it updates the entries in the function address table.
All calls to CreateWindow invoke the function exported from User32.dll.
5.7.5 Linking Implicitly
To implicitly link to a DLL, executables must obtain the following from the provider
of the DLL:
A header file (.h file) containing the declarations of the exported functions and/or
C++classes. The classes, functions, and data should all have __declspec(dllimport).
An import library (.LIB files) to link with. (The linker creates the import library
when the DLL is built.)
The actual DLL (.dll file).
Executables using the DLL must include the header file containing the exported functions
(or C++classes) in each source file that contains calls to the exported functions. From a
coding perspective, the function calls to the exported functions are just like any other
function call.
To build the calling executable file, you must link with the import library. If you are
using an external makefile, specify the file name of the import library where you list other
object (.obj) files or libraries that you are linking with.
The operating system must be able to locate the DLL file when it loads the calling
executable.
Now lets see how to create a simple DLL and its usage in a windows program.
DMC 1944
NOTES
250 ANNA UNIVERSITY CHENNAI
Program 5.2: Program to create a DLL.
1. Open Visual C++and click the New item in the File menu, opening the New
dialog box.
2. Now select the MFC AppWizard(dll) entry in the New dialog box.
3. Give the new program the name dll in the Project name box.
4. Click OK to starts the Visual C++AppWizard.
5. Open dll.cpp file and write the function that is to be exported here,
int _stdcall add(int a,int b)
{
return(a+b);
}
6. In the dll.def file,
EXPORTS
add @ 1
; Explicit exports can go here
7. Compile the application. dll.dll file is created and will be found in your debug
folder.
8. Copy the dll.dll file from debug folder of dll. And paste into debug folder of view
application wizard(exe).
9. In the view.cpp file under #include statements write the prototype of the functions-
typedef int(CALLBACK *lpfn) (int,int);
10. In OnDraw( ) function:
void CViewView::OnDraw(CDC* pDC)
{
CViewDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
HINSTANCE hDll;
int sum;
lpfn f1;
hDll=LoadLibrary(dll);
if(hDll!=NULL)
{
f1=(lpfn)GetProcAddress(hDll,add);
if(!f1)
FreeLibrary(hDll);
else
{
sum=f1(3,4);
char ch[2];
sprintf(ch,%d,ch);
pDC->TextOut(10,10,sum);
}
}
VISUAL PROGRAMMING
NOTES
251 ANNA UNIVERSITY CHENNAI
11. Test the application and observe the result.
The following program is the source code needed to create a simple DLL, Myputs.dll.
It defines a simple string-printing function called myPuts. The Myputs DLL does not define
an entry-point function, because it is linked with the C run-time library and has no initialization
or cleanup functions of its own to perform.
Program 5.3: Creating a simple DLL that defines a simple string-printing function that
ouputs a null-terminated string to the standard output device.
#include <windows.h>
#define EOF (-1)
#ifdef __cplusplus // If used by C++code,
extern C { // we need to export the C interface
#endif
__declspec(dllexport) int __cdecl myPuts(LPWSTR lpszMsg)
{
DWORD cchWritten;
HANDLE hConout;
BOOL fRet;
// Get a handle to the console output device.
hConout =CreateFileW(LCONOUT$,
GENERIC_WRITE,
FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (INVALID_HANDLE_VALUE ==hConout)
return EOF;
// Write a null-terminated string to the console output device.
while (*lpszMsg !=L\0')
{
fRet =WriteConsole(hConout, lpszMsg, 1, &cchWritten, NULL);
if( (FALSE ==fRet) || (1 !=cchWritten) )
return EOF;
lpszMsg++;
}
return 1;
}
#ifdef __cplusplus
}
#endif
DMC 1944
NOTES
252 ANNA UNIVERSITY CHENNAI
After you have created a DLL, you can use the functions it defines in an application.
The following is a simple console application that uses the myPuts function exported from
Myputs.dll. Because this example calls the DLL function explicitly, the module for the
application must be linked with the import library Myputs.lib.
#include <windows.h>
extern C int __cdecl myPuts(LPWSTR); // a function from a DLL
int main(VOID)
{
int Ret =1;
Ret =myPuts(LMessage sent to the DLL function\n);
return Ret;
}
5.8 DATABASE MANAGEMENT WITH ODBC
A large number of applications use a database. Everything from a personal organizer
to a large, corporate personnel system uses a database to store and maintain all the records
that the applications use and manipulate. Visual C++provides several ways to work with
databases. The preferred way is to use one of the class libraries such as the Active Template
Class Library (ATL) or Microsoft Foundation Class (MFC) Library, which simplify working
with the database APIs.
The library classes support the following kinds of data access:
ATL provides OLE DB templates and database attributes.
MFC provides Open Database Connectivity (ODBC) and an ODBC driver.
These libraries supply abstractions that simplify working with databases, complete
with the speed, power, and flexibility of C++. They integrate your data access work with
the librarys application framework.
Alternately, you can directly call database API functions from the COM, ODBC, or
DAO software development kits (SDKs).
Use ATL OLE DB if you need to access data, regardless of the form in which it is
stored. Use the MFC ODBC classes when you are not using Microsoft J et (.mdb)
databases and want to work with the ODBC API for complete data-source independence.
Use the MFC DAO classes when you want to work with Microsoft Jet (.mdb) databases
or with external databases such as ODBC data sources.
VISUAL PROGRAMMING
NOTES
253 ANNA UNIVERSITY CHENNAI
5.8.1 The MFC Classes for ODBC Support
In the Visual C++development environment, most of the ODBC functionality has
been encapsulated into two classes, CRecordset and CDatabase. The CDatabase class
contains the database connection information and can be shared across an entire application.
The CRecordset class encapsulates a set of records from the database. The CRecordset
class allows you to specify a SQL query to be run, and the CRecordset class will run the
query and maintain the set of records that are returned by the database. You can modify
and update the records in the record set, and your changes will be passed back to the
database. You can add or delete records from the record set, and those same actions can
be passed back to the database.
5.8.1.1 Connecting to the Database
Before the CRecordset class can perform any other functions, it has to be connected
to a database. This is accomplished through the use of the CDatabase class. You dont
need to create or set the CDatabase instance; the first instance of the CRecordset class
does this for you. When you create an application using the AppWizard and choose to
include ODBC database support, the AppWizard includes the database connection
information in the first CRecordset-derived class that it creates. When this CRecordset
class is created without being passed a CDatabase object, it uses the default connection
information, which was added by the AppWizard, to create its own database connection.
5.8.1.2 Opening and Closing the Record Set
Once the CRecordset object is created and connected to the database, you need to
open the record set to retrieve the set of records from the database. Do this by calling the
Open member function of the CRecordset object. You can call this function without any
arguments if you want to take the default values for everything, including the SQL statement
to be executed.
Once the user finishes working with the record set, you can call the Close function to
close the record set and free any resources used by the record set. The Close function
doesnt take any arguments.
5.8.1.3 Navigating the Record Set
Once you have a set of records retrieved from the database, you need to be able to
navigate the set of records (unless the set has only one record). The CRecordset class
provides several functions for navigating the record set, allowing you to move the user to
any record. Below is the list of functions that you can use to navigate the record set.
DMC 1944
NOTES
254 ANNA UNIVERSITY CHENNAI
5.8.1.4 Adding, Deleting, and Updating Records
Apart from navigating a set of records you also need to be able to add new records
to the record set, edit and update existing records, and delete records. These actions are
all possible through the various functions that the CRecordset class provides. The functions
that will enable you to add new records to the record set, edit and update existing records,
and delete records are listed below:
None of these functions takes any arguments. However, some of them require following
a few specific steps to get them to work correctly.
To add a new record to the database, you can call the AddNew function. The next
thing that you need to do is set default values in any of the fields that require values, such as
the key fields. Next, you must call the Update function to add the new record to the
database. If you try to navigate to another record before calling the Update function, the
new record will be lost. Once you save the new record, you need to call the Requery
function to refresh the record set so that you can navigate to the new record and let the
user edit it.
Now lets make use of the above mentioned classes and methods to create a simple
database application.
Function Description
MoveFirst Moves to the first record in the set.
MoveLast Moves to the last record in the set.
MoveNext Moves to the next record in the set.
MovePrev Moves to the previous record in the se
Move Can be used to move a specific n
records from the current record or from
record in the set.
SetAbsolutePosition Moves to the specified record in the se
IsBOF Returns TRUE if the current record i
record in the set.
IsEOF Returns TRUE if the current record
record in the set.
GetRecordCount Returns the number of records in the s
Function Description
AddNew Adds a new record to the record set.
Delete Deletes the current record from the record set.
Edit Allows the current record to be edited.
Update Saves the current changes to the database.
Requery Reruns the current SQL query to refresh the record set.
VISUAL PROGRAMMING
NOTES
255 ANNA UNIVERSITY CHENNAI
Program 5.4: Simple DB application to view the contents of a table in a dialog window.
1. First create a database dbs.mdb in MSAccess.
2. Then create a table named Student with the following columns in dbs.mdb: Name,
Roll_No, Age and Department.
3. Save the table and exit MSAccess.
4. Click the ODBC icon in the Windows Control Panel.
Figure 5.8 Registering Student Database
5. The Visual C++Setup program should have already installed the required ODBC
drivers on your hard disk. If you are running Windows 95, click the Drivers button
to see whether the Microsoft Access driver is available. If youre running Windows
98, click the Drivers tab to see whether the Microsoft Access driver is available.
(If the Microsoft Access driver is not available, rerun Visual C++Setup.) Click
the Add button (in Windows 98, the Add button is on the User DSN tab), choose
Microsoft Access Driver in the Add Data Source dialog box (in Windows
98, select the Microsoft Access Driver in the Create New Data Source dialog
box and click the Finish button), and fill in the ODBC Microsoft Access 97 Setup
dialog box as shown in figure 5.8.
Set the database to point to dbs.mdb using the Select button. Finally, click the OK
button.
DMC 1944
NOTES
256 ANNA UNIVERSITY CHENNAI
Figure 5.9 MFC AppWizard Step 2 of 6
1. Now open Visual C++and click the New item in the File menu, opening the New
dialog box.
2. Now select the MFC AppWizard(exe) entry in the New dialog box.
3. Give the new program the name DB in the Project name box.
4. Click Next button, There is a Question: What Database support would you
like to include?, click the radio button labeled Database View with File
Support.
5. Next, click the button labeled Data Source to open the Database Options box as
shown in figure 5.9.
Figure 5.10 Selecting ODBC Database
6. We select the ODBC button, and specify the dbs.mdb files as our Data source as
in figure 5.10.
VISUAL PROGRAMMING
NOTES
257 ANNA UNIVERSITY CHENNAI
7. When the Select Database Tables appears, click the Student table and the OK
button as in figure 5.11.
Figure 5.11 Select Database Tables Dialog Box
Figure 5.12 Dialog Window Design
8. Now we click the OK button and finish button in App Wizard, letting AppWizard
create the New Program.
9. Open the main view, IDD_DB_FORM, in the dialog editor, and add the following
controls: a button with caption Display the current records fields, four edit text
boxes & four static text boxes as shown in figure 5.12.
10. Using Class Wizard, we connect an event handler, OnButton1( ) to the button &
four member variable m_text1, m_text2, m_text3 and m_text4 to four text boxes.
DMC 1944
NOTES
258 ANNA UNIVERSITY CHENNAI
11. Add the following bold faced codes into the OnButton1( ) event handler:
void CDbvcView::OnButton1( )
{
m_text1=m_pSet->m_Name;
UpdateData(false);
m_text2=m_pSet->m_Roll_No;
UpdateData(false);
m_text3=m_pSet->m_Branch;
UpdateData(false);
m_text4=m_pSet->m_Semester;
UpdateData(false);
}
12. Run the application to find the window shown in figure 5.13 as an output. You can
click on the navigation buttons in the toolbar to navigate through the various records.
Figure 5.13 View table information
The above exercise allows the user just to view information from a table. Now lets
work on another program that will allow the user to view, add, modify and delete information
from a table.

RecordNavigationButtons
VISUAL PROGRAMMING
NOTES
259 ANNA UNIVERSITY CHENNAI
Program 5.5: Program to add, delete and modify records into a table.
1. Follow the steps 1 to 11 as given in program 5.4.
2. Selecten the resource view tab, and double click on the Dialog folder to open
the IDD_DB_FORM, in the dialog editor, and add the following controls: four
edit text boxes & four static text boxes as shown in figure 5.14.
Figure 5.14 Dialog Window Design
3. Use ClassWizard to link the edit controls to the recordset data members.
To add a data member, click on the Member Variables tab and choose the ID
corresponding to the edit box for each variable. Click the Add Variable button,
and click the arrow in the Member Variable Name combo box to display a list of
variables. Select only the appropriate variable, as shown in figure 5.15. When
youre finished adding variable names for each edit box, youll see a screen like
the one shown in figure 5.16.
4. Add menu commands. Add the following items to the Record pop-up menu in
the IDR_MAINFRAME menu as shown in figure 5.17. Also, use ClassWizard to
map the commands to the specified CDBView class members.
Menu
Command
Command ID Command Handler
U
Add Record ID_RECORD_ADD OnRecordAdd
Clear Fields ID_RECORD_CLEAR OnRecordClearfields
Delete Record ID_RECORD_DELETE OnRecordDelete OnU
Update Record ID_RECORD_UPDATE OnRecordUpdate OnU
DMC 1944
NOTES
260 ANNA UNIVERSITY CHENNAI
Figure 5.15 Linking control variables to Recordset data members
Figure 5.16 Class Wizard displaying Controls and corresponding Recordset
data members
VISUAL PROGRAMMING
NOTES
261 ANNA UNIVERSITY CHENNAI
Figure 5.17 Adding Menu
5. Add and override the OnMove function in the CDBView class. Invoke Class
Wizard, in the Message Map tab select CDBView from the ObjectID list box
and double click on the OnMove message handler from the Messages list box as
shown in figure 5.18. This will create the OnMove( ) function.
Figure 5.18 Adding OnMove function using Class Wizard
The CRecordView::OnMove function does the work of updating the database when
the user moves out of a record. Because we dont want this behavior, we must override
the function by adding the following bold faced codes inside the CDBView::OnMove( )
function:
DMC 1944
NOTES
262 ANNA UNIVERSITY CHENNAI
BOOL CDBView::OnMove(UINT nIDMoveCommand)
{
switch (nIDMoveCommand)
{
case ID_RECORD_PREV:
m_pSet->MovePrev();
if (!m_pSet->IsBOF())
break;
case ID_RECORD_FIRST:
m_pSet->MoveFirst();
break;
case ID_RECORD_NEXT:
m_pSet->MoveNext();
if (!m_pSet->IsEOF())
break;
if (!m_pSet->CanScroll()) {
// Clear screen since were currently in EOF
m_pSet->SetFieldNull(NULL);
break;
}
case ID_RECORD_LAST:
m_pSet->MoveLast();
break;
default:
// unexpected case value
ASSERT(FALSE);
}
// Show results of Move operation
UpdateData(FALSE);
return TRUE;
}
6. Edit the menu command handlers. The following functions call various
CRecordset member functions to edit the database. To add a record, you must
call CRecordset::AddNew, followed by Update. To modify a record, you must
call CRecordset::Edit, followed by Update. When you add a new record to the
database, you should call CRecordset::MoveLast because the new record is always
added to the end of the dynaset. Add the following boldface code:
VISUAL PROGRAMMING
NOTES
263 ANNA UNIVERSITY CHENNAI
void CDBView::OnRecordAdd( )
{
m_pSet->AddNew( );
UpdateData(TRUE);
if (m_pSet->CanUpdate( ))
{
m_pSet->Update( );
}
if (!m_pSet->IsEOF( ))
{
m_pSet->MoveLast( );
}
m_pSet->Requery( ); // for sorted sets
UpdateData(FALSE);
}
void CDBView::OnRecordClear( )
{
m_pSet->SetFieldNull(NULL);
UpdateData(FALSE);
}
void CDBView::OnRecordDelete()
{
CRecordsetStatus status;
try {
m_pSet->Delete( );
}
catch(CDBException* e) {
AfxMessageBox(e->m_strError);
e->Delete( );
m_pSet->MoveFirst( ); // lost our place!
UpdateData(FALSE);
return;
}
m_pSet->GetStatus(status);
if (status.m_lCurrentRecord == 0) {
// We deleted last of 2 records
m_pSet->MoveFirst( );
}
else {
m_pSet->MoveNext( );
}
UpdateData(FALSE);
}
DMC 1944
NOTES
264 ANNA UNIVERSITY CHENNAI
void CDBView::OnUpdateRecordDelete(CCmdUI* pCmdUI)
{
pCmdUI->Enable(!m_pSet->IsEOF( ));
}
void CDBView::OnRecordUpdate()
{
m_pSet->Edit( );
UpdateData(TRUE);
if (m_pSet->CanUpdate( )) {
m_pSet->Update();
}
// should requery if key field changed
}
void CDBView::OnUpdateRecordUpdate(CCmdUI* pCmdUI)
{
pCmdUI->Enable(!m_pSet->IsEOF( ));
}
Figure 5.19 DB Application window
7. Build and test the DB application again. Now you can add, change, and delete
records using the menu items. You may find an output window similar to the one
shown in figure 5.19.
VISUAL PROGRAMMING
NOTES
265 ANNA UNIVERSITY CHENNAI
5.9 TCP/IP
All networks use layering for their transmission protocols, and the collection of layers
is often called a stack. The application program talks to the top layer, and the bottom layer
talks to the network. Figure 5.20 shows you the stack for a local area network (LAN)
running TCP/IP. Each layer is logically connected to the corresponding layer at the other
end of the communications channel. The server program, continuously listens on one end
of the channel, while the client program, as shown on the left, periodically connects with
the server to exchange data. Think of the server as an HTTP-based World Wide Web
server, and think of the client as a browser program running on your computer.
Figure 5.20 The stack for a LAN running TCP/IP.
Figure 5.21 A simple IP datagram layout.
Application layer
Transport layer
Network layer
Link layer
HTTP protocol
TCP protocol
IP protocol
Ethernet protocol
Ethernet driver
IP
TCP
HTTP Client
DMC 1944
NOTES
266 ANNA UNIVERSITY CHENNAI
5.9.1 The Internet Protocol
The Internet Protocol (IP) defines packets called datagrams that are fundamental
units of Internet communication. These packets, typically less than 1000 bytes in length, go
bouncing all over the world when you open a Web page, download a file, or send e-mail.
Figure 5.21 shows a simplified layout of an IP datagram.
IP datagram contains 32-bit addresses for both the source and destination computers.
These IP addresses uniquely identify computers on the Internet and are used by routers
(specialized computers that act like telephone switches) to direct the individual datagrams
to their destinations.
The IP layer doesnt tell the sending program whether a datagram has successfully
reached its destination. The receiving program can look only at the checksum to determine
whether the IP datagram header was corrupted.
5.9.2 The Transmission Control Protocol
TCP is a protocol that supports error-free transmission of large blocks of data.
Obviously, you want the receiving program to be able to reassemble the bytes in the exact
sequence in which they are transmitted, even though the individual datagrams might arrive
in the wrong sequence. TCP is that protocol, and its the principal transport protocol for all
Internet applications, including HTTP and File Transfer Protocol (FTP). Figure 5.22 shows
the layout of a TCP segment. (Its not called a datagram.) The TCP segment fits inside an
IP datagram, as shown in Figure 5.23.
Figure 5.22 A simple layout of a TCP segment.
VISUAL PROGRAMMING
NOTES
267 ANNA UNIVERSITY CHENNAI
Figure 5.23 The relationship between an IP datagram and a TCP segment.
The TCP protocol establishes a full-duplex, point-to-point connection between two
computers, and a program at each end of this connection uses its own port. The combination
of an IP address and a port number is called a socket. The connection is first established
with a three-way handshake. The initiating program sends a segment with the SYN flag
set, the responding program sends a segment with both the SYN and ACK flags set, and
then the initiating program sends a segment with the ACK flag set.
After the connection is established, each program can send a stream of bytes to the
other program. TCP uses the sequence number fields together with ACK flags to control
this flow of bytes. The sending program doesnt wait for each segment to be acknowledged
but instead sends a number of segments together and then waits for the first acknowledgment.
If the receiving program has data to send back to the sending program, it can piggyback its
acknowledgment and outbound data together in the same segments.
The sending programs sequence numbers are not segment indexes but rather indexes
into the byte stream. The receiving program sends back the sequence numbers (in the
acknowledgment number field) to the sending program, thereby ensuring that all bytes are
received and assembled in sequence. The sending program resends unacknowledged
segments.
Each program closes its end of the TCP connection by sending a segment with the
FIN flag set, which must be acknowledged by the program on the other end. A program
can no longer receive bytes on a connection that has been closed by the program on the
other end.
The Winsock and WinInet APIs hides the complexity of the TCP protocol and most
of the details, so you dont have to worry about ACK flags and sequence numbers. Your
program calls a function to transmit a block of data, and Windows takes care of splitting
the block into segments and stuffing them inside IP datagrams. Windows also takes care of
delivering the bytes on the receiving end.
During the days of Windows 3.x, before networking was built into the Windows
operating system, you could buy the network protocols required for network
communications from numerous different companies. Each of these companies had a slightly
DMC 1944
NOTES
268 ANNA UNIVERSITY CHENNAI
different way that an application performed network communications. As a result, any
applications that performed network communications had a list of the different networking
software that the application would work with. Many application developers were not
happy with this situation. As a result, all the networking companies, including Microsoft,
got together and developed the Winsock (Windows Sockets) and WinInet API. This
provided all application developers with a consistent API to perform all network
communications, regardless of the networking software used.
The WinInet is an application-level API and supports only HTTP, FTP, and Gopher
protocols. While WinSock is set of low-level APIs and supports most of the protocols
described above.
5.9.3 WinInet Vs. WinSock
WinInet provides a higher level-programming interface, which is easy to use while WinSock,
is a low level interface, which is hard to implement. To implement WinSock, you should
have some knowledge of Windows Sockets and TCP/IP. While WinInet hides this all
from developers and does every thing under the hood.
WinInet provides support for only three protocols - HTTP, FTP, and Gopher while
WinSock let you work with most of the protocols. WinInet supports build-in-caching
which improves downloading performance. WinInet provides easy connections and has
support for proxy servers. WinInet provides more security over WinSock.
Basically choosing between WinInet and WinSock is pretty easy. If your application
needs to access HTTP, FTP, or Gopher protocols then WinInet is better choice, whille
WinSock is for rest.
5.9.4 WinInet and its application
WinInet is high level, easy-to-use API to work with HTTP, FTP, and Gopher protocols.
If you use WinInet, you dont have to worry about learning protocol specifications such as
TCP/IP or Windows Sockets.
WinInet may be used for the following cases:
1. HTTP, FTP, and gopher.
2. Download web pages, images, sounds, and video files.
3. Execute server files such as CGI scripts, ISAPI dlls, or ASP scripts.
4. Access remote database and file systems.
5. Perform web searches.
6. Download and Upload files between computers.
VISUAL PROGRAMMING
NOTES
269 ANNA UNIVERSITY CHENNAI
5.9.4.1 Functions of WinInet
The different Internet protocols (such as ftp and http) use several of the same
WinINet functions to handle information on the Internet. These common functions
handle their tasks in a consistent manner, regardless of the particular protocol to
which they are being applied. Applications can use these functions to create general-
purpose functions that handle tasks across the different protocols (such as reading
files for ftp and http).
InternetOpen
This function is root of all WinInet functions, and must be called before any
WinInet function. The InternetOpen function initializes WinInet environment and
prepares to call other WinInet functions. Basically this function starts a new Internet
session. The WinInet is based on hierarchy so next level function will require the
handle returned by InternetOpen.
After initializing WinInet, there are two ways to work with Internet. Either URL
related requirement, or protocol related requirement. InternetConnect function is
followed by protocol related functions and InternetOpenUrl is related to URLs.
InternetOpenUrl is used to download a web page, downoad an image via HTTP,
download a file via FTP, or download a file via Gopher.
InternetConnect
InternetConnect is used for HTTP POST/GET headers to send and retrieve data,
work with FTP such as create, rename, delete directories or upload/download file, use
gopher locators. InternetConnect is responsible for starting new HTTP, FTP, or Gopher
session after establishing a connection using InternetOpen. A single application can have
multiple InternetConnect objects, depends on the requirement of the application.
InternetCloseHandle
This function closes opened Internet connection and terminates any pending operations
on the handle and discards any outstanding data.
InternetOpenUrl
InternetOpenUrl is a general function that an application can use to retrieve data
over any of the protocols that the Win32 Internet functions support. This function is
particularly useful when the application does not need to access the particulars of a protocol,
but only requires the data corresponding to a URL.
The InternetOpenUrl function parses the URL string, establishes a connection to the
server, and prepares to download the data identified by the URL. The application can then
DMC 1944
NOTES
270 ANNA UNIVERSITY CHENNAI
use InternetReadFile (for files) or InternetFindNextFile (for directories) to retrieve the
URL data. It is not necessary to call InternetConnect before InternetOpenUrl.
Program 5.6: Using InternetOpenUrl to download a URL.
1. Create a dialog based application as shown in figure 5.24 with two buttons and
two edit boxes. Set content edit boxs as multiline.
Figure 5.24 Working with InternetOpenUrl
2. Add two variables using Class wizard, m_strURL and m_strContents, for each
edit boxes.
3. Include <wininet.h>in your stdafx.h and link to wininet.lib in your project
settings.
WinInet.lib is in your Lib directory of Visual Studio.
4. And add a handler for Download button using Class Wizard and add this piece of
code:
voidCOpenUrlDlg::OnOk( )
{
UpdateData(TRUE);
if ( m_strURL.IsEmpty( ) )
return;
HINTERNEThINet,hFile;
hINet =InternetOpen(InetURL/
1.0,INTERNET_OPEN_TYPE_PRECONFIG,NULL, NULL, 0 );
if ( !hINet )
{
AfxMessageBox(InternetOpen Failed);
return;
}
hFile =InternetOpenUrl( hINet, m_strURL, NULL, 0, 0, 0 ) ;
VISUAL PROGRAMMING
NOTES
271 ANNA UNIVERSITY CHENNAI
if ( hFile )
{
CHAR buffer[1024];
DWORD dwRead;
while ( InternetReadFile( hFile, buffer, 1023, &dwRead ) )
{
if ( dwRead ==0 )
break;
buffer[dwRead] =0;
m_strURL +=buffer;
}
InternetCloseHandle( hFile );
}
InternetCloseHandle( hINet );
UpdateData(FALSE);
}
5. Now run your program, type URL with http and hit Download. You will see source
code of the URL you have entered.
6. Dont forget to include wininet.h #include <wininet.h>in your stdafx.h.
The MFC classes closely mirror the underlying WinInet architecture, and they add
exception processing. These classes are summarized below:
CInternetSession
You need only one CInternetSession object for each thread that accesses the Internet.
After you have your CInternetSession object, you can establish HTTP, FTP, or gopher
connections or you can open remote files directly by calling the OpenURL member function.
You can use the CInternetSession class directly, or you can derive a class from it in order
to support status callback functions.
The CInternetSession constructor calls the WinInet InternetOpen function, which
returns an HINTERNET session handle that is stored inside the CInternetSession object.
This function initializes your applications use of the Win- Inet library, and the session
handle is used internally as a parameter for other WinInet calls.
CHttpConnection
An object of class CHttpConnection represents a permanent HTTP connection to
a particular host. You know already that HTTP doesnt support permanent connections
and that FTP doesnt either. (The connections last only for the duration of a file transfer.)
WinInet gives the appearance of a permanent connection because it remembers the host
name.
After you have your CInternetSession object, you call the GetHttpConnection member
function, which returns a pointer to a CHttpConnection object. (Dont forget to delete this
object when you are finished with it.)
DMC 1944
NOTES
272 ANNA UNIVERSITY CHENNAI
The GetHttpConnection member function calls the WinInet InternetConnect function,
which returns an HINTERNET connection handle that is stored inside the CHttpConnection
object and used for subsequent WinInet calls.
CFtpConnection, CGopherConnection
These classes are similar to CHttpConnection, but they use the FTP and gopher
protocols. The CFtpConnection member functions GetFile and PutFile allow you to transfer
files directly to and from your disk.
CInternetFile
With HTTP, FTP, or gopher, your client program reads and writes byte streams. The
MFC WinInet classes make these byte streams look like ordinary files. If you look at the
class hierarchy, youll see that CInternetFile is derived from CStdioFile, which is derived
from CFile. Therefore, CInternetFile and its derived classes override familiar CFile functions
such as Read and Write. For FTP files, you use CInternetFile objects directly, but for
HTTP and gopher files, you use objects of the derived classes CHttpFile and CGopherFile.
You dont construct a CInternetFile object directly, but you call CFtpConnection::OpenFile
to get a CInternetFile pointer.
If you have an ordinary CFile object, it has a 32-bit HANDLE data member that
represents the underlying disk file. A CInternetFile object uses the same m_hFile data
member, but that data member holds a 32-bit Internet file handle of type HINTERNET,
which is not interchangeable with a HANDLE. The CInternetFile overridden member
functions use this handle to call WinInet functions such as InternetReadFile and
InternetWriteFile.
CHttpFile
This Internet file class has member functions that are unique to HTTP files, such as
AddRequestHeaders, SendRequest, and GetFileURL. You dont construct a CHttpFile
object directly, but you call the CHttpConnection::OpenRequest function, which calls the
WinInet function HttpOpenRequest and returns a CHttpFile pointer. You can specify a
GET or POST request for this call.
Once you have your CHttpFile pointer, you call the CHttpFile::SendRequest member
function, which actually sends the request to the server. Then you call Read.
CFtpFileFind, CGopherFileFind
These classes let your client program explore FTP and gopher directories.
CInternetException
The MFC WinInet classes throw CInternetException objects that your program can
process with try/catch logic.
VISUAL PROGRAMMING
NOTES
273 ANNA UNIVERSITY CHENNAI
Program 5.7: Creating Internet Applications using HTTP.
1. Open Visual C++and click the New item in the File menu, opening the New
dialog box.
2. Now select the MFC AppWizard(exe) entry in the New dialog box.
3. Give the new program the name http in the Project name box.
4. Click OK to starts the Visual C++AppWizard.
5. Click the option marked Dialog Based in the AppWizard, click Finish.
6. Add a text box and a button. The button ha Download the Web Page as its
caption.
7. Connect an event handler, OnButton1( ), to the button.
8. Well create a new Internet Session. This Internet Session is actually an object of
the MFC CInternetSession class, and this class is the basis of Visual C++Internet
support.
9. Also add the line #include<afxinet.h> to make sure we can use the Internet
components.
// httpDlg.cpp : implementation file
.
.
.
#include afxinet.h
.
.
.
10. Weve set aside a pointer, pInternetSession, for our new Internet session and we
create the session now.
11. If computer is not connected to the Internet, the program will display a connect
box and make the connection. If connection failed, we should terminate the program.
12. Well use the CInternetSession classs OpenURL( ) method to open a web page
for HTTP transfer. This returns a pointer to a file object of class CStdioFile and
save that pointer as pFile.
13. Now we have a pointer to a file object representing the Web page we want to
work with, and we can treat it just like a file.
14. If we want to download the files first 1000 bytes, we do it by setting up a buffer
for our data and using the Read( ) method.
15. To display the data received, we connect a member variable, m_text, to the text
box in our program and places the downloaded text in that text box.
16. We close the file weve opened and Internet Session.
17. The above mentioned steps 10 to 16 will result in the following lines of code in the
OnButton1( ) event handler:
DMC 1944
NOTES
274 ANNA UNIVERSITY CHENNAI
void CHtttpDlg::OnButton1()
{
CInternetSession* pInternetSession; //Step 10
pInternetSession=new CInternetSession(); //Step 10
if(!pInternetSession) //Step 11
{
AfxMessageBox(Could not establish Internet Session,MB_OK);
return;
}
CStdioFile* pFile=NULL; //Step 12
char* buffer; //Step 14
buffer=new char[1000]; //Step 14
pFile=pInternetSession
OpenURL(CString(http://www.microsoft.com));
//Step 12
pFile->Read(buffer,1000); //Step 14
m_text=CString(buffer,1000); //Step 15
UpdateData(false);
pFile->Close(); //Step 16
pInternetSession->Close(); //Step 16
}
18. When you execute the application with a it will display a window as shown in
figure 5.25 as an output.
Figure 5.25 Downloading a Web Page
VISUAL PROGRAMMING
NOTES
275 ANNA UNIVERSITY CHENNAI
5.9.4.2 WinInet FTP MFC Classes
FTP Classes
CFtpConnection and CFtpFindFile are two FTP classes, which encapsulate all
MFC APIs.
CFtpConnection
This class manages connection to your FTP server and allows direct manipulation of
files and directories on the server. You always create a CFtpConnection object using
CInternetSession::GetFtpConnection. All member of this class are easy to understand.
CFtpFindFile
CFtpFindFile is used to find a file on the server.
Lets see how to use the above mentioned class and methods for developing an
internet application.
Program 5.8: Creating Internet Applications using FTP.
1. Open Visual C++and click the New item in the File menu, opening the New
dialog box.
2. Now select the MFC AppWizard(exe) entry in the New dialog box.
3. Give the new program the name ftp in the Project name box.
4. Click OK to start the Visual C++AppWizard.
Members Description
SetCurrentDirectory Sets the current FTP directory.
GetCurrentDirectory Gets the current FTP directory.
GetCurrentDirectoryAsURL Get current dir as a URL.
RemoveDirectory Removes the specified dir.
CreateDirectory Creates a new dir.
Rename Rename a file or a dir.
Remove Removes a file.
PutFile Uploads a file to the server.
GetFile Download a file from the server.
OpenFile Opens a file and returns a pointer to
CInternetFile.
Close Closes the connection.
Members Description
FindFile Finds a file on the server. It returns nonzero if
successful, otherwise 0.
FindNextFile Use to continue to search for a file, which you
started with FindFile.
GetFileURL Gets the URL for a specified file.
DMC 1944
NOTES
276 ANNA UNIVERSITY CHENNAI
5. Click the option marked Dialog Based in the AppWizard, click Finish.
6. Add a text box and a button with the caption Download the File.
7. Connect an event handler, OnButton1( ), to the button and member variable,
m_text, to the text box.
8. Well create a new Internet Session. This Internet Session is actually an object of
the MFC CInternetSession class, and this class is the basis of Visual C++Internet
support.
9. Also add the line #include<afxinet.h> to make sure we can use the Internet
components.
// httpDlg.cpp : implementation file
.
.
.
#include afxinet.h
.
.
.
10. Weve set aside a pointer, pInternetSession, for our new Internet session and we
create the session now.
11. If computer is not connected to the Internet, the program will display a connect
box and make the connection. If connection failed, we should terminate the program.
12. We create pointer to the class CFtpConnection named pFTPConnection. This
class represents the FTP support in VC++.
13. To create this new object, we call the CInternetSession classs
GetFtpConnection( ) method to make an anonymous FTP connection to the
Microsoft site, passing that method the name of the FTP site we want to connect
to, ftp.microsoft.com.
14. If we were unsuccessful in connecting to the FTP site, we display an error message
and finish up.
15. Otherwise, we indicate that we have started the downloading process by placing
the message Downloading in the text box.
16. We close the FTP connection and the Internet session at the end of OnButton1( ).
17. The above mentioned steps 10 to 16 will result in the following lines of code in the
OnButton1( ) event handler:
void CFtpDlg::OnButton1()
{
CInternetSession* pInternetSession; // Step 10
CFtpConnection* pFTPConnection; // Step 12
VISUAL PROGRAMMING
NOTES
277 ANNA UNIVERSITY CHENNAI
pInternetSession=new CInternetSession(); // Step 11
if(!pInternetSession) // Step 11
{
AfxMessageBox(Could not establish Internet session,MB_OK);
return;
}
pFTPConnection=pInternetSession
GetFtpConnection(CString(ftp.microsoft.com));
// Step 13
if(!pFTPConnection) // Step 14
{
AfxMessageBox(Could not establish FTP connection. ,MB_OK);
return;
}
else // Step 15
{
m_text=Downloading.....;
UpdateData(false);
}
pFTPConnection
GetFile(CString(disclaimer.txt),CString(disclaimer.txt));
pFTPConnection->Close(); // Step 16
pInternetSession->Close(); // Step 16
}
18. When you execute the application it will display a window as shown in figure
5.26 and when you click the button it starts downloading the URL.
Figure 5.26 Downloading a web site using FTP
DMC 1944
NOTES
278 ANNA UNIVERSITY CHENNAI
5.9.5 Winsock
Winsock is the lowest level Windows API for TCP/IP programming. Winsock defines
a standard service provider interface (SPI) between the application programming interface
(API), with its functions exported from WS2_32.dll and the protocol stacks. Consequently,
Winsock support is not limited to TCP/IP protocol stacks as is the case for Windows
Sockets 1.1. Part of the code is located in wsock32.dll (the exported functions that your
program calls), and part is inside the Windows kernel. You can write both internet server
programs and internet client programs using the Winsock API. This API is based on the
original Berkely Sockets API for UNIX. A new and much more complex version, Winsock
2, is included for the first time with Windows NT 4.0.
With the Windows Sockets 2 architecture, it is not necessary or desirable, for stack
vendors to supply their own implementation of WS2_32.dll, since a single WS2_32.dll
must work across all stacks. The WS2_32.dll and compatibility shims should be viewed in
the same way as an operating system component. The Windows Sockets 2 architecture is
compliant with the Windows Open System Architecture (WOSA), as illustrated in figure
5.27:
Figure 5.27 Windows Sockets 2 architecture
Windows
Sockets 2
Application
Windows
Sockets 2
Application
Windows Sockets 2
API
Windows Sockets 2
Transport SPI
Windows Sockets 2
Name Space SPI
Name Space Functions
Transport Functions
Transport
Service
Provider
Transport
Service
Provider
Name Space
Service
Provider
Name Space
Service
Provider
WS2_32.DLL
VISUAL PROGRAMMING
NOTES
279 ANNA UNIVERSITY CHENNAI
The following is a step-by-step guide to getting started with Windows Sockets
programming. It is designed to provide an understanding of basic Winsock functions and
data structures, and how they work together. There are two distinct types of socket network
applications: Server and Client. Servers and Clients have different behaviors; therefore,
the process of creating them is different. What follows is the general model for creating a
streaming TCP/IP Server and Client. The client and server application that is used for
illustration is a very basic client and server. The following segment shows the various steps
involved in creating the client and server program.
Server
1. Initialize Winsock.
2. Create a socket.
3. Bind the socket.
4. Listen on the socket for a client.
5. Accept a connection from a client.
6. Receive and send data.
7. Disconnect.
Client
1. Initialize Winsock.
2. Create a socket.
3. Connect to the server.
4. Send and receive data.
5. Disconnect.
Now let us visualize these steps in the form of an application program.
To create a basic Winsock application, adhere to the steps given below:
1. Create a new empty project.
2. Add an empty C++source file to the project.
3. Ensure that the build environment refers to the Include, Lib, and Src directories of
the Microsoft Windows Software Development Kit (SDK) or the earlier Platform
Software Development Kit (SDK).
4. Ensure that the build environment links to the Winsock Library file Ws2_32.lib.
Applications that use Winsock must be linked with the Ws2_32.lib library file.
The #pragma comment indicates to the linker that the Ws2_32.lib file is needed.
5. Begin programming the Winsock application by including the code given belwo.
Use the Winsock API by including the Winsock 2 header files. The Winsock2.h
header file contains most of the Winsock functions, structures, and definitions. The
Ws2tcpip.h header file contains definitions introduced in the WinSock 2 Protocol-
Specific Annex document for TCP/IP that includes newer functions and structures
used to retrieve IP addresses.
DMC 1944
NOTES
280 ANNA UNIVERSITY CHENNAI
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#pragma comment(lib, Ws2_32.lib)
int main( ) {
return 0;
}
To initialize Winsock (both for client and server) - All processes (applications or
DLLs) that call Winsock functions must initialize the use of the Windows Sockets DLL
before making other Winsock functions calls. This also makes certain that Winsock is
supported on the system.
1. Create a WSADATA object called wsaData.
WSADATA wsaData;
2. Call WSAStartup and return its value as an integer and check for errors.
int iResult;
// Initialize Winsock
iResult =WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult !=0) {
printf(WSAStartup failed: %d\n, iResult);
return 1;
}
The WSAStartup function is called to initiate use of WS2_32.dll. The WSADATA
structure contains information about the Windows Sockets implementation. The
MAKEWORD(2,2) parameter of WSAStartup makes a request for version 2.2 of
Winsock on the system, and sets the passed version as the highest version of Windows
Sockets support that the caller can use.
Creating a Socket for the Client - After initialization, a SOCKET object must be
instantiated for use by the client.
1. Declare an addrinfo object that contains a sockaddr structure and initialize these
values. For this application, the Internet address family is unspecified so that either
an IPv6 or IPv4 address can be returned. The application requests the socket
type to be a stream socket for the TCP protocol.
struct addrinfo *result =NULL,
*ptr =NULL,
hints;
ZeroMemory( &hints, sizeof(hints) );
hints.ai_family =AF_UNSPEC;
hints.ai_socktype =SOCK_STREAM;
hints.ai_protocol =IPPROTO_TCP;
VISUAL PROGRAMMING
NOTES
281 ANNA UNIVERSITY CHENNAI
2. Call the getaddrinfo function requesting the IP address for the server name passed
on the command line. The TCP port on the server that the client will connect to is
defined by DEFAULT_PORT as 27015 in this sample. The getaddrinfo function
returns its value as an integer that is checked for errors.
#define DEFAULT_PORT 27015
// Resolve the server address and port
iResult =getaddrinfo(argv[1], DEFAULT_PORT, &hints, &result);
if (iResult !=0) {
printf(getaddrinfo failed: %d\n, iResult);
WSACleanup();
return 1;
}
3. Create a SOCKET object called ConnectSocket.
SOCKET ConnectSocket =INVALID_SOCKET;
4. Call thesocket function and return its value to the ConnectSocket variable. For
this application, use the first IP address returned by the call to getaddrinfo that
matched the address family, socket type, and protocol specified in the hints
parameter. In this example, a TCP stream socket was specified with a socket type
of SOCK_STREAM and a protocol of IPPROTO_TCP. The address family
was left unspecified (AF_UNSPEC), so the returned IP address could be either
an IPv6 or IPv4 address for the server.
If the client application wants to connect using only IPv6 or IPv4, then the address
family needs to be set to AF_INET6 for IPv6 or AF_INET for IPv4 in the hints
parameter.
// Attempt to connect to the first address returned by the call to getaddrinfo
ptr=result;
// Create a SOCKET for connecting to server
ConnectSocket =socket(ptr->ai_family, ptr->ai_socktype,
ptr->ai_protocol);
5. Check for errors to ensure that the socket is a valid socket.
if (ConnectSocket ==INVALID_SOCKET) {
printf(Error at socket(): %ld\n, WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
return 1;
}
The parameters passed to the socket function can be changed for different
implementations.
DMC 1944
NOTES
282 ANNA UNIVERSITY CHENNAI
Error detection is a key part of successful networking code. If the socket call fails, it
returns INVALID_SOCKET. The if statement in the previous code is used to catch any
errors that may have occurred while creating the socket. WSAGetLastError returns an
error number associated with the last error that occurred. WSACleanup is used to terminate
the use of the WS2_32 DLL.
Creating a Socket for the Server - After initialization, a SOCKET object must be
instantiated for use by the server.
1. The getaddrinfo function is used to determine the values in the sockaddr structure:
AF_INET is used to specify the IPv4 address family.
SOCK_STREAM is used to specify a stream socket.
IPPROTO_TCP is used to specify the TCP protocol .
AI_PASSIVE flag indicates the caller intends to use the returned
socket address structure in a call to the bind function. When the
AI_PASSIVE flag is set and nodename parameter to the getaddrinfo
function is a NULL pointer, the IP address portion of the socket address
structure is set to I NADDR_ANY for I Pv4 addresses or
IN6ADDR_ANY_INIT for IPv6 addresses.
27015 is the port number associated with the server that the client
will connect to.
The addrinfo structure is used by the getaddrinfo function.
#define DEFAULT_PORT 27015
struct addrinfo *result =NULL, *ptr =NULL, hints;
ZeroMemory(&hints, sizeof (hints));
hints.ai_family =AF_INET;
hints.ai_socktype =SOCK_STREAM;
hints.ai_protocol =IPPROTO_TCP;
hints.ai_flags =AI_PASSIVE;
// Resolve the local address and port to be used by the server
iResult =getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
if (iResult !=0) {
printf(getaddrinfo failed: %d\n, iResult);
WSACleanup();
return 1;
}
2. Create a SOCKET object called ListenSocket for the server to listen for client
connections.
SOCKET ListenSocket =INVALID_SOCKET;
VISUAL PROGRAMMING
NOTES
283 ANNA UNIVERSITY CHENNAI
3. Call the socket function and return its value to the ListenSocket variable. For this
server application, use the first IP address returned by the call to getaddrinfo that
matched the address family, socket type, and protocol specified in the hints
parameter. In this example, a TCP stream socket for IPv4 was requested with an
address family of IPv4, a socket type of SOCK_STREAM and a protocol of
IPPROTO_TCP. So an IPv4 address is requested for the ListenSocket.
If the server application wants to listen on IPv6, then the address family needs to
be set to AF_INET6 in the hints parameter. If a server wants to listen on both
IPv6 and IPv4, two listen sockets must be created, one for IPv6 and one for
IPv4. These two sockets must be handled separately by the application.
Windows Vista and later offer the ability to create a single IPv6 socket that is put
in dual stack mode to listen on both IPv6 and IPv4.
// Create a SOCKET for the server to listen for client connections
ListenSocket =socket(result->ai_family, result->ai_socktype, result-
>ai_protocol);
4. Check for errors to ensure that the socket is a valid socket.
if (ListenSocket ==INVALID_SOCKET) {
printf(Error at socket(): %ld\n, WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
return 1;
}
Client Connecting to a Socket - For a client to communicate on a network, it must
connect to a server.
Call the connect function, passing the created socket and the sockaddr structure as
parameters. Check for general errors.
// Connect to server.
iResult =connect( ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (iResult ==SOCKET_ERROR) {
closesocket(ConnectSocket);
ConnectSocket =INVALID_SOCKET;
}
// Should really try the next address returned by getaddrinfo if the connect call
failed. But for this // simple example we just free the resources returned by
getaddrinfo and print an error message
DMC 1944
NOTES
284 ANNA UNIVERSITY CHENNAI
freeaddrinfo(result);
if (ConnectSocket ==INVALID_SOCKET) {
printf(Unable to connect to server!\n);
WSACleanup();
return 1;
}
The getaddrinfo function is used to determine the values in the sockaddr structure.
In this example, the first IP address returned by the getaddrinfo function is used to specify
the sockaddr structure passed to the connect. If the connect call fails to the first IP
address, then try the next addrinfo structure in the linked list returned from the getaddrinfo
function.
The information specified in the sockaddr structure includes:
the IP address of the server that the client will try to connect to.
the port number on the server that the client will connect to. This port was specified
as port 27015 when the client called the getaddrinfo function.
Server Binding a Socket - For a server to accept client connections, it must be
bound to a network address within the system. The following code demonstrates how to
bind a socket that has already been created to an IP address and port. Client applications
use the IP address and port to connect to the host network.
1. The sockaddr structure holds information regarding the address family, IP address,
and port number.
2. Call the bind function, passing the created socket and sockaddr structure returned
from the getaddrinfo function as parameters. Check for general errors.
// Setup the TCP listening socket
iResult =bind( ListenSocket, result->ai_addr, (int)result->ai_addrlen);
if (iResult ==SOCKET_ERROR) {
printf(bind failed with error: %d\n, WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
WSACleanup();
return 1;
}
Once the bind function is called, the address information returned by the getaddrinfo
function is no longer needed. The freeaddrinfo function is called to free the memory
allocated by the getaddrinfo function for this address information.
freeaddrinfo(result);
VISUAL PROGRAMMING
NOTES
285 ANNA UNIVERSITY CHENNAI
Server Listening on a Socket - After the socket is bound to an IP address and port
on the system, the server must then listen on that IP address and port for incoming connection
requests.
Call the listen function, passing as parameters the created socket and a value for the
backlog, maximum length of the queue of pending connections to accept. In this example,
the backlog parameter was set to SOMAXCONN. This value is a special constant that
instructs the Winsock provider for this socket to allow a maximum reasonable number of
pending connections in the queue. Check the return value for general errors.
if ( listen( ListenSocket, SOMAXCONN ) ==SOCKET_ERROR ) {
printf( Listen failed with error: %ld\n, WSAGetLastError() );
closesocket(ListenSocket);
WSACleanup();
return 1;
}
Server Accepting a Connection - Once the socket is listening for a connection, the
program must handle connection requests on that socket.
1. Create a temporary SOCKET object called ClientSocket for accepting
connections from clients.
SOCKET ClientSocket;
2. Normally a server application would be designed to listen for connections from
multiple clients. For high-performance servers, multiple threads are commonly
used to handle the multiple client connections.
3. There are several different programming techniques using Winsock that can be
used to listen for multiple client connections. One programming technique is to
create a continuous loop that checks for connection requests using the listen function
(see Listening on a Socket). If a connection request occurs, the application calls
the accept, AcceptEx, or WSAAccept function and passes the work to another
thread to hand0le the request. Several other programming techniques are possible.
Note that this basic example is very simple and does not use multiple threads. The
example also just listens for and accepts only a single connection.
ClientSocket =INVALID_SOCKET;
// Accept a client socket0
ClientSocket =accept(ListenSocket, NULL, NULL);
if (ClientSocket ==INVALID_SOCKET) {
printf(accept failed: %d\n, WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
DMC 1944
NOTES
286 ANNA UNIVERSITY CHENNAI
4. When the client connection has been accepted, a server application would normally
pass the accepted client socket (the ClientSocket variable in the above sample
code) to a worker thread or an I/O completion port and continue accepting
additional connections. In this basic example, the server continues to the next step.
Sending and Receiving Data on the Client - The following code demonstrates
the send and recv functions used by the client once a connection is established.
#define DEFAULT_BUFLEN 512
int recvbuflen =DEFAULT_BUFLEN;
char *sendbuf =this is a test;
char recvbuf[DEFAULT_BUFLEN];
int iResult;
// Send an initial buffer
iResult =send(ConnectSocket, sendbuf, (int) strlen(sendbuf), 0);
if (iResult ==SOCKET_ERROR) {
printf(send failed: %d\n, WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 1;
}
printf(Bytes Sent: %ld\n, iResult);
// shutdown the connection for sending since no more data will be sent
// the client can still use the ConnectSocket for receiving data
iResult =shutdown(ConnectSocket, SD_SEND);
if (iResult ==SOCKET_ERROR) {
printf(shutdown failed: %d\n, WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 1;
}
// Receive data until the server closes the connection
do {
iResult =recv(ConnectSocket, recvbuf, recvbuflen, 0);
if (iResult >0)
printf(Bytes received: %d\n, iResult);
else if (iResult ==0)
printf(Connection closed\n);
else
printf(recv failed: %d\n, WSAGetLastError());
} while (iResult >0);
VISUAL PROGRAMMING
NOTES
287 ANNA UNIVERSITY CHENNAI
The send and recv functions both return an integer value of the number of bytes sent
or received, respectively, or an error. Each function also takes the same parameters: the
active socket, a char buffer, the number of bytes to send or receive, and any flags to use.
Receiving and Sending Data on the Server - The following code demonstrates
the recv and send functions used by the server.
#define DEFAULT_BUFLEN 512
char recvbuf[DEFAULT_BUFLEN];
int iResult, iSendResult;
int recvbuflen =DEFAULT_BUFLEN;
// Receive until the peer shuts down the connection
do {
iResult =recv(ClientSocket, recvbuf, recvbuflen, 0);
if (iResult >0) {
printf(Bytes received: %d\n, iResult);
// Echo the buffer back to the sender
iSendResult =send(ClientSocket, recvbuf, iResult, 0);
if (iSendResult ==SOCKET_ERROR) {
printf(send failed: %d\n, WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
printf(Bytes sent: %d\n, iSendResult);
} else if (iResult ==0)
printf(Connection closing...\n);
else {
printf(recv failed: %d\n, WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
} while (iResult >0);
The send and recv functions both return an integer value of the number of bytes sent
or received, respectively, or an error. Each function also takes the same parameters: the
active socket, a char buffer, the number of bytes to send or receive, and any flags to use.
DMC 1944
NOTES
288 ANNA UNIVERSITY CHENNAI
Disconnecting the Client - Once the client is completed sending and receiving
data, the client disconnects from the server and shutdowns the socket.
1. When the client is done sending data to the server, the shutdown function can be
called specifying SD_SEND to shutdown the sending side of the socket. This
allows the server to release some of the resources for this socket. The client
application can still receive data on the socket.
// shutdown the send half of the connection since no more data will be sent
iResult =shutdown(ConnectSocket, SD_SEND);
if (iResult ==SOCKET_ERROR) {
printf(shutdown failed: %d\n, WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 1;
}
2. When the client application is done receiving data, the closesocket function is
called to close the socket. When the client application is completed using the
Windows Sockets DLL, the WSACleanup function is called to release resources.
// cleanup
closesocket(ConnectSocket);
WSACleanup();
return 0;
Disconnecting the Server - Once the server is completed receiving data from the
client and sending data back to the client, the server disconnects from the client and
shutdowns the socket.
1. When the server is done sending data to the client, the shutdown function can be
called specifying SD_SEND to shutdown the sending side of the socket. This
allows the client to release some of the resources for this socket. The server
application can still receive data on the socket.
// shutdown the send half of the connection since no more data will be sent
iResult =shutdown(ClientSocket, SD_SEND);
if (iResult ==SOCKET_ERROR) {
printf(shutdown failed: %d\n, WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
VISUAL PROGRAMMING
NOTES
289 ANNA UNIVERSITY CHENNAI
2. When the client application is done receiving data, theclosesocket function is
called to close the socket. When the client application is completed using the
Windows Sockets DLL, the WSACleanup function is called to release resources.
// cleanup
closesocket(ClientSocket);
WSACleanup();
return 0;
Running the Winsock Client and Server Code Sample
The server application should be started before the client application is started.
To execute the server, compile the complete server source code and run the executable
file. The server application listens on TCP port 27015 for a client to connect. Once a client
connects, the server receives data from the client and echoes (sends) the data received
back to the client. When the client shuts down the connection, the server shuts down the
client socket, closes the socket, and exits.
To execute the client, compile the complete client source code and run the executable
file. The client application requires that name of the computer or IP address of the computer
where the server application is running is passed as a command-line parameter when the
client is executed. If the client and server are executed on the sample computer, the client
can be started as follows:
client localhost
The client tries to connect to the server on TCP port 27015. Once the client connects,
the client sends data to the server and receives any data send back from the server. The
client then closes the socket and exits.
Several more advanced Winsock client and server samples are included with the
Windows SDK. The readers can try out the other examples.
5.10 ACTIVEX CONTROLS
An ActiveX control is a set of functionality packaged in a COM (Component Object
Model) object. This COM object is self-contained, although it does not have the ability to
run by itself. An ActiveX control can only run within a ActiveX container, such as a Visual
C++or Visual Basic application.
ActiveX controls provide a series of interfaces used by the container application to
trigger the various sets of functionality contained in the control. Many of these interfaces
are used for triggering events in the control or in the containing application. Others are for
specifying the property page of the control or for communicating whether the control has
been activated. All in all, so many interfaces are built into most ActiveX controls that
coding the functionality for each of these interfaces yourself would take quite some time.
Luckily, the Visual C++App and Class Wizards add much of this functionality for you,
allowing you to focus on the specific functionality that the control is supposed to have.
DMC 1944
NOTES
290 ANNA UNIVERSITY CHENNAI
Among the aspects of the control you create that you still must plan yourself are what
properties, methods, and events you will expose for your control. You can add these
elements to your control through the Class Wizard, but if any of the properties or events
require special code on your part, then you must add it yourself. As should be expected
with any methods that you add to your controls, you have to supply all of the code. The
Class Wizard will add the surrounding structure and code to allow the containing application
to see and call the method, just as it will add all the code necessary to call any event
handlers for your applications.
5.10.1 Creating and using ActiveX Controls
Developers have been able to use MFC to create ActiveX controls. However, one of
the downsides of using MFC to create ActiveX controls is that the controls become bound
to MFC. Sometimes you want your controls to be smaller or to work even if the end user
doesnt have the MFC DLLs on his or her system. In addition, using MFC to create
ActiveX controls forces you into making certain design decisions. For example, if you
decide to use MFC to write an ActiveX control, you more or less lock yourself out of
using dual interfaces. Using MFC to create ActiveX controls also means the control and its
property pages need to use IDispatch to communicate between themselves.
To avoid the problems described so far, developers can now use ATL to create
ActiveX controls. ATL now includes the facilities to create full-fledged ActiveX controls,
complete with every feature an ActiveX control should have. These features include incoming
interfaces, persistent properties, property pages, and connection points. If youve ever
written an ActiveX control using MFC, youll see how much more flexible using ATL
can be. Lets first try creating an ActiveX control using SDK type programming.
Program 5.9: Creating an ActiveX control.
1. Open Visual C++and click the New item in the File menu, opening the New
dialog box.
2. Now select the MFC ActiveX ControlWizard entry in the New dialog box.
3. Give the new program the name boxer in the Project name box.
4. Accept all the defaults by pressing the Finish button.
5. We have to divide the control into four rectangles, naming those rectangles box1
to box4 and declaring them in BoxerCtl.h:
class CBoxerCtrl : public COleControl
{
.
.
.
VISUAL PROGRAMMING
NOTES
291 ANNA UNIVERSITY CHENNAI
// Implementation
protected:
~CBoxerCtrl();
CRect box1;
CRect box2;
CRect box3;
CRect box4;
.
.
.
};
6. Now, we have four rectangles to divide the control up in OnDraw( ), placing the
four boxes at upper left, upper right, lower left, and lower right.
7. Then we draw the four rectangles.
void CBoxerCtrl::OnDraw(CDC* pdc, const CRect& rcBounds, const CRect&
rcInvalid)
{
pdc->FillRect(rcBounds,
CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));
box1=CRect(rcBounds.left, rcBounds.top, rcBounds.right/2,
rcBounds.bottom/2);
box2=CRect(rcBounds.left, rcBounds.bottom/2, rcBounds.right/2,
rcBounds.bottom);
box3=CRect(rcBounds.right/2, rcBounds.top, rcBounds.right,
rcBounds.bottom/2);
box4=CRect(rcBounds.right/2, rcBounds.bottom/2, rcBounds.right,
rcBounds.bottom);
pdc->Rectangle(&box1); //Step 7
pdc->Rectangle(&box2); //Step 7
pdc->Rectangle(&box3); //Step 7
pdc->Rectangle(&box4); //Step 7
}
8. To handle mouse click we add an eventhandler LButtonDown( ) using ClassWizard.
9. We can record which of our flag rectangles the user clicked, and which rectangle
to fill with color - by setting up four new Boolean flags, fill1 to fill4, in the
CBoxerCtl header.
DMC 1944
NOTES
292 ANNA UNIVERSITY CHENNAI
class CBoxerCtrl : public COleControl
{
.
.
.
// Implementation
protected:
~CBoxerCtrl( );
CRect box1;
CRect box2;
CRect box3;
CRect box4;
boolean fill1;
boolean fill2;
boolean fill3;
boolean fill4;
.
.
.
};
10. Set those flags to false in the controls constructor:
CBo
xerCtrl::CBoxerCtrl( )
{
InitializeIIDs(&IID_DBoxer, &IID_DBoxerEvents);
fill1 = fill2 = fill3 = fill4 = false;
}
11.In OnLButtonDown( ), we can set the boolean fill flags using the CRect method
PtInRect( ), which returns true if the point you pass to it is in a certain rectangle,
such as our box1 to box4 objects:
void CBoxerCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
fill1 = box1.PtInRect(point);
fill2 = box2.PtInRect(point);
fill3 = box3.PtInRect(point);
fill4 = box4.PtInRect(point);
Invalidate( );
COleControl::OnLButtonDown(nFlags, point);
}
12. Invalidate( ) calls the OnDraw( ), there we check the four Boolean fill flags and
fill the corresponding rectangle using the CDC method FillSolidRect( ):
VISUAL PROGRAMMING
NOTES
293 ANNA UNIVERSITY CHENNAI
void CBoxerCtrl::OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
{
pdc->FillRect(rcBounds,
CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));
box1=CRect(rcBounds.left, rcBounds.top, rcBounds.right/2, rcBounds.bottom/2);
box2=CRect(rcBounds.left, rcBounds.bottom/2, rcBounds.right/2, rcBounds.bottom);
box3=CRect(rcBounds.right/2, rcBounds.top, rcBounds.right, rcBounds.bottom/2);
box4=CRect(rcBounds.right/2, rcBounds.bottom/2, rcBounds.right,
rcBounds.bottom);
pdc->Rectangle(&box1);
pdc->Rectangle(&box2);
pdc->Rectangle(&box3);
pdc->Rectangle(&box4);
if(fill1) pdc-> FillSolidRect(&box1,RGB(0,0,0));
if(fill2) pdc-> FillSolidRect(&box2, RGB(0,0,0));
if(fill3) pdc-> FillSolidRect(&box3, RGB(0,0,0));
if(fill4) pdc-> FillSolidRect(&box4, RGB(0,0,0));
}
13. To test Boxer, start Build Build Boxer.ocx to build the boxer.ocx and
registered that control with Windows.
14. Select the ActiveX Control Test Container item in the tools menu, which brings
up the very useful test container tool.
15. Select Insert New Control item in the test containers Edit menu and Double
click the Boxer control in the Insert Control box that appears. This inserts our
ActiveX control in the test container.
Figure 5.28 ActiveX control Test Container
DMC 1944
NOTES
294 ANNA UNIVERSITY CHENNAI
16. Click one of the boxes in the control, shading it. Clicking another rectangle shades
that rectangle instead.
17. To embed the ActiveX in a program. Create a new dialog based program now
named Boxerapp. To insert a control of Boxer type in this program: select
Project Add to Project Components and Controls, opening the
Components and Controls Gallery.
18. Double click on the Registered ActiveX Controls. Select the Boxer Control
entry and click insert button. This inserts the Boxer control into the dialogs
editors toolbox, where it has an icon OCX.
Figure 5.29 Application involving ActiveX Control
19. Test the application and youll find the windows shown in Figure 5.28 and 5.29 as
output.
5.10.2 Container class - Container-Component Interactions
Analyzing the component and the container separately wont help you to understand
fully how they work. You must watch them working together to understand their interactions.
Figure 5.30 shows a container program looking at a component.
5.10.2.1 Using the Components IOleObject Interface
Loading a component is not the same as activating it. Loading merely starts a process,
which then sits waiting for further instructions. If the container gets an IOleObject pointer
to the component object, the component should then show its main window and act like a
Windows-based program.
VISUAL PROGRAMMING
NOTES
295 ANNA UNIVERSITY CHENNAI
Figure 5.30 A container programs view of the component.
Another important IOleObject function is Close, which is called when the container
wants to terminate the component program. If the component process is currently servicing
one embedded object (as is the case with MFC components), the process exits.
Figure 5.30 also demonstrates that the container manages a storage through an IStorage
pointer and that the component implements IPersistStorage. That means that the component
can load and save its native data when the container calls the Load and Save functions of
IPersistStorage. The container will save the components class ID in the storage. The
container can read the class ID from the storage and use it to start the component program
prior to calling IPersistStorage::Load.
The storage must always be available because the object is constantly loading and
saving itself and reading and writing temporary data.
A compound document appears at the bottom of Figure 5.30. The container manages
the whole file, but the embedded components are responsible for the storages inside it.
Theres one main storage for each embedded object, and the container doesnt know or
care whats inside those storages.
***
Container
application
Document
Object
Component
application
Container maintains a pointer to the object
IUnknown
IOie Object
IData Object
IPersistStorage
IStorage
IClassFactory
Component gets IStorage-from
container: calls IStorage:: Save and
IStorage:: Load
Containers compound file
(compound document)
Object data
(in a storage)
Storage Class factory
DMC 1944
NOTES
296 ANNA UNIVERSITY CHENNAI
NOTES

You might also like