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