185
Skip to content Skip to navigation Log In Contact Us Report a Bug Search: Connexions Home Selected:Content Lenses About Us Help MyCNX You are here: Home » Content » VC++ Tutorial for Beginners Navigation RECENTLY VIEWED Print this page Download Reuse / Edit Add to a lens S earch

Skip to Content Skip to Navigation

Embed Size (px)

Citation preview

Page 1: Skip to Content Skip to Navigation

Skip to content Skip to navigation

Log In  

Contact Us  

Report a Bug  

Search:  

Connexions Home Selected:Content Lenses About Us Help MyCNX

You are here: Home » Content » VC++ Tutorial for Beginners

Navigation

RECENTLY VIEWED 

Print this page

Download 

Reuse / Edit 

Add to a lens 

Search

Page 2: Skip to Content Skip to Navigation

Add to Favorites 

 

VC++ Tutorial for BeginnersModule by: Avanija j. E-mail the author

Summary: This course entails the programming concepts in VC++ with clear syntax specification and programming examples.

Chapter 1

Basics of Windows Programming

1. 1 Paradigms of Programming Languages

Although many different computer architectures are being developed, the most prevalent is still the

traditional von Neumann architecture - consisting of a single sequential CPU separate from memory,

with data piped between cpu and memory. This is reflected in the design of the dominant computer

languages, with dynamic variables (representing memory cells with changing values); sequential

iteration (reflecting the single sequential cpu); assignment statements (reflecting piping). This

combination of choices gives rise to the imperative language paradigm - C, Ada, Pascal, FORTRAN,

COBOL, Basic etc.

But other choices are possible - variables do not have to directly reflect memory cells (logic

programming); repetition need not be iterative (logic, functional, concurrent); assignment need not be

important (logic, functional); data and control need not be separated (object oriented, functional).

A paradigm is essentially a high level model of what computation is about - the unifying factor that

makes Ada and C seem very similar, ignoring details such as what data or control structures are

available, exactly how variables are passed to procedures, and so on.

Some Paradigms

Procedural (COBOL, FORTRAN, Pascal, C)

functional (LISP)

logic (PROLOG)

structured

Page 3: Skip to Content Skip to Navigation

object-oriented (Smalltalk)

4GL (Dbase)

Visual (Visual Basic)

1.1.1 Procedural

This is focusing on grouping organizations and/or code by similar operations or by the operations that

can be done on them.

1.1.2 Functional

Functional programming is so called because a program consists entirely of functions. The program

itself is written as a function which receives the program's input as its argument and delivers the

program's output as its result. Typically the main function is defined in terms of other functions, which

in turn are defined in terms of still more functions, until at the bottom level the functions are language

primitives. These functions are much like ordinary mathematical functions.

Functional programs contain no assignment statements, so variables, once given a value, never

change. Functions can be described intentionally by a rule describing the association, or extensionally

as a set of associated pairs (argument, result) which are called the graph of the function. Functional

programming also provides greater abstraction for solution. One such a feature is polymorphism which

allows general definition of functions which could be applied to objects of any type. To achieve such a

behavior we use type variables which stand for any type. Further higher order functions provide facility

to treat functions as a data objects and use them like other data objects. It means that function (higher

order function) can manipulate and create other functions. Another important feature of the functional

programming is that evaluation of arguments could be delayed but done at most once. This technique

is called lazy evaluation. Postponing sometimes can lead to such a situation that postponed value

could be found as not necessary to evaluate, even when argument is undefined. If such a function can

return a defined result we call it non-strict, else if returns undefined is called strict.

1.1.3 Logic

The basic constructs of logic programming, terms and statements are inherited from logic. There are

three basic statements: facts, rules and queries. There is a single data structure: the logical term.

In a logic programming language the logical relationship between various entities are declared. The

programmer writes a database of facts and rules. The user supplies a queries (goals) which the system

Page 4: Skip to Content Skip to Navigation

tries to prove. This involves matching the current goal against each fact or the left hand side of each

rule using unification. If the goal matches a fact, the goal succeeds; if it matches a rule then the

process recurses, taking each sub-goal on the right hand side of the rule as the current goal. If all sub-

goals succeed then the rule succeeds.

Logic programming languages tend to be declarative programming languages, as opposed to the more

traditional imperative programming languages. In a declarative language, you concentrate on the

relationships between the parts of the problem, rather than on the exact sequence of steps required to

solve the problem. An example of a well-known declarative languages are SQL, Prolog.

1.1.4 Structural

Two mathematicians, Corrado Bohm and Guiseppe Jacopini proved that any computer

program can be written with the three structures : sequences, decisions and loops.

This discovery led to the method of modern programming known as structured

programming. Structured programming can be seen as a subset or sub discipline of

Procedural programming one of the major paradigms (and probably the most popular

one) for Programming computers. It is possible to do structured programming in

almost any procedural programming languages.

Edsger Dijkstra a professor of computer science at the Technological University at Eindhoven proposes

that GOTO statements be abolished from all high-level languages such as BASIC. Modern programming

languages such as Visual Basic do away with the need for GOTO statements.

A computer program is said to be structured if it has a modular design and uses only the three types of

logical structures, sequences, decisions and loops.

Sequences: Statements are executed one after another.

Decisions: One of two blocks of program code is executed based on a test for some condition.

Loops (Iteration): One or more statements are executed repeatedly as long as a specified condition is

true.

One major shortcoming of earlier programming languages was their reliance on the GoTo statement.

This statement was used to branch (that is jump) from one line of the program to another. It was

common for a program to be composed on a convoluted tangle of branching that produced confusing

code sometimes referred to as spaghetti code.

Page 5: Skip to Content Skip to Navigation

The logic of a structured program can be pictured using a flowchart that flows smoothly fro the top to

the bottom without unstructured branching (GoTos). Here is an example of a flowchart showing the

structure with and without the GoTo statement:

Advantages of

Structured Programming

The goal of structured programming is to create correct programs that are easy to write, understand

and change.

Easy to writeModular design increases the

programmer's productivity by allowing them to

look at the big picture first and focus on details

later. Several Programmers can work on a single,

large program, each working on a different

module. Studies show structured programs take

less time to write than standard programs.

Procedures written for one program can be reused

in other programs requiring the same task. A

procedure that can be used in many programs is

said to be reusable

Page 6: Skip to Content Skip to Navigation

Easy to debugSince each procedure is specialized

to perform just one task, a procedure can be

checked individually. Older unstructured programs

consist of a sequence of instructions that are not

grouped for specific tasks. The logic of such

programs is cluttered with details and therefore

difficult to follow.

Easy to UnderstandThe relationship between the

procedures shows the modular design of the

program.Meaningful procedure names and clear

documentation identify the task performed by

each module. Meaningful variable names help the

programmer identify the purpose of each variable.

Easy to ChangeSince a correctly written

structured program is self-documenting, it can be

easily understood by another programmer.

Earlier Analysis and Design

As programs got more complex, programmers realized that there might be a better way to write

programs than getting a problem statement and sitting down and writing code. In other words, a little

abstract planning might help. Along these lines, some abstract modeling techniques were developed.

Earlier methods included flowcharts and functional specifications, functional decomposition. Later

techniques involved:

data flow diagrams (functionality)

data dictionaries (functionality)

Decision trees

process specifications (structured English)

entity relationship diagrams (data -- Information

modeling)

The later techniques arose from the structured programming languages, and became used in

structured analysis and design. The intention of the models was to create extra levels of abstraction

Page 7: Skip to Content Skip to Navigation

between the real-world problem/system and the computer implementation of the system. They served

as a bridge between the real world situation, and the computer code. The problem was mapped into a

verbal problem statement, and then into a requirements analysis model, which was far removed from

the machine implementation. The analysis model was then mapped into a design model, which was

one step closer to the machine implementation (the code). Finally, code was written from the design

model. However, these earlier abstract models all ran on one premise -- there is data, and there are

functions that process the data. The first models attempted only to model the functionality of the real-

world systems. Later, entity relationship diagrams were added -- these modeled the data, or the static

nature of the system. However, the functionality models and the data models were distinct and

separate entities.

1.1.4 Object-oriented

In object-oriented programming programmers define not only the data type of a data structure, but

also the types of operations (functions) that can be applied to the data structure. In this way, the data

structure becomes an object that includes both data and functions. In addition, programmers can

create relationships between one object and another. For example, objects can inherit characteristics

from other objects. Objects and object interactions are the basic elements of design.

One of the principal advantages of object-oriented programming techniques over imperative

programming techniques is that they enable programmers to create modules that do not need to be

changed when a new type of object is added. A programmer can simply create a new object that

inherits many of its features from existing objects. This makes object-oriented programs easier to

modify.

The advantages of object-oriented programming do not evidence themselves when you are writing a

single function for a particular purpose. Instead, the advantages arise when you are designing a large

system that will do similar , but not identical, things to a variety of data objects. By specifying classes

of data objects for which identical effects will occur, you can define a single generic function that

embraces the similarities across object types, but permits individual implementations or methods for

each defined class. As an example of languages that implements object paradigm are Smalltalk, Delphi

and Java.

OO The Object Oriented Paradigm

Is it possible to make a computer think the way people naturally think, rather than in terms of data and

instructions that process data? The base machine will probably always think in terms of data and

instructions that process data. However, are there high-level languages that can add another layer of

Page 8: Skip to Content Skip to Navigation

abstraction on top of the machine, so that the high level languages can be written in code that mirrors

the way people think? Yes, of course -- these are the OO languages! Some OO languages are better at

hiding the basic premise of the machine. Smalltalk is probably the best, while C++ is probably the

worst .

History of OO languages

First OO language was Simula -- 1967. Used widely in Europe, it never caught on in the U.S. Then came

Smalltalk -- 1972. In 1986, Bjarne Stroustrup invented C++, and Brad Cox created Objective-C. OO

languages began taking off at this time. But as of 1994, OO languages have been around for 24 years.

Earlier versions, such as Smalltalk, may have been unpopular because machines weren't powerful

enough to handle them.

What Makes a Language Object-Oriented?

According to Bertrand Meyer, an OO programming language should contain the following 7 qualities

[7]:

The support of modules.

The modules must support data

abstraction, which entails: a.) Information

hiding and b.) Encapsulation.

Automatic memory management (not

necessarily garbage collection).

All data are defined by abstract data type

(ADT) based modules. (e.g. classes).

Ability to extend existing classes (i.e.

inheritance).

Support of polymorphism and dynamic

binding.

Multiple inheritance (the need for this

feature in an OO language is disputed by

many in the OO field.)

Objects

Page 9: Skip to Content Skip to Navigation

Basic building block of OO languages is the object. Like objects of human thought, OO objects combine

both data (nouns and adjectives) and actions (verbs) into one package. Data is implemented as data,

while actions are implemented as functions. The machine still sees a data-functionality split. But the

outside world sees data and functionality merged into one whole.

Classes

OO Languages promote classification at two levels. First, there is the class construct. Classes are like

"cookie cutters" from which objects are moulded. We have a "cat" class from which we create cat

objects, each with different attributes. The class specifies the attributes (and the functionality) while

the objects fill in the attribute values. For example, we have a cat class that has weight, color, and

name attributes specified. From the cat class, we create cat objects, through which the program is

actually run.

Inheritance

A looser classification scheme is obtained through inheritance. We can tie in our cat class into a whole

inheritance hierarchy which includes the entire cat family, the mammals, all animals, and then all

living things.

Polymorphism

Polymorphism is the method by which OO languages mirror the human thought processes' tendency to

group certain actions together. We can call similar functionality by the same name -- e.g. cats eat and

cows eat, but the way they eat is different. However, we still call their actions "eating". OO languages

allow for similar functions (actions) to be given similar names. This allows for conceptual clarity in

writing code. Note that C and other traditional languages use polymorphism to some extent. For

example, the arithmetic operators act on both floating point numbers and integers with the same

operators (+, - , /, *, etc) even though the underlying implementation is radically different.

Abstraction

Software objects mirror the human mind's tendency to abstract out details. Software objects hide the

internal details of an object behind the walls of an interface. The "user" or "client" of an object does

not have to worry about the inner details of the object, only the abstract principles of the object, as

defined by the interface.

1.2. The Windows Environment

Page 10: Skip to Content Skip to Navigation

Windows is a Graphical User Interface (GUI). It uses graphics to organize the user’s workspace. User’s

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 (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.3

A History of Windows

Windows promised an easy-to-use graphical interface, device-independent graphics and multitasking

support. The development was delayed several times, however, and the Windows 1.0 hit the store

shelves in November 1985. The selection of applications was sparse, however, and Windows sales

were modest.

Windows 1.0 package, included

MS-DOS Executive, Calendar, Cardfile, Notepad, Terminal, Calculator, Clock, Reversi, Control Panel, PIF

(Program Information File) Editor, Print Spooler, Clipboard, RAMDrive, Windows Write, Windows Paint.

On November 10, 1983, Microsoft announced Microsoft Windows, an extension of the MS-DOS

operating system that would provide a graphical operating environment for PC users. Microsoft called

Windows 1.0 a new software environment for developing and running applications that use bitmap

displays and mouse pointing devices. With Windows, the graphical user interface (GUI) era at Microsoft

had begun.

Page 11: Skip to Content Skip to Navigation

The release of Windows XP in 2001 marked a major milestone in the Windows desktop operating

system family, by bringing together the two previously separate lines of Windows desktop operating

systems.

With the upcoming release of Windows .NET Server, Microsoft will complete a cycle of server operating

system upgrades it began nearly a decade ago in 1993, with the release of the first version of

Microsoft Windows NT Server. To understand the progression of Windows server operating systems

you have to look back earlier than 1993, however, to the even longer line of Windows desktop

operating systems stretching back to the early 1980s.

To explain the many advances since Windows 1.0, the following pages summarize milestones in the

development of Windows desktop operating systems at Microsoft.

Many longtime PC users trace Windows to the 1990 release of Windows 3.0, the first widely popular

version of Windows and the first version of Windows many PC users ever tried. But Microsoft actually

released the first version of Windows six years earlier, in 1985. To understand the roots of today's

Windows operating systems, we must journey back nearly 20 years.

The Windows 1.0 product box showed the new tiled windows and graphical user interface in the operating systemTABLE 1

1985: Windows 1.0

The first version of Windows was a milestone product because it allowed PC users to switch from the

MS-DOS® method of typing commands at the C prompt (C:\) to using a mouse to point and click their

way through functions, such as starting applications, in the operating system.

Windows 1.0 also allowed users to switch between several programs—without requiring them to quit

and restart individual applications. The product included a set of desktop applications, including the

MS-DOS file management program, a calendar, card file, notepad, calculator, clock, and

telecommunications programs, which helped users manage day-to-day activities.

Even before the Windows 1.0 graphical user interface, there was this pre-Windows 1.0 Interface ManagerTABLE 2

1987: Windows 2.0

Page 12: Skip to Content Skip to Navigation

With the second version of Windows, Microsoft took advantage of the improved processing speed of

the Intel 286 processor, expanded memory, and inter-application communication capabilities using

Dynamic Data Exchange (DDE). Windows 2.0 featured support for the VGA graphics standard, and also

allowed users to overlap windows, control screen layout, and use keyboard combinations to move

rapidly through Windows operations.

Many developers started writing their first Window-based applications for Windows 2.x. Following the

release of Windows 2.0 was Windows/386 2.03, which took advantage of the protected mode and

extended memory capabilities of the Intel 386 processor.

Subsequent Windows releases continued to improve the speed, reliability, and usability of the PC, and

improved the interface design and capabilities.

1990: Windows 3.0

Microsoft's first mainstream computing platform offered 32-bit performance, advanced graphics, and

full support of the more powerful Intel 386 processor. A new wave of 386 PCs helped drive the

popularity of Windows 3.0, which offered a wide range of new features and capabilities, including:

Program Manager, File Manager, and Print

Manager

A completely rewritten application

development environment with modular

virtual device drivers (VxDs), native

support for applications running in

extended memory, and fully pre-emptive

MS-DOS multitasking

An improved set of Windows icons

The popularity of Windows 3.0 blossomed with the release of a completely new Windows software

development kit (SDK), which helped software developers focus more on writing applications and less

on writing device drivers. Widespread acceptance among third-party hardware and software

developers helped fuel the success of Windows 3.0.

Windows 3.0 featured a new File ManagerTABLE 3

Page 13: Skip to Content Skip to Navigation

1993: Windows for Workgroups 3.11

A superset of Windows 3.1, Windows for Workgroups 3.11 added peer-to-peer workgroup and domain

networking support. For the first time, Windows PCs were natively network-aware and became an

integral part of the emerging client/server computing evolution.

Windows for Workgroups was used in local area networks (LANs) and on stand-alone PCs and laptop

computers. It added features of special interest to corporate users, such as centralized configuration

and security, significantly improved support for Novell NetWare networks, and remote access service

(RAS). Windows for Workgroups also offered the performance benefits of Microsoft's new 32-bit file

system.

1993: Windows NT 3.1

The release to manufacturing of Microsoft Windows NT® on July 27, 1993, marked an important

milestone for Microsoft. It completed a project Microsoft began in the late 1980s to build an advanced

new operating system from scratch. "Windows NT represents nothing less than a fundamental change

in the way that companies can address their business computing requirements.

Windows NT was the first Windows operating system to combine support for high-end client/server

business applications with the industry's leading personal productivity applications. The operating

system broke new ground in security, operating system power, performance, desktop scalability, and

reliability with a range of key new features. These included a pre-emptive multitasking scheduler for

Windows-based applications, integrated networking, domain server security, OS/2 and POSIX

subsystems, support for multiple processor architectures, and the NTFS file system.

Windows NT 3.1 contained overlapping windows and other features similar to Windows 3.1TABLE 4

The new operating system began with version 3.1 in order to maintain consistency with Windows 3.1,

which at the time was a well-established operating system for both home and business users.

Windows NT was geared toward business users and was initially available in both a desktop

(workstation) version and a server version called Windows NT Advanced Server. The desktop version

was well received by developers because of its security, stability, and rich Microsoft Win32®

application programming interface (API)—a combination that made it easier to support powerful

programs.

Page 14: Skip to Content Skip to Navigation

Windows NT was a strategic platform that could integrate client/server applications with existing

Windows-based desktop applications, or function as a technical workstation to run high-end

engineering or scientific applications.

1993: Windows NT Workstation 3.5

Windows NT Workstation 3.5 supported the OpenGL graphics standard, which helped power high-end

applications for software development, engineering, financial analysis, scientific, and business-critical

tasks.

The Windows NT Workstation 3.5 release provided the highest degree of protection yet for critical

business applications and data. The product also offered 32-bit performance improvements, better

application support, including support for NetWare file and print servers, and improved productivity

features, such as the capability to give files 255-character names.

1995: Windows 95

Windows 95 was the successor to Microsoft's three existing general-purpose desktop operating

systems—Windows 3.1, Windows for Workgroups, and MS-DOS. Windows 95 included an integrated 32-

bit TCP/IP stack for built-in Internet support, dial-up networking, and new Plug and Play capabilities

that made it easy for users to install hardware and software.

The 32-bit operating system also offered enhanced multimedia capabilities, more powerful features for

mobile computing, and integrated networking. In order to keep memory requirements to a minimum, it

did not include support for such features as system-level security or Unicode, which came later.

1996: Windows NT Workstation 4.0

This upgrade to Microsoft's business desktop operating system brought increased ease of use and

simplified management, higher network throughput, and a complete set of tools for developing and

managing intranets.

Windows NT Workstation 4.0 included the popular Windows 95 user interface and improved networking

support, providing secure, easy access to the Internet and corporate intranets.

In October 1998, Microsoft announced that Windows NT would no longer carry the initials  NT," and

that the next major version of the operating system would be called Windows 2000.

1998: Windows 98

Page 15: Skip to Content Skip to Navigation

Windows 98 was the upgrade to Windows 95. Described as an operating system that "Works Better,

Plays Better," Windows 98 was the first version of Windows designed specifically for consumers.

Windows 98 enabled users to find PC- or Internet-based information easily, it opened and closed

applications more quickly, and it included support for reading DVD discs and connecting to universal

serial bus (USB) devices.

1999: Windows 98 Second Edition

Microsoft Windows 98 SE, as it was often abbreviated, was an incremental update to Windows 98. It

offered consumers a variety of new and enhanced hardware compatibility and Internet-related

features.

Windows 98 SE delivered an improved online experience with Internet Explorer 5 browser software and

Microsoft Windows NetMeeting® version 3.0 conferencing software. It also included Microsoft

DirectX® API 6.1, which delivered a variety of Windows multimedia improvements, and offered home

networking capabilities through Internet connection sharing (ICS). Windows 98 SE was also Microsoft's

first consumer operating system capable of using device drivers that also worked with the Windows NT

business operating system.

2000: Windows Millennium Edition (Windows Me)

Windows Me offered consumers numerous music, video, and home networking enhancements and

reliability improvements.

System Restore let users roll back their PC software configuration to a date or time before a problem

occurred. Windows Movie Maker provided users with the tools to digitally edit, save, and share home

videos. Microsoft Windows Media™ Player 7 technologies allowed users to easily find, organize, and

play digital media.

Windows Me was the last Microsoft operating system to be based on the Windows 95 kernel. Microsoft

announced that all future operating system products would be based on the Windows NT and Windows

2000 kernel.

2000: Windows 2000 Professional

Page 16: Skip to Content Skip to Navigation

Figure 1

Windows 2000 Professional was the upgrade to Windows NT Workstation 4.0, but it was more than just

that. Windows 2000 Professional was designed to replace Windows 95, Windows 98, and Windows NT

Workstation 4.0 on all business desktops and laptops. Built on top of the proven Windows NT

Workstation 4.0 code base, Windows 2000 added major improvements in reliability, ease of use,

Internet compatibility, and support for mobile computing.

Windows 2000 Professional also made hardware installation much easier than it was with Windows NT

Workstation 4.0 by adding support for a wide variety of new Plug and Play hardware, including

advanced networking and wireless products, USB devices, IEEE 1394 devices, and infrared devices.

2001: Windows XP

Windows XP is a unifying leap forward for desktop operating systems. With the release of Windows XP

Home Edition and Windows XP Professional in October 2001, Microsoft succeeded in merging its two

Windows operating system lines for consumers and businesses, uniting them around the Windows NT

and Windows 2000 code base.

With Windows XP, consumers and home users now have performance, stability, and security that

business users benefited from in Windows 2000.

Windows XP also includes the broad base of application and hardware compatibility of Windows 98 and

Windows Me, while adding new tech-support technology, a fresh user interface, and many other

improvements that make it easier to use for a broad range of tasks.

Windows XP is available in two main versions, Windows XP Professional and Windows XP Home Edition,

as well as a 64-bit edition, Windows XP 64-Bit Edition, for power users with workstations that use the

Intel Itanium 64-bit processor.

2001: Windows XP Professional

Page 17: Skip to Content Skip to Navigation

Windows XP Professional benefits from the long track record of Microsoft Windows NT technology:

superior operating system performance, including preemptive multitasking, fault tolerance, and

system memory protection.

Windows XP Professional also offers a redesigned interface and includes features for business and

advanced home computing, including Remote Desktop, encrypting file system, system restore and

advanced networking features. It also offers numerous key enhancements such as wireless 802.1x

networking support, Windows Messenger, Remote Assistance, and the System Restore feature.

2001:WindowsXPHomeEdition

Windows XP Home Edition offers a clean, simplified visual design that makes frequently accessed

features more accessible. The product offers many enhancements aimed at home users such as the

Network Setup Wizard, Microsoft Windows Media™ Player, Windows Movie Maker, and enhanced digital

photo capabilities.

1.4 Windows Programming Model

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 program—not the

operating system—that determines what gets called and when.

Windows programs operate differently. They use the event-driven programming model illustrated in

Figure 1.4, 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. 

Page 18: Skip to Content Skip to Navigation

Figure 1.4 Windows Programming Model

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

Page 19: Skip to Content Skip to Navigation

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.

 The message loop ends when a WM_QUIT message is retrieved from the message queue, signaling

that it's 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 window's upper right

corner), or selected Close from the window's system menu. When the message loop ends, WinMain

returns and the application terminates.

1.5 Dynamic Link Library (DLL)

Dynamic Link Library (DLL) is a collection of software routines programmed in a language such as C or

Pascal, which has been packaged especially for use from another program. For example, a C

programmer might write a routine that accesses a laser disc player. By compiling this as a DLL, it

might be usable by an author of a Windows Help hyper book, without them having to know anything

about the programming. In windows programming DLL plays an important part. Windows provides

function calls to implement its user interface and display text and graphics on the video display. These

functions are implemented in DLL. These are files with extension .DLL or .EXE.

The original idea for the DLL system was that there would be a central repository of code. Here are the

advantages:

Applications would link to this code

library, thus saving greatly on duplication

of effort and storage space.

Applications that used the DLL system

would behave exactly the same as all

other applications that used it.

If a problem arose, or a new feature was

desired, it could be written once and all

