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