[USER32]
[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
761 TRACE("Checking for an LR_SHARED cursor/icon.\n");
762 /* Prepare the resource name string */
763 if(IS_INTRESOURCE(lpszName))
764 {
765 ustrRsrc.Buffer = (LPWSTR)lpszName;
766 ustrRsrc.Length = 0;
767 ustrRsrc.MaximumLength = 0;
768 }
769 else
770 RtlInitUnicodeString(&ustrRsrc, lpszName);
771
772 /* Prepare the module name string */
773 ustrModule.Buffer = HeapAlloc(GetProcessHeap(), 0, size*sizeof(WCHAR));
774 /* Get it */
775 do
776 {
777 DWORD ret = GetModuleFileName(hinst, ustrModule.Buffer, size);
778 if(ret == 0)
779 {
780 HeapFree(GetProcessHeap(), 0, ustrModule.Buffer);
781 return NULL;
782 }
783 if(ret < size)
784 {
785 ustrModule.Length = ret;
786 ustrModule.MaximumLength = size;
787 break;
788 }
789 size *= 2;
790 ustrModule.Buffer = HeapReAlloc(GetProcessHeap(), 0, ustrModule.Buffer, size*sizeof(WCHAR));
791 } while(TRUE);
792
793 /* Ask win32k */
794 hCurIcon = NtUserFindExistingCursorIcon(&ustrModule, &ustrRsrc, cxDesired, cyDesired);
795 if(hCurIcon)
796 {
797 /* Woohoo, got it! */
798 TRACE("MATCH!\n");
799 HeapFree(GetProcessHeap(), 0, ustrModule.Buffer);
800 return hCurIcon;
801 }
802 }
803
804 /* Find resource ID */
805 hrsrc = FindResourceW(
806 hinst,
807 lpszName,
808 (LPWSTR)(bIcon ? RT_GROUP_ICON : RT_GROUP_CURSOR));
809
810 /* We let FindResource, LoadResource, etc. call SetLastError */
811 if(!hrsrc)
812 goto done;
813
814 handle = LoadResource(hinst, hrsrc);
815 if(!handle)
816 goto done;
817
818 dir = LockResource(handle);
819 if(!dir)
820 goto done;
821
822 wResId = LookupIconIdFromDirectoryEx((PBYTE)dir, bIcon, cxDesired, cyDesired, fuLoad & LR_MONOCHROME);
823 FreeResource(handle);
824
825 /* Get the relevant resource pointer */
826 hrsrc = FindResourceW(
827 hinst,
828 MAKEINTRESOURCEW(wResId),
829 (LPWSTR)(bIcon ? RT_ICON : RT_CURSOR));
830 if(!hrsrc)
831 goto done;
832
833 handle = LoadResource(hinst, hrsrc);
834 if(!handle)
835 goto done;
836
837 bits = LockResource(handle);
838 if(!bits)
839 {
840 FreeResource(handle);
841 goto done;
842 }
843
844 /* Get the hotspot */
845 if(bIcon)
846 {
847 ii.xHotspot = cxDesired/2;
848 ii.yHotspot = cyDesired/2;
849 }
850 if(!bIcon)
851 {
852 SHORT* ptr = (SHORT*)bits;
853 ii.xHotspot = ptr[0];
854 ii.yHotspot = ptr[1];
855 bits += 2*sizeof(SHORT);
856 }
857 ii.fIcon = bIcon;
858
859 /* Get the bitmaps */
860 bStatus = CURSORICON_GetIconInfoFromBMI(
861 &ii,
862 (BITMAPINFO*)bits,
863 cxDesired,
864 cyDesired);
865
866 FreeResource( handle );
867
868 if(!bStatus)
869 goto done;
870
871 /* Create the handle */
872 hCurIcon = NtUserxCreateEmptyCurObject(bIcon ? 0 : 1);
873 if(!hCurIcon)
874 {
875 DeleteObject(ii.hbmMask);
876 if(ii.hbmColor) DeleteObject(ii.hbmColor);
877 goto done;
878 }
879
880 /* Tell win32k */
881 if(fuLoad & LR_SHARED)
882 bStatus = NtUserSetCursorIconData(hCurIcon, &ustrModule, &ustrRsrc, &ii);
883 else
884 bStatus = NtUserSetCursorIconData(hCurIcon, NULL, NULL, &ii);
885
886 if(!bStatus)
887 {
888 NtUserDestroyCursor(hCurIcon, TRUE);
889 hCurIcon = NULL;
890 }
891
892 DeleteObject(ii.hbmMask);
893 if(ii.hbmColor) DeleteObject(ii.hbmColor);
894
895 done:
896 if(ustrModule.Buffer)
897 HeapFree(GetProcessHeap(), 0, ustrModule.Buffer);
898 return hCurIcon;
899 }
900
901 static
902 HBITMAP
903 BITMAP_CopyImage(
904 _In_ HBITMAP hbmp,
905 _In_ int cxDesired,
906 _In_ int cyDesired,
907 _In_ UINT fuFlags
908 )
909 {
910 HBITMAP res = NULL;
911 DIBSECTION ds;
912 int objSize;
913 BITMAPINFO * bi;
914
915 objSize = GetObjectW( hbmp, sizeof(ds), &ds );
916 if (!objSize) return 0;
917 if ((cxDesired < 0) || (cyDesired < 0)) return 0;
918
919 if (fuFlags & LR_COPYFROMRESOURCE)
920 {
921 FIXME("The flag LR_COPYFROMRESOURCE is not implemented for bitmaps\n");
922 }
923
924 if (fuFlags & LR_COPYRETURNORG)
925 {
926 FIXME("The flag LR_COPYRETURNORG is not implemented for bitmaps\n");
927 }
928
929 if (cxDesired == 0) cxDesired = ds.dsBm.bmWidth;
930 if (cyDesired == 0) cyDesired = ds.dsBm.bmHeight;
931
932 /* Allocate memory for a BITMAPINFOHEADER structure and a
933 color table. The maximum number of colors in a color table
934 is 256 which corresponds to a bitmap with depth 8.
935 Bitmaps with higher depths don't have color tables. */
936 bi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
937 if (!bi) return 0;
938
939 bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
940 bi->bmiHeader.biPlanes = ds.dsBm.bmPlanes;
941 bi->bmiHeader.biBitCount = ds.dsBm.bmBitsPixel;
942 bi->bmiHeader.biCompression = BI_RGB;
943
944 if (fuFlags & LR_CREATEDIBSECTION)
945 {
946 /* Create a DIB section. LR_MONOCHROME is ignored */
947 void * bits;
948 HDC dc = CreateCompatibleDC(NULL);
949
950 if (objSize == sizeof(DIBSECTION))
951 {
952 /* The source bitmap is a DIB.
953 Get its attributes to create an exact copy */
954 memcpy(bi, &ds.dsBmih, sizeof(BITMAPINFOHEADER));
955 }
956
957 /* Get the color table or the color masks */
958 GetDIBits(dc, hbmp, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
959
960 bi->bmiHeader.biWidth = cxDesired;
961 bi->bmiHeader.biHeight = cyDesired;
962 bi->bmiHeader.biSizeImage = 0;
963
964 res = CreateDIBSection(dc, bi, DIB_RGB_COLORS, &bits, NULL, 0);
965 DeleteDC(dc);
966 }
967 else
968 {
969 /* Create a device-dependent bitmap */
970
971 BOOL monochrome = (fuFlags & LR_MONOCHROME);
972
973 if (objSize == sizeof(DIBSECTION))
974 {
975 /* The source bitmap is a DIB section.
976 Get its attributes */
977 HDC dc = CreateCompatibleDC(NULL);
978 bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
979 bi->bmiHeader.biBitCount = ds.dsBm.bmBitsPixel;
980 GetDIBits(dc, hbmp, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
981 DeleteDC(dc);
982
983 if (!monochrome && ds.dsBm.bmBitsPixel == 1)
984 {
985 /* Look if the colors of the DIB are black and white */
986
987 monochrome =
988 (bi->bmiColors[0].rgbRed == 0xff
989 && bi->bmiColors[0].rgbGreen == 0xff
990 && bi->bmiColors[0].rgbBlue == 0xff
991 && bi->bmiColors[0].rgbReserved == 0
992 && bi->bmiColors[1].rgbRed == 0
993 && bi->bmiColors[1].rgbGreen == 0
994 && bi->bmiColors[1].rgbBlue == 0
995 && bi->bmiColors[1].rgbReserved == 0)
996 ||
997 (bi->bmiColors[0].rgbRed == 0
998 && bi->bmiColors[0].rgbGreen == 0
999 && bi->bmiColors[0].rgbBlue == 0
1000 && bi->bmiColors[0].rgbReserved == 0
1001 && bi->bmiColors[1].rgbRed == 0xff
1002 && bi->bmiColors[1].rgbGreen == 0xff
1003 && bi->bmiColors[1].rgbBlue == 0xff
1004 && bi->bmiColors[1].rgbReserved == 0);
1005 }
1006 }
1007 else if (!monochrome)
1008 {
1009 monochrome = ds.dsBm.bmBitsPixel == 1;
1010 }
1011
1012 if (monochrome)
1013 {
1014 res = CreateBitmap(cxDesired, cyDesired, 1, 1, NULL);
1015 }
1016 else
1017 {
1018 HDC screenDC = GetDC(NULL);
1019 res = CreateCompatibleBitmap(screenDC, cxDesired, cyDesired);
1020 ReleaseDC(NULL, screenDC);
1021 }
1022 }
1023
1024 if (res)
1025 {
1026 /* Only copy the bitmap if it's a DIB section or if it's
1027 compatible to the screen */
1028 BOOL copyContents;
1029
1030 if (objSize == sizeof(DIBSECTION))
1031 {
1032 copyContents = TRUE;
1033 }
1034 else
1035 {
1036 HDC screenDC = GetDC(NULL);
1037 int screen_depth = GetDeviceCaps(screenDC, BITSPIXEL);
1038 ReleaseDC(NULL, screenDC);
1039
1040 copyContents = (ds.dsBm.bmBitsPixel == 1 || ds.dsBm.bmBitsPixel == screen_depth);
1041 }
1042
1043 if (copyContents)
1044 {
1045 /* The source bitmap may already be selected in a device context,
1046 use GetDIBits/StretchDIBits and not StretchBlt */
1047
1048 HDC dc;
1049 void * bits;
1050
1051 dc = CreateCompatibleDC(NULL);
1052
1053 bi->bmiHeader.biWidth = ds.dsBm.bmWidth;
1054 bi->bmiHeader.biHeight = ds.dsBm.bmHeight;
1055 bi->bmiHeader.biSizeImage = 0;
1056 bi->bmiHeader.biClrUsed = 0;
1057 bi->bmiHeader.biClrImportant = 0;
1058
1059 /* Fill in biSizeImage */
1060 GetDIBits(dc, hbmp, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
1061 bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bi->bmiHeader.biSizeImage);
1062
1063 if (bits)
1064 {
1065 HBITMAP oldBmp;
1066
1067 /* Get the image bits of the source bitmap */
1068 GetDIBits(dc, hbmp, 0, ds.dsBm.bmHeight, bits, bi, DIB_RGB_COLORS);
1069
1070 /* Copy it to the destination bitmap */
1071 oldBmp = SelectObject(dc, res);
1072 StretchDIBits(dc, 0, 0, cxDesired, cyDesired,
1073 0, 0, ds.dsBm.bmWidth, ds.dsBm.bmHeight,
1074 bits, bi, DIB_RGB_COLORS, SRCCOPY);
1075 SelectObject(dc, oldBmp);
1076
1077 HeapFree(GetProcessHeap(), 0, bits);
1078 }
1079
1080 DeleteDC(dc);
1081 }
1082
1083 if (fuFlags & LR_COPYDELETEORG)
1084 {
1085 DeleteObject(hbmp);
1086 }
1087 }
1088 HeapFree(GetProcessHeap(), 0, bi);
1089 return res;
1090 }
1091
1092 static
1093 HICON
1094 CURSORICON_CopyImage(
1095 _In_ HICON hicon,
1096 _In_ BOOL bIcon,
1097 _In_ int cxDesired,
1098 _In_ int cyDesired,
1099 _In_ UINT fuFlags
1100 )
1101 {
1102 HICON ret = NULL;
1103 ICONINFO ii;
1104
1105 if(fuFlags & LR_COPYFROMRESOURCE)
1106 {
1107 /* Get the icon module/resource names */
1108 UNICODE_STRING ustrModule;
1109 UNICODE_STRING ustrRsrc;
1110 PVOID pvBuf;
1111 HMODULE hModule;
1112
1113 ustrModule.MaximumLength = MAX_PATH;
1114 ustrRsrc.MaximumLength = 256;
1115
1116 ustrModule.Buffer = HeapAlloc(GetProcessHeap(), 0, ustrModule.MaximumLength * sizeof(WCHAR));
1117 if(!ustrModule.Buffer)
1118 {
1119 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1120 return NULL;
1121 }
1122 /* Keep track of the buffer for the resource, NtUserGetIconInfo might overwrite it */
1123 pvBuf = HeapAlloc(GetProcessHeap(), 0, 256 * sizeof(WCHAR));
1124 if(!pvBuf)
1125 {
1126 HeapFree(GetProcessHeap(), 0, ustrModule.Buffer);
1127 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1128 return NULL;
1129 }
1130 ustrRsrc.Buffer = pvBuf;
1131
1132 do
1133 {
1134 if(!NtUserGetIconInfo(hicon, NULL, &ustrModule, &ustrRsrc, NULL, FALSE))
1135 {
1136 HeapFree(GetProcessHeap(), 0, ustrModule.Buffer);
1137 HeapFree(GetProcessHeap(), 0, pvBuf);
1138 return NULL;
1139 }
1140
1141 if((ustrModule.Length < ustrModule.MaximumLength) && (ustrRsrc.Length < ustrRsrc.MaximumLength))
1142 {
1143 /* Buffers were big enough */
1144 break;
1145 }
1146
1147 /* Find which buffer were too small */
1148 if(ustrModule.Length == ustrModule.MaximumLength)
1149 {
1150 PWSTR newBuffer;
1151 ustrModule.MaximumLength *= 2;
1152 newBuffer = HeapReAlloc(GetProcessHeap(), 0, ustrModule.Buffer, ustrModule.MaximumLength * sizeof(WCHAR));
1153 if(!ustrModule.Buffer)
1154 {
1155 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1156 goto leave;
1157 }
1158 ustrModule.Buffer = newBuffer;
1159 }
1160
1161 if(ustrRsrc.Length == ustrRsrc.MaximumLength)
1162 {
1163 ustrRsrc.MaximumLength *= 2;
1164 pvBuf = HeapReAlloc(GetProcessHeap(), 0, ustrRsrc.Buffer, ustrRsrc.MaximumLength * sizeof(WCHAR));
1165 if(!pvBuf)
1166 {
1167 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1168 goto leave;
1169 }
1170 ustrRsrc.Buffer = pvBuf;
1171 }
1172 } while(TRUE);
1173
1174 /* NULL-terminate our strings */
1175 ustrModule.Buffer[ustrModule.Length] = 0;
1176 if(!IS_INTRESOURCE(ustrRsrc.Buffer))
1177 ustrRsrc.Buffer[ustrRsrc.Length] = 0;
1178
1179 /* Get the module handle */
1180 if(!GetModuleHandleExW(0, ustrModule.Buffer, &hModule))
1181 {
1182 /* This hould never happen */
1183 SetLastError(ERROR_INVALID_PARAMETER);
1184 goto leave;
1185 }
1186
1187 /* Call the relevant function */
1188 ret = CURSORICON_LoadImageW(hModule, ustrRsrc.Buffer, cxDesired, cyDesired, bIcon, fuFlags & LR_DEFAULTSIZE);
1189
1190 FreeLibrary(hModule);
1191
1192 /* If we're here, that means that the passed icon is shared. Don't destroy it, even if LR_COPYDELETEORG is specified */
1193 leave:
1194 HeapFree(GetProcessHeap(), 0, ustrModule.Buffer);
1195 HeapFree(GetProcessHeap(), 0, pvBuf);
1196
1197 return ret;
1198 }
1199
1200 /* This is a regular copy */
1201 if(fuFlags & ~LR_COPYDELETEORG)
1202 FIXME("Unimplemented flags: 0x%08x\n", fuFlags);
1203
1204 if(!GetIconInfo(hicon, &ii))
1205 {
1206 ERR("GetIconInfo failed.\n");
1207 return NULL;
1208 }
1209
1210 ret = CreateIconIndirect(&ii);
1211
1212 DeleteObject(ii.hbmMask);
1213 if(ii.hbmColor) DeleteObject(ii.hbmColor);
1214
1215 if(ret && (fuFlags & LR_COPYDELETEORG))
1216 DestroyIcon(hicon);
1217
1218 return hicon;
1219 }
1220
1221 /************* PUBLIC FUNCTIONS *******************/
1222
1223 HANDLE WINAPI CopyImage(
1224 _In_ HANDLE hImage,
1225 _In_ UINT uType,
1226 _In_ int cxDesired,
1227 _In_ int cyDesired,
1228 _In_ UINT fuFlags
1229 )
1230 {
1231 TRACE("hImage=%p, uType=%u, cxDesired=%d, cyDesired=%d, fuFlags=%x\n",
1232 hImage, uType, cxDesired, cyDesired, fuFlags);
1233 switch(uType)
1234 {
1235 case IMAGE_BITMAP:
1236 return BITMAP_CopyImage(hImage, cxDesired, cyDesired, fuFlags);
1237 case IMAGE_CURSOR:
1238 case IMAGE_ICON:
1239 return CURSORICON_CopyImage(hImage, uType == IMAGE_ICON, cxDesired, cyDesired, fuFlags);
1240 default:
1241 SetLastError(ERROR_INVALID_PARAMETER);
1242 break;
1243 }
1244 return NULL;
1245 }
1246
1247 HICON WINAPI CopyIcon(
1248 _In_ HICON hIcon
1249 )
1250 {
1251 UNIMPLEMENTED;
1252 return NULL;
1253 }
1254
1255 BOOL WINAPI DrawIcon(
1256 _In_ HDC hDC,
1257 _In_ int X,
1258 _In_ int Y,
1259 _In_ HICON hIcon
1260 )
1261 {
1262 return DrawIconEx(hDC, X, Y, hIcon, 0, 0, 0, NULL, DI_NORMAL | DI_COMPAT | DI_DEFAULTSIZE);
1263 }
1264
1265 BOOL WINAPI DrawIconEx(
1266 _In_ HDC hdc,
1267 _In_ int xLeft,
1268 _In_ int yTop,
1269 _In_ HICON hIcon,
1270 _In_ int cxWidth,
1271 _In_ int cyWidth,
1272 _In_ UINT istepIfAniCur,
1273 _In_opt_ HBRUSH hbrFlickerFreeDraw,
1274 _In_ UINT diFlags
1275 )
1276 {
1277 return NtUserDrawIconEx(hdc, xLeft, yTop, hIcon, cxWidth, cyWidth,
1278 istepIfAniCur, hbrFlickerFreeDraw, diFlags,
1279 0, 0);
1280 }
1281
1282 BOOL WINAPI GetIconInfo(
1283 _In_ HICON hIcon,
1284 _Out_ PICONINFO piconinfo
1285 )
1286 {
1287 return NtUserGetIconInfo(hIcon, piconinfo, NULL, NULL, NULL, FALSE);
1288 }
1289
1290 BOOL WINAPI DestroyIcon(
1291 _In_ HICON hIcon
1292 )
1293 {
1294 return NtUserDestroyCursor(hIcon, FALSE);
1295 }
1296
1297 HICON WINAPI LoadIconA(
1298 _In_opt_ HINSTANCE hInstance,
1299 _In_ LPCSTR lpIconName
1300 )
1301 {
1302 TRACE("%p, %s\n", hInstance, debugstr_a(lpIconName));
1303
1304 return LoadImageA(hInstance,
1305 lpIconName,
1306 IMAGE_ICON,
1307 0,
1308 0,
1309 LR_SHARED | LR_DEFAULTSIZE );
1310 }
1311
1312 HICON WINAPI LoadIconW(
1313 _In_opt_ HINSTANCE hInstance,
1314 _In_ LPCWSTR lpIconName
1315 )
1316 {
1317 TRACE("%p, %s\n", hInstance, debugstr_w(lpIconName));
1318
1319 return LoadImageW(hInstance,
1320 lpIconName,
1321 IMAGE_ICON,
1322 0,
1323 0,
1324 LR_SHARED | LR_DEFAULTSIZE );
1325 }
1326
1327 HCURSOR WINAPI LoadCursorA(
1328 _In_opt_ HINSTANCE hInstance,
1329 _In_ LPCSTR lpCursorName
1330 )
1331 {
1332 TRACE("%p, %s\n", hInstance, debugstr_a(lpCursorName));
1333
1334 return LoadImageA(hInstance,
1335 lpCursorName,
1336 IMAGE_CURSOR,
1337 0,
1338 0,
1339 LR_SHARED | LR_DEFAULTSIZE );
1340 }
1341
1342 HCURSOR WINAPI LoadCursorW(
1343 _In_opt_ HINSTANCE hInstance,
1344 _In_ LPCWSTR lpCursorName
1345 )
1346 {
1347 TRACE("%p, %s\n", hInstance, debugstr_w(lpCursorName));
1348
1349 return LoadImageW(hInstance,
1350 lpCursorName,
1351 IMAGE_CURSOR,
1352 0,
1353 0,
1354 LR_SHARED | LR_DEFAULTSIZE );
1355 }
1356
1357 HCURSOR WINAPI LoadCursorFromFileA(
1358 _In_ LPCSTR lpFileName
1359 )
1360 {
1361 TRACE("%s\n", debugstr_a(lpFileName));
1362
1363 return LoadImageA(NULL,
1364 lpFileName,
1365 IMAGE_CURSOR,
1366 0,
1367 0,
1368 LR_LOADFROMFILE | LR_DEFAULTSIZE );
1369 }
1370
1371 HCURSOR WINAPI LoadCursorFromFileW(
1372 _In_ LPCWSTR lpFileName
1373 )
1374 {
1375 TRACE("%s\n", debugstr_w(lpFileName));
1376
1377 return LoadImageW(NULL,
1378 lpFileName,
1379 IMAGE_CURSOR,
1380 0,
1381 0,
1382 LR_LOADFROMFILE | LR_DEFAULTSIZE );
1383 }
1384
1385 HBITMAP WINAPI LoadBitmapA(
1386 _In_opt_ HINSTANCE hInstance,
1387 _In_ LPCSTR lpBitmapName
1388 )
1389 {
1390 TRACE("%p, %s\n", hInstance, debugstr_a(lpBitmapName));
1391
1392 return LoadImageA(hInstance,
1393 lpBitmapName,
1394 IMAGE_BITMAP,
1395 0,
1396 0,
1397 0);
1398 }
1399
1400 HBITMAP WINAPI LoadBitmapW(
1401 _In_opt_ HINSTANCE hInstance,
1402 _In_ LPCWSTR lpBitmapName
1403 )
1404 {
1405 TRACE("%p, %s\n", hInstance, debugstr_w(lpBitmapName));
1406
1407 return LoadImageW(hInstance,
1408 lpBitmapName,
1409 IMAGE_BITMAP,
1410 0,
1411 0,
1412 0);
1413 }
1414
1415 HANDLE WINAPI LoadImageA(
1416 _In_opt_ HINSTANCE hinst,
1417 _In_ LPCSTR lpszName,
1418 _In_ UINT uType,
1419 _In_ int cxDesired,
1420 _In_ int cyDesired,
1421 _In_ UINT fuLoad
1422 )
1423 {
1424 HANDLE res;
1425 LPWSTR u_name;
1426 DWORD len;
1427
1428 if (IS_INTRESOURCE(lpszName))
1429 return LoadImageW(hinst, (LPCWSTR)lpszName, uType, cxDesired, cyDesired, fuLoad);
1430
1431 len = MultiByteToWideChar( CP_ACP, 0, lpszName, -1, NULL, 0 );
1432 u_name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
1433 MultiByteToWideChar( CP_ACP, 0, lpszName, -1, u_name, len );
1434
1435 res = LoadImageW(hinst, u_name, uType, cxDesired, cyDesired, fuLoad);
1436 HeapFree(GetProcessHeap(), 0, u_name);
1437 return res;
1438 }
1439
1440 HANDLE WINAPI LoadImageW(
1441 _In_opt_ HINSTANCE hinst,
1442 _In_ LPCWSTR lpszName,
1443 _In_ UINT uType,
1444 _In_ int cxDesired,
1445 _In_ int cyDesired,
1446 _In_ UINT fuLoad
1447 )
1448 {
1449 /* Redirect to each implementation */
1450 switch(uType)
1451 {
1452 case IMAGE_BITMAP:
1453 return BITMAP_LoadImageW(hinst, lpszName, cxDesired, cyDesired, fuLoad);
1454 case IMAGE_CURSOR:
1455 case IMAGE_ICON:
1456 return CURSORICON_LoadImageW(hinst, lpszName, cxDesired, cyDesired, fuLoad, uType == IMAGE_ICON);
1457 default:
1458 SetLastError(ERROR_INVALID_PARAMETER);
1459 break;
1460 }
1461 return NULL;
1462 }
1463
1464 int WINAPI LookupIconIdFromDirectory(
1465 _In_ PBYTE presbits,
1466 _In_ BOOL fIcon
1467 )
1468 {
1469 return LookupIconIdFromDirectoryEx( presbits, fIcon,
1470 fIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
1471 fIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), fIcon ? 0 : LR_MONOCHROME );
1472 }
1473
1474 int WINAPI LookupIconIdFromDirectoryEx(
1475 _In_ PBYTE presbits,
1476 _In_ BOOL fIcon,
1477 _In_ int cxDesired,
1478 _In_ int cyDesired,
1479 _In_ UINT Flags
1480 )
1481 {
1482 WORD bppDesired;
1483 CURSORICONDIR* dir = (CURSORICONDIR*)presbits;
1484 CURSORICONDIRENTRY* entry;
1485 int i, numMatch, iIndex = -1;
1486 WORD width, height;
1487 USHORT bitcount;
1488 ULONG cxyDiff, cxyDiffTmp;
1489
1490 TRACE("%p, %x, %i, %i, %x.\n", presbits, fIcon, cxDesired, cyDesired, Flags);
1491
1492 if(!(dir && !dir->idReserved && (dir->idType & 3)))
1493 {
1494 WARN("Invalid resource.\n");
1495 return 0;
1496 }
1497
1498 /* idType == 2 is for cursors, 1 for icons */
1499 /*if(fIcon)
1500 {
1501 if(dir->idType == 2)
1502 {
1503 WARN("An icon was asked for a cursor resource.\n");
1504 return 0;
1505 }
1506 }
1507 else if(dir->idType == 1)
1508 {
1509 WARN("A cursor was asked for an icon resource.\n");
1510 return 0;
1511 }*/
1512
1513 if(Flags & LR_MONOCHROME)
1514 bppDesired = 1;
1515 else
1516 {
1517 HDC icScreen;
1518 icScreen = CreateICW(DISPLAYW, NULL, NULL, NULL);
1519 if(!icScreen)
1520 return FALSE;
1521
1522 bppDesired = GetDeviceCaps(icScreen, BITSPIXEL);
1523 DeleteDC(icScreen);
1524 }
1525
1526 /* Find the best match for the desired size */
1527 cxyDiff = 0xFFFFFFFF;
1528 numMatch = 0;
1529 for(i = 0; i < dir->idCount; i++)
1530 {
1531 entry = &dir->idEntries[i];
1532 width = fIcon ? entry->ResInfo.icon.bWidth : entry->ResInfo.cursor.wWidth;
1533 /* Height is twice as big in cursor resources */
1534 height = fIcon ? entry->ResInfo.icon.bHeight : entry->ResInfo.cursor.wHeight/2;
1535 /* 0 represents 256 */
1536 if(!width) width = 256;
1537 if(!height) height = 256;
1538 /* Let it be a 1-norm */
1539 cxyDiffTmp = max(abs(width - cxDesired), abs(height - cyDesired));
1540 if( cxyDiffTmp > cxyDiff)
1541 continue;
1542 if( cxyDiffTmp == cxyDiff)
1543 {
1544 numMatch++;
1545 continue;
1546 }
1547 iIndex = i;
1548 numMatch = 1;
1549 cxyDiff = cxyDiffTmp;
1550 }
1551
1552 if(numMatch == 1)
1553 {
1554 /* Only one entry fit the asked dimensions */
1555 return dir->idEntries[iIndex].wResId;
1556 }
1557
1558 bitcount = 0;
1559 iIndex = -1;
1560 /* Now find the entry with the best depth */
1561 for(i = 0; i < dir->idCount; i++)
1562 {
1563 entry = &dir->idEntries[i];
1564 width = fIcon ? entry->ResInfo.icon.bWidth : entry->ResInfo.cursor.wWidth;
1565 height = fIcon ? entry->ResInfo.icon.bHeight : entry->ResInfo.cursor.wHeight/2;
1566 /* 0 represents 256 */
1567 if(!width) width = 256;
1568 if(!height) height = 256;
1569 /* Check if this is the best match we had */
1570 cxyDiffTmp = max(abs(width - cxDesired), abs(height - cyDesired));
1571 if(cxyDiffTmp != cxyDiff)
1572 continue;
1573 /* Exact match? */
1574 if(entry->wBitCount == bppDesired)
1575 return entry->wResId;
1576 /* We take the highest possible but smaller than the display depth */
1577 if((entry->wBitCount > bitcount) && (entry->wBitCount < bppDesired))
1578 {
1579 iIndex = i;
1580 bitcount = entry->wBitCount;
1581 }
1582 }
1583
1584 if(iIndex >= 0)
1585 return dir->idEntries[iIndex].wResId;
1586
1587 /* No inferior or equal depth available. Get the smallest one */
1588 bitcount = 0x7FFF;
1589 for(i = 0; i < dir->idCount; i++)
1590 {
1591 entry = &dir->idEntries[i];
1592 width = fIcon ? entry->ResInfo.icon.bWidth : entry->ResInfo.cursor.wWidth;
1593 height = fIcon ? entry->ResInfo.icon.bHeight : entry->ResInfo.cursor.wHeight/2;
1594 /* 0 represents 256 */
1595 if(!width) width = 256;
1596 if(!height) height = 256;
1597 /* Check if this is the best match we had */
1598 cxyDiffTmp = max(abs(width - cxDesired), abs(height - cyDesired));
1599 if(cxyDiffTmp != cxyDiff)
1600 continue;
1601 /* Check the bit depth */
1602 if(entry->wBitCount < bitcount)
1603 {
1604 iIndex = i;
1605 bitcount = entry->wBitCount;
1606 }
1607 }
1608
1609 return dir->idEntries[iIndex].wResId;
1610 }
1611
1612 HICON WINAPI CreateIcon(
1613 _In_opt_ HINSTANCE hInstance,
1614 _In_ int nWidth,
1615 _In_ int nHeight,
1616 _In_ BYTE cPlanes,
1617 _In_ BYTE cBitsPixel,
1618 _In_ const BYTE *lpbANDbits,
1619 _In_ const BYTE *lpbXORbits
1620 )
1621 {
1622 ICONINFO iinfo;
1623 HICON hIcon;
1624
1625 TRACE_(icon)("%dx%d, planes %d, bpp %d, xor %p, and %p\n",
1626 nWidth, nHeight, cPlanes, cBitsPixel, lpbXORbits, lpbANDbits);
1627
1628 iinfo.fIcon = TRUE;
1629 iinfo.xHotspot = nWidth / 2;
1630 iinfo.yHotspot = nHeight / 2;
1631 if (cPlanes * cBitsPixel > 1)
1632 {
1633 iinfo.hbmColor = CreateBitmap( nWidth, nHeight, cPlanes, cBitsPixel, lpbXORbits );
1634 iinfo.hbmMask = CreateBitmap( nWidth, nHeight, 1, 1, lpbANDbits );
1635 }
1636 else
1637 {
1638 iinfo.hbmMask = CreateBitmap( nWidth, nHeight * 2, 1, 1, lpbANDbits );
1639 iinfo.hbmColor = NULL;
1640 }
1641
1642 hIcon = CreateIconIndirect( &iinfo );
1643
1644 DeleteObject( iinfo.hbmMask );
1645 if (iinfo.hbmColor) DeleteObject( iinfo.hbmColor );
1646
1647 return hIcon;
1648 }
1649
1650 HICON WINAPI CreateIconFromResource(
1651 _In_ PBYTE presbits,
1652 _In_ DWORD dwResSize,
1653 _In_ BOOL fIcon,
1654 _In_ DWORD dwVer
1655 )
1656 {
1657 return CreateIconFromResourceEx( presbits, dwResSize, fIcon, dwVer, 0,0,0);
1658 }
1659
1660 HICON WINAPI CreateIconFromResourceEx(
1661 _In_ PBYTE pbIconBits,
1662 _In_ DWORD cbIconBits,
1663 _In_ BOOL fIcon,
1664 _In_ DWORD dwVersion,
1665 _In_ int cxDesired,
1666 _In_ int cyDesired,
1667 _In_ UINT uFlags
1668 )
1669 {
1670 ICONINFO ii;
1671 HICON hIcon;
1672
1673 if(uFlags)
1674 FIXME("uFlags 0x%08x ignored.\n", uFlags);
1675
1676 if(fIcon)
1677 {
1678 ii.xHotspot = cxDesired/2;
1679 ii.yHotspot = cyDesired/2;
1680 }
1681 else
1682 {
1683 WORD* pt = (WORD*)pbIconBits;
1684 ii.xHotspot = *pt++;
1685 ii.yHotspot = *pt++;
1686 pbIconBits = (PBYTE)pt;
1687 }
1688 ii.fIcon = fIcon;
1689
1690 if(!CURSORICON_GetIconInfoFromBMI(&ii, (BITMAPINFO*)pbIconBits, cxDesired, cyDesired))
1691 return NULL;
1692
1693 hIcon = CreateIconIndirect(&ii);
1694
1695 /* Clean up */
1696 DeleteObject(ii.hbmMask);
1697 if(ii.hbmColor) DeleteObject(ii.hbmColor);
1698
1699 return hIcon;
1700 }
1701
1702 HICON WINAPI CreateIconIndirect(
1703 _In_ PICONINFO piconinfo
1704 )
1705 {
1706 /* As simple as creating a handle, and let win32k deal with the bitmaps */
1707 HICON hiconRet;
1708
1709 TRACE("%p.\n", piconinfo);
1710
1711 hiconRet = NtUserxCreateEmptyCurObject(piconinfo->fIcon ? 0 : 1);
1712 if(!hiconRet)
1713 return NULL;
1714
1715 if(!NtUserSetCursorIconData(hiconRet, NULL, NULL, piconinfo))
1716 {
1717 NtUserDestroyCursor(hiconRet, FALSE);
1718 hiconRet = NULL;
1719 }
1720
1721 TRACE("Returning 0x%08x.\n", hiconRet);
1722
1723 return hiconRet;
1724 }
1725
1726 HCURSOR WINAPI CreateCursor(
1727 _In_opt_ HINSTANCE hInst,
1728 _In_ int xHotSpot,
1729 _In_ int yHotSpot,
1730 _In_ int nWidth,
1731 _In_ int nHeight,
1732 _In_ const VOID *pvANDPlane,
1733 _In_ const VOID *pvXORPlane
1734 )
1735 {
1736 ICONINFO info;
1737 HCURSOR hCursor;
1738
1739 TRACE_(cursor)("%dx%d spot=%d,%d xor=%p and=%p\n",
1740 nWidth, nHeight, xHotSpot, yHotSpot, pvXORPlane, pvANDPlane);
1741
1742 info.fIcon = FALSE;
1743 info.xHotspot = xHotSpot;
1744 info.yHotspot = yHotSpot;
1745 info.hbmMask = CreateBitmap( nWidth, nHeight, 1, 1, pvANDPlane );
1746 info.hbmColor = CreateBitmap( nWidth, nHeight, 1, 1, pvXORPlane );
1747 hCursor = CreateIconIndirect( &info );
1748 DeleteObject( info.hbmMask );
1749 DeleteObject( info.hbmColor );
1750 return hCursor;
1751 }
1752
1753 BOOL WINAPI SetSystemCursor(
1754 _In_ HCURSOR hcur,
1755 _In_ DWORD id
1756 )
1757 {
1758 UNIMPLEMENTED;
1759 return FALSE;
1760 }
1761
1762 BOOL WINAPI SetCursorPos(
1763 _In_ int X,
1764 _In_ int Y
1765 )
1766 {
1767 UNIMPLEMENTED;
1768 return FALSE;
1769 }
1770
1771 BOOL WINAPI GetCursorPos(
1772 _Out_ LPPOINT lpPoint
1773 )
1774 {
1775 return NtUserxGetCursorPos(lpPoint);
1776 }
1777
1778 int WINAPI ShowCursor(
1779 _In_ BOOL bShow
1780 )
1781 {
1782 UNIMPLEMENTED;
1783 return -1;
1784 }
1785
1786 HCURSOR WINAPI GetCursor(void)
1787 {
1788 UNIMPLEMENTED;
1789 return NULL;
1790 }
1791
1792 BOOL WINAPI DestroyCursor(
1793 _In_ HCURSOR hCursor
1794 )
1795 {
1796 return NtUserDestroyCursor(hCursor, FALSE);
1797 }