Check for failed allocations and fix some resource leaks.
[reactos.git] / reactos / lib / 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 /*forward declerations... actualy in user32\windows\icon.c but usful here****/
34 HICON ICON_CreateCursorFromData(HDC hDC, PVOID ImageData, ICONIMAGE* IconImage, int cxDesired, int cyDesired, int xHotspot, int yHotspot);
35 HICON ICON_CreateIconFromData(HDC hDC, PVOID ImageData, ICONIMAGE* IconImage, int cxDesired, int cyDesired, int xHotspot, int yHotspot);
36 CURSORICONDIRENTRY *CURSORICON_FindBestIcon( CURSORICONDIR *dir, int width, int height, int colors);
37 CURSORICONDIRENTRY *CURSORICON_FindBestCursor( CURSORICONDIR *dir, int width, int height, int colors);
38
39 /* FUNCTIONS *****************************************************************/
40
41 /*
42 * @implemented
43 */
44 HANDLE STDCALL
45 LoadImageA(HINSTANCE hinst,
46 LPCSTR lpszName,
47 UINT uType,
48 int cxDesired,
49 int cyDesired,
50 UINT fuLoad)
51 {
52 LPWSTR lpszWName;
53 HANDLE Handle;
54 UNICODE_STRING NameString;
55
56 if (HIWORD(lpszName))
57 {
58 RtlCreateUnicodeStringFromAsciiz(&NameString, (LPSTR)lpszName);
59 lpszWName = NameString.Buffer;
60 Handle = LoadImageW(hinst, lpszWName, uType, cxDesired,
61 cyDesired, fuLoad);
62 RtlFreeUnicodeString(&NameString);
63 }
64 else
65 {
66 Handle = LoadImageW(hinst, (LPCWSTR)lpszName, uType, cxDesired,
67 cyDesired, fuLoad);
68 }
69 return(Handle);
70 }
71
72
73 static HANDLE
74 LoadCursorImage(HINSTANCE hinst, LPCWSTR lpszName, UINT fuLoad)
75 {
76 HANDLE hResource;
77 HANDLE h2Resource;
78 HANDLE hfRes;
79 HANDLE hFile;
80 HANDLE hSection;
81 CURSORICONDIR *IconDIR;
82 HDC hScreenDc;
83 HANDLE hIcon;
84 ULONG HeaderSize;
85 ULONG ColorCount;
86 PVOID Data;
87 CURSORICONDIRENTRY* dirEntry;
88 ICONIMAGE* SafeIconImage;
89 GRPCURSORICONDIR* IconResDir;
90 INT id;
91 ICONIMAGE *ResIcon;
92 UINT ColorBits;
93
94 if (!(fuLoad & LR_LOADFROMFILE))
95 {
96 if (hinst == NULL)
97 {
98 hinst = GetModuleHandleW(L"USER32");
99 }
100 hResource = hfRes = FindResourceW(hinst, lpszName, RT_GROUP_CURSOR);
101 if (hResource == NULL)
102 {
103 return NULL;
104 }
105
106 if (fuLoad & LR_SHARED)
107 {
108 /* FIXME - pass size! */
109 hIcon = (HANDLE)NtUserFindExistingCursorIcon(hinst, (HRSRC)hfRes, 0, 0);
110 if (hIcon)
111 {
112 return hIcon;
113 }
114 }
115
116 hResource = LoadResource(hinst, hResource);
117 if (hResource == NULL)
118 {
119 return NULL;
120 }
121 IconResDir = LockResource(hResource);
122 if (IconResDir == NULL)
123 {
124 return NULL;
125 }
126
127 /* Find the best fitting in the IconResDir for this resolution. */
128 id = LookupIconIdFromDirectoryEx((PBYTE)IconResDir, TRUE,
129 32, 32, fuLoad & (LR_DEFAULTCOLOR | LR_MONOCHROME));
130
131 h2Resource = FindResourceW(hinst, MAKEINTRESOURCEW(id),
132 MAKEINTRESOURCEW(RT_CURSOR));
133
134 hResource = LoadResource(hinst, h2Resource);
135 if (hResource == NULL)
136 {
137 return NULL;
138 }
139
140 ResIcon = LockResource(hResource);
141 if (ResIcon == NULL)
142 {
143 return NULL;
144 }
145
146 hIcon = (HANDLE)CreateIconFromResourceEx((PBYTE)ResIcon,
147 SizeofResource(hinst, h2Resource), FALSE, 0x00030000,
148 32, 32, fuLoad & (LR_DEFAULTCOLOR | LR_MONOCHROME));
149 if (hIcon && 0 != (fuLoad & LR_SHARED))
150 {
151 NtUserSetCursorIconData((HICON)hIcon, NULL, NULL, hinst, (HRSRC)hfRes,
152 (HRSRC)NULL);
153 }
154
155 return hIcon;
156 }
157
158 if (fuLoad & LR_SHARED)
159 {
160 DbgPrint("FIXME: need LR_SHARED support loading cursor images from files\n");
161 }
162
163 hFile = CreateFileW(lpszName, GENERIC_READ, FILE_SHARE_READ, NULL,
164 OPEN_EXISTING, 0, NULL);
165 if (hFile == NULL)
166 {
167 return NULL;
168 }
169
170 hSection = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
171 CloseHandle(hFile);
172 if (hSection == NULL)
173 {
174 return NULL;
175 }
176
177 IconDIR = MapViewOfFile(hSection, FILE_MAP_READ, 0, 0, 0);
178 CloseHandle(hSection);
179 if (IconDIR == NULL)
180 {
181 return NULL;
182 }
183
184 if (0 != IconDIR->idReserved ||
185 (IMAGE_ICON != IconDIR->idType && IMAGE_CURSOR != IconDIR->idType))
186 {
187 UnmapViewOfFile(IconDIR);
188 return NULL;
189 }
190
191 /*
192 * Get a handle to the screen dc, the icon we create is going to be
193 * compatable with it.
194 */
195 hScreenDc = CreateCompatibleDC(0);
196 if (hScreenDc == NULL)
197 {
198 UnmapViewOfFile(IconDIR);
199 return NULL;
200 }
201
202 if (fuLoad & LR_MONOCHROME)
203 {
204 ColorBits = 1;
205 }
206 else
207 {
208 ColorBits = GetDeviceCaps(hScreenDc, BITSPIXEL);
209 /*
210 * FIXME:
211 * Remove this after proper support for alpha icons will be finished.
212 */
213 if (ColorBits > 8)
214 ColorBits = 8;
215 }
216
217 /* Pick the best size. */
218 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon(IconDIR, 32, 32, ColorBits);
219 if (!dirEntry)
220 {
221 UnmapViewOfFile(IconDIR);
222 return NULL;
223 }
224
225 SafeIconImage = RtlAllocateHeap(GetProcessHeap(), 0, dirEntry->dwBytesInRes);
226 if (SafeIconImage == NULL)
227 {
228 UnmapViewOfFile(IconDIR);
229 return NULL;
230 }
231 memcpy(SafeIconImage, ((PBYTE)IconDIR) + dirEntry->dwImageOffset, dirEntry->dwBytesInRes);
232 UnmapViewOfFile(IconDIR);
233
234 /* at this point we have a copy of the icon image to play with */
235
236 SafeIconImage->icHeader.biHeight = SafeIconImage->icHeader.biHeight /2;
237
238 if (SafeIconImage->icHeader.biSize == sizeof(BITMAPCOREHEADER))
239 {
240 BITMAPCOREHEADER* Core = (BITMAPCOREHEADER*)SafeIconImage;
241 ColorCount = (Core->bcBitCount <= 8) ? (1 << Core->bcBitCount) : 0;
242 HeaderSize = sizeof(BITMAPCOREHEADER) + ColorCount * sizeof(RGBTRIPLE);
243 }
244 else
245 {
246 ColorCount = SafeIconImage->icHeader.biClrUsed;
247 if (ColorCount == 0 && SafeIconImage->icHeader.biBitCount <= 8)
248 {
249 ColorCount = 1 << SafeIconImage->icHeader.biBitCount;
250 }
251 HeaderSize = sizeof(BITMAPINFOHEADER) + ColorCount * sizeof(RGBQUAD);
252 }
253
254 /* make data point to the start of the XOR image data */
255 Data = (PBYTE)SafeIconImage + HeaderSize;
256
257 hIcon = ICON_CreateCursorFromData(hScreenDc, Data, SafeIconImage, 32, 32, dirEntry->Info.cursor.wXHotspot, dirEntry->Info.cursor.wYHotspot);
258 DeleteDC(hScreenDc);
259 RtlFreeHeap(GetProcessHeap(), 0, SafeIconImage);
260 return hIcon;
261 }
262
263
264 static HANDLE
265 LoadIconImage(HINSTANCE hinst, LPCWSTR lpszName, INT width, INT height, UINT fuLoad)
266 {
267 HANDLE hResource;
268 HANDLE h2Resource;
269 HANDLE hfRes;
270 HANDLE hFile;
271 HANDLE hSection;
272 CURSORICONDIR* IconDIR;
273 HDC hScreenDc;
274 HANDLE hIcon;
275 ULONG HeaderSize;
276 ULONG ColorCount;
277 PVOID Data;
278 CURSORICONDIRENTRY* dirEntry;
279 ICONIMAGE* SafeIconImage;
280 GRPCURSORICONDIR* IconResDir;
281 INT id;
282 ICONIMAGE *ResIcon;
283
284 if (!(fuLoad & LR_LOADFROMFILE))
285 {
286 if (hinst == NULL)
287 {
288 hinst = GetModuleHandleW(L"USER32");
289 }
290 hResource = hfRes = FindResourceW(hinst, lpszName, RT_GROUP_ICON);
291 if (hResource == NULL)
292 {
293 return(NULL);
294 }
295
296 if (fuLoad & LR_SHARED)
297 {
298 hIcon = NtUserFindExistingCursorIcon(hinst, (HRSRC)hfRes, width, height);
299 if(hIcon)
300 return hIcon;
301 }
302
303 hResource = LoadResource(hinst, hResource);
304 if (hResource == NULL)
305 {
306 return(NULL);
307 }
308 IconResDir = LockResource(hResource);
309 if (IconResDir == NULL)
310 {
311 return(NULL);
312 }
313
314 //find the best fitting in the IconResDir for this resolution
315 id = LookupIconIdFromDirectoryEx((PBYTE) IconResDir, TRUE,
316 width, height, fuLoad & (LR_DEFAULTCOLOR | LR_MONOCHROME));
317
318 h2Resource = FindResourceW(hinst,
319 MAKEINTRESOURCEW(id),
320 MAKEINTRESOURCEW(RT_ICON));
321
322 hResource = LoadResource(hinst, h2Resource);
323 if (hResource == NULL)
324 {
325 return(NULL);
326 }
327
328 ResIcon = LockResource(hResource);
329 if (ResIcon == NULL)
330 {
331 return(NULL);
332 }
333 hIcon = (HANDLE)CreateIconFromResourceEx((PBYTE) ResIcon,
334 SizeofResource(hinst, h2Resource), TRUE, 0x00030000,
335 width, height, fuLoad & (LR_DEFAULTCOLOR | LR_MONOCHROME));
336 if (hIcon && 0 != (fuLoad & LR_SHARED))
337 {
338 NtUserSetCursorIconData((HICON)hIcon, NULL, NULL, hinst, (HRSRC)hfRes,
339 (HRSRC)NULL);
340 }
341 return hIcon;
342 }
343 else
344 {
345 /*
346 * FIXME: This code is incorrect and is likely to crash in many cases.
347 * In the file the cursor/icon directory records are stored like
348 * CURSORICONFILEDIR, but we treat them like CURSORICONDIR. In Wine
349 * this is solved by creating a fake cursor/icon directory in memory
350 * and passing that to CURSORICON_FindBestIcon.
351 */
352
353 if (fuLoad & LR_SHARED)
354 {
355 DbgPrint("FIXME: need LR_SHARED support for loading icon images from files\n");
356 }
357
358 hFile = CreateFileW(lpszName,
359 GENERIC_READ,
360 FILE_SHARE_READ,
361 NULL,
362 OPEN_EXISTING,
363 0,
364 NULL);
365 if (hFile == NULL)
366 {
367 return NULL;
368 }
369
370 hSection = CreateFileMappingW(hFile,
371 NULL,
372 PAGE_READONLY,
373 0,
374 0,
375 NULL);
376
377 CloseHandle(hFile);
378 if (hSection == NULL)
379 {
380 return NULL;
381 }
382
383 IconDIR = MapViewOfFile(hSection,
384 FILE_MAP_READ,
385 0,
386 0,
387 0);
388 CloseHandle(hSection);
389 if (IconDIR == NULL)
390 {
391 return NULL;
392 }
393
394 if (0 != IconDIR->idReserved ||
395 (IMAGE_ICON != IconDIR->idType && IMAGE_CURSOR != IconDIR->idType))
396 {
397 UnmapViewOfFile(IconDIR);
398 return NULL;
399 }
400
401 //pick the best size.
402 dirEntry = (CURSORICONDIRENTRY *) CURSORICON_FindBestIcon( IconDIR, width, height, 1);
403 if (!dirEntry)
404 {
405 UnmapViewOfFile(IconDIR);
406 return NULL;
407 }
408
409 SafeIconImage = RtlAllocateHeap(GetProcessHeap(), 0, dirEntry->dwBytesInRes);
410
411 memcpy(SafeIconImage, ((PBYTE)IconDIR) + dirEntry->dwImageOffset, dirEntry->dwBytesInRes);
412 UnmapViewOfFile(IconDIR);
413 }
414
415 //at this point we have a copy of the icon image to play with
416
417 SafeIconImage->icHeader.biHeight = SafeIconImage->icHeader.biHeight /2;
418
419 if (SafeIconImage->icHeader.biSize == sizeof(BITMAPCOREHEADER))
420 {
421 BITMAPCOREHEADER* Core = (BITMAPCOREHEADER*)SafeIconImage;
422 ColorCount = (Core->bcBitCount <= 8) ? (1 << Core->bcBitCount) : 0;
423 HeaderSize = sizeof(BITMAPCOREHEADER) + ColorCount * sizeof(RGBTRIPLE);
424 }
425 else
426 {
427 ColorCount = SafeIconImage->icHeader.biClrUsed;
428 if (ColorCount == 0 && SafeIconImage->icHeader.biBitCount <= 8)
429 {
430 ColorCount = 1 << SafeIconImage->icHeader.biBitCount;
431 }
432 HeaderSize = sizeof(BITMAPINFOHEADER) + ColorCount * sizeof(RGBQUAD);
433 }
434
435 //make data point to the start of the XOR image data
436 Data = (PBYTE)SafeIconImage + HeaderSize;
437
438
439 //get a handle to the screen dc, the icon we create is going to be compatable with this
440 hScreenDc = CreateDCW(L"DISPLAY", NULL, NULL, NULL);
441 if (hScreenDc == NULL)
442 {
443 if (fuLoad & LR_LOADFROMFILE)
444 {
445 RtlFreeHeap(GetProcessHeap(), 0, SafeIconImage);
446 }
447 return(NULL);
448 }
449
450 hIcon = ICON_CreateIconFromData(hScreenDc, Data, SafeIconImage, width, height, width/2, height/2);
451 RtlFreeHeap(GetProcessHeap(), 0, SafeIconImage);
452 return hIcon;
453 }
454
455
456 static HANDLE
457 LoadBitmapImage(HINSTANCE hInstance, LPCWSTR lpszName, UINT fuLoad)
458 {
459 HANDLE hResource;
460 HANDLE hFile;
461 HANDLE hSection;
462 BITMAPINFO* BitmapInfo;
463 BITMAPINFO* PrivateInfo;
464 HDC hScreenDc;
465 HANDLE hBitmap;
466 ULONG HeaderSize;
467 ULONG ColorCount;
468 PVOID Data;
469
470 if (!(fuLoad & LR_LOADFROMFILE))
471 {
472 if (hInstance == NULL)
473 {
474 hInstance = GetModuleHandleW(L"USER32");
475 }
476 hResource = FindResourceW(hInstance, lpszName, RT_BITMAP);
477 if (hResource == NULL)
478 {
479 return(NULL);
480 }
481 hResource = LoadResource(hInstance, hResource);
482 if (hResource == NULL)
483 {
484 return(NULL);
485 }
486 BitmapInfo = LockResource(hResource);
487 if (BitmapInfo == NULL)
488 {
489 return(NULL);
490 }
491 }
492 else
493 {
494 hFile = CreateFileW(lpszName,
495 GENERIC_READ,
496 FILE_SHARE_READ,
497 NULL,
498 OPEN_EXISTING,
499 0,
500 NULL);
501 if (hFile == NULL)
502 {
503 return(NULL);
504 }
505 hSection = CreateFileMappingW(hFile,
506 NULL,
507 PAGE_READONLY,
508 0,
509 0,
510 NULL);
511 CloseHandle(hFile);
512 if (hSection == NULL)
513 {
514 return(NULL);
515 }
516 BitmapInfo = MapViewOfFile(hSection,
517 FILE_MAP_READ,
518 0,
519 0,
520 0);
521 CloseHandle(hSection);
522 if (BitmapInfo == NULL)
523 {
524 return(NULL);
525 }
526 /* offset BitmapInfo by 14 bytes to acount for the size of BITMAPFILEHEADER
527 unfortunatly sizeof(BITMAPFILEHEADER) = 16, but the acutal size should be 14!
528 */
529 BitmapInfo = (BITMAPINFO*)(((PBYTE)BitmapInfo) + 14);
530 }
531
532 if (BitmapInfo->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
533 {
534 BITMAPCOREHEADER* Core = (BITMAPCOREHEADER*)BitmapInfo;
535 ColorCount = (Core->bcBitCount <= 8) ? (1 << Core->bcBitCount) : 0;
536 HeaderSize = sizeof(BITMAPCOREHEADER) + ColorCount * sizeof(RGBTRIPLE);
537 }
538 else
539 {
540 ColorCount = BitmapInfo->bmiHeader.biClrUsed;
541 if (ColorCount == 0 && BitmapInfo->bmiHeader.biBitCount <= 8)
542 {
543 ColorCount = 1 << BitmapInfo->bmiHeader.biBitCount;
544 }
545 HeaderSize = sizeof(BITMAPINFOHEADER) + ColorCount * sizeof(RGBQUAD);
546 }
547 Data = (PVOID)((ULONG_PTR)BitmapInfo + HeaderSize);
548
549 PrivateInfo = RtlAllocateHeap(GetProcessHeap(), 0, HeaderSize);
550 if (PrivateInfo == NULL)
551 {
552 if (fuLoad & LR_LOADFROMFILE)
553 {
554 UnmapViewOfFile(BitmapInfo);
555 }
556 return(NULL);
557 }
558 memcpy(PrivateInfo, BitmapInfo, HeaderSize);
559
560 /* FIXME: Handle color conversion and transparency. */
561
562 hScreenDc = CreateCompatibleDC(NULL);
563 if (hScreenDc == NULL)
564 {
565 RtlFreeHeap(GetProcessHeap(), 0, PrivateInfo);
566 if (fuLoad & LR_LOADFROMFILE)
567 {
568 UnmapViewOfFile(BitmapInfo);
569 }
570 return(NULL);
571 }
572
573 if (fuLoad & LR_CREATEDIBSECTION)
574 {
575 DIBSECTION Dib;
576
577 hBitmap = CreateDIBSection(hScreenDc, PrivateInfo, DIB_RGB_COLORS, NULL,
578 0, 0);
579 GetObjectA(hBitmap, sizeof(DIBSECTION), &Dib);
580 SetDIBits(hScreenDc, hBitmap, 0, Dib.dsBm.bmHeight, Data, BitmapInfo,
581 DIB_RGB_COLORS);
582 }
583 else
584 {
585 hBitmap = CreateDIBitmap(hScreenDc, &PrivateInfo->bmiHeader, CBM_INIT,
586 Data, PrivateInfo, DIB_RGB_COLORS);
587 }
588
589 RtlFreeHeap(GetProcessHeap(), 0, PrivateInfo);
590 DeleteDC(hScreenDc);
591 if (fuLoad & LR_LOADFROMFILE)
592 {
593 UnmapViewOfFile(BitmapInfo);
594 }
595 return(hBitmap);
596 }
597
598 HANDLE STDCALL
599 LoadImageW(HINSTANCE hinst,
600 LPCWSTR lpszName,
601 UINT uType,
602 int cxDesired,
603 int cyDesired,
604 UINT fuLoad)
605 {
606 if (fuLoad & LR_DEFAULTSIZE)
607 {
608 if (uType == IMAGE_ICON)
609 {
610 if (cxDesired == 0)
611 {
612 cxDesired = GetSystemMetrics(SM_CXICON);
613 }
614 if (cyDesired == 0)
615 {
616 cyDesired = GetSystemMetrics(SM_CYICON);
617 }
618 }
619 else if (uType == IMAGE_CURSOR)
620 {
621 if (cxDesired == 0)
622 {
623 cxDesired = GetSystemMetrics(SM_CXCURSOR);
624 }
625 if (cyDesired == 0)
626 {
627 cyDesired = GetSystemMetrics(SM_CYCURSOR);
628 }
629 }
630 }
631
632 switch (uType)
633 {
634 case IMAGE_BITMAP:
635 {
636 return(LoadBitmapImage(hinst, lpszName, fuLoad));
637 }
638 case IMAGE_CURSOR:
639 {
640 return(LoadCursorImage(hinst, lpszName, fuLoad));
641 }
642 case IMAGE_ICON:
643 {
644 return(LoadIconImage(hinst, lpszName, cxDesired, cyDesired, fuLoad));
645 }
646 default:
647 DbgBreakPoint();
648 break;
649 }
650 return(NULL);
651 }
652
653
654 /*
655 * @implemented
656 */
657 HBITMAP STDCALL
658 LoadBitmapA(HINSTANCE hInstance, LPCSTR lpBitmapName)
659 {
660 return(LoadImageA(hInstance, lpBitmapName, IMAGE_BITMAP, 0, 0, 0));
661 }
662
663
664 /*
665 * @implemented
666 */
667 HBITMAP STDCALL
668 LoadBitmapW(HINSTANCE hInstance, LPCWSTR lpBitmapName)
669 {
670 return(LoadImageW(hInstance, lpBitmapName, IMAGE_BITMAP, 0, 0, 0));
671 }
672
673
674 /*
675 * @unimplemented
676 */
677 HANDLE WINAPI
678 CopyImage(HANDLE hnd, UINT type, INT desiredx, INT desiredy, UINT flags)
679 {
680 HBITMAP res;
681 BITMAP bm;
682
683 switch (type)
684 {
685 case IMAGE_BITMAP:
686 {
687 DbgPrint("WARNING: Incomplete implementation of CopyImage!\n");
688 /* FIXME: support flags LR_COPYDELETEORG, LR_COPYFROMRESOURCE,
689 LR_COPYRETURNORG, LR_CREATEDIBSECTION,
690 and LR_MONOCHROME; */
691
692 if (!GetObjectW(hnd, sizeof(bm), &bm)) return 0;
693 bm.bmBits = NULL;
694 if ((res = CreateBitmapIndirect(&bm)))
695 {
696 char *buf = HeapAlloc(GetProcessHeap(), 0, bm.bmWidthBytes * bm.bmHeight);
697 if (buf == NULL)
698 {
699 DeleteObject(res);
700 return NULL;
701 }
702 GetBitmapBits(hnd, bm.bmWidthBytes * bm.bmHeight, buf);
703 SetBitmapBits(res, bm.bmWidthBytes * bm.bmHeight, buf);
704 HeapFree(GetProcessHeap(), 0, buf);
705 }
706 return res;
707 }
708 case IMAGE_ICON:
709 {
710 static BOOL IconMsgDisplayed = FALSE;
711 /* FIXME: support loading the image as shared from an instance */
712 if (!IconMsgDisplayed) {
713 DbgPrint("FIXME: CopyImage doesn't support IMAGE_ICON correctly!\n");
714 IconMsgDisplayed = TRUE;
715 }
716 return CopyIcon(hnd);
717 }
718 case IMAGE_CURSOR:
719 {
720 static BOOL IconMsgDisplayed = FALSE;
721 /* FIXME: support loading the image as shared from an instance */
722 if (!IconMsgDisplayed) {
723 DbgPrint("FIXME: CopyImage doesn't support IMAGE_CURSOR correctly!\n");
724 IconMsgDisplayed = TRUE;
725 }
726 return CopyCursor(hnd);
727 }
728 }
729 return 0;
730 }