[user32]
[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 CreateCursorIconFromData(HDC hDC, PVOID ImageData, ICONIMAGE* IconImage, int cxDesired, int cyDesired, int xHotspot, int yHotspot, BOOL fIcon);
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
333 /* Pick the best size. */
334 dirEntry = CURSORICON_FindBestCursorFile( IconDIR, width, height, ColorBits );
335 if (!dirEntry)
336 {
337 DeleteDC(hScreenDc);
338 UnmapViewOfFile(IconDIR);
339 return NULL;
340 }
341
342 if ( dirEntry->dwDIBOffset > filesize )
343 {
344 DeleteDC(hScreenDc);
345 UnmapViewOfFile(IconDIR);
346 return NULL;
347 }
348
349 if ( dirEntry->dwDIBOffset + dirEntry->dwDIBSize > filesize ){
350 DeleteDC(hScreenDc);
351 UnmapViewOfFile(IconDIR);
352 return NULL;
353 }
354
355 SafeIconImage = RtlAllocateHeap(GetProcessHeap(), 0, dirEntry->dwDIBSize);
356 if (SafeIconImage == NULL)
357 {
358 DeleteDC(hScreenDc);
359 UnmapViewOfFile(IconDIR);
360 return NULL;
361 }
362
363 memcpy(SafeIconImage, ((PBYTE)IconDIR) + dirEntry->dwDIBOffset, dirEntry->dwDIBSize);
364 UnmapViewOfFile(IconDIR);
365
366 /* At this point we have a copy of the icon image to play with. */
367
368 SafeIconImage->icHeader.biHeight = SafeIconImage->icHeader.biHeight /2;
369
370 if (SafeIconImage->icHeader.biSize == sizeof(BITMAPCOREHEADER))
371 {
372 BITMAPCOREHEADER* Core = (BITMAPCOREHEADER*)SafeIconImage;
373 ColorCount = (Core->bcBitCount <= 8) ? (1 << Core->bcBitCount) : 0;
374 HeaderSize = sizeof(BITMAPCOREHEADER) + ColorCount * sizeof(RGBTRIPLE);
375 }
376 else
377 {
378 ColorCount = SafeIconImage->icHeader.biClrUsed;
379 if (ColorCount == 0 && SafeIconImage->icHeader.biBitCount <= 8)
380 ColorCount = 1 << SafeIconImage->icHeader.biBitCount;
381 HeaderSize = sizeof(BITMAPINFOHEADER) + ColorCount * sizeof(RGBQUAD);
382 }
383
384 /* Make data point to the start of the XOR image data. */
385 Data = (PBYTE)SafeIconImage + HeaderSize;
386
387 hIcon = CreateCursorIconFromData(hScreenDc, Data, SafeIconImage, width, height, width/2, height/2, Icon);
388 RtlFreeHeap(GetProcessHeap(), 0, SafeIconImage);
389 DeleteDC(hScreenDc);
390
391 return hIcon;
392 }
393
394
395 static HANDLE
396 LoadBitmapImage(HINSTANCE hInstance, LPCWSTR lpszName, UINT fuLoad)
397 {
398 HANDLE hResource;
399 HANDLE hFile;
400 HANDLE hSection;
401 LPBITMAPINFO BitmapInfo;
402 LPBITMAPINFO PrivateInfo;
403 HDC hScreenDc;
404 HANDLE hBitmap;
405 ULONG HeaderSize;
406 ULONG ColorCount;
407 PVOID Data;
408 BOOL Hit = FALSE;
409
410 if (!(fuLoad & LR_LOADFROMFILE))
411 {
412 if (hInstance == NULL)
413 hInstance = User32Instance;
414
415 hResource = FindResourceW(hInstance, lpszName, RT_BITMAP);
416 if (hResource == NULL)
417 return NULL;
418 hResource = LoadResource(hInstance, hResource);
419 if (hResource == NULL)
420 return NULL;
421 BitmapInfo = LockResource(hResource);
422 if (BitmapInfo == NULL)
423 return NULL;
424 }
425 else
426 {
427 hFile = CreateFileW(lpszName, GENERIC_READ, FILE_SHARE_READ, NULL,
428 OPEN_EXISTING, 0, NULL);
429 if (hFile == INVALID_HANDLE_VALUE)
430 return NULL;
431
432 hSection = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
433 CloseHandle(hFile);
434 if (hSection == NULL)
435 return NULL;
436
437 BitmapInfo = MapViewOfFile(hSection, FILE_MAP_READ, 0, 0, 0);
438 CloseHandle(hSection);
439 if (BitmapInfo == NULL)
440 return NULL;
441
442 BitmapInfo = (LPBITMAPINFO)((ULONG_PTR)BitmapInfo + sizeof(BITMAPFILEHEADER));
443 }
444
445 HeaderSize = BitmapInfo->bmiHeader.biSize;
446 if (HeaderSize == sizeof(BITMAPCOREHEADER))
447 {
448 BITMAPCOREHEADER* Core = (BITMAPCOREHEADER*)BitmapInfo;
449 ColorCount = (Core->bcBitCount <= 8) ? (1 << Core->bcBitCount) : 0;
450 HeaderSize += ColorCount * sizeof(RGBTRIPLE);
451 }
452 else
453 {
454 if (BitmapInfo->bmiHeader.biCompression == BI_BITFIELDS)
455 {
456 HeaderSize += 3 * sizeof(RGBQUAD);
457 }
458 else
459 {
460 ColorCount = BitmapInfo->bmiHeader.biClrUsed;
461 if (ColorCount == 0 && BitmapInfo->bmiHeader.biBitCount <= 8)
462 ColorCount = 1 << BitmapInfo->bmiHeader.biBitCount;
463 HeaderSize += ColorCount * sizeof(RGBQUAD);
464 }
465 }
466 Data = (PVOID)((ULONG_PTR)BitmapInfo + HeaderSize);
467
468 PrivateInfo = RtlAllocateHeap(GetProcessHeap(), 0, HeaderSize);
469 if (PrivateInfo == NULL)
470 {
471 if (fuLoad & LR_LOADFROMFILE)
472 UnmapViewOfFile(BitmapInfo);
473 return NULL;
474 }
475
476 _SEH2_TRY
477 {
478 memcpy(PrivateInfo, BitmapInfo, HeaderSize);
479 }
480 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
481 {
482 Hit = TRUE;
483 }
484 _SEH2_END;
485
486 if (Hit)
487 {
488 ERR("We have a thread overrun, these are already freed! pi -> %d, bi -> %d\n", PrivateInfo, BitmapInfo);
489 RtlFreeHeap(GetProcessHeap(), 0, PrivateInfo);
490 if (fuLoad & LR_LOADFROMFILE)
491 UnmapViewOfFile(BitmapInfo);
492 return NULL;
493 }
494
495 /* FIXME: Handle color conversion and transparency. */
496
497 hScreenDc = CreateCompatibleDC(NULL);
498 if (hScreenDc == NULL)
499 {
500 RtlFreeHeap(GetProcessHeap(), 0, PrivateInfo);
501 if (fuLoad & LR_LOADFROMFILE)
502 UnmapViewOfFile(BitmapInfo);
503 return NULL;
504 }
505
506 if (fuLoad & LR_CREATEDIBSECTION)
507 {
508 DIBSECTION Dib;
509
510 hBitmap = CreateDIBSection(hScreenDc, PrivateInfo, DIB_RGB_COLORS, NULL,
511 0, 0);
512 GetObjectA(hBitmap, sizeof(DIBSECTION), &Dib);
513 SetDIBits(hScreenDc, hBitmap, 0, Dib.dsBm.bmHeight, Data, BitmapInfo,
514 DIB_RGB_COLORS);
515 }
516 else
517 {
518 hBitmap = CreateDIBitmap(hScreenDc, &PrivateInfo->bmiHeader, CBM_INIT,
519 Data, PrivateInfo, DIB_RGB_COLORS);
520 }
521
522 RtlFreeHeap(GetProcessHeap(), 0, PrivateInfo);
523 DeleteDC(hScreenDc);
524 if (fuLoad & LR_LOADFROMFILE)
525 UnmapViewOfFile(BitmapInfo);
526
527 return hBitmap;
528 }
529
530 HANDLE WINAPI
531 LoadImageW(
532 IN HINSTANCE hinst,
533 IN LPCWSTR lpszName,
534 IN UINT uType,
535 IN INT cxDesired,
536 IN INT cyDesired,
537 IN UINT fuLoad)
538 {
539 if (fuLoad & LR_DEFAULTSIZE)
540 {
541 if (uType == IMAGE_ICON)
542 {
543 if (cxDesired == 0)
544 cxDesired = GetSystemMetrics(SM_CXICON);
545 if (cyDesired == 0)
546 cyDesired = GetSystemMetrics(SM_CYICON);
547 }
548 else if (uType == IMAGE_CURSOR)
549 {
550 if (cxDesired == 0)
551 cxDesired = GetSystemMetrics(SM_CXCURSOR);
552 if (cyDesired == 0)
553 cyDesired = GetSystemMetrics(SM_CYCURSOR);
554 }
555 }
556
557 switch (uType)
558 {
559 case IMAGE_BITMAP:
560 return LoadBitmapImage(hinst, lpszName, fuLoad);
561 case IMAGE_CURSOR:
562 case IMAGE_ICON:
563 return LoadCursorIconImage(hinst, lpszName, cxDesired, cyDesired,
564 fuLoad, uType);
565 default:
566 break;
567 }
568
569 return NULL;
570 }
571
572
573 /*
574 * @implemented
575 */
576 HBITMAP WINAPI
577 LoadBitmapA(HINSTANCE hInstance, LPCSTR lpBitmapName)
578 {
579 return LoadImageA(hInstance, lpBitmapName, IMAGE_BITMAP, 0, 0, 0);
580 }
581
582
583 /*
584 * @implemented
585 */
586 HBITMAP WINAPI
587 LoadBitmapW(HINSTANCE hInstance, LPCWSTR lpBitmapName)
588 {
589 return LoadImageW(hInstance, lpBitmapName, IMAGE_BITMAP, 0, 0, 0);
590 }
591
592
593 static HANDLE
594 CopyBmp(HANDLE hnd,
595 UINT type,
596 INT desiredx,
597 INT desiredy,
598 UINT flags)
599 {
600 HBITMAP res = NULL;
601 DIBSECTION ds;
602 int objSize;
603 BITMAPINFO * bi;
604
605 objSize = GetObjectW( hnd, sizeof(ds), &ds );
606 if (!objSize) return 0;
607 if ((desiredx < 0) || (desiredy < 0)) return 0;
608
609 if (flags & LR_COPYFROMRESOURCE)
610 {
611 FIXME("FIXME: The flag LR_COPYFROMRESOURCE is not implemented for bitmaps\n");
612 }
613
614 if (desiredx == 0) desiredx = ds.dsBm.bmWidth;
615 if (desiredy == 0) desiredy = ds.dsBm.bmHeight;
616
617 /* Allocate memory for a BITMAPINFOHEADER structure and a
618 color table. The maximum number of colors in a color table
619 is 256 which corresponds to a bitmap with depth 8.
620 Bitmaps with higher depths don't have color tables. */
621 bi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
622 if (!bi) return 0;
623
624 bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
625 bi->bmiHeader.biPlanes = ds.dsBm.bmPlanes;
626 bi->bmiHeader.biBitCount = ds.dsBm.bmBitsPixel;
627 bi->bmiHeader.biCompression = BI_RGB;
628
629 if (flags & LR_CREATEDIBSECTION)
630 {
631 /* Create a DIB section. LR_MONOCHROME is ignored */
632 void * bits;
633 HDC dc = CreateCompatibleDC(NULL);
634
635 if (objSize == sizeof(DIBSECTION))
636 {
637 /* The source bitmap is a DIB.
638 Get its attributes to create an exact copy */
639 memcpy(bi, &ds.dsBmih, sizeof(BITMAPINFOHEADER));
640 }
641
642 /* Get the color table or the color masks */
643 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
644
645 bi->bmiHeader.biWidth = desiredx;
646 bi->bmiHeader.biHeight = desiredy;
647 bi->bmiHeader.biSizeImage = 0;
648
649 res = CreateDIBSection(dc, bi, DIB_RGB_COLORS, &bits, NULL, 0);
650 DeleteDC(dc);
651 }
652 else
653 {
654 /* Create a device-dependent bitmap */
655
656 BOOL monochrome = (flags & LR_MONOCHROME);
657
658 if (objSize == sizeof(DIBSECTION))
659 {
660 /* The source bitmap is a DIB section.
661 Get its attributes */
662 HDC dc = CreateCompatibleDC(NULL);
663 bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
664 bi->bmiHeader.biBitCount = ds.dsBm.bmBitsPixel;
665 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
666 DeleteDC(dc);
667
668 if (!monochrome && ds.dsBm.bmBitsPixel == 1)
669 {
670 /* Look if the colors of the DIB are black and white */
671
672 monochrome =
673 (bi->bmiColors[0].rgbRed == 0xff
674 && bi->bmiColors[0].rgbGreen == 0xff
675 && bi->bmiColors[0].rgbBlue == 0xff
676 && bi->bmiColors[0].rgbReserved == 0
677 && bi->bmiColors[1].rgbRed == 0
678 && bi->bmiColors[1].rgbGreen == 0
679 && bi->bmiColors[1].rgbBlue == 0
680 && bi->bmiColors[1].rgbReserved == 0)
681 ||
682 (bi->bmiColors[0].rgbRed == 0
683 && bi->bmiColors[0].rgbGreen == 0
684 && bi->bmiColors[0].rgbBlue == 0
685 && bi->bmiColors[0].rgbReserved == 0
686 && bi->bmiColors[1].rgbRed == 0xff
687 && bi->bmiColors[1].rgbGreen == 0xff
688 && bi->bmiColors[1].rgbBlue == 0xff
689 && bi->bmiColors[1].rgbReserved == 0);
690 }
691 }
692 else if (!monochrome)
693 {
694 monochrome = ds.dsBm.bmBitsPixel == 1;
695 }
696
697 if (monochrome)
698 {
699 res = CreateBitmap(desiredx, desiredy, 1, 1, NULL);
700 }
701 else
702 {
703 HDC screenDC = GetDC(NULL);
704 res = CreateCompatibleBitmap(screenDC, desiredx, desiredy);
705 ReleaseDC(NULL, screenDC);
706 }
707 }
708
709 if (res)
710 {
711 /* Only copy the bitmap if it's a DIB section or if it's
712 compatible to the screen */
713 BOOL copyContents;
714
715 if (objSize == sizeof(DIBSECTION))
716 {
717 copyContents = TRUE;
718 }
719 else
720 {
721 HDC screenDC = GetDC(NULL);
722 int screen_depth = GetDeviceCaps(screenDC, BITSPIXEL);
723 ReleaseDC(NULL, screenDC);
724
725 copyContents = (ds.dsBm.bmBitsPixel == 1 || ds.dsBm.bmBitsPixel == screen_depth);
726 }
727
728 if (copyContents)
729 {
730 /* The source bitmap may already be selected in a device context,
731 use GetDIBits/StretchDIBits and not StretchBlt */
732
733 HDC dc;
734 void * bits;
735
736 dc = CreateCompatibleDC(NULL);
737
738 bi->bmiHeader.biWidth = ds.dsBm.bmWidth;
739 bi->bmiHeader.biHeight = ds.dsBm.bmHeight;
740 bi->bmiHeader.biSizeImage = 0;
741 bi->bmiHeader.biClrUsed = 0;
742 bi->bmiHeader.biClrImportant = 0;
743
744 /* Fill in biSizeImage */
745 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
746 bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bi->bmiHeader.biSizeImage);
747
748 if (bits)
749 {
750 HBITMAP oldBmp;
751
752 /* Get the image bits of the source bitmap */
753 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, bits, bi, DIB_RGB_COLORS);
754
755 /* Copy it to the destination bitmap */
756 oldBmp = SelectObject(dc, res);
757 StretchDIBits(dc, 0, 0, desiredx, desiredy,
758 0, 0, ds.dsBm.bmWidth, ds.dsBm.bmHeight,
759 bits, bi, DIB_RGB_COLORS, SRCCOPY);
760 SelectObject(dc, oldBmp);
761
762 HeapFree(GetProcessHeap(), 0, bits);
763 }
764
765 DeleteDC(dc);
766 }
767
768 if (flags & LR_COPYDELETEORG)
769 {
770 DeleteObject(hnd);
771 }
772 }
773 HeapFree(GetProcessHeap(), 0, bi);
774 return res;
775 }
776
777
778 INT
779 GetIconCurBpp(PICONINFO pIconInfo)
780 {
781 PBITMAPINFO pbi;
782
783 pbi = (PBITMAPINFO)pIconInfo->hbmColor;
784 return pbi->bmiHeader.biBitCount;
785 }
786
787 #if 0
788 static BOOL
789 SetCursorIconData(
790 HANDLE Handle,
791 HINSTANCE hMod,
792 LPWSTR lpResName,
793 PICONINFO pIconInfo)
794 {
795
796 UNICODE_STRING Res;
797
798 if (!Handle || !pIconInfo)
799 return FALSE;
800
801 RtlInitUnicodeString(&Res, lpResName);
802
803 return NtUserSetCursorIconData(Handle, hMod, &Res, pIconInfo);
804
805 }
806
807
808 /* bare bones icon copy implementation */
809 static HANDLE
810 CopyIcoCur(HANDLE hIconCur,
811 UINT type,
812 INT desiredx,
813 INT desiredy,
814 UINT flags)
815 {
816 HANDLE hNewIcon = NULL;
817 ICONINFO origIconInfo, newIconInfo;
818 SIZE origSize;
819 DWORD origBpp;
820
821 if (!hIconCur)
822 return NULL;
823
824 if (flags & LR_COPYFROMRESOURCE)
825 {
826 TRACE("FIXME: LR_COPYFROMRESOURCE is yet not implemented for icons\n");
827 }
828
829 if (NtUserGetIconSize(hIconCur, 0, &origSize.cx, &origSize.cy))
830 {
831 if (desiredx == 0) desiredx = origSize.cx;
832 if (desiredx == 0) desiredy = origSize.cy;
833
834 if (NtUserGetIconInfo(hIconCur, &origIconInfo, NULL, NULL, &origBpp, TRUE))
835 {
836 hNewIcon = (HANDLE)NtUserCallOneParam(0, ONEPARAM_ROUTINE_CREATECURICONHANDLE);
837
838 if (hNewIcon)
839 {
840 /* the bitmaps returned from the NtUserGetIconInfo are copies of the original,
841 * so we can use these directly to build up our icon/cursor copy */
842 RtlCopyMemory(&newIconInfo, &origIconInfo, sizeof(ICONINFO));
843
844 if (!SetCursorIconData(hNewIcon, NULL, NULL, &newIconInfo))
845 {
846 if (newIconInfo.fIcon)
847 DestroyIcon(hNewIcon);
848 else
849 DestroyCursor(hNewIcon);
850
851 hNewIcon = NULL;
852 }
853 }
854
855 DeleteObject(origIconInfo.hbmMask);
856 DeleteObject(origIconInfo.hbmColor);
857 }
858 }
859
860 if (hNewIcon && (flags & LR_COPYDELETEORG))
861 {
862 DestroyCursor((HCURSOR)hIconCur);
863 }
864
865 return hNewIcon;
866 }
867 #endif
868
869 /*
870 * @unimplemented
871 */
872 HANDLE WINAPI
873 CopyImage(
874 IN HANDLE hnd,
875 IN UINT type,
876 IN INT desiredx,
877 IN INT desiredy,
878 IN UINT flags)
879 {
880 /*
881 * BUGS
882 * Only Windows NT 4.0 supports the LR_COPYRETURNORG flag for bitmaps,
883 * all other versions (95/2000/XP have been tested) ignore it.
884 *
885 * NOTES
886 * If LR_CREATEDIBSECTION is absent, the copy will be monochrome for
887 * a monochrome source bitmap or if LR_MONOCHROME is present, otherwise
888 * the copy will have the same depth as the screen.
889 * The content of the image will only be copied if the bit depth of the
890 * original image is compatible with the bit depth of the screen, or
891 * if the source is a DIB section.
892 * The LR_MONOCHROME flag is ignored if LR_CREATEDIBSECTION is present.
893 */
894 switch (type)
895 {
896 case IMAGE_BITMAP:
897 return CopyBmp(hnd, type, desiredx, desiredy, flags);
898
899 case IMAGE_ICON:
900 //return CopyIcoCur(hnd, type, desiredx, desiredy, flags);
901 return CopyIcon(hnd);
902
903 case IMAGE_CURSOR:
904 {
905 static BOOL IconMsgDisplayed = FALSE;
906 /* FIXME: support loading the image as shared from an instance */
907 if (!IconMsgDisplayed)
908 {
909 FIXME("FIXME: CopyImage doesn't support IMAGE_CURSOR correctly!\n");
910 IconMsgDisplayed = TRUE;
911 }
912 /* Should call CURSORICON_ExtCopy but more testing
913 * needs to be done before we change this
914 */
915 if (flags) FIXME("FIXME: Flags are ignored\n");
916 return CopyCursor(hnd);
917 }
918 }
919
920 return NULL;
921 }