Home > Articles

This chapter is from the book

Introduction to GDI (Graphics Device Interface)

Thus far, the only experience you've had with GDI is the processing of the WM_PAINT message in the main event handler. Remember that GDI, or the Graphics Device Interface, is how all graphics are drawn under Windows when DirectX is not in use. Alas, you haven't yet learned how to actually draw anything on the screen with GDI, but this is very key because rendering on the screen is one of the most important parts of writing a video game. Basically, a game is just logic that drives a video display. In this section, I'm going to revisit the WM_PAINT message, cover some basic video concepts, and teach you how to draw text within your window. The next chapter will focus more heavily on GDI.

Understanding the WM_PAINT message is very important for standard GDI graphics and Windows programming because most Windows programs' displays revolve around this single message. In a DirectX game this isn't true, because DirectX, or more specifically DirectDraw or Direct3D, will do the drawing, but you still need to know GDI to write Windows applications.

The WM_PAINT Message Once Again

The WM_PAINT message is sent to your window's WinProc() whenever the window's client area needs repainting. Until now, you haven't done much processing on this event. Here's the standard WM_PAINT handler you have been using:

PAINTSTRUCT  ps;  // used in WM_PAINT
HDC    hdc;  // handle to a device context

case WM_PAINT:
  // simply validate the window
  hdc = BeginPaint(hwnd,&ps);
  // you would do all your painting here
    // return success
    } break;

Refer to Figure 3.12 for the following explanation. When a window is moved, resized, or in some way graphically obscured by another window or event, some or all of the window's client area must be redrawn. When this happens, a WM_PAINT message is sent and you must deal with it.

Figure 3.12Figure 3.12 The WM_PAINT "message.

In the case of the preceding code example, the calls to BeginPaint() and EndPaint() accomplish a couple of tasks. First, they validate the client area, and second, they fill the background of your window with the background brush defined in the Windows class that the window was originally created with.

Now, if you want to do your own graphics within the BeginPaint()EndPaint() call, you can. However, there is one problem: You will only have access to the portion of the window's client area that actually needs repainting. The coordinates of the invalid rectangle are stored in the rcPaint field of the ps (PAINSTRUCT) returned by the call to BeginPaint():

typedef struct tagPAINTSTRUCT
    HDC hdc;    // graphics device context
    BOOL fErase;   // if TRUE then you must draw background
    RECT rcPaint;  // the RECT containing invalid region
    BOOL fRestore;  // internal
    BOOL fIncUpdate; // internal
    BYTE rgbReserved[32]; // internal

And to refresh your memory, here's the definition of RECT:

typedef struct _RECT
    LONG left;  // left edge if rectangle
    LONG top;  // upper edge of rectangle
    LONG right; // right edge of rectangle
    LONG bottom; // bottom edge of rectangle
    } RECT;

In other words, referring back to Figure 3.12, the window is 400x400, but only the lower region of the window—300,300 to 400,400—needs repainting. Thus, the graphics device context returned by the call to BeginPaint() is only valid for this 100x100 region of your window! Obviously, this is a problem if you want to have access to the entire client area.

The solution to the problem has to do with gaining access to the graphics device context for the window directly without it being sent as part of a window update message via BeginPaint(). You can always get a graphics context for a window or hdc using the GetDC() function, as shown here:

HDC GetDC(HWND hWnd); // handle of window

You simply pass the window handle of the graphics device context you want to access, and the function returns a handle to it. If the function is unsuccessful, it returns NULL. When you're done with the graphics device context handle, you must give it back to Windows with a call to ReleaseDC(), as shown here:

int ReleaseDC(HWND hWnd, // handle of window
       HDC hDC); // handle of device context

ReleaseDC() takes the window handle and the handle to the device context you previously acquired with GetDC().


