text: /*
   * GDI palette objects
   *
   * Copyright 1993,1994 Alexandre Julliard
   * Copyright 1996 Alex Korobka
   *
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
   * This library is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
   * License along with this library; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
   *
   * NOTES:
   * PALETTEOBJ is documented in the Dr. Dobbs Journal May 1993.
   * Information in the "Undocumented Windows" is incorrect.
   */
  
  #include <stdarg.h>
  #include <stdlib.h>
  #include <string.h>
  
  #include "windef.h"
  #include "winbase.h"
  #include "winerror.h"
  #include "wingdi.h"
  #include "winuser.h"
  
  #include "gdi_private.h"
  #include "wine/debug.h"
  
  WINE_DEFAULT_DEBUG_CHANNEL(palette);
  
  typedef BOOL (*unrealize_function)(HPALETTE);
  
  typedef struct tagPALETTEOBJ
  {
      unrealize_function  unrealize;
      WORD                version;    /* palette version */
      WORD                count;      /* count of palette entries */
      PALETTEENTRY       *entries;
  } PALETTEOBJ;
  
  static INT PALETTE_GetObject( HGDIOBJ handle, INT count, LPVOID buffer );
  static BOOL PALETTE_UnrealizeObject( HGDIOBJ handle );
  static BOOL PALETTE_DeleteObject( HGDIOBJ handle );
  
  static const struct gdi_obj_funcs palette_funcs =
  {
      NULL,                     /* pSelectObject */
      PALETTE_GetObject,        /* pGetObjectA */
      PALETTE_GetObject,        /* pGetObjectW */
      PALETTE_UnrealizeObject,  /* pUnrealizeObject */
      PALETTE_DeleteObject      /* pDeleteObject */
  };
  
  /* Pointers to USER implementation of SelectPalette/RealizePalette */
  /* they will be patched by USER on startup */
  HPALETTE (WINAPI *pfnSelectPalette)(HDC hdc, HPALETTE hpal, WORD bkgnd ) = GDISelectPalette;
  UINT (WINAPI *pfnRealizePalette)(HDC hdc) = GDIRealizePalette;
  
  static UINT SystemPaletteUse = SYSPAL_STATIC;  /* currently not considered */
  
  static HPALETTE hPrimaryPalette = 0; /* used for WM_PALETTECHANGED */
  static HPALETTE hLastRealizedPalette = 0; /* UnrealizeObject() needs it */
  
  
  /***********************************************************************
   *           PALETTE_Init
   *
   * Create the system palette.
   */
  HPALETTE PALETTE_Init(void)
  {
      const RGBQUAD *entries = get_default_color_table( 8 );
      char buffer[FIELD_OFFSET( LOGPALETTE, palPalEntry[20] )];
      LOGPALETTE *palPtr = (LOGPALETTE *)buffer;
      int i;
  
      /* create default palette (20 system colors) */
  
      palPtr->palVersion = 0x300;
      palPtr->palNumEntries = 20;
      for (i = 0; i < 20; i++)
      {
          palPtr->palPalEntry[i].peRed   = entries[i < 10 ? i : 236 + i].rgbRed;
          palPtr->palPalEntry[i].peGreen = entries[i < 10 ? i : 236 + i].rgbGreen;
          palPtr->palPalEntry[i].peBlue  = entries[i < 10 ? i : 236 + i].rgbBlue;
          palPtr->palPalEntry[i].peFlags = 0;
      }
      return CreatePalette( palPtr );
  }
  
  
  /***********************************************************************
   * CreatePalette [GDI32.@]
   *
   * Creates a logical color palette.
   *
   * RETURNS
   *    Success: Handle to logical palette
   *    Failure: NULL
   */
  HPALETTE WINAPI CreatePalette(
      const LOGPALETTE* palette) /* [in] Pointer to logical color palette */
  {
      PALETTEOBJ * palettePtr;
      HPALETTE hpalette;
      int size;
  
      if (!palette) return 0;
      TRACE("entries=%i\n", palette->palNumEntries);
  
      if (!(palettePtr = HeapAlloc( GetProcessHeap(), 0, sizeof(*palettePtr) ))) return 0;
      palettePtr->unrealize = NULL;
      palettePtr->version = palette->palVersion;
      palettePtr->count   = palette->palNumEntries;
      size = palettePtr->count * sizeof(*palettePtr->entries);
      if (!(palettePtr->entries = HeapAlloc( GetProcessHeap(), 0, size )))
      {
          HeapFree( GetProcessHeap(), 0, palettePtr );
          return 0;
      }
      memcpy( palettePtr->entries, palette->palPalEntry, size );
      if (!(hpalette = alloc_gdi_handle( palettePtr, OBJ_PAL, &palette_funcs )))
      {
          HeapFree( GetProcessHeap(), 0, palettePtr->entries );
          HeapFree( GetProcessHeap(), 0, palettePtr );
      }
      TRACE("   returning %p\n", hpalette);
      return hpalette;
  }
  
  
  /***********************************************************************
   * CreateHalftonePalette [GDI32.@]
   *
   * Creates a halftone palette.
   *
   * RETURNS
   *    Success: Handle to logical halftone palette
   *    Failure: 0
   *
   * FIXME: This simply creates the halftone palette derived from running
   *        tests on a windows NT machine. This is assuming a color depth
   *        of greater that 256 color. On a 256 color device the halftone
   *        palette will be different and this function will be incorrect
   */
  HPALETTE WINAPI CreateHalftonePalette(
      HDC hdc) /* [in] Handle to device context */
  {
      const RGBQUAD *entries = get_default_color_table( 8 );
      char buffer[FIELD_OFFSET( LOGPALETTE, palPalEntry[256] )];
      LOGPALETTE *pal = (LOGPALETTE *)buffer;
      int i;
  
      pal->palVersion = 0x300;
      pal->palNumEntries = 256;
      for (i = 0; i < 256; i++)
      {
          pal->palPalEntry[i].peRed   = entries[i].rgbRed;
          pal->palPalEntry[i].peGreen = entries[i].rgbGreen;
          pal->palPalEntry[i].peBlue  = entries[i].rgbBlue;
          pal->palPalEntry[i].peFlags = 0;
      }
      return CreatePalette( pal );
  }
  
  
  /***********************************************************************
   * GetPaletteEntries [GDI32.@]
   *
   * Retrieves palette entries.
   *
   * RETURNS
   *    Success: Number of entries from logical palette
   *    Failure: 0
   */
  UINT WINAPI GetPaletteEntries(
      HPALETTE hpalette,    /* [in]  Handle of logical palette */
      UINT start,           /* [in]  First entry to receive */
      UINT count,           /* [in]  Number of entries to receive */
      LPPALETTEENTRY entries) /* [out] Address of array receiving entries */
  {
      PALETTEOBJ * palPtr;
      UINT numEntries;
  
      TRACE("hpal = %p, count=%i\n", hpalette, count );
  
      palPtr = GDI_GetObjPtr( hpalette, OBJ_PAL );
      if (!palPtr) return 0;
  
      /* NOTE: not documented but test show this to be the case */
      if (count == 0)
      {
          count = palPtr->count;
      }
      else
      {
          numEntries = palPtr->count;
          if (start+count > numEntries) count = numEntries - start;
          if (entries)
          {
              if (start >= numEntries) count = 0;
              else memcpy( entries, &palPtr->entries[start], count * sizeof(PALETTEENTRY) );
          }
      }
  
      GDI_ReleaseObj( hpalette );
      return count;
  }
  
  
  /***********************************************************************
   * SetPaletteEntries [GDI32.@]
   *
   * Sets color values for range in palette.
   *
   * RETURNS
   *    Success: Number of entries that were set
   *    Failure: 0
   */
  UINT WINAPI SetPaletteEntries(
      HPALETTE hpalette,    /* [in] Handle of logical palette */
      UINT start,           /* [in] Index of first entry to set */
      UINT count,           /* [in] Number of entries to set */
      const PALETTEENTRY *entries) /* [in] Address of array of structures */
  {
      PALETTEOBJ * palPtr;
      UINT numEntries;
  
      TRACE("hpal=%p,start=%i,count=%i\n",hpalette,start,count );
  
      hpalette = get_full_gdi_handle( hpalette );
      if (hpalette == GetStockObject(DEFAULT_PALETTE)) return 0;
      palPtr = GDI_GetObjPtr( hpalette, OBJ_PAL );
      if (!palPtr) return 0;
  
      numEntries = palPtr->count;
      if (start >= numEntries)
      {
        GDI_ReleaseObj( hpalette );
        return 0;
      }
      if (start+count > numEntries) count = numEntries - start;
      memcpy( &palPtr->entries[start], entries, count * sizeof(PALETTEENTRY) );
      GDI_ReleaseObj( hpalette );
      UnrealizeObject( hpalette );
      return count;
  }
  
  
  /***********************************************************************
   * ResizePalette [GDI32.@]
   *
   * Resizes logical palette.
   *
   * RETURNS
   *    Success: TRUE
   *    Failure: FALSE
   */
  BOOL WINAPI ResizePalette(
      HPALETTE hPal, /* [in] Handle of logical palette */
      UINT cEntries) /* [in] Number of entries in logical palette */
  {
      PALETTEOBJ * palPtr = GDI_GetObjPtr( hPal, OBJ_PAL );
      PALETTEENTRY *entries;
  
      if( !palPtr ) return FALSE;
      TRACE("hpal = %p, prev = %i, new = %i\n", hPal, palPtr->count, cEntries );
  
      if (!(entries = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
                                   palPtr->entries, cEntries * sizeof(*palPtr->entries) )))
      {
          GDI_ReleaseObj( hPal );
          return FALSE;
      }
      palPtr->entries = entries;
      palPtr->count = cEntries;
  
      GDI_ReleaseObj( hPal );
      PALETTE_UnrealizeObject( hPal );
      return TRUE;
  }
  
  
  /***********************************************************************
   * AnimatePalette [GDI32.@]
   *
   * Replaces entries in logical palette.
   *
   * RETURNS
   *    Success: TRUE
   *    Failure: FALSE
   *
   * FIXME
   *    Should use existing mapping when animating a primary palette
   */
  BOOL WINAPI AnimatePalette(
      HPALETTE hPal,              /* [in] Handle to logical palette */
      UINT StartIndex,            /* [in] First entry in palette */
      UINT NumEntries,            /* [in] Count of entries in palette */
      const PALETTEENTRY* PaletteColors) /* [in] Pointer to first replacement */
  {
      TRACE("%p (%i - %i)\n", hPal, StartIndex,StartIndex+NumEntries);
  
      hPal = get_full_gdi_handle( hPal );
      if( hPal != GetStockObject(DEFAULT_PALETTE) )
      {
          PALETTEOBJ * palPtr;
          UINT pal_entries;
          const PALETTEENTRY *pptr = PaletteColors;
  
          palPtr = GDI_GetObjPtr( hPal, OBJ_PAL );
          if (!palPtr) return FALSE;
  
          pal_entries = palPtr->count;
          if (StartIndex >= pal_entries)
          {
            GDI_ReleaseObj( hPal );
            return FALSE;
          }
          if (StartIndex+NumEntries > pal_entries) NumEntries = pal_entries - StartIndex;
          
          for (NumEntries += StartIndex; StartIndex < NumEntries; StartIndex++, pptr++) {
            /* According to MSDN, only animate PC_RESERVED colours */
            if (palPtr->entries[StartIndex].peFlags & PC_RESERVED) {
              TRACE("Animating colour (%d,%d,%d) to (%d,%d,%d)\n",
                palPtr->entries[StartIndex].peRed,
                palPtr->entries[StartIndex].peGreen,
                palPtr->entries[StartIndex].peBlue,
                pptr->peRed, pptr->peGreen, pptr->peBlue);
              palPtr->entries[StartIndex] = *pptr;
            } else {
              TRACE("Not animating entry %d -- not PC_RESERVED\n", StartIndex);
            }
          }
          GDI_ReleaseObj( hPal );
          /* FIXME: check for palette selected in active window */
      }
      return TRUE;
  }
  
  
  /***********************************************************************
   * SetSystemPaletteUse [GDI32.@]
   *
   * Specify whether the system palette contains 2 or 20 static colors.
   *
   * RETURNS
   *    Success: Previous system palette
   *    Failure: SYSPAL_ERROR
   */
  UINT WINAPI SetSystemPaletteUse(
      HDC hdc,  /* [in] Handle of device context */
      UINT use) /* [in] Palette-usage flag */
  {
      UINT old = SystemPaletteUse;
  
      /* Device doesn't support colour palettes */
      if (!(GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE)) {
          return SYSPAL_ERROR;
      }
  
      switch (use) {
          case SYSPAL_NOSTATIC:
          case SYSPAL_NOSTATIC256:        /* WINVER >= 0x0500 */
          case SYSPAL_STATIC:
              SystemPaletteUse = use;
              return old;
          default:
              return SYSPAL_ERROR;
      }
  }
  
  
  /***********************************************************************
   * GetSystemPaletteUse [GDI32.@]
   *
   * Gets state of system palette.
   *
   * RETURNS
   *    Current state of system palette
   */
  UINT WINAPI GetSystemPaletteUse(
      HDC hdc) /* [in] Handle of device context */
  {
      return SystemPaletteUse;
  }
  
  
  /***********************************************************************
   * GetSystemPaletteEntries [GDI32.@]
   *
   * Gets range of palette entries.
   *
   * RETURNS
   *    Success: Number of entries retrieved from palette
   *    Failure: 0
   */
  UINT WINAPI GetSystemPaletteEntries(
      HDC hdc,              /* [in]  Handle of device context */
      UINT start,           /* [in]  Index of first entry to be retrieved */
      UINT count,           /* [in]  Number of entries to be retrieved */
      LPPALETTEENTRY entries) /* [out] Array receiving system-palette entries */
  {
      UINT ret = 0;
      DC *dc;
  
      TRACE("hdc=%p,start=%i,count=%i\n", hdc,start,count);
  
      if ((dc = get_dc_ptr( hdc )))
      {
          PHYSDEV physdev = GET_DC_PHYSDEV( dc, pGetSystemPaletteEntries );
          ret = physdev->funcs->pGetSystemPaletteEntries( physdev, start, count, entries );
          release_dc_ptr( dc );
      }
      return ret;
  }
  
  
  /* null driver fallback implementation for GetSystemPaletteEntries */
  UINT nulldrv_GetSystemPaletteEntries( PHYSDEV dev, UINT start, UINT count, PALETTEENTRY *entries )
  {
      if (entries && start < 256)
      {
          UINT i;
          const RGBQUAD *default_entries;
  
          if (start + count > 256) count = 256 - start;
  
          default_entries = get_default_color_table( 8 );
          for (i = 0; i < count; ++i)
          {
              if (start + i < 10 || start + i >= 246)
              {
                  entries[i].peRed = default_entries[start + i].rgbRed;
                  entries[i].peGreen = default_entries[start + i].rgbGreen;
                  entries[i].peBlue = default_entries[start + i].rgbBlue;
              }
              else
              {
                  entries[i].peRed = 0;
                  entries[i].peGreen = 0;
                  entries[i].peBlue = 0;
              }
              entries[i].peFlags = 0;
          }
      }
      return 0;
  }
  
  /***********************************************************************
   * GetNearestPaletteIndex [GDI32.@]
   *
   * Gets palette index for color.
   *
   * NOTES
   *    Should index be initialized to CLR_INVALID instead of 0?
   *
   * RETURNS
   *    Success: Index of entry in logical palette
   *    Failure: CLR_INVALID
   */
  UINT WINAPI GetNearestPaletteIndex(
      HPALETTE hpalette, /* [in] Handle of logical color palette */
      COLORREF color)      /* [in] Color to be matched */
  {
      PALETTEOBJ* palObj = GDI_GetObjPtr( hpalette, OBJ_PAL );
      UINT index  = 0;
  
      if( palObj )
      {
          int i, diff = 0x7fffffff;
          int r,g,b;
          PALETTEENTRY* entry = palObj->entries;
  
          for( i = 0; i < palObj->count && diff ; i++, entry++)
          {
              r = entry->peRed - GetRValue(color);
              g = entry->peGreen - GetGValue(color);
              b = entry->peBlue - GetBValue(color);
  
              r = r*r + g*g + b*b;
  
              if( r < diff ) { index = i; diff = r; }
          }
          GDI_ReleaseObj( hpalette );
      }
      TRACE("(%p,%06x): returning %d\n", hpalette, color, index );
      return index;
  }
  
  
  /* null driver fallback implementation for GetNearestColor */
  COLORREF nulldrv_GetNearestColor( PHYSDEV dev, COLORREF color )
  {
      unsigned char spec_type;
      DC *dc = get_nulldrv_dc( dev );
  
      if (!(GetDeviceCaps( dev->hdc, RASTERCAPS ) & RC_PALETTE)) return color;
  
      spec_type = color >> 24;
      if (spec_type == 1 || spec_type == 2)
      {
          /* we need logical palette for PALETTERGB and PALETTEINDEX colorrefs */
          UINT index;
          PALETTEENTRY entry;
          HPALETTE hpal = dc->hPalette;
  
          if (!hpal) hpal = GetStockObject( DEFAULT_PALETTE );
          if (spec_type == 2) /* PALETTERGB */
              index = GetNearestPaletteIndex( hpal, color );
          else  /* PALETTEINDEX */
              index = LOWORD(color);
  
          if (!GetPaletteEntries( hpal, index, 1, &entry ))
          {
              WARN("RGB(%x) : idx %d is out of bounds, assuming NULL\n", color, index );
              if (!GetPaletteEntries( hpal, 0, 1, &entry )) return CLR_INVALID;
          }
          color = RGB( entry.peRed, entry.peGreen, entry.peBlue );
      }
      return color & 0x00ffffff;
  }
  
  
  /***********************************************************************
   * GetNearestColor [GDI32.@]
   *
   * Gets a system color to match.
   *
   * RETURNS
   *    Success: Color from system palette that corresponds to given color
   *    Failure: CLR_INVALID
   */
  COLORREF WINAPI GetNearestColor(
      HDC hdc,      /* [in] Handle of device context */
      COLORREF color) /* [in] Color to be matched */
  {
      COLORREF nearest = CLR_INVALID;
      DC *dc;
  
      if ((dc = get_dc_ptr( hdc )))
      {
          PHYSDEV physdev = GET_DC_PHYSDEV( dc, pGetNearestColor );
          nearest = physdev->funcs->pGetNearestColor( physdev, color );
          release_dc_ptr( dc );
      }
      return nearest;
  }
  
  
  /***********************************************************************
   *           PALETTE_GetObject
   */
  static INT PALETTE_GetObject( HGDIOBJ handle, INT count, LPVOID buffer )
  {
      PALETTEOBJ *palette = GDI_GetObjPtr( handle, OBJ_PAL );
  
      if (!palette) return 0;
  
      if (buffer)
      {
          if (count > sizeof(WORD)) count = sizeof(WORD);
          memcpy( buffer, &palette->count, count );
      }
      else count = sizeof(WORD);
      GDI_ReleaseObj( handle );
      return count;
  }
  
  
  /***********************************************************************
   *           PALETTE_UnrealizeObject
   */
  static BOOL PALETTE_UnrealizeObject( HGDIOBJ handle )
  {
      PALETTEOBJ *palette = GDI_GetObjPtr( handle, OBJ_PAL );
  
      if (palette)
      {
          unrealize_function unrealize = palette->unrealize;
          palette->unrealize = NULL;
          GDI_ReleaseObj( handle );
          if (unrealize) unrealize( handle );
      }
  
      if (InterlockedCompareExchangePointer( (void **)&hLastRealizedPalette, 0, handle ) == handle)
          TRACE("unrealizing palette %p\n", handle);
  
      return TRUE;
  }
  
  
  /***********************************************************************
   *           PALETTE_DeleteObject
   */
  static BOOL PALETTE_DeleteObject( HGDIOBJ handle )
  {
      PALETTEOBJ *obj;
  
      PALETTE_UnrealizeObject( handle );
      if (!(obj = free_gdi_handle( handle ))) return FALSE;
      HeapFree( GetProcessHeap(), 0, obj->entries );
      return HeapFree( GetProcessHeap(), 0, obj );
  }
  
  
  /***********************************************************************
   *           GDISelectPalette    (Not a Windows API)
   */
  HPALETTE WINAPI GDISelectPalette( HDC hdc, HPALETTE hpal, WORD wBkg)
  {
      HPALETTE ret = 0;
      DC *dc;
  
      TRACE("%p %p\n", hdc, hpal );
  
      hpal = get_full_gdi_handle( hpal );
      if (GetObjectType(hpal) != OBJ_PAL)
      {
        WARN("invalid selected palette %p\n",hpal);
        return 0;
      }
      if ((dc = get_dc_ptr( hdc )))
      {
          PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSelectPalette );
          ret = dc->hPalette;
          if (physdev->funcs->pSelectPalette( physdev, hpal, FALSE ))
          {
              dc->hPalette = hpal;
              if (!wBkg) hPrimaryPalette = hpal;
          }
          else ret = 0;
          release_dc_ptr( dc );
      }
      return ret;
  }
  
  
  /***********************************************************************
   *           GDIRealizePalette    (Not a Windows API)
   */
  UINT WINAPI GDIRealizePalette( HDC hdc )
  {
      UINT realized = 0;
      DC* dc = get_dc_ptr( hdc );
  
      if (!dc) return 0;
  
      TRACE("%p...\n", hdc );
  
      if( dc->hPalette == GetStockObject( DEFAULT_PALETTE ))
      {
          PHYSDEV physdev = GET_DC_PHYSDEV( dc, pRealizeDefaultPalette );
          realized = physdev->funcs->pRealizeDefaultPalette( physdev );
      }
      else if (InterlockedExchangePointer( (void **)&hLastRealizedPalette, dc->hPalette ) != dc->hPalette)
      {
          PHYSDEV physdev = GET_DC_PHYSDEV( dc, pRealizePalette );
          PALETTEOBJ *palPtr = GDI_GetObjPtr( dc->hPalette, OBJ_PAL );
          if (palPtr)
          {
              realized = physdev->funcs->pRealizePalette( physdev, dc->hPalette,
                                                          (dc->hPalette == hPrimaryPalette) );
              palPtr->unrealize = physdev->funcs->pUnrealizePalette;
              GDI_ReleaseObj( dc->hPalette );
          }
      }
      else TRACE("  skipping (hLastRealizedPalette = %p)\n", hLastRealizedPalette);
  
      release_dc_ptr( dc );
      TRACE("   realized %i colors.\n", realized );
      return realized;
  }
  
  
  /***********************************************************************
   * SelectPalette [GDI32.@]
   *
   * Selects logical palette into DC.
   *
   * RETURNS
   *    Success: Previous logical palette
   *    Failure: NULL
   */
  HPALETTE WINAPI SelectPalette(
      HDC hDC,               /* [in] Handle of device context */
      HPALETTE hPal,         /* [in] Handle of logical color palette */
      BOOL bForceBackground) /* [in] Foreground/background mode */
  {
      return pfnSelectPalette( hDC, hPal, bForceBackground );
  }
  
  
  /***********************************************************************
   * RealizePalette [GDI32.@]
   *
   * Maps palette entries to system palette.
   *
   * RETURNS
   *    Success: Number of entries in logical palette
   *    Failure: GDI_ERROR
   */
  UINT WINAPI RealizePalette(
      HDC hDC) /* [in] Handle of device context */
  {
      return pfnRealizePalette( hDC );
  }
  
  
  typedef HWND (WINAPI *WindowFromDC_funcptr)( HDC );
  typedef BOOL (WINAPI *RedrawWindow_funcptr)( HWND, const RECT *, HRGN, UINT );
  
  /**********************************************************************
   * UpdateColors [GDI32.@]
   *
   * Remaps current colors to logical palette.
   *
   * RETURNS
   *    Success: TRUE
   *    Failure: FALSE
   */
  BOOL WINAPI UpdateColors(
      HDC hDC) /* [in] Handle of device context */
  {
      HMODULE mod;
      int size = GetDeviceCaps( hDC, SIZEPALETTE );
  
      if (!size) return FALSE;
  
      mod = GetModuleHandleA("user32.dll");
      if (mod)
      {
          WindowFromDC_funcptr pWindowFromDC = (WindowFromDC_funcptr)GetProcAddress(mod,"WindowFromDC");
          if (pWindowFromDC)
          {
              HWND hWnd = pWindowFromDC( hDC );
  
              /* Docs say that we have to remap current drawable pixel by pixel
               * but it would take forever given the speed of XGet/PutPixel.
               */
              if (hWnd && size)
              {
                  RedrawWindow_funcptr pRedrawWindow = (void *)GetProcAddress( mod, "RedrawWindow" );
                  if (pRedrawWindow) pRedrawWindow( hWnd, NULL, 0, RDW_INVALIDATE );
              }
          }
      }
      return TRUE;
  }
  
  /*********************************************************************
   *           SetMagicColors   (GDI32.@)
   */
  BOOL WINAPI SetMagicColors(HDC hdc, ULONG u1, ULONG u2)
  {
      FIXME("(%p 0x%08x 0x%08x): stub\n", hdc, u1, u2);
      return TRUE;
  }
  