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