Windows-speak gets confusing when it comes to graphics device contexts. Technically, a handle to a device context can refer to more than one output device. For example, a device context could be a printer. Therefore, I usually refer to a graphics-only device context as a graphics device context. But the data type is HDC or handle to device context. So typically, I will define a graphics device context variable as HDC hdc, but sometimes I will also use HDC gdc because it makes more sense to me. In any case, just be aware that for this book, a graphics device context and a device context are interchangeable, and variables with the names hdc and gdc are of the same type.

Here's how you would use GetDC()ReleaseDC() to do graphics:

HDC gdc = NULL; // this will hold the graphics device context

// get the graphics context for the window
if (!(gdc = GetDC(hwnd)))

// use the gdc here and do graphics – you don't know how yet!

// release the dc back to windows
ReleaseDC(hwnd, gdc);

Of course, you don't know how to do any graphics yet, but I'm getting there.... The important thing is that you now have another way to process a WM_PAINT message. However, there is one problem: When you make a call to GetDC()—ReleaseDC(), Windows has no idea that you have restored or validated the client area of your window. In other words, if you use GetDC()—ReleaseDC() in place of BeginPaint()—EndPaint(), you'll create another problem!

The problem is that BeginPaint()EndPaint() sends a message to Windows indicating that the window contents have been restored (even if you don't make any graphics calls). Hence, Windows won't send any more WM_PAINT messages. On the other hand, if you replace BeginPaint()EndPaint() with GetDC()ReleaseDC() in the WM_PAINT handler, WM_PAINT messages will continue to be sent forever! Why? Because you must validate the window.

To validate the area of a window that needs repainting and tell Windows that you have restored the window, you could call BeginPaint()EndPaint() after the call to GetDC()ReleaseDC(), but this would be inefficient. Instead, use the call specifically designed for this, called ValidateRect():

BOOL ValidateRect(HWND hWnd, // handle of window
 CONST RECT *lpRect); // address of validation rectangle coordinates

To validate a window, send the handle of the window along with the region you want to be validated in lpRect. In most cases, the region to validate would be the entire window. Thus, to use GetDC()—ReleaseDC() in the WM_PAINT handler, you would have to do something like this:

PAINTSTRUCT  ps;  // used in WM_PAINT
HDC    hdc; // handle to a device context
RECT      rect; // rectangle of window

case WM_PAINT:
  // simply validate the window
  hdc = GetDC(hwnd);
  // you would do all your painting here

    // get client rectangle of window – use Win32 call
    // validate window

    // return success
    } break;


Notice the call to GetClientRect(). All this does is get the client rectangle coordinates for you. Remember, because a window can move around, it has two sets of coordinates: window coordinates and client coordinates. Window coordinates are relative to the screen, and client coordinates are relative to the upper left-hand corner of the window (0,0). Figure 3.13 shows this more clearly.

Figure 3.13Figure 3.13 Window coordinates versus client coordinates.

You must be saying, "Does it really need to be this hard?" Of course it does—it's Windows <BG>. Remember, the whole reason for all this drama in the WM_PAINT message handler is that you need to make sure that you can draw graphics anywhere you want in the client area of the window. This is only possible if you use GetDC()ReleaseDC() or BeginPaint()EndPaint() with a completely invalid window. However, we are trying to get the best of both worlds, and we're almost done. The final trick I want to show you is how to invalidate a window manually.

Consider this: If you could somehow invalidate the entire window within your WM_PAINT handler, you would be sure that the rcPaint field of the ps PAINTSTRUCT returned by BeginPaint() and the associated gdc would give you access to the entire client area of the window. To make this happen, you can manually enlarge the invalidated area of any window with a call to InvalidateRect(), as shown here:

BOOL InvalidateRect(HWND hWnd, // handle of window with 
                // changed update region
CONST RECT *lpRect,  // address of rectangle coordinates
BOOL bErase);     // erase-background flag

If bErase is TRUE, the call to BeginPaint() fills in the background brush; otherwise, it doesn't.

