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