would benefit. In this sense, the DLL

system is a weak version of the object-

programming paradigm.

Naturally enough, along with these advantages came some responsibilities. An application should only

place a DLL in the central repository if:

Page 20: Skip to Content Skip to Navigation

The DLL was newer and/or better than the

ones already there.

The DLL was uniquely named, i.e. did not

conflict with a DLL for another purpose

with the same name.

If the DLL replaced another with the same

name, then the code in the DLL would be

exhaustively tested, so that on

replacement, other applications could use

it in the same way as its predecessor.

In time, all these rules have been broken, even by Microsoft itself, the originator of the idea.

On several occasions Microsoft has

created and distributed DLL files that

instantaneously broke every Windows

application in the world.

Regularly, end users will install an

application that has a DLL with the same

name as a "system" DLL, thus

mysteriously bringing down the system

until an expert can sort it out.

Over time, the "synchronization" problem

becomes more severe. In this scenario, a

DLL is replaced that brings it into conflict

with other DLLs it must work with.

The service pack problem is becoming

severe. In this scenario, Microsoft releases

a service pack that updates all key system

DLLs. All the elements of the service pack

must simultaneously be present in their

most recent form or the system will crash.

Then the user installs an application that

blithely replaces one or more of the DLLs

Page 21: Skip to Content Skip to Navigation

from the service pack. Result – system

failure, even on Windows NT 4.0, which,

notwithstanding its reputation for stability

and resilience, will fail utterly and

completely.

This is an example of a collision between an idea and reality, a key element in the human drama. The

idea was sound, but it failed to take into account the imperfections in the human character, in

particular those imperfections that influence the creation and operation of computer programs. The

reality is that Microsoft and any number of software vendors regularly risk the stability and security of

the end user's machine by writing DLL code as though it were normal programming. It isn't. To write a

DLL, you must imagine the effect of your changes and additions on every computer program that uses

it. This is obviously impossible. The solution to these problems is to go back to the system that

preceded the DLL system. Every application should place as many DLL files as possible in its own

directory (some DLL files are part of Windows itself, these must be accessed in common). No

application should assume that it can copy DLLs into the system directory or that its newer version of a

system DLL is safe to copy solely because it is newer. Many applications (including Microsoft's own)

have rendered systems unstable or unusable through this reasoning.

Win32s DLL Libraries

The Win32s DLL Libraries are an add-on set of programs that expand the MS Windows 3.1 and MS

Windows for Workgroups 3.11 systems so that they can run programs that follow the Win32s standard

from MicroSoft. By allowing them to run Win32s compliant programs, programers can write programs

to follow that standard and have it run, hopefully, on MS Windows 3.1, MS Windows for Workgroups

3.11, MS Windows 95 and MS Windows NT.

MS DOS and MS Windows 3.1/MS Windows for Workgroups 3.11 run 16-bit coded programs. The limit

to 16-bit allows them to run on older computers with no significant changes. MS Windows 95 and MS

Windows NT run 32-bit coded programs and do not need DOS at all. The 32-bit code needs at least a

386 IBM Compatible computer to run because the code is 32-bits instead of 16-bits it can:

Use the full BUS width of the CPU to tranfer more

information per computer clock cycle

Have a more robust command structure with a

possible 2^32 ( 4294967296 ) commands. Of

course, at this stage of computer development

Page 22: Skip to Content Skip to Navigation

there is no need for THAT MANY commands. But it

is useful for splitting up common functions into

seperate commands that were previously

combined or grouping some common groups of

commands into single commands.

In the course of writing and distributing Windows applications, the majority of customer problems were

related to DLLs. If you create a program that assumed that standard Windows system DLLs would be

present, those DLLs would not be present or would not be current, and the application would fail. If I

took it upon myself to follow the DLL guidelines and copy DLLs into the system directory after

ascertaining that my DLL was newer than the current one, other applications would fail. To avoid this

problem it is better to include in the application all required DLLs in the program directory.

1.6 API (Application Programming Interface)

A set of routines, protocols, and tools for building software applications. A good API makes it easier to

develop a program by providing all the building blocks. A programmer puts the blocks together.

API (Application Programming Interface) is a set of commands, which interfaces the programs with the

processors. The most commonly used set of external procedures are those that make up Microsoft

Windows itself. The Windows API contains thousands of functions, structures, and constants that you

can declare and use in your projects. Those functions are written in the C language, however, so they

must be declared before you can use them. The declarations for DLL procedures can become fairly

complex. Specifically to C# it is more complex than VB. You can use API viewer tool to get API function

declaration but you have to keep in mind the type of parameter which is different in C#.

Most of the advanced languages support API programming. The Microsoft Foundation Class Library

(MFC) framework encapsulates a large portion of the Win32 (API). ODBC API Functions are useful for

performing fast operations on database. With API your application can request lower-level services to

perform on computer's operating system. As API supports thousands of functionality from simple

Message Box to Encryption or Remote computing, developers should know how to implement API in

their program.

API\’s has many types depending on OS, processor and functionality.

OS specific API:

Each operating system has common set of API's and some special

Page 23: Skip to Content Skip to Navigation

e.g.

Windows NT supports MS-DOS, Win16, Win32, POSIX (Portable Operating System Interface), OS/2

console API and Windows 95 supports MS-DOS, Win16 and Win32 APIs.

Win16 & Win32 API:

Win16 is an API created for 16-bit processor and relies on 16 bit values. It has platform independent

nature.

e.g. you can tie Win16 programs to MS-DOS feature like TSR programs.

Win32 is an API created for 32-bit processor and relies on 32 bit values. It is portable to any operating

system, wide range of processors and platform independent nature. Win32 API’s has ‘32’ prefix after

the library name e.g. KERNEL32, USER32 etc…

All APIs are implemented using 3 Libraries.

Kernel

User

GDI

KERNEL

It is the library named KERNEL32.DLL, which supports capabilities that are associated with OS such as

Process loading.

Context switching.

File I/O.

Memory management.

e.g. The GlobalMemoryStatus function obtains information about the system's current usage of both

physical and virtual memory

USER

This is the library named "USER32.DLL" in Win32. This allows managing the entire user interfaces such

as :

Page 24: Skip to Content Skip to Navigation

Windows

Menus

Dialog Boxes

Icons etc.

e.g. The DrawIcon function draws an icon or cursor into the specified device context.

GDI (Graphical Device Interface)

This is the library named "GDI32.dll" in Win32. It is Graphic output library. Using GDI Windows draws

windows, menus and dialog boxes.

It can create Graphical Output.

It can also use for storing graphical images.

e.g. The CreateBitmap function creates a bitmap with the specified width, height, and color format

(color planes and bits-per-pixel).

1.7 The Programming Environment

The Microsoft Visual C++ package includes more than the C compiler and other files and tools

necessary to compile and link windows programs. It also includes the Visual C++ Developer Studio an

environment in which you can edit your source code, create resources such as icons and dialog boxes

and edit, compile, run and debug your programs. The msdn portion of the Microsoft URL stands for

Microsoft Developer Network which is a program that provides developers with the frequently updated

CD-ROMs containing much of what they need to be on the cutting edge of windows development.

1.7.1 Graphical User Interface Concepts

Since the invention of Graphical User Interface (GUI) is in 1972 from that we have seen a good number

of attempts to define and build the perfect GUI. GUI consists of number of elements such as:

The Explorer – Program that manages the GUI.

The Taskbar – Gray bar across the bottom of the

screen. It contains icons representing all active

programs, the clock and various utilities.

Page 25: Skip to Content Skip to Navigation

The Start Menu – A one button approach to

accessing programs, help, and system settings.

GUIs offer a standard look and feel to application thus reducing development and learning time. A GUI

is an environment that can work with graphic objects and it allows event-based interaction with

program for e.g., clicking on mouse buttons, entering data through a text field (like for the calculator

tool). Each event triggers the execution of event handler function to take appropriate action. Microsoft

Windows a typical example has the following components.

Menus (Including placement and names of options

and styles such as pull down or popup).

Icons (for identifying application and resources).

Tiled Windows (for views of multiple programs or

data or for multiple views of a single program or a

data block).

Dialog Boxes (for selecting files, options and

settings when an option is selected, the one

previously selected is turned off).

Check Lists (from which the user can make

multiple selections as in specifying print or file

attributes).

Support for a pointing device, typically a mouse

(especially to select and drag screen elements).

Scroll bars (along the edges to show the relative

position of the contents such as the end or

beginning of the text or to move to a different

position such as another part of a spread sheet).

A GUI enforces consistency by restricting developers they must support features for the program to

run under the GUI. In addition one benefit of GUI is that the user can learn a second application faster

because he or she is familiar with the environment. Note that the benefit comes with succeeding

applications. Consistency and familiarity help produce shorter learning curves. Users generally prefer

the interface style they know, whether it be Macintosh or Microsoft Windows. The consistency offered

by a GUI trades on the users familiarity with the environment.

Page 26: Skip to Content Skip to Navigation

Drawing and CAD programs are the best suited to GUI. Since, by their nature they manipulate objects

lines and curves, fill closed areas with color. For database programs, such manipulation is not as

useful. However they can use GUIs effectively to:

Specify data fields when setting up reports.

Select sort keys.

Transfer data to or from other applications (such

as a spread sheet).

The last point is particularly important. Database applications often must transfer data to and from

spreadsheets, word processors, desktop publishing programs, business or presentation graphics

programs, statistics programs or project management software. GUIs generally have data exchange

features, such as Microsoft windows dynamic data exchange (DDE) to handle such transfers.

A final benefit of GUI is that it lets you see the final product before you print it. What You See Is What

You Get (WYSIWYG) is a feature essential to desktop publishing and drawing applications and useful in

database applications (so you can inspect reports to see that all data fits on the page).

However there are drawbacks associated with using GUI. The cost includes the expense of graphics

cards, pointing device (such as mouse) and extra memory. Because GUIs run in graphics mode, screen

refresh is usually slower as well. If speed is important, a GUIs consistency may not be sufficient

compensation.

1.8 Event Driven Programming

While your program was looking for a particular kind of input, be it a mouse click or a key press, it

wasn’t doing any other work. If at a particular place in your program you were looking for a mouse

click and a key was pressed, generally the key press was ignored (at least at that instant). While this

approach to programming is functional in many situations, it does not work very well when there are

multiple possible sources of input whose arrival time you cannot predict and where it is unacceptable

to ignore any of the inputs. As an example consider the case of a VCR.

On a typical VCR there are a number of buttons, sensor inputs for tape in and the end of the tape as

well as commands that can be received from the remote control. The program for the embedded

computer controlling the VCR must be able to respond to any of those inputs at any time and in any

sequence. For example, while running fast forward, you can stop, play, change channels, and program

the VCR to record or any number of other actions. The program cannot move to only looking for the

Page 27: Skip to Content Skip to Navigation

channel select buttons while you are programming, or it would miss the end of tape sensor for the

rewinding tape.

Clearly, what we need is a program structure that will allow us to respond to a multitude of possible

inputs, any of which may arrive at unpredictable times and in an unpredictable sequence. While this

problem is very common in embedded systems, like the VCR, it is also very common in modern

desktop computers. Think about using a word processor. While you are typing, the program is

accepting your keys and entering the characters into your document. You can also click with the

mouse at any place on the screen. If the mouse pointer is at another place in your document, the point

of insertion moves. If it is in the menu bar, a menu will drop down. If it is over a formatting button, it

may change the format of the next character entered. Your word processor, or most other programs

running under Windows, MacOS, X-Windows or any other modern Graphical User Interface(GUI), must

also be capable of dealing with the same kind of variable input that the VCR must handle. All of these

operating systems, and many embedded applications, have adopted a common program structure to

deal with the need to respond to many asynchronous (not time sequence) inputs. This program

structure is generally called event driven programming.

Under the event driven programming model, the program structure is divided into two rough groups,

Events and Services. An event represents the occurrence of something interesting. A service is what

you do in response to the event. While events most often originate from the outside your program,

such a mouse click, events can also generated by other parts of the program. The program executes

by constantly checking for possible events and, when an event is detected, executing the associated

service.

In order for this approach to work, the events must checked continuously and often. This implies that

the services must execute quickly, so that the program can get back to checking for events. In order to

meet this requirement, the service can not to go into a state where it is waiting for some long or

indeterminate time. The most common example of this would be a while loop where the condition for

termination was not under program control, for example; a switch closure. This kind of program

structure, an indefinite loop is referred to as ‘Blocking ‘ code. In order for the even t driven

programming model to work, you must only write ‘Non-Blocking’ code. So how to deal with the need to

wait for the switch close? You make the switch closure an event. Then, rather than waiting in a loop for

the switch to close, you program a service that does the right thing when the switch closes and let all

of the event checkers run while you are waiting for the switch to close. In this way, you could also

react to another event while you were waiting for the switch to close.

Event Checkers

Page 28: Skip to Content Skip to Navigation

An event, by its nature, represents a discrete point in time. At one instant, the event has not occurred ,

at the next it has. In the case of a switch, the opening or closing of the switch represents an event. The

switch being open or closed does not represent an event. The event is marked by the transition from

open to closed.

1.9 Header Files

Windows programs begin with a processor directive at the top such as :

#include <windows.h>

WINDOWS.H is a master file that includes other Windows header files, some of which also include other

header files. The most important and most basic of these header files are:

WINDEF.H Basic type definitions.

WINNT.H Type definitions for Unicode support.

WINBASE.H Kernel functions.

WINUSER.H User interface functions.

WINGDI.H Graphics device interface functions.

These header files define all the Windows data types, function calls, data structures and constant

identifiers. They are important part of Windows documentation.

1.10 Program Entry Point

In windows program the entry point is WinMain similar to the main function in C program. The WinMain

function appears like this:

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine,

int nCmdShow)

It is declared in WINBASE.H like so (line breaks and all) :

int

WINAPI

Page 29: Skip to Content Skip to Navigation

WinMain(

HINSTANCE hInstance,

HINSTANCE hPrevInstance,

LPSTR lpCmdLine,

int nShowCmd

);

This declaration uses a system called “Hungarian notation” through which the variable name is

indicated with a short prefix that indicates the variables data type. This notation will be discussed

later. The first parameter to WinMain is an “instance handle”. In windows programming a handle is

simply a number that an application uses to identify something. In this case the handle uniquely

identifies the program. It is required as an argument to some other windows function calls. In early

versions of windows when you run the same program concurrently more than once, multiple instances

of that program will be created. A program can determine if other instances of itself are running by

checking the hPrevInstance parameter. In 32 bit versions this concept has been abandoned.

The second parameter to WinMain is always NULL (defined 0). The third parameter to WinMain is

command line used to run the program. The fourth parameter to WinMain indicates how the program

should be initially displayed either normally or maximized to fill the window or minimized to be

displayed in the task list bar.

1.11 Compile, Link and Run Windows program

When you are ready to compile your program named samplewinprg, you can select Build

samplewinprg.exe from the Build menu or press F7, or select the Build icon from the Build toolbar. The

appearance of this icon is shown in the Build menu. If the Build toolbar is not currently displayed you

can choose Customize from the tools menu and select the Toolbars tab. Pick Build or Build MiniBar.

Alternatively you can execute samplewinprg.exe from the Build menu by pressing Ctrl+F5 or click the

Execute program icon. From the Build toolbar. A message will be displayed asking if you want to build

the program.

During compilation the compiler generates an .OBJ(object) file from the C source code file. During the

ling stage the linker combines the .OBJ file with .LIB(library) files to create the .EXE(executable) file.

You can see a list of these library files by selecting settings from the Project tab and clicking the Link

Page 30: Skip to Content Skip to Navigation

tab. In particular you’ll notice KERNEL32.LIB, USER32.LIB, and GDI32.LIB. These are “import libraries”

for the three major Windows subsystems. They contain the dynamic-ling library names and reference

information that is bound in to the .EXE file. Windows uses this information to resolve calls from the

program to function in the KERNEL32.DLL, USER32.DLL and GDI32.DLL dynamic link libraries. In Visual

C++ Developer Studio, you can compile and link the program in different configurations. By default

these are called Debug and Release.

1.12 MessageBox Function

The MessageBox function is designed to display short messages. The window that a MessageBox

displays is considered to be a dialog box. The first argument to MessageBox is normally a window

handle. The second argument is the text string that appears in the body of the message box and the

third argument is the text string that appears in the caption bar of the message box. The fourth

parameter can be any of the combination of constants beginning with the prefix MB_ that are defined

in the WINUSER.H. The list of buttons that can appear in dialog box are:

MB_OK

MB_OKCANCEL

MB_ABORTRETRYIGNORE

MB_YESNO

MB_YESNOCANCEL

MB_RETRYCANCEL

The appearance of the icon in the message box can be any one of the following:

MB_ICANHAND

MB_ICONEXCLAMATION

MB_ICONASTERISK

1.13 Data Types

Page 31: Skip to Content Skip to Navigation

Windows programming has a reputation for its variety of data types, it uses all C data types and also

introduces a few data types of its own. The sample windows application illustrated in this chapter uses

a few of the Windows data types.

The following code displays a message as displayed in figure 2.10(a)

# include <windows.h>

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,PSTR szCmdLine,

int nCmdShow)

{int i;

MessageBox(0,"Application executing","Application",MB_OK);

return(0);

}

Figure 2.10(a) Sample Output

In this program, the MessageBox function returns the value 1, but it is more proper to say that it

returns IDOK, which is defined in WINUSER.h as equaling 1.Each running copy of a program is called an

instance. To refer to a particular instance of a program, a handle is required. A handle is an unsigned

integer that Windows uses internally to keep track of objects in memory. For example, every window

on the screen has a unique window handle. Handles are also used to keep a track of running

applications, allocated memory blocks and a host of other objects.

A handle is simply a number assigned by the system to a particular entity. It serves to identify the

entity, whether it is an instance, a window, a control or a block of memory. All objects in windows are

referred to by handles. Handles are a replacement of pointers. There are a number of related data

types for describing different kinds of handles. All these data types begin with the letter H. Thus,

Page 32: Skip to Content Skip to Navigation

HWND is the data type for a window handle, and HPEN is the handle to PEN. In the program shown

above, hInstance is the handle that identifies the current instance of the application and hPrevInstance

contains the hInstance value for the last copy of application.

Internally the Kernel of windows maintains tables that allow windows to convert handles to physical

memory addresses. A handle is a pointer to a memory location. The reason for this complexity is that

windows moves objects (memory blocks, programs and so on) in memory to make room for others. If

windows moves and object in memory, the handle table is updated. The handle used by the program

does not need to change since it always gets correctly translated to the right physical memory

addresses by the windows kernel, no matter where the object is moved in memory. Figure 2.10(b)

displays a representation of handles in the memory.

Program Windows Kernel Memory

HandleHandle TablePhysical Address

Figure 2.10(b) Handles in the Memory

If a pointer was used to refer to an object in memory, the pointer will be invalid when the object is

moved by windows as a part of its memory management. Thus pointers can be dereferenced whereas

handles will continue to be valid since the handle to pointer table will be updated automatically by

windows whenever it moves an object in memory.

In the above program, LPSTR is another new windows data type that is used; it is used to store a Long

Pointer to a String same as the char data type of C. The MessageBox function of the Win32 API displays

a message on the screen, with the specified title and message text, the message displayed will show

an OK button also, which will dismiss the MessageBox as specified by the MB_OK parameter.

1.14 Hungarian Naming Convention

The names of the variables used in a window program follow a naming convention called Hungarian

notation, in honor of its inventor Charles Simonyi. The idea is to precede variable names with key

letters that describe the type of data the variable represents and follow a verb-noun combination. The

Table 1.14 represents the Hungarian notations.

Table 1.14 Variable Name Codes in Hungarian Notation

Variable Name PrefixCode

Data Type

b BOOL(Boolean). The variable here can take either True or False

Page 33: Skip to Content Skip to Navigation

values.by BYTE(unsigned character)c Char(character)dw DWORD(double word)fn Functionh Handlei int(integer)l Longn Short(int) or near pointerp Pointers Character stringsz Character string terminated by zerow Word(two bytes)TABLE 5

1.15 Windows String Functions

The collection of string functions included in windows to calculate string length, copy string, concatenate strings and compare strings are listed below:

lstrcmpi - Compares two strings, ignoring case.

lstrcmp – Compares two strings.

lstrcpyn - Copies one string to another, with a maximum length.

lstrcpy - Copies one string to another.

lstrlen - Gets the length of a string in characters.

lstrcmpi

Compares two character strings. The comparison is not case sensitive.

Syntax

int lstrcmpi(LPSTR lpszString1,LPSTR lpszString2);

The first parameter lpszString1 is the pointer to the first null-terminated string to be compared. The

second parameter lpszString2 is the pointer to the second null-terminated string to be compared. This

function returns a negative value if the function succeeds and the string that lpszString1 points to is

less than the string that lpszString2 points to. Returns a positive value if the string that lpszString1

Page 34: Skip to Content Skip to Navigation

points to is greater than the string that lpszString2 points to. Returns zero if the strings are equal. The

lstrcmpi function compares two wide strings by checking the first characters against each other, the

second characters against each other, and so on until it finds an inequality or reaches the ends of the

strings. Similarly two wide strings can be compared using the function lstrcmpiW and also the wide

character string can be represented using LPCWSTR (long pointer to wide character string).

lstrcmp

Compares two strings. The comparison is case sensitive.

Syntax

int lstrcmp(LPSTR lpszString1,LPSTR lpszString2);

The first parameter lpszString1 is the Pointer to the first null-terminated wide string to be compared.

The second parameter lpszString2 is the Pointer to the second null-terminated wide string to be

compared. Returns a negative value if the function succeeds and the string that lpszString1 points to is

less than the string that lpszString2 points to. Returns a positive value if the string that lpszString1

points to is greater than the string that lpszString2 points to. This function returns zero if the strings

are equal. The lstrcmp function compares two strings by checking the first characters against each

other, the second characters against each other, and so on until it finds an inequality or reaches the

ends of the strings. Similarly two wide strings can be compared ignoring case using the function

lstrcmpW.

lstrcpy

Copies a string to a buffer.

Syntax

LPSTR lstrcpy(LPSTR lpszString1,LPSTR lpszString2);

The first parameter lpszString1 is the Pointer to a buffer to receive the contents of the string pointed to

by the lpszString2 parameter. The buffer must be large enough to contain the string, including the

terminating wide null character. The second parameter lpszString2 is the pointer to the null-terminated

wide string to be copied. This function returns a pointer to the buffer. Similarly two wide strings can be

copied using the function lstrcpyW.

lstrcpyn

Page 35: Skip to Content Skip to Navigation

Copies a string to a buffer, up to a specified number of characters.

Syntax

LPSTR lstrcpyn(LPSTR lpszString1,LPSTR lpszString2,int iMaxLength);

The first parameter lpszString1 is the pointer to a buffer to receive the contents of the string that the

lpszString2 parameter points to. The buffer must be large enough to contain the string, including the

terminating wide null character. The second parameter lpszString2 is the pointer to the null-terminated

string to be copied. The third parameter iMaxLength gives the maximum number of characters to

copy, including a terminating null character. This function returns a pointer to the buffer. If iMaxLength

is nonzero, lstrcpyn always inserts a terminating null character in the destination string, which could

result in the source string being truncated. Similarly lstrcpynW copies a wide string to a buffer, up to a

specified number of wide characters.

lstrlen

Retrieves the length of the specified string.

Syntax

int lstrlen(LPSTR lpszString);

The first parameter lpszString is the pointer to a null-terminated wide string. If the function succeeds,

the return value specifies the length of the string. Similarly lstrlenW retrieves the length of the

specified wide string.

1.16 The Sample SDK Program

Creating a window first requires registering a window class and that requires a window procedure to

process messages to the window. This involves a bit of overhead that appears in almost every

windows program. The program shown below is a simple program that handles only three windows

messages(two mouse click messages and a quit message). Figure 1.16(a) shows the applications only

window.

Page 36: Skip to Content Skip to Navigation

Figure 1.16 (a) A Minimal Windows Program written using SDK

// Sample SDK program to display window

#include <windows.h>

WNDCLASS wc;

MSG msg;

HWND hwnd;

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

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,

int nCmdShow)

{

wc.style=CS_HREDRAW|CS_VREDRAW;

wc.lpfnWndProc=wndproc;

wc.hInstance=hInstance;

Page 37: Skip to Content Skip to Navigation

wc.hCursor=LoadCursor(hInstance,IDC_ARROW);

wc.hIcon=LoadIcon(hInstance,NULL);

wc.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);

wc.lpszClassName ="Sample";

wc.lpszMenuName =NULL;

if (!RegisterClass(&wc))

return false;

hwnd=CreateWindow(“Sample”,”AsampleSDK Window”,

WS_OVERLAPPEDWINDOW,//window style

CW_USEDEFAULT, //initial x position

CW_USEDEFAULT, //initial y position

CW_USEDEFAULT, //initial x size

CW_USEDEFAULT, //initial y size

NULL,//parent window handle

NULL,//window menu handle

HINSTANCE,//program instance handle

NULL);//creation parameters