Simply call InvalidateRect() before the BeginPaint()EndPaint() pair, and then, when you do call BeginPaint(), the invalid region will reflect the union of what it was and what you added to it with the InvalidatRect(). However, in most cases, you will use NULL as the lpRect parameter of InvalidateRect(), which will invalidate the entire window. Here's the code:

PAINTSTRUCT  ps;   // used in WM_PAINT
HDC      hdc;  // handle to a device context

case WM_PAINT:
 // invalidate the entire window
 InvalidateRect(hwnd, NULL, FALSE);
 // begin painting
 hdc = BeginPaint(hwnd,&ps);
 // you would do all your painting here
 // return success
 } break;

In most of the programs in this book, you'll use GetDC()—ReleaseDC() in places other than the WM_PAINT message, and BeginPaint()—EndPaint() solely in the WM_PAINT handler. Now let's move on to some simple graphics so you can at least print out text.

Video Display Basics and Color

At this point, I want to take time to discuss some concepts and terminology that relate to graphics and color on the PC. Let's start with some definitions:

  • Pixel—A single addressable picture element on a raster display, such as a computer monitor.

  • Resolution—The number of pixels that the display card supports, such as 640x480, 800x600, and so forth. The higher the resolution, the better the image, but the more memory required too. Table 3.2 lists some of the most common resolutions and their various memory requirements.

  • Color depth—The number of bits or bytes that represent each pixel on the screen—bits per pixel (bpp). For example, if each pixel is represented by 8 bits (a single byte), the display can only support 256 colors because 28 = 256. On the other hand, if each pixel is made of 16 bits (2 bytes), each pixel can support up to 16,384 colors or 216. Again, the greater the color depth, the greater the detail, but memory usage also goes up. Furthermore, 8-bit modes are usually palettized (which will be explained shortly), 16-bit modes are called high color, and 24- and 32-bit modes are called true and ultra-color respectively.

  • Interlaced/noninterlaced displays—Computer displays are drawn by a scanning electron gun one line at a time—rasterization. Standard television draws two frames for each image. One frame consists of all the odd-numbered scan lines, and the other frame is all the even-numbered lines. When these two frames are drawn in quick succession, your eyes fuse them together and create a single image. This only looks acceptable for moving images and therefore is not acceptable for static imagery like a Windows display. However, some cards can only support high-resolution modes if they interlace. When interlacing occurs, you will usually see a flicker or shake in the display.

  • Video RAM (VRAM)—The amount of onboard memory on a video card for representing the video image(s) on the screen or in texture memory.

  • Refresh rate—The number of times per second the video image is refreshed, measured in Hz (hertz) or fps (frames per second). 60Hz is considered the minimum acceptable level these days, and some monitors and display cards go up to well over 100Hz for a rock-solid display.

  • 2D acceleration—Hardware support on the video card that helps Windows and/or DirectX with 2D operations like bitmapped graphics, lines, circles, text, scaling, and so forth.

  • 3D acceleration—Hardware support on the video card that helps Windows or DirectX/Direct3D with 3D graphics rendering.

These elements are shown in Figure 3.14.

Table 3.2 Video Resolutions and Memory Requirements


Bits per Pixel

Memory (min-max)








8, 16, 24, 32



8, 16, 24, 32



8, 16, 24, 32



8, 16, 24, 32



8, 16, 24, 32


*These are considered to be Mode X modes and may not be supported by your video card.

Of course, Table 3.2 is only a sampling of possible video modes and color depths. Your card may support many more. The important thing is to understand that it's pretty easy to eat up 2MB to 4MB of video RAM. The good news is that most DirectX Windows games that you'll write will run in 320x240 or 640x480, which, depending on the color depth, a 2MB card can support.

Figure 3.14Figure 3.14 The mechanics of a video display.

RGB and Palletized Modes

There are two ways to represent color on a video display: directly or indirectly. Direct color modes, or RGB modes, represent each pixel on the screen with either 16, 24, or 32 bits that represent the red, green, and blue components of the color (see Figure 3.15). This is possible due to the additive nature of the primary colors red, green, and blue.

