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