ShowWindow(hwnd,nCmdShow);

UpdateWindow(hwnd);

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

{

TranslateMessage(&msg);

Page 38: Skip to Content Skip to Navigation

DispatchMessage(&msg);

}

return true;

}

LRESULT CALLBACK wndproc(HWND hwnd,UINT wm,WPARAM wp,LPARAM lp)

{

char left[]="You have pressed left mouse button";

char right[]="You have pressed right mouse button";

switch(wm)

{

case WM_LBUTTONDOWN:

{

MessageBox(GetFocus(),left,"About",MB_OK|MB_ICONINFORMATION);

break;

}

case WM_RBUTTONDOWN:

{

MessageBox(GetFocus(),right,"About",MB_OK|MB_ICONINFORMATION);

break;

}

case WM_DESTROY:

{

Page 39: Skip to Content Skip to Navigation

PostQuitMessage(0);

return 0;

}

default:

break;

}

return(DefWindowProc(hwnd,wm,wp,lp));

}

Figure 1.16 (b) The sample SDK program responding to a left mouse click message

1.16.1Dissecting the Program

The code for this program deserves a closer examination. The program starts with

#include<windows.h>. This statement includes the main windows header file(WINDOWS.H) that in

turn includes all the windows header file that contain structures, macros, API prototypes and

everything else that the SDK program needs. Then the two SDK functions declared are: the program

Page 40: Skip to Content Skip to Navigation

entry point WinMain() and the application’s window procedure in this case wndproc. However there is a

reference to wndproc in WinMain, which is why the function is declared near the top of the program.

Windows function calls

The sample SDK windows program makes calls to fewer windows functions. These functions with a

brief description are:

Load IconLoads an icon for use by a program.

Load CursorLoads a mouse cursor for use by a program.

GetStockObjectObtains a graphic object in this case a

brush used for painting the windows background.

RegisterClassRegisters a window class for the program’s

window

MessageBoxDisplays a message box.

CreateWindowCreates a window based on a window class.

ShowWindowShows the window on the screen.

UpdateWindowDirects the window to paint itself.

GetMessageObtains a message from message queue.

TranslateMessage Translates some keyboard messages.

DispatchMessage Sends a message to a window

procedure.

PostQuitMessage To insert a “quit” message in to the

message queue.

DefWindowProc Performe default processing of messages.

Window Class Structure(WNDCLASS)

The WNDCLASS structure is used to define all windows that you can view on your monitor. The

structure of a window class looks like this:

typedef struct_WNDCLASS

Page 41: Skip to Content Skip to Navigation

{UINT style; //window class style

WNDPROC lpfnWndProc; //window procedure

int cbLlsExtra; //extra class bytes

int cbWndExtra; //extra window bytes

HANDLE hInstance; // instance handle

HICON hIcon; // icon handle

HCURSOR hCursor; // cursor handle

HBRUSH hbrBackground; // background brush color

LPCTSTR lpszMenuName; // menu resource

LPCTSTR lpszClassName; // window class name

}WNDCLASS ;

Message Structure

Because almost everything in windows happens in response to messages, the windows message

structure MSG is extremely important. This structure is defined as follows:

typedef Struct tagMsg

{HWND hwnd; // handle of the windows to retrieve messages

UINT message; // message value for each windows identified by macros in WINDOWS.H

WPARAM wp; // additional information about the message

DWORD time; //time at which the message was posted to the queue

POINT pt; // screen coordinates of the cursor when the message was posted

}MSG;

Uppercase Identifiers

Page 42: Skip to Content Skip to Navigation

These identifiers are defined in the windows header files. The identifiers contain a two-letter or three-

letter prefix followed by an underscore:

CS_HREDRAWDT_VCENTERSND_FILENAME

CS_VREDRAWIDC_ARROWWM_CREATE

CW_USEDEFAULTIDI_APPLICATIONWM_DESRTOY

DT_CENTERMB_ICONERRORWM_PAINT

DT_SINGLENAMESND_ASYNCWS_OVERLAPPEDWINDOW

These are simply numeric constants. The prefix indicates a general category to which the constant

belongs.

CS Class style option

CW Create window option

DT Draw text option

IDI ID number for an icon

IDC ID number for a cursor

MB Message box options

SND Sound option

WM Window message

WS Window style

Initializing and Registering the Window Class

Windows allows multiple instances of a single application to run concurrently each application window

has a window class. A window class must be initialized and registered when the first instance begins

execution. If there are no previous instances of the application running the WNDCLASS structure

variable wc is initialized with values and registered with windows by calling the RegisterClass() API

function with a pointer to wc as the only parameter. Here is the way to handle the RegisterClass

function call:

Page 43: Skip to Content Skip to Navigation

if(!RegisterClass(&wc)

return false;

In some sample windows programs you may see the following code in WinMain:

If(!hPrevInstance)

{wc.style=CS_HREDRAW | CS_VREDRAW;

[ other wndclass initialization]

RegisterClass(&wc);

}

This declaration is necessary only for 16 bit version of windows, if you started up a new instance of a

program that was already running then the hPrevInstance parameter should be the instance handle of

the previous instance. The window class can be registered only if hPrevInstance was NULL, indicating

no other instances of the program were running. But in 32 bit versions of windows hPrevInstance is

always NULL, it is not necessary to check hPrevInstance.

Creating the Window

The application window is created by calling the API function CreateWindow(). The CreateWindow()

function takes 11 parameters. Here’s the CreateWindow call with comments identifying the

parameters.

hwnd=CreateWindow( SZAPPNAME, // window class name

SZAPPTITLE, // window caption

WS_OVERLAPPEDWINDOW, // window style

CW_USEDEFAULT, // initial x position

CW_USEDEFAULT, // initial y position

CW_USEDEFAULT, // initial x size

CW_USEDEFAULT, // initial y size

Page 44: Skip to Content Skip to Navigation

NULL, // parent window handle

NULL, // window menu handle

HINSTANCE, // program instance handle

NULL); //creation parameters

The window created by this program is a normal overlapped window. It will have a title bar, system

menu button to the left of the title bar, a thick window sizing border and minimize, maximize and close

buttons to the right of the title bar. This is the standard style for windows. By using the identifier

CW_USEDEFAULT to indicate (initial x , y position and initial x , y size) we are indicating that we want

windows to use the default position for an overlapped window.

The argument marked “parent window handle” is to set to NULL when creating a “top level” window

such as an application window. Normally, when a parent-child relationship exists between two windows

the child window always appears on the surface of its parent. The “window menu handle” is also set to

NULL because the window has no menu. The “program instance handle” is set to the instance handle

passed to the program as a parameter of WinMain. Finally a “creation parameter” is set to NULL. The

CreateWindow function call returns a handle to created window which is stored in the variable hwnd. It

is defined to be of type HWND (handle to a window).

Displaying the Window

After the CreateWindow call returns the window has been created internally in windows. However the

windows do not yet appear on the video display, two more calls are needed. They are:

ShowWindow(hwnd,nCmdShow);

UpdateWindow(hwnd);

The ShowWindow call determines how to display the window on the screen., whether it is normal,

minimized or maximized. The first argument is the handle to the window just created by

CreateWindow. The second argument nCmdShow is the value passed as a parameter to WinMain which

determines how the window is to be internally displayed on the screen whether it is normal, minimized

or maximized. This can be done by defining the second parameter to have one of the fields given

below:

SW_SHOWMAXIMIZED - To display maximized window.

Page 45: Skip to Content Skip to Navigation

SW_SHOWMINIMIZED – To display minimized window.

SW_SHOWNORMAL – To display normal window.

SW_SHOWMINOACTIVE – To display the window in task

bar.

If the second argument to ShowWindow is SW_SHOWNORMAL the client area of the window is erased

with background brush specified in the window class. The function call UpdateWindow causes the

client area to be painted.

Window Procedure

The window procedure determines what the window displays in its client area and how the window

responds to user input. A windows program can contain more than one window procedure. The window

procedure can be defined like this:

LRESULT CALLBACK wndproc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)

These parameters are identical to the first four fields of the MSG structure. The first parameter hwnd is

the handle to window receiving the message. If a program creates multiple windows based on the

same window class and hence the same window procedure, hwnd identifies the particular window

receiving the message. The second parameter is a number that identifies the message. The last two

parameters are 32 bit message parameters that provide more information about the message.

Handling Messages in Window Procedure

After the UpdateWindow call the window is fully visible in the screen. The program must now make

itself ready to read input from the user through mouse and keyboard. Message queue is maintained for

each windows program currently running under windows. When an input event occurs windows

translates the event in to a message that it places in the message queue. The messages can be

retrieved from the message queue by executing the message loop:

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

{ TranslateMessage(&msg);

DispatchMessage(&msg);

}

Page 46: Skip to Content Skip to Navigation

The GetMessage call retrieves a message from a message queue and passes to window a pointer to a

MSG structure named msg.

The TranslateMessage call passes the msg structure back to windows for some keyboard translation.

The DispatchMessage call passes the msg structure back to windows and the windows then sends the

message to the appropriate window procedure for processing.

Every message that window procedure receives is identified by a number. This is defined with the

identifiers beginning with the prefix WM(Window Message) for each type of message. This can be done

through switch and case statement. To process a message, the window procedure should return 0. All

the messages not to be processed must be passed to a windows function named DefWindowProc. The

value returned from DefWindowProc must be returned from the window procedure. In the sample

windows program, wndproc chooses to process four messages: WM_CREATE, WM_LBUTTONDOWN,

WM_RBUTTONDOWN and WM_DESTROY. The messages can be defined like this:

switch(msg)

{ case WM_CREATE:

[process WM_CREATE message]

return 0;

case WM_LBUTTONDOWN :

[process WM_LBUTTONDOWN message]

return 0;

case WM_RBUTTONDOWN :

[process WM_RBUTTONDOWN message]

return 0;

case WM_DESTROY :

[process WM_DESTROY message]

return 0;

Page 47: Skip to Content Skip to Navigation

}

return DefWindowProc(hwnd,msg,wp,lp);

Windows Messages

Windows messages are sent by Windows to your application. These messages begin with the WM_

prefix. The WM_* messages are sent by windows and are usually handled by windows and views, some

of the commonly processed windows messages are: WM_COMMAND, WM_CHAR, WM_DESTROY and

WM_QUIT message.

WM_COMMAND Message

This message notifies the program that the user has selected a menu item, a child window control or

has used an accelerator key. An accelerator key is a key combination which is used to invoke the

options of a menu and other controls.

WM_CHAR Message

This message is used to retrieve ASCII keyboard inputs such as letters, numbers and printable

symbols. This message is generated when the user presses a character with an ASCII value on

keyboard.

WM_DESTROY Message

This message notifies the program that a window is being destroyed after it is removed from the

screen. The message is sent after the window image is removed from the screen. For example

WM_DESTROY is sent to the parent window before a child window is destroyed.

WM_QUIT Message

This message indicates a request to terminate an application and is done when the application calls

the PostQuitMessage function. It causes the GetMessage function to return a zero and drop out from

message loop. The return statement exits from WinMain and terminates the program.

Exercises 1

1. Differentiate Structured Programming and Object

Oriented Programming.

Page 48: Skip to Content Skip to Navigation

2. Define Object and Class.

3. Explain the Windows Programming Model.

4. What is DLL?

5. What is API?

6. Explain the GUI concepts.

7. Write short notes on Event Driven Programming.

8. What is Hungarian Notation?

9. Write short notes on Windows String Functions.

10. Explain the Message function calls used in Windows

Programming.

11. Write the Window Class structure, Message structure

and explain them.

12. Explain how to register the Window class.

13. List out the options available to display the Window.

14. Write short notes on Window Procedure.

15. Write about the Windows Messages.

Chapter – 2

Basics of GDI and DC

2.1Graphics Device Interface (GDI)

The graphics device interface (GDI) provides functions and related structures that an application can

use to generate graphical output for displays, printers, and other devices. Using GDI functions, you can

draw lines, curves, closed figures, paths, text, and bitmap images. The color and style of the items you

draw depends on the drawing objects — that is, pens, brushes, and fonts — that you create. You can

use pens to draw lines and curves, brushes to fill the interiors of closed figures, and fonts to write text.

Applications direct output to a specified device by creating a device context (DC) for the device. The

device context is a GDI-managed structure containing information about the device, such as its

Page 49: Skip to Content Skip to Navigation

operating modes and current selections. An application creates a DC by using device context

functions. GDI returns a device context handle, which is used in subsequent calls to identify the device.

For example, using the handle, an application can retrieve information about the capabilities of the

device, such as its technology type (display, printer, or other device) and the dimensions and

resolution of the display surface.

Applications can direct output to a physical device, such as a display or printer, or to a "logical" device,

such as a memory device or metafile. Logical devices give applications the means to store output in a

form that is easy to send subsequently to a physical device. After an application records output in a

metafile, it can play that metafile any number of times, sending the output to any number of physical

devices.

Applications use attribute functions to set the operating modes and current selections for the device.

The operating modes include the text and background colors, the mixing mode (also called the binary

raster operation) that specifies how colors in a pen or brush combine with colors already on the display

surface, and the mapping mode that specifies how GDI maps the coordinates used by the application

to the coordinate system of the device. The current selections identify which drawing objects are used

when drawing output. Figure 2.1 shows the diagrammatic representation of GDI.

   

Application obtains aGDI uses DC to locate

DC “handle” from the correct window or

Windows GDI anddevice driver and perform

Passes it to all GDIrequested function.

Functions

Figure 2.1 Graphics Device Interface

2.2 Device Context

Page 50: Skip to Content Skip to Navigation

Returns an integer that identifies the device-context of window if it has one, or nil otherwise. A device-

context is a construct used in the Windows API to specify a set of parameters that are used when

drawing on a window. A common graphics application does not normally need to deal with a window's

device-context directly, but if you need to pass the window to a WINAPI function that calls for the

window's device-context (or hDC), then you should pass the integer returned by this function for that

argument. Every non-control window in common graphics (and every lisp-widget window) is

automatically assigned a device-context, which it keeps until it is closed. Controls supplied by the OS

(all controls except lisp-widgets), on the other hand, are not automatically given device-contexts in lisp

since it is normally only the OS rather than lisp that draws on the control. If you do want to draw

directly on a non-lisp control, then you must give the window of the control a device-context while

drawing on it.

2.3 The WM_PAINT message

The WM_PAINT message is a request to repaint the window. Every application is responsible for

redrawing its window(s). This means that the application will have to keep track of the current state, so

that it knows that to draw. In most cases, the WM_PAINT message will be triggerd from the outside.

However, it is also possible to trigger WM_PAINT from inside the application. With the Invalidate()

function, you can tell that the contents of a window are no longer valid so that it will need to be

redrawn. With the InvalidateRect() function, you can specify that only part of the window content is

invalid, so that only that part will be redrawn. In this way, you can prevent the flickering of the screen

when redrawing. Because paint message have very low priority, you might want to send an immediate

redraw request. You can do this with the UpdateWindow() function.

2.4 Getting a Device Context Handle

There are two methods in getting a Device Context handle. The first method is by processing

WM_PAINT messages. Two functions involved in this process are BeginPaint and EndPaint. These

functions require the handle to window, which is passed to the window procedure as an argument and

the address of a structure variable of type PAINTSTRUCT which has to be defined within the window

procedure like so:

PAINTSTRUCT ps; // where ps is the paint structure variable

While processing a WM_PAINT message the window procedure first calls the function BeginPaint which

causes the background of the invalid region to be erased and prepare the window for painting. This

function fills the fields of the paint structure. The value returned by BeginPaint is a device context

Page 51: Skip to Content Skip to Navigation

handle. This value can be stored in a variable commonly named as hdc, which has to be defined in

window procedure like so:

HDC hdc; // handle to DC

HDC is a data type defined as a 32 bit integer. After the definition of HDC the program can use

functions like TextOut. The call to EndPaint releases the device context handle. The processing of

WM_PAINT message looks like this:

case WM_PAINT:

hdc = BeginPaint(hwnd,&ps);

[ GDI functions]

EndPaint (hwnd,&ps);

return 0;

2.5 The Paint Structure(PAINTSTRUCT)

The PAINTSTRUCT structure contains information for an application. This information can be used to

paint the client area of a window owned by that application.

typedef struct tagPAINTSTRUCT { // ps

HDC hdc;

BOOL fErase;

RECT rcPaint;

BOOL fRestore;

BOOL fIncUpdate;

BYTE rgbReserved[32];

} PAINTSTRUCT;

hdc Handle to the display DC to be used for painting.

Page 52: Skip to Content Skip to Navigation

fErase Specifies whether the background must be erased.

This value is nonzero if the application should erase the

background. The application is responsible for erasing the

background if a window class is created without a

background brush. For more information, see the

description of the hbrBackground member of the

WNDCLASS structure.

rcPaint Specifies a RECT structure that specifies the upper

left and lower right corners of the rectangle in which the

painting is requested.

fRestore Reserved; used internally by the system.

fIncUpdate Reserved used internally by the system.

rgbReserved Reserved used internally by the system.

Windows erases the background using the brush specified in the hbrBackground field of the

WNDCLASS structure that is used when registering the window class during WinMain initialization.

Many windows programs specify a white brush for the windows background. This is indicated in the

program with the statement like this:

wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;

The second method to get a handle to DC of the client area of the windows js by calling GetDC to

obtain the handle and ReleaseDC to release the handle. This can be done with the statement like this:

hdc = GetDC (hwnd) ;

[ GDI functions]

ReleaseDC (hwnd,hdc);

The functions GetDC and ReleaseDC should be called in pairs like BeginPaint and EndPaint. GetDC is

used while processing message and ReleaseDC is used to exit the window procedure. Do not call

GetDC in one message and ReleaseDC in another 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 for writing on the entire window.To use the

function GetWindowDC your program has to process WM_NCPAINT (non client paint) message.

Page 53: Skip to Content Skip to Navigation

2.6 TextOut

The TextOut function writes a character string at the specified location, using the currently selected

font, background color, and text color.

BOOL TextOut(

HDC hdc, // handle to device context

int x, // x-coordinate of starting position

int y, // y-coordinate of starting position

LPCTSTR lpString, // pointer to string

int cbString // number of characters in string

);

The first argument is the handle to the device context either the hdc value returned from GetDC or

from BeginPaint during the processing of a WM_PAINT message. The second and third arguments x and

y defines the starting point of the character string within the client area. The fourth argument lpsring is

a pointer to character string and the last argument cbString indicates the number of characters in the

string.

Eg: TextOut (hdc,x,y,”LeftButtonPressed”,17);

2.7 System Font and Text Metrics

The device context defines the font that windows uses to display the text when TextOut function is

called. The default font is a system font which is used by windows for text strings in title bars, menus

and dialog boxes. In earlier versions of windows the system font was a fixed pitch font in which all the

characters had the same width. But now the system font is a “raster font” which means that the

characters are defined as blocks of pixels. The size of a character is based on the size of the video

display.

To display multiple lines of text by using the TextOut function the dimensions of characters in the font

should be known The successive lines of the text can be spaced based on the height of the characters

and the columns of the text can be spaced on the average width of the characters. Just as a program

can determine information about the sizes or metrics of user interface items by calling the

Page 54: Skip to Content Skip to Navigation

GetSystemMetrics function, a program can determine font sizes by calling GetTextMetrics.

GetTextMetrics requires a handle to a device context because it returns information about the font

currently selected in the device context. The TEXTMETRIC structure has 20 fields but only the first

seven fields are essential.

typedef struct tagTEXTMETRIC

{

LONG tmHeight;

LONG tmAscent;

LONG tmDescent;

LONG tmInternalLeading;

LONG tmExternalLeading;

LONG tmAveCharWidth;

LONG tmMaxCharWidth;

[ other structure fields]

}

To use the GetTextMetrics function a structure variable tm should be defined.

TEXTMETRIC tm;

To determine the text metrics you get a handle to a device context and call GetTextMetrics

hdc = GetDC (hwnd) ;

GetTextMetrics (hdc , &tm);

ReleaseDC (hwnd, hdc);

The most important value in TEXTMETRIC is the tmHeight which is the sum of tmAscent and

tmDescent. These two values represent the maximum vertical extents of characters in the font above

and below base line. The term leading refers to the space that the printer inserts between the lines of

Page 55: Skip to Content Skip to Navigation

text. In the TEXTMETRIC structure internal leading is the space in which accent marks appear and the

external leading is not included in the tmHeight value. It is an amount of space that the designer of the

font suggests be added between successive rows of displayed text. The TEXTMETRIC structure

contains two fields that describes the character width one is tmAveCharWidth field which is a weighted

average of lowercase characters and another is tmMaxCharWidth which is the width of the widest

character in the font.

2.8 System Metrics

Display elements are the parts of a window and the display that appear on the system display screen.

System metrics are the dimensions of various display elements. Typical system metrics include the

window border width, icon height, and so on. System metrics also describe other aspects of the

system, such as whether a mouse is installed, double-byte characters are supported, or a debugging

version of the operating system is installed. The header file SYSMETS.H responds to GetSystemMetrics

function call. The GetSystemMetrics function retrieves the specified system metric. If the function

succeeds, the return value is the requested system metric or configuration setting. If the function fails,

the return value is zero. System metrics may vary from display to display. Applications can also

retrieve and set the color of window elements such as menus, scroll bars, and buttons by using the

GetSysColor and SetSysColor functions, respectively.

GetSystemMetrics

The GetSystemMetrics function retrieves various system metrics (widths and heights of display

elements) and system configuration settings. All dimensions retrieved by GetSystemMetrics are in

pixels.

int GetSystemMetrics ( int nIndex)

The nIndex parameter can be one of the following values. Note that all SM_CX* values are widths and

all SM_CY* values are heights.

Table 2.8 (a) nIndex parameter values

Value Meaning

SM_ARRANGEFlags specifying how the system arranged minimized windows. For more information about minimized windows, see the following Remarks section.

SM_CLEANBOOT Value that specifies how the system was started: 0 Normal boot1 Fail-safe boot2 Fail-safe with network bootFail-safe boot (also called SafeBoot, Safe Mode, or Clean Boot)

Page 56: Skip to Content Skip to Navigation

bypasses the user's startup files.

SM_CMONITORSWindows 98/Me, Windows 2000/XP:  Number of display monitors on the desktop.

SM_CMOUSEBUTTONSNumber of buttons on mouse, or zero if no mouse is installed.

SM_CXBORDER, SM_CYBORDER

Width and height of a window border, in pixels. This is equivalent to the SM_CXEDGE value for windows with the 3-D look.

SM_CXCURSOR, SM_CYCURSOR

Width and height of a cursor, in pixels. The system cannot create cursors of other sizes.

SM_CXDLGFRAME, SM_CYDLGFRAME

Same as SM_CXFIXEDFRAME and SM_CYFIXEDFRAME.

SM_CXDOUBLECLK, SM_CYDOUBLECLK

Width and height of the rectangle around the location of a first click in a double-click sequence, in pixels. The second click must occur within this rectangle for the system to consider the two clicks a double-click. (The two clicks must also occur within a specified time.) To set the width and height of the double-click rectangle, call SystemParametersInfo with the SPI_SETDOUBLECLKHEIGHT and SPI_SETDOUBLECLKWIDTH flags.

SM_CXDRAG, SM_CYDRAG

Width and height of a rectangle centered on a drag point to allow for limited movement of the mouse pointer before a drag operation begins. These values are in pixels. It allows the user to click and release the mouse button easily without unintentionally starting a drag operation.

SM_CXEDGE, SM_CYEDGEDimensions of a 3-D border, in pixels. These are the 3-D counterparts of SM_CXBORDER and SM_CYBORDER.

SM_CXFIXEDFRAME, SM_CYFIXEDFRAME

Thickness of the frame around the perimeter of a window that has a caption but is not sizable, in pixels. SM_CXFIXEDFRAME is the height of the horizontal border and SM_CYFIXEDFRAME is the width of the vertical border. Same as SM_CXDLGFRAME and SM_CYDLGFRAME.

SM_CXFOCUSBORDER, SM_CYFOCUSBORDER

Windows XP:  Width of the left and right edges and the height of the top and bottom edges of the focus rectangle drawn by DrawFocusRec. These values are in pixels.

SM_CXFRAME, SM_CYFRAME Same as SM_CXSIZEFRAME and SM_CYSIZEFRAME.

SM_CXFULLSCREEN, SM_CYFULLSCREEN

Width and height of the client area for a full-screen window on the primary display monitor, in pixels. To get the coordinates of the portion of the screen not obscured by the system taskbar or by application desktop toolbars, call the SystemParametersInfo function with the SPI_GETWORKAREA value.

SM_CXHSCROLL, SM_CYHSCROLL

Width of the arrow bitmap on a horizontal scroll bar, in pixels; and height of a horizontal scroll bar, in pixels.

Page 57: Skip to Content Skip to Navigation

SM_CXHTHUMB Width of the thumb box in a horizontal scroll bar, in pixels.

