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