CS-460/560, Wk-2c
Spring, 2000
R. Eckert


Depending on the capabilities of the video subsystem, Windows can
use either direct or indirect color. Direct color modes include
16-bit "High Color" or 24-bit "True Color". For the latter the
frame buffer is divided into 8-bit red, green, and blue channels.
Thus a total of 2^24 different colors is possible. To use direct
color, you can get a color reference with the macro RGB(), as we've
already seen.

More interesting (and, in general, faster) are the indirect color
modes. Either a 16-entry (4 bits per pixel) or a 256-entry (8
bits per pixel) color lookup table can be used. These color
lookup tables are called "palettes" and controlled by the
"Palette Manager"--an integral part of the Windows GDI. In the
following discussion, we will concentrate on the 256-color CLUT.

The Palette Manager maintains a system palette, which can be
thought of as a copy of the physical hardware CLUT. (On most SVGA
video cards, this is not strictly true, since they usually
support 6 bits per channel, while the system palette always
contains a full 8 bits per channel.) The contents of the system
palette determine the colors that will be displayed on the
screen. Given the multitasking nature of Windows and the fact
that there is only one physical hardware palette, sharing the
palette is much more involved than in the case of a single-user
system like DOS. If an application could arbitrarily change the
palette, all other applications would pay the consequences. So
Palette Manager reserves 20 "static" colors that cannot easily
be changed. The other 236 can be changed by obtaining a "logical
palette", selecting it into the display device context, and
"realizing" it. The last step maps the requested logical palette
to the system palette.

The function that causes the color mapping to occur is
RealizePalette(). This function causes Palette Manager to look at
each color in the logical palette and compare it to the colors
already in the system palette. If an exact match is found, the
logical palette entry is mapped to its corresponding entry in the
system palette. If an exact match is not found, Palette Manager
first looks for a free entry in the system palette. If one is
found, the logical entry is copied to the system palette and is
mapped to its newly-created matching entry in the system
palette. If there are no free entries, the closest matching entry
in the system palette is found and the palette entry is mapped to
it. The details of how this occurs depend on the value of a flag
that is a member of the logical palette structure that describes
the logical palette. Active foreground applications are usually
mapped first.

The normal sequence that is used to request a change in the
system palette is:

1. Set up the fields of a "logical palette" structure according to
the colors desired and how the mapping is to be done. Windows
defines the following LOGPALETTE structure:

typedef struct tagLOGPALETTE
    WORD         palVersion;
    WORD         palNumEntries;
    PALETTEENTRY palPalEntry[1];

The palVersion member should be set to 0x300 (Windows verion 3.0 or later), 
the palNumEntries member to the number of colors to be changed in the 
palette, and the palPalEntry[] array is used to describe each new entry.
This structure is defined as follows:

typedef struct tagPALETTEENTRY 
    BYTE  peRed;
    BYTE  peGreen;
    BYTE  peBlue;
    BYTE  peFlags;

The first three members are the intensity of red, green, and blue, while
the last entry describes how the mapping is to be done for that entry. In
most cases 0 can be used for that entry. (Check out the online help for

If you use a variable of type LOGPALETTE and wish to change more than the
first entry in the palette, you will need to allocate memory space for
the rest of the entries you are changing. (LocalAlloc() could be used 
for this.)

2. Once you have your logical palette structure set up, make a call to 
CreatePalette(). This takes a pointer to the logical palette structure 
(type LPLOGPALETTE) as a parameter and returns a handle to the resulting 
palette (type HPALETTE).

3. Select the logical palette whose handle (e.g., hPal) was obtained in 
step 2 into the device context (e.g., hDC) using SelectPalette(hDC,hPal,FALSE); 
The third argument is a Boolean that forces the resulting palette to the 
background if true--which is usually not the desired result. Like the 
SelectObject() function which is used to select other drawing objects into a 
device context, SelectPalette() returns a handle to the old palette that was 
displaced. (A logical palette is in some ways like other kinds of GDI drawing 

4. Finally, call the function RealizePalette(hDC) to map the logical palette
to the system palette. This is when the colors will actually change.

Now that you have your logical palette mapped to the system palette, you will
want to use the colors that are contained in it in your calls to Windows'
drawing functions. Since we are using indirect color, the RGB() macro is not
very useful; instead use the macro PALETTEINDEX(i) to return a color reference
to the color stored at position i in the system palette. This could be done
when you create a solid brush or pen (which would then have to be selected
into a device context) or, for example, if you are setting pixels directly
with SetPixel(), PALETTEINDEX(i) can be used as the last parameter, for

SetPixel(hDC, x, y, PALETTEINDEX(5));  // Set the pixel at x,y to color 5

After you have finished using the palette in your application, you should 
get rid of it by selecting it out of the device context and deleting it:

SelectPalette(hDC,hPalOld,False);  // This assumes we saved the old palette
DeleteObject(hPal);                // in hOldPal when we created the new one