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