Added a possibility to let the internal debugger use a separate
[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 DECLARE_DEBUG_CHANNEL(cursor)
55 DECLARE_DEBUG_CHANNEL(icon)
56
57 static HCURSOR hActiveCursor = 0;  /* Active cursor */
58 static INT CURSOR_ShowCount = 0;   /* Cursor display count */
59 static RECT CURSOR_ClipRect;       /* Cursor clipping rect */
60
61
62 /**********************************************************************
63  * ICONCACHE for cursors/icons loaded with LR_SHARED.
64  *
65  * FIXME: This should not be allocated on the system heap, but on a
66  *        subsystem-global heap (i.e. one for all Win16 processes,
67  *        and one each for every Win32 process).
68  */
69 typedef struct tagICONCACHE
70 {
71     struct tagICONCACHE *next;
72
73     HMODULE              hModule;
74     HRSRC                hRsrc;
75     HANDLE               handle;
76
77     INT                  count;
78
79 } ICONCACHE;
80
81 static ICONCACHE *IconAnchor = NULL;
82 static CRITICAL_SECTION IconCrst;
83
84 /**********************************************************************
85  *          CURSORICON_Init
86  */
87 void CURSORICON_Init( void )
88 {
89     InitializeCriticalSection( &IconCrst );
90     MakeCriticalSectionGlobal( &IconCrst );
91 }
92
93 /**********************************************************************
94  *          CURSORICON_FindSharedIcon
95  */
96 static HANDLE CURSORICON_FindSharedIcon( HMODULE hModule, HRSRC hRsrc )
97 {
98     HANDLE handle = 0;
99     ICONCACHE *ptr;
100
101     EnterCriticalSection( &IconCrst );
102
103     for ( ptr = IconAnchor; ptr; ptr = ptr->next )
104         if ( ptr->hModule == hModule && ptr->hRsrc == hRsrc )
105         {
106             ptr->count++;
107             handle = ptr->handle;
108             break;
109         }
110
111     LeaveCriticalSection( &IconCrst );
112
113     return handle;
114 }
115
116 /**********************************************************************
117  *          CURSORICON_AddSharedIcon
118  */
119 static void CURSORICON_AddSharedIcon( HMODULE hModule, HRSRC hRsrc, HANDLE handle )
120 {
121     ICONCACHE *ptr = HeapAlloc( SystemHeap, 0, sizeof(ICONCACHE) );
122     if ( !ptr ) return;
123
124     ptr->hModule = hModule;
125     ptr->hRsrc   = hRsrc;
126     ptr->handle  = handle;
127     ptr->count   = 1;
128
129     EnterCriticalSection( &IconCrst );
130     ptr->next    = IconAnchor;
131     IconAnchor   = ptr;
132     LeaveCriticalSection( &IconCrst );
133 }
134
135 /**********************************************************************
136  *          CURSORICON_DelSharedIcon
137  */
138 static INT CURSORICON_DelSharedIcon( HANDLE handle )
139 {
140     INT count = -1;
141     ICONCACHE *ptr;
142
143     EnterCriticalSection( &IconCrst );
144
145     for ( ptr = IconAnchor; ptr; ptr = ptr->next )
146         if ( ptr->handle == handle )
147         {
148             if ( ptr->count > 0 ) ptr->count--;
149             count = ptr->count;
150             break;
151         }
152
153     LeaveCriticalSection( &IconCrst );
154
155     return count;
156 }
157
158 /**********************************************************************
159  *          CURSORICON_FreeModuleIcons
160  */
161 void CURSORICON_FreeModuleIcons( HMODULE hModule )
162 {
163     ICONCACHE **ptr = &IconAnchor;
164
165     if ( HIWORD( hModule ) )
166         hModule = MapHModuleLS( hModule );
167     else
168         hModule = GetExePtr( hModule );
169
170     EnterCriticalSection( &IconCrst );
171
172     while ( *ptr )
173     {
174         if ( (*ptr)->hModule == hModule )
175         {
176             ICONCACHE *freePtr = *ptr;
177             *ptr = freePtr->next;
178             
179             GlobalFree16( freePtr->handle );
180             HeapFree( SystemHeap, 0, freePtr );
181             continue;
182         }
183         ptr = &(*ptr)->next;
184     }
185
186     LeaveCriticalSection( &IconCrst );
187 }
188
189 /**********************************************************************
190  *          CURSORICON_FindBestIcon
191  *
192  * Find the icon closest to the requested size and number of colors.
193  */
194 static CURSORICONDIRENTRY *CURSORICON_FindBestIcon( CURSORICONDIR *dir, int width,
195                                               int height, int colors )
196 {
197     int i, maxcolors, maxwidth, maxheight;
198     CURSORICONDIRENTRY *entry, *bestEntry = NULL;
199
200     if (dir->idCount < 1)
201     {
202         WARN(icon, "Empty directory!\n" );
203         return NULL;
204     }
205     if (dir->idCount == 1) return &dir->idEntries[0];  /* No choice... */
206
207     /* First find the exact size with less colors */
208
209     maxcolors = 0;
210     for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
211         if ((entry->ResInfo.icon.bWidth == width) && (entry->ResInfo.icon.bHeight == height) &&
212             (entry->ResInfo.icon.bColorCount <= colors) && (entry->ResInfo.icon.bColorCount > maxcolors))
213         {
214             bestEntry = entry;
215             maxcolors = entry->ResInfo.icon.bColorCount;
216         }
217     if (bestEntry) return bestEntry;
218
219     /* First find the exact size with more colors */
220
221     maxcolors = 255;
222     for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
223         if ((entry->ResInfo.icon.bWidth == width) && (entry->ResInfo.icon.bHeight == height) &&
224             (entry->ResInfo.icon.bColorCount > colors) && (entry->ResInfo.icon.bColorCount <= maxcolors))
225         {
226             bestEntry = entry;
227             maxcolors = entry->ResInfo.icon.bColorCount;
228         }
229     if (bestEntry) return bestEntry;
230
231     /* Now find a smaller one with less colors */
232
233     maxcolors = maxwidth = maxheight = 0;
234     for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
235         if ((entry->ResInfo.icon.bWidth <= width) && (entry->ResInfo.icon.bHeight <= height) &&
236             (entry->ResInfo.icon.bWidth >= maxwidth) && (entry->ResInfo.icon.bHeight >= maxheight) &&
237             (entry->ResInfo.icon.bColorCount <= colors) && (entry->ResInfo.icon.bColorCount > maxcolors))
238         {
239             bestEntry = entry;
240             maxwidth  = entry->ResInfo.icon.bWidth;
241             maxheight = entry->ResInfo.icon.bHeight;
242             maxcolors = entry->ResInfo.icon.bColorCount;
243         }
244     if (bestEntry) return bestEntry;
245
246     /* Now find a smaller one with more colors */
247
248     maxcolors = 255;
249     maxwidth = maxheight = 0;
250     for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
251         if ((entry->ResInfo.icon.bWidth <= width) && (entry->ResInfo.icon.bHeight <= height) &&
252             (entry->ResInfo.icon.bWidth >= maxwidth) && (entry->ResInfo.icon.bHeight >= maxheight) &&
253             (entry->ResInfo.icon.bColorCount > colors) && (entry->ResInfo.icon.bColorCount <= maxcolors))
254         {
255             bestEntry = entry;
256             maxwidth  = entry->ResInfo.icon.bWidth;
257             maxheight = entry->ResInfo.icon.bHeight;
258             maxcolors = entry->ResInfo.icon.bColorCount;
259         }
260     if (bestEntry) return bestEntry;
261
262     /* Now find a larger one with less colors */
263
264     maxcolors = 0;
265     maxwidth = maxheight = 255;
266     for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
267         if ((entry->ResInfo.icon.bWidth <= maxwidth) && (entry->ResInfo.icon.bHeight <= maxheight) &&
268             (entry->ResInfo.icon.bColorCount <= colors) && (entry->ResInfo.icon.bColorCount > maxcolors))
269         {
270             bestEntry = entry;
271             maxwidth  = entry->ResInfo.icon.bWidth;
272             maxheight = entry->ResInfo.icon.bHeight;
273             maxcolors = entry->ResInfo.icon.bColorCount;
274         }
275     if (bestEntry) return bestEntry;
276
277     /* Now find a larger one with more colors */
278
279     maxcolors = maxwidth = maxheight = 255;
280     for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
281         if ((entry->ResInfo.icon.bWidth <= maxwidth) && (entry->ResInfo.icon.bHeight <= maxheight) &&
282             (entry->ResInfo.icon.bColorCount > colors) && (entry->ResInfo.icon.bColorCount <= maxcolors))
283         {
284             bestEntry = entry;
285             maxwidth  = entry->ResInfo.icon.bWidth;
286             maxheight = entry->ResInfo.icon.bHeight;
287             maxcolors = entry->ResInfo.icon.bColorCount;
288         }
289
290     return bestEntry;
291 }
292
293
294 /**********************************************************************
295  *          CURSORICON_FindBestCursor
296  *
297  * Find the cursor closest to the requested size.
298  * FIXME: parameter 'color' ignored and entries with more than 1 bpp
299  *        ignored too
300  */
301 static CURSORICONDIRENTRY *CURSORICON_FindBestCursor( CURSORICONDIR *dir,
302                                                   int width, int height, int color)
303 {
304     int i, maxwidth, maxheight;
305     CURSORICONDIRENTRY *entry, *bestEntry = NULL;
306
307     if (dir->idCount < 1)
308     {
309         WARN(cursor, "Empty directory!\n" );
310         return NULL;
311     }
312     if (dir->idCount == 1) return &dir->idEntries[0]; /* No choice... */
313
314     /* First find the largest one smaller than or equal to the requested size*/
315
316     maxwidth = maxheight = 0;
317     for(i = 0,entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
318         if ((entry->ResInfo.cursor.wWidth <= width) && (entry->ResInfo.cursor.wHeight <= height) &&
319             (entry->ResInfo.cursor.wWidth > maxwidth) && (entry->ResInfo.cursor.wHeight > maxheight) &&
320             (entry->wBitCount == 1))
321         {
322             bestEntry = entry;
323             maxwidth  = entry->ResInfo.cursor.wWidth;
324             maxheight = entry->ResInfo.cursor.wHeight;
325         }
326     if (bestEntry) return bestEntry;
327
328     /* Now find the smallest one larger than the requested size */
329
330     maxwidth = maxheight = 255;
331     for(i = 0,entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
332         if ((entry->ResInfo.cursor.wWidth < maxwidth) && (entry->ResInfo.cursor.wHeight < maxheight) &&
333             (entry->wBitCount == 1))
334         {
335             bestEntry = entry;
336             maxwidth  = entry->ResInfo.cursor.wWidth;
337             maxheight = entry->ResInfo.cursor.wHeight;
338         }
339
340     return bestEntry;
341 }
342
343 /*********************************************************************
344  * The main purpose of this function is to create fake resource directory
345  * and fake resource entries. There are several reasons for this:
346  *      -       CURSORICONDIR and CURSORICONFILEDIR differ in sizes and their
347  *              fields
348  *      There are some "bad" cursor files which do not have
349  *              bColorCount initialized but instead one must read this info
350  *              directly from corresponding DIB sections
351  * Note: wResId is index to array of pointer returned in ptrs (origin is 1)
352  */
353 BOOL CURSORICON_SimulateLoadingFromResourceW( LPWSTR filename, BOOL fCursor,
354                                                 CURSORICONDIR **res, LPBYTE **ptr)
355 {
356     LPBYTE   _free;
357     CURSORICONFILEDIR *bits;
358     int      entries, size, i;
359
360     *res = NULL;
361     *ptr = NULL;
362     if (!(bits = (CURSORICONFILEDIR *)VIRTUAL_MapFileW( filename ))) return FALSE;
363
364     /* FIXME: test for inimated icons
365      * hack to load the first icon from the *.ani file
366      */
367     if ( *(LPDWORD)bits==0x46464952 ) /* "RIFF" */
368     { LPBYTE pos = (LPBYTE) bits;
369       FIXME (cursor,"Animated icons not correctly implemented! %p \n", bits);
370         
371       for (;;)
372       { if (*(LPDWORD)pos==0x6e6f6369)          /* "icon" */
373         { FIXME (cursor,"icon entry found! %p\n", bits);
374           pos+=4;
375           if ( !*(LPWORD) pos==0x2fe)           /* iconsize */
376           { goto fail;
377           }
378           bits+=2;
379           FIXME (cursor,"icon size ok %p \n", bits);
380           break;
381         }
382         pos+=2;
383         if (pos>=(LPBYTE)bits+766) goto fail;
384       }
385     }
386     if (!(entries = bits->idCount)) goto fail;
387     (int)_free = size = sizeof(CURSORICONDIR) + sizeof(CURSORICONDIRENTRY) * 
388                                                 (entries - 1);
389     for (i=0; i < entries; i++)
390       size += bits->idEntries[i].dwDIBSize + (fCursor ? sizeof(POINT16): 0);
391     
392     if (!(*ptr = HeapAlloc( GetProcessHeap(), 0,
393                             entries * sizeof (CURSORICONDIRENTRY*)))) goto fail;
394     if (!(*res = HeapAlloc( GetProcessHeap(), 0, size))) goto fail;
395
396     _free = (LPBYTE)(*res) + (int)_free;
397     memcpy((*res), bits, 6);
398     for (i=0; i<entries; i++)
399     {
400       ((LPBYTE*)(*ptr))[i] = _free;
401       if (fCursor) {
402         (*res)->idEntries[i].ResInfo.cursor.wWidth=bits->idEntries[i].bWidth;
403         (*res)->idEntries[i].ResInfo.cursor.wHeight=bits->idEntries[i].bHeight;
404         ((LPPOINT16)_free)->x=bits->idEntries[i].xHotspot;
405         ((LPPOINT16)_free)->y=bits->idEntries[i].yHotspot;
406         _free+=sizeof(POINT16);
407       } else {
408         (*res)->idEntries[i].ResInfo.icon.bWidth=bits->idEntries[i].bWidth;
409         (*res)->idEntries[i].ResInfo.icon.bHeight=bits->idEntries[i].bHeight;
410         (*res)->idEntries[i].ResInfo.icon.bColorCount = bits->idEntries[i].bColorCount;
411       }
412       (*res)->idEntries[i].wPlanes=1;
413       (*res)->idEntries[i].wBitCount = ((LPBITMAPINFOHEADER)((LPBYTE)bits +
414                                                    bits->idEntries[i].dwDIBOffset))->biBitCount;
415       (*res)->idEntries[i].dwBytesInRes = bits->idEntries[i].dwDIBSize;
416       (*res)->idEntries[i].wResId=i+1;
417
418       memcpy(_free,(LPBYTE)bits +bits->idEntries[i].dwDIBOffset,
419              (*res)->idEntries[i].dwBytesInRes);
420       _free += (*res)->idEntries[i].dwBytesInRes;
421     }
422     UnmapViewOfFile( bits );
423     return TRUE;    
424 fail:
425     if (*res) HeapFree( GetProcessHeap(), 0, *res );
426     if (*ptr) HeapFree( GetProcessHeap(), 0, *ptr );
427     UnmapViewOfFile( bits );
428     return FALSE;
429 }
430
431
432 /**********************************************************************
433  *          CURSORICON_CreateFromResource
434  *
435  * Create a cursor or icon from in-memory resource template. 
436  *
437  * FIXME: Convert to mono when cFlag is LR_MONOCHROME. Do something
438  *        with cbSize parameter as well.
439  */
440 static HGLOBAL16 CURSORICON_CreateFromResource( HINSTANCE16 hInstance, HGLOBAL16 hObj, LPBYTE bits,
441                                                 UINT cbSize, BOOL bIcon, DWORD dwVersion, 
442                                                 INT width, INT height, UINT loadflags )
443 {
444     int sizeAnd, sizeXor;
445     HBITMAP hAndBits = 0, hXorBits = 0; /* error condition for later */
446     BITMAPOBJ *bmpXor, *bmpAnd;
447     POINT16 hotspot = { 0 ,0 };
448     BITMAPINFO *bmi;
449     HDC hdc;
450     BOOL DoStretch;
451     INT size;
452
453     TRACE(cursor,"%08x (%u bytes), ver %08x, %ix%i %s %s\n",
454                         (unsigned)bits, cbSize, (unsigned)dwVersion, width, height,
455                                   bIcon ? "icon" : "cursor", (loadflags & LR_MONOCHROME) ? "mono" : "" );
456     if (dwVersion == 0x00020000)
457     {
458         FIXME(cursor,"\t2.xx resources are not supported\n");
459         return 0;
460     }
461
462     if (bIcon)
463         bmi = (BITMAPINFO *)bits;
464     else /* get the hotspot */
465     {
466         POINT16 *pt = (POINT16 *)bits;
467         hotspot = *pt;
468         bmi = (BITMAPINFO *)(pt + 1);
469     }
470     size = DIB_BitmapInfoSize( bmi, DIB_RGB_COLORS );
471
472     if (!width) width = bmi->bmiHeader.biWidth;
473     if (!height) height = bmi->bmiHeader.biHeight/2;
474     DoStretch = (bmi->bmiHeader.biHeight/2 != height) ||
475       (bmi->bmiHeader.biWidth != width);
476
477     /* Check bitmap header */
478
479     if ( (bmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) &&
480          (bmi->bmiHeader.biSize != sizeof(BITMAPINFOHEADER)  ||
481           bmi->bmiHeader.biCompression != BI_RGB) )
482     {
483           WARN(cursor,"\tinvalid resource bitmap header.\n");
484           return 0;
485     }
486
487     if( (hdc = GetDC( 0 )) )
488     {
489         BITMAPINFO* pInfo;
490
491         /* Make sure we have room for the monochrome bitmap later on.
492          * Note that BITMAPINFOINFO and BITMAPCOREHEADER are the same
493          * up to and including the biBitCount. In-memory icon resource 
494          * format is as follows:
495          *
496          *   BITMAPINFOHEADER   icHeader  // DIB header
497          *   RGBQUAD         icColors[]   // Color table
498          *   BYTE            icXOR[]      // DIB bits for XOR mask
499          *   BYTE            icAND[]      // DIB bits for AND mask
500          */
501
502         if ((pInfo = (BITMAPINFO *)HeapAlloc( GetProcessHeap(), 0, 
503           MAX(size, sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD)))))
504         {       
505             memcpy( pInfo, bmi, size ); 
506             pInfo->bmiHeader.biHeight /= 2;
507
508             /* Create the XOR bitmap */
509
510             if (DoStretch) {
511               if ((hXorBits = CreateCompatibleBitmap(hdc, width, height))) {
512                 HBITMAP hOld;
513                 HDC hMem = CreateCompatibleDC(hdc);
514                 BOOL res;
515
516                 if (hMem) {
517                   hOld = SelectObject(hMem, hXorBits);
518                   res = StretchDIBits(hMem, 0, 0, width, height, 0, 0,
519                     bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight/2,
520                     (char*)bmi + size, pInfo, DIB_RGB_COLORS, SRCCOPY);
521                   SelectObject(hMem, hOld);
522                   DeleteDC(hMem);
523                 } else res = FALSE;
524                 if (!res) { DeleteObject(hXorBits); hXorBits = 0; }
525               }
526             } else hXorBits = CreateDIBitmap( hdc, &pInfo->bmiHeader,
527                 CBM_INIT, (char*)bmi + size, pInfo, DIB_RGB_COLORS );
528             if( hXorBits )
529             {
530                 char* bits = (char *)bmi + size +
531                         DIB_GetDIBImageBytes(bmi->bmiHeader.biWidth,
532                                              bmi->bmiHeader.biHeight,
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->wResId-1];
689         h = CURSORICON_CreateFromResource( 0, 0, bits, dirEntry->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->wResId;
761         dwBytesInRes = dirEntry->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         CURSORICONDIRENTRY* entry;
1383         HDC hdc;
1384         UINT palEnts;
1385         int colors;
1386         hdc = GetDC(0);
1387         palEnts = GetSystemPaletteEntries(hdc, 0, 0, NULL);
1388         if (palEnts == 0)
1389             palEnts = 256;
1390         colors = (cFlag & LR_MONOCHROME) ? 2 : palEnts;
1391
1392         ReleaseDC(0, hdc);
1393
1394         if( bIcon )
1395             entry = CURSORICON_FindBestIcon( dir, width, height, colors );
1396         else
1397             entry = CURSORICON_FindBestCursor( dir, width, height, 1);
1398
1399         if( entry ) retVal = entry->wResId;
1400     }
1401     else WARN(cursor, "invalid resource directory\n");
1402     return retVal;
1403 }
1404
1405 /**********************************************************************
1406  *          LookupIconIdFromDirectoryEx32       (USER32.380)
1407  */
1408 INT WINAPI LookupIconIdFromDirectoryEx( LPBYTE dir, BOOL bIcon,
1409              INT width, INT height, UINT cFlag )
1410 {
1411     return LookupIconIdFromDirectoryEx16( dir, bIcon, width, height, cFlag );
1412 }
1413
1414 /**********************************************************************
1415  *          LookupIconIdFromDirectory           (USER.???)
1416  */
1417 INT16 WINAPI LookupIconIdFromDirectory16( LPBYTE dir, BOOL16 bIcon )
1418 {
1419     return LookupIconIdFromDirectoryEx16( dir, bIcon, 
1420            bIcon ? SYSMETRICS_CXICON : SYSMETRICS_CXCURSOR,
1421            bIcon ? SYSMETRICS_CYICON : SYSMETRICS_CYCURSOR, bIcon ? 0 : LR_MONOCHROME );
1422 }
1423
1424 /**********************************************************************
1425  *          LookupIconIdFromDirectory           (USER32.379)
1426  */
1427 INT WINAPI LookupIconIdFromDirectory( LPBYTE dir, BOOL bIcon )
1428 {
1429     return LookupIconIdFromDirectoryEx( dir, bIcon, 
1430            bIcon ? SYSMETRICS_CXICON : SYSMETRICS_CXCURSOR,
1431            bIcon ? SYSMETRICS_CYICON : SYSMETRICS_CYCURSOR, bIcon ? 0 : LR_MONOCHROME );
1432 }
1433
1434 /**********************************************************************
1435  *          GetIconID    (USER.455)
1436  */
1437 WORD WINAPI GetIconID16( HGLOBAL16 hResource, DWORD resType )
1438 {
1439     LPBYTE lpDir = (LPBYTE)GlobalLock16(hResource);
1440
1441     TRACE(cursor, "hRes=%04x, entries=%i\n",
1442                     hResource, lpDir ? ((CURSORICONDIR*)lpDir)->idCount : 0);
1443
1444     switch(resType)
1445     {
1446         case RT_CURSOR16:
1447              return (WORD)LookupIconIdFromDirectoryEx16( lpDir, FALSE, 
1448                           SYSMETRICS_CXCURSOR, SYSMETRICS_CYCURSOR, LR_MONOCHROME );
1449         case RT_ICON16:
1450              return (WORD)LookupIconIdFromDirectoryEx16( lpDir, TRUE,
1451                           SYSMETRICS_CXICON, SYSMETRICS_CYICON, 0 );
1452         default:
1453              WARN(cursor, "invalid res type %ld\n", resType );
1454     }
1455     return 0;
1456 }
1457
1458 /**********************************************************************
1459  *          LoadCursorIconHandler    (USER.336)
1460  *
1461  * Supposed to load resources of Windows 2.x applications.
1462  */
1463 HGLOBAL16 WINAPI LoadCursorIconHandler16( HGLOBAL16 hResource, HMODULE16 hModule, HRSRC16 hRsrc )
1464 {
1465     FIXME(cursor,"(%04x,%04x,%04x): old 2.x resources are not supported!\n", 
1466           hResource, hModule, hRsrc);
1467     return (HGLOBAL16)0;
1468 }
1469
1470 /**********************************************************************
1471  *          LoadDIBIconHandler    (USER.357)
1472  * 
1473  * RT_ICON resource loader, installed by USER_SignalProc when module
1474  * is initialized.
1475  */
1476 HGLOBAL16 WINAPI LoadDIBIconHandler16( HGLOBAL16 hMemObj, HMODULE16 hModule, HRSRC16 hRsrc )
1477 {
1478     /* If hResource is zero we must allocate a new memory block, if it's
1479      * non-zero but GlobalLock() returns NULL then it was discarded and
1480      * we have to recommit some memory, otherwise we just need to check 
1481      * the block size. See LoadProc() in 16-bit SDK for more.
1482      */
1483
1484      hMemObj = NE_DefResourceHandler( hMemObj, hModule, hRsrc );
1485      if( hMemObj )
1486      {
1487          LPBYTE bits = (LPBYTE)GlobalLock16( hMemObj );
1488          hMemObj = CURSORICON_CreateFromResource( hModule, hMemObj, bits, 
1489                    SizeofResource16(hModule, hRsrc), TRUE, 0x00030000, 
1490                    SYSMETRICS_CXICON, SYSMETRICS_CYICON, LR_DEFAULTCOLOR );
1491      }
1492      return hMemObj;
1493 }
1494
1495 /**********************************************************************
1496  *          LoadDIBCursorHandler    (USER.356)
1497  *
1498  * RT_CURSOR resource loader. Same as above.
1499  */
1500 HGLOBAL16 WINAPI LoadDIBCursorHandler16( HGLOBAL16 hMemObj, HMODULE16 hModule, HRSRC16 hRsrc )
1501 {
1502     hMemObj = NE_DefResourceHandler( hMemObj, hModule, hRsrc );
1503     if( hMemObj )
1504     {
1505         LPBYTE bits = (LPBYTE)GlobalLock16( hMemObj );
1506         hMemObj = CURSORICON_CreateFromResource( hModule, hMemObj, bits,
1507                   SizeofResource16(hModule, hRsrc), FALSE, 0x00030000,
1508                   SYSMETRICS_CXCURSOR, SYSMETRICS_CYCURSOR, LR_MONOCHROME );
1509     }
1510     return hMemObj;
1511 }
1512
1513 /**********************************************************************
1514  *          LoadIconHandler    (USER.456)
1515  */
1516 HICON16 WINAPI LoadIconHandler16( HGLOBAL16 hResource, BOOL16 bNew )
1517 {
1518     LPBYTE bits = (LPBYTE)LockResource16( hResource );
1519
1520     TRACE(cursor,"hRes=%04x\n",hResource);
1521
1522     return CURSORICON_CreateFromResource( 0, 0, bits, 0, TRUE, 
1523                       bNew ? 0x00030000 : 0x00020000, 0, 0, LR_DEFAULTCOLOR );
1524 }
1525
1526 /***********************************************************************
1527  *           LoadCursorW            (USER32.362)
1528  */
1529 HCURSOR WINAPI LoadCursorW(HINSTANCE hInstance, LPCWSTR name)
1530 {
1531     return LoadImageW( hInstance, name, IMAGE_CURSOR, 0, 0, 
1532                        LR_SHARED | LR_DEFAULTSIZE );
1533 }
1534
1535 /***********************************************************************
1536  *           LoadCursorA            (USER32.359)
1537  */
1538 HCURSOR WINAPI LoadCursorA(HINSTANCE hInstance, LPCSTR name)
1539 {
1540     return LoadImageA( hInstance, name, IMAGE_CURSOR, 0, 0, 
1541                        LR_SHARED | LR_DEFAULTSIZE );
1542 }
1543
1544 /***********************************************************************
1545 *            LoadCursorFromFileW    (USER32.361)
1546 */
1547 HCURSOR WINAPI LoadCursorFromFileW (LPCWSTR name)
1548 {
1549     return LoadImageW( 0, name, IMAGE_CURSOR, 0, 0, 
1550                        LR_LOADFROMFILE | LR_DEFAULTSIZE );
1551 }
1552
1553 /***********************************************************************
1554 *            LoadCursorFromFileA    (USER32.360)
1555 */
1556 HCURSOR WINAPI LoadCursorFromFileA (LPCSTR name)
1557 {
1558     return LoadImageA( 0, name, IMAGE_CURSOR, 0, 0, 
1559                        LR_LOADFROMFILE | LR_DEFAULTSIZE );
1560 }
1561   
1562 /***********************************************************************
1563  *           LoadIconW          (USER32.364)
1564  */
1565 HICON WINAPI LoadIconW(HINSTANCE hInstance, LPCWSTR name)
1566 {
1567     return LoadImageW( hInstance, name, IMAGE_ICON, 0, 0, 
1568                        LR_SHARED | LR_DEFAULTSIZE );
1569 }
1570
1571 /***********************************************************************
1572  *           LoadIconA          (USER32.363)
1573  */
1574 HICON WINAPI LoadIconA(HINSTANCE hInstance, LPCSTR name)
1575 {
1576     return LoadImageA( hInstance, name, IMAGE_ICON, 0, 0, 
1577                        LR_SHARED | LR_DEFAULTSIZE );
1578 }
1579
1580 /**********************************************************************
1581  *          GetIconInfo16       (USER.395)
1582  */
1583 BOOL16 WINAPI GetIconInfo16(HICON16 hIcon,LPICONINFO16 iconinfo)
1584 {
1585     ICONINFO    ii32;
1586     BOOL16      ret = GetIconInfo((HICON)hIcon, &ii32);
1587
1588     iconinfo->fIcon = ii32.fIcon;
1589     iconinfo->xHotspot = ii32.xHotspot;
1590     iconinfo->yHotspot = ii32.yHotspot;
1591     iconinfo->hbmMask = ii32.hbmMask;
1592     iconinfo->hbmColor = ii32.hbmColor;
1593     return ret;
1594 }
1595
1596 /**********************************************************************
1597  *          GetIconInfo32               (USER32.242)
1598  */
1599 BOOL WINAPI GetIconInfo(HICON hIcon,LPICONINFO iconinfo) {
1600     CURSORICONINFO      *ciconinfo;
1601
1602     ciconinfo = GlobalLock16(hIcon);
1603     if (!ciconinfo)
1604         return FALSE;
1605     iconinfo->xHotspot = ciconinfo->ptHotSpot.x;
1606     iconinfo->yHotspot = ciconinfo->ptHotSpot.y;
1607     iconinfo->fIcon    = TRUE; /* hmm */
1608
1609     iconinfo->hbmColor = CreateBitmap ( ciconinfo->nWidth, ciconinfo->nHeight,
1610                                 ciconinfo->bPlanes, ciconinfo->bBitsPerPixel,
1611                                 (char *)(ciconinfo + 1)
1612                                 + ciconinfo->nHeight *
1613                                 BITMAP_GetWidthBytes (ciconinfo->nWidth,1) );
1614     iconinfo->hbmMask = CreateBitmap ( ciconinfo->nWidth, ciconinfo->nHeight,
1615                                 1, 1, (char *)(ciconinfo + 1));
1616
1617     GlobalUnlock16(hIcon);
1618
1619     return TRUE;
1620 }
1621
1622 /**********************************************************************
1623  *          CreateIconIndirect          (USER32.78)
1624  */
1625 HICON WINAPI CreateIconIndirect(LPICONINFO iconinfo) {
1626     BITMAPOBJ *bmpXor,*bmpAnd;
1627     HICON hObj;
1628     int sizeXor,sizeAnd;
1629
1630     bmpXor = (BITMAPOBJ *) GDI_GetObjPtr( iconinfo->hbmColor, BITMAP_MAGIC );
1631     bmpAnd = (BITMAPOBJ *) GDI_GetObjPtr( iconinfo->hbmMask, BITMAP_MAGIC );
1632
1633     sizeXor = bmpXor->bitmap.bmHeight * bmpXor->bitmap.bmWidthBytes;
1634     sizeAnd = bmpAnd->bitmap.bmHeight * bmpAnd->bitmap.bmWidthBytes;
1635
1636     hObj = GlobalAlloc16( GMEM_MOVEABLE, 
1637                      sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
1638     if (hObj)
1639     {
1640         CURSORICONINFO *info;
1641
1642         info = (CURSORICONINFO *)GlobalLock16( hObj );
1643         info->ptHotSpot.x   = iconinfo->xHotspot;
1644         info->ptHotSpot.y   = iconinfo->yHotspot;
1645         info->nWidth        = bmpXor->bitmap.bmWidth;
1646         info->nHeight       = bmpXor->bitmap.bmHeight;
1647         info->nWidthBytes   = bmpXor->bitmap.bmWidthBytes;
1648         info->bPlanes       = bmpXor->bitmap.bmPlanes;
1649         info->bBitsPerPixel = bmpXor->bitmap.bmBitsPixel;
1650
1651         /* Transfer the bitmap bits to the CURSORICONINFO structure */
1652
1653         GetBitmapBits( iconinfo->hbmMask ,sizeAnd,(char*)(info + 1) );
1654         GetBitmapBits( iconinfo->hbmColor,sizeXor,(char*)(info + 1) +sizeAnd);
1655         GlobalUnlock16( hObj );
1656     }
1657     return hObj;
1658 }
1659
1660
1661 /**********************************************************************
1662  *          
1663  DrawIconEx16           (USER.394)
1664  */
1665 BOOL16 WINAPI DrawIconEx16 (HDC16 hdc, INT16 xLeft, INT16 yTop, HICON16 hIcon,
1666                             INT16 cxWidth, INT16 cyWidth, UINT16 istep,
1667                             HBRUSH16 hbr, UINT16 flags)
1668 {
1669     return DrawIconEx(hdc, xLeft, yTop, hIcon, cxWidth, cyWidth,
1670                         istep, hbr, flags);
1671 }
1672
1673
1674 /******************************************************************************
1675  * DrawIconEx32 [USER32.160]  Draws an icon or cursor on device context
1676  *
1677  * NOTES
1678  *    Why is this using SM_CXICON instead of SM_CXCURSOR?
1679  *
1680  * PARAMS
1681  *    hdc     [I] Handle to device context
1682  *    x0      [I] X coordinate of upper left corner
1683  *    y0      [I] Y coordinate of upper left corner
1684  *    hIcon   [I] Handle to icon to draw
1685  *    cxWidth [I] Width of icon
1686  *    cyWidth [I] Height of icon
1687  *    istep   [I] Index of frame in animated cursor
1688  *    hbr     [I] Handle to background brush
1689  *    flags   [I] Icon-drawing flags
1690  *
1691  * RETURNS
1692  *    Success: TRUE
1693  *    Failure: FALSE
1694  */
1695 BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
1696                             INT cxWidth, INT cyWidth, UINT istep, 
1697                             HBRUSH hbr, UINT flags )
1698 {
1699     CURSORICONINFO *ptr = (CURSORICONINFO *)GlobalLock16 (hIcon);
1700     HDC hDC_off = 0, hMemDC = CreateCompatibleDC (hdc);
1701     BOOL result = FALSE, DoOffscreen = FALSE;
1702     HBITMAP hB_off = 0, hOld = 0;
1703
1704     if (!ptr) return FALSE;
1705
1706     if (istep)
1707         FIXME(icon, "Ignoring istep=%d\n", istep);
1708     if (flags & DI_COMPAT)
1709         FIXME(icon, "Ignoring flag DI_COMPAT\n");
1710
1711     /* Calculate the size of the destination image.  */
1712     if (cxWidth == 0)
1713     {
1714       if (flags & DI_DEFAULTSIZE)
1715         cxWidth = GetSystemMetrics (SM_CXICON);
1716       else
1717         cxWidth = ptr->nWidth;
1718     }
1719     if (cyWidth == 0)
1720     {
1721       if (flags & DI_DEFAULTSIZE)
1722         cyWidth = GetSystemMetrics (SM_CYICON);
1723       else
1724         cyWidth = ptr->nHeight;
1725     }
1726
1727     if (!(DoOffscreen = (hbr >= STOCK_WHITE_BRUSH) && (hbr <= 
1728       STOCK_HOLLOW_BRUSH)))
1729     {
1730         GDIOBJHDR *object = (GDIOBJHDR *) GDI_HEAP_LOCK(hbr);
1731         if (object)
1732         {
1733             UINT16 magic = object->wMagic;
1734             GDI_HEAP_UNLOCK(hbr);
1735             DoOffscreen = magic == BRUSH_MAGIC;
1736         }
1737     }
1738     if (DoOffscreen) {
1739       RECT r = {0, 0, cxWidth, cxWidth};
1740
1741       hDC_off = CreateCompatibleDC(hdc);
1742       hB_off = CreateCompatibleBitmap(hdc, cxWidth, cyWidth);
1743       if (hDC_off && hB_off) {
1744         hOld = SelectObject(hDC_off, hB_off);
1745         FillRect(hDC_off, &r, hbr);
1746       }
1747     };
1748
1749     if (hMemDC && (!DoOffscreen || (hDC_off && hB_off)))
1750     {
1751         HBITMAP hXorBits, hAndBits;
1752         COLORREF  oldFg, oldBg;
1753         INT     nStretchMode;
1754
1755         nStretchMode = SetStretchBltMode (hdc, STRETCH_DELETESCANS);
1756
1757         hXorBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
1758                                     ptr->bPlanes, ptr->bBitsPerPixel,
1759                                     (char *)(ptr + 1)
1760                                     + ptr->nHeight *
1761                                     BITMAP_GetWidthBytes(ptr->nWidth,1) );
1762         hAndBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
1763                                     1, 1, (char *)(ptr+1) );
1764         oldFg = SetTextColor( hdc, RGB(0,0,0) );
1765         oldBg = SetBkColor( hdc, RGB(255,255,255) );
1766
1767         if (hXorBits && hAndBits)
1768         {
1769             HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
1770             if (flags & DI_MASK)
1771             {
1772               if (DoOffscreen) 
1773                 StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
1774                               hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
1775               else 
1776                 StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
1777                               hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
1778             }
1779             SelectObject( hMemDC, hXorBits );
1780             if (flags & DI_IMAGE)
1781             {
1782               if (DoOffscreen) 
1783                 StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
1784                           hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
1785               else
1786                 StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
1787                               hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
1788             }
1789             SelectObject( hMemDC, hBitTemp );
1790             result = TRUE;
1791         }
1792
1793         SetTextColor( hdc, oldFg );
1794         SetBkColor( hdc, oldBg );
1795         if (hXorBits) DeleteObject( hXorBits );
1796         if (hAndBits) DeleteObject( hAndBits );
1797         SetStretchBltMode (hdc, nStretchMode);
1798         if (DoOffscreen) {
1799           BitBlt(hdc, x0, y0, cxWidth, cyWidth, hDC_off, 0, 0, SRCCOPY);
1800           SelectObject(hDC_off, hOld);
1801         }
1802     }
1803     if (hMemDC) DeleteDC( hMemDC );
1804     if (hDC_off) DeleteDC(hDC_off);
1805     if (hB_off) DeleteObject(hB_off);
1806     GlobalUnlock16( hIcon );
1807     return result;
1808 }