SM_CXICON, SM_CYICONDefault width and height of an icon, in pixels. The LoadIcon function can load only icons of these dimensions.

SM_CXICONSPACING, SM_CYICONSPACING

Dimensions of a grid cell for items in large icon view, in pixels. Each item fits into a rectangle of this size when arranged. These values are always greater than or equal to SM_CXICON and SM_CYICON.

SM_CXMAXIMIZED, SM_CYMAXIMIZED

Default dimensions, in pixels, of a maximized top-level window on the primary display monitor.

SM_CXMAXTRACK, SM_CYMAXTRACK

Default maximum dimensions of a window that has a caption and sizing borders, in pixels. This metric refers to the entire desktop. The user cannot drag the window frame to a size larger than these dimensions. A window can override these values by processing the WM_GETMINMAXINFO message.

SM_CXMENUCHECK, SM_CYMENUCHECK

Dimensions of the default menu check-mark bitmap, in pixels.

SM_CXMENUSIZE, SM_CYMENUSIZE

Dimensions of menu bar buttons, such as the child window close button used in the multiple document interface, in pixels.

SM_CXMIN, SM_CYMIN Minimum width and height of a window, in pixels.SM_CXMINIMIZED, SM_CYMINIMIZED

Dimensions of a minimized window, in pixels.

SM_CXMINSPACING SM_CYMINSPACING

Dimensions of a grid cell for a minimized window, in pixels. Each minimized window fits into a rectangle this size when arranged. These values are always greater than or equal to SM_CXMINIMIZED and SM_CYMINIMIZED.

SM_CXMINTRACK, SM_CYMINTRACK

Minimum tracking width and height of a window, in pixels. The user cannot drag the window frame to a size smaller than these dimensions. A window can override these values by processing the WM_GETMINMAXINFO message.

SM_CXSCREEN, SM_CYSCREEN

Width and height of the screen of the primary display monitor, in pixels. These are the same values obtained by calling GetDeviceCaps (hdcPrimaryMonitor, HORZRES/VERTRES).

SM_CXSIZE, SM_CYSIZEWidth and height of a button in a window's caption or title bar, in pixels.

SM_CXSIZEFRAME, SM_CYSIZEFRAME

Thickness of the sizing border around the perimeter of a window that can be resized, in pixels. SM_CXSIZEFRAME is the width of the horizontal border, and SM_CYSIZEFRAME is the height of the vertical border. Same as SM_CXFRAME and SM_CYFRAME.

SM_CXSMICON, SM_CYSMICON

Recommended dimensions of a small icon, in pixels. Small icons typically appear in window captions and in small icon view.

SM_CXSMSIZE SM_CYSMSIZE Dimensions of small caption buttons, in pixels.

Page 58: Skip to Content Skip to Navigation

SM_CXVIRTUALSCREEN, SM_CYVIRTUALSCREEN

Windows 98/Me, Windows 2000/XP:  Width and height of the virtual screen, in pixels. The virtual screen is the bounding rectangle of all display monitors. The SM_XVIRTUALSCREEN, SM_YVIRTUALSCREEN metrics are the coordinates of the top-left corner of the virtual screen.

SM_CXVSCROLL, SM_CYVSCROLL

Width of a vertical scroll bar, in pixels; and height of the arrow bitmap on a vertical scroll bar, in pixels.

SM_CYCAPTION Height of a caption area, in pixels.SM_CYMENU Height of a single-line menu bar, in pixels.SM_CYSMCAPTION Height of a small caption, in pixels.SM_CYVTHUMB Height of the thumb box in a vertical scroll bar, in pixels.

SM_DBCSENABLEDTRUE or nonzero if the double-byte character-set (DBCS) version of User.exe is installed; FALSE or zero otherwise.

SM_DEBUGTRUE or nonzero if the debug version of User.exe is installed; FALSE or zero otherwise.

SM_IMMENABLED

Windows 2000/XP:  TRUE or nonzero if Input Method Manager/Input Method Editor features are enabled; FALSE or zero otherwise. SM_IMMENABLED indicates whether the system is ready to use a Unicode-based IME on a Unicode application. To ensure that a language-dependent IME works, check SM_DBCSENABLED and the system ANSI code page. Otherwise the ANSI-to-Unicode conversion may not be performed correctly, or some components like fonts or registry setting may not be present.

SM_MENUDROPALIGNMENTTRUE or nonzero if drop-down menus are right-aligned with the corresponding menu-bar item; FALSE or zero if the menus are left-aligned.

SM_MIDEASTENABLEDTRUE if the system is enabled for Hebrew and Arabic languages.

SM_MOUSEPRESENTTRUE or nonzero if a mouse is installed; FALSE or zero otherwise.

SM_MOUSEWHEELPRESENTWindows NT 4.0 and later, Windows 98/Me:  TRUE or nonzero if a mouse with a wheel is installed; FALSE or zero otherwise.

SM_NETWORKLeast significant bit is set if a network is present; otherwise, it is cleared. The other bits are reserved for future use.

SM_PENWINDOWSTRUE or nonzero if the Microsoft Windows for Pen computing extensions are installed; FALSE or zero otherwise.

SM_REMOTECONTROLWindows XP:  This system metric is used in a Terminal Services environment. Its value is TRUE if the current session is remotely controlled; FALSE otherwise.

SM_REMOTESESSION Windows NT 4.0:  This system metric is used in a Terminal Services environment. If the calling process is associated

Page 59: Skip to Content Skip to Navigation

with a Terminal Services client session, the return value is TRUE or nonzero. If the calling process is associated with the Terminal Server console session, the return value is zero.

SM_SECURE TRUE if security is present; FALSE otherwise.

SM_SAMEDISPLAYFORMAT

Windows 98/Me, Windows 2000/XP:  TRUE if all the display monitors have the same color format, FALSE otherwise. Note that two displays can have the same bit depth, but different color formats. For example, the red, green, and blue pixels can be encoded with different numbers of bits, or those bits can be located in different places in a pixel's color value.

SM_SHOWSOUNDS

TRUE or nonzero if the user requires an application to present information visually in situations where it would otherwise present the information only in audible form; FALSE, or zero, otherwise.

SM_SHUTTINGDOWNWindows XP:  TRUE if the current session is shutting down; FALSE otherwise.

SM_SLOWMACHINETRUE if the computer has a low-end (slow) processor; FALSE otherwise.

SM_SWAPBUTTONTRUE or nonzero if the meanings of the left and right mouse buttons are swapped; FALSE or zero otherwise.

SM_XVIRTUALSCREEN, SM_YVIRTUALSCREEN

Windows 98/Me, Windows 2000/XP:  Coordinates for the left side and the top of the virtual screen. The virtual screen is the bounding rectangle of all display monitors. The SM_CXVIRTUALSCREEN, SM_CYVIRTUALSCREEN metrics are the width and height of the virtual screen.

TABLE 6

GetSystemMetrics(SM_CMONITORS) counts only display monitors. The SM_ARRANGE setting specifies

how the system arranges minimized windows, and consists of a starting position and a direction. The

starting position can be one of the following values.

Table 2.8 (b) Starting position values and direction of screen

Value MeaningARW_BOTTOMLEFT Start at the lower-left corner of the screen (default position).

ARW_BOTTOMRIGHTStart at the lower-right corner of the screen. Equivalent to ARW_STARTRIGHT.

ARW_HIDEHide minimized windows by moving them off the visible area of the screen.

ARW_TOPLEFTStart at the upper-left corner of the screen. Equivalent to ARV_STARTTOP.

ARW_TOPRIGHTStart at the upper-right corner of the screen. Equivalent to ARW_STARTTOP | SRW_STARTRIGHT.

TABLE 7

Page 60: Skip to Content Skip to Navigation

Table 2.8 (c) Lists the values of the direction in which to arrange the window.

Value MeaningARW_DOWNArrange vertically, top to bottom.ARW_LEFT Arrange horizontally, left to right.ARW_RIGHTArrange horizontally, right to left.ARW_UP Arrange vertically, bottom to top.TABLE 8

GetSysColor

The GetSysColor function retrieves the current color of the specified display element. Display elements

are the parts of a window and the display that appear on the system display screen. The function

returns the red, green, blue (RGB) color value of the given element. The parameter nIndex is used to

retrieve the color and can have one of the values listed in the Table 2.8(d). If the nIndex parameter is

out of range, the return value is zero. Because zero is also a valid RGB value, you cannot use

GetSysColor to determine whether a system color is supported by the current platform. Instead, use

the GetSysColorBrush function, which returns NULL if the color is not supported.

DWORD GetSysColor ( int nIndex);

Table 2.8 (d) Color values for GetSysColor function call

Value Meaning

COLOR_3DDKSHADOWDark shadow for three-dimensional display elements.

COLOR_3DFACE, COLOR_BTNFACEFace color for three-dimensional display elements and for dialog box backgrounds.

COLOR_3DHILIGHT, COLOR_3DHIGHLIGHT, COLOR_BTNHILIGHT, COLOR_BTNHIGHLIGHT

Highlight color for three-dimensional display elements (for edges facing the light source.)

COLOR_3DLIGHTLight color for three-dimensional display elements (for edges facing the light source.)

COLOR_3DSHADOW, COLOR_BTNSHADOW

Shadow color for three-dimensional display elements (for edges facing away from the light source).

COLOR_ACTIVEBORDER Active window border.

COLOR_ACTIVECAPTION

Active window title bar. Windows 98/Me, Windows 2000/XP:  Specifies the left side color in the color gradient of an active window's title bar if the gradient effect is enabled.

Page 61: Skip to Content Skip to Navigation

COLOR_APPWORKSPACEBackground color of multiple document interface (MDI) applications.

COLOR_BACKGROUND, COLOR_DESKTOP

Desktop.

COLOR_BTNTEXT Text on push buttons.

COLOR_CAPTIONTEXTText in caption, size box, and scroll bar arrow box.

COLOR_GRADIENTACTIVECAPTION

Windows 98/Me, Windows 2000/XP:  Right side color in the color gradient of an active window's title bar. COLOR_ACTIVECAPTION specifies the left side color. Use SPI_GETGRADIENTCAPTIONS with the SystemParametersInfo function to determine whether the gradient effect is enabled.

COLOR_GRADIENTINACTIVECAPTION

Windows 98/Me, Windows 2000/XP:  Right side color in the color gradient of an inactive window's title bar. COLOR_INACTIVECAPTION specifies the left side color.

COLOR_GRAYTEXTGrayed (disabled) text. This color is set to 0 if the current display driver does not support a solid gray color.

COLOR_HIGHLIGHT Item(s) selected in a control.COLOR_HIGHLIGHTTEXT Text of item(s) selected in a control.

COLOR_HOTLIGHTWindows 98/Me, Windows 2000/XP:  Color for a hot-tracked item. Single clicking a hot-tracked item executes the item.

COLOR_INACTIVEBORDER Inactive window border.

COLOR_INACTIVECAPTION

Inactive window caption. Windows 98/Me, Windows 2000/XP:  Specifies the left side color in the color gradient of an inactive window's title bar if the gradient effect is enabled.

COLOR_INACTIVECAPTIONTEXT Color of text in an inactive caption.COLOR_INFOBK Background color for tooltip controls.COLOR_INFOTEXT Text color for tooltip controls.COLOR_MENU Menu background.

COLOR_MENUHILIGHT

Windows XP:  The color used to highlight menu items when the menu appears as a flat menu. The highlighted menu item is outlined with COLOR_HIGHLIGHT.

COLOR_MENUBAR

Windows XP:  The background color for the menu bar when menus appear as flat menus. However, COLOR_MENU continues to specify the background color of the menu popup.

COLOR_MENUTEXT Text in menus.

Page 62: Skip to Content Skip to Navigation

COLOR_SCROLLBAR Scroll bar gray area.COLOR_WINDOW Window background.COLOR_WINDOWFRAME Window frame.COLOR_WINDOWTEXT Text in windows.TABLE 9

SetSysColors

The SetSysColors function sets the colors for one or more display elements. Display elements are the

various parts of a window and the display that appear on the system display screen.

BOOL SetSysColors ( int cElements , const INT* lpaElements, const COLOREF* lpargbvalues);

The first parameter cElements indicates the number of display elements in the lpaElements array. The

second parameter is a pointer to an array of integers that specify the display elements to be changed.

The third parameter is a pointer to an array of COLORREF values that contain the new red, green, blue

(RGB) color values for the display elements in the array pointed to by the lpaElements parameter.

If the function succeeds, the return value is a nonzero value. If the function fails, the return value is

zero. The SetSysColors function sends a WM_SYSCOLORCHANGE message to all windows to inform

them of the change in color. It also directs the system to repaint the affected portions of all currently

visible windows. The SetSysColors function changes the current session only. The new colors are not

saved when the system terminates

2.9 Client area

The client area is the portion of a window where the application displays output, such as text or

graphics also called a client rectangle. Knowing the size of window’s client area the user can display

the text within the client area if the client area is not large enough to hold everything. The dimensions

of the client area is available from the GetSystemMetrics call (SM_CXFULLSCREEN and

CY_FULLSCREEN). The GetClientRect function can be used to determine the dimensions of the client

area. A better method in determining the size of the client area is to process the WM_SIZE message

whenever there is a change in window size. The lparam variable passed to the window procedure

contains the width of the client area in the low word and the height in the high word. For this two static

variable has to be defined in the window procedure as follows:

static int cxClient, cyClient ;

These two variables are set static because they are set while processing one message and used while

processing another message. The WM_SIZE message can be defined as:

Page 63: Skip to Content Skip to Navigation

case WM_SIZE :

cxClient = LOWORD (lparam);

cyClient = HIWORD (lparam);

return 0;

The number of full lines of text displayable within the client area can be calculated using the formula :

cyClient / cyChar

This is zero if the height of the client area is too small to display a full character. Similarly the

approximate number of lowercase characters that can be displayed horizontally within the client area

is equal to

cxClient / cxChar

2.10 GDI Primitives

The types of graphics displayed on the screen can themselves be divided in to several categories,

which are called primitives. These are:

Bitmaps: A bitmap is an array of bits that represent the

attributes of the individual pixels in an image (1 bit per

pixel in a black-and-white display, multiple bits per pixel

in a color or grayscale display). This is used to display

complex images on the monitor or printer. Bitmaps are

also used to display small images such as icons, mouse

cursors and buttons that appear in the toolbar.

Text: A Win32 macro that exists so that code can be

compiled either as American National Standards Institute

(ANSI) text or as Unicode. For Windows, which supports

only Unicode, the macro forces the compiler to convert

ANSI characters to Unicode characters. For example,

passing the ANSI string "Hello Windows '' through the

TEXT macro converts all characters in the string to 16-bit

wide characters.

Page 64: Skip to Content Skip to Navigation

Lines and Curves: A line is a set of highlighted pixels on a

video display (or a series of dots on a printed page) that is

defined by two points: a starting point and an ending

point. GDI supports straight lines, rectangles, ellipses,

arcs that are partial curves on the ellipse and Bezier

splines. Different type of curve can be drawn as a polyline

which is a series of very short lines that define curve.

Furthermore GDI draws lines using pen selected in the

device context.

Filled areas: To sketch or fill in areas of a drawing with the

color and pattern, brush is the tool used. Paint programs

that offer a variety of brush shapes can produce

brushstrokes of varying width and, in some cases,

shadowing or calligraphic effects. A brush can be solid

color, a pattern (which can be a series of horizontal,

vertical or diagonal hatch marks) or a bitmapped image

that is repeated vertically or horizontally within the area.

2.11 Drawing Point, Line and Curve

Windows can draw straight lines, curved lines and Bezier splines through the following functions:

SetPixelDraws a single point

MoveToSets the current position in preparation for

drawing

LineToDraws a line from the current position to the end of

the line

PolylineConnects a set of points with line segments

PolylineToConnects a set of points with line segments

beginning with the

current position and moves the current position to the end of the

polyline

Page 65: Skip to Content Skip to Navigation

ArcDraws an arc ArcTo draws an arc and moves the

current position

to the end of the arc

PolyBezierDraws one or more Bezier splines

PolyBezierToDraws one or more Bezier splines and moves

the current position

to the end of the final spline

PolyDrawDraws a series of line segments and Bezier

splines through a set

points and moves the current position to the end of the final line segment or spline

The functions that draw lines but that also fill the enclosed area within the figure they draw are as

follows:

ChordDraws a closed figure bounded by the intersection

of an ellipse

and a line

EllipseDraws a circle or an ellipse

PieDraws a pie shaped wedge

PolygonConnects a set of points to form a polygon

RectangleDraws a rectangle with square corners

RoundRectDraws a rectangle with rounded corners

Default line color is black and fill color is white. To draw straight line you must call two functions. The

first function specifies the point at which the line begins and the second function specifies the end

point of the line:

In Windows 3.x, the x- and y-coordinates are 16 bits each and are packed into the 32-bit (DWORD)

function return value, the largest valid size. In Win32, the coordinates are 32 bits each, totaling 64

bits, and are thus too large to fit into a single return value. Each Windows 3.x function is replaced by a

Page 66: Skip to Content Skip to Navigation

Win32 function with the same name, but with an Ex suffix added. The Ex functions pass the x- and y-

coordinates using an additional parameter instead of a return value. Both Win32 and Windows 3.x

support these new functions. Each Ex function includes an additional parameter that points to a

location to receive data. After the function call, this data provides the same information as the

corresponding function’s return value. If you do not need this information, you can pass NULL to this

parameter.

Under Windows 3.x, a call to the MoveTo function can be written as follows:

MoveTo( hDC, x, y );

In the portable version supported by both versions of Windows, the call to MoveTo is rewritten as

follows. Note that the information returned by MoveToEx is ignored:

MoveToEx ( hDC, x, y, NULL );

As a general rule, pass NULL as the last parameter unless you need to use the x- and y-coordinates

returned by the Windows 3.x version.

2.12 Using Stock Pens

The pen determines the lines color, width and style which can be solid, dotted or dashed. The default

pen is BLACK_PEN which draws a solid black line. Apart from BLACK_PEN windows provides other two

pens such as WHITE_PEN and NULL_PEN. NULL_PEN is the pen that doesn’t draw. You can also create

your own customized pens. In windows program pen can be referred using a handle. The type HPEN is

a handle to pen. You can define a variable for using this type definition:

HPEN hpen;

The GetStockObject function call is used to obtain the handle to one of the stock pens. For example if

you want to use the stock pen called BLACK_PEN you can define the handle like this:

hpen = GetStockObject (BLACK_PEN)

To select that pen in to Device Context use the definition:

SelectObject (hdc,hpen);

Page 67: Skip to Content Skip to Navigation

Now the BLACK_PEN is the current pen. After this call any line you draw will use the BLACK_PEN until

you select another pen or release the device context handle. Instead of defining hpen variable

explicitly you can combine the StockObject and SelectObject call in to one statement:

SelectObject (hdc, GetStockObject (BLACK_PEN));

If you want to use the WHITE_PEN then you can get that handle to that stock object and select in to the

device context in one statement:

SelectObject (hdc , GetStockObject (WHITE_PEN));

2.13 Creating, Selecting and Deleting Pens

Apart from solid BLACK_PEN and WHITE_PEN you can create your own pens using CreatePen function

call. You can select the pen in to the device context by calling the SelectObject and then draw lines

using new pen. After releasing the device context you can delete the pen by calling DeleteObject. After

doing so the pen is no longer valid. The syntax for CreatePen looks like this:

hpen = CreatePen ( iPenStyle , iWidth, crColor);

The iPenStyle argument determines whether the pen draws a solid line or line with dash and dots. The

argument may be any one of the pen styles listed in figure 2.13.

PS_SOLID____________________________

PS_DASH------------------------------------------

PS_DOT……………………………………

PS_DASHDOT-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.

PS_NULL

PS_INSIDEFRAME____________________

Figure 2.13 Pen Styles

The iWidth argument is the width of the pen. If the value of iWidth argument is zero then Windows can

use one pixel for the pen width. The stock pens are one pixel wide. The crColor argument specifies the

color of the pen. The PS_INSIDEFRAME is the only pen style which uses dithered color only when the

width is greater than 1. For example if your program uses three pens , a black pen of width 3, a red

Page 68: Skip to Content Skip to Navigation

pen of width1 and a black dotted pen. First you have to define static variables for storing the handles

to these pens:

Static HPEN hpen1 , hpen2 , hpen3;

During processing of WM_CREATE you can create the three pens:

hpen1 = CreatePen (PS_SOLID,3,0);

hpen2 = CreatePen (PS_SOLID,1,RGB(255,0,0));

hpen3 = CreatePen(PS_DOT,0,0);

During processing of WM_PAINT message you can select one of these pens in to the device context

and draw with it:

SelectObject (hdc,hpen2)

[ line drawing functions ]

SelectObject(hdc,hpen1);

[line drawing functions]

You can delete the pens by processing WM_DESTROY message:

DeleteObject(hpen1);

DeleteObject(hpen2);

DeleteObject(hpen3);

You can also combine the CreatePen and SelectObject calls in the same statement:

SelectObject (hdc,CreatePen(PS_DASH,0,RGB(255,0,0));

When you draw lines you will be using red dashed pens by executing the above command.

Furthermore the coloring of the gaps between the dashes and the dots needs two attributes such as

the background mode and the background color. The default background mode is opaque which uses

the default background color white. You can also change the background mode to be transparent

which prevents the windows from filling in the gaps by using the command:

Page 69: Skip to Content Skip to Navigation

SetBkMode (hdc,TRANSPARENT) ;

The current background mode can be obtained by calling GetBkMode. Similarly the background color

can be changed using the command:

SetBkColor (hdc,crColor);

The current background color can be obtained by calling the GetBkColor function.

Example program using pen styles in drawing shapes

Create an application named GraphicsDemo by selecting the project type Win 32 Application in the

appwizard and click OK. Now an empty project without using MFC classes is created. Click File->New

and then select the option C++ Source File and give a name to the .cpp implementation file (here the

name is Graph.cpp). Enter the code given below in the implementation file (Graph.cpp).

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPSTR lpCmdLine, int nCmdShow)

{WNDCLASSEX wc;

HWND hwnd;

MSG Msg;

wc.cbSize = sizeof(WNDCLASSEX);

wc.style = 0;

wc.lpfnWndProc = WndProc;

wc.cbClsExtra = 0;

wc.cbWndExtra = 0;

wc.hInstance = hInstance;

wc.hIcon = LoadIcon(NULL,IDI_APPLICATION);

wc.hCursor = LoadCursor(NULL, IDC_ARROW);

Page 70: Skip to Content Skip to Navigation

wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);

wc.lpszMenuName = NULL;

wc.lpszClassName = g_szClassName;

wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

if(!RegisterClassEx(&wc))

{MessageBox(NULL, "Window Registration Failed!", "Error!",

MB_ICONEXCLAMATION | MB_OK);

return 0;

}

hwnd = CreateWindowEx(

WS_EX_CLIENTEDGE,

g_szClassName,

"Graphics Demo Program",

WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,

NULL, NULL, hInstance, NULL);

if(hwnd == NULL)

{MessageBox(NULL, "Window Creation Failed!", "Error!",

MB_ICONEXCLAMATION | MB_OK);

return 0;

}

ShowWindow(hwnd, nCmdShow);

Page 71: Skip to Content Skip to Navigation

UpdateWindow(hwnd);

while(GetMessage(&Msg, NULL, 0, 0) > 0)

{TranslateMessage(&Msg);

DispatchMessage(&Msg);

}

return Msg.wParam;

}

In this application Pen style is used to draw shapes. Compile, Build and Execute the program. You will

get different shapes in the output window as shown in figure 2.13.

Figure 2.13 Running Instance of Graphics Demo Program

Page 72: Skip to Content Skip to Navigation

2.14 Filling Enclosed Areas

Windows can draw the outline of the figure (Rectangle, Ellipse, RoundRect, Chord, Polygon etc.,) with

the current pen selected as well as with the current background mode and background color. The

figure is filled with the current brush selected. The default brush is the WHITE_BRUSH. Apart from the

default brush windows uses five more brushes such as: GRAY_BRUSH, LTGRAY_BRUSH,

DKGRAY_BRUSH, BLACK_BRUSH and HOLLOW_BRUSH or NULL_BRUSH. Any one of the brush can be

selected as the same way as you select the stock pen. First you have to define a variable for the brush

handle:

HBRUSH hbrush;

Where HBRUSH is a handle to the brush. You can get any one of the brush, for example the

BLACK_BRUSH by calling the GetStockObject:

hbrush = GetStockObject ( BLACK_BRUSH);

You can then select in to the device context by calling the SelectObject as:

SelectObject(hdc,hbrush);

Now when you draw a Rectangle the interior will be black. To draw the figure without border NULL_PEN

can be used as:

SelectObject (hdc,GetStockObject (NULL_PEN));

To draw the outline of the figure without filling the interior NULL_BRUSH can be used as:

SelectObject(hdc,GetStockObject(NULL_BRUSH));

The interiors of the figures can be filled with the current brush selected in the device context. You can

