More code moved to the X11 driver (bitmap and palette and misc).
[wine] / objects / cursoricon.c
1 /*
2  * Cursor and icon support
3  *
4  * Copyright 1995 Alexandre Julliard
5  *           1996 Martin Von Loewis
6  *           1997 Alex Korobka
7  *           1998 Turchanov Sergey
8  */
9
10 /*
11  * Theory:
12  *
13  * http://www.microsoft.com/win32dev/ui/icons.htm
14  *
15  * Cursors and icons are stored in a global heap block, with the
16  * following layout:
17  *
18  * CURSORICONINFO info;
19  * BYTE[]         ANDbits;
20  * BYTE[]         XORbits;
21  *
22  * The bits structures are in the format of a device-dependent bitmap.
23  *
24  * This layout is very sub-optimal, as the bitmap bits are stored in
25  * the X client instead of in the server like other bitmaps; however,
26  * some programs (notably Paint Brush) expect to be able to manipulate
27  * the bits directly :-(
28  *
29  * FIXME: what are we going to do with animation and color (bpp > 1) cursors ?!
30  */
31
32 #include <string.h>
33 #include <stdlib.h>
34
35 #include "wine/winbase16.h"
36 #include "wine/winuser16.h"
37 #include "heap.h"
38 #include "color.h"
39 #include "bitmap.h"
40 #include "cursoricon.h"
41 #include "dc.h"
42 #include "gdi.h"
43 #include "sysmetrics.h"
44 #include "global.h"
45 #include "module.h"
46 #include "debug.h"
47 #include "task.h"
48 #include "user.h"
49 #include "input.h"
50 #include "display.h"
51 #include "message.h"
52 #include "winerror.h"
53
54 static HCURSOR hActiveCursor = 0;  /* Active cursor */
55 static INT CURSOR_ShowCount = 0;   /* Cursor display count */
56 static RECT CURSOR_ClipRect;       /* Cursor clipping rect */
57
58
59 /**********************************************************************
60  * ICONCACHE for cursors/icons loaded with LR_SHARED.
61  *
62  * FIXME: This should not be allocated on the system heap, but on a
63  *        subsystem-global heap (i.e. one for all Win16 processes,
64  *        and one each for every Win32 process).
65  */
66 typedef struct tagICONCACHE
67 {
68     struct tagICONCACHE *next;
69
70     HMODULE              hModule;
71     HRSRC                hRsrc;
72     HANDLE               handle;
73
74     INT                  count;
75
76 } ICONCACHE;
77
78 static ICONCACHE *IconAnchor = NULL;
79 static CRITICAL_SECTION IconCrst;
80
81 /**********************************************************************
82  *          CURSORICON_Init
83  */
84 void CURSORICON_Init( void )
85 {
86     InitializeCriticalSection( &IconCrst );
87     MakeCriticalSectionGlobal( &IconCrst );
88 }
89
90 /**********************************************************************
91  *          CURSORICON_FindSharedIcon
92  */
93 static HANDLE CURSORICON_FindSharedIcon( HMODULE hModule, HRSRC hRsrc )
94 {
95     HANDLE handle = 0;
96     ICONCACHE *ptr;
97
98     EnterCriticalSection( &IconCrst );
99
100     for ( ptr = IconAnchor; ptr; ptr = ptr->next )
101         if ( ptr->hModule == hModule && ptr->hRsrc == hRsrc )
102         {
103             ptr->count++;
104             handle = ptr->handle;
105             break;
106         }
107
108     LeaveCriticalSection( &IconCrst );
109
110     return handle;
111 }
112
113 /**********************************************************************
114  *          CURSORICON_AddSharedIcon
115  */
116 static void CURSORICON_AddSharedIcon( HMODULE hModule, HRSRC hRsrc, HANDLE handle )
117 {
118     ICONCACHE *ptr = HeapAlloc( SystemHeap, 0, sizeof(ICONCACHE) );
119     if ( !ptr ) return;
120
121     ptr->hModule = hModule;
122     ptr->hRsrc   = hRsrc;
123     ptr->handle  = handle;
124     ptr->count   = 1;
125
126     EnterCriticalSection( &IconCrst );
127     ptr->next    = IconAnchor;
128     IconAnchor   = ptr;
129     LeaveCriticalSection( &IconCrst );
130 }
131
132 /**********************************************************************
133  *          CURSORICON_DelSharedIcon
134  */
135 static INT CURSORICON_DelSharedIcon( HANDLE handle )
136 {
137     INT count = -1;
138     ICONCACHE *ptr;
139
140     EnterCriticalSection( &IconCrst );
141
142     for ( ptr = IconAnchor; ptr; ptr = ptr->next )
143         if ( ptr->handle == handle )
144         {
145             if ( ptr->count > 0 ) ptr->count--;
146             count = ptr->count;
147             break;
148         }
149
150     LeaveCriticalSection( &IconCrst );
151
152     return count;
153 }
154
155 /**********************************************************************
156  *          CURSORICON_FreeModuleIcons
157  */
158 void CURSORICON_FreeModuleIcons( HMODULE hModule )
159 {
160     ICONCACHE **ptr = &IconAnchor;
161
162     if ( HIWORD( hModule ) )
163         hModule = MapHModuleLS( hModule );
164     else
165         hModule = GetExePtr( hModule );
166
167     EnterCriticalSection( &IconCrst );
168
169     while ( *ptr )
170     {
171         if ( (*ptr)->hModule == hModule )
172         {
173             ICONCACHE *freePtr = *ptr;
174             *ptr = freePtr->next;
175             
176             GlobalFree16( freePtr->handle );
177             HeapFree( SystemHeap, 0, freePtr );
178             continue;
179         }
180         ptr = &(*ptr)->next;
181     }
182
183     LeaveCriticalSection( &IconCrst );
184 }
185
186 /**********************************************************************
187  *          CURSORICON_FindBestIcon
188  *
189  * Find the icon closest to the requested size and number of colors.
190  */
191 static ICONDIRENTRY *CURSORICON_FindBestIcon( CURSORICONDIR *dir, int width,
192                                               int height, int colors )
193 {
194     int i, maxcolors, maxwidth, maxheight;
195     ICONDIRENTRY *entry, *bestEntry = NULL;
196
197     if (dir->idCount < 1)
198     {
199         WARN(icon, "Empty directory!\n" );
200         return NULL;
201     }
202     if (dir->idCount == 1) return &dir->idEntries[0].icon;  /* No choice... */
203
204     /* First find the exact size with less colors */
205
206     maxcolors = 0;
207     for (i = 0, entry = &dir->idEntries[0].icon; i < dir->idCount; i++,entry++)
208         if ((entry->bWidth == width) && (entry->bHeight == height) &&
209             (entry->bColorCount <= colors) && (entry->bColorCount > maxcolors))
210         {
211             bestEntry = entry;
212             maxcolors = entry->bColorCount;
213         }
214     if (bestEntry) return bestEntry;
215
216     /* First find the exact size with more colors */
217
218     maxcolors = 255;
219     for (i = 0, entry = &dir->idEntries[0].icon; i < dir->idCount; i++,entry++)
220         if ((entry->bWidth == width) && (entry->bHeight == height) &&
221             (entry->bColorCount > colors) && (entry->bColorCount <= maxcolors))
222         {
223             bestEntry = entry;
224             maxcolors = entry->bColorCount;
225         }
226     if (bestEntry) return bestEntry;
227
228     /* Now find a smaller one with less colors */
229
230     maxcolors = maxwidth = maxheight = 0;
231     for (i = 0, entry = &dir->idEntries[0].icon; i < dir->idCount; i++,entry++)
232         if ((entry->bWidth <= width) && (entry->bHeight <= height) &&
233             (entry->bWidth >= maxwidth) && (entry->bHeight >= maxheight) &&
234             (entry->bColorCount <= colors) && (entry->bColorCount > maxcolors))
235         {
236             bestEntry = entry;
237             maxwidth  = entry->bWidth;
238             maxheight = entry->bHeight;
239             maxcolors = entry->bColorCount;
240         }
241     if (bestEntry) return bestEntry;
242
243     /* Now find a smaller one with more colors */
244
245     maxcolors = 255;
246     maxwidth = maxheight = 0;
247     for (i = 0, entry = &dir->idEntries[0].icon; i < dir->idCount; i++,entry++)
248         if ((entry->bWidth <= width) && (entry->bHeight <= height) &&
249             (entry->bWidth >= maxwidth) && (entry->bHeight >= maxheight) &&
250             (entry->bColorCount > colors) && (entry->bColorCount <= maxcolors))
251         {
252             bestEntry = entry;
253             maxwidth  = entry->bWidth;
254             maxheight = entry->bHeight;
255             maxcolors = entry->bColorCount;
256         }
257     if (bestEntry) return bestEntry;
258
259     /* Now find a larger one with less colors */
260
261     maxcolors = 0;
262     maxwidth = maxheight = 255;
263     for (i = 0, entry = &dir->idEntries[0].icon; i < dir->idCount; i++,entry++)
264         if ((entry->bWidth <= maxwidth) && (entry->bHeight <= maxheight) &&
265             (entry->bColorCount <= colors) && (entry->bColorCount > maxcolors))
266         {
267             bestEntry = entry;
268             maxwidth  = entry->bWidth;
269             maxheight = entry->bHeight;
270             maxcolors = entry->bColorCount;
271         }
272     if (bestEntry) return bestEntry;
273
274     /* Now find a larger one with more colors */
275
276     maxcolors = maxwidth = maxheight = 255;
277     for (i = 0, entry = &dir->idEntries[0].icon; i < dir->idCount; i++,entry++)
278         if ((entry->bWidth <= maxwidth) && (entry->bHeight <= maxheight) &&
279             (entry->bColorCount > colors) && (entry->bColorCount <= maxcolors))
280         {
281             bestEntry = entry;
282             maxwidth  = entry->bWidth;
283             maxheight = entry->bHeight;
284             maxcolors = entry->bColorCount;
285         }
286
287     return bestEntry;
288 }
289
290
291 /**********************************************************************
292  *          CURSORICON_FindBestCursor
293  *
294  * Find the cursor closest to the requested size.
295  * FIXME: parameter 'color' ignored and entries with more than 1 bpp
296  *        ignored too
297  */
298 static CURSORDIRENTRY *CURSORICON_FindBestCursor( CURSORICONDIR *dir,
299                                                   int width, int height, int color)
300 {
301     int i, maxwidth, maxheight;
302     CURSORDIRENTRY *entry, *bestEntry = NULL;
303
304     if (dir->idCount < 1)
305     {
306         WARN(cursor, "Empty directory!\n" );
307         return NULL;
308     }
309     if (dir->idCount == 1) return &dir->idEntries[0].cursor; /* No choice... */
310
311     /* First find the largest one smaller than or equal to the requested size*/
312
313     maxwidth = maxheight = 0;
314     for(i = 0,entry = &dir->idEntries[0].cursor; i < dir->idCount; i++,entry++)
315         if ((entry->wWidth <= width) && (entry->wHeight <= height) &&
316             (entry->wWidth > maxwidth) && (entry->wHeight > maxheight) &&
317             (entry->wBitCount == 1))
318         {
319             bestEntry = entry;
320             maxwidth  = entry->wWidth;
321             maxheight = entry->wHeight;
322         }
323     if (bestEntry) return bestEntry;
324
325     /* Now find the smallest one larger than the requested size */
326
327     maxwidth = maxheight = 255;
328     for(i = 0,entry = &dir->idEntries[0].cursor; i < dir->idCount; i++,entry++)
329         if ((entry->wWidth < maxwidth) && (entry->wHeight < maxheight) &&
330             (entry->wBitCount == 1))
331         {
332             bestEntry = entry;
333             maxwidth  = entry->wWidth;
334             maxheight = entry->wHeight;
335         }
336
337     return bestEntry;
338 }
339
340 /*********************************************************************
341  * The main purpose of this function is to create fake resource directory
342  * and fake resource entries. There are several reasons for this:
343  *      -       CURSORICONDIR and CURSORICONFILEDIR differ in sizes and their
344  *              fields
345  *      There are some "bad" cursor files which do not have
346  *              bColorCount initialized but instead one must read this info
347  *              directly from corresponding DIB sections
348  * Note: wResId is index to array of pointer returned in ptrs (origin is 1)
349  */
350 BOOL CURSORICON_SimulateLoadingFromResourceW( LPWSTR filename, BOOL fCursor,
351                                                 CURSORICONDIR **res, LPBYTE **ptr)
352 {
353     LPBYTE   _free;
354     CURSORICONFILEDIR *bits;
355     int      entries, size, i;
356
357     *res = NULL;
358     *ptr = NULL;
359     if (!(bits = (CURSORICONFILEDIR *)VIRTUAL_MapFileW( filename ))) return FALSE;
360
361     /* FIXME: test for inimated icons
362      * hack to load the first icon from the *.ani file
363      */
364     if ( *(LPDWORD)bits==0x46464952 ) /* "RIFF" */
365     { LPBYTE pos = (LPBYTE) bits;
366       FIXME (cursor,"Animated icons not correctly implemented! %p \n", bits);
367         
368       for (;;)
369       { if (*(LPDWORD)pos==0x6e6f6369)          /* "icon" */
370         { FIXME (cursor,"icon entry found! %p\n", bits);
371           pos+=4;
372           if ( !*(LPWORD) pos==0x2fe)           /* iconsize */
373           { goto fail;
374           }
375           bits+=2;
376           FIXME (cursor,"icon size ok %p \n", bits);
377           break;
378         }
379         pos+=2;
380         if (pos>=(LPBYTE)bits+766) goto fail;
381       }
382     }
383     if (!(entries = bits->idCount)) goto fail;
384     (int)_free = size = sizeof(CURSORICONDIR) + sizeof(CURSORICONDIRENTRY) * 
385                                                 (entries - 1);
386     for (i=0; i < entries; i++)
387       size += bits->idEntries[i].dwDIBSize + (fCursor ? sizeof(POINT16): 0);
388     
389     if (!(*ptr = HeapAlloc( GetProcessHeap(), 0,
390                             entries * sizeof (CURSORICONDIRENTRY*)))) goto fail;
391     if (!(*res = HeapAlloc( GetProcessHeap(), 0, size))) goto fail;
392
393     _free = (LPBYTE)(*res) + (int)_free;
394     memcpy((*res), bits, 6);
395     for (i=0; i<entries; i++)
396     {
397       ((LPBYTE*)(*ptr))[i] = _free;
398       if (fCursor) {
399         (*res)->idEntries[i].cursor.wWidth=bits->idEntries[i].bWidth;
400         (*res)->idEntries[i].cursor.wHeight=bits->idEntries[i].bHeight;
401         (*res)->idEntries[i].cursor.wPlanes=1;
402         (*res)->idEntries[i].cursor.wBitCount = ((LPBITMAPINFOHEADER)((LPBYTE)bits +
403                                                    bits->idEntries[i].dwDIBOffset))->biBitCount;
404         (*res)->idEntries[i].cursor.dwBytesInRes = bits->idEntries[i].dwDIBSize;
405         (*res)->idEntries[i].cursor.wResId=i+1;
406         ((LPPOINT16)_free)->x=bits->idEntries[i].xHotspot;
407         ((LPPOINT16)_free)->y=bits->idEntries[i].yHotspot;
408         _free+=sizeof(POINT16);
409       } else {
410         (*res)->idEntries[i].icon.bWidth=bits->idEntries[i].bWidth;
411         (*res)->idEntries[i].icon.bHeight=bits->idEntries[i].bHeight;
412         (*res)->idEntries[i].icon.bColorCount = bits->idEntries[i].bColorCount;
413         (*res)->idEntries[i].icon.wPlanes=1;
414         (*res)->idEntries[i].icon.wBitCount= ((LPBITMAPINFOHEADER)((LPBYTE)bits +
415                                              bits->idEntries[i].dwDIBOffset))->biBitCount;
416         (*res)->idEntries[i].icon.dwBytesInRes = bits->idEntries[i].dwDIBSize;
417         (*res)->idEntries[i].icon.wResId=i+1;
418       }
419       memcpy(_free,(LPBYTE)bits +bits->idEntries[i].dwDIBOffset,
420              (*res)->idEntries[i].icon.dwBytesInRes);
421       _free += (*res)->idEntries[i].icon.dwBytesInRes;
422     }
423     UnmapViewOfFile( bits );
424     return TRUE;    
425 fail:
426     if (*res) HeapFree( GetProcessHeap(), 0, *res );
427     if (*ptr) HeapFree( GetProcessHeap(), 0, *ptr );
428     UnmapViewOfFile( bits );
429     return FALSE;
430 }
431
432
433 /**********************************************************************
434  *          CURSORICON_CreateFromResource
435  *
436  * Create a cursor or icon from in-memory resource template. 
437  *
438  * FIXME: Convert to mono when cFlag is LR_MONOCHROME. Do something
439  *        with cbSize parameter as well.
440  */
441 static HGLOBAL16 CURSORICON_CreateFromResource( HINSTANCE16 hInstance, HGLOBAL16 hObj, LPBYTE bits,
442                                                 UINT cbSize, BOOL bIcon, DWORD dwVersion, 
443                                                 INT width, INT height, UINT loadflags )
444 {
445     int sizeAnd, sizeXor;
446     HBITMAP hAndBits = 0, hXorBits = 0; /* error condition for later */
447     BITMAPOBJ *bmpXor, *bmpAnd;
448     POINT16 hotspot = { 0 ,0 };
449     BITMAPINFO *bmi;
450     HDC hdc;
451     BOOL DoStretch;
452     INT size;
453
454     TRACE(cursor,"%08x (%u bytes), ver %08x, %ix%i %s %s\n",
455                         (unsigned)bits, cbSize, (unsigned)dwVersion, width, height,
456                                   bIcon ? "icon" : "cursor", (loadflags & LR_MONOCHROME) ? "mono" : "" );
457     if (dwVersion == 0x00020000)
458     {
459         FIXME(cursor,"\t2.xx resources are not supported\n");
460         return 0;
461     }
462
463     if (bIcon)
464         bmi = (BITMAPINFO *)bits;
465     else /* get the hotspot */
466     {
467         POINT16 *pt = (POINT16 *)bits;
468         hotspot = *pt;
469         bmi = (BITMAPINFO *)(pt + 1);
470     }
471     size = DIB_BitmapInfoSize( bmi, DIB_RGB_COLORS );
472
473     if (!width) width = bmi->bmiHeader.biWidth;
474     if (!height) height = bmi->bmiHeader.biHeight/2;
475     DoStretch = (bmi->bmiHeader.biHeight/2 != height) ||
476       (bmi->bmiHeader.biWidth != width);
477
478     /* Check bitmap header */
479
480     if ( (bmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) &&
481          (bmi->bmiHeader.biSize != sizeof(BITMAPINFOHEADER)  ||
482           bmi->bmiHeader.biCompression != BI_RGB) )
483     {
484           WARN(cursor,"\tinvalid resource bitmap header.\n");
485           return 0;
486     }
487
488     if( (hdc = GetDC( 0 )) )
489     {
490         BITMAPINFO* pInfo;
491
492         /* Make sure we have room for the monochrome bitmap later on.
493          * Note that BITMAPINFOINFO and BITMAPCOREHEADER are the same
494          * up to and including the biBitCount. In-memory icon resource 
495          * format is as follows:
496          *
497          *   BITMAPINFOHEADER   icHeader  // DIB header
498          *   RGBQUAD         icColors[]   // Color table
499          *   BYTE            icXOR[]      // DIB bits for XOR mask
500          *   BYTE            icAND[]      // DIB bits for AND mask
501          */
502
503         if ((pInfo = (BITMAPINFO *)HeapAlloc( GetProcessHeap(), 0, 
504           MAX(size, sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD)))))
505         {       
506             memcpy( pInfo, bmi, size ); 
507             pInfo->bmiHeader.biHeight /= 2;
508
509             /* Create the XOR bitmap */
510
511             if (DoStretch) {
512               if ((hXorBits = CreateCompatibleBitmap(hdc, width, height))) {
513                 HBITMAP hOld;
514                 HDC hMem = CreateCompatibleDC(hdc);
515                 BOOL res;
516
517                 if (hMem) {
518                   hOld = SelectObject(hMem, hXorBits);
519                   res = StretchDIBits(hMem, 0, 0, width, height, 0, 0,
520                     bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight/2,
521                     (char*)bmi + size, pInfo, DIB_RGB_COLORS, SRCCOPY);
522                   SelectObject(hMem, hOld);
523                   DeleteDC(hMem);
524                 } else res = FALSE;
525                 if (!res) { DeleteObject(hXorBits); hXorBits = 0; }
526               }
527             } else hXorBits = CreateDIBitmap( hdc, &pInfo->bmiHeader,
528                 CBM_INIT, (char*)bmi + size, pInfo, DIB_RGB_COLORS );
529             if( hXorBits )
530             {
531                 char* bits = (char *)bmi + size + bmi->bmiHeader.biHeight *
532                                 DIB_GetDIBWidthBytes(bmi->bmiHeader.biWidth,
533                                                      bmi->bmiHeader.biBitCount) / 2;
534
535                 pInfo->bmiHeader.biBitCount = 1;
536                 if (pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
537                 {
538                     RGBQUAD *rgb = pInfo->bmiColors;
539
540                     pInfo->bmiHeader.biClrUsed = pInfo->bmiHeader.biClrImportant = 2;
541                     rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00;
542                     rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff;
543                     rgb[0].rgbReserved = rgb[1].rgbReserved = 0;
544                 }
545                 else
546                 {
547                     RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)pInfo) + 1);
548
549                     rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00;
550                     rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff;
551                 }
552
553                 /* Create the AND bitmap */
554
555             if (DoStretch) {
556               if ((hAndBits = CreateBitmap(width, height, 1, 1, NULL))) {
557                 HBITMAP hOld;
558                 HDC hMem = CreateCompatibleDC(hdc);
559                 BOOL res;
560
561                 if (hMem) {
562                   hOld = SelectObject(hMem, hAndBits);
563                   res = StretchDIBits(hMem, 0, 0, width, height, 0, 0,
564                     pInfo->bmiHeader.biWidth, pInfo->bmiHeader.biHeight,
565                     bits, pInfo, DIB_RGB_COLORS, SRCCOPY);
566                   SelectObject(hMem, hOld);
567                   DeleteDC(hMem);
568                 } else res = FALSE;
569                 if (!res) { DeleteObject(hAndBits); hAndBits = 0; }
570               }
571             } else hAndBits = CreateDIBitmap( hdc, &pInfo->bmiHeader,
572               CBM_INIT, bits, pInfo, DIB_RGB_COLORS );
573
574                 if( !hAndBits ) DeleteObject( hXorBits );
575             }
576             HeapFree( GetProcessHeap(), 0, pInfo ); 
577         }
578         ReleaseDC( 0, hdc );
579     }
580
581     if( !hXorBits || !hAndBits ) 
582     {
583         WARN(cursor,"\tunable to create an icon bitmap.\n");
584         return 0;
585     }
586
587     /* Now create the CURSORICONINFO structure */
588     bmpXor = (BITMAPOBJ *) GDI_GetObjPtr( hXorBits, BITMAP_MAGIC );
589     bmpAnd = (BITMAPOBJ *) GDI_GetObjPtr( hAndBits, BITMAP_MAGIC );
590     sizeXor = bmpXor->bitmap.bmHeight * bmpXor->bitmap.bmWidthBytes;
591     sizeAnd = bmpAnd->bitmap.bmHeight * bmpAnd->bitmap.bmWidthBytes;
592
593     if (hObj) hObj = GlobalReAlloc16( hObj, 
594                      sizeof(CURSORICONINFO) + sizeXor + sizeAnd, GMEM_MOVEABLE );
595     if (!hObj) hObj = GlobalAlloc16( GMEM_MOVEABLE, 
596                      sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
597     if (hObj)
598     {
599         CURSORICONINFO *info;
600
601         /* Make it owned by the module */
602         if (hInstance) FarSetOwner16( hObj, GetExePtr(hInstance) );
603
604         info = (CURSORICONINFO *)GlobalLock16( hObj );
605         info->ptHotSpot.x   = hotspot.x;
606         info->ptHotSpot.y   = hotspot.y;
607         info->nWidth        = bmpXor->bitmap.bmWidth;
608         info->nHeight       = bmpXor->bitmap.bmHeight;
609         info->nWidthBytes   = bmpXor->bitmap.bmWidthBytes;
610         info->bPlanes       = bmpXor->bitmap.bmPlanes;
611         info->bBitsPerPixel = bmpXor->bitmap.bmBitsPixel;
612
613         /* Transfer the bitmap bits to the CURSORICONINFO structure */
614
615         GetBitmapBits( hAndBits, sizeAnd, (char *)(info + 1) );
616         GetBitmapBits( hXorBits, sizeXor, (char *)(info + 1) + sizeAnd );
617         GlobalUnlock16( hObj );
618     }
619
620     DeleteObject( hXorBits );
621     DeleteObject( hAndBits );
622     return hObj;
623 }
624
625
626 /**********************************************************************
627  *          CreateIconFromResourceEx16          (USER.450)
628  *
629  * FIXME: not sure about exact parameter types
630  */
631 HICON16 WINAPI CreateIconFromResourceEx16( LPBYTE bits, UINT16 cbSize, BOOL16 bIcon,
632                                     DWORD dwVersion, INT16 width, INT16 height, UINT16 cFlag )
633 {
634     return CreateIconFromResourceEx(bits, cbSize, bIcon, dwVersion, 
635       width, height, cFlag);
636 }
637
638
639 /**********************************************************************
640  *          CreateIconFromResource          (USER32.76)
641  */
642 HICON WINAPI CreateIconFromResource( LPBYTE bits, UINT cbSize,
643                                            BOOL bIcon, DWORD dwVersion)
644 {
645     return CreateIconFromResourceEx( bits, cbSize, bIcon, dwVersion, 0,0,0);
646 }
647
648
649 /**********************************************************************
650  *          CreateIconFromResourceEx32          (USER32.77)
651  */
652 HICON WINAPI CreateIconFromResourceEx( LPBYTE bits, UINT cbSize,
653                                            BOOL bIcon, DWORD dwVersion,
654                                            INT width, INT height,
655                                            UINT cFlag )
656 {
657     TDB* pTask = (TDB*)GlobalLock16( GetCurrentTask() );
658     if( pTask )
659         return CURSORICON_CreateFromResource( pTask->hInstance, 0, bits, cbSize, bIcon, dwVersion,
660                                               width, height, cFlag );
661     return 0;
662 }
663
664 /**********************************************************************
665  *          CURSORICON_Load
666  *
667  * Load a cursor or icon from resource or file.
668  */
669 HGLOBAL CURSORICON_Load( HINSTANCE hInstance, LPCWSTR name,
670                          INT width, INT height, INT colors,
671                          BOOL fCursor, UINT loadflags )
672 {
673     HANDLE handle = 0, h = 0;
674     HANDLE hRsrc;
675     CURSORICONDIR *dir;
676     CURSORICONDIRENTRY *dirEntry;
677     LPBYTE bits;
678
679     if ( loadflags & LR_LOADFROMFILE )    /* Load from file */
680     {
681         LPBYTE *ptr;
682         if (!CURSORICON_SimulateLoadingFromResourceW((LPWSTR)name, fCursor, &dir, &ptr))
683             return 0;
684         if (fCursor)
685             dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor(dir, width, height, 1);
686         else
687             dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon(dir, width, height, colors);
688         bits = ptr[dirEntry->icon.wResId-1];
689         h = CURSORICON_CreateFromResource( 0, 0, bits, dirEntry->icon.dwBytesInRes, 
690                                            !fCursor, 0x00030000, width, height, loadflags);
691         HeapFree( GetProcessHeap(), 0, dir );
692         HeapFree( GetProcessHeap(), 0, ptr );
693     }
694
695     else if ( !hInstance )  /* Load OEM cursor/icon */
696     {
697         WORD resid;
698         HDC hdc;
699         DC *dc;
700
701         if ( HIWORD(name) )
702         {
703             LPSTR ansi = HEAP_strdupWtoA(GetProcessHeap(),0,name);
704             if( ansi[0]=='#')        /*Check for '#xxx' name */
705             {
706                 resid = atoi(ansi+1);
707                 HeapFree( GetProcessHeap(), 0, ansi );
708             }
709             else
710             {
711                 HeapFree( GetProcessHeap(), 0, ansi );
712                 return 0;
713             }
714         }
715         else resid = LOWORD(name);
716         hdc = CreateDCA( "DISPLAY", NULL, NULL, NULL );
717         dc = DC_GetDCPtr( hdc );
718         if (dc->funcs->pLoadOEMResource)
719             h = dc->funcs->pLoadOEMResource( resid, fCursor ?
720                                                     OEM_CURSOR : OEM_ICON );
721         GDI_HEAP_UNLOCK( hdc );
722         DeleteDC(  hdc );
723     }
724
725     else  /* Load from resource */
726     {
727         WORD wResId;
728         DWORD dwBytesInRes;
729
730         /* Normalize hInstance (must be uniquely represented for icon cache) */
731         
732         if ( HIWORD( hInstance ) )
733             hInstance = MapHModuleLS( hInstance );
734         else
735             hInstance = GetExePtr( hInstance );
736
737         /* Get directory resource ID */
738
739         if (!(hRsrc = FindResourceW( hInstance, name,
740                           fCursor ? RT_GROUP_CURSORW : RT_GROUP_ICONW )))
741             return 0;
742
743         /* If shared icon, check whether it was already loaded */
744
745         if (    (loadflags & LR_SHARED) 
746              && (h = CURSORICON_FindSharedIcon( hInstance, hRsrc ) ) != 0 )
747             return h;
748
749         /* Find the best entry in the directory */
750  
751         if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
752         if (!(dir = (CURSORICONDIR*)LockResource( handle ))) return 0;
753         if (fCursor)
754             dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor( dir,
755                                                               width, height, 1);
756         else
757             dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon( dir,
758                                                        width, height, colors );
759         if (!dirEntry) return 0;
760         wResId = dirEntry->icon.wResId;
761         dwBytesInRes = dirEntry->icon.dwBytesInRes;
762         FreeResource( handle );
763
764         /* Load the resource */
765
766         if (!(hRsrc = FindResourceW(hInstance,MAKEINTRESOURCEW(wResId),
767                                       fCursor ? RT_CURSORW : RT_ICONW ))) return 0;
768         if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
769         bits = (LPBYTE)LockResource( handle );
770         h = CURSORICON_CreateFromResource( 0, 0, bits, dwBytesInRes, 
771                                            !fCursor, 0x00030000, width, height, loadflags);
772         FreeResource( handle );
773
774         /* If shared icon, add to icon cache */
775
776         if ( h && (loadflags & LR_SHARED) )
777             CURSORICON_AddSharedIcon( hInstance, hRsrc, h );
778     }
779
780     return h;
781 }
782
783 /***********************************************************************
784  *           CURSORICON_Copy
785  *
786  * Make a copy of a cursor or icon.
787  */
788 static HGLOBAL16 CURSORICON_Copy( HINSTANCE16 hInstance, HGLOBAL16 handle )
789 {
790     char *ptrOld, *ptrNew;
791     int size;
792     HGLOBAL16 hNew;
793
794     if (!(ptrOld = (char *)GlobalLock16( handle ))) return 0;
795     if (!(hInstance = GetExePtr( hInstance ))) return 0;
796     size = GlobalSize16( handle );
797     hNew = GlobalAlloc16( GMEM_MOVEABLE, size );
798     FarSetOwner16( hNew, hInstance );
799     ptrNew = (char *)GlobalLock16( hNew );
800     memcpy( ptrNew, ptrOld, size );
801     GlobalUnlock16( handle );
802     GlobalUnlock16( hNew );
803     return hNew;
804 }
805
806 /***********************************************************************
807  *           CURSORICON_IconToCursor
808  *
809  * Converts bitmap to mono and truncates if icon is too large (should
810  * probably do StretchBlt() instead).
811  */
812 HCURSOR16 CURSORICON_IconToCursor(HICON16 hIcon, BOOL bSemiTransparent)
813 {
814  HCURSOR16       hRet = 0;
815  CURSORICONINFO *pIcon = NULL;
816  HTASK16         hTask = GetCurrentTask();
817  TDB*            pTask = (TDB *)GlobalLock16(hTask);
818
819  if(hIcon && pTask)
820     if (!(pIcon = (CURSORICONINFO*)GlobalLock16( hIcon ))) return FALSE;
821        if (pIcon->bPlanes * pIcon->bBitsPerPixel == 1)
822            hRet = CURSORICON_Copy( pTask->hInstance, hIcon );
823        else
824        {
825            BYTE  pAndBits[128];
826            BYTE  pXorBits[128];
827            int   maxx, maxy, ix, iy, bpp = pIcon->bBitsPerPixel;
828            BYTE* psPtr, *pxbPtr = pXorBits;
829            unsigned xor_width, and_width, val_base = 0xffffffff >> (32 - bpp);
830            BYTE* pbc = NULL;
831
832            CURSORICONINFO cI;
833
834            TRACE(icon, "[%04x] %ix%i %ibpp (bogus %ibps)\n", 
835                 hIcon, pIcon->nWidth, pIcon->nHeight, pIcon->bBitsPerPixel, pIcon->nWidthBytes );
836
837            xor_width = BITMAP_GetWidthBytes( pIcon->nWidth, bpp );
838            and_width = BITMAP_GetWidthBytes( pIcon->nWidth, 1 );
839            psPtr = (BYTE *)(pIcon + 1) + pIcon->nHeight * and_width;
840
841            memset(pXorBits, 0, 128);
842            cI.bBitsPerPixel = 1; cI.bPlanes = 1;
843            cI.ptHotSpot.x = cI.ptHotSpot.y = 15;
844            cI.nWidth = 32; cI.nHeight = 32;
845            cI.nWidthBytes = 4;  /* 32x1bpp */
846
847            maxx = (pIcon->nWidth > 32) ? 32 : pIcon->nWidth;
848            maxy = (pIcon->nHeight > 32) ? 32 : pIcon->nHeight;
849
850            for( iy = 0; iy < maxy; iy++ )
851            {
852               unsigned shift = iy % 2; 
853
854               memcpy( pAndBits + iy * 4, (BYTE *)(pIcon + 1) + iy * and_width, 
855                                          (and_width > 4) ? 4 : and_width );
856               for( ix = 0; ix < maxx; ix++ )
857               {
858                 if( bSemiTransparent && ((ix+shift)%2) )
859                 {
860                     /* set AND bit, XOR bit stays 0 */
861
862                     pbc = pAndBits + iy * 4 + ix/8;
863                    *pbc |= 0x80 >> (ix%8);
864                 }
865                 else
866                 {
867                     /* keep AND bit, set XOR bit */
868
869                   unsigned *psc = (unsigned*)(psPtr + (ix * bpp)/8);
870                   unsigned  val = ((*psc) >> (ix * bpp)%8) & val_base;
871                   if(!PALETTE_Driver->pIsDark(val))
872                   {
873                     pbc = pxbPtr + ix/8;
874                    *pbc |= 0x80 >> (ix%8);
875                   }
876                 }
877               }
878               psPtr += xor_width;
879               pxbPtr += 4;
880            }
881
882            hRet = CreateCursorIconIndirect16( pTask->hInstance , &cI, pAndBits, pXorBits);
883
884            if( !hRet ) /* fall back on default drag cursor */
885                 hRet = CURSORICON_Copy( pTask->hInstance ,
886                               CURSORICON_Load(0,MAKEINTRESOURCEW(OCR_DRAGOBJECT),
887                                          SYSMETRICS_CXCURSOR, SYSMETRICS_CYCURSOR, 1, TRUE, 0) );
888        }
889
890  return hRet;
891 }
892
893
894 /***********************************************************************
895  *           LoadCursor16    (USER.173)
896  */
897 HCURSOR16 WINAPI LoadCursor16( HINSTANCE16 hInstance, SEGPTR name )
898 {
899     LPCSTR nameStr = HIWORD(name)? PTR_SEG_TO_LIN(name) : (LPCSTR)name;
900     return LoadCursorA( hInstance, nameStr );
901 }
902
903
904 /***********************************************************************
905  *           LoadIcon16    (USER.174)
906  */
907 HICON16 WINAPI LoadIcon16( HINSTANCE16 hInstance, SEGPTR name )
908 {
909     LPCSTR nameStr = HIWORD(name)? PTR_SEG_TO_LIN(name) : (LPCSTR)name;
910     return LoadIconA( hInstance, nameStr );
911 }
912
913
914 /***********************************************************************
915  *           CreateCursor16    (USER.406)
916  */
917 HCURSOR16 WINAPI CreateCursor16( HINSTANCE16 hInstance,
918                                  INT16 xHotSpot, INT16 yHotSpot,
919                                  INT16 nWidth, INT16 nHeight,
920                                  LPCVOID lpANDbits, LPCVOID lpXORbits )
921 {
922     CURSORICONINFO info = { { xHotSpot, yHotSpot }, nWidth, nHeight, 0, 1, 1 };
923
924     TRACE(cursor, "%dx%d spot=%d,%d xor=%p and=%p\n",
925                     nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits);
926     return CreateCursorIconIndirect16( hInstance, &info, lpANDbits, lpXORbits );
927 }
928
929
930 /***********************************************************************
931  *           CreateCursor32    (USER32.67)
932  */
933 HCURSOR WINAPI CreateCursor( HINSTANCE hInstance,
934                                  INT xHotSpot, INT yHotSpot,
935                                  INT nWidth, INT nHeight,
936                                  LPCVOID lpANDbits, LPCVOID lpXORbits )
937 {
938     CURSORICONINFO info = { { xHotSpot, yHotSpot }, nWidth, nHeight, 0, 1, 1 };
939
940     TRACE(cursor, "%dx%d spot=%d,%d xor=%p and=%p\n",
941                     nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits);
942     return CreateCursorIconIndirect16( 0, &info, lpANDbits, lpXORbits );
943 }
944
945
946 /***********************************************************************
947  *           CreateIcon16    (USER.407)
948  */
949 HICON16 WINAPI CreateIcon16( HINSTANCE16 hInstance, INT16 nWidth,
950                              INT16 nHeight, BYTE bPlanes, BYTE bBitsPixel,
951                              LPCVOID lpANDbits, LPCVOID lpXORbits )
952 {
953     CURSORICONINFO info = { { 0, 0 }, nWidth, nHeight, 0, bPlanes, bBitsPixel};
954
955     TRACE(icon, "%dx%dx%d, xor=%p, and=%p\n",
956                   nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits);
957     return CreateCursorIconIndirect16( hInstance, &info, lpANDbits, lpXORbits );
958 }
959
960
961 /***********************************************************************
962  *           CreateIcon32    (USER32.75)
963  */
964 HICON WINAPI CreateIcon( HINSTANCE hInstance, INT nWidth,
965                              INT nHeight, BYTE bPlanes, BYTE bBitsPixel,
966                              LPCVOID lpANDbits, LPCVOID lpXORbits )
967 {
968     CURSORICONINFO info = { { 0, 0 }, nWidth, nHeight, 0, bPlanes, bBitsPixel};
969
970     TRACE(icon, "%dx%dx%d, xor=%p, and=%p\n",
971                   nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits);
972     return CreateCursorIconIndirect16( 0, &info, lpANDbits, lpXORbits );
973 }
974
975
976 /***********************************************************************
977  *           CreateCursorIconIndirect    (USER.408)
978  */
979 HGLOBAL16 WINAPI CreateCursorIconIndirect16( HINSTANCE16 hInstance,
980                                            CURSORICONINFO *info,
981                                            LPCVOID lpANDbits,
982                                            LPCVOID lpXORbits )
983 {
984     HGLOBAL16 handle;
985     char *ptr;
986     int sizeAnd, sizeXor;
987
988     hInstance = GetExePtr( hInstance );  /* Make it a module handle */
989     if (!lpXORbits || !lpANDbits || info->bPlanes != 1) return 0;
990     info->nWidthBytes = BITMAP_GetWidthBytes(info->nWidth,info->bBitsPerPixel);
991     sizeXor = info->nHeight * info->nWidthBytes;
992     sizeAnd = info->nHeight * BITMAP_GetWidthBytes( info->nWidth, 1 );
993     if (!(handle = GlobalAlloc16( GMEM_MOVEABLE,
994                                   sizeof(CURSORICONINFO) + sizeXor + sizeAnd)))
995         return 0;
996     if (hInstance) FarSetOwner16( handle, hInstance );
997     ptr = (char *)GlobalLock16( handle );
998     memcpy( ptr, info, sizeof(*info) );
999     memcpy( ptr + sizeof(CURSORICONINFO), lpANDbits, sizeAnd );
1000     memcpy( ptr + sizeof(CURSORICONINFO) + sizeAnd, lpXORbits, sizeXor );
1001     GlobalUnlock16( handle );
1002     return handle;
1003 }
1004
1005
1006 /***********************************************************************
1007  *           CopyIcon16    (USER.368)
1008  */
1009 HICON16 WINAPI CopyIcon16( HINSTANCE16 hInstance, HICON16 hIcon )
1010 {
1011     TRACE(icon, "%04x %04x\n", hInstance, hIcon );
1012     return CURSORICON_Copy( hInstance, hIcon );
1013 }
1014
1015
1016 /***********************************************************************
1017  *           CopyIcon32    (USER32.60)
1018  */
1019 HICON WINAPI CopyIcon( HICON hIcon )
1020 {
1021   HTASK16 hTask = GetCurrentTask ();
1022   TDB* pTask = (TDB *) GlobalLock16 (hTask);
1023     TRACE(icon, "%04x\n", hIcon );
1024   return CURSORICON_Copy( pTask->hInstance, hIcon );
1025 }
1026
1027
1028 /***********************************************************************
1029  *           CopyCursor16    (USER.369)
1030  */
1031 HCURSOR16 WINAPI CopyCursor16( HINSTANCE16 hInstance, HCURSOR16 hCursor )
1032 {
1033     TRACE(cursor, "%04x %04x\n", hInstance, hCursor );
1034     return CURSORICON_Copy( hInstance, hCursor );
1035 }
1036
1037 /**********************************************************************
1038  *          CURSORICON_Destroy   (USER.610)
1039  *
1040  * This routine is actually exported from Win95 USER under the name
1041  * DestroyIcon32 ...  The behaviour implemented here should mimic 
1042  * the Win95 one exactly, especially the return values, which 
1043  * depend on the setting of various flags.
1044  */
1045 WORD WINAPI CURSORICON_Destroy( HGLOBAL16 handle, UINT16 flags )
1046 {
1047     WORD retv;
1048
1049     TRACE( icon, "(%04x, %04x)\n", handle, flags );
1050
1051     /* Check whether destroying active cursor */
1052
1053     if ( hActiveCursor == handle )
1054     {
1055         ERR( cursor, "Destroying active cursor!\n" );
1056         SetCursor( 0 );
1057     }
1058
1059     /* Try shared cursor/icon first */
1060
1061     if ( !(flags & CID_NONSHARED) )
1062     {
1063         INT count = CURSORICON_DelSharedIcon( handle );
1064
1065         if ( count != -1 )
1066             return (flags & CID_WIN32)? TRUE : (count == 0);
1067
1068         /* FIXME: OEM cursors/icons should be recognized */
1069     }
1070
1071     /* Now assume non-shared cursor/icon */
1072
1073     retv = GlobalFree16( handle );
1074     return (flags & CID_RESOURCE)? retv : TRUE;
1075 }
1076
1077 /***********************************************************************
1078  *           DestroyIcon16    (USER.457)
1079  */
1080 BOOL16 WINAPI DestroyIcon16( HICON16 hIcon )
1081 {
1082     return CURSORICON_Destroy( hIcon, 0 );
1083 }
1084
1085 /***********************************************************************
1086  *           DestroyIcon      (USER32.133)
1087  */
1088 BOOL WINAPI DestroyIcon( HICON hIcon )
1089 {
1090     return CURSORICON_Destroy( hIcon, CID_WIN32 );
1091 }
1092
1093 /***********************************************************************
1094  *           DestroyCursor16  (USER.458)
1095  */
1096 BOOL16 WINAPI DestroyCursor16( HCURSOR16 hCursor )
1097 {
1098     return CURSORICON_Destroy( hCursor, 0 );
1099 }
1100
1101 /***********************************************************************
1102  *           DestroyCursor    (USER32.132)
1103  */
1104 BOOL WINAPI DestroyCursor( HCURSOR hCursor )
1105 {
1106     return CURSORICON_Destroy( hCursor, CID_WIN32 );
1107 }
1108
1109
1110 /***********************************************************************
1111  *           DrawIcon16    (USER.84)
1112  */
1113 BOOL16 WINAPI DrawIcon16( HDC16 hdc, INT16 x, INT16 y, HICON16 hIcon )
1114 {
1115     return DrawIcon( hdc, x, y, hIcon );
1116 }
1117
1118
1119 /***********************************************************************
1120  *           DrawIcon32    (USER32.159)
1121  */
1122 BOOL WINAPI DrawIcon( HDC hdc, INT x, INT y, HICON hIcon )
1123 {
1124     CURSORICONINFO *ptr;
1125     HDC hMemDC;
1126     HBITMAP hXorBits, hAndBits;
1127     COLORREF oldFg, oldBg;
1128
1129     if (!(ptr = (CURSORICONINFO *)GlobalLock16( hIcon ))) return FALSE;
1130     if (!(hMemDC = CreateCompatibleDC( hdc ))) return FALSE;
1131     hAndBits = CreateBitmap( ptr->nWidth, ptr->nHeight, 1, 1,
1132                                (char *)(ptr+1) );
1133     hXorBits = CreateBitmap( ptr->nWidth, ptr->nHeight, ptr->bPlanes,
1134                                ptr->bBitsPerPixel, (char *)(ptr + 1)
1135                         + ptr->nHeight * BITMAP_GetWidthBytes(ptr->nWidth,1) );
1136     oldFg = SetTextColor( hdc, RGB(0,0,0) );
1137     oldBg = SetBkColor( hdc, RGB(255,255,255) );
1138
1139     if (hXorBits && hAndBits)
1140     {
1141         HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
1142         BitBlt( hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0, SRCAND );
1143         SelectObject( hMemDC, hXorBits );
1144         BitBlt(hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0,SRCINVERT);
1145         SelectObject( hMemDC, hBitTemp );
1146     }
1147     DeleteDC( hMemDC );
1148     if (hXorBits) DeleteObject( hXorBits );
1149     if (hAndBits) DeleteObject( hAndBits );
1150     GlobalUnlock16( hIcon );
1151     SetTextColor( hdc, oldFg );
1152     SetBkColor( hdc, oldBg );
1153     return TRUE;
1154 }
1155
1156
1157 /***********************************************************************
1158  *           DumpIcon    (USER.459)
1159  */
1160 DWORD WINAPI DumpIcon16( SEGPTR pInfo, WORD *lpLen,
1161                        SEGPTR *lpXorBits, SEGPTR *lpAndBits )
1162 {
1163     CURSORICONINFO *info = PTR_SEG_TO_LIN( pInfo );
1164     int sizeAnd, sizeXor;
1165
1166     if (!info) return 0;
1167     sizeXor = info->nHeight * info->nWidthBytes;
1168     sizeAnd = info->nHeight * BITMAP_GetWidthBytes( info->nWidth, 1 );
1169     if (lpAndBits) *lpAndBits = pInfo + sizeof(CURSORICONINFO);
1170     if (lpXorBits) *lpXorBits = pInfo + sizeof(CURSORICONINFO) + sizeAnd;
1171     if (lpLen) *lpLen = sizeof(CURSORICONINFO) + sizeAnd + sizeXor;
1172     return MAKELONG( sizeXor, sizeXor );
1173 }
1174
1175
1176 /***********************************************************************
1177  *           SetCursor16    (USER.69)
1178  */
1179 HCURSOR16 WINAPI SetCursor16( HCURSOR16 hCursor )
1180 {
1181     return (HCURSOR16)SetCursor( hCursor );
1182 }
1183
1184
1185 /***********************************************************************
1186  *           SetCursor32    (USER32.472)
1187  * RETURNS:
1188  *      A handle to the previous cursor shape.
1189  */
1190 HCURSOR WINAPI SetCursor(
1191                  HCURSOR hCursor /* Handle of cursor to show */
1192 ) {
1193     HCURSOR hOldCursor;
1194
1195     if (hCursor == hActiveCursor) return hActiveCursor;  /* No change */
1196     TRACE(cursor, "%04x\n", hCursor );
1197     hOldCursor = hActiveCursor;
1198     hActiveCursor = hCursor;
1199     /* Change the cursor shape only if it is visible */
1200     if (CURSOR_ShowCount >= 0)
1201     {
1202         DISPLAY_SetCursor( (CURSORICONINFO*)GlobalLock16( hActiveCursor ) );
1203         GlobalUnlock16( hActiveCursor );
1204     }
1205     return hOldCursor;
1206 }
1207
1208
1209 /***********************************************************************
1210  *           SetCursorPos16    (USER.70)
1211  */
1212 void WINAPI SetCursorPos16( INT16 x, INT16 y )
1213 {
1214     SetCursorPos( x, y );
1215 }
1216
1217
1218 /***********************************************************************
1219  *           SetCursorPos32    (USER32.474)
1220  */
1221 BOOL WINAPI SetCursorPos( INT x, INT y )
1222 {
1223     DISPLAY_MoveCursor( x, y );
1224     return TRUE;
1225 }
1226
1227
1228 /***********************************************************************
1229  *           ShowCursor16    (USER.71)
1230  */
1231 INT16 WINAPI ShowCursor16( BOOL16 bShow )
1232 {
1233     return ShowCursor( bShow );
1234 }
1235
1236
1237 /***********************************************************************
1238  *           ShowCursor32    (USER32.530)
1239  */
1240 INT WINAPI ShowCursor( BOOL bShow )
1241 {
1242     TRACE(cursor, "%d, count=%d\n",
1243                     bShow, CURSOR_ShowCount );
1244
1245     if (bShow)
1246     {
1247         if (++CURSOR_ShowCount == 0)  /* Show it */
1248         {
1249             DISPLAY_SetCursor((CURSORICONINFO*)GlobalLock16( hActiveCursor ));
1250             GlobalUnlock16( hActiveCursor );
1251         }
1252     }
1253     else
1254     {
1255         if (--CURSOR_ShowCount == -1)  /* Hide it */
1256             DISPLAY_SetCursor( NULL );
1257     }
1258     return CURSOR_ShowCount;
1259 }
1260
1261
1262 /***********************************************************************
1263  *           GetCursor16    (USER.247)
1264  */
1265 HCURSOR16 WINAPI GetCursor16(void)
1266 {
1267     return hActiveCursor;
1268 }
1269
1270
1271 /***********************************************************************
1272  *           GetCursor32    (USER32.227)
1273  */
1274 HCURSOR WINAPI GetCursor(void)
1275 {
1276     return hActiveCursor;
1277 }
1278
1279
1280 /***********************************************************************
1281  *           ClipCursor16    (USER.16)
1282  */
1283 BOOL16 WINAPI ClipCursor16( const RECT16 *rect )
1284 {
1285     if (!rect) SetRectEmpty( &CURSOR_ClipRect );
1286     else CONV_RECT16TO32( rect, &CURSOR_ClipRect );
1287     return TRUE;
1288 }
1289
1290
1291 /***********************************************************************
1292  *           ClipCursor32    (USER32.53)
1293  */
1294 BOOL WINAPI ClipCursor( const RECT *rect )
1295 {
1296     if (!rect) SetRectEmpty( &CURSOR_ClipRect );
1297     else CopyRect( &CURSOR_ClipRect, rect );
1298     return TRUE;
1299 }
1300
1301
1302 /***********************************************************************
1303  *           GetCursorPos16    (USER.17)
1304  */
1305 BOOL16 WINAPI GetCursorPos16( POINT16 *pt )
1306 {
1307     DWORD posX, posY, state;
1308
1309     if (!pt) return 0;
1310     if (!EVENT_QueryPointer( &posX, &posY, &state ))
1311         pt->x = pt->y = 0;
1312     else
1313     {
1314         pt->x = posX;
1315         pt->y = posY;
1316         if (state & MK_LBUTTON)
1317             AsyncMouseButtonsStates[0] = MouseButtonsStates[0] = TRUE;
1318         else
1319             MouseButtonsStates[0] = FALSE;
1320         if (state & MK_MBUTTON)
1321             AsyncMouseButtonsStates[1] = MouseButtonsStates[1] = TRUE;
1322         else       
1323             MouseButtonsStates[1] = FALSE;
1324         if (state & MK_RBUTTON)
1325             AsyncMouseButtonsStates[2] = MouseButtonsStates[2] = TRUE;
1326         else
1327             MouseButtonsStates[2] = FALSE;
1328     }
1329     TRACE(cursor, "ret=%d,%d\n", pt->x, pt->y );
1330     return 1;
1331 }
1332
1333
1334 /***********************************************************************
1335  *           GetCursorPos32    (USER32.229)
1336  */
1337 BOOL WINAPI GetCursorPos( POINT *pt )
1338 {
1339     BOOL ret;
1340
1341     POINT16 pt16;
1342     ret = GetCursorPos16( &pt16 );
1343     if (pt) CONV_POINT16TO32( &pt16, pt );
1344     return ((pt) ? ret : 0);
1345 }
1346
1347
1348 /***********************************************************************
1349  *           GetClipCursor16    (USER.309)
1350  */
1351 void WINAPI GetClipCursor16( RECT16 *rect )
1352 {
1353     if (rect) CONV_RECT32TO16( &CURSOR_ClipRect, rect );
1354 }
1355
1356
1357 /***********************************************************************
1358  *           GetClipCursor32    (USER32.221)
1359  */
1360 BOOL WINAPI GetClipCursor( RECT *rect )
1361 {
1362     if (rect) 
1363     {
1364        CopyRect( rect, &CURSOR_ClipRect );
1365        return TRUE;
1366     }
1367     return FALSE;
1368 }
1369
1370 /**********************************************************************
1371  *          LookupIconIdFromDirectoryEx16       (USER.364)
1372  *
1373  * FIXME: exact parameter sizes
1374  */
1375 INT16 WINAPI LookupIconIdFromDirectoryEx16( LPBYTE xdir, BOOL16 bIcon,
1376              INT16 width, INT16 height, UINT16 cFlag )
1377 {
1378     CURSORICONDIR       *dir = (CURSORICONDIR*)xdir;
1379     UINT16 retVal = 0;
1380     if( dir && !dir->idReserved && (dir->idType & 3) )
1381     {
1382         HDC hdc = GetDC(0);
1383         UINT palEnts = GetSystemPaletteEntries(hdc, 0, 0, NULL);
1384         int colors = (cFlag & LR_MONOCHROME) ? 2 : palEnts;
1385         ReleaseDC(0, hdc);
1386
1387         if( bIcon )
1388         {
1389             ICONDIRENTRY* entry;
1390             entry = CURSORICON_FindBestIcon( dir, width, height, colors );
1391             if( entry ) retVal = entry->wResId;
1392         }
1393         else
1394         {
1395             CURSORDIRENTRY* entry;
1396             entry = CURSORICON_FindBestCursor( dir, width, height, 1);
1397             if( entry ) retVal = entry->wResId;
1398         }
1399     }
1400     else WARN(cursor, "invalid resource directory\n");
1401     return retVal;
1402 }
1403
1404 /**********************************************************************
1405  *          LookupIconIdFromDirectoryEx32       (USER32.380)
1406  */
1407 INT WINAPI LookupIconIdFromDirectoryEx( LPBYTE dir, BOOL bIcon,
1408              INT width, INT height, UINT cFlag )
1409 {
1410     return LookupIconIdFromDirectoryEx16( dir, bIcon, width, height, cFlag );
1411 }
1412
1413 /**********************************************************************
1414  *          LookupIconIdFromDirectory           (USER.???)
1415  */
1416 INT16 WINAPI LookupIconIdFromDirectory16( LPBYTE dir, BOOL16 bIcon )
1417 {
1418     return LookupIconIdFromDirectoryEx16( dir, bIcon, 
1419            bIcon ? SYSMETRICS_CXICON : SYSMETRICS_CXCURSOR,
1420            bIcon ? SYSMETRICS_CYICON : SYSMETRICS_CYCURSOR, bIcon ? 0 : LR_MONOCHROME );
1421 }
1422
1423 /**********************************************************************
1424  *          LookupIconIdFromDirectory           (USER32.379)
1425  */
1426 INT WINAPI LookupIconIdFromDirectory( LPBYTE dir, BOOL bIcon )
1427 {
1428     return LookupIconIdFromDirectoryEx( dir, bIcon, 
1429            bIcon ? SYSMETRICS_CXICON : SYSMETRICS_CXCURSOR,
1430            bIcon ? SYSMETRICS_CYICON : SYSMETRICS_CYCURSOR, bIcon ? 0 : LR_MONOCHROME );
1431 }
1432
1433 /**********************************************************************
1434  *          GetIconID    (USER.455)
1435  */
1436 WORD WINAPI GetIconID16( HGLOBAL16 hResource, DWORD resType )
1437 {
1438     LPBYTE lpDir = (LPBYTE)GlobalLock16(hResource);
1439
1440     TRACE(cursor, "hRes=%04x, entries=%i\n",
1441                     hResource, lpDir ? ((CURSORICONDIR*)lpDir)->idCount : 0);
1442
1443     switch(resType)
1444     {
1445         case RT_CURSOR16:
1446              return (WORD)LookupIconIdFromDirectoryEx16( lpDir, FALSE, 
1447                           SYSMETRICS_CXCURSOR, SYSMETRICS_CYCURSOR, LR_MONOCHROME );
1448         case RT_ICON16:
1449              return (WORD)LookupIconIdFromDirectoryEx16( lpDir, TRUE,
1450                           SYSMETRICS_CXICON, SYSMETRICS_CYICON, 0 );
1451         default:
1452              WARN(cursor, "invalid res type %ld\n", resType );
1453     }
1454     return 0;
1455 }
1456
1457 /**********************************************************************
1458  *          LoadCursorIconHandler    (USER.336)
1459  *
1460  * Supposed to load resources of Windows 2.x applications.
1461  */
1462 HGLOBAL16 WINAPI LoadCursorIconHandler16( HGLOBAL16 hResource, HMODULE16 hModule, HRSRC16 hRsrc )
1463 {
1464     FIXME(cursor,"(%04x,%04x,%04x): old 2.x resources are not supported!\n", 
1465           hResource, hModule, hRsrc);
1466     return (HGLOBAL16)0;
1467 }
1468
1469 /**********************************************************************
1470  *          LoadDIBIconHandler    (USER.357)
1471  * 
1472  * RT_ICON resource loader, installed by USER_SignalProc when module
1473  * is initialized.
1474  */
1475 HGLOBAL16 WINAPI LoadDIBIconHandler16( HGLOBAL16 hMemObj, HMODULE16 hModule, HRSRC16 hRsrc )
1476 {
1477     /* If hResource is zero we must allocate a new memory block, if it's
1478      * non-zero but GlobalLock() returns NULL then it was discarded and
1479      * we have to recommit some memory, otherwise we just need to check 
1480      * the block size. See LoadProc() in 16-bit SDK for more.
1481      */
1482
1483      hMemObj = NE_DefResourceHandler( hMemObj, hModule, hRsrc );
1484      if( hMemObj )
1485      {
1486          LPBYTE bits = (LPBYTE)GlobalLock16( hMemObj );
1487          hMemObj = CURSORICON_CreateFromResource( hModule, hMemObj, bits, 
1488                    SizeofResource16(hModule, hRsrc), TRUE, 0x00030000, 
1489                    SYSMETRICS_CXICON, SYSMETRICS_CYICON, LR_DEFAULTCOLOR );
1490      }
1491      return hMemObj;
1492 }
1493
1494 /**********************************************************************
1495  *          LoadDIBCursorHandler    (USER.356)
1496  *
1497  * RT_CURSOR resource loader. Same as above.
1498  */
1499 HGLOBAL16 WINAPI LoadDIBCursorHandler16( HGLOBAL16 hMemObj, HMODULE16 hModule, HRSRC16 hRsrc )
1500 {
1501     hMemObj = NE_DefResourceHandler( hMemObj, hModule, hRsrc );
1502     if( hMemObj )
1503     {
1504         LPBYTE bits = (LPBYTE)GlobalLock16( hMemObj );
1505         hMemObj = CURSORICON_CreateFromResource( hModule, hMemObj, bits,
1506                   SizeofResource16(hModule, hRsrc), FALSE, 0x00030000,
1507                   SYSMETRICS_CXCURSOR, SYSMETRICS_CYCURSOR, LR_MONOCHROME );
1508     }
1509     return hMemObj;
1510 }
1511
1512 /**********************************************************************
1513  *          LoadIconHandler    (USER.456)
1514  */
1515 HICON16 WINAPI LoadIconHandler16( HGLOBAL16 hResource, BOOL16 bNew )
1516 {
1517     LPBYTE bits = (LPBYTE)LockResource16( hResource );
1518
1519     TRACE(cursor,"hRes=%04x\n",hResource);
1520
1521     return CURSORICON_CreateFromResource( 0, 0, bits, 0, TRUE, 
1522                       bNew ? 0x00030000 : 0x00020000, 0, 0, LR_DEFAULTCOLOR );
1523 }
1524
1525 /***********************************************************************
1526  *           LoadCursorW            (USER32.362)
1527  */
1528 HCURSOR WINAPI LoadCursorW(HINSTANCE hInstance, LPCWSTR name)
1529 {
1530     return LoadImageW( hInstance, name, IMAGE_CURSOR, 0, 0, 
1531                        LR_SHARED | LR_DEFAULTSIZE );
1532 }
1533
1534 /***********************************************************************
1535  *           LoadCursorA            (USER32.359)
1536  */
1537 HCURSOR WINAPI LoadCursorA(HINSTANCE hInstance, LPCSTR name)
1538 {
1539     return LoadImageA( hInstance, name, IMAGE_CURSOR, 0, 0, 
1540                        LR_SHARED | LR_DEFAULTSIZE );
1541 }
1542
1543 /***********************************************************************
1544 *            LoadCursorFromFileW    (USER32.361)
1545 */
1546 HCURSOR WINAPI LoadCursorFromFileW (LPCWSTR name)
1547 {
1548     return LoadImageW( 0, name, IMAGE_CURSOR, 0, 0, 
1549                        LR_LOADFROMFILE | LR_DEFAULTSIZE );
1550 }
1551
1552 /***********************************************************************
1553 *            LoadCursorFromFileA    (USER32.360)
1554 */
1555 HCURSOR WINAPI LoadCursorFromFileA (LPCSTR name)
1556 {
1557     return LoadImageA( 0, name, IMAGE_CURSOR, 0, 0, 
1558                        LR_LOADFROMFILE | LR_DEFAULTSIZE );
1559 }
1560   
1561 /***********************************************************************
1562  *           LoadIconW          (USER32.364)
1563  */
1564 HICON WINAPI LoadIconW(HINSTANCE hInstance, LPCWSTR name)
1565 {
1566     return LoadImageW( hInstance, name, IMAGE_ICON, 0, 0, 
1567                        LR_SHARED | LR_DEFAULTSIZE );
1568 }
1569
1570 /***********************************************************************
1571  *           LoadIconA          (USER32.363)
1572  */
1573 HICON WINAPI LoadIconA(HINSTANCE hInstance, LPCSTR name)
1574 {
1575     return LoadImageA( hInstance, name, IMAGE_ICON, 0, 0, 
1576                        LR_SHARED | LR_DEFAULTSIZE );
1577 }
1578
1579 /**********************************************************************
1580  *          GetIconInfo16       (USER.395)
1581  */
1582 BOOL16 WINAPI GetIconInfo16(HICON16 hIcon,LPICONINFO16 iconinfo)
1583 {
1584     ICONINFO    ii32;
1585     BOOL16      ret = GetIconInfo((HICON)hIcon, &ii32);
1586
1587     iconinfo->fIcon = ii32.fIcon;
1588     iconinfo->xHotspot = ii32.xHotspot;
1589     iconinfo->yHotspot = ii32.yHotspot;
1590     iconinfo->hbmMask = ii32.hbmMask;
1591     iconinfo->hbmColor = ii32.hbmColor;
1592     return ret;
1593 }
1594
1595 /**********************************************************************
1596  *          GetIconInfo32               (USER32.242)
1597  */
1598 BOOL WINAPI GetIconInfo(HICON hIcon,LPICONINFO iconinfo) {
1599     CURSORICONINFO      *ciconinfo;
1600
1601     ciconinfo = GlobalLock16(hIcon);
1602     if (!ciconinfo)
1603         return FALSE;
1604     iconinfo->xHotspot = ciconinfo->ptHotSpot.x;
1605     iconinfo->yHotspot = ciconinfo->ptHotSpot.y;
1606     iconinfo->fIcon    = TRUE; /* hmm */
1607
1608     iconinfo->hbmColor = CreateBitmap ( ciconinfo->nWidth, ciconinfo->nHeight,
1609                                 ciconinfo->bPlanes, ciconinfo->bBitsPerPixel,
1610                                 (char *)(ciconinfo + 1)
1611                                 + ciconinfo->nHeight *
1612                                 BITMAP_GetWidthBytes (ciconinfo->nWidth,1) );
1613     iconinfo->hbmMask = CreateBitmap ( ciconinfo->nWidth, ciconinfo->nHeight,
1614                                 1, 1, (char *)(ciconinfo + 1));
1615
1616     GlobalUnlock16(hIcon);
1617
1618     return TRUE;
1619 }
1620
1621 /**********************************************************************
1622  *          CreateIconIndirect          (USER32.78)
1623  */
1624 HICON WINAPI CreateIconIndirect(LPICONINFO iconinfo) {
1625     BITMAPOBJ *bmpXor,*bmpAnd;
1626     HICON hObj;
1627     int sizeXor,sizeAnd;
1628
1629     bmpXor = (BITMAPOBJ *) GDI_GetObjPtr( iconinfo->hbmColor, BITMAP_MAGIC );
1630     bmpAnd = (BITMAPOBJ *) GDI_GetObjPtr( iconinfo->hbmMask, BITMAP_MAGIC );
1631
1632     sizeXor = bmpXor->bitmap.bmHeight * bmpXor->bitmap.bmWidthBytes;
1633     sizeAnd = bmpAnd->bitmap.bmHeight * bmpAnd->bitmap.bmWidthBytes;
1634
1635     hObj = GlobalAlloc16( GMEM_MOVEABLE, 
1636                      sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
1637     if (hObj)
1638     {
1639         CURSORICONINFO *info;
1640
1641         info = (CURSORICONINFO *)GlobalLock16( hObj );
1642         info->ptHotSpot.x   = iconinfo->xHotspot;
1643         info->ptHotSpot.y   = iconinfo->yHotspot;
1644         info->nWidth        = bmpXor->bitmap.bmWidth;
1645         info->nHeight       = bmpXor->bitmap.bmHeight;
1646         info->nWidthBytes   = bmpXor->bitmap.bmWidthBytes;
1647         info->bPlanes       = bmpXor->bitmap.bmPlanes;
1648         info->bBitsPerPixel = bmpXor->bitmap.bmBitsPixel;
1649
1650         /* Transfer the bitmap bits to the CURSORICONINFO structure */
1651
1652         GetBitmapBits( iconinfo->hbmMask ,sizeAnd,(char*)(info + 1) );
1653         GetBitmapBits( iconinfo->hbmColor,sizeXor,(char*)(info + 1) +sizeAnd);
1654         GlobalUnlock16( hObj );
1655     }
1656     return hObj;
1657 }
1658
1659
1660 /**********************************************************************
1661  *          
1662  DrawIconEx16           (USER.394)
1663  */
1664 BOOL16 WINAPI DrawIconEx16 (HDC16 hdc, INT16 xLeft, INT16 yTop, HICON16 hIcon,
1665                             INT16 cxWidth, INT16 cyWidth, UINT16 istep,
1666                             HBRUSH16 hbr, UINT16 flags)
1667 {
1668     return DrawIconEx(hdc, xLeft, yTop, hIcon, cxWidth, cyWidth,
1669                         istep, hbr, flags);
1670 }
1671
1672
1673 /******************************************************************************
1674  * DrawIconEx32 [USER32.160]  Draws an icon or cursor on device context
1675  *
1676  * NOTES
1677  *    Why is this using SM_CXICON instead of SM_CXCURSOR?
1678  *
1679  * PARAMS
1680  *    hdc     [I] Handle to device context
1681  *    x0      [I] X coordinate of upper left corner
1682  *    y0      [I] Y coordinate of upper left corner
1683  *    hIcon   [I] Handle to icon to draw
1684  *    cxWidth [I] Width of icon
1685  *    cyWidth [I] Height of icon
1686  *    istep   [I] Index of frame in animated cursor
1687  *    hbr     [I] Handle to background brush
1688  *    flags   [I] Icon-drawing flags
1689  *
1690  * RETURNS
1691  *    Success: TRUE
1692  *    Failure: FALSE
1693  */
1694 BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
1695                             INT cxWidth, INT cyWidth, UINT istep, 
1696                             HBRUSH hbr, UINT flags )
1697 {
1698     CURSORICONINFO *ptr = (CURSORICONINFO *)GlobalLock16 (hIcon);
1699     HDC hDC_off = 0, hMemDC = CreateCompatibleDC (hdc);
1700     BOOL result = FALSE, DoOffscreen = FALSE;
1701     HBITMAP hB_off = 0, hOld = 0;
1702
1703     if (!ptr) return FALSE;
1704
1705     if (istep)
1706         FIXME(icon, "Ignoring istep=%d\n", istep);
1707     if (flags & DI_COMPAT)
1708         FIXME(icon, "Ignoring flag DI_COMPAT\n");
1709
1710     /* Calculate the size of the destination image.  */
1711     if (cxWidth == 0)
1712     {
1713       if (flags & DI_DEFAULTSIZE)
1714         cxWidth = GetSystemMetrics (SM_CXICON);
1715       else
1716         cxWidth = ptr->nWidth;
1717     }
1718     if (cyWidth == 0)
1719     {
1720       if (flags & DI_DEFAULTSIZE)
1721         cyWidth = GetSystemMetrics (SM_CYICON);
1722       else
1723         cyWidth = ptr->nHeight;
1724     }
1725
1726     if (!(DoOffscreen = (hbr >= STOCK_WHITE_BRUSH) && (hbr <= 
1727       STOCK_HOLLOW_BRUSH)))
1728     {
1729         GDIOBJHDR *object = (GDIOBJHDR *) GDI_HEAP_LOCK(hbr);
1730         if (object)
1731         {
1732             UINT16 magic = object->wMagic;
1733             GDI_HEAP_UNLOCK(hbr);
1734             DoOffscreen = magic == BRUSH_MAGIC;
1735         }
1736     }
1737     if (DoOffscreen) {
1738       RECT r = {0, 0, cxWidth, cxWidth};
1739
1740       hDC_off = CreateCompatibleDC(hdc);
1741       hB_off = CreateCompatibleBitmap(hdc, cxWidth, cyWidth);
1742       if (hDC_off && hB_off) {
1743         hOld = SelectObject(hDC_off, hB_off);
1744         FillRect(hDC_off, &r, hbr);
1745       }
1746     };
1747
1748     if (hMemDC && (!DoOffscreen || (hDC_off && hB_off)))
1749     {
1750         HBITMAP hXorBits, hAndBits;
1751         COLORREF  oldFg, oldBg;
1752         INT     nStretchMode;
1753
1754         nStretchMode = SetStretchBltMode (hdc, STRETCH_DELETESCANS);
1755
1756         hXorBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
1757                                     ptr->bPlanes, ptr->bBitsPerPixel,
1758                                     (char *)(ptr + 1)
1759                                     + ptr->nHeight *
1760                                     BITMAP_GetWidthBytes(ptr->nWidth,1) );
1761         hAndBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
1762                                     1, 1, (char *)(ptr+1) );
1763         oldFg = SetTextColor( hdc, RGB(0,0,0) );
1764         oldBg = SetBkColor( hdc, RGB(255,255,255) );
1765
1766         if (hXorBits && hAndBits)
1767         {
1768             HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
1769             if (flags & DI_MASK)
1770             {
1771               if (DoOffscreen) 
1772                 StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
1773                               hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
1774               else 
1775                 StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
1776                               hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
1777             }
1778             SelectObject( hMemDC, hXorBits );
1779             if (flags & DI_IMAGE)
1780             {
1781               if (DoOffscreen) 
1782                 StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
1783                           hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
1784               else
1785                 StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
1786                               hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
1787             }
1788             SelectObject( hMemDC, hBitTemp );
1789             result = TRUE;
1790         }
1791
1792         SetTextColor( hdc, oldFg );
1793         SetBkColor( hdc, oldBg );
1794         if (hXorBits) DeleteObject( hXorBits );
1795         if (hAndBits) DeleteObject( hAndBits );
1796         SetStretchBltMode (hdc, nStretchMode);
1797         if (DoOffscreen) {
1798           BitBlt(hdc, x0, y0, cxWidth, cyWidth, hDC_off, 0, 0, SRCCOPY);
1799           SelectObject(hDC_off, hOld);
1800         }
1801     }
1802     if (hMemDC) DeleteDC( hMemDC );
1803     if (hDC_off) DeleteDC(hDC_off);
1804     if (hB_off) DeleteObject(hB_off);
1805     GlobalUnlock16( hIcon );
1806     return result;
1807 }