merge trunk rev : 25663 and 25664 to 0.3.1 branch - update freetype, take care of...
[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
35 #include "pshpack1.h"
36
37 typedef struct {
38 BYTE bWidth;
39 BYTE bHeight;
40 BYTE bColorCount;
41 BYTE bReserved;
42 WORD xHotspot;
43 WORD yHotspot;
44 DWORD dwDIBSize;
45 DWORD dwDIBOffset;
46 } CURSORICONFILEDIRENTRY;
47
48 typedef struct
49 {
50 WORD idReserved;
51 WORD idType;
52 WORD idCount;
53 CURSORICONFILEDIRENTRY idEntries[1];
54 } CURSORICONFILEDIR;
55
56 #include "poppack.h"
57
58 /*forward declerations... actualy in user32\windows\icon.c but usful here****/
59 HICON ICON_CreateCursorFromData(HDC hDC, PVOID ImageData, ICONIMAGE* IconImage, int cxDesired, int cyDesired, int xHotspot, int yHotspot);
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 STDCALL
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 HANDLE hResource;
190 HANDLE h2Resource;
191 HANDLE hfRes;
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 hResource = hfRes = FindResourceW(hinst, lpszName,
215 Icon ? RT_GROUP_ICON : RT_GROUP_CURSOR);
216 if (hResource == NULL)
217 return NULL;
218
219 if (fuLoad & LR_SHARED)
220 {
221 hIcon = NtUserFindExistingCursorIcon(hinst, (HRSRC)hfRes, width, height);
222 if (hIcon)
223 return hIcon;
224 }
225
226 hResource = LoadResource(hinst, hResource);
227 if (hResource == NULL)
228 return NULL;
229
230 IconResDir = LockResource(hResource);
231 if (IconResDir == NULL)
232 return NULL;
233
234 /*
235 * Find the best fitting in the IconResDir for this resolution
236 */
237
238 id = LookupIconIdFromDirectoryEx((PBYTE)IconResDir, Icon, width, height,
239 fuLoad & (LR_DEFAULTCOLOR | LR_MONOCHROME));
240
241 h2Resource = FindResourceW(hinst, MAKEINTRESOURCEW(id),
242 Icon ? MAKEINTRESOURCEW(RT_ICON) :
243 MAKEINTRESOURCEW(RT_CURSOR));
244 if (h2Resource == NULL)
245 return NULL;
246
247 hResource = LoadResource(hinst, h2Resource);
248 if (hResource == NULL)
249 return NULL;
250
251 ResIcon = LockResource(hResource);
252 if (ResIcon == NULL)
253 return NULL;
254
255 hIcon = CreateIconFromResourceEx((PBYTE)ResIcon,
256 SizeofResource(hinst, h2Resource),
257 Icon, 0x00030000, width, height,
258 fuLoad & (LR_DEFAULTCOLOR | LR_MONOCHROME));
259 if (hIcon && 0 != (fuLoad & LR_SHARED))
260 {
261 NtUserSetCursorIconData((HICON)hIcon, NULL, NULL, hinst, (HRSRC)hfRes,
262 (HRSRC)NULL);
263 }
264
265 return hIcon;
266 }
267
268 if (fuLoad & LR_SHARED)
269 {
270 DbgPrint("FIXME: need LR_SHARED support for loading icon images from files\n");
271 }
272
273 hFile = CreateFileW(lpszName, GENERIC_READ, FILE_SHARE_READ, NULL,
274 OPEN_EXISTING, 0, NULL);
275 if (hFile == INVALID_HANDLE_VALUE)
276 return NULL;
277
278 hSection = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
279 filesize = GetFileSize( hFile, NULL );
280 CloseHandle(hFile);
281 if (hSection == NULL)
282 return NULL;
283
284 IconDIR = MapViewOfFile(hSection, FILE_MAP_READ, 0, 0, 0);
285 CloseHandle(hSection);
286 if (IconDIR == NULL)
287 return NULL;
288
289 if (0 != IconDIR->idReserved ||
290 (IMAGE_ICON != IconDIR->idType && IMAGE_CURSOR != IconDIR->idType))
291 {
292 UnmapViewOfFile(IconDIR);
293 return NULL;
294 }
295
296 /* Get a handle to the screen dc, the icon we create is going to be
297 * compatable with this. */
298 hScreenDc = CreateDCW(NULL, NULL, NULL, NULL);
299 if (hScreenDc == NULL)
300 {
301 UnmapViewOfFile(IconDIR);
302 RtlFreeHeap(GetProcessHeap(), 0, SafeIconImage);
303 return NULL;
304 }
305
306 if (fuLoad & LR_MONOCHROME)
307 {
308 ColorBits = 1;
309 }
310 else
311 {
312 ColorBits = GetDeviceCaps(hScreenDc, BITSPIXEL);
313 /*
314 * FIXME:
315 * Remove this after proper support for alpha icons will be finished.
316 */
317 if (ColorBits > 8)
318 ColorBits = 8;
319 }
320
321 /* Pick the best size. */
322 dirEntry = CURSORICON_FindBestCursorFile( IconDIR, width, height, ColorBits );
323 if (!dirEntry)
324 {
325 DeleteDC(hScreenDc);
326 UnmapViewOfFile(IconDIR);
327 return NULL;
328 }
329
330 if ( dirEntry->dwDIBOffset > filesize )
331 {
332 DeleteDC(hScreenDc);
333 UnmapViewOfFile(IconDIR);
334 return NULL;
335 }
336
337 if ( dirEntry->dwDIBOffset + dirEntry->dwDIBSize > filesize ){
338 DeleteDC(hScreenDc);
339 UnmapViewOfFile(IconDIR);
340 return NULL;
341 }
342
343 SafeIconImage = RtlAllocateHeap(GetProcessHeap(), 0, dirEntry->dwDIBSize);
344 if (SafeIconImage == NULL)
345 {
346 DeleteDC(hScreenDc);
347 UnmapViewOfFile(IconDIR);
348 return NULL;
349 }
350
351 memcpy(SafeIconImage, ((PBYTE)IconDIR) + dirEntry->dwDIBOffset, dirEntry->dwDIBSize);
352 UnmapViewOfFile(IconDIR);
353
354 /* At this point we have a copy of the icon image to play with. */
355
356 SafeIconImage->icHeader.biHeight = SafeIconImage->icHeader.biHeight /2;
357
358 if (SafeIconImage->icHeader.biSize == sizeof(BITMAPCOREHEADER))
359 {
360 BITMAPCOREHEADER* Core = (BITMAPCOREHEADER*)SafeIconImage;
361 ColorCount = (Core->bcBitCount <= 8) ? (1 << Core->bcBitCount) : 0;
362 HeaderSize = sizeof(BITMAPCOREHEADER) + ColorCount * sizeof(RGBTRIPLE);
363 }
364 else
365 {
366 ColorCount = SafeIconImage->icHeader.biClrUsed;
367 if (ColorCount == 0 && SafeIconImage->icHeader.biBitCount <= 8)
368 ColorCount = 1 << SafeIconImage->icHeader.biBitCount;
369 HeaderSize = sizeof(BITMAPINFOHEADER) + ColorCount * sizeof(RGBQUAD);
370 }
371
372 /* Make data point to the start of the XOR image data. */
373 Data = (PBYTE)SafeIconImage + HeaderSize;
374
375 hIcon = ICON_CreateIconFromData(hScreenDc, Data, SafeIconImage, width, height, width/2, height/2);
376 RtlFreeHeap(GetProcessHeap(), 0, SafeIconImage);
377 DeleteDC(hScreenDc);
378
379 return hIcon;
380 }
381
382
383 static HANDLE
384 LoadBitmapImage(HINSTANCE hInstance, LPCWSTR lpszName, UINT fuLoad)
385 {
386 HANDLE hResource;
387 HANDLE hFile;
388 HANDLE hSection;
389 LPBITMAPINFO BitmapInfo;
390 LPBITMAPINFO PrivateInfo;
391 HDC hScreenDc;
392 HANDLE hBitmap;
393 ULONG HeaderSize;
394 ULONG ColorCount;
395 PVOID Data;
396
397 if (!(fuLoad & LR_LOADFROMFILE))
398 {
399 if (hInstance == NULL)
400 hInstance = User32Instance;
401
402 hResource = FindResourceW(hInstance, lpszName, RT_BITMAP);
403 if (hResource == NULL)
404 return NULL;
405 hResource = LoadResource(hInstance, hResource);
406 if (hResource == NULL)
407 return NULL;
408 BitmapInfo = LockResource(hResource);
409 if (BitmapInfo == NULL)
410 return NULL;
411 }
412 else
413 {
414 hFile = CreateFileW(lpszName, GENERIC_READ, FILE_SHARE_READ, NULL,
415 OPEN_EXISTING, 0, NULL);
416 if (hFile == INVALID_HANDLE_VALUE)
417 return NULL;
418
419 hSection = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
420 CloseHandle(hFile);
421 if (hSection == NULL)
422 return NULL;
423
424 BitmapInfo = MapViewOfFile(hSection, FILE_MAP_READ, 0, 0, 0);
425 CloseHandle(hSection);
426 if (BitmapInfo == NULL)
427 return NULL;
428
429 BitmapInfo = (LPBITMAPINFO)((ULONG_PTR)BitmapInfo + sizeof(BITMAPFILEHEADER));
430 }
431
432 if (BitmapInfo->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
433 {
434 BITMAPCOREHEADER* Core = (BITMAPCOREHEADER*)BitmapInfo;
435 ColorCount = (Core->bcBitCount <= 8) ? (1 << Core->bcBitCount) : 0;
436 HeaderSize = sizeof(BITMAPCOREHEADER) + ColorCount * sizeof(RGBTRIPLE);
437 }
438 else
439 {
440 ColorCount = BitmapInfo->bmiHeader.biClrUsed;
441 if (ColorCount == 0 && BitmapInfo->bmiHeader.biBitCount <= 8)
442 ColorCount = 1 << BitmapInfo->bmiHeader.biBitCount;
443 HeaderSize = sizeof(BITMAPINFOHEADER) + ColorCount * sizeof(RGBQUAD);
444 }
445 Data = (PVOID)((ULONG_PTR)BitmapInfo + HeaderSize);
446
447 PrivateInfo = RtlAllocateHeap(GetProcessHeap(), 0, HeaderSize);
448 if (PrivateInfo == NULL)
449 {
450 if (fuLoad & LR_LOADFROMFILE)
451 UnmapViewOfFile(BitmapInfo);
452 return NULL;
453 }
454 memcpy(PrivateInfo, BitmapInfo, HeaderSize);
455
456 /* FIXME: Handle color conversion and transparency. */
457
458 hScreenDc = CreateCompatibleDC(NULL);
459 if (hScreenDc == NULL)
460 {
461 RtlFreeHeap(GetProcessHeap(), 0, PrivateInfo);
462 if (fuLoad & LR_LOADFROMFILE)
463 UnmapViewOfFile(BitmapInfo);
464 return NULL;
465 }
466
467 if (fuLoad & LR_CREATEDIBSECTION)
468 {
469 DIBSECTION Dib;
470
471 hBitmap = CreateDIBSection(hScreenDc, PrivateInfo, DIB_RGB_COLORS, NULL,
472 0, 0);
473 GetObjectA(hBitmap, sizeof(DIBSECTION), &Dib);
474 SetDIBits(hScreenDc, hBitmap, 0, Dib.dsBm.bmHeight, Data, BitmapInfo,
475 DIB_RGB_COLORS);
476 }
477 else
478 {
479 hBitmap = CreateDIBitmap(hScreenDc, &PrivateInfo->bmiHeader, CBM_INIT,
480 Data, PrivateInfo, DIB_RGB_COLORS);
481 }
482
483 RtlFreeHeap(GetProcessHeap(), 0, PrivateInfo);
484 DeleteDC(hScreenDc);
485 if (fuLoad & LR_LOADFROMFILE)
486 UnmapViewOfFile(BitmapInfo);
487
488 return hBitmap;
489 }
490
491 HANDLE STDCALL
492 LoadImageW(
493 IN HINSTANCE hinst,
494 IN LPCWSTR lpszName,
495 IN UINT uType,
496 IN INT cxDesired,
497 IN INT cyDesired,
498 IN UINT fuLoad)
499 {
500 if (fuLoad & LR_DEFAULTSIZE)
501 {
502 if (uType == IMAGE_ICON)
503 {
504 if (cxDesired == 0)
505 cxDesired = GetSystemMetrics(SM_CXICON);
506 if (cyDesired == 0)
507 cyDesired = GetSystemMetrics(SM_CYICON);
508 }
509 else if (uType == IMAGE_CURSOR)
510 {
511 if (cxDesired == 0)
512 cxDesired = GetSystemMetrics(SM_CXCURSOR);
513 if (cyDesired == 0)
514 cyDesired = GetSystemMetrics(SM_CYCURSOR);
515 }
516 }
517
518 switch (uType)
519 {
520 case IMAGE_BITMAP:
521 return LoadBitmapImage(hinst, lpszName, fuLoad);
522 case IMAGE_CURSOR:
523 case IMAGE_ICON:
524 return LoadCursorIconImage(hinst, lpszName, cxDesired, cyDesired,
525 fuLoad, uType);
526 default:
527 break;
528 }
529
530 return NULL;
531 }
532
533
534 /*
535 * @implemented
536 */
537 HBITMAP STDCALL
538 LoadBitmapA(HINSTANCE hInstance, LPCSTR lpBitmapName)
539 {
540 return LoadImageA(hInstance, lpBitmapName, IMAGE_BITMAP, 0, 0, 0);
541 }
542
543
544 /*
545 * @implemented
546 */
547 HBITMAP STDCALL
548 LoadBitmapW(HINSTANCE hInstance, LPCWSTR lpBitmapName)
549 {
550 return LoadImageW(hInstance, lpBitmapName, IMAGE_BITMAP, 0, 0, 0);
551 }
552
553
554 /*
555 * @unimplemented
556 */
557 HANDLE WINAPI
558 CopyImage(
559 IN HANDLE hnd,
560 IN UINT type,
561 IN INT desiredx,
562 IN INT desiredy,
563 IN UINT flags)
564 {
565 /*
566 * BUGS
567 * Only Windows NT 4.0 supports the LR_COPYRETURNORG flag for bitmaps,
568 * all other versions (95/2000/XP have been tested) ignore it.
569 *
570 * NOTES
571 * If LR_CREATEDIBSECTION is absent, the copy will be monochrome for
572 * a monochrome source bitmap or if LR_MONOCHROME is present, otherwise
573 * the copy will have the same depth as the screen.
574 * The content of the image will only be copied if the bit depth of the
575 * original image is compatible with the bit depth of the screen, or
576 * if the source is a DIB section.
577 * The LR_MONOCHROME flag is ignored if LR_CREATEDIBSECTION is present.
578 */
579 switch (type)
580 {
581 case IMAGE_BITMAP:
582 {
583 HBITMAP res = NULL;
584 DIBSECTION ds;
585 int objSize;
586 BITMAPINFO * bi;
587
588 objSize = GetObjectW( hnd, sizeof(ds), &ds );
589 if (!objSize) return 0;
590 if ((desiredx < 0) || (desiredy < 0)) return 0;
591
592 if (flags & LR_COPYFROMRESOURCE)
593 {
594 DPRINT1("FIXME: The flag LR_COPYFROMRESOURCE is not implemented for bitmaps\n");
595 }
596
597 if (desiredx == 0) desiredx = ds.dsBm.bmWidth;
598 if (desiredy == 0) desiredy = ds.dsBm.bmHeight;
599
600 /* Allocate memory for a BITMAPINFOHEADER structure and a
601 color table. The maximum number of colors in a color table
602 is 256 which corresponds to a bitmap with depth 8.
603 Bitmaps with higher depths don't have color tables. */
604 bi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
605 if (!bi) return 0;
606
607 bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
608 bi->bmiHeader.biPlanes = ds.dsBm.bmPlanes;
609 bi->bmiHeader.biBitCount = ds.dsBm.bmBitsPixel;
610 bi->bmiHeader.biCompression = BI_RGB;
611
612 if (flags & LR_CREATEDIBSECTION)
613 {
614 /* Create a DIB section. LR_MONOCHROME is ignored */
615 void * bits;
616 HDC dc = CreateCompatibleDC(NULL);
617
618 if (objSize == sizeof(DIBSECTION))
619 {
620 /* The source bitmap is a DIB.
621 Get its attributes to create an exact copy */
622 memcpy(bi, &ds.dsBmih, sizeof(BITMAPINFOHEADER));
623 }
624
625 /* Get the color table or the color masks */
626 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
627
628 bi->bmiHeader.biWidth = desiredx;
629 bi->bmiHeader.biHeight = desiredy;
630 bi->bmiHeader.biSizeImage = 0;
631
632 res = CreateDIBSection(dc, bi, DIB_RGB_COLORS, &bits, NULL, 0);
633 DeleteDC(dc);
634 }
635 else
636 {
637 /* Create a device-dependent bitmap */
638
639 BOOL monochrome = (flags & LR_MONOCHROME);
640
641 if (objSize == sizeof(DIBSECTION))
642 {
643 /* The source bitmap is a DIB section.
644 Get its attributes */
645 HDC dc = CreateCompatibleDC(NULL);
646 bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
647 bi->bmiHeader.biBitCount = ds.dsBm.bmBitsPixel;
648 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
649 DeleteDC(dc);
650
651 if (!monochrome && ds.dsBm.bmBitsPixel == 1)
652 {
653 /* Look if the colors of the DIB are black and white */
654
655 monochrome =
656 (bi->bmiColors[0].rgbRed == 0xff
657 && bi->bmiColors[0].rgbGreen == 0xff
658 && bi->bmiColors[0].rgbBlue == 0xff
659 && bi->bmiColors[0].rgbReserved == 0
660 && bi->bmiColors[1].rgbRed == 0
661 && bi->bmiColors[1].rgbGreen == 0
662 && bi->bmiColors[1].rgbBlue == 0
663 && bi->bmiColors[1].rgbReserved == 0)
664 ||
665 (bi->bmiColors[0].rgbRed == 0
666 && bi->bmiColors[0].rgbGreen == 0
667 && bi->bmiColors[0].rgbBlue == 0
668 && bi->bmiColors[0].rgbReserved == 0
669 && bi->bmiColors[1].rgbRed == 0xff
670 && bi->bmiColors[1].rgbGreen == 0xff
671 && bi->bmiColors[1].rgbBlue == 0xff
672 && bi->bmiColors[1].rgbReserved == 0);
673 }
674 }
675 else if (!monochrome)
676 {
677 monochrome = ds.dsBm.bmBitsPixel == 1;
678 }
679
680 if (monochrome)
681 {
682 res = CreateBitmap(desiredx, desiredy, 1, 1, NULL);
683 }
684 else
685 {
686 HDC screenDC = GetDC(NULL);
687 res = CreateCompatibleBitmap(screenDC, desiredx, desiredy);
688 ReleaseDC(NULL, screenDC);
689 }
690 }
691
692 if (res)
693 {
694 /* Only copy the bitmap if it's a DIB section or if it's
695 compatible to the screen */
696 BOOL copyContents;
697
698 if (objSize == sizeof(DIBSECTION))
699 {
700 copyContents = TRUE;
701 }
702 else
703 {
704 HDC screenDC = GetDC(NULL);
705 int screen_depth = GetDeviceCaps(screenDC, BITSPIXEL);
706 ReleaseDC(NULL, screenDC);
707
708 copyContents = (ds.dsBm.bmBitsPixel == 1 || ds.dsBm.bmBitsPixel == screen_depth);
709 }
710
711 if (copyContents)
712 {
713 /* The source bitmap may already be selected in a device context,
714 use GetDIBits/StretchDIBits and not StretchBlt */
715
716 HDC dc;
717 void * bits;
718
719 dc = CreateCompatibleDC(NULL);
720
721 bi->bmiHeader.biWidth = ds.dsBm.bmWidth;
722 bi->bmiHeader.biHeight = ds.dsBm.bmHeight;
723 bi->bmiHeader.biSizeImage = 0;
724 bi->bmiHeader.biClrUsed = 0;
725 bi->bmiHeader.biClrImportant = 0;
726
727 /* Fill in biSizeImage */
728 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
729 bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bi->bmiHeader.biSizeImage);
730
731 if (bits)
732 {
733 HBITMAP oldBmp;
734
735 /* Get the image bits of the source bitmap */
736 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, bits, bi, DIB_RGB_COLORS);
737
738 /* Copy it to the destination bitmap */
739 oldBmp = SelectObject(dc, res);
740 StretchDIBits(dc, 0, 0, desiredx, desiredy,
741 0, 0, ds.dsBm.bmWidth, ds.dsBm.bmHeight,
742 bits, bi, DIB_RGB_COLORS, SRCCOPY);
743 SelectObject(dc, oldBmp);
744
745 HeapFree(GetProcessHeap(), 0, bits);
746 }
747
748 DeleteDC(dc);
749 }
750
751 if (flags & LR_COPYDELETEORG)
752 {
753 DeleteObject(hnd);
754 }
755 }
756 HeapFree(GetProcessHeap(), 0, bi);
757 return (HICON)res;
758 }
759 case IMAGE_ICON:
760 {
761 static BOOL IconMsgDisplayed = FALSE;
762 /* FIXME: support loading the image as shared from an instance */
763 if (!IconMsgDisplayed)
764 {
765 DPRINT("FIXME: CopyImage doesn't support IMAGE_ICON correctly!\n");
766 IconMsgDisplayed = TRUE;
767 }
768 return CopyIcon(hnd);
769 // return CURSORICON_ExtCopy(hnd,type, desiredx, desiredy, flags);
770 }
771
772 case IMAGE_CURSOR:
773 {
774 static BOOL IconMsgDisplayed = FALSE;
775 /* FIXME: support loading the image as shared from an instance */
776 if (!IconMsgDisplayed)
777 {
778 DPRINT("FIXME: CopyImage doesn't support IMAGE_CURSOR correctly!\n");
779 IconMsgDisplayed = TRUE;
780 }
781 /* Should call CURSORICON_ExtCopy but more testing
782 * needs to be done before we change this
783 */
784 if (flags) DPRINT1("FIXME: Flags are ignored\n");
785 return CopyCursor(hnd);
786 }
787 }
788 return NULL;
789 }
790