select the brush in to the device context with the function SelectObject. The function to create a logical

brush is:

hbrush = CreateSolidBrush (crColor) ;

You can also create a brush with hatch marks made up of horizontal, vertical or diagonal lines. The

function for creating the hatch brush is:

hbrush = CreateHatchBrush (hatchstyle,crColor)

Page 73: Skip to Content Skip to Navigation

The hatchstyle argument specifies one of the hatch styles shown below.

HS_HORIZONTAL: Horizontal Hatch

HS_VERTICAL: Vertical Hatch

HS_FDIAGONAL: Upward hatch (left to right) at 45 degrees

HS_BDIAGONAL: Downward hatch (left to right) at 45

degrees

HS_CROSS: Horizontal and vertical crosshatch

HS_DIAGCROSS: Crosshatch at 45 degrees

The crColor argument specifies the color of the hatch lines. Once you have a handle to the brush you

can select the brush in to the device context using SelectObject:

SelectObject(hdc,hbrush);

You can later delete a created brush with DeleteObject function:

DeleteObject(hbrush);

Example Program for filling the area of shapes

Create an application named FillArea by selecting the project type Win 32 Application in the appwizard

and click OK. Now an empty project without using MFC classes is created. Click File->New and then

select the option C++ Source File and give a name to the .cpp implementation file (here the name is

Filling.cpp). Enter the code given below in the implementation file (Filling.cpp).

#include <windows.h>

const char g_szClassName[] = "myWindowClass";

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)

{HDC hdc;

PAINTSTRUCT ps;

POINT parray[10]={10,70,50,70,50,10,90,10,90,50,30,50,30,90,70,90,70,30,10,30};

Page 74: Skip to Content Skip to Navigation

switch(msg)

{

case WM_PAINT:

hdc=BeginPaint(hwnd,&ps);

SelectObject(hdc,GetStockObject(GRAY_BRUSH));

SetPolyFillMode(hdc,ALTERNATE);

Polygon(hdc,parray,10);//first parameter handle to device context,second CONST POINT //*lpPoints

pointer to polygon's vertices, third count of polygon's vertices

EndPaint(hwnd,&ps);

return 0;

case WM_CLOSE:

DestroyWindow(hwnd);

break;

case WM_DESTROY:

PostQuitMessage(0);

break;

default:

return DefWindowProc(hwnd, msg, wParam, lParam);

}

return 0;

}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

Page 75: Skip to Content Skip to Navigation

LPSTR lpCmdLine, int nCmdShow)

{

WNDCLASSEX wc;

HWND hwnd;

MSG Msg;

wc.cbSize = sizeof(WNDCLASSEX);

wc.style = 0;

wc.lpfnWndProc = WndProc;

wc.cbClsExtra = 0;

wc.cbWndExtra = 0;

wc.hInstance = hInstance;

wc.hIcon = LoadIcon(NULL,IDI_APPLICATION);

wc.hCursor = LoadCursor(NULL, IDC_ARROW);

wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);

wc.lpszMenuName = NULL;

wc.lpszClassName = g_szClassName;

wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

if(!RegisterClassEx(&wc))

{MessageBox(NULL, "Window Registration Failed!", "Error!",

MB_ICONEXCLAMATION | MB_OK);

return 0;

}

Page 76: Skip to Content Skip to Navigation

hwnd = CreateWindowEx(

WS_EX_CLIENTEDGE,

g_szClassName,

"Filled Area",

WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,

NULL, NULL, hInstance, NULL);

if(hwnd == NULL)

{MessageBox(NULL, "Window Creation Failed!", "Error!",

MB_ICONEXCLAMATION | MB_OK);

return 0;

}

ShowWindow(hwnd, nCmdShow);

UpdateWindow(hwnd);

while(GetMessage(&Msg, NULL, 0, 0) > 0)

{TranslateMessage(&Msg);

DispatchMessage(&Msg);

}

return Msg.wParam;

}

In this application brush style is used to fill the area of polygon. Compile, Build and Execute the

program you will get the output as shown in figure 2.14.

Page 77: Skip to Content Skip to Navigation

Figure 2.14 Running Instance of FillArea Program

2.15 Keyboard Messages

The message that an application receives from windows about the keyboard events shows the

difference between keystrokes and characters. Keyboard is a collection of keys. Pressing the key and

releasing the key is called as a keystroke. For keystroke combinations that result in displayable

characters windows sends both keystroke and character messages. But some keys such as shift,

function keys, cursor movement keys do not generate characters. For these keys windows generates

only keystroke messages.

There are two types of keystrokes such as System keystroke and Nonsystem keystroke. The “SYS” in

WM_SYSKEYDOWN and WM_SYSKEYUP stands for “system” and refers to system keystrokes that are

more important to windows than to windows applications. Nonsystem keystroke messages refer to

messages such as WM_KEYDOWN and WM_KEYUP. For all the four keystroke messages (WM_KEYUP,

WM_KEYDOWN, WM_SYSKEYUP, WM_SYSKEYDOWN) wparam is a virtual key code that identifies the

key being pressed or released and lparam contains other data pertaining to keystroke.

Virtual Key Codes

The virtual key code identifies the key being pressed or released. The virtual key code is stored in the

wparam parameter . The following table shows the symbolic constant names, hexadecimal values, and

keyboard equivalents for the virtual-key codes used by the Windows operating system. The codes are

listed in numeric order in Table 2.15.

Table 2.15 Virtual Key Codes

Symbolic constant Value (Hex)Mouse or keyboard equivalentVK_LBUTTON 01 Left mouse button

Page 78: Skip to Content Skip to Navigation

VK_RBUTTON 02 Right mouse buttonVK_CANCEL 03 Control-break processingVK_MBUTTON 04 Middle mouse button (three-button mouse)— 05–07 UndefinedVK_BACK 08 BACKSPACE keyVK_TAB 09 TAB key— 0A–0B UndefinedVK_CLEAR 0C CLEAR keyVK_RETURN 0D ENTER key— 0E–0F UndefinedVK_SHIFT 10 SHIFT keyVK_CONTROL 11 CTRL keyVK_MENU 12 ALT keyVK_PAUSE 13 PAUSE keyVK_CAPITAL 14 CAPS LOCK key— 15–19 Reserved for Kanji systems— 1A UndefinedVK_ESCAPE 1B ESC key— 1C–1F Reserved for Kanji systemsVK_SPACE 20 SPACEBARVK_PRIOR 21 PAGE UP keyVK_NEXT 22 PAGE DOWN keyVK_END 23 END keyVK_HOME 24 HOME keyVK_LEFT 25 LEFT ARROW keyVK_UP 26 UP ARROW keyVK_RIGHT 27 RIGHT ARROW keyVK_DOWN 28 DOWN ARROW keyVK_SELECT 29 SELECT key  2A OEM specificVK_EXECUTE 2B EXECUTE keyVK_SNAPSHOT 2C PRINT SCREEN key for Windows 3.0 and laterVK_INSERT 2D INS keyVK_DELETE 2E DEL keyVK_HELP 2F HELP keyVK_0 30 0 keyVK_1 31 1 keyVK_2 32 2 keyVK_3 33 3 keyVK_4 34 4 keyVK_5 35 5 keyVK_6 36 6 keyVK_7 37 7 keyVK_8 38 8 key

Page 79: Skip to Content Skip to Navigation

VK_9 39 9 key  3A–40 UndefinedVK_A 41 A keyVK_B 42 B keyVK_C 43 C keyVK_D 44 D keyVK_E 45 E keyVK_F 46 F keyVK_G 47 G keyVK_H 48 H keyVK_I 49 I keyVK_J 4A J keyVK_K 4B K keyVK_L 4C L keyVK_M 4D M keyVK_N 4E N keyVK_O 4F O keyVK_P 50 P keyVK_Q 51 Q keyVK_R 52 R keyVK_S 53 S keyVK_T 54 T keyVK_U 55 U keyVK_V 56 V keyVK_W 57 W keyVK_X 58 X keyVK_Y 59 Y keyVK_Z 5A Z keyVK_LWIN 5B Left Windows key (Microsoft Natural Keyboard)VK_RWIN 5C Right Windows key (Microsoft Natural Keyboard)VK_APPS 5D Applications key (Microsoft Natural Keyboard)  5E–5F UndefinedVK_NUMPAD0 60 Numeric keypad 0 keyVK_NUMPAD1 61 Numeric keypad 1 keyVK_NUMPAD2 62 Numeric keypad 2 keyVK_NUMPAD3 63 Numeric keypad 3 keyVK_NUMPAD4 64 Numeric keypad 4 keyVK_NUMPAD5 65 Numeric keypad 5 keyVK_NUMPAD6 66 Numeric keypad 6 keyVK_NUMPAD7 67 Numeric keypad 7 keyVK_NUMPAD8 68 Numeric keypad 8 keyVK_NUMPAD9 69 Numeric keypad 9 keyVK_MULTIPLY 6A Multiply keyVK_ADD 6B Add key

Page 80: Skip to Content Skip to Navigation

VK_SEPARATOR6C Separator keyVK_SUBTRACT 6D Subtract keyVK_DECIMAL 6E Decimal keyVK_DIVIDE 6F Divide keyVK_F1 70 F1 keyVK_F2 71 F2 keyVK_F3 72 F3 keyVK_F4 73 F4 keyVK_F5 74 F5 keyVK_F6 75 F6 keyVK_F7 76 F7 keyVK_F8 77 F8 keyVK_F9 78 F9 keyVK_F10 79 F10 keyVK_F11 7A F11 keyVK_F12 7B F12 keyVK_F13 7C F13 keyVK_F14 7D F14 keyVK_F15 7E F15 keyVK_F16 7F F16 keyVK_F17 80H F17 keyVK_F18 81H F18 keyVK_F19 82H F19 keyVK_F20 83H F20 keyVK_F21 84H F21 keyVK_F22 85H F22 keyVK_F23 86H F23 keyVK_F24 87H F24 key  88–8F UnassignedVK_NUMLOCK 90 NUM LOCK keyVK_SCROLL 91 SCROLL LOCK keyTABLE 10

2.16 Mouse Messages

Windows sends keyboard messages only to the window that has the input focus. But mouse messages

are different, a window procedure receives mouse messages whenever the mouse passes over the

window or clicked within the window. There are two types of mouse messages such as client area

mouse messages and Non client area mouse messages. The client area is the portion of a window

where the application displays output, such as text or graphics. Also called a client rectangle. The

parts of a window that are not a part of the client area. A window’s nonclient area consists of the

border, menu bar, title bar, and scroll bar.

Page 81: Skip to Content Skip to Navigation

Table 2.16 (a) Client area mouse messages

Button Pressed Released Pressed (second click)

LeftWM_LBUTTONDOWN WM_LBUTTONUP WM_LBUTTONDBLCLK

MiddleWM_MBUTTONDOWN WM_MBUTTONUP WM_MBUTTONDBLCLK

RightWM_RBUTTONDOWN WM_RBUTTONUP WM_RBUTTONDBLCLK

Table 2.16 (b) Non Client area mouse messages

Button Pressed Released Pressed (second click)

LeftWM_NCLBUTTONDOWN WM_NCLBUTTONUP WM_NCLBUTTONDBLCLK

Middle WM_NCMBUTTONDOWN WM_NCMBUTTONUP WM_NCMBUTTONDBLCLK

RightWM_NCRBUTTONDOWN WM_NCRBUTTONUP WM_NCRBUTTONDBLCLK

Example program for mouse and keyboard messages

Create an application named MouseKeyMsg by selecting the project type Win 32 Application in the

appwizard and click OK. Now an empty project without using MFC classes is created. Click File->New

and then select the option C++ Source File and give a name to the .cpp implementation file (here the

name is Mouse.cpp). Enter the code given below in the implementation file (Mouse.cpp).

#include <windows.h>

const char g_szClassName[] = "myWindowClass";

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)

{

switch(msg)

{case WM_LBUTTONDOWN:

MessageBox(GetFocus(),"You have pressed left mouse button","About",MB_OK|

MB_ICONINFORMATION);

Page 82: Skip to Content Skip to Navigation

break;

case WM_RBUTTONDOWN:

MessageBox(GetFocus(),"You have pressed right mouse button","About",MB_OK|

MB_ICONINFORMATION);

break;

case WM_KEYDOWN:

MessageBox(0,"You have pressed down arrow key","About",MB_OK|MB_ICONINFORMATION);

break;

case WM_CLOSE:

DestroyWindow(hwnd);

break;

case WM_DESTROY:

PostQuitMessage(0);

break;

default:

return DefWindowProc(hwnd, msg, wParam, lParam);

}

return 0;

}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPSTR lpCmdLine, int nCmdShow)

{

Page 83: Skip to Content Skip to Navigation

WNDCLASSEX wc;

HWND hwnd;

MSG Msg;

wc.cbSize = sizeof(WNDCLASSEX);

wc.style = 0;

wc.lpfnWndProc = WndProc;

wc.cbClsExtra = 0;

wc.cbWndExtra = 0;

wc.hInstance = hInstance;

wc.hIcon = LoadIcon(NULL,IDI_APPLICATION);

wc.hCursor = LoadCursor(NULL, IDC_ARROW);

wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);

wc.lpszMenuName = NULL;

wc.lpszClassName = g_szClassName;

wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

if(!RegisterClassEx(&wc))

{MessageBox(NULL, "Window Registration Failed!", "Error!",

MB_ICONEXCLAMATION | MB_OK);

return 0;

}

hwnd = CreateWindowEx(

WS_EX_CLIENTEDGE,

Page 84: Skip to Content Skip to Navigation

g_szClassName,

"Mouse and Key operations",

WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,

NULL, NULL, hInstance, NULL);

if(hwnd == NULL)

{MessageBox(NULL, "Window Creation Failed!", "Error!",

MB_ICONEXCLAMATION | MB_OK);

return 0;

}

ShowWindow(hwnd, nCmdShow);

UpdateWindow(hwnd);

while(GetMessage(&Msg, NULL, 0, 0) > 0)

{TranslateMessage(&Msg);

DispatchMessage(&Msg);

}

return Msg.wParam;

}

Compile, Build and Execute the program. The output of the program is shown in figure 2.16.

Page 85: Skip to Content Skip to Navigation

Figure 2.16 Running Instance of MouseKeyMsg Program

Exercises 2

1. What is GDI?

2. Define DC.

3. What is WM_PAINT Message?

4. List the Paint Structure (PAINTSTRUCT) and explain it.

5. Write the syntax of TextOut function.

6. Define System Metrics.

7. What is Client area and Non Client area.

8. What are the GDI Primitives?

9. List out the Pen and Brush Styles.

10. Write a Windows Program to draw a Bezier Spline.

11. List out the Mouse and Keyboard Messages.

12. Write a Windows Program to draw a Sine Wave.

Chapter 3

Page 86: Skip to Content Skip to Navigation

Windows Controls and Resources

3.1 Child Window Controls

Windows provides several predefined window classes which we can readily use in our own programs.

Most of the time we use them as components of a dialog box so they're usually called child window

controls. The child window controls process their own mouse and keyboard messages and notify the

parent window when their states have changed. They relieve the burden from programmers

enormously so you should use them as much as possible. Controls can be placed on a normal window

by using the Create command with various styles to design them. But in reality you should put them in

a dialog box.

Examples of predefined window classes are buttons, listbox, checkboxes, radio buttons, edit controls,

etc.

In order to use a child window control, you must create it with win.CreateWindow or

win.CreateWindowEx. Note that you don't have to register the window class since it's registered for

you by Windows. The class name parameter MUST be the predefined class name. Say, if you want to

create a button, you must specify "button" as the class name in win.CreateWindowEx. The other

parameters you must fill in are the parent window handle and the control ID. The control ID must be

unique among the controls. The control ID is the ID of that control. You use it to differentiate between

the controls.

After the control was created, it will send messages notifying the parent window when its state has

changed. Normally, you create the child windows during win.WM_CREATE message of the parent

window. The child window sends win.WM_COMMAND messages to the parent window with its control ID

in the low word of wParam, the notification code in the high word of wParam, and its window handle in

lParam. Each child window control has different notification codes, refer to your Win32 API reference

for more information.

The parent window can send commands to the child windows too, by calling win.SendMessage

function. win.SendMessage function sends the specified message with accompanying values in

wParam and lParam to the window specified by the window handle. It's an extremely useful function

since it can send messages to any window provided you know its window handle.

So, after creating the child windows, the parent window must process win. WM_COMMAND messages

to be able to receive notification codes from the child windows. The examples in this chapter uses

dialog box to place various controls.

Page 87: Skip to Content Skip to Navigation

3.2 Button Class

Buttons are Windows Controls that respond to user clicks. They are created with the CreateWindow or

CreateWindowEx Window function. They can have a variety of styles as shown below:

BS_AUTOCHECKBOX   Same as a check box, except that a

check mark appears in the check box when the user

selects the box; the check mark disappears the next time

the user selects the box.

BS_AUTORADIOBUTTON   Same as a radio button, except

that when the user selects it, the button automatically

highlights itself and removes the selection from any other

radio buttons with the same style in the same group.

BS_AUTO3STATE   Same as a three-state check box,

except that the box changes its state when the user

selects it.

BS_CHECKBOX   Creates a small square that has text

displayed to its right (unless this style is combined with

the BS_LEFTTEXT style).

BS_DEFPUSHBUTTON   Creates a button that has a heavy

black border. The user can select this button by pressing

the ENTER key. This style enables the user to quickly

select the most likely option (the default option).

BS_GROUPBOX   Creates a rectangle in which other

buttons can be grouped. Any text associated with this

style is displayed in the rectangle’s upper-left corner.

BS_LEFTTEXT   When combined with a radio-button or

check-box style, the text appears on the left side of the

radio button or check box.

BS_PUSHBUTTON   Creates a pushbutton that posts a

WM_COMMAND message to the owner window when the

user selects the button.

Page 88: Skip to Content Skip to Navigation

BS_RADIOBUTTON   Creates a small circle that has text

displayed to its right (unless this style is combined with

the BS_LEFTTEXT style). Radio buttons are usually used in

groups of related but mutually exclusive choices.

BS_3STATE   Same as a check box, except that the box

can be dimmed as well as checked. The dimmed state

typically is used to show that a check box has been

disabled.

3.2.1 Communication between Child and Parent Windows

When you click a button with the mouse the child window control sends a WM_COMMAND message to

its parent window. The program traps the WM_COMMAND message and displays the values of wparam

(child window ID and notification code) and lparam (child window handle). The notification code

indicates in more detail what the message means. The possible button notification messages are:

BN_CLICK

BN_DBCLICK

BN_PAINT

BN_KILLFOCUS

BN_HILITE

BN_UNHILITE

BN_PUSHED

BN_UNPUSHED

BN_DISABLE

BN_SETFOCUS

BN_KILLFOCUS

Page 89: Skip to Content Skip to Navigation

In addition to the notification messages mentioned above there are also button messages each begins

with letter BM. These messages are used by the window procedure to send messages to the child

window control. The button messages are:

BM_GETCHECK

BM_GETIMAGE

BM_GETSTATE

BM_SETCHECK

BM_SETIMAGE

BM_SETSTYLE

BM_CLICKED

3.2.2 Push Buttons

A small rectangular control that a user can turn on or off. A push button, also known as a command

button, has a raised appearance in its default off state and a depressed appearance when it is turned

on. Push button controls are used to trigger an immediate action without retaining any type of on/off

indication. The rectangle takes up the full height and width of the dimension given in the

CreateWindow. There are two types of push buttons BS_PUSHBUTTON and BS_DEFPUSHBUTTON where

“DEF” stands for default.

An application sends a BM_SETSTATE message to change the highlight state of a button. The highlight

state indicates whether the button is highlighted as if the user had pushed it.

BM_SETSTATE message syntax:

wParam = (WPARAM) fstate; // highlight state

lParam = 0; // not used; must be zero

where fState is the value of wParam and specifies whether the button is to be highlighted. A value of

TRUE or nonzero highlights the button. A value of FALSE or zero removes any highlighting.

This message always returns zero. Highlighting only affects the appearance of a button. It has no

effect on the check state or a radio button or check box. A button is automatically highlighted when

Page 90: Skip to Content Skip to Navigation

the user positions the cursor over it and presses and holds the left mouse button. The highlighting is

removed when the user releases the mouse button.

This call causes the button to be depressed:

SendMessage(hwndButton,BM_SETSTATE,1,0);

To return to the normal state the call to be used is:

SendMessage(hwndButton,BM_SETSTATE,0,0);

The hwndButton window handle is the value returned from the CreateWindow call. You can also send a

BM_GETSTATE message to push button. An application sends a BM_GETSTATE message to determine

the state of a button or check box. The value TRUE is returned if the button is depressed and FALSE if

it is not depressed. Most applications do not require this information.

BM_GETSTATE message syntax:

wParam = 0; // not used; must be zero

lParam = 0; // not used; must be zero

The BM_SETCHECK and BM_GETCHECK messages are not used by push button because they do not

retain on/off information.

3.2.3 Check Boxes

An interactive control found in graphical user interfaces. Check boxes are used to enable or disable

one or more features or options from a set. When an option is selected, an X or a check mark appears

in the box. The two most common styles of check box are BS_CHECKBOX and BS_AUTOCHECKBOX. You

can set the check state of the check box with the message BM_SETCHECK.

BM_SETCHECKMESSAGE has two parameters:

wParam = (WPARAM)fcheck; // check state

lParam = 0; // not used; must be zero

where fCheck is the value of wParam.and specifies the check state. This parameter can be one of the

values mentioned in Table 3.2.3.

Page 91: Skip to Content Skip to Navigation

Table 3.2.3 Values for fCheck Parameter

Value MeaningBST_CHECKED Sets the button state to checked.

BST_INDETERMINATESets the button state to grayed, indicating an indeterminate state. Use this value only if the button has the BS_3STATE or BS_AUTO3STATE style.

BST_UNCHECKED Sets the button state to cleared.TABLE 11

You can initialize a check box with a check mark by sending BM_SETCHECK message:

SendMessage(hwndButton,BM_SETCHECK,1,0);

For BS_AUTOCHECKBOX style the button control itself toggles the check mark on and off. When the

current state of the button is needed send the control a BM_GETCHECK message:

iCheck = (int) SendMessage(hwndButton,BM_SETCHECK,0,0);

The value of iCheck is TRUE or nonzero if the button is checked and FALSE or 0 if not checked.

3.2.4 Radio Buttons

A small round button with a label next to it. The label may be text, an icon, or a bitmap. Radio buttons,

also known as option buttons, are usually grouped together in a group box, representing a set of

related, but mutually exclusive options. When a user selects an option button or radio button, all other

option buttons in the same group is automatically unselected. The two most common styles of radio

buttons are BS_RADIOBUTTON and BS_AUTORADIOBUTTON. When you receive a WM_COMMAND

message from a radio button you should display its check by sending it a BM_SETCHECK with wparam

equal to 1:

SendMessage(hwndButton,BM_SETCHECK,1,0);

For all other radio buttons in the same group you can turn off the checks by sending them

BM_SETCHECK messages with wparam equal to 0:

SendMessage(hwndButton,BM_SETCHECK,0,0);

3.2.5 Group Boxes

Page 92: Skip to Content Skip to Navigation

The group box which has the BS_GROUPBOX style is a rectangular area within a dialog box in which

you can group together other controls that are semantically related. The controls are grouped by

drawing a rectangular border around them. Any text associated with the group box is displayed in its

upper-left corner. It neither processes mouse or keyboard input nor sends WM_COMMAND message to

its parent.

In the program given below dialog box is used to place various controls. The details regarding the

dialog box creation and usage is given in section 3.3.4.

3.2.6 Changing the Button Text and Input Focus

The text in the button can be changed by calling SetWindowText. However, SetWindowText cannot

change the text of a control in another application.

SetWindowText(

HWND hwnd, // handle to window or control

LPCTSTR lpstring // address of string

);

The parameters hwnd is a handle to the window or control whose text is to be

changed and lpstring is a pointer to a null-terminated string to be used as the new

title or control text.

You can also obtain the current text of a window by the command:

GetWindowText(

HWND hwnd, // handle to window or control with text

LPTSTR lpstring, // pointer to buffer for text

int nMaxCount // maximum number of characters to copy

);

The parameters hwnd is a handle to the window or control containing the text,

lpstring is a pointer to the buffer that will receive the text and nMaxCount specifies

Page 93: Skip to Content Skip to Navigation

the maximum number of characters to copy to the buffer, including the NULL

character. If the text exceeds this limit, it is truncated.

The push buttons, check boxes and radio buttons receive the input focus when they

are clicked with the mouse. When the child window control gets the input focus, the

parent window loses it. However the child window control responds only to the

spacebar which now functions like the mouse. When the window switches the input

focus from one window (parent) to another (child), it first sends WM_KILLFOCUS

message to the window losing the input focus.

case WM_KILLFOCUS:

if (hwnd==GetParent ((HWND) wparam))

SetFocus (hwnd);

return 0;

