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