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