This method prevents the button from responding to the space bar because the

button never gets input focus. A better approach is to get input focus to the button

and also include the facility to move from button to button using Tab key.

3.2.7 System Colors

The parts of display can be painted using various system colors. GetSysColor and SetSysColor

functions are used to set these colors. The GetSysColor retrieves the current color of the specified

display element. Display elements are the parts of a window and the display that appear on the

system display screen. Identifiers defined in the windows header files specify the system color.

GetSysColor(

int nIndex // display element

);

The parameter nIndex specifies the display element whose color is to be retrieved. This parameter

must be one of the values mentioned in Table 3.2.7

Table 3.2.7 Values for nInex Parameter

Value Meaning

Page 94: Skip to Content Skip to Navigation

COLOR_3DDKSHADOWDark shadow for three-dimensional display elements.

COLOR_3DFACE, COLOR_BTNFACEFace color for three-dimensional display elements and for dialog box backgrounds.

COLOR_3DHILIGHT, COLOR_3DHIGHLIGHT, COLOR_BTNHILIGHT, COLOR_BTNHIGHLIGHT

Highlight color for three-dimensional display elements (for edges facing the light source.)

COLOR_3DLIGHTLight color for three-dimensional display elements (for edges facing the light source.)

COLOR_3DSHADOW, COLOR_BTNSHADOWShadow color for three-dimensional display elements (for edges facing away from the light source).

COLOR_ACTIVEBORDER Active window border.COLOR_ACTIVECAPTION Active window title bar.

COLOR_APPWORKSPACEBackground color of multiple document interface (MDI) applications.

COLOR_BACKGROUND, COLOR_DESKTOP Desktop.COLOR_BTNTEXT Text on push buttons.

COLOR_CAPTIONTEXTText in caption, size box, and scroll bar arrow box.

COLOR_GRAYTEXTGrayed (disabled) text. This color is set to 0 if the current display driver does not support a solid gray color.

COLOR_HIGHLIGHT Item(s) selected in a control.COLOR_HIGHLIGHTTEXT Text of item(s) selected in a control.COLOR_INACTIVEBORDER Inactive window border.COLOR_INACTIVECAPTION Inactive window caption.COLOR_INACTIVECAPTIONTEXT Color of text in an inactive caption.COLOR_INFOBK Background color for tooltip controls.COLOR_INFOTEXT Text color for tooltip controls.COLOR_MENU Menu background.COLOR_MENUTEXT Text in menus.COLOR_SCROLLBAR Scroll bar gray area.COLOR_WINDOW Window background.COLOR_WINDOWFRAME Window frame.COLOR_WINDOWTEXT Text in windows.TABLE 12

The SetSysColors function sets the colors for one or more display elements. Display elements are the

various parts of a window and the display that appear on the system display screen.

WINAPI SetSysColors(

Page 95: Skip to Content Skip to Navigation

int cElements, // number of elements to change

CONST int *lpaElements, // address of array of elements

CONST COLORREF *lpargbValues // address of array of RGB values

);

3.2.8 List Box Class

The list box is a window that displays a list of character strings. The user selects a string from the list

by tapping it with the stylus. When a string is selected, it appears highlighted. You can use a vertical or

horizontal scroll bar with a list box to scroll lists that are too long for the control window. The list box

automatically hides or shows the scroll bar, as needed.

Messages

As you may remember from our earlier discussion of the message loop, windows communicate using

messages, you send them to get a control to do something, and when an event occurs on the control it

will send you a notification message back. For the standard controls this notification will be a

WM_COMMAND message as we've already seen with buttons and menus. For the Common Controls

which I may get to later, it will be WM_NOTIFY.

The messages you send are widely varied between each control, and each control has it's own set of

messages. Once in a while the same message will be used for more than one kind of control, but in

general they will only work on the control they are intended for. This is especially annoying with the

listbox and combobox messages (LB_* and CB_*) which although they perform nearly identical tasks,

are NOT interchangeable.On the other hand, generic messages like WM_SETTEXT are supported by

almost all controls. A control is just a window after all.

You can send messages using the SendMessage() API, and use GetDlgItem() to retreive the handle to

the control, or you can use SendDlgItemMessage() which does both steps for you, the results of both

methods are identical.

Adding Items to list box

The first thing you'll want to do with a listbox is add items to it.

int index = SendDlgItemMessage(hwnd, IDC_LIST, LB_ADDSTRING, 0, (LPARAM)"Hi there!");

Page 96: Skip to Content Skip to Navigation

As you can see, this is a pretty simple task. If the listbox has the LBS_SORT style, the new item will be

added in alphabetical order; otherwise it will just be added to the end of the list.

This message returns the index of the new item either way, and we can use this to perform other tasks

on the item, such as associating some data with it. Usually this will be things like a pointer to a struct

containing more information, or maybe an ID that you will use to identify the item, it's up to you.

SendDlgItemMessage(hwnd, IDC_LIST, LB_SETITEMDATA, (WPARAM)index, (LPARAM)nTimes);

Notifications

The whole purpose of listboxes is to allow the user to select things from a list. Now sometimes we

don't care when exactly they do this, for example with our Remove button, we don't need to know

when the selection changes right away, we just check when the user activates the button.

However, sometimes you want to be able to do something right away, perhaps display different or

updated information based on what items are selected. In order to do this we need to handle the

notification messages that the listbox passes to us. In this case, we are interested in LBN_SELCHANGE,

which tells us that the selection has been modified by the user. LBN_SELCHANGE is sent via

WM_COMMAND but unlike handling the WM_COMMAND from buttons or menu's, which are usually only

in response to a click, a list box sends WM_COMMAND for various reasons, and we need a second

check to find out what it's telling us. The Notification Code is passed as the HIWORD of wParam, the

other half of the parameter that gave us the control ID in the first place.

case WM_COMMAND:

switch(LOWORD(wParam))

{

case IDC_LIST:

// It's our listbox, check the notification code

switch(HIWORD(wParam))

{

case LBN_SELCHANGE:

Page 97: Skip to Content Skip to Navigation

// Selection changed, do stuff here.

break;

}

break;

// ... other controls

}

break;

Getting Data from the ListBox

Now that we know the selection has changed, or at the request of the user, we need to get the

selection from the listbox and do something useful with it.

In this example I've used a multiselection list box, so getting the list of selected items is a little trickier.

If it were a single selection listbox, than you could simply send LB_GETCURSEL to retrieve the item

index.

First we need to get the number of selected items, so that we can allocate a buffer to save the indexes

in.

HWND hList = GetDlgItem(hwnd, IDC_LIST);

int count = SendMessage(hList, LB_GETSELCOUNT, 0, 0);

Then we allocate a buffer based on the number of items, and send LB_GETSELITEMS to fill in the array.

int *buf = GlobalAlloc(GPTR, sizeof(int) * count);

SendMessage(hList, LB_GETSELITEMS, (WPARAM)count, (LPARAM)buf);

// ... Do stuff with indexes

GlobalFree(buf);

In this example, buf[0] is the first index, and so on up to buf[count - 1].

Page 98: Skip to Content Skip to Navigation

One of the things you would likely want to do with this list of indexes, is retreive the data associated

with each item, and do some processing with it. This is just as simple as setting the data was originally,

we just send another message.

int data = SendMessage(hList, LB_GETITEMDATA, (WPARAM)index, 0);

If the data was some other type of value (anything that is 32-bits) you could simply cast to the

appropriate type. For example if you stored HBITMAPs instead of ints...

HBITMAP hData = (HBITMAP)SendMessage(hList, LB_GETITEMDATA, (WPARAM)index, 0);

Example Program illustrating the use of Controls

Create an application named ControlDemo by selecting the project type Win 32 Application in the

appwizard and click OK. Now an empty project without using MFC classes is created.

Click Insert->Resource from the menu and then select the Dialog option. Design the dialog as shown in

figure 3.2.8(a).

Figure 3.2.8(a) Dialog design for ControlDemo program

Change the ID for the controls as shown below:

Control TypeID

Edit ControlID_CNAME

Page 99: Skip to Content Skip to Navigation

List BoxID_ITEM

Option button (Cash)ID_CASH

Option button(Cheque)ID_CHEQUE

Select Insert-> resource from the menu and then select the option Menu from it. The menu contains

two options named (Item and Exit). If the Item option is clicked Dialog box containing the controls will

be displayed. If the Exit option is selected from the menu the output window will be closed. Now close

your dialog window and save your design by giving a name to the Script. This will be stored in .rc

extension. Include this file and the resource header file (resource.h) to your project by clicking Project-

>Add to Project->Files. Now select the .rc and resource.h file for your project and click OK. Now the

resource is included in your project workspace.

Click File->New and then select the option C++ Source File and give a name to the .cpp

implementation file (here the name is Control.cpp). Enter the code given below in the implementation

file (Control.cpp).

# include <windows.h>

#include "resource.h"

HINSTANCE hInstance;

WNDCLASS wc;

MSG msg;

HWND hwnd;

LRESULT CALLBACK wndproc(HWND hwnd,UINT wm,WPARAM wp,LPARAM lp);

LRESULT CALLBACK item(HWND hDlg,UINT wm,WPARAM wp,LPARAM lp);

int APIENTRY WinMain(HINSTANCE hInst,HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow)

{

//TODO :place code here

if(hPrevInstance==NULL)

Page 100: Skip to Content Skip to Navigation

{

memset(&wc,0,sizeof(wc));

wc.style=CS_HREDRAW;

wc.lpfnWndProc=wndproc;

wc.hInstance=hInstance;

wc.hCursor=LoadCursor(hInstance,IDC_CROSS);

wc.hIcon=LoadIcon(hInstance,NULL);

wc.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);

wc.lpszClassName="Sample";

wc.lpszMenuName=MAKEINTRESOURCE(IDR_MENU1);

if(!RegisterClass(&wc))

return false;

}

hwnd=CreateWindow("Sample","Control

Demo",WS_OVERLAPPEDWINDOW,10,10,500,500,NULL,NULL,hInst,NULL);

ShowWindow(hwnd,nCmdShow);

UpdateWindow(hwnd);

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

DispatchMessage(&msg);

//return 0;

return true;

}

Page 101: Skip to Content Skip to Navigation

LRESULT CALLBACK wndproc(HWND hwnd,UINT wm,WPARAM wp,LPARAM lp)

{DLGPROC dlgproc;

switch(wm)

{

case WM_COMMAND:

switch(wp)

{

case ID_ITEM:

dlgproc=(DLGPROC)item;

DialogBox(hInstance,MAKEINTRESOURCE(IDD_DIALOG1),hwnd,dlgproc);

return 0;

break;

case ID_EXIT:

DestroyWindow(hwnd);

break;

}

break;

case WM_DESTROY :

PostQuitMessage(0);

break;

}

return(DefWindowProc(hwnd,wm,wp,lp));

Page 102: Skip to Content Skip to Navigation

}

char itm[5][10]={ "Hard Disk",

"Printer",

"Monitor",

"Scanner",

"Keyboard"};

LRESULT CALLBACK item(HWND hDlg,UINT wm,WPARAM wp,LPARAM lp)

{static HWND hlist;

char cname[30],optionsel[10],str[100],payment[10];

int i,sel,cash,cheque;

switch(wm)

{

case WM_INITDIALOG:

for(i=0;i<5;i++)

SendDlgItemMessage(hDlg,ID_ITEM,LB_ADDSTRING,0,(LPARAM)(LPCTSTR)itm[i]);

return true;

case WM_COMMAND:

switch(wp)

{

case IDOK:

sel=SendDlgItemMessage(hDlg,ID_ITEM,LB_GETCURSEL,0,0);

SendDlgItemMessage(hDlg,ID_ITEM,LB_GETTEXT,sel,(LPARAM)(LPCTSTR)optionsel);

Page 103: Skip to Content Skip to Navigation

cash=SendDlgItemMessage(hDlg,ID_CASH,BM_GETCHECK,0,0);

cheque=SendDlgItemMessage(hDlg,ID_CHEQUE,BM_GETCHECK,0,0);

if(cash==BST_CHECKED)

strcpy(payment,"Cash");

else

{if(cheque==BST_CHECKED)

strcpy(payment,"Cheque");

}

GetDlgItemText(hDlg,ID_CNAME,cname,30);

wsprintf(str,"%s is purchased from %s , Payment is by %s",optionsel,cname,payment);

MessageBox(hDlg,str,"Item details",0);

EndDialog(hDlg,true);

return 1;

case IDCANCEL:

EndDialog(hDlg,false);

return 1;

}

break;

}

return 0;

};

Page 104: Skip to Content Skip to Navigation

Now Compile, Build and Execute the program. The output window appears as shown in figure 3.2.8(b).

Click the Item option from menu. The dialog resource appears.Select any one of the item from the list

box . Enter the Company name and click OK. A message is displayed as shown in figure 3.2.8(b).

Figure 3.2.8(b) Running Instance of ControlDemo Program

3.2.9 Edits

One of the most commonly used controls in the windows environment, the EDIT control, is used to

allow the user to enter, modify, copy, etc... text. Windows Notepad is little more than a plain old

window with a big edit control inside it.

Here is the code used to interface with the edit control in this example:

SetDlgItemText(hwnd, IDC_TEXT, "This is a string");

That's all it takes to change the text contained in the control (this can be used for pretty much any

control that has a text value associated with it, STATICs, BUTTONs and so on).

Page 105: Skip to Content Skip to Navigation

Retrieving the text from the control is easy as well, although slightly more work than setting it...

int len = GetWindowTextLength(GetDlgItem(hwnd, IDC_TEXT));

if(len > 0)

{

int i;

char* buf;

buf = (char*)GlobalAlloc(GPTR, len + 1);

GetDlgItemText(hwnd, IDC_TEXT, buf, len + 1);

//... do stuff with text ...

GlobalFree((HANDLE)buf);

}

First of all, we need to allocate some memory to store the string in, it won't just return us a pointer to

the string already in memory. In order to do this, we first need to know how much memory to allocate.

There isn't a GetDlgItemTextLength(), but there is a GetWindowTextLength(), so all we need to do it

get the handle to the control yourself using GetDlgItem().

Now that we have the length, we can allocate some memory. Here I've added a check to see if there is

any text to begin with, since most likely you don't want to be working with an empty string...

sometimes you might, but that's up to you. Assuming that there is something there to work with, we

call GlobalAlloc() to allocate some memory. GlobalAlloc() is equivalent to calloc(), if you're used to

DOS/UNIX coding. It allocates some memory, initializes it's contents to 0 and returns a pointer to that

memory. There are different flags you can pass as the first parameter to make it behave differently for

different purposes, but this is the only way I will be using it in this tutorial.

Note that I added 1 to the length in two places, what's up with that? Well, GetWindowTextLength()

returns the number of characters of text the control contains NOT INCLUDING the null terminator. This

means that if we were to allocate a string without adding 1, the text would fit, but the null terminator

would overflow the memory block, possibly corrupting other data, causing an access violation, or any

number of other bad things. You must be careful when dealing with string sizes in windows, some APIs

Page 106: Skip to Content Skip to Navigation

and messages expect text lengths to include the null and others don't, always read the docs

thoroughly.

Finally we can call GetDlgItemText() to retrieve the contents of the control into the memory buffer that

we've just allocated. This call expects the size of the buffer INCLUDING the null terminator. The return

value, which we ignored here, is the number of characters copied, NOT including the null

terminator.After we're all done using the text (which we'll get to in a moment), we need to free up the

memory that we allocated so that it doesn't leak out and drip down onto the CPU and short circuit your

computer. To accomplish this, we simply call GlobalFree() and pass in our pointer.

You may be or become aware of a second set of APIs named LocalAlloc(), LocalFree(), etc... which are

legacy APIs from 16-bit windows. In Win32, the Local* and Global* memory functions are identical.

Edits with Numbers

Entering text is all well and fine, but what if you want the user to enter in a number? This is a pretty

common task, and fortunately there is an API to make this simpler, which takes care of all the memory

allocation, as well as converting the string to an integer value.

BOOL bSuccess;

int nTimes = GetDlgItemInt(hwnd, IDC_NUMBER, &bSuccess, FALSE);

GetDlgItemInt() works much like GetDlgItemText(), except that instead of copying the string to a

buffer, it converts it internally into an integer and returns the value to you. The third parameter is

optional, and takes a pointer to a BOOL. Since the function returns 0 on failure, there is no way to tell

just from that whether or not the function failed or the user just entered 0. If you are fine with a value

of 0 in the event of an error, then feel free to ignore this parameter.

Another useful feature is the ES_NUMBER style for edit controls, which allows only the characters 0

through 9 to be entered. This is very handy if you only want positive integers, otherwise it's not much

good, since you can't enter any other characters, including - (minus) . (decimel) or , (comma).

3.2.10 Statics

Like buttons, static controls are largely trivial, but for the sake or being complete I include them here.

Static controls are usually just that, static, meaning they don't change or really do anything else very

special, they're largely for displaying text to the user. However you can make them slightly more

Page 107: Skip to Content Skip to Navigation

useful by assigning them a unique ID (VC++ assigns a default ID of IDC_STATIC, which is -1 and

effectively means "No ID") and then setting the text at runtime to present dynamic data to the user.

In the example code, I use one to display the data of the item selected in the list box, assuming one

and only one is selected.

SetDlgItemInt(hwnd, IDC_SHOWCOUNT, data, FALSE);

3.2.11 Scroll Bar Class

In some graphical user interfaces, a vertical or horizontal bar at the side or bottom of a display area

that can be used with a mouse for moving around in that area. Scroll bars often have four active areas:

two scroll arrows for moving line by line, a sliding scroll box for moving to an arbitrary location in the

display area, and the gray areas in the scroll bar for moving in of one-window increments.

You add the window scroll bar by including the identifier WS_VSCROLL or WS_HSCROLL or both in the

window style. scroll bar control can have a number of styles to control the orientation and position of

the scroll bar. You specify the styles that you want when you call the CreateWindowEx 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. Two commonly used scroll bar styles are SBS_VERT and SBS_HORZ.

Example Program to change the Color of the Text using Scroll bar

Create an application named ScrollBar by selecting the project type Win 32 Application in the

appwizard and click OK. Now an empty project without using MFC classes is created. Click File->New

and then select the option C++ Source File and give a name to the .cpp implementation file (here the

name is Scroll.cpp). Enter the code given below in the implementation file (Scroll.cpp).

#include<windows.h>

HINSTANCE hinst;

HWND hscroll[3],hwnd1;

int nval[3];

RECT r;

int i1=255,i2=255,i3=255,j;

Page 108: Skip to Content Skip to Navigation

int key=0;

int h=0;

HBRUSH hbrush;

LRESULT CALLBACK wndproc(HWND hwnd,UINT wm,WPARAM wp,LPARAM lp)

{

HDC hdc;

PAINTSTRUCT ps;

int i;

r.left=0;

r.right=800;

r.top=0;

r.bottom=800;

switch(wm)

{

case WM_COMMAND:

case WM_CREATE:

for(i=0;i<3;i++)

{

hscroll[i]=CreateWindow("scrollbar","",WS_CHILD,10,10+40*i,

130,30,hwnd,NULL,hinst,NULL);

ShowScrollBar(hscroll[i],SB_CTL,SW_SHOW);

SetScrollRange(hscroll[i],SB_CTL,0,255,FALSE);

Page 109: Skip to Content Skip to Navigation

SetScrollPos(hscroll[i],SB_CTL,0,TRUE);

nval[i]=0;

}

break;

case WM_HSCROLL:

switch(LOWORD(wp))

{

case SB_LINEUP:

hwnd1=(HWND)lp;

for(j=0;j<3;j++)

{

if(hscroll[j]==hwnd)

break;

}

nval[j]-=1;

h=nval[j];

break;

case SB_LINEDOWN:

hwnd1=(HWND)lp;

for(j=0;j<3;j++)

{

if(hscroll[j]==hwnd1)

Page 110: Skip to Content Skip to Navigation

break;

}

nval[j]+=1;

h=nval[j];

break;

case SB_PAGEDOWN:

hwnd1=(HWND)lp;

for(j=0;j<3;j++)

{

if(hscroll[j]==hwnd1)

break;

}

nval[j]+=10;

h=nval[j];

break;

case SB_PAGEUP:

hwnd1=(HWND)lp;

for(j=0;j<3;j++)

{

if(hscroll[j]==hwnd1)

break;

}

Page 111: Skip to Content Skip to Navigation

nval[j]-=10;

h=nval[j];

break;

case SB_THUMBPOSITION:

hwnd1=(HWND)lp;

for(j=0;j<3;j++)

{

if(hscroll[j]==hwnd1)

{

h=HIWORD(wp);

nval[j]=h;

break;

}

}

break;

}

ShowScrollBar(hwnd1,SB_CTL,SW_SHOW);

SetScrollPos(hwnd1,SB_CTL,h,TRUE);

hdc=GetDC(hwnd);

if(key==0)

{

SetTextColor(hdc,RGB(nval[0],nval[1],nval[2]));

Page 112: Skip to Content Skip to Navigation

TextOut(hdc,100,200,"the Color of the text is changing",33);

ReleaseDC(hwnd,hdc);

}

else

{

i1=nval[0];

i2=nval[1];

i3=nval[2];

SetClassLong(hwnd,GCL_HBRBACKGROUND,(LONG)CreateSolidBrush(RGB(nval[0],nval[1],nval[2])));

SetBkColor(hdc,RGB(nval[0],nval[1],nval[2]));

InvalidateRect(hwnd,&r,TRUE);

}

break;

case WM_PAINT:

hdc=BeginPaint(hwnd,&ps);

EndPaint(hwnd,&ps);

break;

case WM_DESTROY:

PostQuitMessage(0);

break;

default:

return DefWindowProc(hwnd,wm,wp,lp);

Page 113: Skip to Content Skip to Navigation

}

return 0;

}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPSTR lpCmdLine, int nCmdShow)

{

WNDCLASSEX wc;

HWND hwnd;

MSG Msg;

wc.cbSize = sizeof(WNDCLASSEX);

wc.style = 0;

wc.lpfnWndProc = wndproc;

wc.cbClsExtra = 0;

wc.cbWndExtra = 0;

wc.hInstance = hInstance;

wc.hIcon = LoadIcon(NULL,IDI_APPLICATION);

wc.hCursor = LoadCursor(NULL, IDC_ARROW);

wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);

wc.lpszMenuName = NULL;

wc.lpszClassName = "scroll bar";

wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

if(!RegisterClassEx(&wc))

Page 114: Skip to Content Skip to Navigation

{

MessageBox(NULL, "Window Registration Failed!", "Error!",

MB_ICONEXCLAMATION | MB_OK);

return 0;

}

hwnd = CreateWindowEx(

WS_EX_CLIENTEDGE,

"scroll bar",

"Scroll bar Program",

WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,

NULL, NULL, hInstance, NULL);

if(hwnd == NULL)

{

MessageBox(NULL, "Window Creation Failed!", "Error!",

MB_ICONEXCLAMATION | MB_OK);

return 0;

}

ShowWindow(hwnd, nCmdShow);

UpdateWindow(hwnd);

while(GetMessage(&Msg, NULL, 0, 0) > 0)

{

Page 115: Skip to Content Skip to Navigation

TranslateMessage(&Msg);

DispatchMessage(&Msg);

}

return Msg.wParam;

}

Compile, Build and Execute the program. The output of the program is shown in figure 3.2.11. As you

scroll the scroll bars the color of the text will be changed.

Figure 3.2.11 Running Instance of ScrollBar Program

3.3 Windows Resources

Windows resources include icons, cursors, menus, dialog boxes, bitmaps, fonts, keyboard accelerator

tables, message table entries, string table entries, version data, and user-defined data. Resources are

data that are stored in program’s .exe file, but they do not reside in the executable program’s data

area. Windows provides functions that explicitly or implicitly load a programs resource in to memory so

that they can be used. In this section the resources such as icons, cursors, character strings, menus,

keyboard accelerators, dialog boxes and bitmaps are described.

3.3.1 Icons

Page 116: Skip to Content Skip to Navigation

An icon is a small bitmap that represents another object in a windows program. Icons are used to

represent minimized child windows in MDI application. Icons are widely used by windows itself. When a

program is minimized its icon is displayed in the windows task bar. When you are using the explorer,

the icon representing an application associated with each file is displayed next to the file’s name.

Windows displays the program’s icon in the upper left corner of the main window title bar. There are

four different types of icons such as:

Large Icons: Used for most programs written for

windows before the release of Windows 95, these

icons are 32x32 pixels in size and support 16

colors.

Small Icons: First introduced with Windows 95,

these icons are usually a smaller 16x16 pixels

version of a program’s large icon.

256 Color Icons: These icons support more than

the standard 16 colors available to other types of

icons. These icons are 48x48 pixels in size and

never displayed as a program’s icon when the

window is minimized.

Monochrome Icons: These icons support only two

colors and are 32x32 pixels.

Creating Icons Using Image Editor

When creating a new project, AppWizard creates a set of default icons for your project automatically.

