SAMPLE: Using the Palette Under Windows

Last reviewed: February 15, 1996
Article ID: Q74908
The information in this article applies to:
  • Microsoft Windows Software Development Kit (SDK) for Windows versions 3.0 and 3.1

SUMMARY

The palette is a mechanism to manage the colors used on the Windows display. This article discusses the steps necessary for an application to create and use a palette. This article is meant to supplement the information provided in the Windows SDK documentation.

MORE INFORMATION

Q: What is the difference between the system palette and a logical

   palette?

A: The system palette is the palette that is actually in use (the
   colors on the screen at any given time are the colors of the system
   palette). Many applications do not create a logical palette.
   Therefore, by default, these applications use the predefined colors
   in the default system palette. The handle to this default palette
   can be obtained by calling GetStockObject(DEFAULT_PALETTE).

   A logical palette is one that the application creates; the
   application also specifies what colors the palette contains. Using
   certain GDI calls, the application can temporarily replace most of
   the system palette with the logical palette, which allows the
   application to use the colors in the logical palette. Windows
   reserves some entries in the system palette for itself. These are
   not replaced when the operations described in this article are
   used.


Q: How are logical palettes created?

A: Before creating a palette, the application should check the

   system's capabilities for color resolution. The following code
   demonstrates how this is done:

    HDC           hDCGlobal;
    NPLOGPALETTE  pLogPal;               // Pointer to program's
                                         // logical palette

    int           iNumColors;            // Number of colors supported
                                         // by device

    int           iPalSize, iRasterCaps; // Size of Physical palette

    hDCGlobal = GetDC(NULL);
    iPalSize = GetDeviceCaps(hDCGlobal, SIZEPALETTE);
    iRasterCaps = GetDeviceCaps(hDCGlobal, RASTERCAPS);
    iRasterCaps = (iRasterCaps & RC_PALETTE) ? TRUE : FALSE;

    if (iRasterCaps)
      iNumColors = GetDeviceCaps(hDCGlobal, SIZEPALETTE);
    else
      iNumColors = GetDeviceCaps(hDCGlobal, NUMCOLORS);

    ReleaseDC(NULL, hDCGlobal);

   The variable iNumColors should have a value of 2, 16, or 256,
   depending on the video card installed. This number can change in
   the future, depending on the advances in hardware technology.

   If RC_PALETTE is not set, the device is not capable of palette
   manipulation. When this is the case, however, an application can
   still create a palette, select it into a display context, and use
   the colors from the palette. GDI will create a dithered pattern
   (the disadvantages of which are discussed below) to simulate the
   color in the palette.

   After the number of colors has been determined, a block of memory
   must be allocated to hold the palette entries. A palette entry is a
   structure that contains the red, green, and blue values to specify
   the color, plus a flag. The flag is used to denote special colors
   for use in animation and other special cases. Consult the SDK
   documentation for a more complete description. For this article,
   the default flag value of NULL will be used; which means this color
   has no special attributes.

   The following code will allocate a block of memory large enough for
   the palette in local memory:

    pLogPal = (NPLOGPALETTE)LocalAlloc(LMEM_FIXED,
        (sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * (iNumColors))));

    pLogPal->palVersion = 0x300;      // Windows Version 3.0
    pLogPal->palNumEntries = iNumColors;


   Now that the memory structure has been created, it is the
   responsibility of the application to put the necessary values into
   the structure to create colors. There are two different means of
   doing this: use the default system color, or create a custom color.
   The following code examples demonstrate these two options. Assume
   that the variable PaletteIndex is valid in the range from 0 (zero)
   to (iNumColors-1).

   Use the default system color:

      pLogPal->palPalEntry[PaletteIndex].peRed = PaletteIndex;
      pLogPal->palPalEntry[PaletteIndex].peFlags = PC_EXPLICIT;

   Use a custom color:

      pLogPal->palPalEntry[PaletteIndex].peRed = <red value>;
      pLogPal->palPalEntry[PaletteIndex].peGreen = <green value>;
      pLogPal->palPalEntry[PaletteIndex].peBlue  = <blue value>;
      pLogPal->palPalEntry[PaletteIndex].peFlags = NULL;

   Once the structure has been filled with the appropriate values, it
   is time to use the GDI call CreatePalette() to make the logical
   palette:

      hPal = CreatePalette((LPLOGPALETTE)pLogPal);

   During the processing of one of the application termination message
   (WM_QUIT or WM_CLOSE), use DeleteObject(hPal) to free the system
   resources used by the palette.


Q: How are logical palettes used?

A: In Windows applications, colors are generated by three means: by

   specifying the explicit red, green, and blue color values [using
   the RGB() macro], by specifying the index into a palette [using the
   PALETTEINDEX() macro], or by specifying red, green, and blue color
   values and asking Windows to return the closest entry into the
   palette. Therefore, if a particular set of red, green, and blue
   values has been specified for palette entry 25, the following three
   lines of code will seem to be identical:

      hBrush = CreateSolidBrush(RGB(122, 15, 200));
      hBrush = CreateSolidBrush(PALETTEINDEX(25));
      hBrush = CreateSolidBrush(PALETTERGB(122, 15, 200));

   However, this is not the case. Even though the palette entry #25
   may have red, green, and blue (RGB) values of 122, 15, and 200,
   respectively, the results will be different. The first example will
   produce a brush that is a dithered pattern of the eight main system
   colors. The second and third examples will use the pure color
   defined in the palette, which produces more pleasing results.

   There are advantages and disadvantages to using RGB dithers or
   to using palette colors:

   - RGB dithers will always retain their color, even as the palette
   is changed, because they are composed of reserved colors. RGB
   dithers will appear identical on 16-color and 256-color systems.
   However, RGB dithers are less attractive than pure palette colors,
   and single-pixel-thick lines will be drawn in the pure color that
   most closely matches the dithered color.

   - Palette entries will use a true color for the red, green, and
   blue values. Single-pixel-thick lines will not be matched to one of
   the reserved pure colors. However, when the application loses
   focus, the system palette may change (due to another application
   changing the palette). This will cause the colors that the
   application uses to change. When the application regains the focus,
   it can restore the palette if it was changed. Managing the palette
   also requires additional code and memory.

   CWHEEL.EXE is a file in the Software Library that demonstrates
   managing the palette by drawing a color wheel on the screen. The
   following is an excerpt of the code in that file.

      case WM_PAINT:

          hDC = BeginPaint(hWnd, (LPPAINTSTRUCT)&ps);

          // Bring in the palette
          hOldPal = SelectPalette(hDC, hPal, FALSE);

          // Synchronize the system palette with this application's
          // logical palette
          RealizePalette(hDC);

          // Perform any GDI operations here....

          // Bring back in the previous palette
          SelectPalette(hDC, hOldPal, TRUE);

          EndPaint(hWnd, (LPPAINTSTRUCT)&ps);
          break;

Download CWHEEL.EXE, a self-extracting file, from the Microsoft Software Library (MSL) on the following services:
  • Microsoft Download Service (MSDL)

          Dial (206) 936-6735 to connect to MSDL
          Download CWHEEL.EXE (size: 21196 bytes) 
    
  • Internet (anonymous FTP)

          ftp ftp.microsoft.com
          Change to the \SOFTLIB\MSLFILES directory
          Get CWHEEL.EXE (size: 21196 bytes) 
    


Additional reference words: 3.00 3.10 softlib CWHEEL.EXE
KBCategory: kbprg kbfile
KBSubcategory: GdiPal


THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

Last reviewed: February 15, 1996
© 1998 Microsoft Corporation. All rights reserved. Terms of Use.