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