2 * PROJECT: ReactOS user32.dll
3 * COPYRIGHT: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/user32/windows/class.c
5 * PURPOSE: Window classes
6 * PROGRAMMER: Jérôme Gardou (jerome.gardou@reactos.org)
11 #include <wine/debug.h>
13 WINE_DEFAULT_DEBUG_CHANNEL(cursor
);
14 WINE_DECLARE_DEBUG_CHANNEL(icon
);
15 //WINE_DECLARE_DEBUG_CHANNEL(resource);
17 /************* USER32 INTERNAL FUNCTIONS **********/
19 /* This callback routine is called directly after switching to gui mode */
22 User32SetupDefaultCursors(PVOID Arguments
,
25 BOOL
*DefaultCursor
= (BOOL
*)Arguments
;
30 /* set default cursor */
31 hCursor
= LoadCursorW(0, (LPCWSTR
)IDC_ARROW
);
36 /* FIXME load system cursor scheme */
38 hCursor
= LoadCursorW(0, (LPCWSTR
)IDC_ARROW
);
42 return(ZwCallbackReturn(&hCursor
, sizeof(HCURSOR
), STATUS_SUCCESS
));
45 BOOL
get_icon_size(HICON hIcon
, SIZE
*size
)
47 return NtUserGetIconSize(hIcon
, 0, &size
->cx
, &size
->cy
);
50 HCURSOR
CursorIconToCursor(HICON hIcon
, BOOL SemiTransparent
)
56 /************* IMPLEMENTATION HELPERS ******************/
58 static const WCHAR DISPLAYW
[] = L
"DISPLAY";
60 static void *map_fileW( LPCWSTR name
, LPDWORD filesize
)
62 HANDLE hFile
, hMapping
;
65 hFile
= CreateFileW( name
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
66 OPEN_EXISTING
, FILE_FLAG_RANDOM_ACCESS
, 0 );
67 if (hFile
!= INVALID_HANDLE_VALUE
)
69 hMapping
= CreateFileMappingW( hFile
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
72 ptr
= MapViewOfFile( hMapping
, FILE_MAP_READ
, 0, 0, 0 );
73 CloseHandle( hMapping
);
75 *filesize
= GetFileSize( hFile
, NULL
);
82 static int get_dib_image_size( int width
, int height
, int depth
)
84 return (((width
* depth
+ 31) / 8) & ~3) * abs( height
);
87 static BOOL
is_dib_monochrome( const BITMAPINFO
* info
)
89 if (info
->bmiHeader
.biBitCount
!= 1) return FALSE
;
91 if (info
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
93 const RGBTRIPLE
*rgb
= ((const BITMAPCOREINFO
*)info
)->bmciColors
;
95 /* Check if the first color is black */
96 if ((rgb
->rgbtRed
== 0) && (rgb
->rgbtGreen
== 0) && (rgb
->rgbtBlue
== 0))
100 /* Check if the second color is white */
101 return ((rgb
->rgbtRed
== 0xff) && (rgb
->rgbtGreen
== 0xff)
102 && (rgb
->rgbtBlue
== 0xff));
106 else /* assume BITMAPINFOHEADER */
108 const RGBQUAD
*rgb
= info
->bmiColors
;
110 /* Check if the first color is black */
111 if ((rgb
->rgbRed
== 0) && (rgb
->rgbGreen
== 0) &&
112 (rgb
->rgbBlue
== 0) && (rgb
->rgbReserved
== 0))
116 /* Check if the second color is white */
117 return ((rgb
->rgbRed
== 0xff) && (rgb
->rgbGreen
== 0xff)
118 && (rgb
->rgbBlue
== 0xff) && (rgb
->rgbReserved
== 0));
124 static int bitmap_info_size( const BITMAPINFO
* info
, WORD coloruse
)
126 unsigned int colors
, size
, masks
= 0;
128 if (info
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
130 const BITMAPCOREHEADER
*core
= (const BITMAPCOREHEADER
*)info
;
131 colors
= (core
->bcBitCount
<= 8) ? 1 << core
->bcBitCount
: 0;
132 return sizeof(BITMAPCOREHEADER
) + colors
*
133 ((coloruse
== DIB_RGB_COLORS
) ? sizeof(RGBTRIPLE
) : sizeof(WORD
));
135 else /* assume BITMAPINFOHEADER */
137 colors
= info
->bmiHeader
.biClrUsed
;
138 if (colors
> 256) /* buffer overflow otherwise */
140 if (!colors
&& (info
->bmiHeader
.biBitCount
<= 8))
141 colors
= 1 << info
->bmiHeader
.biBitCount
;
142 if (info
->bmiHeader
.biCompression
== BI_BITFIELDS
) masks
= 3;
143 size
= max( info
->bmiHeader
.biSize
, sizeof(BITMAPINFOHEADER
) + masks
* sizeof(DWORD
) );
144 return size
+ colors
* ((coloruse
== DIB_RGB_COLORS
) ? sizeof(RGBQUAD
) : sizeof(WORD
));
148 static int DIB_GetBitmapInfo( const BITMAPINFOHEADER
*header
, LONG
*width
,
149 LONG
*height
, WORD
*bpp
, DWORD
*compr
)
151 if (header
->biSize
== sizeof(BITMAPCOREHEADER
))
153 const BITMAPCOREHEADER
*core
= (const BITMAPCOREHEADER
*)header
;
154 *width
= core
->bcWidth
;
155 *height
= core
->bcHeight
;
156 *bpp
= core
->bcBitCount
;
160 else if (header
->biSize
== sizeof(BITMAPINFOHEADER
) ||
161 header
->biSize
== sizeof(BITMAPV4HEADER
) ||
162 header
->biSize
== sizeof(BITMAPV5HEADER
))
164 *width
= header
->biWidth
;
165 *height
= header
->biHeight
;
166 *bpp
= header
->biBitCount
;
167 *compr
= header
->biCompression
;
170 ERR("(%d): unknown/wrong size for header\n", header
->biSize
);
174 /************* IMPLEMENTATION CORE ****************/
176 static BOOL
CURSORICON_GetIconInfoFromBMI(
177 _Inout_ ICONINFO
* pii
,
178 _In_
const BITMAPINFO
*pbmi
,
183 UINT ubmiSize
= bitmap_info_size(pbmi
, DIB_RGB_COLORS
);
184 BOOL monochrome
= is_dib_monochrome(pbmi
);
190 BITMAPINFO
* pbmiCopy
;
191 HBITMAP hbmpOld
= NULL
;
192 BOOL bResult
= FALSE
;
193 const VOID
*pvColor
, *pvMask
;
195 ibmpType
= DIB_GetBitmapInfo(&pbmi
->bmiHeader
, &width
, &height
, &bpp
, &compr
);
200 /* No compression for icons */
204 /* Fix the hotspot coords */
207 if(cxDesired
!= pbmi
->bmiHeader
.biWidth
)
208 pii
->xHotspot
= (pii
->xHotspot
* cxDesired
) / pbmi
->bmiHeader
.biWidth
;
209 if(cxDesired
!= (pbmi
->bmiHeader
.biHeight
/2))
210 pii
->yHotspot
= (pii
->yHotspot
* cyDesired
* 2) / pbmi
->bmiHeader
.biHeight
;
213 hdcScreen
= CreateDCW(DISPLAYW
, NULL
, NULL
, NULL
);
216 hdc
= CreateCompatibleDC(hdcScreen
);
223 pbmiCopy
= HeapAlloc(GetProcessHeap(), 0, max(ubmiSize
, FIELD_OFFSET(BITMAPINFO
, bmiColors
[3])));
226 RtlCopyMemory(pbmiCopy
, pbmi
, ubmiSize
);
228 /* In an icon/cursor, the BITMAPINFO holds twice the height */
229 if(pbmiCopy
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
230 ((BITMAPCOREHEADER
*)&pbmiCopy
->bmiHeader
)->bcHeight
/= 2;
232 pbmiCopy
->bmiHeader
.biHeight
/= 2;
234 pvColor
= (const char*)pbmi
+ ubmiSize
;
235 pvMask
= (const char*)pvColor
+
236 get_dib_image_size(pbmi
->bmiHeader
.biWidth
, pbmiCopy
->bmiHeader
.biHeight
, pbmi
->bmiHeader
.biBitCount
);
241 /* Create the 1bpp bitmap which will contain everything */
242 pii
->hbmColor
= NULL
;
243 pii
->hbmMask
= CreateCompatibleBitmap(hdc
, cxDesired
, cyDesired
* 2);
246 hbmpOld
= SelectObject(hdc
, pii
->hbmMask
);
250 if(!StretchDIBits(hdc
, 0, cyDesired
, cxDesired
, cyDesired
,
251 0, 0, pbmiCopy
->bmiHeader
.biWidth
, pbmiCopy
->bmiHeader
.biHeight
,
252 pvColor
, pbmiCopy
, DIB_RGB_COLORS
, SRCCOPY
))
257 /* Create the bitmap. It has to be compatible with the screen surface */
258 pii
->hbmColor
= CreateCompatibleBitmap(hdcScreen
, cxDesired
, cyDesired
);
261 /* Create the 1bpp mask bitmap */
262 pii
->hbmMask
= CreateCompatibleBitmap(hdc
, cxDesired
, cyDesired
);
265 hbmpOld
= SelectObject(hdc
, pii
->hbmColor
);
268 if(!StretchDIBits(hdc
, 0, 0, cxDesired
, cyDesired
,
269 0, 0, pbmiCopy
->bmiHeader
.biWidth
, pbmiCopy
->bmiHeader
.biHeight
,
270 pvColor
, pbmiCopy
, DIB_RGB_COLORS
, SRCCOPY
))
273 /* Now convert the info to monochrome for the mask bits */
274 pbmiCopy
->bmiHeader
.biBitCount
= 1;
275 /* Handle the CORE/INFO difference */
276 if (pbmiCopy
->bmiHeader
.biSize
!= sizeof(BITMAPCOREHEADER
))
278 RGBQUAD
*rgb
= pbmiCopy
->bmiColors
;
280 pbmiCopy
->bmiHeader
.biClrUsed
= pbmiCopy
->bmiHeader
.biClrImportant
= 2;
281 rgb
[0].rgbBlue
= rgb
[0].rgbGreen
= rgb
[0].rgbRed
= 0x00;
282 rgb
[1].rgbBlue
= rgb
[1].rgbGreen
= rgb
[1].rgbRed
= 0xff;
283 rgb
[0].rgbReserved
= rgb
[1].rgbReserved
= 0;
287 RGBTRIPLE
*rgb
= (RGBTRIPLE
*)(((BITMAPCOREHEADER
*)pbmiCopy
) + 1);
289 rgb
[0].rgbtBlue
= rgb
[0].rgbtGreen
= rgb
[0].rgbtRed
= 0x00;
290 rgb
[1].rgbtBlue
= rgb
[1].rgbtGreen
= rgb
[1].rgbtRed
= 0xff;
293 /* Set the mask bits */
294 if(!SelectObject(hdc
, pii
->hbmMask
))
296 bResult
= StretchDIBits(hdc
, 0, 0, cxDesired
, cyDesired
,
297 0, 0, pbmiCopy
->bmiHeader
.biWidth
, pbmiCopy
->bmiHeader
.biHeight
,
298 pvMask
, pbmiCopy
, DIB_RGB_COLORS
, SRCCOPY
) != 0;
302 if(hbmpOld
) SelectObject(hdc
, hbmpOld
);
304 if(pbmiCopy
) HeapFree(GetProcessHeap(), 0, pbmiCopy
);
305 /* Clean up in case of failure */
308 if(pii
->hbmMask
) DeleteObject(pii
->hbmMask
);
309 if(pii
->hbmColor
) DeleteObject(pii
->hbmColor
);
317 _In_opt_ HINSTANCE hinst
,
318 _In_ LPCWSTR lpszName
,
324 const BITMAPINFO
* pbmi
;
325 BITMAPINFO
* pbmiScaled
= NULL
;
326 BITMAPINFO
* pbmiCopy
= NULL
;
327 const VOID
* pvMapping
;
332 HDC hdcScreen
= NULL
;
334 HBITMAP hbmpRet
, hbmpOld
;
336 /* Map the bitmap info */
337 if(fuLoad
& LR_LOADFROMFILE
)
339 const BITMAPFILEHEADER
* pbmfh
;
341 pvMapping
= map_fileW(lpszName
, NULL
);
345 if (pbmfh
->bfType
!= 0x4d42 /* 'BM' */)
347 WARN("Invalid/unsupported bitmap format!\n");
350 pbmi
= (const BITMAPINFO
*)(pbmfh
+ 1);
352 /* Get the image bits */
354 dwOffset
= pbmfh
->bfOffBits
- sizeof(BITMAPFILEHEADER
);
360 /* Caller wants an OEM bitmap */
362 hinst
= User32Instance
;
363 hrsrc
= FindResourceW(hinst
, lpszName
, (LPWSTR
)RT_BITMAP
);
366 hgRsrc
= LoadResource(hinst
, hrsrc
);
369 pbmi
= LockResource(hgRsrc
);
374 /* See if we must scale the bitmap */
375 iBMISize
= bitmap_info_size(pbmi
, DIB_RGB_COLORS
);
377 /* Get a pointer to the image data */
378 pvBits
= (char*)pbmi
+ (dwOffset
? dwOffset
: iBMISize
);
380 /* Create a copy of the info describing the bitmap in the file */
381 pbmiCopy
= HeapAlloc(GetProcessHeap(), 0, iBMISize
);
384 CopyMemory(pbmiCopy
, pbmi
, iBMISize
);
386 /* Fix it up, if needed */
387 if(fuLoad
& (LR_LOADTRANSPARENT
| LR_LOADMAP3DCOLORS
))
389 WORD bpp
, incr
, numColors
;
392 COLORREF crWindow
, cr3DShadow
, cr3DFace
, cr3DLight
;
393 BYTE pixel
= *((BYTE
*)pvBits
);
396 if(pbmiCopy
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
398 bpp
= ((BITMAPCOREHEADER
*)&pbmiCopy
->bmiHeader
)->bcBitCount
;
399 numColors
= 1 << bpp
;
400 /* BITMAPCOREINFO holds RGBTRIPLEs */
405 bpp
= pbmiCopy
->bmiHeader
.biBitCount
;
406 /* BITMAPINFOHEADER holds RGBQUADs */
408 numColors
= pbmiCopy
->bmiHeader
.biClrUsed
;
409 if(numColors
> 256) numColors
= 256;
410 if (!numColors
&& (bpp
<= 8)) numColors
= 1 << bpp
;
416 pbmiColors
= (char*)pbmiCopy
+ pbmiCopy
->bmiHeader
.biSize
;
418 /* Get the relevant colors */
419 crWindow
= GetSysColor(COLOR_WINDOW
);
420 cr3DShadow
= GetSysColor(COLOR_3DSHADOW
);
421 cr3DFace
= GetSysColor(COLOR_3DFACE
);
422 cr3DLight
= GetSysColor(COLOR_3DLIGHT
);
424 /* Fix the transparent palette entry */
425 if(fuLoad
& LR_LOADTRANSPARENT
)
429 case 1: pixel
>>= 7; break;
430 case 4: pixel
>>= 4; break;
433 FIXME("Unhandled bit depth %d.\n", bpp
);
437 if(pixel
>= numColors
)
439 ERR("Wrong pixel passed in.\n");
443 /* If both flags are set, we must use COLOR_3DFACE */
444 if(fuLoad
& LR_LOADMAP3DCOLORS
) crWindow
= cr3DFace
;
446 /* Define the color */
447 ptr
= (RGBTRIPLE
*)(pbmiColors
+ pixel
*incr
);
448 ptr
->rgbtBlue
= GetBValue(crWindow
);
449 ptr
->rgbtGreen
= GetGValue(crWindow
);
450 ptr
->rgbtRed
= GetRValue(crWindow
);
454 /* If we are here, then LR_LOADMAP3DCOLORS is set without LR_TRANSPARENT */
455 for(i
= 0; i
<numColors
; i
++)
457 ptr
= (RGBTRIPLE
*)(pbmiColors
+ i
*incr
);
458 if((ptr
->rgbtBlue
== ptr
->rgbtRed
) && (ptr
->rgbtBlue
== ptr
->rgbtGreen
))
460 if(ptr
->rgbtBlue
== 128)
462 ptr
->rgbtBlue
= GetBValue(cr3DShadow
);
463 ptr
->rgbtGreen
= GetGValue(cr3DShadow
);
464 ptr
->rgbtRed
= GetRValue(cr3DShadow
);
466 if(ptr
->rgbtBlue
== 192)
468 ptr
->rgbtBlue
= GetBValue(cr3DFace
);
469 ptr
->rgbtGreen
= GetGValue(cr3DFace
);
470 ptr
->rgbtRed
= GetRValue(cr3DFace
);
472 if(ptr
->rgbtBlue
== 223)
474 ptr
->rgbtBlue
= GetBValue(cr3DLight
);
475 ptr
->rgbtGreen
= GetGValue(cr3DLight
);
476 ptr
->rgbtRed
= GetRValue(cr3DLight
);
483 if(fuLoad
& LR_CREATEDIBSECTION
)
485 /* Allocate the BMI describing the new bitmap */
486 pbmiScaled
= HeapAlloc(GetProcessHeap(), 0, iBMISize
);
489 CopyMemory(pbmiScaled
, pbmiCopy
, iBMISize
);
492 if(pbmiScaled
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
494 BITMAPCOREHEADER
* pbmch
= (BITMAPCOREHEADER
*)&pbmiScaled
->bmiHeader
;
496 cxDesired
= pbmch
->bcWidth
;
498 cyDesired
== pbmch
->bcHeight
;
499 else if(pbmch
->bcHeight
< 0)
500 cyDesired
= -cyDesired
;
502 pbmch
->bcWidth
= cxDesired
;
503 pbmch
->bcHeight
= cyDesired
;
507 if ((pbmi
->bmiHeader
.biHeight
> 65535) || (pbmi
->bmiHeader
.biWidth
> 65535)) {
508 WARN("Broken BITMAPINFO!\n");
513 cxDesired
= pbmi
->bmiHeader
.biWidth
;
515 cyDesired
= pbmi
->bmiHeader
.biHeight
;
516 else if(pbmi
->bmiHeader
.biHeight
< 0)
517 cyDesired
= -cyDesired
;
519 pbmiScaled
->bmiHeader
.biWidth
= cxDesired
;
520 pbmiScaled
->bmiHeader
.biHeight
= cyDesired
;
521 /* No compression for DIB sections */
522 if(fuLoad
& LR_CREATEDIBSECTION
)
523 pbmiScaled
->bmiHeader
.biCompression
= BI_RGB
;
528 if(cyDesired
< 0) cyDesired
= -cyDesired
;
530 /* We need a device context */
531 hdcScreen
= CreateDCW(DISPLAYW
, NULL
, NULL
, NULL
);
534 hdc
= CreateCompatibleDC(hdcScreen
);
538 /* Now create the bitmap */
539 if(fuLoad
& LR_CREATEDIBSECTION
)
540 hbmpRet
= CreateDIBSection(hdc
, pbmiScaled
, DIB_RGB_COLORS
, NULL
, 0, 0);
543 if(is_dib_monochrome(pbmiCopy
) || (fuLoad
& LR_MONOCHROME
))
544 hbmpRet
= CreateBitmap(cxDesired
, cyDesired
, 1, 1, NULL
);
546 hbmpRet
= CreateCompatibleBitmap(hdcScreen
, cxDesired
, cyDesired
);
552 hbmpOld
= SelectObject(hdc
, hbmpRet
);
555 if(!StretchDIBits(hdc
, 0, 0, cxDesired
, cyDesired
,
556 0, 0, pbmi
->bmiHeader
.biWidth
, pbmi
->bmiHeader
.biWidth
,
557 pvBits
, pbmiCopy
, DIB_RGB_COLORS
, SRCCOPY
))
559 ERR("StretchDIBits failed!.\n");
560 SelectObject(hdc
, hbmpOld
);
561 DeleteObject(hbmpRet
);
566 SelectObject(hdc
, hbmpOld
);
574 HeapFree(GetProcessHeap(), 0, pbmiScaled
);
576 HeapFree(GetProcessHeap(), 0, pbmiCopy
);
577 if (fuLoad
& LR_LOADFROMFILE
)
578 UnmapViewOfFile( pvMapping
);
580 FreeResource(hgRsrc
);
585 #include "pshpack1.h"
596 } CURSORICONFILEDIRENTRY
;
603 CURSORICONFILEDIRENTRY idEntries
[1];
610 CURSORICON_LoadFromFileW(
611 _In_ LPCWSTR lpszName
,
618 CURSORICONDIR
* fakeDir
;
619 CURSORICONDIRENTRY
* fakeEntry
;
620 CURSORICONFILEDIRENTRY
*entry
;
621 CURSORICONFILEDIR
*dir
;
628 TRACE("loading %s\n", debugstr_w( lpszName
));
630 bits
= map_fileW( lpszName
, &filesize
);
634 /* Check for .ani. */
635 if (memcmp( bits
, "RIFF", 4 ) == 0)
641 dir
= (CURSORICONFILEDIR
*) bits
;
642 if ( filesize
< sizeof(*dir
) )
645 if ( filesize
< (sizeof(*dir
) + sizeof(dir
->idEntries
[0])*(dir
->idCount
-1)) )
650 * We allocate a buffer, fake it as if it was a pointer to a resource in a module,
651 * pass it to LookupIconIdFromDirectoryEx and get back the index we have to use
653 fakeDir
= HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(CURSORICONDIR
, idEntries
[dir
->idCount
]));
656 fakeDir
->idReserved
= 0;
657 fakeDir
->idType
= dir
->idType
;
658 fakeDir
->idCount
= dir
->idCount
;
659 for(i
= 0; i
<dir
->idCount
; i
++)
661 fakeEntry
= &fakeDir
->idEntries
[i
];
662 entry
= &dir
->idEntries
[i
];
663 /* Take this as an occasion to perform a size check */
664 if((entry
->dwDIBOffset
+ entry
->dwDIBSize
) > filesize
)
666 /* File icon/cursors are not like resource ones */
669 fakeEntry
->ResInfo
.icon
.bWidth
= entry
->bWidth
;
670 fakeEntry
->ResInfo
.icon
.bHeight
= entry
->bHeight
;
671 fakeEntry
->ResInfo
.icon
.bColorCount
= 0;
672 fakeEntry
->ResInfo
.icon
.bReserved
= 0;
676 fakeEntry
->ResInfo
.cursor
.wWidth
= entry
->bWidth
;
677 fakeEntry
->ResInfo
.cursor
.wHeight
= entry
->bHeight
;
679 /* Let's assume there's always one plane */
680 fakeEntry
->wPlanes
= 1;
681 /* We must get the bitcount from the BITMAPINFOHEADER itself */
682 fakeEntry
->wBitCount
= ((BITMAPINFOHEADER
*)((char *)dir
+ entry
->dwDIBOffset
))->biBitCount
;
683 fakeEntry
->dwBytesInRes
= entry
->dwDIBSize
;
684 fakeEntry
->wResId
= i
+ 1;
687 /* Now call LookupIconIdFromResourceEx */
688 i
= LookupIconIdFromDirectoryEx((PBYTE
)fakeDir
, bIcon
, cxDesired
, cyDesired
, fuLoad
& LR_MONOCHROME
);
689 /* We don't need this anymore */
690 HeapFree(GetProcessHeap(), 0, fakeDir
);
693 WARN("Unable to get a fit entry index.\n");
698 entry
= &dir
->idEntries
[i
-1];
699 /* A bit of preparation */
700 ii
.xHotspot
= entry
->xHotspot
;
701 ii
.yHotspot
= entry
->yHotspot
;
705 if(!CURSORICON_GetIconInfoFromBMI(&ii
, (BITMAPINFO
*)&bits
[entry
->dwDIBOffset
], cxDesired
, cyDesired
))
708 /* Create the icon. NOTE: there's no LR_SHARED icons if they are created from file */
709 hRet
= CreateIconIndirect(&ii
);
712 DeleteObject(ii
.hbmMask
);
713 DeleteObject(ii
.hbmColor
);
716 UnmapViewOfFile(bits
);
722 CURSORICON_LoadImageW(
723 _In_opt_ HINSTANCE hinst
,
724 _In_ LPCWSTR lpszName
,
732 HANDLE handle
, hCurIcon
= NULL
;
738 UNICODE_STRING ustrRsrc
;
739 UNICODE_STRING ustrModule
= {0, 0, NULL
};
741 /* Fix width/height */
742 if(fuLoad
& LR_DEFAULTSIZE
)
744 if(!cxDesired
) cxDesired
= GetSystemMetrics(bIcon
? SM_CXICON
: SM_CXCURSOR
);
745 if(!cyDesired
) cyDesired
= GetSystemMetrics(bIcon
? SM_CYICON
: SM_CYCURSOR
);
748 if(fuLoad
& LR_LOADFROMFILE
)
750 return CURSORICON_LoadFromFileW(lpszName
, cxDesired
, cyDesired
, fuLoad
, bIcon
);
753 /* Check if caller wants OEM icons */
755 hinst
= User32Instance
;
757 if(fuLoad
& LR_SHARED
)
759 DWORD size
= MAX_PATH
;
761 TRACE("Checking for an LR_SHARED cursor/icon.\n");
762 /* Prepare the resource name string */
763 if(IS_INTRESOURCE(lpszName
))
765 ustrRsrc
.Buffer
= (LPWSTR
)lpszName
;
767 ustrRsrc
.MaximumLength
= 0;
770 RtlInitUnicodeString(&ustrRsrc
, lpszName
);
772 /* Prepare the module name string */
773 ustrModule
.Buffer
= HeapAlloc(GetProcessHeap(), 0, size
*sizeof(WCHAR
));
777 DWORD ret
= GetModuleFileName(hinst
, ustrModule
.Buffer
, size
);
780 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
785 ustrModule
.Length
= ret
;
786 ustrModule
.MaximumLength
= size
;
790 ustrModule
.Buffer
= HeapReAlloc(GetProcessHeap(), 0, ustrModule
.Buffer
, size
*sizeof(WCHAR
));
794 hCurIcon
= NtUserFindExistingCursorIcon(&ustrModule
, &ustrRsrc
, cxDesired
, cyDesired
);
797 /* Woohoo, got it! */
799 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
804 /* Find resource ID */
805 hrsrc
= FindResourceW(
808 (LPWSTR
)(bIcon
? RT_GROUP_ICON
: RT_GROUP_CURSOR
));
810 /* We let FindResource, LoadResource, etc. call SetLastError */
814 handle
= LoadResource(hinst
, hrsrc
);
818 dir
= LockResource(handle
);
822 wResId
= LookupIconIdFromDirectoryEx((PBYTE
)dir
, bIcon
, cxDesired
, cyDesired
, fuLoad
& LR_MONOCHROME
);
823 FreeResource(handle
);
825 /* Get the relevant resource pointer */
826 hrsrc
= FindResourceW(
828 MAKEINTRESOURCEW(wResId
),
829 (LPWSTR
)(bIcon
? RT_ICON
: RT_CURSOR
));
833 handle
= LoadResource(hinst
, hrsrc
);
837 bits
= LockResource(handle
);
840 FreeResource(handle
);
844 /* Get the hotspot */
847 ii
.xHotspot
= cxDesired
/2;
848 ii
.yHotspot
= cyDesired
/2;
852 SHORT
* ptr
= (SHORT
*)bits
;
853 ii
.xHotspot
= ptr
[0];
854 ii
.yHotspot
= ptr
[1];
855 bits
+= 2*sizeof(SHORT
);
859 /* Get the bitmaps */
860 bStatus
= CURSORICON_GetIconInfoFromBMI(
866 FreeResource( handle
);
871 /* Create the handle */
872 hCurIcon
= NtUserxCreateEmptyCurObject(bIcon
? 0 : 1);
875 DeleteObject(ii
.hbmMask
);
876 if(ii
.hbmColor
) DeleteObject(ii
.hbmColor
);
881 if(fuLoad
& LR_SHARED
)
882 bStatus
= NtUserSetCursorIconData(hCurIcon
, &ustrModule
, &ustrRsrc
, &ii
);
884 bStatus
= NtUserSetCursorIconData(hCurIcon
, NULL
, NULL
, &ii
);
888 NtUserDestroyCursor(hCurIcon
, TRUE
);
892 DeleteObject(ii
.hbmMask
);
893 if(ii
.hbmColor
) DeleteObject(ii
.hbmColor
);
896 if(ustrModule
.Buffer
)
897 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
915 objSize
= GetObjectW( hbmp
, sizeof(ds
), &ds
);
916 if (!objSize
) return 0;
917 if ((cxDesired
< 0) || (cyDesired
< 0)) return 0;
919 if (fuFlags
& LR_COPYFROMRESOURCE
)
921 FIXME("The flag LR_COPYFROMRESOURCE is not implemented for bitmaps\n");
924 if (fuFlags
& LR_COPYRETURNORG
)
926 FIXME("The flag LR_COPYRETURNORG is not implemented for bitmaps\n");
929 if (cxDesired
== 0) cxDesired
= ds
.dsBm
.bmWidth
;
930 if (cyDesired
== 0) cyDesired
= ds
.dsBm
.bmHeight
;
932 /* Allocate memory for a BITMAPINFOHEADER structure and a
933 color table. The maximum number of colors in a color table
934 is 256 which corresponds to a bitmap with depth 8.
935 Bitmaps with higher depths don't have color tables. */
936 bi
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
) + 256 * sizeof(RGBQUAD
));
939 bi
->bmiHeader
.biSize
= sizeof(bi
->bmiHeader
);
940 bi
->bmiHeader
.biPlanes
= ds
.dsBm
.bmPlanes
;
941 bi
->bmiHeader
.biBitCount
= ds
.dsBm
.bmBitsPixel
;
942 bi
->bmiHeader
.biCompression
= BI_RGB
;
944 if (fuFlags
& LR_CREATEDIBSECTION
)
946 /* Create a DIB section. LR_MONOCHROME is ignored */
948 HDC dc
= CreateCompatibleDC(NULL
);
950 if (objSize
== sizeof(DIBSECTION
))
952 /* The source bitmap is a DIB.
953 Get its attributes to create an exact copy */
954 memcpy(bi
, &ds
.dsBmih
, sizeof(BITMAPINFOHEADER
));
957 /* Get the color table or the color masks */
958 GetDIBits(dc
, hbmp
, 0, ds
.dsBm
.bmHeight
, NULL
, bi
, DIB_RGB_COLORS
);
960 bi
->bmiHeader
.biWidth
= cxDesired
;
961 bi
->bmiHeader
.biHeight
= cyDesired
;
962 bi
->bmiHeader
.biSizeImage
= 0;
964 res
= CreateDIBSection(dc
, bi
, DIB_RGB_COLORS
, &bits
, NULL
, 0);
969 /* Create a device-dependent bitmap */
971 BOOL monochrome
= (fuFlags
& LR_MONOCHROME
);
973 if (objSize
== sizeof(DIBSECTION
))
975 /* The source bitmap is a DIB section.
976 Get its attributes */
977 HDC dc
= CreateCompatibleDC(NULL
);
978 bi
->bmiHeader
.biSize
= sizeof(bi
->bmiHeader
);
979 bi
->bmiHeader
.biBitCount
= ds
.dsBm
.bmBitsPixel
;
980 GetDIBits(dc
, hbmp
, 0, ds
.dsBm
.bmHeight
, NULL
, bi
, DIB_RGB_COLORS
);
983 if (!monochrome
&& ds
.dsBm
.bmBitsPixel
== 1)
985 /* Look if the colors of the DIB are black and white */
988 (bi
->bmiColors
[0].rgbRed
== 0xff
989 && bi
->bmiColors
[0].rgbGreen
== 0xff
990 && bi
->bmiColors
[0].rgbBlue
== 0xff
991 && bi
->bmiColors
[0].rgbReserved
== 0
992 && bi
->bmiColors
[1].rgbRed
== 0
993 && bi
->bmiColors
[1].rgbGreen
== 0
994 && bi
->bmiColors
[1].rgbBlue
== 0
995 && bi
->bmiColors
[1].rgbReserved
== 0)
997 (bi
->bmiColors
[0].rgbRed
== 0
998 && bi
->bmiColors
[0].rgbGreen
== 0
999 && bi
->bmiColors
[0].rgbBlue
== 0
1000 && bi
->bmiColors
[0].rgbReserved
== 0
1001 && bi
->bmiColors
[1].rgbRed
== 0xff
1002 && bi
->bmiColors
[1].rgbGreen
== 0xff
1003 && bi
->bmiColors
[1].rgbBlue
== 0xff
1004 && bi
->bmiColors
[1].rgbReserved
== 0);
1007 else if (!monochrome
)
1009 monochrome
= ds
.dsBm
.bmBitsPixel
== 1;
1014 res
= CreateBitmap(cxDesired
, cyDesired
, 1, 1, NULL
);
1018 HDC screenDC
= GetDC(NULL
);
1019 res
= CreateCompatibleBitmap(screenDC
, cxDesired
, cyDesired
);
1020 ReleaseDC(NULL
, screenDC
);
1026 /* Only copy the bitmap if it's a DIB section or if it's
1027 compatible to the screen */
1030 if (objSize
== sizeof(DIBSECTION
))
1032 copyContents
= TRUE
;
1036 HDC screenDC
= GetDC(NULL
);
1037 int screen_depth
= GetDeviceCaps(screenDC
, BITSPIXEL
);
1038 ReleaseDC(NULL
, screenDC
);
1040 copyContents
= (ds
.dsBm
.bmBitsPixel
== 1 || ds
.dsBm
.bmBitsPixel
== screen_depth
);
1045 /* The source bitmap may already be selected in a device context,
1046 use GetDIBits/StretchDIBits and not StretchBlt */
1051 dc
= CreateCompatibleDC(NULL
);
1053 bi
->bmiHeader
.biWidth
= ds
.dsBm
.bmWidth
;
1054 bi
->bmiHeader
.biHeight
= ds
.dsBm
.bmHeight
;
1055 bi
->bmiHeader
.biSizeImage
= 0;
1056 bi
->bmiHeader
.biClrUsed
= 0;
1057 bi
->bmiHeader
.biClrImportant
= 0;
1059 /* Fill in biSizeImage */
1060 GetDIBits(dc
, hbmp
, 0, ds
.dsBm
.bmHeight
, NULL
, bi
, DIB_RGB_COLORS
);
1061 bits
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, bi
->bmiHeader
.biSizeImage
);
1067 /* Get the image bits of the source bitmap */
1068 GetDIBits(dc
, hbmp
, 0, ds
.dsBm
.bmHeight
, bits
, bi
, DIB_RGB_COLORS
);
1070 /* Copy it to the destination bitmap */
1071 oldBmp
= SelectObject(dc
, res
);
1072 StretchDIBits(dc
, 0, 0, cxDesired
, cyDesired
,
1073 0, 0, ds
.dsBm
.bmWidth
, ds
.dsBm
.bmHeight
,
1074 bits
, bi
, DIB_RGB_COLORS
, SRCCOPY
);
1075 SelectObject(dc
, oldBmp
);
1077 HeapFree(GetProcessHeap(), 0, bits
);
1083 if (fuFlags
& LR_COPYDELETEORG
)
1088 HeapFree(GetProcessHeap(), 0, bi
);
1094 CURSORICON_CopyImage(
1105 if(fuFlags
& LR_COPYFROMRESOURCE
)
1107 /* Get the icon module/resource names */
1108 UNICODE_STRING ustrModule
;
1109 UNICODE_STRING ustrRsrc
;
1113 ustrModule
.MaximumLength
= MAX_PATH
;
1114 ustrRsrc
.MaximumLength
= 256;
1116 ustrModule
.Buffer
= HeapAlloc(GetProcessHeap(), 0, ustrModule
.MaximumLength
* sizeof(WCHAR
));
1117 if(!ustrModule
.Buffer
)
1119 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1122 /* Keep track of the buffer for the resource, NtUserGetIconInfo might overwrite it */
1123 pvBuf
= HeapAlloc(GetProcessHeap(), 0, 256 * sizeof(WCHAR
));
1126 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1127 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1130 ustrRsrc
.Buffer
= pvBuf
;
1134 if(!NtUserGetIconInfo(hicon
, NULL
, &ustrModule
, &ustrRsrc
, NULL
, FALSE
))
1136 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1137 HeapFree(GetProcessHeap(), 0, pvBuf
);
1141 if((ustrModule
.Length
< ustrModule
.MaximumLength
) && (ustrRsrc
.Length
< ustrRsrc
.MaximumLength
))
1143 /* Buffers were big enough */
1147 /* Find which buffer were too small */
1148 if(ustrModule
.Length
== ustrModule
.MaximumLength
)
1151 ustrModule
.MaximumLength
*= 2;
1152 newBuffer
= HeapReAlloc(GetProcessHeap(), 0, ustrModule
.Buffer
, ustrModule
.MaximumLength
* sizeof(WCHAR
));
1153 if(!ustrModule
.Buffer
)
1155 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1158 ustrModule
.Buffer
= newBuffer
;
1161 if(ustrRsrc
.Length
== ustrRsrc
.MaximumLength
)
1163 ustrRsrc
.MaximumLength
*= 2;
1164 pvBuf
= HeapReAlloc(GetProcessHeap(), 0, ustrRsrc
.Buffer
, ustrRsrc
.MaximumLength
* sizeof(WCHAR
));
1167 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1170 ustrRsrc
.Buffer
= pvBuf
;
1174 /* NULL-terminate our strings */
1175 ustrModule
.Buffer
[ustrModule
.Length
] = 0;
1176 if(!IS_INTRESOURCE(ustrRsrc
.Buffer
))
1177 ustrRsrc
.Buffer
[ustrRsrc
.Length
] = 0;
1179 /* Get the module handle */
1180 if(!GetModuleHandleExW(0, ustrModule
.Buffer
, &hModule
))
1182 /* This hould never happen */
1183 SetLastError(ERROR_INVALID_PARAMETER
);
1187 /* Call the relevant function */
1188 ret
= CURSORICON_LoadImageW(hModule
, ustrRsrc
.Buffer
, cxDesired
, cyDesired
, bIcon
, fuFlags
& LR_DEFAULTSIZE
);
1190 FreeLibrary(hModule
);
1192 /* If we're here, that means that the passed icon is shared. Don't destroy it, even if LR_COPYDELETEORG is specified */
1194 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1195 HeapFree(GetProcessHeap(), 0, pvBuf
);
1200 /* This is a regular copy */
1201 if(fuFlags
& ~LR_COPYDELETEORG
)
1202 FIXME("Unimplemented flags: 0x%08x\n", fuFlags
);
1204 if(!GetIconInfo(hicon
, &ii
))
1206 ERR("GetIconInfo failed.\n");
1210 ret
= CreateIconIndirect(&ii
);
1212 DeleteObject(ii
.hbmMask
);
1213 if(ii
.hbmColor
) DeleteObject(ii
.hbmColor
);
1215 if(ret
&& (fuFlags
& LR_COPYDELETEORG
))
1221 /************* PUBLIC FUNCTIONS *******************/
1223 HANDLE WINAPI
CopyImage(
1231 TRACE("hImage=%p, uType=%u, cxDesired=%d, cyDesired=%d, fuFlags=%x\n",
1232 hImage
, uType
, cxDesired
, cyDesired
, fuFlags
);
1236 return BITMAP_CopyImage(hImage
, cxDesired
, cyDesired
, fuFlags
);
1239 return CURSORICON_CopyImage(hImage
, uType
== IMAGE_ICON
, cxDesired
, cyDesired
, fuFlags
);
1241 SetLastError(ERROR_INVALID_PARAMETER
);
1247 HICON WINAPI
CopyIcon(
1255 BOOL WINAPI
DrawIcon(
1262 return DrawIconEx(hDC
, X
, Y
, hIcon
, 0, 0, 0, NULL
, DI_NORMAL
| DI_COMPAT
| DI_DEFAULTSIZE
);
1265 BOOL WINAPI
DrawIconEx(
1272 _In_ UINT istepIfAniCur
,
1273 _In_opt_ HBRUSH hbrFlickerFreeDraw
,
1277 return NtUserDrawIconEx(hdc
, xLeft
, yTop
, hIcon
, cxWidth
, cyWidth
,
1278 istepIfAniCur
, hbrFlickerFreeDraw
, diFlags
,
1282 BOOL WINAPI
GetIconInfo(
1284 _Out_ PICONINFO piconinfo
1287 return NtUserGetIconInfo(hIcon
, piconinfo
, NULL
, NULL
, NULL
, FALSE
);
1290 BOOL WINAPI
DestroyIcon(
1294 return NtUserDestroyCursor(hIcon
, FALSE
);
1297 HICON WINAPI
LoadIconA(
1298 _In_opt_ HINSTANCE hInstance
,
1299 _In_ LPCSTR lpIconName
1302 TRACE("%p, %s\n", hInstance
, debugstr_a(lpIconName
));
1304 return LoadImageA(hInstance
,
1309 LR_SHARED
| LR_DEFAULTSIZE
);
1312 HICON WINAPI
LoadIconW(
1313 _In_opt_ HINSTANCE hInstance
,
1314 _In_ LPCWSTR lpIconName
1317 TRACE("%p, %s\n", hInstance
, debugstr_w(lpIconName
));
1319 return LoadImageW(hInstance
,
1324 LR_SHARED
| LR_DEFAULTSIZE
);
1327 HCURSOR WINAPI
LoadCursorA(
1328 _In_opt_ HINSTANCE hInstance
,
1329 _In_ LPCSTR lpCursorName
1332 TRACE("%p, %s\n", hInstance
, debugstr_a(lpCursorName
));
1334 return LoadImageA(hInstance
,
1339 LR_SHARED
| LR_DEFAULTSIZE
);
1342 HCURSOR WINAPI
LoadCursorW(
1343 _In_opt_ HINSTANCE hInstance
,
1344 _In_ LPCWSTR lpCursorName
1347 TRACE("%p, %s\n", hInstance
, debugstr_w(lpCursorName
));
1349 return LoadImageW(hInstance
,
1354 LR_SHARED
| LR_DEFAULTSIZE
);
1357 HCURSOR WINAPI
LoadCursorFromFileA(
1358 _In_ LPCSTR lpFileName
1361 TRACE("%s\n", debugstr_a(lpFileName
));
1363 return LoadImageA(NULL
,
1368 LR_LOADFROMFILE
| LR_DEFAULTSIZE
);
1371 HCURSOR WINAPI
LoadCursorFromFileW(
1372 _In_ LPCWSTR lpFileName
1375 TRACE("%s\n", debugstr_w(lpFileName
));
1377 return LoadImageW(NULL
,
1382 LR_LOADFROMFILE
| LR_DEFAULTSIZE
);
1385 HBITMAP WINAPI
LoadBitmapA(
1386 _In_opt_ HINSTANCE hInstance
,
1387 _In_ LPCSTR lpBitmapName
1390 TRACE("%p, %s\n", hInstance
, debugstr_a(lpBitmapName
));
1392 return LoadImageA(hInstance
,
1400 HBITMAP WINAPI
LoadBitmapW(
1401 _In_opt_ HINSTANCE hInstance
,
1402 _In_ LPCWSTR lpBitmapName
1405 TRACE("%p, %s\n", hInstance
, debugstr_w(lpBitmapName
));
1407 return LoadImageW(hInstance
,
1415 HANDLE WINAPI
LoadImageA(
1416 _In_opt_ HINSTANCE hinst
,
1417 _In_ LPCSTR lpszName
,
1428 if (IS_INTRESOURCE(lpszName
))
1429 return LoadImageW(hinst
, (LPCWSTR
)lpszName
, uType
, cxDesired
, cyDesired
, fuLoad
);
1431 len
= MultiByteToWideChar( CP_ACP
, 0, lpszName
, -1, NULL
, 0 );
1432 u_name
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
1433 MultiByteToWideChar( CP_ACP
, 0, lpszName
, -1, u_name
, len
);
1435 res
= LoadImageW(hinst
, u_name
, uType
, cxDesired
, cyDesired
, fuLoad
);
1436 HeapFree(GetProcessHeap(), 0, u_name
);
1440 HANDLE WINAPI
LoadImageW(
1441 _In_opt_ HINSTANCE hinst
,
1442 _In_ LPCWSTR lpszName
,
1449 /* Redirect to each implementation */
1453 return BITMAP_LoadImageW(hinst
, lpszName
, cxDesired
, cyDesired
, fuLoad
);
1456 return CURSORICON_LoadImageW(hinst
, lpszName
, cxDesired
, cyDesired
, fuLoad
, uType
== IMAGE_ICON
);
1458 SetLastError(ERROR_INVALID_PARAMETER
);
1464 int WINAPI
LookupIconIdFromDirectory(
1465 _In_ PBYTE presbits
,
1469 return LookupIconIdFromDirectoryEx( presbits
, fIcon
,
1470 fIcon
? GetSystemMetrics(SM_CXICON
) : GetSystemMetrics(SM_CXCURSOR
),
1471 fIcon
? GetSystemMetrics(SM_CYICON
) : GetSystemMetrics(SM_CYCURSOR
), fIcon
? 0 : LR_MONOCHROME
);
1474 int WINAPI
LookupIconIdFromDirectoryEx(
1475 _In_ PBYTE presbits
,
1483 CURSORICONDIR
* dir
= (CURSORICONDIR
*)presbits
;
1484 CURSORICONDIRENTRY
* entry
;
1485 int i
, numMatch
, iIndex
= -1;
1488 ULONG cxyDiff
, cxyDiffTmp
;
1490 TRACE("%p, %x, %i, %i, %x.\n", presbits
, fIcon
, cxDesired
, cyDesired
, Flags
);
1492 if(!(dir
&& !dir
->idReserved
&& (dir
->idType
& 3)))
1494 WARN("Invalid resource.\n");
1498 /* idType == 2 is for cursors, 1 for icons */
1501 if(dir->idType == 2)
1503 WARN("An icon was asked for a cursor resource.\n");
1507 else if(dir->idType == 1)
1509 WARN("A cursor was asked for an icon resource.\n");
1513 if(Flags
& LR_MONOCHROME
)
1518 icScreen
= CreateICW(DISPLAYW
, NULL
, NULL
, NULL
);
1522 bppDesired
= GetDeviceCaps(icScreen
, BITSPIXEL
);
1526 /* Find the best match for the desired size */
1527 cxyDiff
= 0xFFFFFFFF;
1529 for(i
= 0; i
< dir
->idCount
; i
++)
1531 entry
= &dir
->idEntries
[i
];
1532 width
= fIcon
? entry
->ResInfo
.icon
.bWidth
: entry
->ResInfo
.cursor
.wWidth
;
1533 /* Height is twice as big in cursor resources */
1534 height
= fIcon
? entry
->ResInfo
.icon
.bHeight
: entry
->ResInfo
.cursor
.wHeight
/2;
1535 /* 0 represents 256 */
1536 if(!width
) width
= 256;
1537 if(!height
) height
= 256;
1538 /* Let it be a 1-norm */
1539 cxyDiffTmp
= max(abs(width
- cxDesired
), abs(height
- cyDesired
));
1540 if( cxyDiffTmp
> cxyDiff
)
1542 if( cxyDiffTmp
== cxyDiff
)
1549 cxyDiff
= cxyDiffTmp
;
1554 /* Only one entry fit the asked dimensions */
1555 return dir
->idEntries
[iIndex
].wResId
;
1560 /* Now find the entry with the best depth */
1561 for(i
= 0; i
< dir
->idCount
; i
++)
1563 entry
= &dir
->idEntries
[i
];
1564 width
= fIcon
? entry
->ResInfo
.icon
.bWidth
: entry
->ResInfo
.cursor
.wWidth
;
1565 height
= fIcon
? entry
->ResInfo
.icon
.bHeight
: entry
->ResInfo
.cursor
.wHeight
/2;
1566 /* 0 represents 256 */
1567 if(!width
) width
= 256;
1568 if(!height
) height
= 256;
1569 /* Check if this is the best match we had */
1570 cxyDiffTmp
= max(abs(width
- cxDesired
), abs(height
- cyDesired
));
1571 if(cxyDiffTmp
!= cxyDiff
)
1574 if(entry
->wBitCount
== bppDesired
)
1575 return entry
->wResId
;
1576 /* We take the highest possible but smaller than the display depth */
1577 if((entry
->wBitCount
> bitcount
) && (entry
->wBitCount
< bppDesired
))
1580 bitcount
= entry
->wBitCount
;
1585 return dir
->idEntries
[iIndex
].wResId
;
1587 /* No inferior or equal depth available. Get the smallest one */
1589 for(i
= 0; i
< dir
->idCount
; i
++)
1591 entry
= &dir
->idEntries
[i
];
1592 width
= fIcon
? entry
->ResInfo
.icon
.bWidth
: entry
->ResInfo
.cursor
.wWidth
;
1593 height
= fIcon
? entry
->ResInfo
.icon
.bHeight
: entry
->ResInfo
.cursor
.wHeight
/2;
1594 /* 0 represents 256 */
1595 if(!width
) width
= 256;
1596 if(!height
) height
= 256;
1597 /* Check if this is the best match we had */
1598 cxyDiffTmp
= max(abs(width
- cxDesired
), abs(height
- cyDesired
));
1599 if(cxyDiffTmp
!= cxyDiff
)
1601 /* Check the bit depth */
1602 if(entry
->wBitCount
< bitcount
)
1605 bitcount
= entry
->wBitCount
;
1609 return dir
->idEntries
[iIndex
].wResId
;
1612 HICON WINAPI
CreateIcon(
1613 _In_opt_ HINSTANCE hInstance
,
1617 _In_ BYTE cBitsPixel
,
1618 _In_
const BYTE
*lpbANDbits
,
1619 _In_
const BYTE
*lpbXORbits
1625 TRACE_(icon
)("%dx%d, planes %d, bpp %d, xor %p, and %p\n",
1626 nWidth
, nHeight
, cPlanes
, cBitsPixel
, lpbXORbits
, lpbANDbits
);
1629 iinfo
.xHotspot
= nWidth
/ 2;
1630 iinfo
.yHotspot
= nHeight
/ 2;
1631 if (cPlanes
* cBitsPixel
> 1)
1633 iinfo
.hbmColor
= CreateBitmap( nWidth
, nHeight
, cPlanes
, cBitsPixel
, lpbXORbits
);
1634 iinfo
.hbmMask
= CreateBitmap( nWidth
, nHeight
, 1, 1, lpbANDbits
);
1638 iinfo
.hbmMask
= CreateBitmap( nWidth
, nHeight
* 2, 1, 1, lpbANDbits
);
1639 iinfo
.hbmColor
= NULL
;
1642 hIcon
= CreateIconIndirect( &iinfo
);
1644 DeleteObject( iinfo
.hbmMask
);
1645 if (iinfo
.hbmColor
) DeleteObject( iinfo
.hbmColor
);
1650 HICON WINAPI
CreateIconFromResource(
1651 _In_ PBYTE presbits
,
1652 _In_ DWORD dwResSize
,
1657 return CreateIconFromResourceEx( presbits
, dwResSize
, fIcon
, dwVer
, 0,0,0);
1660 HICON WINAPI
CreateIconFromResourceEx(
1661 _In_ PBYTE pbIconBits
,
1662 _In_ DWORD cbIconBits
,
1664 _In_ DWORD dwVersion
,
1674 FIXME("uFlags 0x%08x ignored.\n", uFlags
);
1678 ii
.xHotspot
= cxDesired
/2;
1679 ii
.yHotspot
= cyDesired
/2;
1683 WORD
* pt
= (WORD
*)pbIconBits
;
1684 ii
.xHotspot
= *pt
++;
1685 ii
.yHotspot
= *pt
++;
1686 pbIconBits
= (PBYTE
)pt
;
1690 if(!CURSORICON_GetIconInfoFromBMI(&ii
, (BITMAPINFO
*)pbIconBits
, cxDesired
, cyDesired
))
1693 hIcon
= CreateIconIndirect(&ii
);
1696 DeleteObject(ii
.hbmMask
);
1697 if(ii
.hbmColor
) DeleteObject(ii
.hbmColor
);
1702 HICON WINAPI
CreateIconIndirect(
1703 _In_ PICONINFO piconinfo
1706 /* As simple as creating a handle, and let win32k deal with the bitmaps */
1709 TRACE("%p.\n", piconinfo
);
1711 hiconRet
= NtUserxCreateEmptyCurObject(piconinfo
->fIcon
? 0 : 1);
1715 if(!NtUserSetCursorIconData(hiconRet
, NULL
, NULL
, piconinfo
))
1717 NtUserDestroyCursor(hiconRet
, FALSE
);
1721 TRACE("Returning 0x%08x.\n", hiconRet
);
1726 HCURSOR WINAPI
CreateCursor(
1727 _In_opt_ HINSTANCE hInst
,
1732 _In_
const VOID
*pvANDPlane
,
1733 _In_
const VOID
*pvXORPlane
1739 TRACE_(cursor
)("%dx%d spot=%d,%d xor=%p and=%p\n",
1740 nWidth
, nHeight
, xHotSpot
, yHotSpot
, pvXORPlane
, pvANDPlane
);
1743 info
.xHotspot
= xHotSpot
;
1744 info
.yHotspot
= yHotSpot
;
1745 info
.hbmMask
= CreateBitmap( nWidth
, nHeight
, 1, 1, pvANDPlane
);
1746 info
.hbmColor
= CreateBitmap( nWidth
, nHeight
, 1, 1, pvXORPlane
);
1747 hCursor
= CreateIconIndirect( &info
);
1748 DeleteObject( info
.hbmMask
);
1749 DeleteObject( info
.hbmColor
);
1753 BOOL WINAPI
SetSystemCursor(
1762 BOOL WINAPI
SetCursorPos(
1771 BOOL WINAPI
GetCursorPos(
1772 _Out_ LPPOINT lpPoint
1775 return NtUserxGetCursorPos(lpPoint
);
1778 int WINAPI
ShowCursor(
1786 HCURSOR WINAPI
GetCursor(void)
1792 BOOL WINAPI
DestroyCursor(
1793 _In_ HCURSOR hCursor
1796 return NtUserDestroyCursor(hCursor
, FALSE
);