You can use the Developer Studio image editor to edit or create new icons for your project. To open

the image editor, open the Resource view in the project workspace and then open the icon folder.

Double click any icon resource contained in the folder to open the editor.

To insert a new icon resource in to an existing project, right click the icon folder in the resource view

and select insert icon from pop up menu; this opens the image editor with a blank icon ready for

editing.

Page 117: Skip to Content Skip to Navigation

Figure 3.3.1 The standard 32x32 Icon file as displayed in Developer Studio

The program can be compiled and run now. Developer studio has put a line in the .rc resource script

that equates the icon file with an identifier (IDI_ICON). The header file “resource.h” contains the

definition of IDI_ICON. Developer studio compiles resources by using the resource compiler rc.exe. The

text resource script is converted in to a binary form which is a file with extension .res.

Loading an Icon in your programs

After you have added an icon to a project, loading and displaying it can be bone through LoadIcon

command. A program can obtain a handle to icon by calling LoadIcon:

hIcon = LoadIcon (hInstance,MAKEINTRESOURCE (IDI_ICON));

LoadIcon returns a value of type HICON, a handle to an icon. The parameters

hInstance is a handle to an instance of the module whose executable file contains the

icon to be loaded. This parameter must be NULL when a standard icon is being loaded

and MAKEINTRESOURCE contains the name of the icon resource to be loaded. To use

one of the predefined icons, set the hInstance parameter to NULL and the second

parameter to one of the values in Table 3.3.1.

Table 3.3.1 Second Parameter values for LoadIcon

Value DescriptionIDI_APPLICATION Default application icon.IDI_ASTERISK Same as IDI_INFORMATION.IDI_ERROR Hand-shaped icon.IDI_EXCLAMATIONSame as IDI_WARNING.IDI_HAND Same as IDI_ERROR.

Page 118: Skip to Content Skip to Navigation

IDI_INFORMATION Asterisk icon.IDI_QUESTION Question mark icon.IDI_WARNING Exclamation point icon.IDI_WINLOGO Windows logo icon.TABLE 13

The icon created can be displayed in its client area, repeated horizontally and vertically using the

statement LoadIcon and obtains a handle to the icon using the statements:

cxIcon = GetSystemMetrics (SM_CXICON);

cyIcon = GetSystemMetrics (SM_CYICON);

It obtains the size of the icon. The program can then display the icon with multiple calls to

DrawIcon (hdc , x , y ,hIcon);

Where x and y coordinates of where the upper left corner of the displayed icon is positioned. The

smaller icon size can also be obtained from the system metrics SM_CXSMSIZE and SM_CYSMSIZE

indices. The first SM means system metrics and the second SM means small.

Example program for icon demo

Create an application named IconDemo by selecting the project type Win 32 Application in the

appwizard and click OK. Now an empty project without using MFC classes is created.

Click Insert->Resource from the menu and then select the Icon option. Design the Icon as shown in

figure 3.3.1(a).

Figure 3.3.1(a) Icon design for the program

Page 119: Skip to Content Skip to Navigation

Save the icon design in your project and then include the .rc and resource.h header file to your project

workspace. Change the ID for Icon as ID_ICON Click File->New and then select the option C++ Source

File and give a name to the .cpp implementation file (here the name is Icon.cpp). Enter the code given

below in the implementation file (Icon.cpp).

#include <windows.h>

#include "resource.h"

const char g_szClassName[] = "myWindowClass";

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)

{static HICON hIcon;

static int cxIcon,cyIcon,cxClient,cyClient;

HDC hdc;

HINSTANCE hInstance;

PAINTSTRUCT ps;

int x,y;

switch(msg)

{

case WM_CREATE:

hInstance=((LPCREATESTRUCT)lParam)->hInstance;

hIcon=LoadIcon(hInstance,MAKEINTRESOURCE (IDI_ICON));

cxIcon=GetSystemMetrics(SM_CXICON);

cyIcon=GetSystemMetrics(SM_CYICON);

return 0;

case WM_SIZE:

Page 120: Skip to Content Skip to Navigation

cxClient=LOWORD(lParam);

cyClient=HIWORD(lParam);

return 0;

case WM_PAINT:

hdc=BeginPaint(hwnd,&ps);

for(y=0;y<cyClient;y+=cyIcon)

for(x=0;x<cxClient;x+=cxIcon)

DrawIcon(hdc,x,y,hIcon);

EndPaint(hwnd,&ps);

return 0;

case WM_CLOSE:

DestroyWindow(hwnd);

break;

case WM_DESTROY:

PostQuitMessage(0);

break;

default:

return DefWindowProc(hwnd, msg, wParam, lParam);

}

return 0;

}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

Page 121: Skip to Content Skip to Navigation

LPSTR lpCmdLine, int nCmdShow)

{

WNDCLASSEX wc;

HWND hwnd;

MSG Msg;

wc.cbSize = sizeof(WNDCLASSEX);

wc.style = 0;

wc.lpfnWndProc = WndProc;

wc.cbClsExtra = 0;

wc.cbWndExtra = 0;

wc.hInstance = hInstance;

wc.hIcon = LoadIcon(hInstance,MAKEINTRESOURCE(IDI_ICON));

wc.hCursor = LoadCursor(NULL, IDC_ARROW);

wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);

wc.lpszMenuName = NULL;

wc.lpszClassName = g_szClassName;

wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

if(!RegisterClassEx(&wc))

{MessageBox(NULL, "Window Registration Failed!", "Error!",

MB_ICONEXCLAMATION | MB_OK);

return 0;

}

Page 122: Skip to Content Skip to Navigation

hwnd = CreateWindowEx(

WS_EX_CLIENTEDGE,

g_szClassName,

"Icon Demo Program",

WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,

NULL, NULL, hInstance, NULL);

if(hwnd == NULL)

{MessageBox(NULL, "Window Creation Failed!", "Error!",

MB_ICONEXCLAMATION | MB_OK);

return 0;

}

ShowWindow(hwnd, nCmdShow);

UpdateWindow(hwnd);

while(GetMessage(&Msg, NULL, 0, 0) > 0)

{TranslateMessage(&Msg);

DispatchMessage(&Msg);

}

return Msg.wParam;

}

Compile, Build and Execute the program. The output is as shown in figure 3.3.1(b).

Page 123: Skip to Content Skip to Navigation

Figure 3.3.1(b) Running Instance of IconDemo Program

3.3.2 Cursors

Cursors represent the position of a pointing device, such as a mouse. You can create a cursor in the

same way as an icon by selecting resource from insert menu and selecting cursor. After you have

added a cursor to a project, loading and displaying it can be bone through LoadCursor command.

wndclass.hCursor = LoadCursor (hInstance,szCursor);

Whenever the mouse is positioned over a window created based on this class the cursor associated

with IDC_CURSOR or szCursor will be displayed. If you separate your client area in to smaller logical

areas without using child windows, you can use SetCursor to establish the cursor shape.

SetCursor (hCursor);

3.3.3 Menus

A menu is probably the most important of the consistent user interface that windows programs offer,

and adding a menu to your program is a relatively easy part of windows programming. This will be

created as .rc file and will be compiled and linked into your .exe. This is rather compiler specific,

commercial compilers will have a resource editor that you can use to create your menus, but for this

example I will show the text of the .rc file so you can add it in manually. I usually have an .h file as well

which is included in both my .rc file and my .c source files. This file contains the identifiers for controls

and menu items etc.

For this example you can start with the window code from simple_window and add this code into it as

instructed.

Page 124: Skip to Content Skip to Navigation

First the .h file. Usually called "resource.h"

#define IDR_MYMENU 101

#define IDI_MYICON 201

#define ID_FILE_EXIT 9001

#define ID_STUFF_GO 9002

Not much there, but our menu will be pretty simple. The names and values here are up to you for the

choosing. Now we write our .rc file.

#include "resource.h"

IDR_MYMENU MENU

BEGIN

POPUP "&File"

BEGIN

MENUITEM "E&xit", ID_FILE_EXIT

END

POPUP "&Stuff"

BEGIN

MENUITEM "&Go", ID_STUFF_GO

MENUITEM "G&o somewhere else", 0, GRAYED

END

END

IDI_MYICON ICON "menu_one.ico"

You will want to add the .rc file to your project or makefile depending on what tools you are using.

Page 125: Skip to Content Skip to Navigation

You also want to #include "resource.h" in your source file (.c) so that the menu command identifiers

and the menu resource id will be defined. The easiest way to attach the menu and icon to your window

is to specify them when you register the window class, like this:

wc.lpszMenuName=MAKEINTRESOURCE(IDR_MYMENU); wc.hIcon=LoadIcon(GetModuleHandle(NULL),

MAKEINTRESOURCE(IDI_MYICON));

wc.hIconSm=(HICON)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_MYICON),

IMAGE_ICON, 16, 16, 0);

Change that and see what happens. Your window should now have a File and Stuff menu with the

respective items underneath. That is assuming your .rc file was properly compiled and linked into your

program.

I've used LoadIcon() to load the large icon because it's simpler, however it will only load icons at the

default resolution of 32x32, so in order to load the smaller image, we need to use LoadImage(). Be

aware that icon files and resources can contain multiple images, and in this case the ones I've supplied

contain the two sizes that I'm loading.

An alternative to using a menu resource is to create one on the fly (or when your program runs). This

is a bit more work programming wise, but adds flexibility and is sometimes necessary.

You can also use icons that aren't stored as resources, you could choose to store your icon as a

separate file and load it at runtime. This would also give you the option of allowing the user to select

an icon of their choice with the common dialogs discussed later, or something to that effect.

Start again from simple_window without the .h or .rc added. Now we will handle the WM_CREATE

message and add a menu to our window.

#define ID_FILE_EXIT 9001

#define ID_STUFF_GO 9002

Put these two id's at the top of your .c file this time, underneath your #includes. Next we add the

following code into our WM_CREATE handler.

case WM_CREATE:

{

Page 126: Skip to Content Skip to Navigation

HMENU hMenu, hSubMenu;

HICON hIcon, hIconSm;

hMenu = CreateMenu();

hSubMenu = CreatePopupMenu();

AppendMenu(hSubMenu, MF_STRING, ID_FILE_EXIT, "E&xit");

AppendMenu(hMenu,MF_STRING| MF_POPUP,(UINT)hSubMenu, "&File");

hSubMenu = CreatePopupMenu();

AppendMenu(hSubMenu, MF_STRING, ID_STUFF_GO, "&Go");

AppendMenu(hMenu,MF_STRING|MF_POPUP, (UINT)hSubMenu, "&Stuff");

SetMenu(hwnd, hMenu);

hIcon=LoadImage(NULL,"menu_two.ico",IMAGE_ICON,32,32,LR_LOADFROMFILE);

if(hIcon)

SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);

else

MessageBox(hwnd,"Could not load large icon!", "Error", MB_OK | MB_ICONERROR);

hIconSm = LoadImage(NULL, "menu_two.ico", IMAGE_ICON, 16, 16, LR_LOADFROMFILE);

if(hIconSm)

SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hIconSm);

else

MessageBox(hwnd, "Could not load small icon!", "Error", MB_OK | MB_ICONERROR);

}

break;

Page 127: Skip to Content Skip to Navigation

This creates a menu almost the same as the one we had in the resource and attaches it to our window.

A menu that is assigned to a window is automatically removed when the program terminates, so we

don't need to worry about getting rid of it later. If we did though, we could use GetMenu() and

DestroyMenu().

The code for the icons is pretty simple, we call LoadImage() twice, to load the icon as both a 16x16

size and a 32x32 size. We can't use LoadIcon() at all because it will only load resources, not files. We

specify NULL for the instance handle parameter because we aren't loading a resource from our

module, and instead of a resource ID we pass in the name of the icon file we want to load. Finally, we

pass in the LR_LOADFROMFILE flag to indicate that we want the function to treat the string we give it

as a filename and not a resource name.

If each call succeeds we assign the icon handle to our window with WM_SETICON, and if it fails we pop

up a message box letting us know something went wrong. Note that the LoadImage() calls will fail if

the icon file isn't in the current working directory of the program. If you are using VC++ and you run

the program from the IDE, the current working directory will be the one the project file is in. However if

you run the program from the Debug or Release directories from explorer or the command shell, then

you'll need to copy the icon file into that directory in order for the program to find it. If all else fails,

specify the full path to the icon, "C:\\Path\\To\\Icon.ico".

Now that we have our menu, we need to make it do something. This is pretty simple, all we need to do

is handle the WM_COMMAND message. Also we'll need to check which command we are getting and

act accordingly. Now our WndProc() should look something like this.

LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)

{

switch(Message)

{

case WM_CREATE:

{

HMENU hMenu, hSubMenu;

hMenu = CreateMenu();

Page 128: Skip to Content Skip to Navigation

hSubMenu = CreatePopupMenu();

AppendMenu(hSubMenu, MF_STRING, ID_FILE_EXIT, "E&xit");

AppendMenu(hMenu,MF_STRING|MF_POPUP,(UINT)hSubMenu,"&File");

hSubMenu = CreatePopupMenu();

AppendMenu(hSubMenu, MF_STRING, ID_STUFF_GO, "&Go");

AppendMenu(hMenu,MF_STRING|MF_POPUP, (UINT)hSubMenu, "&Stuff");

SetMenu(hwnd, hMenu);

hIcon = LoadImage(NULL, "menu_two.ico", IMAGE_ICON, 32, 32, LR_LOADFROMFILE);

if(hIcon)

SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);

Else

MessageBox(hwnd, "Could not load large icon!", "Error", MB_OK | MB_ICONERROR);

hIconSm=LoadImage(NULL,"menu_two.ico",IMAGE_ICON,16,16, LR_LOADFROMFILE);

if(hIconSm)

SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hIconSm);

else

MessageBox(hwnd, "Could not load small icon!", "Error", MB_OK | MB_ICONERROR);

}

break;

case WM_COMMAND:

switch(LOWORD(wParam))

{

Page 129: Skip to Content Skip to Navigation

case ID_FILE_EXIT:

break;

case ID_STUFF_GO:

break;

}

break;

case WM_CLOSE:

DestroyWindow(hwnd);

break;

case WM_DESTROY:

PostQuitMessage(0);

break;

default:

return DefWindowProc(hwnd, Message, wParam, lParam);

}

return 0;

}

As you can see we've got our WM_COMMAND all set up, and it even has another switch() in it. This

switch()'s on the value of the low word of wParam, which in the case of WM_COMMAND contains the

control or menu id that sent the message.

We obviously want the Exit menu item to close the program. So in the WM_COMMAND, ID_FILE_EXIT

handler you can use the following code to do just that.

PostMessage(hwnd, WM_CLOSE, 0, 0);

Page 130: Skip to Content Skip to Navigation

Your WM_COMMAND handler should now look like this:

case WM_COMMAND:

switch(LOWORD(wParam))

{

case ID_FILE_EXIT:

PostMessage(hwnd, WM_CLOSE, 0, 0);

break;

case ID_STUFF_GO:

break;

}

break;

Example Program to illustrate menu design

Create an application named ModalDialog by selecting the project type Win 32 Application in the

appwizard and click OK. Now an empty project without using MFC classes is created. Design the Menu

resource with the options Stuff and File. Under the option Stuff options Go and GoSomewhereElse are

included. Under the option File->Exit is included. After designing the menu save the script with .rc

extension and then include this .rc file and resource.h header file in your project. Change the ID for

menu as IDR_MENU1. Similarly open the Icon resource and make a design of your own. Change the ID

of Icon as IDI_MYICON. The Icon which you design will appear on the top of the window.

Click File->New and then select the option C++ Source File and give a name to the .cpp

implementation file (here the name is Menu.cpp). Enter the code given below in the implementation

file (Menu.cpp).

#include <windows.h>

#include "resource.h"

const char g_szClassName[] = "myWindowClass";

Page 131: Skip to Content Skip to Navigation

LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)

{switch(Message)

{

case WM_COMMAND:

switch(LOWORD(wParam))

{

case ID_FILE_EXIT:

PostMessage(hwnd, WM_CLOSE, 0, 0);

break;

case ID_STUFF_GO:

MessageBox(hwnd, "You clicked Go!", "Woo!", MB_OK);

break;

}

break;

case WM_CLOSE:

DestroyWindow(hwnd);

break;

case WM_DESTROY:

PostQuitMessage(0);

break;

default:

return DefWindowProc(hwnd, Message, wParam, lParam);

Page 132: Skip to Content Skip to Navigation

}

return 0;

}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPSTR lpCmdLine, int nCmdShow)

{WNDCLASSEX wc;

HWND hwnd;

MSG Msg;

wc.cbSize = sizeof(WNDCLASSEX);

wc.style = 0;

wc.lpfnWndProc = WndProc;

wc.cbClsExtra = 0;

wc.cbWndExtra = 0;

wc.hInstance = hInstance;

wc.hIcon=LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_MYICON));

wc.hCursor= LoadCursor(NULL, IDC_ARROW);

wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);

wc.lpszMenuName = MAKEINTRESOURCE(IDR_MYMENU);

wc.lpszClassName = g_szClassName;

wc.hIconSm =(HICON)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_MYICON),

IMAGE_ICON, 16, 16, 0);

if(!RegisterClassEx(&wc))

Page 133: Skip to Content Skip to Navigation

{MessageBox(NULL, "Window Registration Failed!", "Error!",

MB_ICONEXCLAMATION | MB_OK);

return 0;

}

hwnd = CreateWindowEx(

WS_EX_CLIENTEDGE,

g_szClassName,

"A Menu",

WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,

NULL, NULL, hInstance, NULL);

if(hwnd == NULL)

{MessageBox(NULL, "Window Creation Failed!", "Error!",

MB_ICONEXCLAMATION | MB_OK);

return 0;

}

ShowWindow(hwnd, nCmdShow);

UpdateWindow(hwnd);

while(GetMessage(&Msg, NULL, 0, 0) > 0)

{TranslateMessage(&Msg);

DispatchMessage(&Msg);

}

Page 134: Skip to Content Skip to Navigation

return Msg.wParam;

}

Compile, Build and Execute the Program. The output is as shown in figures 3.3.3(a) and 3.3.3(b). Click

the menu item Stuff. The message is displayed as shown in figure 3.3.3(b)

Figure 3.3.3(a) Running Instance of Menu program

Figure 3.3.3(b) Running Instance of Menu program

3.3.4 Dialog Box

A dialog box is a temporary window that contains controls. You can use it to display status information and to get user input. Just go File -> Open in any text editor or any other kind of editor; you are presented with a dialog box, one that probably allows you to select a file to be opened. Dialogs aren't limited to the standard open file ones; they can look like and do whatever you choose. The attractive point of dialogs is that they provide a quick way to arrange and create a GUI (Graphic User Interface) and even some default processing, cutting down on the amount of code you must write.

Page 135: Skip to Content Skip to Navigation

One thing to remember is that dialogs are just windows. The difference between a dialog and a

"normal" window is that the system does some additional default processing for dialogs, such as

creating and initializing controls, and handling tab order. Nearly all APIs that are applicable to "normal"

windows will work just as well on dialogs, and vice versa! There are two types of dialog box such as

“modal” and “modeless” dialog box. The modal dialog box is the most common. When your program

displays a modal dialog box the user must explicitly end the dialog box by clicking a push button

marked either OK or Cancel. The user can switch to another program while the dialog box is still

displayed.

The first step is to create the dialog resource. As with any resource how you do this will depend on

your compiler/IDE. Here I will show you the plain text of the dialog in the .rc file and let you incorporate

it into your project.

IDD_ABOUT DIALOG DISCARDABLE 0, 0, 239, 66

STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU

CAPTION "My About Box"

FONT 8, "MS Sans Serif"

BEGIN

DEFPUSHBUTTON "&OK",IDOK,174,18,50,14

PUSHBUTTON "&Cancel",IDCANCEL,174,35,50,14

GROUPBOX "About this program...",IDC_STATIC,7,7,225,52

CTEXT "An example program showing how to use Dialog Boxes\r\n\r\n by

Avanija",IDC_STATIC,16,18,144,33

END

On this first line, IDD_ABOUTDLG is the id of the resource. DIALOG is the resource type, and the four

number are the Left, Top, Width and Height co-ordinates. These ARE NOT PIXELS, they are in Dialog

Units, which are based on the size of the font used by the system (and chosen by the user). If you have

a large font selected, the dialog will be large, if you use a smaller font, the dialog will be that much

smaller. This is important as it makes sure that all of the controls are the proper size to display their

text in the current font. You can convert dialog units to pixels at runtime using MapDialogRect().

Page 136: Skip to Content Skip to Navigation

DISCARDABLE tells the system it may swap the resource memory to disk when it's not being used in

order to conserve system resources (essentially pointless).

The second line starts with STYLE and follows with the window styles that will be used to create the

dialog. These should be explained under CreateWindow() in your help files. In order to use the

predefined constants you may need to add #include "windows.h" to your .rc file, or in the case of VC+

+, winres.h or afxres.h will do. If you use the resource editor these files will certainly be included

automatically if needed.

The CAPTION line should be self explanatory. The FONT line specifies the size and name of the font you

wish to use for this dialog box. This might not end up exactly the same on each computer as different

people will have different fonts and may have specified different font sizes. You usually don't need to

worry about that though. Now we have the list of controls to create on the dialog:

DEFPUSHBUTTON "&OK",IDOK,174,18,50,14

Here's the line for the OK button. The & in this case like with menus underlines the next letter "O", so

that by pressing Alt+O the user can activate this control (part of the default processing I mentioned).

IDOK is the control identifier. IDOK is pre-defined so we don't need to #define it ourselves. The four

numbers at the end are the left, top, width and height, all in dialog units.

This information should be purely academic, as you almost always use a resource editor to create

dialogs, but knowing how to do it from text is sometimes necessary, expecially if you have no visual

editor.

Two of the controls have an ID of IDC_STATIC (which is -1), this is used to indicate we never need to

access them, so they have no need of an identifier. However it doesn't hurt to give them an ID and

your resource editor might do so automatically.

The "\r\n" in the text of the static control is a CR-LF pair, the way windows represents a new line. So!

Having added that to your .rc file we need to write a Dialog Procedure to process message for this box.

Don't worry this is nothing new, it's practicly the same as our main Window Procedure (but not

exactly).

BOOL CALLBACK AboutDlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)

{

switch(Message)

Page 137: Skip to Content Skip to Navigation

{

case WM_INITDIALOG:

return TRUE;

case WM_COMMAND:

switch(LOWORD(wParam))

{

case IDOK:

EndDialog(hwnd, IDOK);

break;

case IDCANCEL:

EndDialog(hwnd, IDCANCEL);

break;

}

break;

default:

return FALSE;

}

return TRUE;

}

There are a few important differences between a dialog procedure and window procedure. One is that

you DO NOT call DefWindowProc() for message you don't handle. With dialogs this is done

automatically for you (and will really screw things up if you do it).

Page 138: Skip to Content Skip to Navigation

Secondly, in general you return FALSE for messages you don't process, and TRUE for messages you do

process, UNLESS the message specifies you return something else. Note that this is what we do above,

the default is to do nothing and return FALSE, while messages we do handle break the switch() and

return TRUE.

Thirdly, You do not call DestroyWindow() to close a dialog, you call EndDialog(). The second parameter

is the value that is returned to whatever code called DialogBox().

Finally, instead of handling WM_CREATE, you handle WM_INITDIALOG to do any processing that needs

to be done before the dialog appears, and then return TRUE to have the keyboard focus set to the

default control. (You can actually handle WM_CREATE as well, but it is sent BEFORE any of the controls

have been created, so you can't access them. In WM_INITDIALOG the controls have already been

created).

case WM_COMMAND:

switch(LOWORD(wParam))

{

case ID_HELP_ABOUT:

{

int ret = DialogBox(GetModuleHandle(NULL),

MAKEINTRESOURCE(IDD_ABOUT), hwnd, AboutDlgProc);

if(ret == IDOK){

MessageBox(hwnd, "Dialog exited with IDOK.", "Notice",

MB_OK | MB_ICONINFORMATION);

}

else if(ret == IDCANCEL){

MessageBox(hwnd, "Dialog exited with IDCANCEL.", "Notice",

MB_OK | MB_ICONINFORMATION);

Page 139: Skip to Content Skip to Navigation

}

else if(ret == -1){

MessageBox(hwnd, "Dialog failed!", "Error",

MB_OK | MB_ICONINFORMATION);

}

}

break;

// Other menu commands...

}

break;

This is the code used to create my about box, you can probably guess that this is to be merged into

your WM_COMMAND handler, if you aren't clear on this aspect, you might want to review the section

on menus. ID_HELP_ABOUT is the identifier of my Help -> About menu item.

Since we want the menu on our main window to create the dialog, we obviously want to put this code

in the WndProc() of our main window, not the dialog proc. Now the return value is by making a call to

DialogBox(), this is just so you can observe the effects of pressing the two buttons, hitting Esc, Enter

etc... from inside the dialog. It also illustrates how to use the return value from a dialog box to check

