[Win32SS]
[reactos.git] / reactos / win32ss / user / user32 / windows / cursoricon.c
1 /*
2 * Cursor and icon support
3 *
4 * Copyright 1995 Alexandre Julliard
5 * 1996 Martin Von Loewis
6 * 1997 Alex Korobka
7 * 1998 Turchanov Sergey
8 * 2007 Henri Verbeet
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25 #include <user32.h>
26
27 #include <wine/debug.h>
28
29 WINE_DEFAULT_DEBUG_CHANNEL(cursor);
30 WINE_DECLARE_DEBUG_CHANNEL(icon);
31 WINE_DECLARE_DEBUG_CHANNEL(resource);
32
33 #include "pshpack1.h"
34
35 typedef struct {
36 BYTE bWidth;
37 BYTE bHeight;
38 BYTE bColorCount;
39 BYTE bReserved;
40 WORD xHotspot;
41 WORD yHotspot;
42 DWORD dwDIBSize;
43 DWORD dwDIBOffset;
44 } CURSORICONFILEDIRENTRY;
45
46 typedef struct
47 {
48 WORD idReserved;
49 WORD idType;
50 WORD idCount;
51 CURSORICONFILEDIRENTRY idEntries[1];
52 } CURSORICONFILEDIR;
53
54 #include "poppack.h"
55
56 static HDC screen_dc;
57
58 static const WCHAR DISPLAYW[] = {'D','I','S','P','L','A','Y',0};
59
60
61 static CRITICAL_SECTION IconCrst;
62 static CRITICAL_SECTION_DEBUG critsect_debug =
63 {
64 0, 0, &IconCrst,
65 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
66 0, 0, { (DWORD_PTR)(__FILE__ ": IconCrst") }
67 };
68 static CRITICAL_SECTION IconCrst = { &critsect_debug, -1, 0, 0, 0, 0 };
69
70 /***********************************************************************
71 * CreateCursorIconHandle
72 *
73 * Creates a handle with everything in there
74 */
75 static
76 HICON
77 CreateCursorIconHandle( PICONINFO IconInfo )
78 {
79 HICON hIcon = NtUserxCreateEmptyCurObject(0);
80 if(!hIcon)
81 return NULL;
82
83 NtUserSetCursorContents(hIcon, IconInfo);
84 return hIcon;
85 }
86
87
88
89 /***********************************************************************
90 * map_fileW
91 *
92 * Helper function to map a file to memory:
93 * name - file name
94 * [RETURN] ptr - pointer to mapped file
95 * [RETURN] filesize - pointer size of file to be stored if not NULL
96 */
97 static void *map_fileW( LPCWSTR name, LPDWORD filesize )
98 {
99 HANDLE hFile, hMapping;
100 LPVOID ptr = NULL;
101
102 hFile = CreateFileW( name, GENERIC_READ, FILE_SHARE_READ, NULL,
103 OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, 0 );
104 if (hFile != INVALID_HANDLE_VALUE)
105 {
106 hMapping = CreateFileMappingW( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
107 if (hMapping)
108 {
109 ptr = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 );
110 CloseHandle( hMapping );
111 if (filesize)
112 *filesize = GetFileSize( hFile, NULL );
113 }
114 CloseHandle( hFile );
115 }
116 return ptr;
117 }
118
119
120 /***********************************************************************
121 * get_dib_width_bytes
122 *
123 * Return the width of a DIB bitmap in bytes. DIB bitmap data is 32-bit aligned.
124 */
125 static int get_dib_width_bytes( int width, int depth )
126 {
127 int words;
128
129 switch(depth)
130 {
131 case 1: words = (width + 31) / 32; break;
132 case 4: words = (width + 7) / 8; break;
133 case 8: words = (width + 3) / 4; break;
134 case 15:
135 case 16: words = (width + 1) / 2; break;
136 case 24: words = (width * 3 + 3)/4; break;
137 default:
138 WARN("(%d): Unsupported depth\n", depth );
139 /* fall through */
140 case 32:
141 words = width;
142 }
143 return 4 * words;
144 }
145
146
147 /***********************************************************************
148 * bitmap_info_size
149 *
150 * Return the size of the bitmap info structure including color table.
151 */
152 static int bitmap_info_size( const BITMAPINFO * info, WORD coloruse )
153 {
154 unsigned int colors, size, masks = 0;
155
156 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
157 {
158 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
159 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
160 return sizeof(BITMAPCOREHEADER) + colors *
161 ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
162 }
163 else /* assume BITMAPINFOHEADER */
164 {
165 colors = info->bmiHeader.biClrUsed;
166 if (colors > 256) /* buffer overflow otherwise */
167 colors = 256;
168 if (!colors && (info->bmiHeader.biBitCount <= 8))
169 colors = 1 << info->bmiHeader.biBitCount;
170 if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
171 size = max( info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) );
172 return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
173 }
174 }
175
176
177 /***********************************************************************
178 * is_dib_monochrome
179 *
180 * Returns whether a DIB can be converted to a monochrome DDB.
181 *
182 * A DIB can be converted if its color table contains only black and
183 * white. Black must be the first color in the color table.
184 *
185 * Note : If the first color in the color table is white followed by
186 * black, we can't convert it to a monochrome DDB with
187 * SetDIBits, because black and white would be inverted.
188 */
189 static BOOL is_dib_monochrome( const BITMAPINFO* info )
190 {
191 if (info->bmiHeader.biBitCount != 1) return FALSE;
192
193 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
194 {
195 const RGBTRIPLE *rgb = ((const BITMAPCOREINFO*)info)->bmciColors;
196
197 /* Check if the first color is black */
198 if ((rgb->rgbtRed == 0) && (rgb->rgbtGreen == 0) && (rgb->rgbtBlue == 0))
199 {
200 rgb++;
201
202 /* Check if the second color is white */
203 return ((rgb->rgbtRed == 0xff) && (rgb->rgbtGreen == 0xff)
204 && (rgb->rgbtBlue == 0xff));
205 }
206 else return FALSE;
207 }
208 else /* assume BITMAPINFOHEADER */
209 {
210 const RGBQUAD *rgb = info->bmiColors;
211
212 /* Check if the first color is black */
213 if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) &&
214 (rgb->rgbBlue == 0) && (rgb->rgbReserved == 0))
215 {
216 rgb++;
217
218 /* Check if the second color is white */
219 return ((rgb->rgbRed == 0xff) && (rgb->rgbGreen == 0xff)
220 && (rgb->rgbBlue == 0xff) && (rgb->rgbReserved == 0));
221 }
222 else return FALSE;
223 }
224 }
225
226 /***********************************************************************
227 * DIB_GetBitmapInfo
228 *
229 * Get the info from a bitmap header.
230 * Return 1 for INFOHEADER, 0 for COREHEADER,
231 */
232 static int DIB_GetBitmapInfo( const BITMAPINFOHEADER *header, LONG *width,
233 LONG *height, WORD *bpp, DWORD *compr )
234 {
235 if (header->biSize == sizeof(BITMAPCOREHEADER))
236 {
237 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)header;
238 *width = core->bcWidth;
239 *height = core->bcHeight;
240 *bpp = core->bcBitCount;
241 *compr = 0;
242 return 0;
243 }
244 else if (header->biSize == sizeof(BITMAPINFOHEADER) ||
245 header->biSize == sizeof(BITMAPV4HEADER) ||
246 header->biSize == sizeof(BITMAPV5HEADER))
247 {
248 *width = header->biWidth;
249 *height = header->biHeight;
250 *bpp = header->biBitCount;
251 *compr = header->biCompression;
252 return 1;
253 }
254 ERR("(%d): unknown/wrong size for header\n", header->biSize );
255 return -1;
256 }
257
258
259 /*
260 * The following macro functions account for the irregularities of
261 * accessing cursor and icon resources in files and resource entries.
262 */
263 typedef BOOL (*fnGetCIEntry)( LPVOID dir, int n,
264 int *width, int *height, int *bits );
265
266 /**********************************************************************
267 * CURSORICON_FindBestIcon
268 *
269 * Find the icon closest to the requested size and bit depth.
270 */
271 static int CURSORICON_FindBestIcon( LPVOID dir, fnGetCIEntry get_entry,
272 int width, int height, int depth )
273 {
274 int i, cx, cy, bits, bestEntry = -1;
275 UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
276 UINT iTempXDiff, iTempYDiff, iTempColorDiff;
277
278 /* Find Best Fit */
279 iTotalDiff = 0xFFFFFFFF;
280 iColorDiff = 0xFFFFFFFF;
281 for ( i = 0; get_entry( dir, i, &cx, &cy, &bits ); i++ )
282 {
283 iTempXDiff = abs(width - cx);
284 iTempYDiff = abs(height - cy);
285
286 if(iTotalDiff > (iTempXDiff + iTempYDiff))
287 {
288 iXDiff = iTempXDiff;
289 iYDiff = iTempYDiff;
290 iTotalDiff = iXDiff + iYDiff;
291 }
292 }
293
294 /* Find Best Colors for Best Fit */
295 for ( i = 0; get_entry( dir, i, &cx, &cy, &bits ); i++ )
296 {
297 if(abs(width - cx) == iXDiff && abs(height - cy) == iYDiff)
298 {
299 iTempColorDiff = abs(depth - bits);
300 if(iColorDiff > iTempColorDiff)
301 {
302 bestEntry = i;
303 iColorDiff = iTempColorDiff;
304 }
305 }
306 }
307
308 return bestEntry;
309 }
310
311 static BOOL CURSORICON_GetResIconEntry( LPVOID dir, int n,
312 int *width, int *height, int *bits )
313 {
314 CURSORICONDIR *resdir = dir;
315 ICONRESDIR *icon;
316
317 if ( resdir->idCount <= n )
318 return FALSE;
319 icon = &resdir->idEntries[n].ResInfo.icon;
320 *width = icon->bWidth;
321 *height = icon->bHeight;
322 *bits = resdir->idEntries[n].wBitCount;
323 return TRUE;
324 }
325
326 /**********************************************************************
327 * CURSORICON_FindBestCursor
328 *
329 * Find the cursor closest to the requested size.
330 *
331 * FIXME: parameter 'color' ignored.
332 */
333 static int CURSORICON_FindBestCursor( LPVOID dir, fnGetCIEntry get_entry,
334 int width, int height, int depth )
335 {
336 int i, maxwidth, maxheight, cx, cy, bits, bestEntry = -1;
337
338 /* Double height to account for AND and XOR masks */
339
340 height *= 2;
341
342 /* First find the largest one smaller than or equal to the requested size*/
343
344 maxwidth = maxheight = 0;
345 for ( i = 0; get_entry( dir, i, &cx, &cy, &bits ); i++ )
346 {
347 if ((cx <= width) && (cy <= height) &&
348 (cx > maxwidth) && (cy > maxheight))
349 {
350 bestEntry = i;
351 maxwidth = cx;
352 maxheight = cy;
353 }
354 }
355 if (bestEntry != -1) return bestEntry;
356
357 /* Now find the smallest one larger than the requested size */
358
359 maxwidth = maxheight = 255;
360 for ( i = 0; get_entry( dir, i, &cx, &cy, &bits ); i++ )
361 {
362 if (((cx < maxwidth) && (cy < maxheight)) || (bestEntry == -1))
363 {
364 bestEntry = i;
365 maxwidth = cx;
366 maxheight = cy;
367 }
368 }
369
370 return bestEntry;
371 }
372
373 static BOOL CURSORICON_GetResCursorEntry( LPVOID dir, int n,
374 int *width, int *height, int *bits )
375 {
376 CURSORICONDIR *resdir = dir;
377 CURSORDIR *cursor;
378
379 if ( resdir->idCount <= n )
380 return FALSE;
381 cursor = &resdir->idEntries[n].ResInfo.cursor;
382 *width = cursor->wWidth;
383 *height = cursor->wHeight;
384 *bits = resdir->idEntries[n].wBitCount;
385 return TRUE;
386 }
387
388 static CURSORICONDIRENTRY *CURSORICON_FindBestIconRes( CURSORICONDIR * dir,
389 int width, int height, int depth )
390 {
391 int n;
392
393 n = CURSORICON_FindBestIcon( dir, CURSORICON_GetResIconEntry,
394 width, height, depth );
395 if ( n < 0 )
396 return NULL;
397 return &dir->idEntries[n];
398 }
399
400 static CURSORICONDIRENTRY *CURSORICON_FindBestCursorRes( CURSORICONDIR *dir,
401 int width, int height, int depth )
402 {
403 int n = CURSORICON_FindBestCursor( dir, CURSORICON_GetResCursorEntry,
404 width, height, depth );
405 if ( n < 0 )
406 return NULL;
407 return &dir->idEntries[n];
408 }
409
410 static BOOL CURSORICON_GetFileEntry( LPVOID dir, int n,
411 int *width, int *height, int *bits )
412 {
413 CURSORICONFILEDIR *filedir = dir;
414 CURSORICONFILEDIRENTRY *entry;
415 BITMAPINFOHEADER *info;
416
417 if ( filedir->idCount <= n )
418 return FALSE;
419 entry = &filedir->idEntries[n];
420 /* FIXME: check against file size */
421 info = (BITMAPINFOHEADER *)((char *)dir + entry->dwDIBOffset);
422 *width = entry->bWidth;
423 *height = entry->bHeight;
424 *bits = info->biBitCount;
425 return TRUE;
426 }
427
428 static CURSORICONFILEDIRENTRY *CURSORICON_FindBestCursorFile( CURSORICONFILEDIR *dir,
429 int width, int height, int depth )
430 {
431 int n = CURSORICON_FindBestCursor( dir, CURSORICON_GetFileEntry,
432 width, height, depth );
433 if ( n < 0 )
434 return NULL;
435 return &dir->idEntries[n];
436 }
437
438 static CURSORICONFILEDIRENTRY *CURSORICON_FindBestIconFile( CURSORICONFILEDIR *dir,
439 int width, int height, int depth )
440 {
441 int n = CURSORICON_FindBestIcon( dir, CURSORICON_GetFileEntry,
442 width, height, depth );
443 if ( n < 0 )
444 return NULL;
445 return &dir->idEntries[n];
446 }
447
448 /***********************************************************************
449 * create_icon_bitmaps
450 *
451 * Create the color, mask and alpha bitmaps from the DIB info.
452 */
453 static BOOL create_icon_bitmaps( const BITMAPINFO *bmi, int width, int height,
454 HBITMAP *color, HBITMAP *mask )
455 {
456 BOOL monochrome = is_dib_monochrome( bmi );
457 unsigned int size = bitmap_info_size( bmi, DIB_RGB_COLORS );
458 BITMAPINFO *info;
459 void *color_bits, *mask_bits;
460 BOOL ret = FALSE;
461 HDC hdc = 0;
462
463 if (!(info = HeapAlloc( GetProcessHeap(), 0, max( size, FIELD_OFFSET( BITMAPINFO, bmiColors[2] )))))
464 return FALSE;
465 if (!(hdc = CreateCompatibleDC(NULL))) goto done;
466
467 memcpy( info, bmi, size );
468 info->bmiHeader.biHeight /= 2;
469
470 color_bits = (char *)bmi + size;
471 mask_bits = (char *)color_bits +
472 get_dib_width_bytes( bmi->bmiHeader.biWidth,
473 bmi->bmiHeader.biBitCount ) * abs(info->bmiHeader.biHeight);
474
475 if (monochrome)
476 {
477 if (!(*mask = CreateBitmap( width, height * 2, 1, 1, NULL ))) goto done;
478 *color = 0;
479
480 /* copy color data into second half of mask bitmap */
481 SelectObject( hdc, *mask );
482 StretchDIBits( hdc, 0, height, width, height,
483 0, 0, info->bmiHeader.biWidth, info->bmiHeader.biHeight,
484 color_bits, info, DIB_RGB_COLORS, SRCCOPY );
485 }
486 else
487 {
488 if (!(*mask = CreateBitmap( width, height, 1, 1, NULL ))) goto done;
489 if (!(*color = CreateBitmap( width, height, GetDeviceCaps(hdc, PLANES),
490 GetDeviceCaps(hdc, BITSPIXEL), NULL )))
491 {
492 DeleteObject( *mask );
493 goto done;
494 }
495 SelectObject( hdc, *color );
496 StretchDIBits( hdc, 0, 0, width, height,
497 0, 0, info->bmiHeader.biWidth, info->bmiHeader.biHeight,
498 color_bits, info, DIB_RGB_COLORS, SRCCOPY );
499
500 /* convert info to monochrome to copy the mask */
501 info->bmiHeader.biBitCount = 1;
502 if (info->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
503 {
504 RGBQUAD *rgb = info->bmiColors;
505
506 info->bmiHeader.biClrUsed = info->bmiHeader.biClrImportant = 2;
507 rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00;
508 rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff;
509 rgb[0].rgbReserved = rgb[1].rgbReserved = 0;
510 }
511 else
512 {
513 RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)info) + 1);
514
515 rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00;
516 rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff;
517 }
518 }
519
520 SelectObject( hdc, *mask );
521 StretchDIBits( hdc, 0, 0, width, height,
522 0, 0, info->bmiHeader.biWidth, info->bmiHeader.biHeight,
523 mask_bits, info, DIB_RGB_COLORS, SRCCOPY );
524 ret = TRUE;
525
526 done:
527 if(hdc) DeleteDC( hdc );
528 HeapFree( GetProcessHeap(), 0, info );
529 return ret;
530 }
531
532 static HICON CURSORICON_CreateIconFromBMI( BITMAPINFO *bmi,
533 POINT hotspot, BOOL bIcon,
534 DWORD dwVersion,
535 INT width, INT height,
536 UINT cFlag )
537 {
538 HBITMAP color = 0, mask = 0;
539 BOOL do_stretch;
540 ICONINFO IconInfo;
541
542 if (dwVersion == 0x00020000)
543 {
544 FIXME_(cursor)("\t2.xx resources are not supported\n");
545 return 0;
546 }
547
548 /* Check bitmap header */
549
550 if ( (bmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) &&
551 (bmi->bmiHeader.biSize != sizeof(BITMAPINFOHEADER) ||
552 bmi->bmiHeader.biCompression != BI_RGB) )
553 {
554 WARN_(cursor)("\tinvalid resource bitmap header.\n");
555 return 0;
556 }
557
558 if (!width) width = bmi->bmiHeader.biWidth;
559 if (!height) height = bmi->bmiHeader.biHeight/2;
560 do_stretch = (bmi->bmiHeader.biHeight/2 != height) ||
561 (bmi->bmiHeader.biWidth != width);
562
563 /* Scale the hotspot */
564 if (bIcon)
565 {
566 hotspot.x = width / 2;
567 hotspot.y = height / 2;
568 }
569 else if (do_stretch)
570 {
571 hotspot.x = (hotspot.x * width) / bmi->bmiHeader.biWidth;
572 hotspot.y = (hotspot.y * height) / (bmi->bmiHeader.biHeight / 2);
573 }
574
575 if (!screen_dc) screen_dc = CreateDCW( DISPLAYW, NULL, NULL, NULL );
576 if (!screen_dc) return 0;
577
578 if (!create_icon_bitmaps( bmi, width, height, &color, &mask )) return 0;
579
580 IconInfo.xHotspot = hotspot.x;
581 IconInfo.yHotspot = hotspot.y;
582 IconInfo.fIcon = bIcon;
583 IconInfo.hbmColor = color;
584 IconInfo.hbmMask = mask;
585
586 return CreateCursorIconHandle(&IconInfo);
587 }
588
589
590 /**********************************************************************
591 * .ANI cursor support
592 */
593 #define RIFF_FOURCC( c0, c1, c2, c3 ) \
594 ( (DWORD)(BYTE)(c0) | ( (DWORD)(BYTE)(c1) << 8 ) | \
595 ( (DWORD)(BYTE)(c2) << 16 ) | ( (DWORD)(BYTE)(c3) << 24 ) )
596
597 #define ANI_RIFF_ID RIFF_FOURCC('R', 'I', 'F', 'F')
598 #define ANI_LIST_ID RIFF_FOURCC('L', 'I', 'S', 'T')
599 #define ANI_ACON_ID RIFF_FOURCC('A', 'C', 'O', 'N')
600 #define ANI_anih_ID RIFF_FOURCC('a', 'n', 'i', 'h')
601 #define ANI_seq__ID RIFF_FOURCC('s', 'e', 'q', ' ')
602 #define ANI_fram_ID RIFF_FOURCC('f', 'r', 'a', 'm')
603
604 #define ANI_FLAG_ICON 0x1
605 #define ANI_FLAG_SEQUENCE 0x2
606
607 typedef struct {
608 DWORD header_size;
609 DWORD num_frames;
610 DWORD num_steps;
611 DWORD width;
612 DWORD height;
613 DWORD bpp;
614 DWORD num_planes;
615 DWORD display_rate;
616 DWORD flags;
617 } ani_header;
618
619 typedef struct {
620 DWORD data_size;
621 const unsigned char *data;
622 } riff_chunk_t;
623
624 static void dump_ani_header( const ani_header *header )
625 {
626 TRACE(" header size: %d\n", header->header_size);
627 TRACE(" frames: %d\n", header->num_frames);
628 TRACE(" steps: %d\n", header->num_steps);
629 TRACE(" width: %d\n", header->width);
630 TRACE(" height: %d\n", header->height);
631 TRACE(" bpp: %d\n", header->bpp);
632 TRACE(" planes: %d\n", header->num_planes);
633 TRACE(" display rate: %d\n", header->display_rate);
634 TRACE(" flags: 0x%08x\n", header->flags);
635 }
636
637
638 /*
639 * RIFF:
640 * DWORD "RIFF"
641 * DWORD size
642 * DWORD riff_id
643 * BYTE[] data
644 *
645 * LIST:
646 * DWORD "LIST"
647 * DWORD size
648 * DWORD list_id
649 * BYTE[] data
650 *
651 * CHUNK:
652 * DWORD chunk_id
653 * DWORD size
654 * BYTE[] data
655 */
656 static void riff_find_chunk( DWORD chunk_id, DWORD chunk_type, const riff_chunk_t *parent_chunk, riff_chunk_t *chunk )
657 {
658 const unsigned char *ptr = parent_chunk->data;
659 const unsigned char *end = parent_chunk->data + (parent_chunk->data_size - (2 * sizeof(DWORD)));
660
661 if (chunk_type == ANI_LIST_ID || chunk_type == ANI_RIFF_ID) end -= sizeof(DWORD);
662
663 while (ptr < end)
664 {
665 if ((!chunk_type && *(const DWORD *)ptr == chunk_id )
666 || (chunk_type && *(const DWORD *)ptr == chunk_type && *((const DWORD *)ptr + 2) == chunk_id ))
667 {
668 ptr += sizeof(DWORD);
669 chunk->data_size = (*(const DWORD *)ptr + 1) & ~1;
670 ptr += sizeof(DWORD);
671 if (chunk_type == ANI_LIST_ID || chunk_type == ANI_RIFF_ID) ptr += sizeof(DWORD);
672 chunk->data = ptr;
673
674 return;
675 }
676
677 ptr += sizeof(DWORD);
678 ptr += (*(const DWORD *)ptr + 1) & ~1;
679 ptr += sizeof(DWORD);
680 }
681 }
682
683
684 /*
685 * .ANI layout:
686 *
687 * RIFF:'ACON' RIFF chunk
688 * |- CHUNK:'anih' Header
689 * |- CHUNK:'seq ' Sequence information (optional)
690 * \- LIST:'fram' Frame list
691 * |- CHUNK:icon Cursor frames
692 * |- CHUNK:icon
693 * |- ...
694 * \- CHUNK:icon
695 */
696 static HCURSOR CURSORICON_CreateIconFromANI( const LPBYTE bits, DWORD bits_size,
697 INT width, INT height, INT depth )
698 {
699 HCURSOR cursor;
700 ani_header header = {0};
701 LPBYTE frame_bits = 0;
702 POINT hotspot;
703 CURSORICONFILEDIRENTRY *entry;
704
705 riff_chunk_t root_chunk = { bits_size, bits };
706 riff_chunk_t ACON_chunk = {0};
707 riff_chunk_t anih_chunk = {0};
708 riff_chunk_t fram_chunk = {0};
709 const unsigned char *icon_data;
710
711 TRACE("bits %p, bits_size %d\n", bits, bits_size);
712
713 if (!bits) return 0;
714
715 riff_find_chunk( ANI_ACON_ID, ANI_RIFF_ID, &root_chunk, &ACON_chunk );
716 if (!ACON_chunk.data)
717 {
718 ERR("Failed to get root chunk.\n");
719 return 0;
720 }
721
722 riff_find_chunk( ANI_anih_ID, 0, &ACON_chunk, &anih_chunk );
723 if (!anih_chunk.data)
724 {
725 ERR("Failed to get 'anih' chunk.\n");
726 return 0;
727 }
728 memcpy( &header, anih_chunk.data, sizeof(header) );
729 dump_ani_header( &header );
730
731 riff_find_chunk( ANI_fram_ID, ANI_LIST_ID, &ACON_chunk, &fram_chunk );
732 if (!fram_chunk.data)
733 {
734 ERR("Failed to get icon list.\n");
735 return 0;
736 }
737
738 /* FIXME: For now, just load the first frame. Before we can load all the
739 * frames, we need to write the needed code in wineserver, etc. to handle
740 * cursors. Once this code is written, we can extend it to support .ani
741 * cursors and then update user32 and winex11.drv to load all frames.
742 *
743 * Hopefully this will at least make some games (C&C3, etc.) more playable
744 * in the meantime.
745 */
746 FIXME("Loading all frames for .ani cursors not implemented.\n");
747 icon_data = fram_chunk.data + (2 * sizeof(DWORD));
748
749 entry = CURSORICON_FindBestIconFile( (CURSORICONFILEDIR *) icon_data,
750 width, height, depth );
751
752 frame_bits = HeapAlloc( GetProcessHeap(), 0, entry->dwDIBSize );
753 memcpy( frame_bits, icon_data + entry->dwDIBOffset, entry->dwDIBSize );
754
755 if (!header.width || !header.height)
756 {
757 header.width = entry->bWidth;
758 header.height = entry->bHeight;
759 }
760
761 hotspot.x = entry->xHotspot;
762 hotspot.y = entry->yHotspot;
763
764 cursor = CURSORICON_CreateIconFromBMI( (BITMAPINFO *) frame_bits, hotspot,
765 FALSE, 0x00030000, header.width, header.height, 0 );
766
767 HeapFree( GetProcessHeap(), 0, frame_bits );
768
769 return cursor;
770 }
771
772
773 /**********************************************************************
774 * CreateIconFromResourceEx (USER32.@)
775 *
776 * FIXME: Convert to mono when cFlag is LR_MONOCHROME. Do something
777 * with cbSize parameter as well.
778 */
779 HICON WINAPI CreateIconFromResourceEx( PBYTE bits, DWORD cbSize,
780 BOOL bIcon, DWORD dwVersion,
781 int width, int height,
782 UINT cFlag )
783 {
784 POINT hotspot;
785 BITMAPINFO *bmi;
786
787 TRACE_(cursor)("%p (%u bytes), ver %08x, %ix%i %s %s\n",
788 bits, cbSize, dwVersion, width, height,
789 bIcon ? "icon" : "cursor", (cFlag & LR_MONOCHROME) ? "mono" : "" );
790
791 if (bIcon)
792 {
793 hotspot.x = width / 2;
794 hotspot.y = height / 2;
795 bmi = (BITMAPINFO *)bits;
796 }
797 else /* get the hotspot */
798 {
799 SHORT *pt = (SHORT *)bits;
800 hotspot.x = pt[0];
801 hotspot.y = pt[1];
802 bmi = (BITMAPINFO *)(pt + 2);
803 }
804
805 return CURSORICON_CreateIconFromBMI( bmi, hotspot, bIcon, dwVersion,
806 width, height, cFlag );
807 }
808
809
810 /**********************************************************************
811 * CreateIconFromResource (USER32.@)
812 */
813 HICON WINAPI CreateIconFromResource( PBYTE bits, DWORD cbSize,
814 BOOL bIcon, DWORD dwVersion)
815 {
816 return CreateIconFromResourceEx( bits, cbSize, bIcon, dwVersion, 0,0,0);
817 }
818
819
820 static HICON CURSORICON_LoadFromFile( LPCWSTR filename,
821 INT width, INT height, INT depth,
822 BOOL fCursor, UINT loadflags)
823 {
824 CURSORICONFILEDIRENTRY *entry;
825 CURSORICONFILEDIR *dir;
826 DWORD filesize = 0;
827 HICON hIcon = 0;
828 LPBYTE bits;
829 POINT hotspot;
830
831 TRACE("loading %s\n", debugstr_w( filename ));
832
833 bits = map_fileW( filename, &filesize );
834 if (!bits)
835 return hIcon;
836
837 /* Check for .ani. */
838 if (memcmp( bits, "RIFF", 4 ) == 0)
839 {
840 hIcon = CURSORICON_CreateIconFromANI( bits, filesize, width, height,
841 depth );
842 goto end;
843 }
844
845 dir = (CURSORICONFILEDIR*) bits;
846 if ( filesize < sizeof(*dir) )
847 goto end;
848
849 if ( filesize < (sizeof(*dir) + sizeof(dir->idEntries[0])*(dir->idCount-1)) )
850 goto end;
851
852 if ( fCursor )
853 entry = CURSORICON_FindBestCursorFile( dir, width, height, depth );
854 else
855 entry = CURSORICON_FindBestIconFile( dir, width, height, depth );
856
857 if ( !entry )
858 goto end;
859
860 /* check that we don't run off the end of the file */
861 if ( entry->dwDIBOffset > filesize )
862 goto end;
863 if ( entry->dwDIBOffset + entry->dwDIBSize > filesize )
864 goto end;
865
866 hotspot.x = entry->xHotspot;
867 hotspot.y = entry->yHotspot;
868 hIcon = CURSORICON_CreateIconFromBMI( (BITMAPINFO *)&bits[entry->dwDIBOffset],
869 hotspot, !fCursor, 0x00030000,
870 width, height, loadflags );
871 end:
872 TRACE("loaded %s -> %p\n", debugstr_w( filename ), hIcon );
873 UnmapViewOfFile( bits );
874 return hIcon;
875 }
876
877 /**********************************************************************
878 * CURSORICON_Load
879 *
880 * Load a cursor or icon from resource or file.
881 */
882 static HICON CURSORICON_Load(HINSTANCE hInstance, LPCWSTR name,
883 INT width, INT height, INT depth,
884 BOOL fCursor, UINT loadflags)
885 {
886 HANDLE handle = 0;
887 HICON hIcon = 0;
888 HRSRC hRsrc;
889 //HRSRC hGroupRsrc;
890 CURSORICONDIR *dir;
891 CURSORICONDIRENTRY *dirEntry;
892 LPBYTE bits;
893 WORD wResId;
894 DWORD dwBytesInRes;
895
896 TRACE("%p, %s, %dx%d, depth %d, fCursor %d, flags 0x%04x\n",
897 hInstance, debugstr_w(name), width, height, depth, fCursor, loadflags);
898
899 if ( loadflags & LR_LOADFROMFILE ) /* Load from file */
900 return CURSORICON_LoadFromFile( name, width, height, depth, fCursor, loadflags );
901
902 if (!hInstance) hInstance = User32Instance; /* Load OEM cursor/icon */
903
904 /* don't cache 16-bit instances (FIXME: should never get 16-bit instances in the first place) */
905 if ((ULONG_PTR)hInstance >> 16 == 0) loadflags &= ~LR_SHARED;
906
907 /* Get directory resource ID */
908
909 if (!(hRsrc = FindResourceW( hInstance, name,
910 (LPWSTR)(fCursor ? RT_GROUP_CURSOR : RT_GROUP_ICON) )))
911 return 0;
912 //hGroupRsrc = hRsrc;
913
914 /* Find the best entry in the directory */
915
916 if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
917 if (!(dir = LockResource( handle ))) return 0;
918 if (fCursor)
919 dirEntry = CURSORICON_FindBestCursorRes( dir, width, height, depth );
920 else
921 dirEntry = CURSORICON_FindBestIconRes( dir, width, height, depth );
922 if (!dirEntry) return 0;
923 wResId = dirEntry->wResId;
924 dwBytesInRes = dirEntry->dwBytesInRes;
925 FreeResource( handle );
926
927 /* Load the resource */
928
929 if (!(hRsrc = FindResourceW(hInstance,MAKEINTRESOURCEW(wResId),
930 (LPWSTR)(fCursor ? RT_CURSOR : RT_ICON) ))) return 0;
931
932 /* If shared icon, check whether it was already loaded */
933 if ( (loadflags & LR_SHARED)
934 && (hIcon = NtUserFindExistingCursorIcon( hInstance, hRsrc, 0, 0 ) ) != 0 )
935 return hIcon;
936
937 if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
938 bits = LockResource( handle );
939 hIcon = CreateIconFromResourceEx( bits, dwBytesInRes,
940 !fCursor, 0x00030000, width, height, loadflags);
941 FreeResource( handle );
942
943 /* If shared icon, add to icon cache */
944
945 if (hIcon && 0 != (loadflags & LR_SHARED))
946 {
947 #if 1
948 NtUserSetCursorIconData((HICON)hIcon, NULL, NULL, hInstance, hRsrc,
949 (HRSRC)NULL);
950 #else
951 ICONINFO iconInfo;
952
953 if(NtUserGetIconInfo(ResIcon, &iconInfo, NULL, NULL, NULL, FALSE))
954 NtUserSetCursorIconData((HICON)hIcon, hinst, NULL, &iconInfo);
955 #endif
956 }
957
958 return hIcon;
959 }
960
961
962 /*************************************************************************
963 * CURSORICON_ExtCopy
964 *
965 * Copies an Image from the Cache if LR_COPYFROMRESOURCE is specified
966 *
967 * PARAMS
968 * Handle [I] handle to an Image
969 * nType [I] Type of Handle (IMAGE_CURSOR | IMAGE_ICON)
970 * iDesiredCX [I] The Desired width of the Image
971 * iDesiredCY [I] The desired height of the Image
972 * nFlags [I] The flags from CopyImage
973 *
974 * RETURNS
975 * Success: The new handle of the Image
976 *
977 * NOTES
978 * LR_COPYDELETEORG and LR_MONOCHROME are currently not implemented.
979 * LR_MONOCHROME should be implemented by CreateIconFromResourceEx.
980 * LR_COPYFROMRESOURCE will only work if the Image is in the Cache.
981 *
982 *
983 */
984
985 static HICON CURSORICON_ExtCopy(HICON hIcon, UINT nType,
986 INT iDesiredCX, INT iDesiredCY,
987 UINT nFlags)
988 {
989 HICON hNew=0;
990
991 TRACE_(icon)("hIcon %p, nType %u, iDesiredCX %i, iDesiredCY %i, nFlags %u\n",
992 hIcon, nType, iDesiredCX, iDesiredCY, nFlags);
993
994 if(hIcon == 0)
995 {
996 return 0;
997 }
998
999 /* Best Fit or Monochrome */
1000 if( (nFlags & LR_COPYFROMRESOURCE
1001 && (iDesiredCX > 0 || iDesiredCY > 0))
1002 || nFlags & LR_MONOCHROME)
1003 {
1004 TRACE("Copying from resource isn't implemented yet\n");
1005 hNew = CopyIcon(hIcon);
1006
1007 #if 0
1008 ICONCACHE* pIconCache = CURSORICON_FindCache(hIcon);
1009
1010 /* Not Found in Cache, then do a straight copy
1011 */
1012 if(pIconCache == NULL)
1013 {
1014 hNew = CopyIcon( hIcon );
1015 if(nFlags & LR_COPYFROMRESOURCE)
1016 {
1017 TRACE_(icon)("LR_COPYFROMRESOURCE: Failed to load from cache\n");
1018 }
1019 }
1020 else
1021 {
1022 int iTargetCY = iDesiredCY, iTargetCX = iDesiredCX;
1023 LPBYTE pBits;
1024 HANDLE hMem;
1025 HRSRC hRsrc;
1026 DWORD dwBytesInRes;
1027 WORD wResId;
1028 CURSORICONDIR *pDir;
1029 CURSORICONDIRENTRY *pDirEntry;
1030 BOOL bIsIcon = (nType == IMAGE_ICON);
1031
1032 /* Completing iDesiredCX CY for Monochrome Bitmaps if needed
1033 */
1034 if(((nFlags & LR_MONOCHROME) && !(nFlags & LR_COPYFROMRESOURCE))
1035 || (iDesiredCX == 0 && iDesiredCY == 0))
1036 {
1037 iDesiredCY = GetSystemMetrics(bIsIcon ?
1038 SM_CYICON : SM_CYCURSOR);
1039 iDesiredCX = GetSystemMetrics(bIsIcon ?
1040 SM_CXICON : SM_CXCURSOR);
1041 }
1042
1043 /* Retrieve the CURSORICONDIRENTRY
1044 */
1045 if (!(hMem = LoadResource( pIconCache->hModule ,
1046 pIconCache->hGroupRsrc)))
1047 {
1048 return 0;
1049 }
1050 if (!(pDir = LockResource( hMem )))
1051 {
1052 return 0;
1053 }
1054
1055 /* Find Best Fit
1056 */
1057 if(bIsIcon)
1058 {
1059 pDirEntry = CURSORICON_FindBestIconRes(
1060 pDir, iDesiredCX, iDesiredCY, 256 );
1061 }
1062 else
1063 {
1064 pDirEntry = CURSORICON_FindBestCursorRes(
1065 pDir, iDesiredCX, iDesiredCY, 1);
1066 }
1067
1068 wResId = pDirEntry->wResId;
1069 dwBytesInRes = pDirEntry->dwBytesInRes;
1070 FreeResource(hMem);
1071
1072 TRACE_(icon)("ResID %u, BytesInRes %u, Width %d, Height %d DX %d, DY %d\n",
1073 wResId, dwBytesInRes, pDirEntry->ResInfo.icon.bWidth,
1074 pDirEntry->ResInfo.icon.bHeight, iDesiredCX, iDesiredCY);
1075
1076 /* Get the Best Fit
1077 */
1078 if (!(hRsrc = FindResourceW(pIconCache->hModule ,
1079 MAKEINTRESOURCEW(wResId), (LPWSTR)(bIsIcon ? RT_ICON : RT_CURSOR))))
1080 {
1081 return 0;
1082 }
1083 if (!(hMem = LoadResource( pIconCache->hModule , hRsrc )))
1084 {
1085 return 0;
1086 }
1087
1088 pBits = LockResource( hMem );
1089
1090 if(nFlags & LR_DEFAULTSIZE)
1091 {
1092 iTargetCY = GetSystemMetrics(SM_CYICON);
1093 iTargetCX = GetSystemMetrics(SM_CXICON);
1094 }
1095
1096 /* Create a New Icon with the proper dimension
1097 */
1098 hNew = CreateIconFromResourceEx( pBits, dwBytesInRes,
1099 bIsIcon, 0x00030000, iTargetCX, iTargetCY, nFlags);
1100 FreeResource(hMem);
1101 }
1102 #endif
1103 }
1104 else hNew = CopyIcon( hIcon );
1105 return hNew;
1106 }
1107
1108
1109 /***********************************************************************
1110 * CreateCursor (USER32.@)
1111 */
1112 HCURSOR WINAPI CreateCursor( HINSTANCE hInstance,
1113 INT xHotSpot, INT yHotSpot,
1114 INT nWidth, INT nHeight,
1115 LPCVOID lpANDbits, LPCVOID lpXORbits )
1116 {
1117 ICONINFO info;
1118 HCURSOR hCursor;
1119
1120 TRACE_(cursor)("%dx%d spot=%d,%d xor=%p and=%p\n",
1121 nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits);
1122
1123 info.fIcon = FALSE;
1124 info.xHotspot = xHotSpot;
1125 info.yHotspot = yHotSpot;
1126 info.hbmMask = CreateBitmap( nWidth, nHeight, 1, 1, lpANDbits );
1127 info.hbmColor = CreateBitmap( nWidth, nHeight, 1, 1, lpXORbits );
1128 hCursor = CreateIconIndirect( &info );
1129 DeleteObject( info.hbmMask );
1130 DeleteObject( info.hbmColor );
1131 return hCursor;
1132 }
1133
1134
1135 /***********************************************************************
1136 * CreateIcon (USER32.@)
1137 *
1138 * Creates an icon based on the specified bitmaps. The bitmaps must be
1139 * provided in a device dependent format and will be resized to
1140 * (SM_CXICON,SM_CYICON) and depth converted to match the screen's color
1141 * depth. The provided bitmaps must be top-down bitmaps.
1142 * Although Windows does not support 15bpp(*) this API must support it
1143 * for Winelib applications.
1144 *
1145 * (*) Windows does not support 15bpp but it supports the 555 RGB 16bpp
1146 * format!
1147 *
1148 * RETURNS
1149 * Success: handle to an icon
1150 * Failure: NULL
1151 *
1152 * FIXME: Do we need to resize the bitmaps?
1153 */
1154 HICON WINAPI CreateIcon(
1155 HINSTANCE hInstance, /* [in] the application's hInstance */
1156 int nWidth, /* [in] the width of the provided bitmaps */
1157 int nHeight, /* [in] the height of the provided bitmaps */
1158 BYTE bPlanes, /* [in] the number of planes in the provided bitmaps */
1159 BYTE bBitsPixel, /* [in] the number of bits per pixel of the lpXORbits bitmap */
1160 const BYTE* lpANDbits, /* [in] a monochrome bitmap representing the icon's mask */
1161 const BYTE* lpXORbits) /* [in] the icon's 'color' bitmap */
1162 {
1163 ICONINFO iinfo;
1164 HICON hIcon;
1165
1166 TRACE_(icon)("%dx%d, planes %d, bpp %d, xor %p, and %p\n",
1167 nWidth, nHeight, bPlanes, bBitsPixel, lpXORbits, lpANDbits);
1168
1169 iinfo.fIcon = TRUE;
1170 iinfo.xHotspot = nWidth / 2;
1171 iinfo.yHotspot = nHeight / 2;
1172 if (bPlanes * bBitsPixel > 1)
1173 {
1174 iinfo.hbmColor = CreateBitmap( nWidth, nHeight, bPlanes, bBitsPixel, lpXORbits );
1175 iinfo.hbmMask = CreateBitmap( nWidth, nHeight, 1, 1, lpANDbits );
1176 }
1177 else
1178 {
1179 iinfo.hbmMask = CreateBitmap( nWidth, nHeight * 2, 1, 1, lpANDbits );
1180 iinfo.hbmColor = NULL;
1181 }
1182
1183 hIcon = CreateIconIndirect( &iinfo );
1184
1185 DeleteObject( iinfo.hbmMask );
1186 if (iinfo.hbmColor) DeleteObject( iinfo.hbmColor );
1187
1188 return hIcon;
1189 }
1190
1191
1192 /***********************************************************************
1193 * CopyIcon (USER32.@)
1194 */
1195 HICON WINAPI CopyIcon( HICON hIcon )
1196 {
1197 HICON hRetIcon = NULL;
1198 ICONINFO IconInfo;
1199
1200 if(GetIconInfo(hIcon, &IconInfo))
1201 {
1202 hRetIcon = CreateIconIndirect(&IconInfo);
1203 DeleteObject(IconInfo.hbmColor);
1204 DeleteObject(IconInfo.hbmMask);
1205 }
1206
1207 return hRetIcon;
1208 }
1209
1210
1211 /***********************************************************************
1212 * DestroyIcon (USER32.@)
1213 */
1214 BOOL WINAPI DestroyIcon( HICON hIcon )
1215 {
1216 TRACE_(icon)("%p\n", hIcon );
1217
1218 return NtUserDestroyCursor(hIcon, 0);
1219 }
1220
1221
1222 /***********************************************************************
1223 * DestroyCursor (USER32.@)
1224 */
1225 BOOL WINAPI DestroyCursor( HCURSOR hCursor )
1226 {
1227 if (GetCursor() == hCursor)
1228 {
1229 WARN_(cursor)("Destroying active cursor!\n" );
1230 return FALSE;
1231 }
1232 return DestroyIcon( hCursor );
1233 }
1234
1235 /***********************************************************************
1236 * DrawIcon (USER32.@)
1237 */
1238 BOOL WINAPI DrawIcon( HDC hdc, INT x, INT y, HICON hIcon )
1239 {
1240 return DrawIconEx( hdc, x, y, hIcon, 0, 0, 0, 0, DI_NORMAL | DI_COMPAT | DI_DEFAULTSIZE );
1241 }
1242
1243 /***********************************************************************
1244 * ShowCursor (USER32.@)
1245 */
1246 INT WINAPI /*DECLSPEC_HOTPATCH*/ ShowCursor( BOOL bShow )
1247 {
1248 return NtUserxShowCursor(bShow);
1249 }
1250
1251 /***********************************************************************
1252 * GetCursor (USER32.@)
1253 */
1254 HCURSOR WINAPI GetCursor(void)
1255 {
1256 return (HCURSOR)NtUserGetThreadState(THREADSTATE_GETCURSOR);
1257 }
1258
1259
1260 /***********************************************************************
1261 * SetSystemCursor (USER32.@)
1262 */
1263 BOOL WINAPI SetSystemCursor(HCURSOR hcur, DWORD id)
1264 {
1265 FIXME("(%p,%08x),stub!\n", hcur, id);
1266 return TRUE;
1267 }
1268
1269
1270 /**********************************************************************
1271 * LookupIconIdFromDirectoryEx (USER32.@)
1272 */
1273 INT WINAPI LookupIconIdFromDirectoryEx( LPBYTE xdir, BOOL bIcon,
1274 INT width, INT height, UINT cFlag )
1275 {
1276 CURSORICONDIR *dir = (CURSORICONDIR*)xdir;
1277 UINT retVal = 0;
1278 if( dir && !dir->idReserved && (dir->idType & 3) )
1279 {
1280 CURSORICONDIRENTRY* entry;
1281
1282 const HDC hdc = GetDC(0);
1283 const int depth = (cFlag & LR_MONOCHROME) ?
1284 1 : GetDeviceCaps(hdc, BITSPIXEL);
1285 ReleaseDC(0, hdc);
1286
1287 if( bIcon )
1288 entry = CURSORICON_FindBestIconRes( dir, width, height, depth );
1289 else
1290 entry = CURSORICON_FindBestCursorRes( dir, width, height, depth );
1291
1292 if( entry ) retVal = entry->wResId;
1293 }
1294 else WARN_(cursor)("invalid resource directory\n");
1295 return retVal;
1296 }
1297
1298 /**********************************************************************
1299 * LookupIconIdFromDirectory (USER32.@)
1300 */
1301 INT WINAPI LookupIconIdFromDirectory( LPBYTE dir, BOOL bIcon )
1302 {
1303 return LookupIconIdFromDirectoryEx( dir, bIcon,
1304 bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
1305 bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
1306 }
1307
1308 /***********************************************************************
1309 * LoadCursorW (USER32.@)
1310 */
1311 HCURSOR WINAPI LoadCursorW(HINSTANCE hInstance, LPCWSTR name)
1312 {
1313 TRACE("%p, %s\n", hInstance, debugstr_w(name));
1314
1315 return LoadImageW( hInstance, name, IMAGE_CURSOR, 0, 0,
1316 LR_SHARED | LR_DEFAULTSIZE );
1317 }
1318
1319 /***********************************************************************
1320 * LoadCursorA (USER32.@)
1321 */
1322 HCURSOR WINAPI LoadCursorA(HINSTANCE hInstance, LPCSTR name)
1323 {
1324 TRACE("%p, %s\n", hInstance, debugstr_a(name));
1325
1326 return LoadImageA( hInstance, name, IMAGE_CURSOR, 0, 0,
1327 LR_SHARED | LR_DEFAULTSIZE );
1328 }
1329
1330 /***********************************************************************
1331 * LoadCursorFromFileW (USER32.@)
1332 */
1333 HCURSOR WINAPI LoadCursorFromFileW (LPCWSTR name)
1334 {
1335 TRACE("%s\n", debugstr_w(name));
1336
1337 return LoadImageW( 0, name, IMAGE_CURSOR, 0, 0,
1338 LR_LOADFROMFILE | LR_DEFAULTSIZE );
1339 }
1340
1341 /***********************************************************************
1342 * LoadCursorFromFileA (USER32.@)
1343 */
1344 HCURSOR WINAPI LoadCursorFromFileA (LPCSTR name)
1345 {
1346 TRACE("%s\n", debugstr_a(name));
1347
1348 return LoadImageA( 0, name, IMAGE_CURSOR, 0, 0,
1349 LR_LOADFROMFILE | LR_DEFAULTSIZE );
1350 }
1351
1352 /***********************************************************************
1353 * LoadIconW (USER32.@)
1354 */
1355 HICON WINAPI LoadIconW(HINSTANCE hInstance, LPCWSTR name)
1356 {
1357 TRACE("%p, %s\n", hInstance, debugstr_w(name));
1358
1359 return LoadImageW( hInstance, name, IMAGE_ICON, 0, 0,
1360 LR_SHARED | LR_DEFAULTSIZE );
1361 }
1362
1363 /***********************************************************************
1364 * LoadIconA (USER32.@)
1365 */
1366 HICON WINAPI LoadIconA(HINSTANCE hInstance, LPCSTR name)
1367 {
1368 TRACE("%p, %s\n", hInstance, debugstr_a(name));
1369
1370 return LoadImageA( hInstance, name, IMAGE_ICON, 0, 0,
1371 LR_SHARED | LR_DEFAULTSIZE );
1372 }
1373
1374 /**********************************************************************
1375 * GetIconInfo (USER32.@)
1376 */
1377 BOOL WINAPI GetIconInfo(HICON hIcon, PICONINFO iconinfo)
1378 {
1379 return NtUserGetIconInfo(hIcon, iconinfo, 0, 0, 0, 0);
1380 }
1381
1382 /* copy an icon bitmap, even when it can't be selected into a DC */
1383 /* helper for CreateIconIndirect */
1384 static void stretch_blt_icon( HDC hdc_dst, int dst_x, int dst_y, int dst_width, int dst_height,
1385 HBITMAP src, int width, int height )
1386 {
1387 HDC hdc = CreateCompatibleDC( 0 );
1388
1389 if (!SelectObject( hdc, src )) /* do it the hard way */
1390 {
1391 BITMAPINFO *info;
1392 void *bits;
1393
1394 if (!(info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) return;
1395 info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1396 info->bmiHeader.biWidth = width;
1397 info->bmiHeader.biHeight = height;
1398 info->bmiHeader.biPlanes = GetDeviceCaps( hdc_dst, PLANES );
1399 info->bmiHeader.biBitCount = GetDeviceCaps( hdc_dst, BITSPIXEL );
1400 info->bmiHeader.biCompression = BI_RGB;
1401 info->bmiHeader.biSizeImage = height * get_dib_width_bytes( width, info->bmiHeader.biBitCount );
1402 info->bmiHeader.biXPelsPerMeter = 0;
1403 info->bmiHeader.biYPelsPerMeter = 0;
1404 info->bmiHeader.biClrUsed = 0;
1405 info->bmiHeader.biClrImportant = 0;
1406 bits = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage );
1407 if (bits && GetDIBits( hdc, src, 0, height, bits, info, DIB_RGB_COLORS ))
1408 StretchDIBits( hdc_dst, dst_x, dst_y, dst_width, dst_height,
1409 0, 0, width, height, bits, info, DIB_RGB_COLORS, SRCCOPY );
1410
1411 HeapFree( GetProcessHeap(), 0, bits );
1412 HeapFree( GetProcessHeap(), 0, info );
1413 }
1414 else StretchBlt( hdc_dst, dst_x, dst_y, dst_width, dst_height, hdc, 0, 0, width, height, SRCCOPY );
1415
1416 DeleteDC( hdc );
1417 }
1418
1419 /**********************************************************************
1420 * CreateIconIndirect (USER32.@)
1421 */
1422 HICON WINAPI CreateIconIndirect(PICONINFO iconinfo)
1423 {
1424 BITMAP bmpXor, bmpAnd;
1425 HBITMAP color = 0, mask;
1426 int width, height;
1427 HDC hdc;
1428 ICONINFO iinfo;
1429
1430 TRACE("color %p, mask %p, hotspot %ux%u, fIcon %d\n",
1431 iconinfo->hbmColor, iconinfo->hbmMask,
1432 iconinfo->xHotspot, iconinfo->yHotspot, iconinfo->fIcon);
1433
1434 if (!iconinfo->hbmMask) return 0;
1435
1436 GetObjectW( iconinfo->hbmMask, sizeof(bmpAnd), &bmpAnd );
1437 TRACE("mask: width %d, height %d, width bytes %d, planes %u, bpp %u\n",
1438 bmpAnd.bmWidth, bmpAnd.bmHeight, bmpAnd.bmWidthBytes,
1439 bmpAnd.bmPlanes, bmpAnd.bmBitsPixel);
1440
1441 if (iconinfo->hbmColor)
1442 {
1443 GetObjectW( iconinfo->hbmColor, sizeof(bmpXor), &bmpXor );
1444 TRACE("color: width %d, height %d, width bytes %d, planes %u, bpp %u\n",
1445 bmpXor.bmWidth, bmpXor.bmHeight, bmpXor.bmWidthBytes,
1446 bmpXor.bmPlanes, bmpXor.bmBitsPixel);
1447
1448 // the size of the mask bitmap always determines the icon size!
1449 width = bmpAnd.bmWidth;
1450 height = bmpAnd.bmHeight;
1451 if (bmpXor.bmPlanes * bmpXor.bmBitsPixel != 1 )
1452 {
1453 color = CreateBitmap( width, height, bmpXor.bmPlanes, bmpXor.bmBitsPixel, NULL );
1454 if(!color)
1455 {
1456 ERR("Unable to create color bitmap!\n");
1457 return NULL;
1458 }
1459 mask = CreateBitmap( width, height, 1, 1, NULL );
1460 if(!mask)
1461 {
1462 ERR("Unable to create mask bitmap!\n");
1463 DeleteObject(color);
1464 return NULL;
1465 }
1466 }
1467 else
1468 {
1469 mask = CreateBitmap( width, height * 2, 1, 1, NULL );
1470 if(!mask)
1471 {
1472 ERR("Unable to create mask bitmap!\n");
1473 return NULL;
1474 }
1475 }
1476 }
1477 else
1478 {
1479 width = bmpAnd.bmWidth;
1480 height = bmpAnd.bmHeight;
1481 mask = CreateBitmap( width, height, 1, 1, NULL );
1482 }
1483
1484 hdc = CreateCompatibleDC( 0 );
1485 SelectObject( hdc, mask );
1486 stretch_blt_icon( hdc, 0, 0, width, height, iconinfo->hbmMask, bmpAnd.bmWidth, bmpAnd.bmHeight );
1487
1488 if (color)
1489 {
1490 SelectObject( hdc, color );
1491 stretch_blt_icon( hdc, 0, 0, width, height, iconinfo->hbmColor, width, height );
1492 }
1493 else if (iconinfo->hbmColor)
1494 {
1495 stretch_blt_icon( hdc, 0, height, width, height, iconinfo->hbmColor, width, height );
1496 }
1497 else height /= 2;
1498
1499 DeleteDC( hdc );
1500
1501 iinfo.hbmColor = color ;
1502 iinfo.hbmMask = mask ;
1503 iinfo.fIcon = iconinfo->fIcon;
1504 if (iinfo.fIcon)
1505 {
1506 iinfo.xHotspot = width / 2;
1507 iinfo.yHotspot = height / 2;
1508 }
1509 else
1510 {
1511 iinfo.xHotspot = iconinfo->xHotspot;
1512 iinfo.yHotspot = iconinfo->yHotspot;
1513 }
1514
1515 return CreateCursorIconHandle(&iinfo);
1516 }
1517
1518 /******************************************************************************
1519 * DrawIconEx (USER32.@) Draws an icon or cursor on device context
1520 *
1521 * NOTES
1522 * Why is this using SM_CXICON instead of SM_CXCURSOR?
1523 *
1524 * PARAMS
1525 * hdc [I] Handle to device context
1526 * x0 [I] X coordinate of upper left corner
1527 * y0 [I] Y coordinate of upper left corner
1528 * hIcon [I] Handle to icon to draw
1529 * cxWidth [I] Width of icon
1530 * cyWidth [I] Height of icon
1531 * istep [I] Index of frame in animated cursor
1532 * hbr [I] Handle to background brush
1533 * flags [I] Icon-drawing flags
1534 *
1535 * RETURNS
1536 * Success: TRUE
1537 * Failure: FALSE
1538 */
1539 BOOL WINAPI DrawIconEx( HDC hdc, INT xLeft, INT yTop, HICON hIcon,
1540 INT cxWidth, INT cyWidth, UINT istepIfAniCur,
1541 HBRUSH hbrFlickerFreeDraw, UINT diFlags )
1542 {
1543 return NtUserDrawIconEx(hdc, xLeft, yTop, hIcon, cxWidth, cyWidth,
1544 istepIfAniCur, hbrFlickerFreeDraw, diFlags,
1545 0, 0);
1546 }
1547
1548 /***********************************************************************
1549 * DIB_FixColorsToLoadflags
1550 *
1551 * Change color table entries when LR_LOADTRANSPARENT or LR_LOADMAP3DCOLORS
1552 * are in loadflags
1553 */
1554 static void DIB_FixColorsToLoadflags(BITMAPINFO * bmi, UINT loadflags, BYTE pix)
1555 {
1556 int colors;
1557 COLORREF c_W, c_S, c_F, c_L, c_C;
1558 int incr,i;
1559 RGBQUAD *ptr;
1560 int bitmap_type;
1561 LONG width;
1562 LONG height;
1563 WORD bpp;
1564 DWORD compr;
1565
1566 if (((bitmap_type = DIB_GetBitmapInfo((BITMAPINFOHEADER*) bmi, &width, &height, &bpp, &compr)) == -1))
1567 {
1568 WARN_(resource)("Invalid bitmap\n");
1569 return;
1570 }
1571
1572 if (bpp > 8) return;
1573
1574 if (bitmap_type == 0) /* BITMAPCOREHEADER */
1575 {
1576 incr = 3;
1577 colors = 1 << bpp;
1578 }
1579 else
1580 {
1581 incr = 4;
1582 colors = bmi->bmiHeader.biClrUsed;
1583 if (colors > 256) colors = 256;
1584 if (!colors && (bpp <= 8)) colors = 1 << bpp;
1585 }
1586
1587 c_W = GetSysColor(COLOR_WINDOW);
1588 c_S = GetSysColor(COLOR_3DSHADOW);
1589 c_F = GetSysColor(COLOR_3DFACE);
1590 c_L = GetSysColor(COLOR_3DLIGHT);
1591
1592 if (loadflags & LR_LOADTRANSPARENT) {
1593 switch (bpp) {
1594 case 1: pix = pix >> 7; break;
1595 case 4: pix = pix >> 4; break;
1596 case 8: break;
1597 default:
1598 WARN_(resource)("(%d): Unsupported depth\n", bpp);
1599 return;
1600 }
1601 if (pix >= colors) {
1602 WARN_(resource)("pixel has color index greater than biClrUsed!\n");
1603 return;
1604 }
1605 if (loadflags & LR_LOADMAP3DCOLORS) c_W = c_F;
1606 ptr = (RGBQUAD*)((char*)bmi->bmiColors+pix*incr);
1607 ptr->rgbBlue = GetBValue(c_W);
1608 ptr->rgbGreen = GetGValue(c_W);
1609 ptr->rgbRed = GetRValue(c_W);
1610 }
1611 if (loadflags & LR_LOADMAP3DCOLORS)
1612 for (i=0; i<colors; i++) {
1613 ptr = (RGBQUAD*)((char*)bmi->bmiColors+i*incr);
1614 c_C = RGB(ptr->rgbRed, ptr->rgbGreen, ptr->rgbBlue);
1615 if (c_C == RGB(128, 128, 128)) {
1616 ptr->rgbRed = GetRValue(c_S);
1617 ptr->rgbGreen = GetGValue(c_S);
1618 ptr->rgbBlue = GetBValue(c_S);
1619 } else if (c_C == RGB(192, 192, 192)) {
1620 ptr->rgbRed = GetRValue(c_F);
1621 ptr->rgbGreen = GetGValue(c_F);
1622 ptr->rgbBlue = GetBValue(c_F);
1623 } else if (c_C == RGB(223, 223, 223)) {
1624 ptr->rgbRed = GetRValue(c_L);
1625 ptr->rgbGreen = GetGValue(c_L);
1626 ptr->rgbBlue = GetBValue(c_L);
1627 }
1628 }
1629 }
1630
1631
1632 /**********************************************************************
1633 * BITMAP_Load
1634 */
1635 static HBITMAP BITMAP_Load( HINSTANCE instance, LPCWSTR name,
1636 INT desiredx, INT desiredy, UINT loadflags )
1637 {
1638 HBITMAP hbitmap = 0, orig_bm;
1639 HRSRC hRsrc;
1640 HGLOBAL handle;
1641 char *ptr = NULL;
1642 BITMAPINFO *info, *fix_info = NULL, *scaled_info = NULL;
1643 int size;
1644 BYTE pix;
1645 char *bits;
1646 LONG width, height, new_width, new_height;
1647 WORD bpp_dummy;
1648 DWORD compr_dummy, offbits = 0;
1649 INT bm_type;
1650 HDC screen_mem_dc = NULL;
1651
1652 if (!(loadflags & LR_LOADFROMFILE))
1653 {
1654 if (!instance)
1655 {
1656 /* OEM bitmap: try to load the resource from user32.dll */
1657 instance = User32Instance;
1658 }
1659
1660 if (!(hRsrc = FindResourceW( instance, name, (LPWSTR)RT_BITMAP ))) return 0;
1661 if (!(handle = LoadResource( instance, hRsrc ))) return 0;
1662
1663 if ((info = LockResource( handle )) == NULL) return 0;
1664 }
1665 else
1666 {
1667 BITMAPFILEHEADER * bmfh;
1668
1669 if (!(ptr = map_fileW( name, NULL ))) return 0;
1670 info = (BITMAPINFO *)(ptr + sizeof(BITMAPFILEHEADER));
1671 bmfh = (BITMAPFILEHEADER *)ptr;
1672 if (bmfh->bfType != 0x4d42 /* 'BM' */)
1673 {
1674 WARN("Invalid/unsupported bitmap format!\n");
1675 goto end_close;
1676 }
1677 if (bmfh->bfOffBits) offbits = bmfh->bfOffBits - sizeof(BITMAPFILEHEADER);
1678 }
1679
1680 size = bitmap_info_size(info, DIB_RGB_COLORS);
1681 fix_info = HeapAlloc(GetProcessHeap(), 0, size);
1682 scaled_info = HeapAlloc(GetProcessHeap(), 0, size);
1683
1684 if (!fix_info || !scaled_info) goto end;
1685 memcpy(fix_info, info, size);
1686
1687 pix = *((LPBYTE)info + size);
1688 DIB_FixColorsToLoadflags(fix_info, loadflags, pix);
1689
1690 memcpy(scaled_info, fix_info, size);
1691 bm_type = DIB_GetBitmapInfo( &fix_info->bmiHeader, &width, &height,
1692 &bpp_dummy, &compr_dummy);
1693 if(desiredx != 0)
1694 new_width = desiredx;
1695 else
1696 new_width = width;
1697
1698 if(desiredy != 0)
1699 new_height = height > 0 ? desiredy : -desiredy;
1700 else
1701 new_height = height;
1702
1703 if (bm_type == 0)
1704 {
1705 BITMAPCOREHEADER *core = (BITMAPCOREHEADER *)&scaled_info->bmiHeader;
1706 core->bcWidth = new_width;
1707 core->bcHeight = new_height;
1708 }
1709 else if (bm_type == 1)
1710 {
1711 /* Some sanity checks for BITMAPINFO (not applicable to BITMAPCOREINFO) */
1712 if (info->bmiHeader.biHeight > 65535 || info->bmiHeader.biWidth > 65535) {
1713 WARN("Broken BitmapInfoHeader!\n");
1714 goto end;
1715 }
1716
1717 scaled_info->bmiHeader.biWidth = new_width;
1718 scaled_info->bmiHeader.biHeight = new_height;
1719 }
1720 else
1721 goto end;
1722
1723 if (new_height < 0) new_height = -new_height;
1724
1725 if (!screen_dc) screen_dc = CreateDCW( DISPLAYW, NULL, NULL, NULL );
1726 if (!(screen_mem_dc = CreateCompatibleDC( screen_dc ))) goto end;
1727
1728 bits = (char *)info + (offbits ? offbits : size);
1729
1730 if (loadflags & LR_CREATEDIBSECTION)
1731 {
1732 scaled_info->bmiHeader.biCompression = 0; /* DIBSection can't be compressed */
1733 hbitmap = CreateDIBSection(screen_dc, scaled_info, DIB_RGB_COLORS, NULL, 0, 0);
1734 }
1735 else
1736 {
1737 if (is_dib_monochrome(fix_info))
1738 hbitmap = CreateBitmap(new_width, new_height, 1, 1, NULL);
1739 else
1740 hbitmap = CreateCompatibleBitmap(screen_dc, new_width, new_height);
1741 }
1742
1743 orig_bm = SelectObject(screen_mem_dc, hbitmap);
1744 StretchDIBits(screen_mem_dc, 0, 0, new_width, new_height, 0, 0, width, height, bits, fix_info, DIB_RGB_COLORS, SRCCOPY);
1745 SelectObject(screen_mem_dc, orig_bm);
1746
1747 end:
1748 if (screen_mem_dc) DeleteDC(screen_mem_dc);
1749 HeapFree(GetProcessHeap(), 0, scaled_info);
1750 HeapFree(GetProcessHeap(), 0, fix_info);
1751 end_close:
1752 if (loadflags & LR_LOADFROMFILE) UnmapViewOfFile( ptr );
1753
1754 return hbitmap;
1755 }
1756
1757 /**********************************************************************
1758 * LoadImageA (USER32.@)
1759 *
1760 * See LoadImageW.
1761 */
1762 HANDLE WINAPI LoadImageA( HINSTANCE hinst, LPCSTR name, UINT type,
1763 INT desiredx, INT desiredy, UINT loadflags)
1764 {
1765 HANDLE res;
1766 LPWSTR u_name;
1767
1768 if (IS_INTRESOURCE(name))
1769 return LoadImageW(hinst, (LPCWSTR)name, type, desiredx, desiredy, loadflags);
1770
1771 _SEH2_TRY
1772 {
1773 DWORD len = MultiByteToWideChar( CP_ACP, 0, name, -1, NULL, 0 );
1774 u_name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
1775 MultiByteToWideChar( CP_ACP, 0, name, -1, u_name, len );
1776 }
1777 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1778 {
1779 SetLastError( ERROR_INVALID_PARAMETER );
1780 _SEH2_YIELD(return 0);
1781 }
1782 _SEH2_END
1783 res = LoadImageW(hinst, u_name, type, desiredx, desiredy, loadflags);
1784 HeapFree(GetProcessHeap(), 0, u_name);
1785 return res;
1786 }
1787
1788
1789 /******************************************************************************
1790 * LoadImageW (USER32.@) Loads an icon, cursor, or bitmap
1791 *
1792 * PARAMS
1793 * hinst [I] Handle of instance that contains image
1794 * name [I] Name of image
1795 * type [I] Type of image
1796 * desiredx [I] Desired width
1797 * desiredy [I] Desired height
1798 * loadflags [I] Load flags
1799 *
1800 * RETURNS
1801 * Success: Handle to newly loaded image
1802 * Failure: NULL
1803 *
1804 * FIXME: Implementation lacks some features, see LR_ defines in winuser.h
1805 */
1806 HANDLE WINAPI LoadImageW( HINSTANCE hinst, LPCWSTR name, UINT type,
1807 INT desiredx, INT desiredy, UINT loadflags )
1808 {
1809 TRACE_(resource)("(%p,%s,%d,%d,%d,0x%08x)\n",
1810 hinst,debugstr_w(name),type,desiredx,desiredy,loadflags);
1811
1812 if (loadflags & LR_DEFAULTSIZE) {
1813 if (type == IMAGE_ICON) {
1814 if (!desiredx) desiredx = GetSystemMetrics(SM_CXICON);
1815 if (!desiredy) desiredy = GetSystemMetrics(SM_CYICON);
1816 } else if (type == IMAGE_CURSOR) {
1817 if (!desiredx) desiredx = GetSystemMetrics(SM_CXCURSOR);
1818 if (!desiredy) desiredy = GetSystemMetrics(SM_CYCURSOR);
1819 }
1820 }
1821 if (loadflags & LR_LOADFROMFILE) loadflags &= ~LR_SHARED;
1822 switch (type) {
1823 case IMAGE_BITMAP:
1824 return BITMAP_Load( hinst, name, desiredx, desiredy, loadflags );
1825
1826 case IMAGE_ICON:
1827 if (!screen_dc) screen_dc = CreateDCW( DISPLAYW, NULL, NULL, NULL );
1828 if (screen_dc)
1829 {
1830 return CURSORICON_Load(hinst, name, desiredx, desiredy,
1831 GetDeviceCaps(screen_dc, BITSPIXEL),
1832 FALSE, loadflags);
1833 }
1834 break;
1835
1836 case IMAGE_CURSOR:
1837 return CURSORICON_Load(hinst, name, desiredx, desiredy,
1838 1, TRUE, loadflags);
1839 }
1840 return 0;
1841 }
1842
1843 /******************************************************************************
1844 * CopyImage (USER32.@) Creates new image and copies attributes to it
1845 *
1846 * PARAMS
1847 * hnd [I] Handle to image to copy
1848 * type [I] Type of image to copy
1849 * desiredx [I] Desired width of new image
1850 * desiredy [I] Desired height of new image
1851 * flags [I] Copy flags
1852 *
1853 * RETURNS
1854 * Success: Handle to newly created image
1855 * Failure: NULL
1856 *
1857 * BUGS
1858 * Only Windows NT 4.0 supports the LR_COPYRETURNORG flag for bitmaps,
1859 * all other versions (95/2000/XP have been tested) ignore it.
1860 *
1861 * NOTES
1862 * If LR_CREATEDIBSECTION is absent, the copy will be monochrome for
1863 * a monochrome source bitmap or if LR_MONOCHROME is present, otherwise
1864 * the copy will have the same depth as the screen.
1865 * The content of the image will only be copied if the bit depth of the
1866 * original image is compatible with the bit depth of the screen, or
1867 * if the source is a DIB section.
1868 * The LR_MONOCHROME flag is ignored if LR_CREATEDIBSECTION is present.
1869 */
1870 HANDLE WINAPI CopyImage( HANDLE hnd, UINT type, INT desiredx,
1871 INT desiredy, UINT flags )
1872 {
1873 TRACE("hnd=%p, type=%u, desiredx=%d, desiredy=%d, flags=%x\n",
1874 hnd, type, desiredx, desiredy, flags);
1875
1876 switch (type)
1877 {
1878 case IMAGE_BITMAP:
1879 {
1880 HBITMAP res = NULL;
1881 DIBSECTION ds;
1882 int objSize;
1883 BITMAPINFO * bi;
1884
1885 objSize = GetObjectW( hnd, sizeof(ds), &ds );
1886 if (!objSize) return 0;
1887 if ((desiredx < 0) || (desiredy < 0)) return 0;
1888
1889 if (flags & LR_COPYFROMRESOURCE)
1890 {
1891 FIXME("The flag LR_COPYFROMRESOURCE is not implemented for bitmaps\n");
1892 }
1893
1894 if (desiredx == 0) desiredx = ds.dsBm.bmWidth;
1895 if (desiredy == 0) desiredy = ds.dsBm.bmHeight;
1896
1897 /* Allocate memory for a BITMAPINFOHEADER structure and a
1898 color table. The maximum number of colors in a color table
1899 is 256 which corresponds to a bitmap with depth 8.
1900 Bitmaps with higher depths don't have color tables. */
1901 bi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1902 if (!bi) return 0;
1903
1904 bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
1905 bi->bmiHeader.biPlanes = ds.dsBm.bmPlanes;
1906 bi->bmiHeader.biBitCount = ds.dsBm.bmBitsPixel;
1907 bi->bmiHeader.biCompression = BI_RGB;
1908
1909 if (flags & LR_CREATEDIBSECTION)
1910 {
1911 /* Create a DIB section. LR_MONOCHROME is ignored */
1912 void * bits;
1913 HDC dc = CreateCompatibleDC(NULL);
1914
1915 if (objSize == sizeof(DIBSECTION))
1916 {
1917 /* The source bitmap is a DIB.
1918 Get its attributes to create an exact copy */
1919 memcpy(bi, &ds.dsBmih, sizeof(BITMAPINFOHEADER));
1920 }
1921
1922 /* Get the color table or the color masks */
1923 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
1924
1925 bi->bmiHeader.biWidth = desiredx;
1926 bi->bmiHeader.biHeight = desiredy;
1927 bi->bmiHeader.biSizeImage = 0;
1928
1929 res = CreateDIBSection(dc, bi, DIB_RGB_COLORS, &bits, NULL, 0);
1930 DeleteDC(dc);
1931 }
1932 else
1933 {
1934 /* Create a device-dependent bitmap */
1935
1936 BOOL monochrome = (flags & LR_MONOCHROME);
1937
1938 if (objSize == sizeof(DIBSECTION))
1939 {
1940 /* The source bitmap is a DIB section.
1941 Get its attributes */
1942 HDC dc = CreateCompatibleDC(NULL);
1943 bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
1944 bi->bmiHeader.biBitCount = ds.dsBm.bmBitsPixel;
1945 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
1946 DeleteDC(dc);
1947
1948 if (!monochrome && ds.dsBm.bmBitsPixel == 1)
1949 {
1950 /* Look if the colors of the DIB are black and white */
1951
1952 monochrome =
1953 (bi->bmiColors[0].rgbRed == 0xff
1954 && bi->bmiColors[0].rgbGreen == 0xff
1955 && bi->bmiColors[0].rgbBlue == 0xff
1956 && bi->bmiColors[0].rgbReserved == 0
1957 && bi->bmiColors[1].rgbRed == 0
1958 && bi->bmiColors[1].rgbGreen == 0
1959 && bi->bmiColors[1].rgbBlue == 0
1960 && bi->bmiColors[1].rgbReserved == 0)
1961 ||
1962 (bi->bmiColors[0].rgbRed == 0
1963 && bi->bmiColors[0].rgbGreen == 0
1964 && bi->bmiColors[0].rgbBlue == 0
1965 && bi->bmiColors[0].rgbReserved == 0
1966 && bi->bmiColors[1].rgbRed == 0xff
1967 && bi->bmiColors[1].rgbGreen == 0xff
1968 && bi->bmiColors[1].rgbBlue == 0xff
1969 && bi->bmiColors[1].rgbReserved == 0);
1970 }
1971 }
1972 else if (!monochrome)
1973 {
1974 monochrome = ds.dsBm.bmBitsPixel == 1;
1975 }
1976
1977 if (monochrome)
1978 {
1979 res = CreateBitmap(desiredx, desiredy, 1, 1, NULL);
1980 }
1981 else
1982 {
1983 HDC screenDC = GetDC(NULL);
1984 res = CreateCompatibleBitmap(screenDC, desiredx, desiredy);
1985 ReleaseDC(NULL, screenDC);
1986 }
1987 }
1988
1989 if (res)
1990 {
1991 /* Only copy the bitmap if it's a DIB section or if it's
1992 compatible to the screen */
1993 BOOL copyContents;
1994
1995 if (objSize == sizeof(DIBSECTION))
1996 {
1997 copyContents = TRUE;
1998 }
1999 else
2000 {
2001 HDC screenDC = GetDC(NULL);
2002 int screen_depth = GetDeviceCaps(screenDC, BITSPIXEL);
2003 ReleaseDC(NULL, screenDC);
2004
2005 copyContents = (ds.dsBm.bmBitsPixel == 1 || ds.dsBm.bmBitsPixel == screen_depth);
2006 }
2007
2008 if (copyContents)
2009 {
2010 /* The source bitmap may already be selected in a device context,
2011 use GetDIBits/StretchDIBits and not StretchBlt */
2012
2013 HDC dc;
2014 void * bits;
2015
2016 dc = CreateCompatibleDC(NULL);
2017
2018 bi->bmiHeader.biWidth = ds.dsBm.bmWidth;
2019 bi->bmiHeader.biHeight = ds.dsBm.bmHeight;
2020 bi->bmiHeader.biSizeImage = 0;
2021 bi->bmiHeader.biClrUsed = 0;
2022 bi->bmiHeader.biClrImportant = 0;
2023
2024 /* Fill in biSizeImage */
2025 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
2026 bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bi->bmiHeader.biSizeImage);
2027
2028 if (bits)
2029 {
2030 HBITMAP oldBmp;
2031
2032 /* Get the image bits of the source bitmap */
2033 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, bits, bi, DIB_RGB_COLORS);
2034
2035 /* Copy it to the destination bitmap */
2036 oldBmp = SelectObject(dc, res);
2037 StretchDIBits(dc, 0, 0, desiredx, desiredy,
2038 0, 0, ds.dsBm.bmWidth, ds.dsBm.bmHeight,
2039 bits, bi, DIB_RGB_COLORS, SRCCOPY);
2040 SelectObject(dc, oldBmp);
2041
2042 HeapFree(GetProcessHeap(), 0, bits);
2043 }
2044
2045 DeleteDC(dc);
2046 }
2047
2048 if (flags & LR_COPYDELETEORG)
2049 {
2050 DeleteObject(hnd);
2051 }
2052 }
2053 HeapFree(GetProcessHeap(), 0, bi);
2054 return res;
2055 }
2056 case IMAGE_ICON:
2057 return CURSORICON_ExtCopy(hnd,type, desiredx, desiredy, flags);
2058 case IMAGE_CURSOR:
2059 /* Should call CURSORICON_ExtCopy but more testing
2060 * needs to be done before we change this
2061 */
2062 if (flags) FIXME("Flags are ignored\n");
2063 return CopyCursor(hnd);
2064 }
2065 return 0;
2066 }
2067
2068
2069 /******************************************************************************
2070 * LoadBitmapW (USER32.@) Loads bitmap from the executable file
2071 *
2072 * RETURNS
2073 * Success: Handle to specified bitmap
2074 * Failure: NULL
2075 */
2076 HBITMAP WINAPI LoadBitmapW(
2077 HINSTANCE instance, /* [in] Handle to application instance */
2078 LPCWSTR name) /* [in] Address of bitmap resource name */
2079 {
2080 return LoadImageW( instance, name, IMAGE_BITMAP, 0, 0, 0 );
2081 }
2082
2083 /**********************************************************************
2084 * LoadBitmapA (USER32.@)
2085 *
2086 * See LoadBitmapW.
2087 */
2088 HBITMAP WINAPI LoadBitmapA( HINSTANCE instance, LPCSTR name )
2089 {
2090 return LoadImageA( instance, name, IMAGE_BITMAP, 0, 0, 0 );
2091 }
2092
2093 HCURSOR
2094 CursorIconToCursor(HICON hIcon,
2095 BOOL SemiTransparent)
2096 {
2097 UNIMPLEMENTED;
2098 return 0;
2099 }
2100
2101 /*
2102 * @implemented
2103 */
2104 BOOL
2105 WINAPI
2106 SetCursorPos(int X, int Y)
2107 {
2108 return NtUserxSetCursorPos(X,Y);
2109 }
2110
2111 /*
2112 * @implemented
2113 */
2114 BOOL
2115 WINAPI
2116 GetCursorPos(LPPOINT lpPoint)
2117 {
2118 BOOL res;
2119 /* Windows doesn't check if lpPoint == NULL, we do */
2120 if(!lpPoint)
2121 {
2122 SetLastError(ERROR_INVALID_PARAMETER);
2123 return FALSE;
2124 }
2125
2126 res = NtUserxGetCursorPos(lpPoint);
2127
2128 return res;
2129 }
2130
2131 /* INTERNAL ******************************************************************/
2132
2133 /* This callback routine is called directly after switching to gui mode */
2134 NTSTATUS
2135 WINAPI
2136 User32SetupDefaultCursors(PVOID Arguments,
2137 ULONG ArgumentLength)
2138 {
2139 BOOL *DefaultCursor = (BOOL*)Arguments;
2140 LRESULT Result = TRUE;
2141
2142 if(*DefaultCursor)
2143 {
2144 /* set default cursor */
2145 SetCursor(LoadCursorW(0, (LPCWSTR)IDC_ARROW));
2146 }
2147 else
2148 {
2149 /* FIXME load system cursor scheme */
2150 SetCursor(0);
2151 SetCursor(LoadCursorW(0, (LPCWSTR)IDC_ARROW));
2152 }
2153
2154 return(ZwCallbackReturn(&Result, sizeof(LRESULT), STATUS_SUCCESS));
2155 }
2156
2157 BOOL get_icon_size(HICON hIcon, SIZE *size)
2158 {
2159 ICONINFO info;
2160 BITMAP bitmap;
2161
2162 if (!GetIconInfo(hIcon, &info)) return FALSE;
2163 if (!GetObject(info.hbmMask, sizeof(bitmap), &bitmap)) return FALSE;
2164
2165 size->cx = bitmap.bmWidth;
2166 size->cy = bitmap.bmHeight;
2167
2168 /* Black and white icons store both the XOR and AND bitmap in hbmMask */
2169 if (!info.hbmColor)
2170 {
2171 size->cy /= 2;
2172 }
2173 else
2174 {
2175 DeleteObject(info.hbmColor);
2176 }
2177
2178 DeleteObject(info.hbmMask);
2179
2180 return TRUE;
2181 }