Referring to Figure 3.15, you can see that for each possible color depth (16, 24, 32), there are a number of bits assigned to each color channel. Of course, with 16-bit and 32-bit color, these numbers aren't evenly divisible by 3; therefore, there might be an unequal amount of one of the color channels. For example, with 16-bit color modes, there are three different RGB encodings you might find:

  • RGB (6.5.5)—Six bits of red, five bits of green, and five bits of blue.

  • RGB (—One bit alpha and five bits each of red, green, and blue. Alpha is a transparency control.

  • RGB (5.6.5)—Five bits of red, six bits of green, and five bits of blue. This is the most common, in my experience.

Figure 3.15Figure 3.15 Color encoding for RGB modes.

The 24-bit mode is almost always eight bits per channel. However, the 32-bit mode can be weird, and in most cases there are eight bits for alpha (transparency) and eight bits each for the red, green, and blue channels.

Basically, RGB modes give you control over the exact red, green, and blue components of each pixel on the screen. Palettized modes work on a principle called indirection. When there are only eight bits per pixel, you could decide to allocate the three bits for red, three bits for green, and maybe two bits for blue or some combination thereof. However, this would leave you with only a few shades of each of the primary colors, and that wouldn't be very exciting. Instead, 8-bit modes use a palette.

As shown in Figure 3.16, a palette is a table that has 256 entries, one for each possible value of a single byte—0 to 255. However, each of these entries is really composed of three 8-bit entries of red, green, and blue. In essence, it's a full RGB 24-bit descriptor. The color lookup table (CLUT) works like this: When a pixel in an 8-bit color mode is read from the screen, say value 26, the 26 is used as an index into the color table. Then the 24-bit RGB value for color descriptor index 26 is used to drive the red, green, and blue channels for the actual color that is sent to the display. In this way, you can have just 256 colors on the screen at once, but they can be from among 16.7 million colors or 24-bit RGB values. Figure 3.16 illustrates the lookup process.

Figure 3.16Figure 3.16 How 256-color palettized modes work.

We are getting a little ahead of ourselves with all this color stuff, but I want to let you chew on the concepts a bit so that when you see them again during the DirectDraw discussion, it won't be for the first time. In fact, color is such a complex problem to work with in normal GDI-based Windows graphics that Windows has abstracted color to a 24-bit model no matter what. That way you don't have to worry about the details of color depth and such when you're programming. Of course, you will get better results if you do worry about them, but you don't have to.

Basic Text Printing

Windows has one of the most complex and robust text-rendering systems of any operating system I have ever seen. Of course, for most game programmers, printing the score is all we want to do, but it's nice to have nonetheless.

In reality, the GDI text engine is usually too slow to print text in a real-time game, so in the end you will need to design our own DirectX-based text engine. For now, though, let's learn how to print text with GDI. At the very least, it will help with debugging and output with demos.

There are two popular functions for printing text: TextOut() and DrawText(). TextOut() is the "ghetto ride" version of text output, and DrawText() is the Lexus. I usually use TextOut() because it's faster and I don't need all the bells and whistles of DrawText(), but we'll take a look at both. Here are their prototypes:

BOOL TextOut(HDC hdc, // handle of device context
   int nXStart,   // x-coordinate of starting position
   int nYStart,   // y-coordinate of starting position
   LPCTSTR lpString,// address of string
   int cbString);  // number of characters in string

int DrawText( HDC hDC, // handle to device context
  LPCTSTR lpString, // pointer to string to draw
  int nCount,    // string length, in characters
  LPRECT lpRect,   // ptr to bounding RECT
  UINT uFormat);   // text-drawing flags

Most of the parameters are self-explanatory. For TextOut(), you simply send the device context, the x,y coordinates to print to, and the ASCII string, along with the length of the string in bytes. DrawText(), on the other hand, is a little more complex. Because it does word wrapping and formatting, it takes a different approach to printing via a rendering RECT. Thus, DrawText() doesn't take an x,y for the place to start printing; instead, it takes a RECT that defines where the printing will take place within the window (see Figure 3.17). Along with the RECT of where to print it, you send some flags that describe how to print it (such as left-justified). Please refer to the Win32 documentation for all the flags, because there are a ton of them. I'll just stick to DT_LEFT, which is the most intuitive and justifies all text to the left.

Figure 3.17Figure 3.17 The drawing RECT of DrawText().

The only problem with both calls is that there's no mention of color. Hmmmm. That's almost as strange as Boogie Nights, but who cares? Anyway, thankfully there is a way to set both the foreground color of the text and the background color behind it, in addition to the transparency mode of the text.

The transparency mode of the text dictates how the characters will be drawn. Will the characters be stamped down with rectangular regions or drawn pixel by pixel as an overlay? Figure 3.18 illustrates transparency as it relates to printing. As you can see, when text is printed with transparency, it looks as if it was drawn right on top of the graphics. Without transparency, you can actually see that there is an opaque block surrounding each character, which obscures everything—very ugly.

Figure 3.18Figure 3.18 Opaque and transparent text printing.


Rendering without transparency is faster, so if you're printing on a monochrome background and you can get away with it, do it!

Let's take a look at the functions to set the foreground and background colors of text:

COLORREF SetTextColor(HDC hdc, // handle of device context
 COLORREF Color); // foreground character color

COLORREF SetBkColor(HDC hdc, // handle of device context
 COLORREF color); // background color

Both functions take the graphics device context (from a call to GetDC() or BeginPaint()) along with the color to use in COLORREF format. Once you set these colors, they stay in flux until you change them. In addition, when you do set the colors, each function returns the current value so you can restore the old one when you're done or when your application exits.

You're almost ready to print, but this new COLORREF type has to be dealt with, don't you think? Okay, then! Here's the definition of COLORREF:

typedef struct tagCOLORREF
    BYTE bRed;  // the red component
    BYTE bGreen; // the green component
    BYTE bBlue; // the blue component
    BYTE bDummy; // unused

So in memory, a COLORREF looks like 0x00bbggrr. Remember, PCs are Little Endian—that is, low BYTE to high BYTE. To create a valid COLORREF, you can use the RGB() macro, like this:

COLORREF red  = RGB(255,0,0);
COLORREF yellow = RGB(255,255,0);

And so forth. While we're looking at color descriptor structures, we might as well look at PALETTEENTRY because it is absolutely identical:

typedef struct tagPALETTEENTRY
    BYTE peRed;   // red bits
    BYTE peGreen;  // green bits
    BYTE peBlue;  // blue bits
    BYTE peFlags;  // control flags

peFlags can take on the values in Table 3.3. In most cases you will use PC_NOCOLLAPSE and PC_RESERVED, but for now just know they exist. The interesting thing that I wanted to point out, though, is the similarity between COLORREFs and PALETTEENTRYs. They are identical except for the interpretation of the last BYTE. Hence, in many cases they're interchangeable.





Specifies that the low-order word of the logical palette entry designates a hardware palette index. Advanced.


Specifies that the color be placed in an unused entry in the system palette instead of being matched to an existing color in the system palette.


Specifies that the logical palette entry be used for palette animation. This flag prevents other windows from matching colors to the palette entry because the color frequently changes. If an unused system-palette entry is available, the color is placed in that entry. Otherwise, the color is not available for animation.

Now you're almost ready to print, but remember that there was the issue of transparency and how to set it. The function used to set the transparency mode is SetBkMode(), and here's its prototype:

int SetBkMode(HDC hdc,   // handle to device context
       int iBkMode); // transparency mode

The function takes the graphics device context along with the new transparency mode to switch to, which can be either TRANSPARENT or OPAQUE. The function returns the old mode so you can save it for later restoration.

Now you're ready to kick the tires and light the fires, big daddy. Here's how you would print some text:

COLORREF old_fcolor, // old foreground text color
     old_bcolor; // old background text color

int old_tmode; // old text transparency mode

// first get a graphics device context
HDC hdc = GetDC(hwnd);

// set the foreground color to green and save old one
old_fcolor = SetTextColor(hdc, RGB(0,255,0));

// set the background color to black and save old one
old_bcolor = SetBkColor(hdc, RGB(0,0,0));

// finally set the transparency mode to transparent
old_tmode = SetBkMode(hdc, TRANSPARENT);

// draw some text at (20,30)
TextOut(hdc, 20,30, "Hello",strlen("Hello"));

// now restore everything
SetTextColor(hwnd, old_fcolor);
SetBkColor(hwnd, old_bcolor);
SetBkMode(hwnd, old_tmode);

// release the device context
ReleaseDC(hwnd, hdc);

Of course, there is no law that you have to restore the old values, but I did it here just to show you how. Also, the color and transparency settings are valid as long as you have the handle to the device context. Let's say you wanted to draw some blue text in addition to the green text. You'd only have to change the text color to blue and then draw the text. You wouldn't have to set all three values again.

For an example of printing text using the preceding technique, take a look at DEMO3_5.CPP and the executable DEMO3_5.EXE. The demo creates a display of randomly positioned text strings in different colors all over the screen, as shown in Figure 3.19.

Figure 3.19Figure 3.19 Random text output from DEMO3_5.EXE.

The following is an excerpt from the program's WinMain(), where all the action takes place:

// get the dc and hold it
HDC hdc = GetDC(hwnd);

// enter main event loop, but this time we use PeekMessage()
// instead of GetMessage() to retrieve messages
  // test if there is a message in queue, if so get it
  if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
    // test if this is a quit
    if (msg.message == WM_QUIT)

    // translate any accelerator keys

    // send the message to the window proc
    } // end if

  // main game processing goes here

  // set the foreground color to random
  SetTextColor(hdc, RGB(rand()%256,rand()%256,rand()%256));

  // set the background color to black
  SetBkColor(hdc, RGB(0,0,0));

  // finally set the transparency mode to transparent
  SetBkMode(hdc, TRANSPARENT);

  // draw some text at a random location
  "GDI Text Demo!", strlen("GDI Text Demo!"));

  } // end while

