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