Check for failed allocations. Spotted by Martin Bealby.
[reactos.git] / reactos / lib / user32 / windows / icon.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/icon.c
23 * PURPOSE: Icon
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 #define NDEBUG
33 #include <debug.h>
34
35
36 /* FUNCTIONS *****************************************************************/
37
38 HICON
39 ICON_CreateIconFromData(HDC hDC, PVOID ImageData, ICONIMAGE* IconImage, int cxDesired, int cyDesired, int xHotspot, int yHotspot)
40 {
41 BYTE BitmapInfoBuffer[sizeof(BITMAPINFOHEADER) + 2 * sizeof(RGBQUAD)];
42 BITMAPINFO *bwBIH = (BITMAPINFO *)BitmapInfoBuffer;
43 ICONINFO IconInfo;
44
45 IconInfo.fIcon = TRUE;
46 IconInfo.xHotspot = xHotspot;
47 IconInfo.yHotspot = yHotspot;
48
49 /* Load the XOR bitmap */
50 IconInfo.hbmColor = CreateDIBitmap(hDC, &IconImage->icHeader, CBM_INIT,
51 ImageData, (BITMAPINFO*)IconImage,
52 DIB_RGB_COLORS);
53
54 /* Make ImageData point to the start of the AND image data. */
55 ImageData = ((PBYTE)ImageData) + (((IconImage->icHeader.biWidth *
56 IconImage->icHeader.biBitCount + 31) & ~31) >> 3) *
57 (IconImage->icHeader.biHeight );
58
59 /* Create a BITMAPINFO header for the monocrome part of the icon. */
60 bwBIH->bmiHeader.biBitCount = 1;
61 bwBIH->bmiHeader.biWidth = IconImage->icHeader.biWidth;
62 bwBIH->bmiHeader.biHeight = IconImage->icHeader.biHeight;
63 bwBIH->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
64 bwBIH->bmiHeader.biPlanes = 1;
65 bwBIH->bmiHeader.biSizeImage = 0;
66 bwBIH->bmiHeader.biCompression = BI_RGB;
67 bwBIH->bmiHeader.biClrImportant = 0;
68 bwBIH->bmiHeader.biClrUsed = 0;
69 bwBIH->bmiHeader.biXPelsPerMeter = 0;
70 bwBIH->bmiHeader.biYPelsPerMeter = 0;
71
72 bwBIH->bmiColors[0].rgbBlue = 0;
73 bwBIH->bmiColors[0].rgbGreen = 0;
74 bwBIH->bmiColors[0].rgbRed = 0;
75 bwBIH->bmiColors[0].rgbReserved = 0;
76
77 bwBIH->bmiColors[1].rgbBlue = 0xff;
78 bwBIH->bmiColors[1].rgbGreen = 0xff;
79 bwBIH->bmiColors[1].rgbRed = 0xff;
80 bwBIH->bmiColors[1].rgbReserved = 0;
81
82 /* Load the AND bitmap. */
83 IconInfo.hbmMask = CreateDIBitmap(hDC, &bwBIH->bmiHeader, 0,
84 ImageData, bwBIH, DIB_RGB_COLORS);
85
86 SetDIBits(hDC, IconInfo.hbmMask, 0, IconImage->icHeader.biHeight,
87 ImageData, bwBIH, DIB_RGB_COLORS);
88
89 /* Create the icon based on everything we have so far */
90 return NtUserCreateCursorIconHandle(&IconInfo, FALSE);
91 }
92
93 HICON
94 ICON_CreateCursorFromData(HDC hDC, PVOID ImageData, ICONIMAGE* IconImage, int cxDesired, int cyDesired, int xHotspot, int yHotspot)
95 {
96 /* FIXME - color cursors */
97 BYTE BitmapInfoBuffer[sizeof(BITMAPINFOHEADER) + 2 * sizeof(RGBQUAD)];
98 BITMAPINFO *bwBIH = (BITMAPINFO *)BitmapInfoBuffer;
99 ICONINFO IconInfo;
100 PVOID XORImageData = ImageData;
101
102 IconInfo.fIcon = FALSE;
103 IconInfo.xHotspot = xHotspot;
104 IconInfo.yHotspot = yHotspot;
105
106 /* Create a BITMAPINFO header for the monocrome part of the icon */
107 bwBIH->bmiHeader.biBitCount = 1;
108 bwBIH->bmiHeader.biWidth = IconImage->icHeader.biWidth;
109 bwBIH->bmiHeader.biHeight = IconImage->icHeader.biHeight;
110 bwBIH->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
111 bwBIH->bmiHeader.biPlanes = 1;
112 bwBIH->bmiHeader.biSizeImage = 0;
113 bwBIH->bmiHeader.biCompression = BI_RGB;
114 bwBIH->bmiHeader.biClrImportant = 0;
115 bwBIH->bmiHeader.biClrUsed = 0;
116 bwBIH->bmiHeader.biXPelsPerMeter = 0;
117 bwBIH->bmiHeader.biYPelsPerMeter = 0;
118
119 bwBIH->bmiColors[0].rgbBlue = 0;
120 bwBIH->bmiColors[0].rgbGreen = 0;
121 bwBIH->bmiColors[0].rgbRed = 0;
122 bwBIH->bmiColors[0].rgbReserved = 0;
123
124 bwBIH->bmiColors[1].rgbBlue = 0xff;
125 bwBIH->bmiColors[1].rgbGreen = 0xff;
126 bwBIH->bmiColors[1].rgbRed = 0xff;
127 bwBIH->bmiColors[1].rgbReserved = 0;
128
129 /* Load the AND bitmap */
130 IconInfo.hbmMask = CreateDIBitmap(hDC, &bwBIH->bmiHeader, 0,
131 XORImageData, bwBIH, DIB_RGB_COLORS);
132 if (IconInfo.hbmMask)
133 {
134 SetDIBits(hDC, IconInfo.hbmMask, 0, IconImage->icHeader.biHeight,
135 XORImageData, bwBIH, DIB_RGB_COLORS);
136 }
137
138 IconInfo.hbmColor = (HBITMAP)0;
139
140 /* Create the icon based on everything we have so far */
141 return NtUserCreateCursorIconHandle(&IconInfo, FALSE);
142 }
143
144
145 /*
146 * @implemented
147 */
148 HICON
149 STDCALL
150 CopyIcon(
151 HICON hIcon)
152 {
153 ICONINFO IconInfo;
154
155 if(NtUserGetCursorIconInfo((HANDLE)hIcon, &IconInfo))
156 {
157 return NtUserCreateCursorIconHandle(&IconInfo, FALSE);
158 }
159 return (HICON)0;
160 }
161
162
163 /*
164 * @implemented
165 */
166 HICON
167 STDCALL
168 CreateIcon(
169 HINSTANCE hInstance,
170 int nWidth,
171 int nHeight,
172 BYTE cPlanes,
173 BYTE cBitsPixel,
174 CONST BYTE *ANDbits,
175 CONST BYTE *XORbits)
176 {
177 ICONINFO IconInfo;
178
179 IconInfo.fIcon = TRUE;
180 IconInfo.xHotspot = nWidth / 2;
181 IconInfo.yHotspot = nHeight / 2;
182 IconInfo.hbmMask = CreateBitmap(nWidth, nHeight, 1, 1, ANDbits);
183 if(!IconInfo.hbmMask)
184 {
185 return (HICON)0;
186 }
187 IconInfo.hbmColor = CreateBitmap(nWidth, nHeight, cPlanes, cBitsPixel, XORbits);
188 if(!IconInfo.hbmColor)
189 {
190 DeleteObject(IconInfo.hbmMask);
191 return (HICON)0;
192 }
193
194 return NtUserCreateCursorIconHandle(&IconInfo, FALSE);
195 }
196
197
198 /*
199 * @implemented
200 */
201 HICON
202 STDCALL
203 CreateIconFromResource(
204 PBYTE presbits,
205 DWORD dwResSize,
206 BOOL fIcon,
207 DWORD dwVer)
208 {
209 return CreateIconFromResourceEx(presbits, dwResSize, fIcon, dwVer, 0, 0, 0);
210 }
211
212
213 /*
214 * @implemented
215 */
216 HICON
217 STDCALL
218 CreateIconFromResourceEx(
219 PBYTE pbIconBits,
220 DWORD cbIconBits,
221 BOOL fIcon,
222 DWORD dwVersion,
223 int cxDesired,
224 int cyDesired,
225 UINT uFlags)
226 {
227 ICONIMAGE* SafeIconImage;
228 HICON hIcon;
229 ULONG HeaderSize;
230 ULONG ColourCount;
231 PVOID Data;
232 HDC hScreenDc;
233 WORD wXHotspot;
234 WORD wYHotspot;
235
236 /*
237 FIXME - does win support LR_SHARED? According to msdn it does but we don't
238 have useful information to identify the icon
239 if (uFlags & LR_SHARED)
240 {
241 DbgPrint("FIXME: need LR_SHARED support in CreateIconFromResourceEx()\n");
242 }
243 */
244
245 DPRINT("dwVersion, cxDesired, cyDesired are all ignored in this implementation!\n");
246
247 if (! fIcon)
248 {
249 wXHotspot = (WORD)*pbIconBits;
250 pbIconBits+=2;
251 wYHotspot = (WORD)*pbIconBits;
252 pbIconBits+=2;
253 cbIconBits-=4;
254 }
255 else
256 {
257 wXHotspot = cxDesired / 2;
258 wYHotspot = cyDesired / 2;
259 }
260
261 /* get an safe copy of the icon data */
262 SafeIconImage = RtlAllocateHeap(GetProcessHeap(), 0, cbIconBits);
263 if (SafeIconImage == NULL)
264 {
265 return NULL;
266 }
267 memcpy(SafeIconImage, pbIconBits, cbIconBits);
268
269 /* take into acount the origonal height was for both the AND and XOR images */
270 if(fIcon)
271 SafeIconImage->icHeader.biHeight /= 2;
272
273 if (SafeIconImage->icHeader.biSize == sizeof(BITMAPCOREHEADER))
274 {
275 BITMAPCOREHEADER* Core = (BITMAPCOREHEADER*)SafeIconImage;
276 ColourCount = (Core->bcBitCount <= 8) ? (1 << Core->bcBitCount) : 0;
277 HeaderSize = sizeof(BITMAPCOREHEADER) + ColourCount * sizeof(RGBTRIPLE);
278 }
279 else
280 {
281 ColourCount = (SafeIconImage->icHeader.biBitCount <= 8) ?
282 (1 << SafeIconImage->icHeader.biBitCount) : 0;
283 HeaderSize = sizeof(BITMAPINFOHEADER) + ColourCount * sizeof(RGBQUAD);
284 }
285
286 /* make data point to the start of the XOR image data */
287 Data = (PBYTE)SafeIconImage + HeaderSize;
288
289 /* get a handle to the screen dc, the icon we create is going to be compatable with this */
290 hScreenDc = CreateCompatibleDC(NULL);
291 if (hScreenDc == NULL)
292 {
293 RtlFreeHeap(GetProcessHeap(), 0, SafeIconImage);
294 return(NULL);
295 }
296
297 if(fIcon)
298 hIcon = ICON_CreateIconFromData(hScreenDc, Data, SafeIconImage, cxDesired, cyDesired, wXHotspot, wYHotspot);
299 else
300 hIcon = ICON_CreateCursorFromData(hScreenDc, Data, SafeIconImage, cxDesired, cyDesired, wXHotspot, wYHotspot);
301 RtlFreeHeap(GetProcessHeap(), 0, SafeIconImage);
302 DeleteDC(hScreenDc);
303
304 return hIcon;
305 }
306
307
308 /*
309 * @implemented
310 */
311 HICON
312 STDCALL
313 CreateIconIndirect(PICONINFO IconInfo)
314 {
315 BITMAP ColorBitmap;
316 BITMAP MaskBitmap;
317
318 if(!IconInfo)
319 {
320 SetLastError(ERROR_INVALID_PARAMETER);
321 return (HICON)0;
322 }
323
324 if(!GetObjectW(IconInfo->hbmMask, sizeof(BITMAP), &MaskBitmap))
325 {
326 return (HICON)0;
327 }
328 /* FIXME - does there really *have* to be a color bitmap? monochrome cursors don't have one */
329 if(IconInfo->hbmColor && !GetObjectW(IconInfo->hbmColor, sizeof(BITMAP), &ColorBitmap))
330 {
331 return (HICON)0;
332 }
333
334 /* FIXME - i doubt this is right (monochrome cursors */
335 /*if(ColorBitmap.bmWidth != MaskBitmap.bmWidth ||
336 ColorBitmap.bmHeight != MaskBitmap.bmWidth)
337 {
338 SetLastError(ERROR_INVALID_PARAMETER);
339 return (HICON)0;
340 }*/
341
342 return (HICON)NtUserCreateCursorIconHandle(IconInfo, TRUE);
343 }
344
345
346 /*
347 * @implemented
348 */
349 BOOL
350 STDCALL
351 DestroyIcon(
352 HICON hIcon)
353 {
354 return (BOOL)NtUserDestroyCursorIcon((HANDLE)hIcon, 0);
355 }
356
357
358 /*
359 * @implemented
360 */
361 BOOL
362 STDCALL
363 DrawIcon(
364 HDC hDC,
365 int X,
366 int Y,
367 HICON hIcon)
368 {
369 return DrawIconEx(hDC, X, Y, hIcon, 0, 0, 0, NULL, DI_NORMAL | DI_DEFAULTSIZE);
370 }
371
372 /*
373 * @implemented
374 */
375 BOOL
376 STDCALL
377 DrawIconEx(
378 HDC hdc,
379 int xLeft,
380 int yTop,
381 HICON hIcon,
382 int cxWidth,
383 int cyWidth,
384 UINT istepIfAniCur,
385 HBRUSH hbrFlickerFreeDraw,
386 UINT diFlags)
387 {
388 return (BOOL)NtUserDrawIconEx(hdc, xLeft, yTop, hIcon, cxWidth, cyWidth,
389 istepIfAniCur, hbrFlickerFreeDraw, diFlags,
390 0, 0);
391 }
392
393
394 /*
395 * @implemented
396 */
397 BOOL
398 STDCALL
399 GetIconInfo(
400 HICON hIcon,
401 PICONINFO IconInfo)
402 {
403 /* FIXME - copy bitmaps */
404 return (BOOL)NtUserGetCursorIconInfo((HANDLE)hIcon, IconInfo);
405 }
406
407
408 /*
409 * @implemented
410 */
411 HICON
412 STDCALL
413 LoadIconA(
414 HINSTANCE hInstance,
415 LPCSTR lpIconName)
416 {
417 return(LoadImageA(hInstance, lpIconName, IMAGE_ICON, 0, 0, LR_SHARED | LR_DEFAULTSIZE));
418 }
419
420
421 /*
422 * @implemented
423 */
424 HICON
425 STDCALL
426 LoadIconW(
427 HINSTANCE hInstance,
428 LPCWSTR lpIconName)
429 {
430 return(LoadImageW(hInstance, lpIconName, IMAGE_ICON, 0, 0, LR_SHARED | LR_DEFAULTSIZE));
431 }
432
433
434 /*
435 * @implemented
436 */
437 int
438 STDCALL
439 LookupIconIdFromDirectory(
440 PBYTE presbits,
441 BOOL fIcon)
442 {
443 return LookupIconIdFromDirectoryEx( presbits, fIcon,
444 fIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
445 fIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), LR_DEFAULTCOLOR );
446 }
447
448 /* Ported from WINE20030408 */
449 GRPCURSORICONDIRENTRY*
450 CURSORICON_FindBestCursor( GRPCURSORICONDIR *dir, int width, int height, int colors)
451 {
452 int i;
453 GRPCURSORICONDIRENTRY *entry, *bestEntry = NULL;
454 UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
455 UINT iTempXDiff, iTempYDiff, iTempColorDiff;
456
457 if (dir->idCount < 1)
458 {
459 DPRINT("Empty directory!\n");
460 return NULL;
461 }
462 if (dir->idCount == 1)
463 return &dir->idEntries[0]; /* No choice... */
464
465 /* Find Best Fit */
466 iTotalDiff = 0xFFFFFFFF;
467 iColorDiff = 0xFFFFFFFF;
468 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
469 {
470 iTempXDiff = abs(width - entry->ResInfo.icon.bWidth);
471 iTempYDiff = abs(height - entry->ResInfo.icon.bHeight);
472
473 if(iTotalDiff > (iTempXDiff + iTempYDiff))
474 {
475 iXDiff = iTempXDiff;
476 iYDiff = iTempYDiff;
477 iTotalDiff = iXDiff + iYDiff;
478 }
479 }
480
481 /* Find Best Colors for Best Fit */
482 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
483 {
484 if(abs(width - entry->ResInfo.icon.bWidth) == (int) iXDiff &&
485 abs(height - entry->ResInfo.icon.bHeight) == (int) iYDiff)
486 {
487 iTempColorDiff = abs(colors - entry->ResInfo.icon.bColorCount);
488
489 if(iColorDiff > iTempColorDiff)
490 {
491 bestEntry = entry;
492 iColorDiff = iTempColorDiff;
493 }
494 }
495 }
496
497 return bestEntry;
498 }
499
500 /* Ported from WINE20030408 */
501 GRPCURSORICONDIRENTRY*
502 CURSORICON_FindBestIcon( GRPCURSORICONDIR *dir, int width, int height, int colorbits)
503 {
504 int i;
505 GRPCURSORICONDIRENTRY *entry, *bestEntry = NULL;
506 UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
507 UINT iTempXDiff, iTempYDiff, iTempColorDiff;
508
509 if (dir->idCount < 1)
510 {
511 DPRINT("Empty directory!\n");
512 return NULL;
513 }
514 if (dir->idCount == 1)
515 return &dir->idEntries[0]; /* No choice... */
516
517 /* Find Best Fit */
518 iTotalDiff = 0xFFFFFFFF;
519 iColorDiff = 0xFFFFFFFF;
520 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
521 {
522 iTempXDiff = abs(width - entry->ResInfo.icon.bWidth);
523
524 iTempYDiff = abs(height - entry->ResInfo.icon.bHeight);
525
526 if(iTotalDiff > (iTempXDiff + iTempYDiff))
527 {
528 iXDiff = iTempXDiff;
529 iYDiff = iTempYDiff;
530 iTotalDiff = iXDiff + iYDiff;
531 }
532 }
533
534 /* Find Best Colors for Best Fit */
535 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
536 {
537 if(abs(width - entry->ResInfo.icon.bWidth) == (int) iXDiff &&
538 abs(height - entry->ResInfo.icon.bHeight) == (int) iYDiff)
539 {
540 iTempColorDiff = abs(colorbits - entry->wBitCount);
541 if(iColorDiff > iTempColorDiff)
542 {
543 bestEntry = entry;
544 iColorDiff = iTempColorDiff;
545 }
546 }
547 }
548
549 return bestEntry;
550 }
551
552 /* Ported from WINE20030408 */
553 /*
554 * @implemented
555 */
556 INT STDCALL
557 LookupIconIdFromDirectoryEx(
558 PBYTE presbits,
559 BOOL fIcon,
560 int cxDesired,
561 int cyDesired,
562 UINT Flags)
563 {
564 GRPCURSORICONDIR *dir = (GRPCURSORICONDIR*)presbits;
565 UINT retVal = 0;
566
567 if (dir && !dir->idReserved && (IMAGE_ICON == dir->idType || IMAGE_CURSOR == dir->idType))
568 {
569 GRPCURSORICONDIRENTRY *entry;
570 HDC hdc;
571 int ColorBits;
572
573 hdc = CreateICW(NULL, NULL, NULL, NULL);
574 if (Flags & LR_MONOCHROME)
575 {
576 ColorBits = 1;
577 }
578 else
579 {
580 ColorBits = GetDeviceCaps(hdc, BITSPIXEL);
581 if (ColorBits > 8)
582 ColorBits = 8;
583 }
584 DeleteDC(hdc);
585
586 entry = CURSORICON_FindBestIcon( dir, cxDesired, cyDesired, ColorBits );
587
588 if (entry)
589 retVal = entry->nID;
590 }
591 else
592 {
593 DbgPrint("invalid resource directory\n");
594 }
595 return retVal;
596 }