Sync with trunk r43000
[reactos.git] / reactos / dll / win32 / user32 / windows / bitmap.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id$
20 *
21 * PROJECT: ReactOS user32.dll
22 * FILE: lib/user32/windows/input.c
23 * PURPOSE: Input
24 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
25 * UPDATE HISTORY:
26 * 09-05-2001 CSH Created
27 */
28
29 /* INCLUDES ******************************************************************/
30
31 #include <user32.h>
32
33 #include <wine/debug.h>
34 WINE_DEFAULT_DEBUG_CHANNEL(user32);
35
36 #include "pshpack1.h"
37
38 typedef struct {
39 BYTE bWidth;
40 BYTE bHeight;
41 BYTE bColorCount;
42 BYTE bReserved;
43 WORD xHotspot;
44 WORD yHotspot;
45 DWORD dwDIBSize;
46 DWORD dwDIBOffset;
47 } CURSORICONFILEDIRENTRY;
48
49 typedef struct
50 {
51 WORD idReserved;
52 WORD idType;
53 WORD idCount;
54 CURSORICONFILEDIRENTRY idEntries[1];
55 } CURSORICONFILEDIR;
56
57 #include "poppack.h"
58
59 /* forward declarations... actually in user32\windows\icon.c but useful here */
60 HICON ICON_CreateIconFromData(HDC hDC, PVOID ImageData, ICONIMAGE* IconImage, int cxDesired, int cyDesired, int xHotspot, int yHotspot);
61 CURSORICONDIRENTRY *CURSORICON_FindBestIcon( CURSORICONDIR *dir, int width, int height, int colors);
62 CURSORICONDIRENTRY *CURSORICON_FindBestCursor( CURSORICONDIR *dir, int width, int height, int colors);
63
64 /* FUNCTIONS *****************************************************************/
65
66 /*
67 * @implemented
68 */
69 HANDLE WINAPI
70 LoadImageA(HINSTANCE hinst,
71 LPCSTR lpszName,
72 UINT uType,
73 int cxDesired,
74 int cyDesired,
75 UINT fuLoad)
76 {
77 LPWSTR lpszWName;
78 HANDLE Handle;
79 UNICODE_STRING NameString;
80
81 if (HIWORD(lpszName))
82 {
83 RtlCreateUnicodeStringFromAsciiz(&NameString, (LPSTR)lpszName);
84 lpszWName = NameString.Buffer;
85 Handle = LoadImageW(hinst, lpszWName, uType, cxDesired,
86 cyDesired, fuLoad);
87 RtlFreeUnicodeString(&NameString);
88 }
89 else
90 {
91 Handle = LoadImageW(hinst, (LPCWSTR)lpszName, uType, cxDesired,
92 cyDesired, fuLoad);
93 }
94
95 return Handle;
96 }
97
98
99 /*
100 * The following macro functions account for the irregularities of
101 * accessing cursor and icon resources in files and resource entries.
102 */
103 typedef BOOL (*fnGetCIEntry)( LPVOID dir, int n,
104 int *width, int *height, int *bits );
105
106 /**********************************************************************
107 * CURSORICON_FindBestCursor2
108 *
109 * Find the cursor closest to the requested size.
110 * FIXME: parameter 'color' ignored and entries with more than 1 bpp
111 * ignored too
112 */
113 static int CURSORICON_FindBestCursor2( LPVOID dir, fnGetCIEntry get_entry,
114 int width, int height, int color )
115 {
116 int i, maxwidth, maxheight, cx, cy, bits, bestEntry = -1;
117
118 /* Double height to account for AND and XOR masks */
119
120 height *= 2;
121
122 /* First find the largest one smaller than or equal to the requested size*/
123
124 maxwidth = maxheight = 0;
125 for ( i = 0; get_entry( dir, i, &cx, &cy, &bits ); i++ )
126 {
127 if ((cx <= width) && (cy <= height) &&
128 (cx > maxwidth) && (cy > maxheight) &&
129 (bits == 1))
130 {
131 bestEntry = i;
132 maxwidth = cx;
133 maxheight = cy;
134 }
135 }
136 if (bestEntry != -1) return bestEntry;
137
138 /* Now find the smallest one larger than the requested size */
139
140 maxwidth = maxheight = 255;
141 for ( i = 0; get_entry( dir, i, &cx, &cy, &bits ); i++ )
142 {
143 if (((cx < maxwidth) && (cy < maxheight) && (bits == 1)) ||
144 (bestEntry==-1))
145 {
146 bestEntry = i;
147 maxwidth = cx;
148 maxheight = cy;
149 }
150 }
151
152 return bestEntry;
153 }
154
155 static BOOL CURSORICON_GetFileEntry( LPVOID dir, int n,
156 int *width, int *height, int *bits )
157 {
158 CURSORICONFILEDIR *filedir = dir;
159 CURSORICONFILEDIRENTRY *entry;
160
161 if ( filedir->idCount <= n )
162 return FALSE;
163 entry = &filedir->idEntries[n];
164 *width = entry->bWidth;
165 *height = entry->bHeight;
166 *bits = entry->bColorCount;
167 return TRUE;
168 }
169
170 static CURSORICONFILEDIRENTRY *CURSORICON_FindBestCursorFile( CURSORICONFILEDIR *dir,
171 int width, int height, int color )
172 {
173 int n = CURSORICON_FindBestCursor2( dir, CURSORICON_GetFileEntry,
174 width, height, color );
175 if ( n < 0 )
176 return NULL;
177 return &dir->idEntries[n];
178 }
179
180 static HANDLE
181 LoadCursorIconImage(
182 HINSTANCE hinst,
183 LPCWSTR lpszName,
184 INT width,
185 INT height,
186 UINT fuLoad,
187 ULONG uType)
188 {
189 HRSRC hResInfo;
190 HANDLE hResource;
191 HANDLE hFile;
192 HANDLE hSection;
193 CURSORICONFILEDIR *IconDIR;
194 HDC hScreenDc;
195 HICON hIcon;
196 ULONG HeaderSize;
197 ULONG ColorCount;
198 ULONG ColorBits;
199 PVOID Data;
200 CURSORICONFILEDIRENTRY* dirEntry;
201 ICONIMAGE* SafeIconImage = NULL;
202 GRPCURSORICONDIR* IconResDir;
203 INT id;
204 ICONIMAGE *ResIcon;
205 BOOL Icon = (uType == IMAGE_ICON);
206 DWORD filesize = 0;
207
208 if (!(fuLoad & LR_LOADFROMFILE))
209 {
210 if (hinst == NULL)
211 hinst = User32Instance;
212
213 hResInfo = FindResourceW(hinst, lpszName,
214 Icon ? RT_GROUP_ICON : RT_GROUP_CURSOR);
215 if (hResInfo == NULL)
216 return NULL;
217
218 hResource = LoadResource(hinst, hResInfo);
219 if (hResource == NULL)
220 return NULL;
221
222 IconResDir = LockResource(hResource);
223 if (IconResDir == NULL)
224 {
225 return NULL;
226 }
227
228 /* Find the best fitting in the IconResDir for this resolution */
229 id = LookupIconIdFromDirectoryEx((PBYTE)IconResDir, Icon, width, height,
230 fuLoad & (LR_DEFAULTCOLOR | LR_MONOCHROME));
231
232 hResInfo = FindResourceW(hinst, MAKEINTRESOURCEW(id),
233 Icon ? (LPCWSTR) RT_ICON :
234 (LPCWSTR) RT_CURSOR);
235 if (hResInfo == NULL)
236 {
237 return NULL;
238 }
239
240 /* Now we have found the icon we want to load.
241 * Let's see if we already loaded it */
242 if (fuLoad & LR_SHARED)
243 {
244 hIcon = NtUserFindExistingCursorIcon(hinst, hResInfo, 0, 0);
245 if (hIcon)
246 {
247 return hIcon;
248 }
249 else
250 TRACE("Didn't find the shared icon!!\n");
251 }
252
253 hResource = LoadResource(hinst, hResInfo);
254 if (hResource == NULL)
255 {
256 return NULL;
257 }
258
259 ResIcon = LockResource(hResource);
260 if (ResIcon == NULL)
261 {
262 return NULL;
263 }
264
265 hIcon = CreateIconFromResourceEx((PBYTE)ResIcon,
266 SizeofResource(hinst, hResInfo),
267 Icon, 0x00030000, width, height,
268 (fuLoad & (LR_DEFAULTSIZE | LR_SHARED)) | LR_DEFAULTCOLOR);
269
270 if (hIcon && 0 != (fuLoad & LR_SHARED))
271 {
272 #if 1
273 NtUserSetCursorIconData((HICON)hIcon, NULL, NULL, hinst, hResInfo,
274 (HRSRC)NULL);
275 #else
276 ICONINFO iconInfo;
277
278 if(NtUserGetIconInfo(ResIcon, &iconInfo, NULL, NULL, NULL, FALSE))
279 NtUserSetCursorIconData((HICON)hIcon, hinst, NULL, &iconInfo);
280 #endif
281 }
282
283 return hIcon;
284 }
285
286 if (fuLoad & LR_SHARED)
287 {
288 FIXME("Need LR_SHARED support for loading icon images from files\n");
289 }
290
291 hFile = CreateFileW(lpszName, GENERIC_READ, FILE_SHARE_READ, NULL,
292 OPEN_EXISTING, 0, NULL);
293 if (hFile == INVALID_HANDLE_VALUE)
294 return NULL;
295
296 hSection = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
297 filesize = GetFileSize( hFile, NULL );
298 CloseHandle(hFile);
299 if (hSection == NULL)
300 return NULL;
301
302 IconDIR = MapViewOfFile(hSection, FILE_MAP_READ, 0, 0, 0);
303 CloseHandle(hSection);
304 if (IconDIR == NULL)
305 return NULL;
306
307 if (0 != IconDIR->idReserved ||
308 (IMAGE_ICON != IconDIR->idType && IMAGE_CURSOR != IconDIR->idType))
309 {
310 UnmapViewOfFile(IconDIR);
311 return NULL;
312 }
313
314 /* Get a handle to the screen dc, the icon we create is going to be
315 * compatable with this. */
316 hScreenDc = CreateDCW(NULL, NULL, NULL, NULL);
317 if (hScreenDc == NULL)
318 {
319 UnmapViewOfFile(IconDIR);
320 RtlFreeHeap(GetProcessHeap(), 0, SafeIconImage);
321 return NULL;
322 }
323
324 if (fuLoad & LR_MONOCHROME)
325 {
326 ColorBits = 1;
327 }
328 else
329 {
330 ColorBits = GetDeviceCaps(hScreenDc, BITSPIXEL);
331 /*
332 * FIXME:
333 * Remove this after proper support for alpha icons will be finished.
334 */
335 if (ColorBits > 8)
336 ColorBits = 8;
337 }
338
339 /* Pick the best size. */
340 dirEntry = CURSORICON_FindBestCursorFile( IconDIR, width, height, ColorBits );
341 if (!dirEntry)
342 {
343 DeleteDC(hScreenDc);
344 UnmapViewOfFile(IconDIR);
345 return NULL;
346 }
347
348 if ( dirEntry->dwDIBOffset > filesize )
349 {
350 DeleteDC(hScreenDc);
351 UnmapViewOfFile(IconDIR);
352 return NULL;
353 }
354
355 if ( dirEntry->dwDIBOffset + dirEntry->dwDIBSize > filesize ){
356 DeleteDC(hScreenDc);
357 UnmapViewOfFile(IconDIR);
358 return NULL;
359 }
360
361 SafeIconImage = RtlAllocateHeap(GetProcessHeap(), 0, dirEntry->dwDIBSize);
362 if (SafeIconImage == NULL)
363 {
364 DeleteDC(hScreenDc);
365 UnmapViewOfFile(IconDIR);
366 return NULL;
367 }
368
369 memcpy(SafeIconImage, ((PBYTE)IconDIR) + dirEntry->dwDIBOffset, dirEntry->dwDIBSize);
370 UnmapViewOfFile(IconDIR);
371
372 /* At this point we have a copy of the icon image to play with. */
373
374 SafeIconImage->icHeader.biHeight = SafeIconImage->icHeader.biHeight /2;
375
376 if (SafeIconImage->icHeader.biSize == sizeof(BITMAPCOREHEADER))
377 {
378 BITMAPCOREHEADER* Core = (BITMAPCOREHEADER*)SafeIconImage;
379 ColorCount = (Core->bcBitCount <= 8) ? (1 << Core->bcBitCount) : 0;
380 HeaderSize = sizeof(BITMAPCOREHEADER) + ColorCount * sizeof(RGBTRIPLE);
381 }
382 else
383 {
384 ColorCount = SafeIconImage->icHeader.biClrUsed;
385 if (ColorCount == 0 && SafeIconImage->icHeader.biBitCount <= 8)
386 ColorCount = 1 << SafeIconImage->icHeader.biBitCount;
387 HeaderSize = sizeof(BITMAPINFOHEADER) + ColorCount * sizeof(RGBQUAD);
388 }
389
390 /* Make data point to the start of the XOR image data. */
391 Data = (PBYTE)SafeIconImage + HeaderSize;
392
393 hIcon = ICON_CreateIconFromData(hScreenDc, Data, SafeIconImage, width, height, width/2, height/2);
394 RtlFreeHeap(GetProcessHeap(), 0, SafeIconImage);
395 DeleteDC(hScreenDc);
396
397 return hIcon;
398 }
399
400
401 static HANDLE
402 LoadBitmapImage(HINSTANCE hInstance, LPCWSTR lpszName, UINT fuLoad)
403 {
404 HANDLE hResource;
405 HANDLE hFile;
406 HANDLE hSection;
407 LPBITMAPINFO BitmapInfo;
408 LPBITMAPINFO PrivateInfo;
409 HDC hScreenDc;
410 HANDLE hBitmap;
411 ULONG HeaderSize;
412 ULONG ColorCount;
413 PVOID Data;
414 BOOL Hit = FALSE;
415
416 if (!(fuLoad & LR_LOADFROMFILE))
417 {
418 if (hInstance == NULL)
419 hInstance = User32Instance;
420
421 hResource = FindResourceW(hInstance, lpszName, RT_BITMAP);
422 if (hResource == NULL)
423 return NULL;
424 hResource = LoadResource(hInstance, hResource);
425 if (hResource == NULL)
426 return NULL;
427 BitmapInfo = LockResource(hResource);
428 if (BitmapInfo == NULL)
429 return NULL;
430 }
431 else
432 {
433 hFile = CreateFileW(lpszName, GENERIC_READ, FILE_SHARE_READ, NULL,
434 OPEN_EXISTING, 0, NULL);
435 if (hFile == INVALID_HANDLE_VALUE)
436 return NULL;
437
438 hSection = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
439 CloseHandle(hFile);
440 if (hSection == NULL)
441 return NULL;
442
443 BitmapInfo = MapViewOfFile(hSection, FILE_MAP_READ, 0, 0, 0);
444 CloseHandle(hSection);
445 if (BitmapInfo == NULL)
446 return NULL;
447
448 BitmapInfo = (LPBITMAPINFO)((ULONG_PTR)BitmapInfo + sizeof(BITMAPFILEHEADER));
449 }
450
451 HeaderSize = BitmapInfo->bmiHeader.biSize;
452 if (HeaderSize == sizeof(BITMAPCOREHEADER))
453 {
454 BITMAPCOREHEADER* Core = (BITMAPCOREHEADER*)BitmapInfo;
455 ColorCount = (Core->bcBitCount <= 8) ? (1 << Core->bcBitCount) : 0;
456 HeaderSize += ColorCount * sizeof(RGBTRIPLE);
457 }
458 else
459 {
460 if (BitmapInfo->bmiHeader.biCompression == BI_BITFIELDS)
461 {
462 HeaderSize += 3 * sizeof(RGBQUAD);
463 }
464 else
465 {
466 ColorCount = BitmapInfo->bmiHeader.biClrUsed;
467 if (ColorCount == 0 && BitmapInfo->bmiHeader.biBitCount <= 8)
468 ColorCount = 1 << BitmapInfo->bmiHeader.biBitCount;
469 HeaderSize += ColorCount * sizeof(RGBQUAD);
470 }
471 }
472 Data = (PVOID)((ULONG_PTR)BitmapInfo + HeaderSize);
473
474 PrivateInfo = RtlAllocateHeap(GetProcessHeap(), 0, HeaderSize);
475 if (PrivateInfo == NULL)
476 {
477 if (fuLoad & LR_LOADFROMFILE)
478 UnmapViewOfFile(BitmapInfo);
479 return NULL;
480 }
481
482 _SEH2_TRY
483 {
484 memcpy(PrivateInfo, BitmapInfo, HeaderSize);
485 }
486 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
487 {
488 Hit = TRUE;
489 }
490 _SEH2_END;
491
492 if (Hit)
493 {
494 ERR("We have a thread overrun, these are already freed! pi -> %d, bi -> %d\n", PrivateInfo, BitmapInfo);
495 RtlFreeHeap(GetProcessHeap(), 0, PrivateInfo);
496 if (fuLoad & LR_LOADFROMFILE)
497 UnmapViewOfFile(BitmapInfo);
498 return NULL;
499 }
500
501 /* FIXME: Handle color conversion and transparency. */
502
503 hScreenDc = CreateCompatibleDC(NULL);
504 if (hScreenDc == NULL)
505 {
506 RtlFreeHeap(GetProcessHeap(), 0, PrivateInfo);
507 if (fuLoad & LR_LOADFROMFILE)
508 UnmapViewOfFile(BitmapInfo);
509 return NULL;
510 }
511
512 if (fuLoad & LR_CREATEDIBSECTION)
513 {
514 DIBSECTION Dib;
515
516 hBitmap = CreateDIBSection(hScreenDc, PrivateInfo, DIB_RGB_COLORS, NULL,
517 0, 0);
518 GetObjectA(hBitmap, sizeof(DIBSECTION), &Dib);
519 SetDIBits(hScreenDc, hBitmap, 0, Dib.dsBm.bmHeight, Data, BitmapInfo,
520 DIB_RGB_COLORS);
521 }
522 else
523 {
524 hBitmap = CreateDIBitmap(hScreenDc, &PrivateInfo->bmiHeader, CBM_INIT,
525 Data, PrivateInfo, DIB_RGB_COLORS);
526 }
527
528 RtlFreeHeap(GetProcessHeap(), 0, PrivateInfo);
529 DeleteDC(hScreenDc);
530 if (fuLoad & LR_LOADFROMFILE)
531 UnmapViewOfFile(BitmapInfo);
532
533 return hBitmap;
534 }
535
536 HANDLE WINAPI
537 LoadImageW(
538 IN HINSTANCE hinst,
539 IN LPCWSTR lpszName,
540 IN UINT uType,
541 IN INT cxDesired,
542 IN INT cyDesired,
543 IN UINT fuLoad)
544 {
545 if (fuLoad & LR_DEFAULTSIZE)
546 {
547 if (uType == IMAGE_ICON)
548 {
549 if (cxDesired == 0)
550 cxDesired = GetSystemMetrics(SM_CXICON);
551 if (cyDesired == 0)
552 cyDesired = GetSystemMetrics(SM_CYICON);
553 }
554 else if (uType == IMAGE_CURSOR)
555 {
556 if (cxDesired == 0)
557 cxDesired = GetSystemMetrics(SM_CXCURSOR);
558 if (cyDesired == 0)
559 cyDesired = GetSystemMetrics(SM_CYCURSOR);
560 }
561 }
562
563 switch (uType)
564 {
565 case IMAGE_BITMAP:
566 return LoadBitmapImage(hinst, lpszName, fuLoad);
567 case IMAGE_CURSOR:
568 case IMAGE_ICON:
569 return LoadCursorIconImage(hinst, lpszName, cxDesired, cyDesired,
570 fuLoad, uType);
571 default:
572 break;
573 }
574
575 return NULL;
576 }
577
578
579 /*
580 * @implemented
581 */
582 HBITMAP WINAPI
583 LoadBitmapA(HINSTANCE hInstance, LPCSTR lpBitmapName)
584 {
585 return LoadImageA(hInstance, lpBitmapName, IMAGE_BITMAP, 0, 0, 0);
586 }
587
588
589 /*
590 * @implemented
591 */
592 HBITMAP WINAPI
593 LoadBitmapW(HINSTANCE hInstance, LPCWSTR lpBitmapName)
594 {
595 return LoadImageW(hInstance, lpBitmapName, IMAGE_BITMAP, 0, 0, 0);
596 }
597
598
599 static HANDLE
600 CopyBmp(HANDLE hnd,
601 UINT type,
602 INT desiredx,
603 INT desiredy,
604 UINT flags)
605 {
606 HBITMAP res = NULL;
607 DIBSECTION ds;
608 int objSize;
609 BITMAPINFO * bi;
610
611 objSize = GetObjectW( hnd, sizeof(ds), &ds );
612 if (!objSize) return 0;
613 if ((desiredx < 0) || (desiredy < 0)) return 0;
614
615 if (flags & LR_COPYFROMRESOURCE)
616 {
617 FIXME("FIXME: The flag LR_COPYFROMRESOURCE is not implemented for bitmaps\n");
618 }
619
620 if (desiredx == 0) desiredx = ds.dsBm.bmWidth;
621 if (desiredy == 0) desiredy = ds.dsBm.bmHeight;
622
623 /* Allocate memory for a BITMAPINFOHEADER structure and a
624 color table. The maximum number of colors in a color table
625 is 256 which corresponds to a bitmap with depth 8.
626 Bitmaps with higher depths don't have color tables. */
627 bi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
628 if (!bi) return 0;
629
630 bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
631 bi->bmiHeader.biPlanes = ds.dsBm.bmPlanes;
632 bi->bmiHeader.biBitCount = ds.dsBm.bmBitsPixel;
633 bi->bmiHeader.biCompression = BI_RGB;
634
635 if (flags & LR_CREATEDIBSECTION)
636 {
637 /* Create a DIB section. LR_MONOCHROME is ignored */
638 void * bits;
639 HDC dc = CreateCompatibleDC(NULL);
640
641 if (objSize == sizeof(DIBSECTION))
642 {
643 /* The source bitmap is a DIB.
644 Get its attributes to create an exact copy */
645 memcpy(bi, &ds.dsBmih, sizeof(BITMAPINFOHEADER));
646 }
647
648 /* Get the color table or the color masks */
649 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
650
651 bi->bmiHeader.biWidth = desiredx;
652 bi->bmiHeader.biHeight = desiredy;
653 bi->bmiHeader.biSizeImage = 0;
654
655 res = CreateDIBSection(dc, bi, DIB_RGB_COLORS, &bits, NULL, 0);
656 DeleteDC(dc);
657 }
658 else
659 {
660 /* Create a device-dependent bitmap */
661
662 BOOL monochrome = (flags & LR_MONOCHROME);
663
664 if (objSize == sizeof(DIBSECTION))
665 {
666 /* The source bitmap is a DIB section.
667 Get its attributes */
668 HDC dc = CreateCompatibleDC(NULL);
669 bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
670 bi->bmiHeader.biBitCount = ds.dsBm.bmBitsPixel;
671 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
672 DeleteDC(dc);
673
674 if (!monochrome && ds.dsBm.bmBitsPixel == 1)
675 {
676 /* Look if the colors of the DIB are black and white */
677
678 monochrome =
679 (bi->bmiColors[0].rgbRed == 0xff
680 && bi->bmiColors[0].rgbGreen == 0xff
681 && bi->bmiColors[0].rgbBlue == 0xff
682 && bi->bmiColors[0].rgbReserved == 0
683 && bi->bmiColors[1].rgbRed == 0
684 && bi->bmiColors[1].rgbGreen == 0
685 && bi->bmiColors[1].rgbBlue == 0
686 && bi->bmiColors[1].rgbReserved == 0)
687 ||
688 (bi->bmiColors[0].rgbRed == 0
689 && bi->bmiColors[0].rgbGreen == 0
690 && bi->bmiColors[0].rgbBlue == 0
691 && bi->bmiColors[0].rgbReserved == 0
692 && bi->bmiColors[1].rgbRed == 0xff
693 && bi->bmiColors[1].rgbGreen == 0xff
694 && bi->bmiColors[1].rgbBlue == 0xff
695 && bi->bmiColors[1].rgbReserved == 0);
696 }
697 }
698 else if (!monochrome)
699 {
700 monochrome = ds.dsBm.bmBitsPixel == 1;
701 }
702
703 if (monochrome)
704 {
705 res = CreateBitmap(desiredx, desiredy, 1, 1, NULL);
706 }
707 else
708 {
709 HDC screenDC = GetDC(NULL);
710 res = CreateCompatibleBitmap(screenDC, desiredx, desiredy);
711 ReleaseDC(NULL, screenDC);
712 }
713 }
714
715 if (res)
716 {
717 /* Only copy the bitmap if it's a DIB section or if it's
718 compatible to the screen */
719 BOOL copyContents;
720
721 if (objSize == sizeof(DIBSECTION))
722 {
723 copyContents = TRUE;
724 }
725 else
726 {
727 HDC screenDC = GetDC(NULL);
728 int screen_depth = GetDeviceCaps(screenDC, BITSPIXEL);
729 ReleaseDC(NULL, screenDC);
730
731 copyContents = (ds.dsBm.bmBitsPixel == 1 || ds.dsBm.bmBitsPixel == screen_depth);
732 }
733
734 if (copyContents)
735 {
736 /* The source bitmap may already be selected in a device context,
737 use GetDIBits/StretchDIBits and not StretchBlt */
738
739 HDC dc;
740 void * bits;
741
742 dc = CreateCompatibleDC(NULL);
743
744 bi->bmiHeader.biWidth = ds.dsBm.bmWidth;
745 bi->bmiHeader.biHeight = ds.dsBm.bmHeight;
746 bi->bmiHeader.biSizeImage = 0;
747 bi->bmiHeader.biClrUsed = 0;
748 bi->bmiHeader.biClrImportant = 0;
749
750 /* Fill in biSizeImage */
751 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
752 bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bi->bmiHeader.biSizeImage);
753
754 if (bits)
755 {
756 HBITMAP oldBmp;
757
758 /* Get the image bits of the source bitmap */
759 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, bits, bi, DIB_RGB_COLORS);
760
761 /* Copy it to the destination bitmap */
762 oldBmp = SelectObject(dc, res);
763 StretchDIBits(dc, 0, 0, desiredx, desiredy,
764 0, 0, ds.dsBm.bmWidth, ds.dsBm.bmHeight,
765 bits, bi, DIB_RGB_COLORS, SRCCOPY);
766 SelectObject(dc, oldBmp);
767
768 HeapFree(GetProcessHeap(), 0, bits);
769 }
770
771 DeleteDC(dc);
772 }
773
774 if (flags & LR_COPYDELETEORG)
775 {
776 DeleteObject(hnd);
777 }
778 }
779 HeapFree(GetProcessHeap(), 0, bi);
780 return res;
781 }
782
783
784 INT
785 GetIconCurBpp(PICONINFO pIconInfo)
786 {
787 PBITMAPINFO pbi;
788
789 pbi = (PBITMAPINFO)pIconInfo->hbmColor;
790 return pbi->bmiHeader.biBitCount;
791 }
792
793 #if 0
794 static BOOL
795 SetCursorIconData(
796 HANDLE Handle,
797 HINSTANCE hMod,
798 LPWSTR lpResName,
799 PICONINFO pIconInfo)
800 {
801
802 UNICODE_STRING Res;
803
804 if (!Handle || !pIconInfo)
805 return FALSE;
806
807 RtlInitUnicodeString(&Res, lpResName);
808
809 return NtUserSetCursorIconData(Handle, hMod, &Res, pIconInfo);
810
811 }
812
813
814 /* bare bones icon copy implementation */
815 static HANDLE
816 CopyIcoCur(HANDLE hIconCur,
817 UINT type,
818 INT desiredx,
819 INT desiredy,
820 UINT flags)
821 {
822 HANDLE hNewIcon = NULL;
823 ICONINFO origIconInfo, newIconInfo;
824 SIZE origSize;
825 DWORD origBpp;
826
827 if (!hIconCur)
828 return NULL;
829
830 if (flags & LR_COPYFROMRESOURCE)
831 {
832 TRACE("FIXME: LR_COPYFROMRESOURCE is yet not implemented for icons\n");
833 }
834
835 if (NtUserGetIconSize(hIconCur, 0, &origSize.cx, &origSize.cy))
836 {
837 if (desiredx == 0) desiredx = origSize.cx;
838 if (desiredx == 0) desiredy = origSize.cy;
839
840 if (NtUserGetIconInfo(hIconCur, &origIconInfo, NULL, NULL, &origBpp, TRUE))
841 {
842 hNewIcon = (HANDLE)NtUserCallOneParam(0, ONEPARAM_ROUTINE_CREATECURICONHANDLE);
843
844 if (hNewIcon)
845 {
846 /* the bitmaps returned from the NtUserGetIconInfo are copies of the original,
847 * so we can use these directly to build up our icon/cursor copy */
848 RtlCopyMemory(&newIconInfo, &origIconInfo, sizeof(ICONINFO));
849
850 if (!SetCursorIconData(hNewIcon, NULL, NULL, &newIconInfo))
851 {
852 if (newIconInfo.fIcon)
853 DestroyIcon(hNewIcon);
854 else
855 DestroyCursor(hNewIcon);
856
857 hNewIcon = NULL;
858 }
859 }
860
861 DeleteObject(origIconInfo.hbmMask);
862 DeleteObject(origIconInfo.hbmColor);
863 }
864 }
865
866 if (hNewIcon && (flags & LR_COPYDELETEORG))
867 {
868 DestroyCursor((HCURSOR)hIconCur);
869 }
870
871 return hNewIcon;
872 }
873 #endif
874
875 /*
876 * @unimplemented
877 */
878 HANDLE WINAPI
879 CopyImage(
880 IN HANDLE hnd,
881 IN UINT type,
882 IN INT desiredx,
883 IN INT desiredy,
884 IN UINT flags)
885 {
886 /*
887 * BUGS
888 * Only Windows NT 4.0 supports the LR_COPYRETURNORG flag for bitmaps,
889 * all other versions (95/2000/XP have been tested) ignore it.
890 *
891 * NOTES
892 * If LR_CREATEDIBSECTION is absent, the copy will be monochrome for
893 * a monochrome source bitmap or if LR_MONOCHROME is present, otherwise
894 * the copy will have the same depth as the screen.
895 * The content of the image will only be copied if the bit depth of the
896 * original image is compatible with the bit depth of the screen, or
897 * if the source is a DIB section.
898 * The LR_MONOCHROME flag is ignored if LR_CREATEDIBSECTION is present.
899 */
900 switch (type)
901 {
902 case IMAGE_BITMAP:
903 return CopyBmp(hnd, type, desiredx, desiredy, flags);
904
905 case IMAGE_ICON:
906 //return CopyIcoCur(hnd, type, desiredx, desiredy, flags);
907 return CopyIcon(hnd);
908
909 case IMAGE_CURSOR:
910 {
911 static BOOL IconMsgDisplayed = FALSE;
912 /* FIXME: support loading the image as shared from an instance */
913 if (!IconMsgDisplayed)
914 {
915 FIXME("FIXME: CopyImage doesn't support IMAGE_CURSOR correctly!\n");
916 IconMsgDisplayed = TRUE;
917 }
918 /* Should call CURSORICON_ExtCopy but more testing
919 * needs to be done before we change this
920 */
921 if (flags) FIXME("FIXME: Flags are ignored\n");
922 return CopyCursor(hnd);
923 }
924 }
925
926 return NULL;
927 }