// release the dc

As a second example of printing text, let's try doing something like updating a counter in response to the WM_PAINT message. Here's the code to do that:

char buffer[80]; // used to print string
static int wm_paint_count = 0; // track number of msg's

  case WM_PAINT:
  // simply validate the window
  hdc = BeginPaint(hwnd,&ps);

    // set the foreground color to blue
    SetTextColor(hdc, RGB(0,0,255));
    // set the background color to black
    SetBkColor(hdc, RGB(0,0,0));
    // finally set the transparency mode to transparent
    SetBkMode(hdc, OPAQUE);

    // draw some text at (0,0) reflecting number of times
    // wm_paint has been called
    sprintf(buffer,"WM_PAINT called %d times  ", ++wm_paint_count);
    TextOut(hdc, 0,0, buffer, strlen(buffer));

    // return success
  } break;

Take a look at DEMO3_6.CPP and the executable DEMO3_6.EXE on the CD-ROM to see the program in action. Notice that nothing will print until you move or overwrite the window. This is because WM_PAINT is generated only when there is some reason to restore or redraw the window, such as a movement or resize.

That's about it for basic printing. Of course, the DrawText() function does a lot more, but that's up to you. Also, you might want to look into fonts and that whole can of worms, but stuff like that is normally for full Windows GUI programming and is not really what we're trying to do in this book.

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information

To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.


Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.


If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information

Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.


This site is not directed to children under the age of 13.


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information

If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information

Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents

California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure

Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact

Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice

We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020