for success, failure, a users choice, or whatever other information you choose to send back to the

caller from the Dialog Procedure.

DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_ABOUT), hwnd, AboutDlgProc);

This is the only important part, and you can choose to put it wherever in your code that you want the

dialog to come up. IDD_ABOUT is the id of the dialog resource. hwnd is the handle to the parent

window of the dialog. AboutDlgProc() is of course the dialog procedure to use to control the dialog.

A particularly astute reader might eventually wonder, if DialogBox() doesn't return until the dialog

closes we can't process messages while it's up, so how does it work? Well the nifty thing about

DialogBox() is that it has it's own message loop, so while the dialog is displayed, our message loop is

Page 140: Skip to Content Skip to Navigation

out of the picture and the default loop is handled by windows. This loop also takes care of fun things

like moving the keyboard focus from control to control when you press Tab.

Another effect of using DialogBox is that your main window is disabled until the dialog is dismissed.

Sometimes this is what we want, and sometimes it isn't, such as when we want to use a dialog as a

floating toolbar. In this case we want to be able to interact with both out dialog and our main window.

Example program for Modal dialog box

Create an application named ModalDialog by selecting the project type Win 32 Application in the

appwizard and click OK. Now an empty project without using MFC classes is created. Design the Menu

resource with the options Help and File. Under the option Help->About and under File->Exit are

included. After designing the menu open the dialog resource and design it as shown in figure 3.3.4(a).

Next step is to save the script with .rc extension and then include this .rc file and resource.h header

file in your project. Change the ID for menu as IDR_MYMENU and the ID for dialog as IDD_ABOUT.

Figure 3.3.4(a) Dialog design for ModalDialog Program.

Click File->New and then select the option C++ Source File and give a name to the .cpp

implementation file (here the name is Dialog.cpp). Enter the code given below in the implementation

file (Dialog.cpp).

#include <windows.h>

#include "resource.h"

const char g_szClassName[] = "myWindowClass";

BOOL CALLBACK AboutDlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)

Page 141: Skip to Content Skip to Navigation

{

switch(Message)

{

case WM_INITDIALOG:

return TRUE;

case WM_COMMAND:

switch(LOWORD(wParam))

{

case IDOK:

EndDialog(hwnd, IDOK);

break;

case IDCANCEL:

EndDialog(hwnd, IDCANCEL);

break;

}

break;

default:

return FALSE;

}

return TRUE;

}

LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)

Page 142: Skip to Content Skip to Navigation

{

switch(Message)

{

case WM_COMMAND:

switch(LOWORD(wParam))

{

case ID_FILE_EXIT:

PostMessage(hwnd, WM_CLOSE, 0, 0);

break;

case ID_HELP_ABOUT:

{

int ret = DialogBox(GetModuleHandle(NULL),

MAKEINTRESOURCE(IDD_ABOUT), hwnd, AboutDlgProc);

if(ret == IDOK){

MessageBox(hwnd, "Dialog exited with IDOK.", "Notice",MB_OK | MB_ICONINFORMATION);

}

else if(ret == IDCANCEL){

MessageBox(hwnd, "Dialog exited with IDCANCEL.", "Notice",

MB_OK | MB_ICONINFORMATION);

}

else if(ret == -1){

MessageBox(hwnd, "Dialog failed!", "Error",

Page 143: Skip to Content Skip to Navigation

MB_OK | MB_ICONINFORMATION);

}

}

break;

}

break;

case WM_CLOSE:

DestroyWindow(hwnd);

break;

case WM_DESTROY:

PostQuitMessage(0);

break;

default:

return DefWindowProc(hwnd, Message, wParam, lParam);

}

return 0;

}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPSTR lpCmdLine, int nCmdShow)

{WNDCLASSEX wc;

HWND hwnd;

MSG Msg;

Page 144: Skip to Content Skip to Navigation

wc.cbSize = sizeof(WNDCLASSEX);

wc.style = 0;

wc.lpfnWndProc = WndProc;

wc.cbClsExtra = 0;

wc.cbWndExtra = 0;

wc.hInstance = hInstance;

wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);

wc.hCursor = LoadCursor(NULL, IDC_ARROW);

wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);

wc.lpszMenuName = MAKEINTRESOURCE(IDR_MYMENU);

wc.lpszClassName = g_szClassName;

wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

if(!RegisterClassEx(&wc))

{MessageBox(NULL, "Window Registration Failed!", "Error!",

MB_ICONEXCLAMATION | MB_OK);

return 0;

}

hwnd = CreateWindowEx(

WS_EX_CLIENTEDGE,

g_szClassName,

"The title of my window",

WS_OVERLAPPEDWINDOW,

Page 145: Skip to Content Skip to Navigation

CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,

NULL, NULL, hInstance, NULL);

if(hwnd == NULL)

{MessageBox(NULL, "Window Creation Failed!", "Error!",

MB_ICONEXCLAMATION | MB_OK);

return 0;

}

ShowWindow(hwnd, nCmdShow);

UpdateWindow(hwnd);

while(GetMessage(&Msg, NULL, 0, 0) > 0)

{TranslateMessage(&Msg);

DispatchMessage(&Msg);

}

return Msg.wParam;

}

Compile, Build and Execute the program. The output is shown through figures 3.3.4(b) through

3.3.4(d).

Figure 3.3.4(b) Running Instance of ModalDialog Program

Page 146: Skip to Content Skip to Navigation

Figure 3.3.4(c) Running Instance of ModalDialog Program

Figure 3.3.4(d) Running Instance of ModalDialog Program

3.3.5 Modeless Dialogs

Figure 2

Now we take a look at CreateDialog(), DialogBox()'s sister function. The difference is that while

DialogBox() implements it's own message loop and does not return until the dialog is closed,

CreateDialog() acts more like a window created with CreateWindowEx() in that it returns immediately

and depends on your message loop to pump the messages as it does for your main window. This is

termed Modeless, whereas DialogBox() creates Modal dialogs.

You can create the dialog resource just like you did for the last dialog example, you might also want to

set the "Tool window" extended style to give it's title bar the typical smaller caption of toolbars. The

dialog resource is created as follows:

IDD_TOOLBAR DIALOGEX 0, 0, 98, 52

Page 147: Skip to Content Skip to Navigation

STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION

EXSTYLE WS_EX_TOOLWINDOW

CAPTION "My Dialog Toolbar"

FONT 8, "MS Sans Serif"

BEGIN

PUSHBUTTON "&Press This Button",IDC_PRESS,7,7,84,14

PUSHBUTTON "&Or This One",IDC_OTHER,7,31,84,14

END

You may notice that the resource editor has replaced DIALOG with DIALOGEX indicating we want to set

an EXSTYLE on our dialog.

Next we want to create the dialog when our program runs with the help of the command WM_CREATE.

We also want to declare a global variable to hold the window handle returned from CreateDialog() so

that we can use it later. DialogBox() didn't return a handle to us since when DialogBox() returns the

window has been destroyed.

HWND g_hToolbar = NULL;

case WM_CREATE:

g_hToolbar = CreateDialog(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_TOOLBAR),

hwnd, ToolDlgProc);

if(g_hToolbar != NULL)

{

ShowWindow(g_hToolbar, SW_SHOW);

}

else

Page 148: Skip to Content Skip to Navigation

{

MessageBox(hwnd, "CreateDialog returned NULL", "Warning!",

MB_OK | MB_ICONINFORMATION);

}

break;

We show the window with ShowWindow(), with DialogBox() this isn't necessary since the system calls

ShowWindow() for us. Now we need a dialog procedure for our toolbar.

BOOL CALLBACK ToolDlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)

{

switch(Message)

{

case WM_COMMAND:

switch(LOWORD(wParam))

{

case IDC_PRESS:

MessageBox(hwnd, "Hi!", "This is a message",

MB_OK | MB_ICONEXCLAMATION);

break;

case IDC_OTHER:

MessageBox(hwnd, "Bye!", "This is also a message",

MB_OK | MB_ICONEXCLAMATION);

break;

Page 149: Skip to Content Skip to Navigation

}

break;

default:

return FALSE;

}

return TRUE;

}

Most of the same message handling rules apply to dialogs created with CreateDialog() as with

DialogBox(), don't call DefWindowProc(), return FALSE for messages you don't handle and TRUE for

those you do.

One change is that we don't call EndDialog() for modeless dialogs, we can use DestroyWindow() just

like for regular windows. In this case I destroy the dialog when the main window is destroyed. In the

main window's WndProc()...

case WM_DESTROY:

DestroyWindow(g_hToolbar);

PostQuitMessage(0);

break;

Last but not least, we want to be able to display and hide our toolbar whenever we choose so I've

added two commands to my menu to do this, and handled them so:

case WM_COMMAND:

switch(LOWORD(wParam))

{

case ID_DIALOG_SHOW:

ShowWindow(g_hToolbar, SW_SHOW);

Page 150: Skip to Content Skip to Navigation

break;

case ID_DIALOG_HIDE:

ShowWindow(g_hToolbar, SW_HIDE);

break;

//... other command handlers

}

break;

You should be able to create your own menu using the resource editor or manually.Now when you run

the program, you should be able to access both the dialog window, and main window at the same

time.

If you've run the program at this point and tried tabbing between the two buttons, you have probably

noticed it doesn't work, neither does hitting Alt-P or Alt-O to activate the buttons. Why not? Whereas

DialogBox() implements it's own message loop and handles these events by default, CreateDialog()

does not. We can do it ourselves though, by calling IsDialogMessage() in our message loop which will

do the default processing for us.

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

{

if(!IsDialogMessage(g_hToolbar, &Msg))

{

TranslateMessage(&Msg);

DispatchMessage(&Msg);

}

}

Page 151: Skip to Content Skip to Navigation

Here we first pass the message to IsDialogMessage(), if the message is destined for our toolbar

(indicated by the window handle we pass in) the system will perform the default processing and return

TRUE. Is this case the message has already been handled so we don't want to call TranslateMessage()

or DispatchMessage(). If the message is for another window we process as usual.

It's also worth noting that IsDialogMessage() can also be used with windows that aren't dialogs in order

to to give them dialog-like behaviour. Remember, a dialog is a window, and most (if not all) dialog APIs

will work on any window.

And that is pretty much all there is to modeless dialogs! One issue that may arise is if you have more

than one toolbar... what do you do? Well one possible solution is to have a list (either an array, an STL

std::list, or similar) and loop through it in your message loop passing each handle to IsDialogMessage()

until the right one is found, and if none, do the regular processing.

Example Program for Modeless dialog

Create an application named ModelessDialog by selecting the project type Win 32 Application in the

appwizard and click OK. Now an empty project without using MFC classes is created. Design the Menu

resource with the options Dialog and File. Under the option Dialog include the options Show and Hide.

These two options is to make your dialog visible and invisible in the output window. Under the option

File include Exit to close the output window. After designing the menu open the dialog resource and

design it as shown in figure 3.3.5(a). Next step is to save the script with .rc extension and then include

this .rc file and resource.h header file in your project. Change the ID for menu as IDR_MYMENU and the

ID for dialog as IDD_DIALOG.

Figure 3.3.5(a) Dialog design for ModelessDialog program

Page 152: Skip to Content Skip to Navigation

Click File->New and then select the option C++ Source File and give a name to the .cpp

implementation file (here the name is ModelessDialog.cpp). Enter the code given below in the

implementation file (ModelessDialog.cpp).

#include <windows.h>

#include "resource.h"

const char g_szClassName[] = "myWindowClass";

HWND g_hToolbar = NULL;

BOOL CALLBACK ToolDlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)

{

switch(Message)

{

case WM_COMMAND:

switch(LOWORD(wParam))

{

case IDC_PRESS:

MessageBox(hwnd, "Hi!", "This is a message",

MB_OK | MB_ICONEXCLAMATION);

break;

case IDC_OTHER:

MessageBox(hwnd, "Bye!", "This is also a message",

MB_OK | MB_ICONEXCLAMATION);

break;

Page 153: Skip to Content Skip to Navigation

}

break;

default:

return FALSE;

}

return TRUE;

}

LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)

{

switch(Message)

{

case WM_CREATE:

g_hToolbar=CreateDialog(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOG),

hwnd, ToolDlgProc);

if(g_hToolbar != NULL)

{

ShowWindow(g_hToolbar, SW_SHOW);

}

else

{

MessageBox(hwnd, "CreateDialog returned NULL", "Warning!",

MB_OK | MB_ICONINFORMATION);

Page 154: Skip to Content Skip to Navigation

}

break;

case WM_COMMAND:

switch(LOWORD(wParam))

{

case ID_FILE_EXIT:

PostMessage(hwnd, WM_CLOSE, 0, 0);

break;

case ID_DIALOG_SHOW:

ShowWindow(g_hToolbar, SW_SHOW);

break;

case ID_DIALOG_HIDE:

ShowWindow(g_hToolbar, SW_HIDE);

break;

}

break;

case WM_CLOSE:

DestroyWindow(hwnd);

break;

case WM_DESTROY:

DestroyWindow(g_hToolbar);

PostQuitMessage(0);

Page 155: Skip to Content Skip to Navigation

break;

default:

return DefWindowProc(hwnd, Message, wParam, lParam);

}

return 0;

}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPSTR lpCmdLine, int nCmdShow)

{

WNDCLASSEX wc;

HWND hwnd;

MSG Msg;

wc.cbSize = sizeof(WNDCLASSEX);

wc.style = 0;

wc.lpfnWndProc = WndProc;

wc.cbClsExtra = 0;

wc.cbWndExtra = 0;

wc.hInstance = hInstance;

wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);

wc.hCursor = LoadCursor(NULL, IDC_ARROW);

wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);

wc.lpszMenuName = MAKEINTRESOURCE(IDR_MYMENU);

Page 156: Skip to Content Skip to Navigation

wc.lpszClassName = g_szClassName;

wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

if(!RegisterClassEx(&wc))

{MessageBox(NULL, "Window Registration Failed!", "Error!",

MB_ICONEXCLAMATION | MB_OK);

return 0;

}

hwnd = CreateWindowEx(

WS_EX_CLIENTEDGE,

g_szClassName,

"The title of my window",

WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,

NULL, NULL, hInstance, NULL);

if(hwnd == NULL)

{MessageBox(NULL, "Window Creation Failed!", "Error!",

MB_ICONEXCLAMATION | MB_OK);

return 0;

}

ShowWindow(hwnd, nCmdShow);

UpdateWindow(hwnd);

while(GetMessage(&Msg, NULL, 0, 0) > 0)

Page 157: Skip to Content Skip to Navigation

{

if(!IsDialogMessage(g_hToolbar, &Msg))

{TranslateMessage(&Msg);

DispatchMessage(&Msg);

}

}

return Msg.wParam;

}

Compile, Build and Execute the program. The output is as shown in figures 3.3.5(b) through 3.3.5(d).

Figure 3.3.5(b) Running Instance of ModelessDialog Program

Page 158: Skip to Content Skip to Navigation

Figure 3.3.5(c) Running Instance of ModelessDialog Program

Figure 3.3.5(d) Running Instance of ModelessDialog Program

3.3.6 Bitmaps

Bitmaps can be loaded much like icons in earlier examples, there is LoadBitmap() for the most basic

functionality of simply loading a bitmap resource, and LoadImage() can be used to load bitmaps from a

*.bmp file just as it can for icons.

Page 159: Skip to Content Skip to Navigation

One of the quirks of GDI is that you can't draw to bitmap objects (HBITMAP type) directly. Remember

that drawing operations are abstracted by Device Contexts, so in order to use these drawing functions

on a bitmap, you need to create a Memory DC, and then select the HBITMAP into it with SelectObject().

The effect is that the "device" that the HDC refers to is the bitmap in memory, and when you operate

on the HDC, the resulting graphic operations are applied to the bitmap. As I mentioned, this is actually

a very convenient way of doing things, as you can write code that draws to an HDC and you can use it

on a Window DC or a Memory DC without any checks or changes. You do have the option of

manipulating the bitmap data in memory yourself. You can do this with Device Independent Bitmaps

(DIB), and you can even combine GDI and manual operations on the DIB.

GDI Leaks

Once you're finished with an HDC, it's very important to release it (just how you do that depends on

how you got it, which we'll talk about in a bit). GDI objects are limited in number. In versions of

windows prior to Windows 95, they were not only incredibly limited but also shared system wide, so

that if one program used up too many, none of the rest would be able to draw anything! Fortunately

this isn't the case any longer, and you could get away with using up quite a lot of resources in

Windows 2000 or XP before anything too bad happened... but it's easy to forget to free GDI objects and

they can quickly run your program out of GDI resources under Windows 9x. Theoretically you shouldn't

be able to drain the system of GDI resources in NT systems (NT/2K/XP) but it still happens in extreme

cases.

If your program runs fine for a few minutes and then starts drawing strangely or not at all, it's a good

sign that you're leaking GDI resources. HDCs aren't the only GDI objects you need to be careful about

releasing, but generally it's ok to keep things like bitmaps and fonts around for the entire lifetime of

your program, since it's much more efficient than reloading them each time you need them.

Also, an HDC can only contain one of each type of object (bitmap, font, pen...) at a time, and when you

select a new one in it will return the last one. It's very important that you deal with this object properly.

If you ignore it completely, it will be lost and they will pile up in memory causing GDI leaks. When an

HDC is created, it's also created with some default objects selected into it... it's a good idea to store

these when they are returned to you, and then when you are completed drawing with the HDC select

them back into it. This will not only remove any of your own objects from the HDC (which is a good

thing) but it will also cause the default objects to be properly disposed of when you release or destroy

the HDC (a VERY good thing).

Displaying Bitmaps

Page 160: Skip to Content Skip to Navigation

The simplest drawing operations on a window occur by handling WM_PAINT. When your window is first

displayed, restored from being minimized, 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 it's

contents. When you draw something on the screen it is NOT permanent, it's only there until something

else draws over it, and at that point you need to draw it again when the time comes.

HBITMAP g_hbmBall = NULL;

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, and there are

no significant differences from loading other resource types. Then we can get down to drawing...

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);

Page 161: Skip to Content Skip to Navigation

EndPaint(hwnd, &ps);

}

break;

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

it's name doesn't 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 it's required for the call to BeginPaint(). BeginPaint() as it's 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, it's 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.

Setting up a Memory DC for the Bitmap

As mention above, 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.

Drawing

Once we've gotten the dimensions 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

Page 162: Skip to Content Skip to Navigation

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.

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. Here's a list of the common methods of gaining an HDC, and how to release it when

you're 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 isn't absolutely required, since modern Windows platforms are pretty good at

freeing everything when your program exists, but it's always a good idea to keep track of your own

objects because if get lazy and don't delete them they have a habit of getting loose. And no doubt,

there are still bugs in windows especially older versions that won't clean up all of your GDI objects if

you don't do a thorough job.

case WM_DESTROY:

DeleteObject(g_hbmBall);

PostQuitMessage(0);

break;

Example Bitmap Program

Page 163: Skip to Content Skip to Navigation

Create an application named BitmapDemo by selecting the project type Win 32 Application in the

appwizard and click OK. Now an empty project without using MFC classes is created.

Click Insert->Resource from the menu and then select the Bitmap option. Design the Bitmap as shown

in figure 3.3.6(a).

Figure 3.3.6(a) Bitmap design for the program

Save the Bitmap design in your project and then include the .rc and resource.h header file to your

project workspace. Change the ID for Bitmap as IDB_BALL Click File->New and then select the option

C++ Source File and give a name to the .cpp implementation file (here the name is Bitmap.cpp). Enter

the code given below in the implementation file (Bitmap.cpp).

#include <windows.h>

#include "resource.h"

const char g_szClassName[] = "myWindowClass";

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)

{

static HBITMAP g_hbmBall;

HINSTANCE hInstance;

Page 164: Skip to Content Skip to Navigation

switch(msg)

{

case WM_CREATE:

hInstance=((LPCREATESTRUCT) lParam)->hInstance;

g_hbmBall = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BALL));

break;

case WM_CLOSE:

DestroyWindow(hwnd);

break;

case WM_PAINT:

{

// Just a note, never use a MessageBox from inside WM_PAINT

// The box will cause more WM_PAINT messages and you'll probably end up

// stuck in a loop

BITMAP bm;

PAINTSTRUCT ps;

HDC hdc = BeginPaint(hwnd, &ps);

HDC hdcMem = CreateCompatibleDC(hdc);

SelectObject(hdcMem, g_hbmBall);

GetObject(g_hbmBall, sizeof(bm), &bm);

BitBlt(hdc, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY);

DeleteDC(hdcMem);

Page 165: Skip to Content Skip to Navigation

EndPaint(hwnd, &ps);

}

break;

case WM_DESTROY:

DeleteObject(g_hbmBall);

PostQuitMessage(0);

break;

default:

return DefWindowProc(hwnd, msg, wParam, lParam);

}

return 0;

}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPSTR lpCmdLine, int nCmdShow)

{

WNDCLASSEX wc;

HWND hwnd;

MSG Msg;

wc.cbSize = sizeof(WNDCLASSEX);

wc.style = 0;

wc.lpfnWndProc = WndProc;

wc.cbClsExtra = 0;

Page 166: Skip to Content Skip to Navigation

wc.cbWndExtra = 0;

wc.hInstance = hInstance;

wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);

wc.hCursor = LoadCursor(NULL, IDC_ARROW);

wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);

wc.lpszMenuName = NULL;

wc.lpszClassName = g_szClassName;

wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

if(!RegisterClassEx(&wc))

{

MessageBox(NULL, "Window Registration Failed!", "Error!",

MB_ICONEXCLAMATION | MB_OK);

return 0;

}

hwnd = CreateWindowEx(

WS_EX_CLIENTEDGE,

g_szClassName,

"A Bitmap Program",

WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,

NULL, NULL, hInstance, NULL);

if(hwnd == NULL)

Page 167: Skip to Content Skip to Navigation

{

MessageBox(NULL, "Window Creation Failed!", "Error!",

MB_ICONEXCLAMATION | MB_OK);

return 0;

}

ShowWindow(hwnd, nCmdShow);

UpdateWindow(hwnd);

while(GetMessage(&Msg, NULL, 0, 0) > 0)

{

TranslateMessage(&Msg);

DispatchMessage(&Msg);

}

return Msg.wParam;

}

Compile, Build and Execute the program. The output is as shown in figure 3.3.6(b).

Figure 3.3.6(b) Running Instance of Bitmap Program

Page 168: Skip to Content Skip to Navigation

Exercises 3

1. What are the various button styles that

can be used in Windows Programming?

2. Explain the functions SetDlgItemText

and GetDlgItemText.

3. Explain the List Box and Scroll Bar Class.

4. Explain the LoadIcon and LoadBitmap

functions.

5. Explain SetMenu and LoadMenu

functions.

6. What are the advantages of using Dialog

Box?

7. Differentiate Modal Dialog and Modeless

Dialog.

8. Explain the BitBlt function.

9. Write a Windows program to add and

removo items in a List box.

10. Write a Windows program to display a

Bitmap in the centre of the screen.

 

Content actions

SHARE CONTENT

SHARE MODULE:  

GIVE FEEDBACK:

E-mail the module author

DOWNLOAD MODULE AS:

PDF | EPUB (?) 

WHAT IS AN EPUB FILE?

EPUB is an electronic book format that can be read on a variety of mobile devices.

Page 169: Skip to Content Skip to Navigation

DOWNLOADING TO A READING DEVICE

For detailed instructions on how to download this content's EPUB to your specific device, click the"(?)"link.

| More downloads ...

ADD MODULE TO:

My Favorites Login Required(?) 'My Favorites' is a special kind of lens which you can use to bookmark modules and collections. 'My Favorites' can only be seen by you, and collections saved in 'My Favorites' can remember the last module you were on. You need an account to use 'My Favorites'.

| A lens I own Login Required(?) 

Definition of a lens

LensesA lens is a custom view of the content in the repository. You can think of it as a fancy kind of list that will let you see content through the eyes of organizations and people you trust.

What is in a lens?Lens makers point to materials (modules and collections), creating a guide that includes their own comments and descriptive tags about the content.

Who can create a lens?Any individual member, a community, or a respected organization.

What are tags?

Tags are descriptors added by lens makers to help label content, attaching a vocabulary that is meaningful in the context of the lens.

| External bookmarks

REUSE / EDIT:

Reuse or edit module Login Required(?)Check out and editIf you have permission to edit this content, using the "Reuse / Edit" action will allow you to check the content out into your Personal Workspace or a shared Workgroup and then make your edits.

Derive a copyIf you don't have permission to edit the content, you can still use "Reuse / Edit" to adapt the content by creating a derived copy of it and then editing and publishing the copy.

Footer

 

More about this module: Metadata | Downloads | Version History

How to   reuse   and attribute this content

How to   cite   and attribute this content

This work is licensed by Avanija j under a Creative Commons Attribution License (CC-BY 2.0), and is an Open Educational Resource.

Last edited by Avanija j on Apr 4, 2007 12:57 pm GMT-5.

Page 170: Skip to Content Skip to Navigation