[WIN32SS/USER]
[reactos.git] / reactos / win32ss / user / user32 / windows / cursoricon_new.c
1 /*
2 * PROJECT: ReactOS user32.dll
3 * COPYRIGHT: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/user32/windows/class.c
5 * PURPOSE: Window classes
6 * PROGRAMMER: Jérôme Gardou (jerome.gardou@reactos.org)
7 */
8
9 #include <user32.h>
10
11 #include <wine/debug.h>
12
13 WINE_DEFAULT_DEBUG_CHANNEL(cursor);
14 WINE_DECLARE_DEBUG_CHANNEL(icon);
15 //WINE_DECLARE_DEBUG_CHANNEL(resource);
16
17 /************* USER32 INTERNAL FUNCTIONS **********/
18
19 /* This callback routine is called directly after switching to gui mode */
20 NTSTATUS
21 WINAPI
22 User32SetupDefaultCursors(PVOID Arguments,
23 ULONG ArgumentLength)
24 {
25 BOOL *DefaultCursor = (BOOL*)Arguments;
26 HCURSOR hCursor;
27
28 if(*DefaultCursor)
29 {
30 /* set default cursor */
31 hCursor = LoadCursorW(0, (LPCWSTR)IDC_ARROW);
32 SetCursor(hCursor);
33 }
34 else
35 {
36 /* FIXME load system cursor scheme */
37 SetCursor(0);
38 hCursor = LoadCursorW(0, (LPCWSTR)IDC_ARROW);
39 SetCursor(hCursor);
40 }
41
42 return(ZwCallbackReturn(&hCursor, sizeof(HCURSOR), STATUS_SUCCESS));
43 }
44
45 BOOL get_icon_size(HICON hIcon, SIZE *size)
46 {
47 return NtUserGetIconSize(hIcon, 0, &size->cx, &size->cy);
48 }
49
50 HCURSOR CursorIconToCursor(HICON hIcon, BOOL SemiTransparent)
51 {
52 UNIMPLEMENTED;
53 return NULL;
54 }
55
56 /************* IMPLEMENTATION HELPERS ******************/
57
58 static const WCHAR DISPLAYW[] = L"DISPLAY";
59
60 static void *map_fileW( LPCWSTR name, LPDWORD filesize )
61 {
62 HANDLE hFile, hMapping;
63 LPVOID ptr = NULL;
64
65 hFile = CreateFileW( name, GENERIC_READ, FILE_SHARE_READ, NULL,
66 OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, 0 );
67 if (hFile != INVALID_HANDLE_VALUE)
68 {
69 hMapping = CreateFileMappingW( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
70 if (hMapping)
71 {
72 ptr = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 );
73 CloseHandle( hMapping );
74 if (filesize)
75 *filesize = GetFileSize( hFile, NULL );
76 }
77 CloseHandle( hFile );
78 }
79 return ptr;
80 }
81
82 static int get_dib_image_size( int width, int height, int depth )
83 {
84 return (((width * depth + 31) / 8) & ~3) * abs( height );
85 }
86
87 static BOOL is_dib_monochrome( const BITMAPINFO* info )
88 {
89 if (info->bmiHeader.biBitCount != 1) return FALSE;
90
91 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
92 {
93 const RGBTRIPLE *rgb = ((const BITMAPCOREINFO*)info)->bmciColors;
94
95 /* Check if the first color is black */
96 if ((rgb->rgbtRed == 0) && (rgb->rgbtGreen == 0) && (rgb->rgbtBlue == 0))
97 {
98 rgb++;
99
100 /* Check if the second color is white */
101 return ((rgb->rgbtRed == 0xff) && (rgb->rgbtGreen == 0xff)
102 && (rgb->rgbtBlue == 0xff));
103 }
104 else return FALSE;
105 }
106 else /* assume BITMAPINFOHEADER */
107 {
108 const RGBQUAD *rgb = info->bmiColors;
109
110 /* Check if the first color is black */
111 if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) &&
112 (rgb->rgbBlue == 0) && (rgb->rgbReserved == 0))
113 {
114 rgb++;
115
116 /* Check if the second color is white */
117 return ((rgb->rgbRed == 0xff) && (rgb->rgbGreen == 0xff)
118 && (rgb->rgbBlue == 0xff) && (rgb->rgbReserved == 0));
119 }
120 else return FALSE;
121 }
122 }
123
124 static int bitmap_info_size( const BITMAPINFO * info, WORD coloruse )
125 {
126 unsigned int colors, size, masks = 0;
127
128 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
129 {
130 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
131 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
132 return sizeof(BITMAPCOREHEADER) + colors *
133 ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
134 }
135 else /* assume BITMAPINFOHEADER */
136 {
137 colors = info->bmiHeader.biClrUsed;
138 if (colors > 256) /* buffer overflow otherwise */
139 colors = 256;
140 if (!colors && (info->bmiHeader.biBitCount <= 8))
141 colors = 1 << info->bmiHeader.biBitCount;
142 if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
143 size = max( info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) );
144 return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
145 }
146 }
147
148 static int DIB_GetBitmapInfo( const BITMAPINFOHEADER *header, LONG *width,
149 LONG *height, WORD *bpp, DWORD *compr )
150 {
151 if (header->biSize == sizeof(BITMAPCOREHEADER))
152 {
153 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)header;
154 *width = core->bcWidth;
155 *height = core->bcHeight;
156 *bpp = core->bcBitCount;
157 *compr = 0;
158 return 0;
159 }
160 else if (header->biSize == sizeof(BITMAPINFOHEADER) ||
161 header->biSize == sizeof(BITMAPV4HEADER) ||
162 header->biSize == sizeof(BITMAPV5HEADER))
163 {
164 *width = header->biWidth;
165 *height = header->biHeight;
166 *bpp = header->biBitCount;
167 *compr = header->biCompression;
168 return 1;
169 }
170 ERR("(%d): unknown/wrong size for header\n", header->biSize );
171 return -1;
172 }
173
174 /************* IMPLEMENTATION CORE ****************/
175
176 static BOOL CURSORICON_GetIconInfoFromBMI(
177 _Inout_ ICONINFO* pii,
178 _In_ const BITMAPINFO *pbmi,
179 _In_ int cxDesired,
180 _In_ int cyDesired
181 )
182 {
183 UINT ubmiSize = bitmap_info_size(pbmi, DIB_RGB_COLORS);
184 BOOL monochrome = is_dib_monochrome(pbmi);
185 LONG width, height;
186 WORD bpp;
187 DWORD compr;
188 int ibmpType;
189 HDC hdc, hdcScreen;
190 BITMAPINFO* pbmiCopy;
191 HBITMAP hbmpOld = NULL;
192 BOOL bResult = FALSE;
193 const VOID *pvColor, *pvMask;
194
195 ibmpType = DIB_GetBitmapInfo(&pbmi->bmiHeader, &width, &height, &bpp, &compr);
196 /* Invalid data */
197 if(ibmpType < 0)
198 return FALSE;
199
200 /* No compression for icons */
201 if(compr != BI_RGB)
202 return FALSE;
203
204 /* Fix the hotspot coords */
205 if(!pii->fIcon)
206 {
207 if(cxDesired != pbmi->bmiHeader.biWidth)
208 pii->xHotspot = (pii->xHotspot * cxDesired) / pbmi->bmiHeader.biWidth;
209 if(cxDesired != (pbmi->bmiHeader.biHeight/2))
210 pii->yHotspot = (pii->yHotspot * cyDesired * 2) / pbmi->bmiHeader.biHeight;
211 }
212
213 hdcScreen = CreateDCW(DISPLAYW, NULL, NULL, NULL);
214 if(!hdcScreen)
215 return FALSE;
216 hdc = CreateCompatibleDC(hdcScreen);
217 if(!hdc)
218 {
219 DeleteDC(hdcScreen);
220 return FALSE;
221 }
222
223 pbmiCopy = HeapAlloc(GetProcessHeap(), 0, max(ubmiSize, FIELD_OFFSET(BITMAPINFO, bmiColors[3])));
224 if(!pbmiCopy)
225 goto done;
226 RtlCopyMemory(pbmiCopy, pbmi, ubmiSize);
227
228 /* In an icon/cursor, the BITMAPINFO holds twice the height */
229 if(pbmiCopy->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
230 ((BITMAPCOREHEADER*)&pbmiCopy->bmiHeader)->bcHeight /= 2;
231 else
232 pbmiCopy->bmiHeader.biHeight /= 2;
233
234 pvColor = (const char*)pbmi + ubmiSize;
235 pvMask = (const char*)pvColor +
236 get_dib_image_size(pbmi->bmiHeader.biWidth, pbmiCopy->bmiHeader.biHeight, pbmi->bmiHeader.biBitCount );
237
238 /* Set XOR bits */
239 if(monochrome)
240 {
241 /* Create the 1bpp bitmap which will contain everything */
242 pii->hbmColor = NULL;
243 pii->hbmMask = CreateCompatibleBitmap(hdc, cxDesired, cyDesired * 2);
244 if(!pii->hbmMask)
245 goto done;
246 hbmpOld = SelectObject(hdc, pii->hbmMask);
247 if(!hbmpOld)
248 goto done;
249
250 if(!StretchDIBits(hdc, 0, cyDesired, cxDesired, cyDesired,
251 0, 0, pbmiCopy->bmiHeader.biWidth, pbmiCopy->bmiHeader.biHeight,
252 pvColor, pbmiCopy, DIB_RGB_COLORS, SRCCOPY))
253 goto done;
254 }
255 else
256 {
257 /* Create the bitmap. It has to be compatible with the screen surface */
258 pii->hbmColor = CreateCompatibleBitmap(hdcScreen, cxDesired, cyDesired);
259 if(!pii->hbmColor)
260 goto done;
261 /* Create the 1bpp mask bitmap */
262 pii->hbmMask = CreateCompatibleBitmap(hdc, cxDesired, cyDesired);
263 if(!pii->hbmMask)
264 goto done;
265 hbmpOld = SelectObject(hdc, pii->hbmColor);
266 if(!hbmpOld)
267 goto done;
268 if(!StretchDIBits(hdc, 0, 0, cxDesired, cyDesired,
269 0, 0, pbmiCopy->bmiHeader.biWidth, pbmiCopy->bmiHeader.biHeight,
270 pvColor, pbmiCopy, DIB_RGB_COLORS, SRCCOPY))
271 goto done;
272
273 /* Now convert the info to monochrome for the mask bits */
274 pbmiCopy->bmiHeader.biBitCount = 1;
275 /* Handle the CORE/INFO difference */
276 if (pbmiCopy->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
277 {
278 RGBQUAD *rgb = pbmiCopy->bmiColors;
279
280 pbmiCopy->bmiHeader.biClrUsed = pbmiCopy->bmiHeader.biClrImportant = 2;
281 rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00;
282 rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff;
283 rgb[0].rgbReserved = rgb[1].rgbReserved = 0;
284 }
285 else
286 {
287 RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)pbmiCopy) + 1);
288
289 rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00;
290 rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff;
291 }
292 }
293 /* Set the mask bits */
294 if(!SelectObject(hdc, pii->hbmMask))
295 goto done;
296 bResult = StretchDIBits(hdc, 0, 0, cxDesired, cyDesired,
297 0, 0, pbmiCopy->bmiHeader.biWidth, pbmiCopy->bmiHeader.biHeight,
298 pvMask, pbmiCopy, DIB_RGB_COLORS, SRCCOPY) != 0;
299
300 done:
301 DeleteDC(hdcScreen);
302 if(hbmpOld) SelectObject(hdc, hbmpOld);
303 DeleteDC(hdc);
304 if(pbmiCopy) HeapFree(GetProcessHeap(), 0, pbmiCopy);
305 /* Clean up in case of failure */
306 if(!bResult)
307 {
308 if(pii->hbmMask) DeleteObject(pii->hbmMask);
309 if(pii->hbmColor) DeleteObject(pii->hbmColor);
310 }
311 return bResult;
312 }
313
314 static
315 HBITMAP
316 BITMAP_LoadImageW(
317 _In_opt_ HINSTANCE hinst,
318 _In_ LPCWSTR lpszName,
319 _In_ int cxDesired,
320 _In_ int cyDesired,
321 _In_ UINT fuLoad
322 )
323 {
324 const BITMAPINFO* pbmi;
325 BITMAPINFO* pbmiScaled = NULL;
326 BITMAPINFO* pbmiCopy = NULL;
327 const VOID* pvMapping;
328 DWORD dwOffset = 0;
329 HGLOBAL hgRsrc;
330 int iBMISize;
331 PVOID pvBits;
332 HDC hdcScreen = NULL;
333 HDC hdc = NULL;
334 HBITMAP hbmpRet, hbmpOld;
335
336 /* Map the bitmap info */
337 if(fuLoad & LR_LOADFROMFILE)
338 {
339 const BITMAPFILEHEADER* pbmfh;
340
341 pvMapping = map_fileW(lpszName, NULL);
342 if(!pvMapping)
343 return NULL;
344 pbmfh = pvMapping;
345 if (pbmfh->bfType != 0x4d42 /* 'BM' */)
346 {
347 WARN("Invalid/unsupported bitmap format!\n");
348 goto end;
349 }
350 pbmi = (const BITMAPINFO*)(pbmfh + 1);
351
352 /* Get the image bits */
353 if(pbmfh->bfOffBits)
354 dwOffset = pbmfh->bfOffBits - sizeof(BITMAPFILEHEADER);
355 }
356 else
357 {
358 HRSRC hrsrc;
359
360 /* Caller wants an OEM bitmap */
361 if(!hinst)
362 hinst = User32Instance;
363 hrsrc = FindResourceW(hinst, lpszName, (LPWSTR)RT_BITMAP);
364 if(!hrsrc)
365 return NULL;
366 hgRsrc = LoadResource(hinst, hrsrc);
367 if(!hgRsrc)
368 return NULL;
369 pbmi = LockResource(hgRsrc);
370 if(!pbmi)
371 return NULL;
372 }
373
374 /* See if we must scale the bitmap */
375 iBMISize = bitmap_info_size(pbmi, DIB_RGB_COLORS);
376
377 /* Get a pointer to the image data */
378 pvBits = (char*)pbmi + (dwOffset ? dwOffset : iBMISize);
379
380 /* Create a copy of the info describing the bitmap in the file */
381 pbmiCopy = HeapAlloc(GetProcessHeap(), 0, iBMISize);
382 if(!pbmiCopy)
383 goto end;
384 CopyMemory(pbmiCopy, pbmi, iBMISize);
385
386 /* Fix it up, if needed */
387 if(fuLoad & (LR_LOADTRANSPARENT | LR_LOADMAP3DCOLORS))
388 {
389 WORD bpp, incr, numColors;
390 char* pbmiColors;
391 RGBTRIPLE* ptr;
392 COLORREF crWindow, cr3DShadow, cr3DFace, cr3DLight;
393 BYTE pixel = *((BYTE*)pvBits);
394 UINT i;
395
396 if(pbmiCopy->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
397 {
398 bpp = ((BITMAPCOREHEADER*)&pbmiCopy->bmiHeader)->bcBitCount;
399 numColors = 1 << bpp;
400 /* BITMAPCOREINFO holds RGBTRIPLEs */
401 incr = 3;
402 }
403 else
404 {
405 bpp = pbmiCopy->bmiHeader.biBitCount;
406 /* BITMAPINFOHEADER holds RGBQUADs */
407 incr = 4;
408 numColors = pbmiCopy->bmiHeader.biClrUsed;
409 if(numColors > 256) numColors = 256;
410 if (!numColors && (bpp <= 8)) numColors = 1 << bpp;
411 }
412
413 if(bpp > 8)
414 goto create_bitmap;
415
416 pbmiColors = (char*)pbmiCopy + pbmiCopy->bmiHeader.biSize;
417
418 /* Get the relevant colors */
419 crWindow = GetSysColor(COLOR_WINDOW);
420 cr3DShadow = GetSysColor(COLOR_3DSHADOW);
421 cr3DFace = GetSysColor(COLOR_3DFACE);
422 cr3DLight = GetSysColor(COLOR_3DLIGHT);
423
424 /* Fix the transparent palette entry */
425 if(fuLoad & LR_LOADTRANSPARENT)
426 {
427 switch(bpp)
428 {
429 case 1: pixel >>= 7; break;
430 case 4: pixel >>= 4; break;
431 case 8: break;
432 default:
433 FIXME("Unhandled bit depth %d.\n", bpp);
434 goto create_bitmap;
435 }
436
437 if(pixel >= numColors)
438 {
439 ERR("Wrong pixel passed in.\n");
440 goto create_bitmap;
441 }
442
443 /* If both flags are set, we must use COLOR_3DFACE */
444 if(fuLoad & LR_LOADMAP3DCOLORS) crWindow = cr3DFace;
445
446 /* Define the color */
447 ptr = (RGBTRIPLE*)(pbmiColors + pixel*incr);
448 ptr->rgbtBlue = GetBValue(crWindow);
449 ptr->rgbtGreen = GetGValue(crWindow);
450 ptr->rgbtRed = GetRValue(crWindow);
451 goto create_bitmap;
452 }
453
454 /* If we are here, then LR_LOADMAP3DCOLORS is set without LR_TRANSPARENT */
455 for(i = 0; i<numColors; i++)
456 {
457 ptr = (RGBTRIPLE*)(pbmiColors + i*incr);
458 if((ptr->rgbtBlue == ptr->rgbtRed) && (ptr->rgbtBlue == ptr->rgbtGreen))
459 {
460 if(ptr->rgbtBlue == 128)
461 {
462 ptr->rgbtBlue = GetBValue(cr3DShadow);
463 ptr->rgbtGreen = GetGValue(cr3DShadow);
464 ptr->rgbtRed = GetRValue(cr3DShadow);
465 }
466 if(ptr->rgbtBlue == 192)
467 {
468 ptr->rgbtBlue = GetBValue(cr3DFace);
469 ptr->rgbtGreen = GetGValue(cr3DFace);
470 ptr->rgbtRed = GetRValue(cr3DFace);
471 }
472 if(ptr->rgbtBlue == 223)
473 {
474 ptr->rgbtBlue = GetBValue(cr3DLight);
475 ptr->rgbtGreen = GetGValue(cr3DLight);
476 ptr->rgbtRed = GetRValue(cr3DLight);
477 }
478 }
479 }
480 }
481
482 create_bitmap:
483 if(fuLoad & LR_CREATEDIBSECTION)
484 {
485 /* Allocate the BMI describing the new bitmap */
486 pbmiScaled = HeapAlloc(GetProcessHeap(), 0, iBMISize);
487 if(!pbmiScaled)
488 goto end;
489 CopyMemory(pbmiScaled, pbmiCopy, iBMISize);
490
491 /* Fix it up */
492 if(pbmiScaled->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
493 {
494 BITMAPCOREHEADER* pbmch = (BITMAPCOREHEADER*)&pbmiScaled->bmiHeader;
495 if(cxDesired == 0)
496 cxDesired = pbmch->bcWidth;
497 if(cyDesired == 0)
498 cyDesired == pbmch->bcHeight;
499 else if(pbmch->bcHeight < 0)
500 cyDesired = -cyDesired;
501
502 pbmch->bcWidth = cxDesired;
503 pbmch->bcHeight = cyDesired;
504 }
505 else
506 {
507 if ((pbmi->bmiHeader.biHeight > 65535) || (pbmi->bmiHeader.biWidth > 65535)) {
508 WARN("Broken BITMAPINFO!\n");
509 goto end;
510 }
511
512 if(cxDesired == 0)
513 cxDesired = pbmi->bmiHeader.biWidth;
514 if(cyDesired == 0)
515 cyDesired = pbmi->bmiHeader.biHeight;
516 else if(pbmi->bmiHeader.biHeight < 0)
517 cyDesired = -cyDesired;
518
519 pbmiScaled->bmiHeader.biWidth = cxDesired;
520 pbmiScaled->bmiHeader.biHeight = cyDesired;
521 /* No compression for DIB sections */
522 if(fuLoad & LR_CREATEDIBSECTION)
523 pbmiScaled->bmiHeader.biCompression = BI_RGB;
524 }
525 }
526
527 /* Top-down image */
528 if(cyDesired < 0) cyDesired = -cyDesired;
529
530 /* We need a device context */
531 hdcScreen = CreateDCW(DISPLAYW, NULL, NULL, NULL);
532 if(!hdcScreen)
533 goto end;
534 hdc = CreateCompatibleDC(hdcScreen);
535 if(!hdc)
536 goto end;
537
538 /* Now create the bitmap */
539 if(fuLoad & LR_CREATEDIBSECTION)
540 hbmpRet = CreateDIBSection(hdc, pbmiScaled, DIB_RGB_COLORS, NULL, 0, 0);
541 else
542 {
543 if(is_dib_monochrome(pbmiCopy) || (fuLoad & LR_MONOCHROME))
544 hbmpRet = CreateBitmap(cxDesired, cyDesired, 1, 1, NULL);
545 else
546 hbmpRet = CreateCompatibleBitmap(hdcScreen, cxDesired, cyDesired);
547 }
548
549 if(!hbmpRet)
550 goto end;
551
552 hbmpOld = SelectObject(hdc, hbmpRet);
553 if(!hbmpOld)
554 goto end;
555 if(!StretchDIBits(hdc, 0, 0, cxDesired, cyDesired,
556 0, 0, pbmi->bmiHeader.biWidth, pbmi->bmiHeader.biWidth,
557 pvBits, pbmiCopy, DIB_RGB_COLORS, SRCCOPY))
558 {
559 ERR("StretchDIBits failed!.\n");
560 SelectObject(hdc, hbmpOld);
561 DeleteObject(hbmpRet);
562 hbmpRet = NULL;
563 goto end;
564 }
565
566 SelectObject(hdc, hbmpOld);
567
568 end:
569 if(hdcScreen)
570 DeleteDC(hdcScreen);
571 if(hdc)
572 DeleteDC(hdc);
573 if(pbmiScaled)
574 HeapFree(GetProcessHeap(), 0, pbmiScaled);
575 if(pbmiCopy)
576 HeapFree(GetProcessHeap(), 0, pbmiCopy);
577 if (fuLoad & LR_LOADFROMFILE)
578 UnmapViewOfFile( pvMapping );
579 else
580 FreeResource(hgRsrc);
581
582 return hbmpRet;
583 }
584
585 #include "pshpack1.h"
586
587 typedef struct {
588 BYTE bWidth;
589 BYTE bHeight;
590 BYTE bColorCount;
591 BYTE bReserved;
592 WORD xHotspot;
593 WORD yHotspot;
594 DWORD dwDIBSize;
595 DWORD dwDIBOffset;
596 } CURSORICONFILEDIRENTRY;
597
598 typedef struct
599 {
600 WORD idReserved;
601 WORD idType;
602 WORD idCount;
603 CURSORICONFILEDIRENTRY idEntries[1];
604 } CURSORICONFILEDIR;
605
606 #include "poppack.h"
607
608 static
609 HANDLE
610 CURSORICON_LoadFromFileW(
611 _In_ LPCWSTR lpszName,
612 _In_ int cxDesired,
613 _In_ int cyDesired,
614 _In_ UINT fuLoad,
615 _In_ BOOL bIcon
616 )
617 {
618 CURSORICONDIR* fakeDir;
619 CURSORICONDIRENTRY* fakeEntry;
620 CURSORICONFILEDIRENTRY *entry;
621 CURSORICONFILEDIR *dir;
622 DWORD filesize = 0;
623 LPBYTE bits;
624 HANDLE hRet = NULL;
625 WORD i;
626 ICONINFO ii;
627
628 TRACE("loading %s\n", debugstr_w( lpszName ));
629
630 bits = map_fileW( lpszName, &filesize );
631 if (!bits)
632 return NULL;
633
634 /* Check for .ani. */
635 if (memcmp( bits, "RIFF", 4 ) == 0)
636 {
637 UNIMPLEMENTED;
638 goto end;
639 }
640
641 dir = (CURSORICONFILEDIR*) bits;
642 if ( filesize < sizeof(*dir) )
643 goto end;
644
645 if ( filesize < (sizeof(*dir) + sizeof(dir->idEntries[0])*(dir->idCount-1)) )
646 goto end;
647
648 /*
649 * Cute little hack:
650 * We allocate a buffer, fake it as if it was a pointer to a resource in a module,
651 * pass it to LookupIconIdFromDirectoryEx and get back the index we have to use
652 */
653 fakeDir = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(CURSORICONDIR, idEntries[dir->idCount]));
654 if(!fakeDir)
655 goto end;
656 fakeDir->idReserved = 0;
657 fakeDir->idType = dir->idType;
658 fakeDir->idCount = dir->idCount;
659 for(i = 0; i<dir->idCount; i++)
660 {
661 fakeEntry = &fakeDir->idEntries[i];
662 entry = &dir->idEntries[i];
663 /* Take this as an occasion to perform a size check */
664 if((entry->dwDIBOffset + entry->dwDIBSize) > filesize)
665 goto end;
666 /* File icon/cursors are not like resource ones */
667 if(bIcon)
668 {
669 fakeEntry->ResInfo.icon.bWidth = entry->bWidth;
670 fakeEntry->ResInfo.icon.bHeight = entry->bHeight;
671 fakeEntry->ResInfo.icon.bColorCount = 0;
672 fakeEntry->ResInfo.icon.bReserved = 0;
673 }
674 else
675 {
676 fakeEntry->ResInfo.cursor.wWidth = entry->bWidth;
677 fakeEntry->ResInfo.cursor.wHeight = entry->bHeight;
678 }
679 /* Let's assume there's always one plane */
680 fakeEntry->wPlanes = 1;
681 /* We must get the bitcount from the BITMAPINFOHEADER itself */
682 fakeEntry->wBitCount = ((BITMAPINFOHEADER *)((char *)dir + entry->dwDIBOffset))->biBitCount;
683 fakeEntry->dwBytesInRes = entry->dwDIBSize;
684 fakeEntry->wResId = i + 1;
685 }
686
687 /* Now call LookupIconIdFromResourceEx */
688 i = LookupIconIdFromDirectoryEx((PBYTE)fakeDir, bIcon, cxDesired, cyDesired, fuLoad & LR_MONOCHROME);
689 /* We don't need this anymore */
690 HeapFree(GetProcessHeap(), 0, fakeDir);
691 if(i == 0)
692 {
693 WARN("Unable to get a fit entry index.\n");
694 goto end;
695 }
696
697 /* Get our entry */
698 entry = &dir->idEntries[i-1];
699 /* A bit of preparation */
700 ii.xHotspot = entry->xHotspot;
701 ii.yHotspot = entry->yHotspot;
702 ii.fIcon = bIcon;
703
704 /* Do the dance */
705 if(!CURSORICON_GetIconInfoFromBMI(&ii, (BITMAPINFO*)&bits[entry->dwDIBOffset], cxDesired, cyDesired))
706 goto end;
707
708 /* Create the icon. NOTE: there's no LR_SHARED icons if they are created from file */
709 hRet = CreateIconIndirect(&ii);
710
711 /* Clean up */
712 DeleteObject(ii.hbmMask);
713 DeleteObject(ii.hbmColor);
714
715 end:
716 UnmapViewOfFile(bits);
717 return hRet;
718 }
719
720 static
721 HANDLE
722 CURSORICON_LoadImageW(
723 _In_opt_ HINSTANCE hinst,
724 _In_ LPCWSTR lpszName,
725 _In_ int cxDesired,
726 _In_ int cyDesired,
727 _In_ UINT fuLoad,
728 _In_ BOOL bIcon
729 )
730 {
731 HRSRC hrsrc;
732 HANDLE handle, hCurIcon = NULL;
733 CURSORICONDIR* dir;
734 WORD wResId;
735 LPBYTE bits;
736 ICONINFO ii;
737 BOOL bStatus;
738 UNICODE_STRING ustrRsrc;
739 UNICODE_STRING ustrModule = {0, 0, NULL};
740
741 /* Fix width/height */
742 if(fuLoad & LR_DEFAULTSIZE)
743 {
744 if(!cxDesired) cxDesired = GetSystemMetrics(bIcon ? SM_CXICON : SM_CXCURSOR);
745 if(!cyDesired) cyDesired = GetSystemMetrics(bIcon ? SM_CYICON : SM_CYCURSOR);
746 }
747
748 if(fuLoad & LR_LOADFROMFILE)
749 {
750 return CURSORICON_LoadFromFileW(lpszName, cxDesired, cyDesired, fuLoad, bIcon);
751 }
752
753 /* Check if caller wants OEM icons */
754 if(!hinst)
755 hinst = User32Instance;
756
757 if(fuLoad & LR_SHARED)
758 {
759 DWORD size = MAX_PATH;
760 FINDEXISTINGCURICONPARAM param;
761
762 TRACE("Checking for an LR_SHARED cursor/icon.\n");
763 /* Prepare the resource name string */
764 if(IS_INTRESOURCE(lpszName))
765 {
766 ustrRsrc.Buffer = (LPWSTR)lpszName;
767 ustrRsrc.Length = 0;
768 ustrRsrc.MaximumLength = 0;
769 }
770 else
771 RtlInitUnicodeString(&ustrRsrc, lpszName);
772
773 /* Prepare the module name string */
774 ustrModule.Buffer = HeapAlloc(GetProcessHeap(), 0, size*sizeof(WCHAR));
775 /* Get it */
776 do
777 {
778 DWORD ret = GetModuleFileName(hinst, ustrModule.Buffer, size);
779 if(ret == 0)
780 {
781 HeapFree(GetProcessHeap(), 0, ustrModule.Buffer);
782 return NULL;
783 }
784 if(ret < size)
785 {
786 ustrModule.Length = ret;
787 ustrModule.MaximumLength = size;
788 break;
789 }
790 size *= 2;
791 ustrModule.Buffer = HeapReAlloc(GetProcessHeap(), 0, ustrModule.Buffer, size*sizeof(WCHAR));
792 } while(TRUE);
793
794 /* Ask win32k */
795 param.bIcon = bIcon;
796 param.cx = cxDesired;
797 param.cy = cyDesired;
798 hCurIcon = NtUserFindExistingCursorIcon(&ustrModule, &ustrRsrc, &param);
799 if(hCurIcon)
800 {
801 /* Woohoo, got it! */
802 TRACE("MATCH!\n");
803 HeapFree(GetProcessHeap(), 0, ustrModule.Buffer);
804 return hCurIcon;
805 }
806 }
807
808 /* Find resource ID */
809 hrsrc = FindResourceW(
810 hinst,
811 lpszName,
812 (LPWSTR)(bIcon ? RT_GROUP_ICON : RT_GROUP_CURSOR));
813
814 /* We let FindResource, LoadResource, etc. call SetLastError */
815 if(!hrsrc)
816 goto done;
817
818 handle = LoadResource(hinst, hrsrc);
819 if(!handle)
820 goto done;
821
822 dir = LockResource(handle);
823 if(!dir)
824 goto done;
825
826 wResId = LookupIconIdFromDirectoryEx((PBYTE)dir, bIcon, cxDesired, cyDesired, fuLoad & LR_MONOCHROME);
827 FreeResource(handle);
828
829 /* Get the relevant resource pointer */
830 hrsrc = FindResourceW(
831 hinst,
832 MAKEINTRESOURCEW(wResId),
833 (LPWSTR)(bIcon ? RT_ICON : RT_CURSOR));
834 if(!hrsrc)
835 goto done;
836
837 handle = LoadResource(hinst, hrsrc);
838 if(!handle)
839 goto done;
840
841 bits = LockResource(handle);
842 if(!bits)
843 {
844 FreeResource(handle);
845 goto done;
846 }
847
848 /* Get the hotspot */
849 if(bIcon)
850 {
851 ii.xHotspot = cxDesired/2;
852 ii.yHotspot = cyDesired/2;
853 }
854 if(!bIcon)
855 {
856 SHORT* ptr = (SHORT*)bits;
857 ii.xHotspot = ptr[0];
858 ii.yHotspot = ptr[1];
859 bits += 2*sizeof(SHORT);
860 }
861 ii.fIcon = bIcon;
862
863 /* Get the bitmaps */
864 bStatus = CURSORICON_GetIconInfoFromBMI(
865 &ii,
866 (BITMAPINFO*)bits,
867 cxDesired,
868 cyDesired);
869
870 FreeResource( handle );
871
872 if(!bStatus)
873 goto done;
874
875 /* Create the handle */
876 hCurIcon = NtUserxCreateEmptyCurObject(bIcon ? 0 : 1);
877 if(!hCurIcon)
878 {
879 DeleteObject(ii.hbmMask);
880 if(ii.hbmColor) DeleteObject(ii.hbmColor);
881 goto done;
882 }
883
884 /* Tell win32k */
885 if(fuLoad & LR_SHARED)
886 bStatus = NtUserSetCursorIconData(hCurIcon, &ustrModule, &ustrRsrc, &ii);
887 else
888 bStatus = NtUserSetCursorIconData(hCurIcon, NULL, NULL, &ii);
889
890 if(!bStatus)
891 {
892 NtUserDestroyCursor(hCurIcon, TRUE);
893 hCurIcon = NULL;
894 }
895
896 DeleteObject(ii.hbmMask);
897 if(ii.hbmColor) DeleteObject(ii.hbmColor);
898
899 done:
900 if(ustrModule.Buffer)
901 HeapFree(GetProcessHeap(), 0, ustrModule.Buffer);
902 return hCurIcon;
903 }
904
905 static
906 HBITMAP
907 BITMAP_CopyImage(
908 _In_ HBITMAP hbmp,
909 _In_ int cxDesired,
910 _In_ int cyDesired,
911 _In_ UINT fuFlags
912 )
913 {
914 HBITMAP res = NULL;
915 DIBSECTION ds;
916 int objSize;
917 BITMAPINFO * bi;
918
919 objSize = GetObjectW( hbmp, sizeof(ds), &ds );
920 if (!objSize) return 0;
921 if ((cxDesired < 0) || (cyDesired < 0)) return 0;
922
923 if (fuFlags & LR_COPYFROMRESOURCE)
924 {
925 FIXME("The flag LR_COPYFROMRESOURCE is not implemented for bitmaps\n");
926 }
927
928 if (fuFlags & LR_COPYRETURNORG)
929 {
930 FIXME("The flag LR_COPYRETURNORG is not implemented for bitmaps\n");
931 }
932
933 if (cxDesired == 0) cxDesired = ds.dsBm.bmWidth;
934 if (cyDesired == 0) cyDesired = ds.dsBm.bmHeight;
935
936 /* Allocate memory for a BITMAPINFOHEADER structure and a
937 color table. The maximum number of colors in a color table
938 is 256 which corresponds to a bitmap with depth 8.
939 Bitmaps with higher depths don't have color tables. */
940 bi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
941 if (!bi) return 0;
942
943 bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
944 bi->bmiHeader.biPlanes = ds.dsBm.bmPlanes;
945 bi->bmiHeader.biBitCount = ds.dsBm.bmBitsPixel;
946 bi->bmiHeader.biCompression = BI_RGB;
947
948 if (fuFlags & LR_CREATEDIBSECTION)
949 {
950 /* Create a DIB section. LR_MONOCHROME is ignored */
951 void * bits;
952 HDC dc = CreateCompatibleDC(NULL);
953
954 if (objSize == sizeof(DIBSECTION))
955 {
956 /* The source bitmap is a DIB.
957 Get its attributes to create an exact copy */
958 memcpy(bi, &ds.dsBmih, sizeof(BITMAPINFOHEADER));
959 }
960
961 /* Get the color table or the color masks */
962 GetDIBits(dc, hbmp, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
963
964 bi->bmiHeader.biWidth = cxDesired;
965 bi->bmiHeader.biHeight = cyDesired;
966 bi->bmiHeader.biSizeImage = 0;
967
968 res = CreateDIBSection(dc, bi, DIB_RGB_COLORS, &bits, NULL, 0);
969 DeleteDC(dc);
970 }
971 else
972 {
973 /* Create a device-dependent bitmap */
974
975 BOOL monochrome = (fuFlags & LR_MONOCHROME);
976
977 if (objSize == sizeof(DIBSECTION))
978 {
979 /* The source bitmap is a DIB section.
980 Get its attributes */
981 HDC dc = CreateCompatibleDC(NULL);
982 bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
983 bi->bmiHeader.biBitCount = ds.dsBm.bmBitsPixel;
984 GetDIBits(dc, hbmp, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
985 DeleteDC(dc);
986
987 if (!monochrome && ds.dsBm.bmBitsPixel == 1)
988 {
989 /* Look if the colors of the DIB are black and white */
990
991 monochrome =
992 (bi->bmiColors[0].rgbRed == 0xff
993 && bi->bmiColors[0].rgbGreen == 0xff
994 && bi->bmiColors[0].rgbBlue == 0xff
995 && bi->bmiColors[0].rgbReserved == 0
996 && bi->bmiColors[1].rgbRed == 0
997 && bi->bmiColors[1].rgbGreen == 0
998 && bi->bmiColors[1].rgbBlue == 0
999 && bi->bmiColors[1].rgbReserved == 0)
1000 ||
1001 (bi->bmiColors[0].rgbRed == 0
1002 && bi->bmiColors[0].rgbGreen == 0
1003 && bi->bmiColors[0].rgbBlue == 0
1004 && bi->bmiColors[0].rgbReserved == 0
1005 && bi->bmiColors[1].rgbRed == 0xff
1006 && bi->bmiColors[1].rgbGreen == 0xff
1007 && bi->bmiColors[1].rgbBlue == 0xff
1008 && bi->bmiColors[1].rgbReserved == 0);
1009 }
1010 }
1011 else if (!monochrome)
1012 {
1013 monochrome = ds.dsBm.bmBitsPixel == 1;
1014 }
1015
1016 if (monochrome)
1017 {
1018 res = CreateBitmap(cxDesired, cyDesired, 1, 1, NULL);
1019 }
1020 else
1021 {
1022 HDC screenDC = GetDC(NULL);
1023 res = CreateCompatibleBitmap(screenDC, cxDesired, cyDesired);
1024 ReleaseDC(NULL, screenDC);
1025 }
1026 }
1027
1028 if (res)
1029 {
1030 /* Only copy the bitmap if it's a DIB section or if it's
1031 compatible to the screen */
1032 BOOL copyContents;
1033
1034 if (objSize == sizeof(DIBSECTION))
1035 {
1036 copyContents = TRUE;
1037 }
1038 else
1039 {
1040 HDC screenDC = GetDC(NULL);
1041 int screen_depth = GetDeviceCaps(screenDC, BITSPIXEL);
1042 ReleaseDC(NULL, screenDC);
1043
1044 copyContents = (ds.dsBm.bmBitsPixel == 1 || ds.dsBm.bmBitsPixel == screen_depth);
1045 }
1046
1047 if (copyContents)
1048 {
1049 /* The source bitmap may already be selected in a device context,
1050 use GetDIBits/StretchDIBits and not StretchBlt */
1051
1052 HDC dc;
1053 void * bits;
1054
1055 dc = CreateCompatibleDC(NULL);
1056
1057 bi->bmiHeader.biWidth = ds.dsBm.bmWidth;
1058 bi->bmiHeader.biHeight = ds.dsBm.bmHeight;
1059 bi->bmiHeader.biSizeImage = 0;
1060 bi->bmiHeader.biClrUsed = 0;
1061 bi->bmiHeader.biClrImportant = 0;
1062
1063 /* Fill in biSizeImage */
1064 GetDIBits(dc, hbmp, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
1065 bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bi->bmiHeader.biSizeImage);
1066
1067 if (bits)
1068 {
1069 HBITMAP oldBmp;
1070
1071 /* Get the image bits of the source bitmap */
1072 GetDIBits(dc, hbmp, 0, ds.dsBm.bmHeight, bits, bi, DIB_RGB_COLORS);
1073
1074 /* Copy it to the destination bitmap */
1075 oldBmp = SelectObject(dc, res);
1076 StretchDIBits(dc, 0, 0, cxDesired, cyDesired,
1077 0, 0, ds.dsBm.bmWidth, ds.dsBm.bmHeight,
1078 bits, bi, DIB_RGB_COLORS, SRCCOPY);
1079 SelectObject(dc, oldBmp);
1080
1081 HeapFree(GetProcessHeap(), 0, bits);
1082 }
1083
1084 DeleteDC(dc);
1085 }
1086
1087 if (fuFlags & LR_COPYDELETEORG)
1088 {
1089 DeleteObject(hbmp);
1090 }
1091 }
1092 HeapFree(GetProcessHeap(), 0, bi);
1093 return res;
1094 }
1095
1096 static
1097 HICON
1098 CURSORICON_CopyImage(
1099 _In_ HICON hicon,
1100 _In_ BOOL bIcon,
1101 _In_ int cxDesired,
1102 _In_ int cyDesired,
1103 _In_ UINT fuFlags
1104 )
1105 {
1106 HICON ret = NULL;
1107 ICONINFO ii;
1108
1109 if(fuFlags & LR_COPYFROMRESOURCE)
1110 {
1111 /* Get the icon module/resource names */
1112 UNICODE_STRING ustrModule;
1113 UNICODE_STRING ustrRsrc;
1114 PVOID pvBuf;
1115 HMODULE hModule;
1116
1117 ustrModule.MaximumLength = MAX_PATH;
1118 ustrRsrc.MaximumLength = 256;
1119
1120 ustrModule.Buffer = HeapAlloc(GetProcessHeap(), 0, ustrModule.MaximumLength * sizeof(WCHAR));
1121 if(!ustrModule.Buffer)
1122 {
1123 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1124 return NULL;
1125 }
1126 /* Keep track of the buffer for the resource, NtUserGetIconInfo might overwrite it */
1127 pvBuf = HeapAlloc(GetProcessHeap(), 0, 256 * sizeof(WCHAR));
1128 if(!pvBuf)
1129 {
1130 HeapFree(GetProcessHeap(), 0, ustrModule.Buffer);
1131 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1132 return NULL;
1133 }
1134 ustrRsrc.Buffer = pvBuf;
1135
1136 do
1137 {
1138 if(!NtUserGetIconInfo(hicon, NULL, &ustrModule, &ustrRsrc, NULL, FALSE))
1139 {
1140 HeapFree(GetProcessHeap(), 0, ustrModule.Buffer);
1141 HeapFree(GetProcessHeap(), 0, pvBuf);
1142 return NULL;
1143 }
1144
1145 if((ustrModule.Length < ustrModule.MaximumLength) && (ustrRsrc.Length < ustrRsrc.MaximumLength))
1146 {
1147 /* Buffers were big enough */
1148 break;
1149 }
1150
1151 /* Find which buffer were too small */
1152 if(ustrModule.Length == ustrModule.MaximumLength)
1153 {
1154 PWSTR newBuffer;
1155 ustrModule.MaximumLength *= 2;
1156 newBuffer = HeapReAlloc(GetProcessHeap(), 0, ustrModule.Buffer, ustrModule.MaximumLength * sizeof(WCHAR));
1157 if(!ustrModule.Buffer)
1158 {
1159 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1160 goto leave;
1161 }
1162 ustrModule.Buffer = newBuffer;
1163 }
1164
1165 if(ustrRsrc.Length == ustrRsrc.MaximumLength)
1166 {
1167 ustrRsrc.MaximumLength *= 2;
1168 pvBuf = HeapReAlloc(GetProcessHeap(), 0, ustrRsrc.Buffer, ustrRsrc.MaximumLength * sizeof(WCHAR));
1169 if(!pvBuf)
1170 {
1171 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1172 goto leave;
1173 }
1174 ustrRsrc.Buffer = pvBuf;
1175 }
1176 } while(TRUE);
1177
1178 /* NULL-terminate our strings */
1179 ustrModule.Buffer[ustrModule.Length] = 0;
1180 if(!IS_INTRESOURCE(ustrRsrc.Buffer))
1181 ustrRsrc.Buffer[ustrRsrc.Length] = 0;
1182
1183 /* Get the module handle */
1184 if(!GetModuleHandleExW(0, ustrModule.Buffer, &hModule))
1185 {
1186 /* This hould never happen */
1187 SetLastError(ERROR_INVALID_PARAMETER);
1188 goto leave;
1189 }
1190
1191 /* Call the relevant function */
1192 ret = CURSORICON_LoadImageW(hModule, ustrRsrc.Buffer, cxDesired, cyDesired, fuFlags & LR_DEFAULTSIZE, bIcon);
1193
1194 FreeLibrary(hModule);
1195
1196 /* If we're here, that means that the passed icon is shared. Don't destroy it, even if LR_COPYDELETEORG is specified */
1197 leave:
1198 HeapFree(GetProcessHeap(), 0, ustrModule.Buffer);
1199 HeapFree(GetProcessHeap(), 0, pvBuf);
1200
1201 return ret;
1202 }
1203
1204 /* This is a regular copy */
1205 if(fuFlags & ~LR_COPYDELETEORG)
1206 FIXME("Unimplemented flags: 0x%08x\n", fuFlags);
1207
1208 if(!GetIconInfo(hicon, &ii))
1209 {
1210 ERR("GetIconInfo failed.\n");
1211 return NULL;
1212 }
1213
1214 ret = CreateIconIndirect(&ii);
1215
1216 DeleteObject(ii.hbmMask);
1217 if(ii.hbmColor) DeleteObject(ii.hbmColor);
1218
1219 if(ret && (fuFlags & LR_COPYDELETEORG))
1220 DestroyIcon(hicon);
1221
1222 return hicon;
1223 }
1224
1225 /************* PUBLIC FUNCTIONS *******************/
1226
1227 HANDLE WINAPI CopyImage(
1228 _In_ HANDLE hImage,
1229 _In_ UINT uType,
1230 _In_ int cxDesired,
1231 _In_ int cyDesired,
1232 _In_ UINT fuFlags
1233 )
1234 {
1235 TRACE("hImage=%p, uType=%u, cxDesired=%d, cyDesired=%d, fuFlags=%x\n",
1236 hImage, uType, cxDesired, cyDesired, fuFlags);
1237 switch(uType)
1238 {
1239 case IMAGE_BITMAP:
1240 return BITMAP_CopyImage(hImage, cxDesired, cyDesired, fuFlags);
1241 case IMAGE_CURSOR:
1242 case IMAGE_ICON:
1243 return CURSORICON_CopyImage(hImage, uType == IMAGE_ICON, cxDesired, cyDesired, fuFlags);
1244 default:
1245 SetLastError(ERROR_INVALID_PARAMETER);
1246 break;
1247 }
1248 return NULL;
1249 }
1250
1251 HICON WINAPI CopyIcon(
1252 _In_ HICON hIcon
1253 )
1254 {
1255 UNIMPLEMENTED;
1256 return NULL;
1257 }
1258
1259 BOOL WINAPI DrawIcon(
1260 _In_ HDC hDC,
1261 _In_ int X,
1262 _In_ int Y,
1263 _In_ HICON hIcon
1264 )
1265 {
1266 return DrawIconEx(hDC, X, Y, hIcon, 0, 0, 0, NULL, DI_NORMAL | DI_COMPAT | DI_DEFAULTSIZE);
1267 }
1268
1269 BOOL WINAPI DrawIconEx(
1270 _In_ HDC hdc,
1271 _In_ int xLeft,
1272 _In_ int yTop,
1273 _In_ HICON hIcon,
1274 _In_ int cxWidth,
1275 _In_ int cyWidth,
1276 _In_ UINT istepIfAniCur,
1277 _In_opt_ HBRUSH hbrFlickerFreeDraw,
1278 _In_ UINT diFlags
1279 )
1280 {
1281 return NtUserDrawIconEx(hdc, xLeft, yTop, hIcon, cxWidth, cyWidth,
1282 istepIfAniCur, hbrFlickerFreeDraw, diFlags,
1283 0, 0);
1284 }
1285
1286 BOOL WINAPI GetIconInfo(
1287 _In_ HICON hIcon,
1288 _Out_ PICONINFO piconinfo
1289 )
1290 {
1291 return NtUserGetIconInfo(hIcon, piconinfo, NULL, NULL, NULL, FALSE);
1292 }
1293
1294 BOOL WINAPI DestroyIcon(
1295 _In_ HICON hIcon
1296 )
1297 {
1298 return NtUserDestroyCursor(hIcon, FALSE);
1299 }
1300
1301 HICON WINAPI LoadIconA(
1302 _In_opt_ HINSTANCE hInstance,
1303 _In_ LPCSTR lpIconName
1304 )
1305 {
1306 TRACE("%p, %s\n", hInstance, debugstr_a(lpIconName));
1307
1308 return LoadImageA(hInstance,
1309 lpIconName,
1310 IMAGE_ICON,
1311 0,
1312 0,
1313 LR_SHARED | LR_DEFAULTSIZE );
1314 }
1315
1316 HICON WINAPI LoadIconW(
1317 _In_opt_ HINSTANCE hInstance,
1318 _In_ LPCWSTR lpIconName
1319 )
1320 {
1321 TRACE("%p, %s\n", hInstance, debugstr_w(lpIconName));
1322
1323 return LoadImageW(hInstance,
1324 lpIconName,
1325 IMAGE_ICON,
1326 0,
1327 0,
1328 LR_SHARED | LR_DEFAULTSIZE );
1329 }
1330
1331 HCURSOR WINAPI LoadCursorA(
1332 _In_opt_ HINSTANCE hInstance,
1333 _In_ LPCSTR lpCursorName
1334 )
1335 {
1336 TRACE("%p, %s\n", hInstance, debugstr_a(lpCursorName));
1337
1338 return LoadImageA(hInstance,
1339 lpCursorName,
1340 IMAGE_CURSOR,
1341 0,
1342 0,
1343 LR_SHARED | LR_DEFAULTSIZE );
1344 }
1345
1346 HCURSOR WINAPI LoadCursorW(
1347 _In_opt_ HINSTANCE hInstance,
1348 _In_ LPCWSTR lpCursorName
1349 )
1350 {
1351 TRACE("%p, %s\n", hInstance, debugstr_w(lpCursorName));
1352
1353 return LoadImageW(hInstance,
1354 lpCursorName,
1355 IMAGE_CURSOR,
1356 0,
1357 0,
1358 LR_SHARED | LR_DEFAULTSIZE );
1359 }
1360
1361 HCURSOR WINAPI LoadCursorFromFileA(
1362 _In_ LPCSTR lpFileName
1363 )
1364 {
1365 TRACE("%s\n", debugstr_a(lpFileName));
1366
1367 return LoadImageA(NULL,
1368 lpFileName,
1369 IMAGE_CURSOR,
1370 0,
1371 0,
1372 LR_LOADFROMFILE | LR_DEFAULTSIZE );
1373 }
1374
1375 HCURSOR WINAPI LoadCursorFromFileW(
1376 _In_ LPCWSTR lpFileName
1377 )
1378 {
1379 TRACE("%s\n", debugstr_w(lpFileName));
1380
1381 return LoadImageW(NULL,
1382 lpFileName,
1383 IMAGE_CURSOR,
1384 0,
1385 0,
1386 LR_LOADFROMFILE | LR_DEFAULTSIZE );
1387 }
1388
1389 HBITMAP WINAPI LoadBitmapA(
1390 _In_opt_ HINSTANCE hInstance,
1391 _In_ LPCSTR lpBitmapName
1392 )
1393 {
1394 TRACE("%p, %s\n", hInstance, debugstr_a(lpBitmapName));
1395
1396 return LoadImageA(hInstance,
1397 lpBitmapName,
1398 IMAGE_BITMAP,
1399 0,
1400 0,
1401 0);
1402 }
1403
1404 HBITMAP WINAPI LoadBitmapW(
1405 _In_opt_ HINSTANCE hInstance,
1406 _In_ LPCWSTR lpBitmapName
1407 )
1408 {
1409 TRACE("%p, %s\n", hInstance, debugstr_w(lpBitmapName));
1410
1411 return LoadImageW(hInstance,
1412 lpBitmapName,
1413 IMAGE_BITMAP,
1414 0,
1415 0,
1416 0);
1417 }
1418
1419 HANDLE WINAPI LoadImageA(
1420 _In_opt_ HINSTANCE hinst,
1421 _In_ LPCSTR lpszName,
1422 _In_ UINT uType,
1423 _In_ int cxDesired,
1424 _In_ int cyDesired,
1425 _In_ UINT fuLoad
1426 )
1427 {
1428 HANDLE res;
1429 LPWSTR u_name;
1430 DWORD len;
1431
1432 if (IS_INTRESOURCE(lpszName))
1433 return LoadImageW(hinst, (LPCWSTR)lpszName, uType, cxDesired, cyDesired, fuLoad);
1434
1435 len = MultiByteToWideChar( CP_ACP, 0, lpszName, -1, NULL, 0 );
1436 u_name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
1437 MultiByteToWideChar( CP_ACP, 0, lpszName, -1, u_name, len );
1438
1439 res = LoadImageW(hinst, u_name, uType, cxDesired, cyDesired, fuLoad);
1440 HeapFree(GetProcessHeap(), 0, u_name);
1441 return res;
1442 }
1443
1444 HANDLE WINAPI LoadImageW(
1445 _In_opt_ HINSTANCE hinst,
1446 _In_ LPCWSTR lpszName,
1447 _In_ UINT uType,
1448 _In_ int cxDesired,
1449 _In_ int cyDesired,
1450 _In_ UINT fuLoad
1451 )
1452 {
1453 /* Redirect to each implementation */
1454 switch(uType)
1455 {
1456 case IMAGE_BITMAP:
1457 return BITMAP_LoadImageW(hinst, lpszName, cxDesired, cyDesired, fuLoad);
1458 case IMAGE_CURSOR:
1459 case IMAGE_ICON:
1460 return CURSORICON_LoadImageW(hinst, lpszName, cxDesired, cyDesired, fuLoad, uType == IMAGE_ICON);
1461 default:
1462 SetLastError(ERROR_INVALID_PARAMETER);
1463 break;
1464 }
1465 return NULL;
1466 }
1467
1468 int WINAPI LookupIconIdFromDirectory(
1469 _In_ PBYTE presbits,
1470 _In_ BOOL fIcon
1471 )
1472 {
1473 return LookupIconIdFromDirectoryEx( presbits, fIcon,
1474 fIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
1475 fIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), fIcon ? 0 : LR_MONOCHROME );
1476 }
1477
1478 int WINAPI LookupIconIdFromDirectoryEx(
1479 _In_ PBYTE presbits,
1480 _In_ BOOL fIcon,
1481 _In_ int cxDesired,
1482 _In_ int cyDesired,
1483 _In_ UINT Flags
1484 )
1485 {
1486 WORD bppDesired;
1487 CURSORICONDIR* dir = (CURSORICONDIR*)presbits;
1488 CURSORICONDIRENTRY* entry;
1489 int i, numMatch, iIndex = -1;
1490 WORD width, height;
1491 USHORT bitcount;
1492 ULONG cxyDiff, cxyDiffTmp;
1493
1494 TRACE("%p, %x, %i, %i, %x.\n", presbits, fIcon, cxDesired, cyDesired, Flags);
1495
1496 if(!(dir && !dir->idReserved && (dir->idType & 3)))
1497 {
1498 WARN("Invalid resource.\n");
1499 return 0;
1500 }
1501
1502 /* idType == 2 is for cursors, 1 for icons */
1503 /*if(fIcon)
1504 {
1505 if(dir->idType == 2)
1506 {
1507 WARN("An icon was asked for a cursor resource.\n");
1508 return 0;
1509 }
1510 }
1511 else if(dir->idType == 1)
1512 {
1513 WARN("A cursor was asked for an icon resource.\n");
1514 return 0;
1515 }*/
1516
1517 if(Flags & LR_MONOCHROME)
1518 bppDesired = 1;
1519 else
1520 {
1521 HDC icScreen;
1522 icScreen = CreateICW(DISPLAYW, NULL, NULL, NULL);
1523 if(!icScreen)
1524 return FALSE;
1525
1526 bppDesired = GetDeviceCaps(icScreen, BITSPIXEL);
1527 DeleteDC(icScreen);
1528 }
1529
1530 /* Find the best match for the desired size */
1531 cxyDiff = 0xFFFFFFFF;
1532 numMatch = 0;
1533 for(i = 0; i < dir->idCount; i++)
1534 {
1535 entry = &dir->idEntries[i];
1536 width = fIcon ? entry->ResInfo.icon.bWidth : entry->ResInfo.cursor.wWidth;
1537 /* Height is twice as big in cursor resources */
1538 height = fIcon ? entry->ResInfo.icon.bHeight : entry->ResInfo.cursor.wHeight/2;
1539 /* 0 represents 256 */
1540 if(!width) width = 256;
1541 if(!height) height = 256;
1542 /* Let it be a 1-norm */
1543 cxyDiffTmp = max(abs(width - cxDesired), abs(height - cyDesired));
1544 if( cxyDiffTmp > cxyDiff)
1545 continue;
1546 if( cxyDiffTmp == cxyDiff)
1547 {
1548 numMatch++;
1549 continue;
1550 }
1551 iIndex = i;
1552 numMatch = 1;
1553 cxyDiff = cxyDiffTmp;
1554 }
1555
1556 if(numMatch == 1)
1557 {
1558 /* Only one entry fit the asked dimensions */
1559 return dir->idEntries[iIndex].wResId;
1560 }
1561
1562 bitcount = 0;
1563 iIndex = -1;
1564 /* Now find the entry with the best depth */
1565 for(i = 0; i < dir->idCount; i++)
1566 {
1567 entry = &dir->idEntries[i];
1568 width = fIcon ? entry->ResInfo.icon.bWidth : entry->ResInfo.cursor.wWidth;
1569 height = fIcon ? entry->ResInfo.icon.bHeight : entry->ResInfo.cursor.wHeight/2;
1570 /* 0 represents 256 */
1571 if(!width) width = 256;
1572 if(!height) height = 256;
1573 /* Check if this is the best match we had */
1574 cxyDiffTmp = max(abs(width - cxDesired), abs(height - cyDesired));
1575 if(cxyDiffTmp != cxyDiff)
1576 continue;
1577 /* Exact match? */
1578 if(entry->wBitCount == bppDesired)
1579 return entry->wResId;
1580 /* We take the highest possible but smaller than the display depth */
1581 if((entry->wBitCount > bitcount) && (entry->wBitCount < bppDesired))
1582 {
1583 iIndex = i;
1584 bitcount = entry->wBitCount;
1585 }
1586 }
1587
1588 if(iIndex >= 0)
1589 return dir->idEntries[iIndex].wResId;
1590
1591 /* No inferior or equal depth available. Get the smallest one */
1592 bitcount = 0x7FFF;
1593 for(i = 0; i < dir->idCount; i++)
1594 {
1595 entry = &dir->idEntries[i];
1596 width = fIcon ? entry->ResInfo.icon.bWidth : entry->ResInfo.cursor.wWidth;
1597 height = fIcon ? entry->ResInfo.icon.bHeight : entry->ResInfo.cursor.wHeight/2;
1598 /* 0 represents 256 */
1599 if(!width) width = 256;
1600 if(!height) height = 256;
1601 /* Check if this is the best match we had */
1602 cxyDiffTmp = max(abs(width - cxDesired), abs(height - cyDesired));
1603 if(cxyDiffTmp != cxyDiff)
1604 continue;
1605 /* Check the bit depth */
1606 if(entry->wBitCount < bitcount)
1607 {
1608 iIndex = i;
1609 bitcount = entry->wBitCount;
1610 }
1611 }
1612
1613 return dir->idEntries[iIndex].wResId;
1614 }
1615
1616 HICON WINAPI CreateIcon(
1617 _In_opt_ HINSTANCE hInstance,
1618 _In_ int nWidth,
1619 _In_ int nHeight,
1620 _In_ BYTE cPlanes,
1621 _In_ BYTE cBitsPixel,
1622 _In_ const BYTE *lpbANDbits,
1623 _In_ const BYTE *lpbXORbits
1624 )
1625 {
1626 ICONINFO iinfo;
1627 HICON hIcon;
1628
1629 TRACE_(icon)("%dx%d, planes %d, bpp %d, xor %p, and %p\n",
1630 nWidth, nHeight, cPlanes, cBitsPixel, lpbXORbits, lpbANDbits);
1631
1632 iinfo.fIcon = TRUE;
1633 iinfo.xHotspot = nWidth / 2;
1634 iinfo.yHotspot = nHeight / 2;
1635 if (cPlanes * cBitsPixel > 1)
1636 {
1637 iinfo.hbmColor = CreateBitmap( nWidth, nHeight, cPlanes, cBitsPixel, lpbXORbits );
1638 iinfo.hbmMask = CreateBitmap( nWidth, nHeight, 1, 1, lpbANDbits );
1639 }
1640 else
1641 {
1642 iinfo.hbmMask = CreateBitmap( nWidth, nHeight * 2, 1, 1, lpbANDbits );
1643 iinfo.hbmColor = NULL;
1644 }
1645
1646 hIcon = CreateIconIndirect( &iinfo );
1647
1648 DeleteObject( iinfo.hbmMask );
1649 if (iinfo.hbmColor) DeleteObject( iinfo.hbmColor );
1650
1651 return hIcon;
1652 }
1653
1654 HICON WINAPI CreateIconFromResource(
1655 _In_ PBYTE presbits,
1656 _In_ DWORD dwResSize,
1657 _In_ BOOL fIcon,
1658 _In_ DWORD dwVer
1659 )
1660 {
1661 return CreateIconFromResourceEx( presbits, dwResSize, fIcon, dwVer, 0,0,0);
1662 }
1663
1664 HICON WINAPI CreateIconFromResourceEx(
1665 _In_ PBYTE pbIconBits,
1666 _In_ DWORD cbIconBits,
1667 _In_ BOOL fIcon,
1668 _In_ DWORD dwVersion,
1669 _In_ int cxDesired,
1670 _In_ int cyDesired,
1671 _In_ UINT uFlags
1672 )
1673 {
1674 ICONINFO ii;
1675 HICON hIcon;
1676
1677 if(uFlags)
1678 FIXME("uFlags 0x%08x ignored.\n", uFlags);
1679
1680 if(fIcon)
1681 {
1682 ii.xHotspot = cxDesired/2;
1683 ii.yHotspot = cyDesired/2;
1684 }
1685 else
1686 {
1687 WORD* pt = (WORD*)pbIconBits;
1688 ii.xHotspot = *pt++;
1689 ii.yHotspot = *pt++;
1690 pbIconBits = (PBYTE)pt;
1691 }
1692 ii.fIcon = fIcon;
1693
1694 if(!CURSORICON_GetIconInfoFromBMI(&ii, (BITMAPINFO*)pbIconBits, cxDesired, cyDesired))
1695 return NULL;
1696
1697 hIcon = CreateIconIndirect(&ii);
1698
1699 /* Clean up */
1700 DeleteObject(ii.hbmMask);
1701 if(ii.hbmColor) DeleteObject(ii.hbmColor);
1702
1703 return hIcon;
1704 }
1705
1706 HICON WINAPI CreateIconIndirect(
1707 _In_ PICONINFO piconinfo
1708 )
1709 {
1710 /* As simple as creating a handle, and let win32k deal with the bitmaps */
1711 HICON hiconRet;
1712
1713 TRACE("%p.\n", piconinfo);
1714
1715 hiconRet = NtUserxCreateEmptyCurObject(piconinfo->fIcon ? 0 : 1);
1716 if(!hiconRet)
1717 return NULL;
1718
1719 if(!NtUserSetCursorIconData(hiconRet, NULL, NULL, piconinfo))
1720 {
1721 NtUserDestroyCursor(hiconRet, FALSE);
1722 hiconRet = NULL;
1723 }
1724
1725 TRACE("Returning 0x%08x.\n", hiconRet);
1726
1727 return hiconRet;
1728 }
1729
1730 HCURSOR WINAPI CreateCursor(
1731 _In_opt_ HINSTANCE hInst,
1732 _In_ int xHotSpot,
1733 _In_ int yHotSpot,
1734 _In_ int nWidth,
1735 _In_ int nHeight,
1736 _In_ const VOID *pvANDPlane,
1737 _In_ const VOID *pvXORPlane
1738 )
1739 {
1740 ICONINFO info;
1741 HCURSOR hCursor;
1742
1743 TRACE_(cursor)("%dx%d spot=%d,%d xor=%p and=%p\n",
1744 nWidth, nHeight, xHotSpot, yHotSpot, pvXORPlane, pvANDPlane);
1745
1746 info.fIcon = FALSE;
1747 info.xHotspot = xHotSpot;
1748 info.yHotspot = yHotSpot;
1749 info.hbmMask = CreateBitmap( nWidth, nHeight, 1, 1, pvANDPlane );
1750 info.hbmColor = CreateBitmap( nWidth, nHeight, 1, 1, pvXORPlane );
1751 hCursor = CreateIconIndirect( &info );
1752 DeleteObject( info.hbmMask );
1753 DeleteObject( info.hbmColor );
1754 return hCursor;
1755 }
1756
1757 BOOL WINAPI SetSystemCursor(
1758 _In_ HCURSOR hcur,
1759 _In_ DWORD id
1760 )
1761 {
1762 UNIMPLEMENTED;
1763 return FALSE;
1764 }
1765
1766 BOOL WINAPI SetCursorPos(
1767 _In_ int X,
1768 _In_ int Y
1769 )
1770 {
1771 UNIMPLEMENTED;
1772 return FALSE;
1773 }
1774
1775 BOOL WINAPI GetCursorPos(
1776 _Out_ LPPOINT lpPoint
1777 )
1778 {
1779 return NtUserxGetCursorPos(lpPoint);
1780 }
1781
1782 int WINAPI ShowCursor(
1783 _In_ BOOL bShow
1784 )
1785 {
1786 UNIMPLEMENTED;
1787 return -1;
1788 }
1789
1790 HCURSOR WINAPI GetCursor(void)
1791 {
1792 UNIMPLEMENTED;
1793 return NULL;
1794 }
1795
1796 BOOL WINAPI DestroyCursor(
1797 _In_ HCURSOR hCursor
1798 )
1799 {
1800 return NtUserDestroyCursor(hCursor, FALSE);
1801 }