009a8475faca9bedd5a730d8927d2f94bade248a
[reactos.git] / 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 TRACE("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 if (bPlanes * bBitsPixel > 1)
1177 {
1178 iinfo.hbmColor = CreateBitmap( nWidth, nHeight, bPlanes, bBitsPixel, lpXORbits );
1179 iinfo.hbmMask = CreateBitmap( nWidth, nHeight, 1, 1, lpANDbits );
1180 }
1181 else
1182 {
1183 iinfo.hbmMask = CreateBitmap( nWidth, nHeight * 2, 1, 1, lpANDbits );
1184 iinfo.hbmColor = NULL;
1185 }
1186
1187 hIcon = CreateIconIndirect( &iinfo );
1188
1189 DeleteObject( iinfo.hbmMask );
1190 if (iinfo.hbmColor) DeleteObject( iinfo.hbmColor );
1191
1192 return hIcon;
1193 }
1194
1195
1196 /***********************************************************************
1197 * CopyIcon (USER32.@)
1198 */
1199 HICON WINAPI CopyIcon( HICON hIcon )
1200 {
1201 HICON hRetIcon = NULL;
1202 ICONINFO IconInfo;
1203
1204 if(GetIconInfo(hIcon, &IconInfo))
1205 {
1206 hRetIcon = CreateIconIndirect(&IconInfo);
1207 DeleteObject(IconInfo.hbmColor);
1208 DeleteObject(IconInfo.hbmMask);
1209 }
1210
1211 return hRetIcon;
1212 }
1213
1214
1215 /***********************************************************************
1216 * DestroyIcon (USER32.@)
1217 */
1218 BOOL WINAPI DestroyIcon( HICON hIcon )
1219 {
1220 TRACE_(icon)("%p\n", hIcon );
1221
1222 return NtUserDestroyCursor(hIcon, 0);
1223 }
1224
1225
1226 /***********************************************************************
1227 * DestroyCursor (USER32.@)
1228 */
1229 BOOL WINAPI DestroyCursor( HCURSOR hCursor )
1230 {
1231 if (GetCursor() == hCursor)
1232 {
1233 WARN_(cursor)("Destroying active cursor!\n" );
1234 return FALSE;
1235 }
1236 return DestroyIcon( hCursor );
1237 }
1238
1239 /***********************************************************************
1240 * DrawIcon (USER32.@)
1241 */
1242 BOOL WINAPI DrawIcon( HDC hdc, INT x, INT y, HICON hIcon )
1243 {
1244 return DrawIconEx( hdc, x, y, hIcon, 0, 0, 0, 0, DI_NORMAL | DI_COMPAT | DI_DEFAULTSIZE );
1245 }
1246
1247 /***********************************************************************
1248 * SetCursor (USER32.@)
1249 *
1250 * Set the cursor shape.
1251 *
1252 * RETURNS
1253 * A handle to the previous cursor shape.
1254 */
1255 HCURSOR WINAPI /*DECLSPEC_HOTPATCH*/ SetCursor( HCURSOR hCursor /* [in] Handle of cursor to show */ )
1256 {
1257 return NtUserSetCursor(hCursor);
1258 }
1259
1260 /***********************************************************************
1261 * ShowCursor (USER32.@)
1262 */
1263 INT WINAPI /*DECLSPEC_HOTPATCH*/ ShowCursor( BOOL bShow )
1264 {
1265 return NtUserShowCursor(bShow);
1266 }
1267
1268 /***********************************************************************
1269 * GetCursor (USER32.@)
1270 */
1271 HCURSOR WINAPI GetCursor(void)
1272 {
1273 CURSORINFO ci;
1274 ci.cbSize = sizeof(CURSORINFO);
1275 if(NtUserGetCursorInfo(&ci))
1276 return ci.hCursor;
1277 else
1278 return (HCURSOR)0;
1279 }
1280
1281
1282 /***********************************************************************
1283 * ClipCursor (USER32.@)
1284 */
1285 BOOL WINAPI /*DECLSPEC_HOTPATCH*/ ClipCursor( const RECT *rect )
1286 {
1287 return NtUserClipCursor((RECT *)rect);
1288 }
1289
1290
1291 /***********************************************************************
1292 * GetClipCursor (USER32.@)
1293 */
1294 BOOL WINAPI /*DECLSPEC_HOTPATCH*/ GetClipCursor( RECT *rect )
1295 {
1296 return NtUserGetClipCursor(rect);
1297 }
1298
1299
1300 /***********************************************************************
1301 * SetSystemCursor (USER32.@)
1302 */
1303 BOOL WINAPI SetSystemCursor(HCURSOR hcur, DWORD id)
1304 {
1305 FIXME("(%p,%08x),stub!\n", hcur, id);
1306 return TRUE;
1307 }
1308
1309
1310 /**********************************************************************
1311 * LookupIconIdFromDirectoryEx (USER32.@)
1312 */
1313 INT WINAPI LookupIconIdFromDirectoryEx( LPBYTE xdir, BOOL bIcon,
1314 INT width, INT height, UINT cFlag )
1315 {
1316 CURSORICONDIR *dir = (CURSORICONDIR*)xdir;
1317 UINT retVal = 0;
1318 if( dir && !dir->idReserved && (dir->idType & 3) )
1319 {
1320 CURSORICONDIRENTRY* entry;
1321
1322 const HDC hdc = GetDC(0);
1323 const int depth = (cFlag & LR_MONOCHROME) ?
1324 1 : GetDeviceCaps(hdc, BITSPIXEL);
1325 ReleaseDC(0, hdc);
1326
1327 if( bIcon )
1328 entry = CURSORICON_FindBestIconRes( dir, width, height, depth );
1329 else
1330 entry = CURSORICON_FindBestCursorRes( dir, width, height, depth );
1331
1332 if( entry ) retVal = entry->wResId;
1333 }
1334 else WARN_(cursor)("invalid resource directory\n");
1335 return retVal;
1336 }
1337
1338 /**********************************************************************
1339 * LookupIconIdFromDirectory (USER32.@)
1340 */
1341 INT WINAPI LookupIconIdFromDirectory( LPBYTE dir, BOOL bIcon )
1342 {
1343 return LookupIconIdFromDirectoryEx( dir, bIcon,
1344 bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
1345 bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
1346 }
1347
1348 /***********************************************************************
1349 * LoadCursorW (USER32.@)
1350 */
1351 HCURSOR WINAPI LoadCursorW(HINSTANCE hInstance, LPCWSTR name)
1352 {
1353 TRACE("%p, %s\n", hInstance, debugstr_w(name));
1354
1355 return LoadImageW( hInstance, name, IMAGE_CURSOR, 0, 0,
1356 LR_SHARED | LR_DEFAULTSIZE );
1357 }
1358
1359 /***********************************************************************
1360 * LoadCursorA (USER32.@)
1361 */
1362 HCURSOR WINAPI LoadCursorA(HINSTANCE hInstance, LPCSTR name)
1363 {
1364 TRACE("%p, %s\n", hInstance, debugstr_a(name));
1365
1366 return LoadImageA( hInstance, name, IMAGE_CURSOR, 0, 0,
1367 LR_SHARED | LR_DEFAULTSIZE );
1368 }
1369
1370 /***********************************************************************
1371 * LoadCursorFromFileW (USER32.@)
1372 */
1373 HCURSOR WINAPI LoadCursorFromFileW (LPCWSTR name)
1374 {
1375 TRACE("%s\n", debugstr_w(name));
1376
1377 return LoadImageW( 0, name, IMAGE_CURSOR, 0, 0,
1378 LR_LOADFROMFILE | LR_DEFAULTSIZE );
1379 }
1380
1381 /***********************************************************************
1382 * LoadCursorFromFileA (USER32.@)
1383 */
1384 HCURSOR WINAPI LoadCursorFromFileA (LPCSTR name)
1385 {
1386 TRACE("%s\n", debugstr_a(name));
1387
1388 return LoadImageA( 0, name, IMAGE_CURSOR, 0, 0,
1389 LR_LOADFROMFILE | LR_DEFAULTSIZE );
1390 }
1391
1392 /***********************************************************************
1393 * LoadIconW (USER32.@)
1394 */
1395 HICON WINAPI LoadIconW(HINSTANCE hInstance, LPCWSTR name)
1396 {
1397 TRACE("%p, %s\n", hInstance, debugstr_w(name));
1398
1399 return LoadImageW( hInstance, name, IMAGE_ICON, 0, 0,
1400 LR_SHARED | LR_DEFAULTSIZE );
1401 }
1402
1403 /***********************************************************************
1404 * LoadIconA (USER32.@)
1405 */
1406 HICON WINAPI LoadIconA(HINSTANCE hInstance, LPCSTR name)
1407 {
1408 TRACE("%p, %s\n", hInstance, debugstr_a(name));
1409
1410 return LoadImageA( hInstance, name, IMAGE_ICON, 0, 0,
1411 LR_SHARED | LR_DEFAULTSIZE );
1412 }
1413
1414 /**********************************************************************
1415 * GetIconInfo (USER32.@)
1416 */
1417 BOOL WINAPI GetIconInfo(HICON hIcon, PICONINFO iconinfo)
1418 {
1419 return NtUserGetIconInfo(hIcon, iconinfo, 0, 0, 0, 0);
1420 }
1421
1422 /* copy an icon bitmap, even when it can't be selected into a DC */
1423 /* helper for CreateIconIndirect */
1424 static void stretch_blt_icon( HDC hdc_dst, int dst_x, int dst_y, int dst_width, int dst_height,
1425 HBITMAP src, int width, int height )
1426 {
1427 HDC hdc = CreateCompatibleDC( 0 );
1428
1429 if (!SelectObject( hdc, src )) /* do it the hard way */
1430 {
1431 BITMAPINFO *info;
1432 void *bits;
1433
1434 if (!(info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) return;
1435 info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1436 info->bmiHeader.biWidth = width;
1437 info->bmiHeader.biHeight = height;
1438 info->bmiHeader.biPlanes = GetDeviceCaps( hdc_dst, PLANES );
1439 info->bmiHeader.biBitCount = GetDeviceCaps( hdc_dst, BITSPIXEL );
1440 info->bmiHeader.biCompression = BI_RGB;
1441 info->bmiHeader.biSizeImage = height * get_dib_width_bytes( width, info->bmiHeader.biBitCount );
1442 info->bmiHeader.biXPelsPerMeter = 0;
1443 info->bmiHeader.biYPelsPerMeter = 0;
1444 info->bmiHeader.biClrUsed = 0;
1445 info->bmiHeader.biClrImportant = 0;
1446 bits = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage );
1447 if (bits && GetDIBits( hdc, src, 0, height, bits, info, DIB_RGB_COLORS ))
1448 StretchDIBits( hdc_dst, dst_x, dst_y, dst_width, dst_height,
1449 0, 0, width, height, bits, info, DIB_RGB_COLORS, SRCCOPY );
1450
1451 HeapFree( GetProcessHeap(), 0, bits );
1452 HeapFree( GetProcessHeap(), 0, info );
1453 }
1454 else StretchBlt( hdc_dst, dst_x, dst_y, dst_width, dst_height, hdc, 0, 0, width, height, SRCCOPY );
1455
1456 DeleteDC( hdc );
1457 }
1458
1459 /**********************************************************************
1460 * CreateIconIndirect (USER32.@)
1461 */
1462 HICON WINAPI CreateIconIndirect(PICONINFO iconinfo)
1463 {
1464 BITMAP bmpXor, bmpAnd;
1465 HBITMAP color = 0, mask;
1466 int width, height;
1467 HDC hdc;
1468 ICONINFO iinfo;
1469
1470 TRACE("color %p, mask %p, hotspot %ux%u, fIcon %d\n",
1471 iconinfo->hbmColor, iconinfo->hbmMask,
1472 iconinfo->xHotspot, iconinfo->yHotspot, iconinfo->fIcon);
1473
1474 if (!iconinfo->hbmMask) return 0;
1475
1476 GetObjectW( iconinfo->hbmMask, sizeof(bmpAnd), &bmpAnd );
1477 TRACE("mask: width %d, height %d, width bytes %d, planes %u, bpp %u\n",
1478 bmpAnd.bmWidth, bmpAnd.bmHeight, bmpAnd.bmWidthBytes,
1479 bmpAnd.bmPlanes, bmpAnd.bmBitsPixel);
1480
1481 if (iconinfo->hbmColor)
1482 {
1483 GetObjectW( iconinfo->hbmColor, sizeof(bmpXor), &bmpXor );
1484 TRACE("color: width %d, height %d, width bytes %d, planes %u, bpp %u\n",
1485 bmpXor.bmWidth, bmpXor.bmHeight, bmpXor.bmWidthBytes,
1486 bmpXor.bmPlanes, bmpXor.bmBitsPixel);
1487
1488 // the size of the mask bitmap always determines the icon size!
1489 width = bmpAnd.bmWidth;
1490 height = bmpAnd.bmHeight;
1491 if (bmpXor.bmPlanes * bmpXor.bmBitsPixel != 1)
1492 {
1493 color = CreateBitmap( width, height, bmpXor.bmPlanes, bmpXor.bmBitsPixel, NULL );
1494 if(!color)
1495 {
1496 ERR("Unable to create color bitmap!\n");
1497 return NULL;
1498 }
1499 mask = CreateBitmap( width, height, 1, 1, NULL );
1500 if(!mask)
1501 {
1502 ERR("Unable to create mask bitmap!\n");
1503 DeleteObject(color);
1504 return NULL;
1505 }
1506 }
1507 else
1508 {
1509 mask = CreateBitmap( width, height * 2, 1, 1, NULL );
1510 if(!mask)
1511 {
1512 ERR("Unable to create mask bitmap!\n");
1513 return NULL;
1514 }
1515 }
1516 }
1517 else
1518 {
1519 width = bmpAnd.bmWidth;
1520 height = bmpAnd.bmHeight;
1521 mask = CreateBitmap( width, height, 1, 1, NULL );
1522 }
1523
1524 hdc = CreateCompatibleDC( 0 );
1525 SelectObject( hdc, mask );
1526 stretch_blt_icon( hdc, 0, 0, width, height, iconinfo->hbmMask, bmpAnd.bmWidth, bmpAnd.bmHeight );
1527
1528 if (color)
1529 {
1530 SelectObject( hdc, color );
1531 stretch_blt_icon( hdc, 0, 0, width, height, iconinfo->hbmColor, width, height );
1532 }
1533 else if (iconinfo->hbmColor)
1534 {
1535 stretch_blt_icon( hdc, 0, height, width, height, iconinfo->hbmColor, width, height );
1536 }
1537 else height /= 2;
1538
1539 DeleteDC( hdc );
1540
1541 iinfo.hbmColor = color ;
1542 iinfo.hbmMask = mask ;
1543 iinfo.fIcon = iconinfo->fIcon;
1544 if (iinfo.fIcon)
1545 {
1546 iinfo.xHotspot = width / 2;
1547 iinfo.yHotspot = height / 2;
1548 }
1549 else
1550 {
1551 iinfo.xHotspot = iconinfo->xHotspot;
1552 iinfo.yHotspot = iconinfo->yHotspot;
1553 }
1554
1555 return CreateCursorIconHandle(&iinfo);
1556 }
1557
1558 /******************************************************************************
1559 * DrawIconEx (USER32.@) Draws an icon or cursor on device context
1560 *
1561 * NOTES
1562 * Why is this using SM_CXICON instead of SM_CXCURSOR?
1563 *
1564 * PARAMS
1565 * hdc [I] Handle to device context
1566 * x0 [I] X coordinate of upper left corner
1567 * y0 [I] Y coordinate of upper left corner
1568 * hIcon [I] Handle to icon to draw
1569 * cxWidth [I] Width of icon
1570 * cyWidth [I] Height of icon
1571 * istep [I] Index of frame in animated cursor
1572 * hbr [I] Handle to background brush
1573 * flags [I] Icon-drawing flags
1574 *
1575 * RETURNS
1576 * Success: TRUE
1577 * Failure: FALSE
1578 */
1579 BOOL WINAPI DrawIconEx( HDC hdc, INT xLeft, INT yTop, HICON hIcon,
1580 INT cxWidth, INT cyWidth, UINT istepIfAniCur,
1581 HBRUSH hbrFlickerFreeDraw, UINT diFlags )
1582 {
1583 return NtUserDrawIconEx(hdc, xLeft, yTop, hIcon, cxWidth, cyWidth,
1584 istepIfAniCur, hbrFlickerFreeDraw, diFlags,
1585 0, 0);
1586 }
1587
1588 /***********************************************************************
1589 * DIB_FixColorsToLoadflags
1590 *
1591 * Change color table entries when LR_LOADTRANSPARENT or LR_LOADMAP3DCOLORS
1592 * are in loadflags
1593 */
1594 static void DIB_FixColorsToLoadflags(BITMAPINFO * bmi, UINT loadflags, BYTE pix)
1595 {
1596 int colors;
1597 COLORREF c_W, c_S, c_F, c_L, c_C;
1598 int incr,i;
1599 RGBQUAD *ptr;
1600 int bitmap_type;
1601 LONG width;
1602 LONG height;
1603 WORD bpp;
1604 DWORD compr;
1605
1606 if (((bitmap_type = DIB_GetBitmapInfo((BITMAPINFOHEADER*) bmi, &width, &height, &bpp, &compr)) == -1))
1607 {
1608 WARN_(resource)("Invalid bitmap\n");
1609 return;
1610 }
1611
1612 if (bpp > 8) return;
1613
1614 if (bitmap_type == 0) /* BITMAPCOREHEADER */
1615 {
1616 incr = 3;
1617 colors = 1 << bpp;
1618 }
1619 else
1620 {
1621 incr = 4;
1622 colors = bmi->bmiHeader.biClrUsed;
1623 if (colors > 256) colors = 256;
1624 if (!colors && (bpp <= 8)) colors = 1 << bpp;
1625 }
1626
1627 c_W = GetSysColor(COLOR_WINDOW);
1628 c_S = GetSysColor(COLOR_3DSHADOW);
1629 c_F = GetSysColor(COLOR_3DFACE);
1630 c_L = GetSysColor(COLOR_3DLIGHT);
1631
1632 if (loadflags & LR_LOADTRANSPARENT) {
1633 switch (bpp) {
1634 case 1: pix = pix >> 7; break;
1635 case 4: pix = pix >> 4; break;
1636 case 8: break;
1637 default:
1638 WARN_(resource)("(%d): Unsupported depth\n", bpp);
1639 return;
1640 }
1641 if (pix >= colors) {
1642 WARN_(resource)("pixel has color index greater than biClrUsed!\n");
1643 return;
1644 }
1645 if (loadflags & LR_LOADMAP3DCOLORS) c_W = c_F;
1646 ptr = (RGBQUAD*)((char*)bmi->bmiColors+pix*incr);
1647 ptr->rgbBlue = GetBValue(c_W);
1648 ptr->rgbGreen = GetGValue(c_W);
1649 ptr->rgbRed = GetRValue(c_W);
1650 }
1651 if (loadflags & LR_LOADMAP3DCOLORS)
1652 for (i=0; i<colors; i++) {
1653 ptr = (RGBQUAD*)((char*)bmi->bmiColors+i*incr);
1654 c_C = RGB(ptr->rgbRed, ptr->rgbGreen, ptr->rgbBlue);
1655 if (c_C == RGB(128, 128, 128)) {
1656 ptr->rgbRed = GetRValue(c_S);
1657 ptr->rgbGreen = GetGValue(c_S);
1658 ptr->rgbBlue = GetBValue(c_S);
1659 } else if (c_C == RGB(192, 192, 192)) {
1660 ptr->rgbRed = GetRValue(c_F);
1661 ptr->rgbGreen = GetGValue(c_F);
1662 ptr->rgbBlue = GetBValue(c_F);
1663 } else if (c_C == RGB(223, 223, 223)) {
1664 ptr->rgbRed = GetRValue(c_L);
1665 ptr->rgbGreen = GetGValue(c_L);
1666 ptr->rgbBlue = GetBValue(c_L);
1667 }
1668 }
1669 }
1670
1671
1672 /**********************************************************************
1673 * BITMAP_Load
1674 */
1675 static HBITMAP BITMAP_Load( HINSTANCE instance, LPCWSTR name,
1676 INT desiredx, INT desiredy, UINT loadflags )
1677 {
1678 HBITMAP hbitmap = 0, orig_bm;
1679 HRSRC hRsrc;
1680 HGLOBAL handle;
1681 char *ptr = NULL;
1682 BITMAPINFO *info, *fix_info = NULL, *scaled_info = NULL;
1683 int size;
1684 BYTE pix;
1685 char *bits;
1686 LONG width, height, new_width, new_height;
1687 WORD bpp_dummy;
1688 DWORD compr_dummy, offbits = 0;
1689 INT bm_type;
1690 HDC screen_mem_dc = NULL;
1691
1692 if (!(loadflags & LR_LOADFROMFILE))
1693 {
1694 if (!instance)
1695 {
1696 /* OEM bitmap: try to load the resource from user32.dll */
1697 instance = User32Instance;
1698 }
1699
1700 if (!(hRsrc = FindResourceW( instance, name, (LPWSTR)RT_BITMAP ))) return 0;
1701 if (!(handle = LoadResource( instance, hRsrc ))) return 0;
1702
1703 if ((info = LockResource( handle )) == NULL) return 0;
1704 }
1705 else
1706 {
1707 BITMAPFILEHEADER * bmfh;
1708
1709 if (!(ptr = map_fileW( name, NULL ))) return 0;
1710 info = (BITMAPINFO *)(ptr + sizeof(BITMAPFILEHEADER));
1711 bmfh = (BITMAPFILEHEADER *)ptr;
1712 if (bmfh->bfType != 0x4d42 /* 'BM' */)
1713 {
1714 WARN("Invalid/unsupported bitmap format!\n");
1715 goto end_close;
1716 }
1717 if (bmfh->bfOffBits) offbits = bmfh->bfOffBits - sizeof(BITMAPFILEHEADER);
1718 }
1719
1720 size = bitmap_info_size(info, DIB_RGB_COLORS);
1721 fix_info = HeapAlloc(GetProcessHeap(), 0, size);
1722 scaled_info = HeapAlloc(GetProcessHeap(), 0, size);
1723
1724 if (!fix_info || !scaled_info) goto end;
1725 memcpy(fix_info, info, size);
1726
1727 pix = *((LPBYTE)info + size);
1728 DIB_FixColorsToLoadflags(fix_info, loadflags, pix);
1729
1730 memcpy(scaled_info, fix_info, size);
1731 bm_type = DIB_GetBitmapInfo( &fix_info->bmiHeader, &width, &height,
1732 &bpp_dummy, &compr_dummy);
1733 if(desiredx != 0)
1734 new_width = desiredx;
1735 else
1736 new_width = width;
1737
1738 if(desiredy != 0)
1739 new_height = height > 0 ? desiredy : -desiredy;
1740 else
1741 new_height = height;
1742
1743 if(bm_type == 0)
1744 {
1745 BITMAPCOREHEADER *core = (BITMAPCOREHEADER *)&scaled_info->bmiHeader;
1746 core->bcWidth = new_width;
1747 core->bcHeight = new_height;
1748 }
1749 else
1750 {
1751 /* Some sanity checks for BITMAPINFO (not applicable to BITMAPCOREINFO) */
1752 if (info->bmiHeader.biHeight > 65535 || info->bmiHeader.biWidth > 65535) {
1753 WARN("Broken BitmapInfoHeader!\n");
1754 goto end;
1755 }
1756
1757 scaled_info->bmiHeader.biWidth = new_width;
1758 scaled_info->bmiHeader.biHeight = new_height;
1759 }
1760
1761 if (new_height < 0) new_height = -new_height;
1762
1763 if (!screen_dc) screen_dc = CreateDCW( DISPLAYW, NULL, NULL, NULL );
1764 if (!(screen_mem_dc = CreateCompatibleDC( screen_dc ))) goto end;
1765
1766 bits = (char *)info + (offbits ? offbits : size);
1767
1768 if (loadflags & LR_CREATEDIBSECTION)
1769 {
1770 scaled_info->bmiHeader.biCompression = 0; /* DIBSection can't be compressed */
1771 hbitmap = CreateDIBSection(screen_dc, scaled_info, DIB_RGB_COLORS, NULL, 0, 0);
1772 }
1773 else
1774 {
1775 if (is_dib_monochrome(fix_info))
1776 hbitmap = CreateBitmap(new_width, new_height, 1, 1, NULL);
1777 else
1778 hbitmap = CreateCompatibleBitmap(screen_dc, new_width, new_height);
1779 }
1780
1781 orig_bm = SelectObject(screen_mem_dc, hbitmap);
1782 StretchDIBits(screen_mem_dc, 0, 0, new_width, new_height, 0, 0, width, height, bits, fix_info, DIB_RGB_COLORS, SRCCOPY);
1783 SelectObject(screen_mem_dc, orig_bm);
1784
1785 end:
1786 if (screen_mem_dc) DeleteDC(screen_mem_dc);
1787 HeapFree(GetProcessHeap(), 0, scaled_info);
1788 HeapFree(GetProcessHeap(), 0, fix_info);
1789 end_close:
1790 if (loadflags & LR_LOADFROMFILE) UnmapViewOfFile( ptr );
1791
1792 return hbitmap;
1793 }
1794
1795 /**********************************************************************
1796 * LoadImageA (USER32.@)
1797 *
1798 * See LoadImageW.
1799 */
1800 HANDLE WINAPI LoadImageA( HINSTANCE hinst, LPCSTR name, UINT type,
1801 INT desiredx, INT desiredy, UINT loadflags)
1802 {
1803 HANDLE res;
1804 LPWSTR u_name;
1805
1806 if (IS_INTRESOURCE(name))
1807 return LoadImageW(hinst, (LPCWSTR)name, type, desiredx, desiredy, loadflags);
1808
1809 __TRY {
1810 DWORD len = MultiByteToWideChar( CP_ACP, 0, name, -1, NULL, 0 );
1811 u_name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
1812 MultiByteToWideChar( CP_ACP, 0, name, -1, u_name, len );
1813 }
1814 __EXCEPT_PAGE_FAULT {
1815 SetLastError( ERROR_INVALID_PARAMETER );
1816 return 0;
1817 }
1818 __ENDTRY
1819 res = LoadImageW(hinst, u_name, type, desiredx, desiredy, loadflags);
1820 HeapFree(GetProcessHeap(), 0, u_name);
1821 return res;
1822 }
1823
1824
1825 /******************************************************************************
1826 * LoadImageW (USER32.@) Loads an icon, cursor, or bitmap
1827 *
1828 * PARAMS
1829 * hinst [I] Handle of instance that contains image
1830 * name [I] Name of image
1831 * type [I] Type of image
1832 * desiredx [I] Desired width
1833 * desiredy [I] Desired height
1834 * loadflags [I] Load flags
1835 *
1836 * RETURNS
1837 * Success: Handle to newly loaded image
1838 * Failure: NULL
1839 *
1840 * FIXME: Implementation lacks some features, see LR_ defines in winuser.h
1841 */
1842 HANDLE WINAPI LoadImageW( HINSTANCE hinst, LPCWSTR name, UINT type,
1843 INT desiredx, INT desiredy, UINT loadflags )
1844 {
1845 TRACE_(resource)("(%p,%s,%d,%d,%d,0x%08x)\n",
1846 hinst,debugstr_w(name),type,desiredx,desiredy,loadflags);
1847
1848 if (loadflags & LR_DEFAULTSIZE) {
1849 if (type == IMAGE_ICON) {
1850 if (!desiredx) desiredx = GetSystemMetrics(SM_CXICON);
1851 if (!desiredy) desiredy = GetSystemMetrics(SM_CYICON);
1852 } else if (type == IMAGE_CURSOR) {
1853 if (!desiredx) desiredx = GetSystemMetrics(SM_CXCURSOR);
1854 if (!desiredy) desiredy = GetSystemMetrics(SM_CYCURSOR);
1855 }
1856 }
1857 if (loadflags & LR_LOADFROMFILE) loadflags &= ~LR_SHARED;
1858 switch (type) {
1859 case IMAGE_BITMAP:
1860 return BITMAP_Load( hinst, name, desiredx, desiredy, loadflags );
1861
1862 case IMAGE_ICON:
1863 if (!screen_dc) screen_dc = CreateDCW( DISPLAYW, NULL, NULL, NULL );
1864 if (screen_dc)
1865 {
1866 return CURSORICON_Load(hinst, name, desiredx, desiredy,
1867 GetDeviceCaps(screen_dc, BITSPIXEL),
1868 FALSE, loadflags);
1869 }
1870 break;
1871
1872 case IMAGE_CURSOR:
1873 return CURSORICON_Load(hinst, name, desiredx, desiredy,
1874 1, TRUE, loadflags);
1875 }
1876 return 0;
1877 }
1878
1879 /******************************************************************************
1880 * CopyImage (USER32.@) Creates new image and copies attributes to it
1881 *
1882 * PARAMS
1883 * hnd [I] Handle to image to copy
1884 * type [I] Type of image to copy
1885 * desiredx [I] Desired width of new image
1886 * desiredy [I] Desired height of new image
1887 * flags [I] Copy flags
1888 *
1889 * RETURNS
1890 * Success: Handle to newly created image
1891 * Failure: NULL
1892 *
1893 * BUGS
1894 * Only Windows NT 4.0 supports the LR_COPYRETURNORG flag for bitmaps,
1895 * all other versions (95/2000/XP have been tested) ignore it.
1896 *
1897 * NOTES
1898 * If LR_CREATEDIBSECTION is absent, the copy will be monochrome for
1899 * a monochrome source bitmap or if LR_MONOCHROME is present, otherwise
1900 * the copy will have the same depth as the screen.
1901 * The content of the image will only be copied if the bit depth of the
1902 * original image is compatible with the bit depth of the screen, or
1903 * if the source is a DIB section.
1904 * The LR_MONOCHROME flag is ignored if LR_CREATEDIBSECTION is present.
1905 */
1906 HANDLE WINAPI CopyImage( HANDLE hnd, UINT type, INT desiredx,
1907 INT desiredy, UINT flags )
1908 {
1909 TRACE("hnd=%p, type=%u, desiredx=%d, desiredy=%d, flags=%x\n",
1910 hnd, type, desiredx, desiredy, flags);
1911
1912 switch (type)
1913 {
1914 case IMAGE_BITMAP:
1915 {
1916 HBITMAP res = NULL;
1917 DIBSECTION ds;
1918 int objSize;
1919 BITMAPINFO * bi;
1920
1921 objSize = GetObjectW( hnd, sizeof(ds), &ds );
1922 if (!objSize) return 0;
1923 if ((desiredx < 0) || (desiredy < 0)) return 0;
1924
1925 if (flags & LR_COPYFROMRESOURCE)
1926 {
1927 FIXME("The flag LR_COPYFROMRESOURCE is not implemented for bitmaps\n");
1928 }
1929
1930 if (desiredx == 0) desiredx = ds.dsBm.bmWidth;
1931 if (desiredy == 0) desiredy = ds.dsBm.bmHeight;
1932
1933 /* Allocate memory for a BITMAPINFOHEADER structure and a
1934 color table. The maximum number of colors in a color table
1935 is 256 which corresponds to a bitmap with depth 8.
1936 Bitmaps with higher depths don't have color tables. */
1937 bi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1938 if (!bi) return 0;
1939
1940 bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
1941 bi->bmiHeader.biPlanes = ds.dsBm.bmPlanes;
1942 bi->bmiHeader.biBitCount = ds.dsBm.bmBitsPixel;
1943 bi->bmiHeader.biCompression = BI_RGB;
1944
1945 if (flags & LR_CREATEDIBSECTION)
1946 {
1947 /* Create a DIB section. LR_MONOCHROME is ignored */
1948 void * bits;
1949 HDC dc = CreateCompatibleDC(NULL);
1950
1951 if (objSize == sizeof(DIBSECTION))
1952 {
1953 /* The source bitmap is a DIB.
1954 Get its attributes to create an exact copy */
1955 memcpy(bi, &ds.dsBmih, sizeof(BITMAPINFOHEADER));
1956 }
1957
1958 /* Get the color table or the color masks */
1959 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
1960
1961 bi->bmiHeader.biWidth = desiredx;
1962 bi->bmiHeader.biHeight = desiredy;
1963 bi->bmiHeader.biSizeImage = 0;
1964
1965 res = CreateDIBSection(dc, bi, DIB_RGB_COLORS, &bits, NULL, 0);
1966 DeleteDC(dc);
1967 }
1968 else
1969 {
1970 /* Create a device-dependent bitmap */
1971
1972 BOOL monochrome = (flags & LR_MONOCHROME);
1973
1974 if (objSize == sizeof(DIBSECTION))
1975 {
1976 /* The source bitmap is a DIB section.
1977 Get its attributes */
1978 HDC dc = CreateCompatibleDC(NULL);
1979 bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
1980 bi->bmiHeader.biBitCount = ds.dsBm.bmBitsPixel;
1981 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
1982 DeleteDC(dc);
1983
1984 if (!monochrome && ds.dsBm.bmBitsPixel == 1)
1985 {
1986 /* Look if the colors of the DIB are black and white */
1987
1988 monochrome =
1989 (bi->bmiColors[0].rgbRed == 0xff
1990 && bi->bmiColors[0].rgbGreen == 0xff
1991 && bi->bmiColors[0].rgbBlue == 0xff
1992 && bi->bmiColors[0].rgbReserved == 0
1993 && bi->bmiColors[1].rgbRed == 0
1994 && bi->bmiColors[1].rgbGreen == 0
1995 && bi->bmiColors[1].rgbBlue == 0
1996 && bi->bmiColors[1].rgbReserved == 0)
1997 ||
1998 (bi->bmiColors[0].rgbRed == 0
1999 && bi->bmiColors[0].rgbGreen == 0
2000 && bi->bmiColors[0].rgbBlue == 0
2001 && bi->bmiColors[0].rgbReserved == 0
2002 && bi->bmiColors[1].rgbRed == 0xff
2003 && bi->bmiColors[1].rgbGreen == 0xff
2004 && bi->bmiColors[1].rgbBlue == 0xff
2005 && bi->bmiColors[1].rgbReserved == 0);
2006 }
2007 }
2008 else if (!monochrome)
2009 {
2010 monochrome = ds.dsBm.bmBitsPixel == 1;
2011 }
2012
2013 if (monochrome)
2014 {
2015 res = CreateBitmap(desiredx, desiredy, 1, 1, NULL);
2016 }
2017 else
2018 {
2019 HDC screenDC = GetDC(NULL);
2020 res = CreateCompatibleBitmap(screenDC, desiredx, desiredy);
2021 ReleaseDC(NULL, screenDC);
2022 }
2023 }
2024
2025 if (res)
2026 {
2027 /* Only copy the bitmap if it's a DIB section or if it's
2028 compatible to the screen */
2029 BOOL copyContents;
2030
2031 if (objSize == sizeof(DIBSECTION))
2032 {
2033 copyContents = TRUE;
2034 }
2035 else
2036 {
2037 HDC screenDC = GetDC(NULL);
2038 int screen_depth = GetDeviceCaps(screenDC, BITSPIXEL);
2039 ReleaseDC(NULL, screenDC);
2040
2041 copyContents = (ds.dsBm.bmBitsPixel == 1 || ds.dsBm.bmBitsPixel == screen_depth);
2042 }
2043
2044 if (copyContents)
2045 {
2046 /* The source bitmap may already be selected in a device context,
2047 use GetDIBits/StretchDIBits and not StretchBlt */
2048
2049 HDC dc;
2050 void * bits;
2051
2052 dc = CreateCompatibleDC(NULL);
2053
2054 bi->bmiHeader.biWidth = ds.dsBm.bmWidth;
2055 bi->bmiHeader.biHeight = ds.dsBm.bmHeight;
2056 bi->bmiHeader.biSizeImage = 0;
2057 bi->bmiHeader.biClrUsed = 0;
2058 bi->bmiHeader.biClrImportant = 0;
2059
2060 /* Fill in biSizeImage */
2061 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
2062 bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bi->bmiHeader.biSizeImage);
2063
2064 if (bits)
2065 {
2066 HBITMAP oldBmp;
2067
2068 /* Get the image bits of the source bitmap */
2069 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, bits, bi, DIB_RGB_COLORS);
2070
2071 /* Copy it to the destination bitmap */
2072 oldBmp = SelectObject(dc, res);
2073 StretchDIBits(dc, 0, 0, desiredx, desiredy,
2074 0, 0, ds.dsBm.bmWidth, ds.dsBm.bmHeight,
2075 bits, bi, DIB_RGB_COLORS, SRCCOPY);
2076 SelectObject(dc, oldBmp);
2077
2078 HeapFree(GetProcessHeap(), 0, bits);
2079 }
2080
2081 DeleteDC(dc);
2082 }
2083
2084 if (flags & LR_COPYDELETEORG)
2085 {
2086 DeleteObject(hnd);
2087 }
2088 }
2089 HeapFree(GetProcessHeap(), 0, bi);
2090 return res;
2091 }
2092 case IMAGE_ICON:
2093 return CURSORICON_ExtCopy(hnd,type, desiredx, desiredy, flags);
2094 case IMAGE_CURSOR:
2095 /* Should call CURSORICON_ExtCopy but more testing
2096 * needs to be done before we change this
2097 */
2098 if (flags) FIXME("Flags are ignored\n");
2099 return CopyCursor(hnd);
2100 }
2101 return 0;
2102 }
2103
2104
2105 /******************************************************************************
2106 * LoadBitmapW (USER32.@) Loads bitmap from the executable file
2107 *
2108 * RETURNS
2109 * Success: Handle to specified bitmap
2110 * Failure: NULL
2111 */
2112 HBITMAP WINAPI LoadBitmapW(
2113 HINSTANCE instance, /* [in] Handle to application instance */
2114 LPCWSTR name) /* [in] Address of bitmap resource name */
2115 {
2116 return LoadImageW( instance, name, IMAGE_BITMAP, 0, 0, 0 );
2117 }
2118
2119 /**********************************************************************
2120 * LoadBitmapA (USER32.@)
2121 *
2122 * See LoadBitmapW.
2123 */
2124 HBITMAP WINAPI LoadBitmapA( HINSTANCE instance, LPCSTR name )
2125 {
2126 return LoadImageA( instance, name, IMAGE_BITMAP, 0, 0, 0 );
2127 }
2128
2129 HCURSOR
2130 CursorIconToCursor(HICON hIcon,
2131 BOOL SemiTransparent)
2132 {
2133 UNIMPLEMENTED;
2134 return 0;
2135 }
2136
2137 /*
2138 * @implemented
2139 */
2140 BOOL
2141 WINAPI
2142 SetCursorPos(int X,
2143 int Y)
2144 {
2145 return NtUserSetCursorPos(X,Y);
2146 }
2147
2148 /*
2149 * @implemented
2150 */
2151 BOOL
2152 WINAPI
2153 GetCursorPos(LPPOINT lpPoint)
2154 {
2155 BOOL res;
2156 /* Windows doesn't check if lpPoint == NULL, we do */
2157 if(!lpPoint)
2158 {
2159 SetLastError(ERROR_INVALID_PARAMETER);
2160 return FALSE;
2161 }
2162
2163 res = NtUserGetCursorPos(lpPoint);
2164
2165 return res;
2166 }
2167
2168 /* INTERNAL ******************************************************************/
2169
2170 /* This callback routine is called directly after switching to gui mode */
2171 NTSTATUS
2172 WINAPI
2173 User32SetupDefaultCursors(PVOID Arguments,
2174 ULONG ArgumentLength)
2175 {
2176 BOOL *DefaultCursor = (BOOL*)Arguments;
2177 LRESULT Result = TRUE;
2178
2179 if(*DefaultCursor)
2180 {
2181 /* set default cursor */
2182 SetCursor(LoadCursorW(0, (LPCWSTR)IDC_ARROW));
2183 }
2184 else
2185 {
2186 /* FIXME load system cursor scheme */
2187 SetCursor(0);
2188 SetCursor(LoadCursorW(0, (LPCWSTR)IDC_ARROW));
2189 }
2190
2191 return(ZwCallbackReturn(&Result, sizeof(LRESULT), STATUS_SUCCESS));
2192 }
2193
2194 BOOL get_icon_size(HICON hIcon, SIZE *size)
2195 {
2196 ICONINFO info;
2197 BITMAP bitmap;
2198
2199 if (!GetIconInfo(hIcon, &info)) return FALSE;
2200 if (!GetObject(info.hbmMask, sizeof(bitmap), &bitmap)) return FALSE;
2201
2202 size->cx = bitmap.bmWidth;
2203 size->cy = bitmap.bmHeight;
2204
2205 /* Black and white icons store both the XOR and AND bitmap in hbmMask */
2206 if (!info.hbmColor)
2207 {
2208 size->cy /= 2;
2209 }
2210
2211 return TRUE;
2212 }