d622d563e242a44ecd5934c47dafc12d5d5d45c8
[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/cursoricon.c
5 * PURPOSE: cursor and icons implementation
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 /***********************************************************************
175 * bmi_has_alpha
176 */
177 static BOOL bmi_has_alpha( const BITMAPINFO *info, const void *bits )
178 {
179 int i;
180 BOOL has_alpha = FALSE;
181 const unsigned char *ptr = bits;
182
183 if (info->bmiHeader.biBitCount != 32) return FALSE;
184 for (i = 0; i < info->bmiHeader.biWidth * abs(info->bmiHeader.biHeight); i++, ptr += 4)
185 if ((has_alpha = (ptr[3] != 0))) break;
186 return has_alpha;
187 }
188
189 /***********************************************************************
190 * create_alpha_bitmap
191 *
192 * Create the alpha bitmap for a 32-bpp icon that has an alpha channel.
193 */
194 static HBITMAP create_alpha_bitmap(
195 _In_ HBITMAP color,
196 _In_opt_ const BITMAPINFO *src_info,
197 _In_opt_ const void *color_bits )
198 {
199 HBITMAP alpha = NULL, hbmpOld;
200 BITMAPINFO *info = NULL;
201 HDC hdc = NULL, hdcScreen;
202 void *bits = NULL;
203 unsigned char *ptr;
204 int i;
205 LONG width, height;
206 BITMAP bm;
207
208 if (!GetObjectW( color, sizeof(bm), &bm ))
209 return NULL;
210 if (bm.bmBitsPixel != 32)
211 return NULL;
212
213 hdcScreen = CreateDCW(DISPLAYW, NULL, NULL, NULL);
214 if(!hdcScreen)
215 return NULL;
216 if(GetDeviceCaps(hdcScreen, BITSPIXEL) != 32)
217 goto done;
218 hdc = CreateCompatibleDC(hdcScreen);
219 if(!hdc)
220 goto done;
221
222 if(src_info)
223 {
224 WORD bpp;
225 DWORD compr;
226 int size;
227
228 if(!bmi_has_alpha(src_info, color_bits))
229 goto done;
230
231 if(!DIB_GetBitmapInfo(&src_info->bmiHeader, &width, &height, &bpp, &compr))
232 goto done;
233 if(bpp != 32)
234 goto done;
235
236 size = get_dib_image_size(width, height, bpp);
237 bits = HeapAlloc(GetProcessHeap(), 0, size);
238 if(!bits)
239 goto done;
240 CopyMemory(bits, color_bits, size);
241 }
242 else
243 {
244 info = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(BITMAPINFO, bmiColors[256]));
245 if(!info)
246 goto done;
247 info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
248 info->bmiHeader.biWidth = bm.bmWidth;
249 info->bmiHeader.biHeight = -bm.bmHeight;
250 info->bmiHeader.biPlanes = 1;
251 info->bmiHeader.biBitCount = 32;
252 info->bmiHeader.biCompression = BI_RGB;
253 info->bmiHeader.biSizeImage = bm.bmWidth * bm.bmHeight * 4;
254 info->bmiHeader.biXPelsPerMeter = 0;
255 info->bmiHeader.biYPelsPerMeter = 0;
256 info->bmiHeader.biClrUsed = 0;
257 info->bmiHeader.biClrImportant = 0;
258
259 bits = HeapAlloc(GetProcessHeap(), 0, info->bmiHeader.biSizeImage);
260 if(!bits)
261 goto done;
262 if(!GetDIBits( hdc, color, 0, bm.bmHeight, bits, info, DIB_RGB_COLORS ))
263 goto done;
264 if (!bmi_has_alpha( info, bits ))
265 goto done;
266 width = bm.bmWidth;
267 height = bm.bmHeight;
268 }
269
270 /* pre-multiply by alpha */
271 for (i = 0, ptr = bits; i < width * height; i++, ptr += 4)
272 {
273 unsigned int alpha = ptr[3];
274 ptr[0] = ptr[0] * alpha / 255;
275 ptr[1] = ptr[1] * alpha / 255;
276 ptr[2] = ptr[2] * alpha / 255;
277 }
278
279 /* Create the bitmap */
280 alpha = CreateCompatibleBitmap(hdcScreen, bm.bmWidth, bm.bmHeight);
281 if(!alpha)
282 goto done;
283 hbmpOld = SelectObject(hdc, alpha);
284 if(!hbmpOld)
285 goto done;
286 if(!StretchDIBits( hdc, 0, 0, bm.bmWidth, bm.bmHeight,
287 0, 0, width, height,
288 bits, src_info ? src_info : info, DIB_RGB_COLORS, SRCCOPY ))
289 {
290 SelectObject(hdc, hbmpOld);
291 hbmpOld = NULL;
292 DeleteObject(alpha);
293 alpha = NULL;
294 }
295 SelectObject(hdc, hbmpOld);
296
297 done:
298 DeleteDC(hdcScreen);
299 if(hdc) DeleteDC( hdc );
300 if(info) HeapFree( GetProcessHeap(), 0, info );
301 if(bits) HeapFree(GetProcessHeap(), 0, bits);
302
303 TRACE("Returning 0x%08x.\n", alpha);
304 return alpha;
305 }
306
307 /************* IMPLEMENTATION CORE ****************/
308
309 static BOOL CURSORICON_GetCursorDataFromBMI(
310 _Inout_ CURSORDATA* pdata,
311 _In_ const BITMAPINFO *pbmi
312 )
313 {
314 UINT ubmiSize = bitmap_info_size(pbmi, DIB_RGB_COLORS);
315 BOOL monochrome = is_dib_monochrome(pbmi);
316 LONG width, height;
317 WORD bpp;
318 DWORD compr;
319 int ibmpType;
320 HDC hdc, hdcScreen;
321 BITMAPINFO* pbmiCopy;
322 HBITMAP hbmpOld = NULL;
323 BOOL bResult = FALSE;
324 const VOID *pvColor, *pvMask;
325
326 ibmpType = DIB_GetBitmapInfo(&pbmi->bmiHeader, &width, &height, &bpp, &compr);
327 /* Invalid data */
328 if(ibmpType < 0)
329 return FALSE;
330
331 /* No compression for icons */
332 if(compr != BI_RGB)
333 return FALSE;
334
335 /* If no dimensions were set, use the one from the icon */
336 if(!pdata->cx) pdata->cx = width;
337 if(!pdata->cy) pdata->cy = height < 0 ? -height/2 : height/2;
338
339 /* Fix the hotspot coords */
340 if(pdata->rt == (USHORT)((ULONG_PTR)RT_CURSOR))
341 {
342 if(pdata->cx != width)
343 pdata->xHotspot = (pdata->xHotspot * pdata->cx) / width;
344 if(pdata->cy != height/2)
345 pdata->yHotspot = (pdata->yHotspot * pdata->cy * 2) / height;
346 }
347 else
348 {
349 pdata->xHotspot = pdata->cx/2;
350 pdata->yHotspot = pdata->cy/2;
351 }
352
353 hdcScreen = CreateDCW(DISPLAYW, NULL, NULL, NULL);
354 if(!hdcScreen)
355 return FALSE;
356 hdc = CreateCompatibleDC(hdcScreen);
357 if(!hdc)
358 {
359 DeleteDC(hdcScreen);
360 return FALSE;
361 }
362
363 pbmiCopy = HeapAlloc(GetProcessHeap(), 0, max(ubmiSize, FIELD_OFFSET(BITMAPINFO, bmiColors[3])));
364 if(!pbmiCopy)
365 goto done;
366 RtlCopyMemory(pbmiCopy, pbmi, ubmiSize);
367
368 /* In an icon/cursor, the BITMAPINFO holds twice the height */
369 if(pbmiCopy->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
370 ((BITMAPCOREHEADER*)&pbmiCopy->bmiHeader)->bcHeight /= 2;
371 else
372 pbmiCopy->bmiHeader.biHeight /= 2;
373 height /= 2;
374
375 pvColor = (const char*)pbmi + ubmiSize;
376 pvMask = (const char*)pvColor +
377 get_dib_image_size(width, height, bpp );
378
379 /* Set XOR bits */
380 if(monochrome)
381 {
382 /* Create the 1bpp bitmap which will contain everything */
383 pdata->hbmColor = NULL;
384 pdata->hbmMask = CreateBitmap(pdata->cx, pdata->cy * 2, 1, 1, NULL);
385 if(!pdata->hbmMask)
386 goto done;
387 hbmpOld = SelectObject(hdc, pdata->hbmMask);
388 if(!hbmpOld)
389 goto done;
390
391 if(!StretchDIBits(hdc, 0, pdata->cy, pdata->cx, pdata->cy,
392 0, 0, width, height,
393 pvColor, pbmiCopy, DIB_RGB_COLORS, SRCCOPY))
394 goto done;
395 pdata->bpp = 1;
396 }
397 else
398 {
399 /* Create the bitmap. It has to be compatible with the screen surface */
400 pdata->hbmColor = CreateCompatibleBitmap(hdcScreen, pdata->cx, pdata->cy);
401 if(!pdata->hbmColor)
402 goto done;
403 /* Create the 1bpp mask bitmap */
404 pdata->hbmMask = CreateBitmap(pdata->cx, pdata->cy, 1, 1, NULL);
405 if(!pdata->hbmMask)
406 goto done;
407 hbmpOld = SelectObject(hdc, pdata->hbmColor);
408 if(!hbmpOld)
409 goto done;
410 if(!StretchDIBits(hdc, 0, 0, pdata->cx, pdata->cy,
411 0, 0, width, height,
412 pvColor, pbmiCopy, DIB_RGB_COLORS, SRCCOPY))
413 goto done;
414 pdata->bpp = GetDeviceCaps(hdcScreen, BITSPIXEL);
415 if(pdata->bpp == 32)
416 pdata->hbmAlpha = create_alpha_bitmap(pdata->hbmColor, pbmiCopy, pvColor);
417
418 /* Now convert the info to monochrome for the mask bits */
419 if (pbmiCopy->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
420 {
421 RGBQUAD *rgb = pbmiCopy->bmiColors;
422
423 pbmiCopy->bmiHeader.biClrUsed = pbmiCopy->bmiHeader.biClrImportant = 2;
424 rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00;
425 rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff;
426 rgb[0].rgbReserved = rgb[1].rgbReserved = 0;
427 pbmiCopy->bmiHeader.biBitCount = 1;
428 }
429 else
430 {
431 RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)pbmiCopy) + 1);
432
433 rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00;
434 rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff;
435 ((BITMAPCOREHEADER*)&pbmiCopy->bmiHeader)->bcBitCount = 1;
436 }
437 }
438 /* Set the mask bits */
439 if(!SelectObject(hdc, pdata->hbmMask))
440 goto done;
441 bResult = StretchDIBits(hdc, 0, 0, pdata->cx, pdata->cy,
442 0, 0, width, height,
443 pvMask, pbmiCopy, DIB_RGB_COLORS, SRCCOPY) != 0;
444
445 done:
446 DeleteDC(hdcScreen);
447 if(hbmpOld) SelectObject(hdc, hbmpOld);
448 DeleteDC(hdc);
449 if(pbmiCopy) HeapFree(GetProcessHeap(), 0, pbmiCopy);
450 /* Clean up in case of failure */
451 if(!bResult)
452 {
453 if(pdata->hbmMask) DeleteObject(pdata->hbmMask);
454 if(pdata->hbmColor) DeleteObject(pdata->hbmColor);
455 if(pdata->hbmAlpha) DeleteObject(pdata->hbmAlpha);
456 }
457 return bResult;
458 }
459
460 static BOOL CURSORICON_GetCursorDataFromIconInfo(
461 _Out_ CURSORDATA* pCursorData,
462 _In_ ICONINFO* pIconInfo
463 )
464 {
465 BITMAP bm;
466
467 ZeroMemory(pCursorData, sizeof(*pCursorData));
468 /* Use the CopyImage function, as it will gracefully convert our bitmap to the screen bit depth */
469 if(pIconInfo->hbmColor)
470 {
471 pCursorData->hbmColor = CopyImage(pIconInfo->hbmColor, IMAGE_BITMAP, 0, 0, 0);
472 if(!pCursorData->hbmColor)
473 return FALSE;
474 }
475 pCursorData->hbmMask = CopyImage(pIconInfo->hbmMask, IMAGE_BITMAP, 0, 0, LR_MONOCHROME);
476 if(!pCursorData->hbmMask)
477 return FALSE;
478
479 /* Now, fill some information */
480 pCursorData->rt = (USHORT)((ULONG_PTR)(pIconInfo->fIcon ? RT_ICON : RT_CURSOR));
481 if(pCursorData->hbmColor)
482 {
483 GetObject(pCursorData->hbmColor, sizeof(bm), &bm);
484 pCursorData->bpp = bm.bmBitsPixel;
485 pCursorData->cx = bm.bmWidth;
486 pCursorData->cy = bm.bmHeight;
487 if(pCursorData->bpp == 32)
488 pCursorData->hbmAlpha = create_alpha_bitmap(pCursorData->hbmColor, NULL, NULL);
489 }
490 else
491 {
492 GetObject(pCursorData->hbmMask, sizeof(bm), &bm);
493 pCursorData->bpp = 1;
494 pCursorData->cx = bm.bmWidth;
495 pCursorData->cy = bm.bmHeight/2;
496 }
497
498 if(pIconInfo->fIcon)
499 {
500 pCursorData->xHotspot = pCursorData->cx/2;
501 pCursorData->yHotspot = pCursorData->cy/2;
502 }
503 else
504 {
505 pCursorData->xHotspot = pIconInfo->xHotspot;
506 pCursorData->yHotspot = pIconInfo->yHotspot;
507 }
508
509 return TRUE;
510 }
511
512 static
513 HBITMAP
514 BITMAP_LoadImageW(
515 _In_opt_ HINSTANCE hinst,
516 _In_ LPCWSTR lpszName,
517 _In_ int cxDesired,
518 _In_ int cyDesired,
519 _In_ UINT fuLoad
520 )
521 {
522 const BITMAPINFO* pbmi;
523 BITMAPINFO* pbmiScaled = NULL;
524 BITMAPINFO* pbmiCopy = NULL;
525 const VOID* pvMapping = NULL;
526 DWORD dwOffset = 0;
527 HGLOBAL hgRsrc = NULL;
528 int iBMISize;
529 PVOID pvBits;
530 HDC hdcScreen = NULL;
531 HDC hdc = NULL;
532 HBITMAP hbmpOld, hbmpRet = NULL;
533 LONG width, height;
534 WORD bpp;
535 DWORD compr;
536
537 /* Map the bitmap info */
538 if(fuLoad & LR_LOADFROMFILE)
539 {
540 const BITMAPFILEHEADER* pbmfh;
541
542 pvMapping = map_fileW(lpszName, NULL);
543 if(!pvMapping)
544 return NULL;
545 pbmfh = pvMapping;
546 if (pbmfh->bfType != 0x4d42 /* 'BM' */)
547 {
548 WARN("Invalid/unsupported bitmap format!\n");
549 goto end;
550 }
551 pbmi = (const BITMAPINFO*)(pbmfh + 1);
552
553 /* Get the image bits */
554 if(pbmfh->bfOffBits)
555 dwOffset = pbmfh->bfOffBits - sizeof(BITMAPFILEHEADER);
556 }
557 else
558 {
559 HRSRC hrsrc;
560
561 /* Caller wants an OEM bitmap */
562 if(!hinst)
563 hinst = User32Instance;
564 hrsrc = FindResourceW(hinst, lpszName, (LPWSTR)RT_BITMAP);
565 if(!hrsrc)
566 return NULL;
567 hgRsrc = LoadResource(hinst, hrsrc);
568 if(!hgRsrc)
569 return NULL;
570 pbmi = LockResource(hgRsrc);
571 if(!pbmi)
572 return NULL;
573 }
574
575 /* Fix up values */
576 if(DIB_GetBitmapInfo(&pbmi->bmiHeader, &width, &height, &bpp, &compr) == -1)
577 goto end;
578 if((width > 65535) || (height > 65535))
579 goto end;
580 if(cxDesired == 0)
581 cxDesired = width;
582 if(cyDesired == 0)
583 cyDesired = height;
584 else if(height < 0)
585 cyDesired = -cyDesired;
586
587 iBMISize = bitmap_info_size(pbmi, DIB_RGB_COLORS);
588
589 /* Get a pointer to the image data */
590 pvBits = (char*)pbmi + (dwOffset ? dwOffset : iBMISize);
591
592 /* Create a copy of the info describing the bitmap in the file */
593 pbmiCopy = HeapAlloc(GetProcessHeap(), 0, iBMISize);
594 if(!pbmiCopy)
595 goto end;
596 CopyMemory(pbmiCopy, pbmi, iBMISize);
597
598 /* Fix it up, if needed */
599 if(fuLoad & (LR_LOADTRANSPARENT | LR_LOADMAP3DCOLORS))
600 {
601 WORD bpp, incr, numColors;
602 char* pbmiColors;
603 RGBTRIPLE* ptr;
604 COLORREF crWindow, cr3DShadow, cr3DFace, cr3DLight;
605 BYTE pixel = *((BYTE*)pvBits);
606 UINT i;
607
608 if(pbmiCopy->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
609 {
610 bpp = ((BITMAPCOREHEADER*)&pbmiCopy->bmiHeader)->bcBitCount;
611 numColors = 1 << bpp;
612 /* BITMAPCOREINFO holds RGBTRIPLEs */
613 incr = 3;
614 }
615 else
616 {
617 bpp = pbmiCopy->bmiHeader.biBitCount;
618 /* BITMAPINFOHEADER holds RGBQUADs */
619 incr = 4;
620 numColors = pbmiCopy->bmiHeader.biClrUsed;
621 if(numColors > 256) numColors = 256;
622 if (!numColors && (bpp <= 8)) numColors = 1 << bpp;
623 }
624
625 if(bpp > 8)
626 goto create_bitmap;
627
628 pbmiColors = (char*)pbmiCopy + pbmiCopy->bmiHeader.biSize;
629
630 /* Get the relevant colors */
631 crWindow = GetSysColor(COLOR_WINDOW);
632 cr3DShadow = GetSysColor(COLOR_3DSHADOW);
633 cr3DFace = GetSysColor(COLOR_3DFACE);
634 cr3DLight = GetSysColor(COLOR_3DLIGHT);
635
636 /* Fix the transparent palette entry */
637 if(fuLoad & LR_LOADTRANSPARENT)
638 {
639 switch(bpp)
640 {
641 case 1: pixel >>= 7; break;
642 case 4: pixel >>= 4; break;
643 case 8: break;
644 default:
645 FIXME("Unhandled bit depth %d.\n", bpp);
646 goto create_bitmap;
647 }
648
649 if(pixel >= numColors)
650 {
651 ERR("Wrong pixel passed in.\n");
652 goto create_bitmap;
653 }
654
655 /* If both flags are set, we must use COLOR_3DFACE */
656 if(fuLoad & LR_LOADMAP3DCOLORS) crWindow = cr3DFace;
657
658 /* Define the color */
659 ptr = (RGBTRIPLE*)(pbmiColors + pixel*incr);
660 ptr->rgbtBlue = GetBValue(crWindow);
661 ptr->rgbtGreen = GetGValue(crWindow);
662 ptr->rgbtRed = GetRValue(crWindow);
663 goto create_bitmap;
664 }
665
666 /* If we are here, then LR_LOADMAP3DCOLORS is set without LR_TRANSPARENT */
667 for(i = 0; i<numColors; i++)
668 {
669 ptr = (RGBTRIPLE*)(pbmiColors + i*incr);
670 if((ptr->rgbtBlue == ptr->rgbtRed) && (ptr->rgbtBlue == ptr->rgbtGreen))
671 {
672 if(ptr->rgbtBlue == 128)
673 {
674 ptr->rgbtBlue = GetBValue(cr3DShadow);
675 ptr->rgbtGreen = GetGValue(cr3DShadow);
676 ptr->rgbtRed = GetRValue(cr3DShadow);
677 }
678 if(ptr->rgbtBlue == 192)
679 {
680 ptr->rgbtBlue = GetBValue(cr3DFace);
681 ptr->rgbtGreen = GetGValue(cr3DFace);
682 ptr->rgbtRed = GetRValue(cr3DFace);
683 }
684 if(ptr->rgbtBlue == 223)
685 {
686 ptr->rgbtBlue = GetBValue(cr3DLight);
687 ptr->rgbtGreen = GetGValue(cr3DLight);
688 ptr->rgbtRed = GetRValue(cr3DLight);
689 }
690 }
691 }
692 }
693
694 create_bitmap:
695 if(fuLoad & LR_CREATEDIBSECTION)
696 {
697 /* Allocate the BMI describing the new bitmap */
698 pbmiScaled = HeapAlloc(GetProcessHeap(), 0, iBMISize);
699 if(!pbmiScaled)
700 goto end;
701 CopyMemory(pbmiScaled, pbmiCopy, iBMISize);
702
703 /* Fix it up */
704 if(pbmiScaled->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
705 {
706 BITMAPCOREHEADER* pbmch = (BITMAPCOREHEADER*)&pbmiScaled->bmiHeader;
707 pbmch->bcWidth = cxDesired;
708 pbmch->bcHeight = cyDesired;
709 }
710 else
711 {
712 pbmiScaled->bmiHeader.biWidth = cxDesired;
713 pbmiScaled->bmiHeader.biHeight = cyDesired;
714 /* No compression for DIB sections */
715 pbmiScaled->bmiHeader.biCompression = BI_RGB;
716 }
717 }
718
719 /* Top-down image */
720 if(cyDesired < 0) cyDesired = -cyDesired;
721
722 /* We need a device context */
723 hdcScreen = CreateDCW(DISPLAYW, NULL, NULL, NULL);
724 if(!hdcScreen)
725 goto end;
726 hdc = CreateCompatibleDC(hdcScreen);
727 if(!hdc)
728 goto end;
729
730 /* Now create the bitmap */
731 if(fuLoad & LR_CREATEDIBSECTION)
732 hbmpRet = CreateDIBSection(hdc, pbmiScaled, DIB_RGB_COLORS, NULL, 0, 0);
733 else
734 {
735 if(is_dib_monochrome(pbmiCopy) || (fuLoad & LR_MONOCHROME))
736 hbmpRet = CreateBitmap(cxDesired, cyDesired, 1, 1, NULL);
737 else
738 hbmpRet = CreateCompatibleBitmap(hdcScreen, cxDesired, cyDesired);
739 }
740
741 if(!hbmpRet)
742 goto end;
743
744 hbmpOld = SelectObject(hdc, hbmpRet);
745 if(!hbmpOld)
746 goto end;
747 if(!StretchDIBits(hdc, 0, 0, cxDesired, cyDesired,
748 0, 0, pbmi->bmiHeader.biWidth, pbmi->bmiHeader.biHeight,
749 pvBits, pbmiCopy, DIB_RGB_COLORS, SRCCOPY))
750 {
751 ERR("StretchDIBits failed!.\n");
752 SelectObject(hdc, hbmpOld);
753 DeleteObject(hbmpRet);
754 hbmpRet = NULL;
755 goto end;
756 }
757
758 SelectObject(hdc, hbmpOld);
759
760 end:
761 if(hdcScreen)
762 DeleteDC(hdcScreen);
763 if(hdc)
764 DeleteDC(hdc);
765 if(pbmiScaled)
766 HeapFree(GetProcessHeap(), 0, pbmiScaled);
767 if(pbmiCopy)
768 HeapFree(GetProcessHeap(), 0, pbmiCopy);
769 if (pvMapping)
770 UnmapViewOfFile( pvMapping );
771 if(hgRsrc)
772 FreeResource(hgRsrc);
773
774 return hbmpRet;
775 }
776
777 #include "pshpack1.h"
778
779 typedef struct {
780 BYTE bWidth;
781 BYTE bHeight;
782 BYTE bColorCount;
783 BYTE bReserved;
784 WORD xHotspot;
785 WORD yHotspot;
786 DWORD dwDIBSize;
787 DWORD dwDIBOffset;
788 } CURSORICONFILEDIRENTRY;
789
790 typedef struct
791 {
792 WORD idReserved;
793 WORD idType;
794 WORD idCount;
795 CURSORICONFILEDIRENTRY idEntries[1];
796 } CURSORICONFILEDIR;
797
798 #include "poppack.h"
799
800 static
801 HANDLE
802 CURSORICON_LoadFromFileW(
803 _In_ LPCWSTR lpszName,
804 _In_ int cxDesired,
805 _In_ int cyDesired,
806 _In_ UINT fuLoad,
807 _In_ BOOL bIcon
808 )
809 {
810 CURSORICONDIR* fakeDir;
811 CURSORICONDIRENTRY* fakeEntry;
812 CURSORICONFILEDIRENTRY *entry;
813 CURSORICONFILEDIR *dir;
814 DWORD filesize = 0;
815 LPBYTE bits;
816 HANDLE hCurIcon = NULL;
817 WORD i;
818 CURSORDATA cursorData;
819
820 TRACE("loading %s\n", debugstr_w( lpszName ));
821
822 bits = map_fileW( lpszName, &filesize );
823 if (!bits)
824 return NULL;
825
826 /* Check for .ani. */
827 if (memcmp( bits, "RIFF", 4 ) == 0)
828 {
829 UNIMPLEMENTED;
830 goto end;
831 }
832
833 dir = (CURSORICONFILEDIR*) bits;
834 if ( filesize < sizeof(*dir) )
835 goto end;
836
837 if ( filesize < (sizeof(*dir) + sizeof(dir->idEntries[0])*(dir->idCount-1)) )
838 goto end;
839
840 /*
841 * Cute little hack:
842 * We allocate a buffer, fake it as if it was a pointer to a resource in a module,
843 * pass it to LookupIconIdFromDirectoryEx and get back the index we have to use
844 */
845 fakeDir = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(CURSORICONDIR, idEntries[dir->idCount]));
846 if(!fakeDir)
847 goto end;
848 fakeDir->idReserved = 0;
849 fakeDir->idType = dir->idType;
850 fakeDir->idCount = dir->idCount;
851 for(i = 0; i<dir->idCount; i++)
852 {
853 fakeEntry = &fakeDir->idEntries[i];
854 entry = &dir->idEntries[i];
855 /* Take this as an occasion to perform a size check */
856 if((entry->dwDIBOffset + entry->dwDIBSize) > filesize)
857 goto end;
858 /* File icon/cursors are not like resource ones */
859 if(bIcon)
860 {
861 fakeEntry->ResInfo.icon.bWidth = entry->bWidth;
862 fakeEntry->ResInfo.icon.bHeight = entry->bHeight;
863 fakeEntry->ResInfo.icon.bColorCount = 0;
864 fakeEntry->ResInfo.icon.bReserved = 0;
865 }
866 else
867 {
868 fakeEntry->ResInfo.cursor.wWidth = entry->bWidth;
869 fakeEntry->ResInfo.cursor.wHeight = entry->bHeight;
870 }
871 /* Let's assume there's always one plane */
872 fakeEntry->wPlanes = 1;
873 /* We must get the bitcount from the BITMAPINFOHEADER itself */
874 fakeEntry->wBitCount = ((BITMAPINFOHEADER *)((char *)dir + entry->dwDIBOffset))->biBitCount;
875 fakeEntry->dwBytesInRes = entry->dwDIBSize;
876 fakeEntry->wResId = i + 1;
877 }
878
879 /* Now call LookupIconIdFromResourceEx */
880 i = LookupIconIdFromDirectoryEx((PBYTE)fakeDir, bIcon, cxDesired, cyDesired, fuLoad & LR_MONOCHROME);
881 /* We don't need this anymore */
882 HeapFree(GetProcessHeap(), 0, fakeDir);
883 if(i == 0)
884 {
885 WARN("Unable to get a fit entry index.\n");
886 goto end;
887 }
888
889 /* Get our entry */
890 entry = &dir->idEntries[i-1];
891 /* Fix dimensions */
892 if(!cxDesired) cxDesired = entry->bWidth;
893 if(!cyDesired) cyDesired = entry->bHeight;
894 /* A bit of preparation */
895 ZeroMemory(&cursorData, sizeof(cursorData));
896 if(!bIcon)
897 {
898 cursorData.xHotspot = entry->xHotspot;
899 cursorData.yHotspot = entry->yHotspot;
900 }
901 cursorData.rt = (USHORT)((ULONG_PTR)(bIcon ? RT_ICON : RT_CURSOR));
902
903 /* Do the dance */
904 if(!CURSORICON_GetCursorDataFromBMI(&cursorData, (BITMAPINFO*)&bits[entry->dwDIBOffset]))
905 goto end;
906
907 hCurIcon = NtUserxCreateEmptyCurObject(bIcon ? 0 : 1);
908 if(!hCurIcon)
909 goto end_error;
910
911 /* Tell win32k */
912 if(!NtUserSetCursorIconData(hCurIcon, NULL, NULL, &cursorData))
913 {
914 NtUserDestroyCursor(hCurIcon, TRUE);
915 goto end_error;
916 }
917
918 end:
919 UnmapViewOfFile(bits);
920 return hCurIcon;
921
922 /* Clean up */
923 end_error:
924 DeleteObject(cursorData.hbmMask);
925 if(cursorData.hbmColor) DeleteObject(cursorData.hbmColor);
926 if(cursorData.hbmAlpha) DeleteObject(cursorData.hbmAlpha);
927
928 return NULL;
929 }
930
931 static
932 HANDLE
933 CURSORICON_LoadImageW(
934 _In_opt_ HINSTANCE hinst,
935 _In_ LPCWSTR lpszName,
936 _In_ int cxDesired,
937 _In_ int cyDesired,
938 _In_ UINT fuLoad,
939 _In_ BOOL bIcon
940 )
941 {
942 HRSRC hrsrc;
943 HANDLE handle, hCurIcon = NULL;
944 CURSORICONDIR* dir;
945 WORD wResId;
946 LPBYTE bits;
947 CURSORDATA cursorData;
948 BOOL bStatus;
949 UNICODE_STRING ustrRsrc;
950 UNICODE_STRING ustrModule = {0, 0, NULL};
951
952 /* Fix width/height */
953 if(fuLoad & LR_DEFAULTSIZE)
954 {
955 if(!cxDesired) cxDesired = GetSystemMetrics(bIcon ? SM_CXICON : SM_CXCURSOR);
956 if(!cyDesired) cyDesired = GetSystemMetrics(bIcon ? SM_CYICON : SM_CYCURSOR);
957 }
958
959 if(fuLoad & LR_LOADFROMFILE)
960 {
961 return CURSORICON_LoadFromFileW(lpszName, cxDesired, cyDesired, fuLoad, bIcon);
962 }
963
964 /* Check if caller wants OEM icons */
965 if(!hinst)
966 hinst = User32Instance;
967
968 if(fuLoad & LR_SHARED)
969 {
970 DWORD size = MAX_PATH;
971 FINDEXISTINGCURICONPARAM param;
972
973 TRACE("Checking for an LR_SHARED cursor/icon.\n");
974 /* Prepare the resource name string */
975 if(IS_INTRESOURCE(lpszName))
976 {
977 ustrRsrc.Buffer = (LPWSTR)lpszName;
978 ustrRsrc.Length = 0;
979 ustrRsrc.MaximumLength = 0;
980 }
981 else
982 RtlInitUnicodeString(&ustrRsrc, lpszName);
983
984 /* Prepare the module name string */
985 ustrModule.Buffer = HeapAlloc(GetProcessHeap(), 0, size*sizeof(WCHAR));
986 /* Get it */
987 do
988 {
989 DWORD ret = GetModuleFileNameW(hinst, ustrModule.Buffer, size);
990 if(ret == 0)
991 {
992 HeapFree(GetProcessHeap(), 0, ustrModule.Buffer);
993 return NULL;
994 }
995 if(ret < size)
996 {
997 ustrModule.Length = ret*sizeof(WCHAR);
998 ustrModule.MaximumLength = size*sizeof(WCHAR);
999 break;
1000 }
1001 size *= 2;
1002 ustrModule.Buffer = HeapReAlloc(GetProcessHeap(), 0, ustrModule.Buffer, size*sizeof(WCHAR));
1003 } while(TRUE);
1004
1005 /* Ask win32k */
1006 param.bIcon = bIcon;
1007 param.cx = cxDesired;
1008 param.cy = cyDesired;
1009 hCurIcon = NtUserFindExistingCursorIcon(&ustrModule, &ustrRsrc, &param);
1010 if(hCurIcon)
1011 {
1012 /* Woohoo, got it! */
1013 TRACE("MATCH!\n");
1014 HeapFree(GetProcessHeap(), 0, ustrModule.Buffer);
1015 return hCurIcon;
1016 }
1017 }
1018
1019 /* Find resource ID */
1020 hrsrc = FindResourceW(
1021 hinst,
1022 lpszName,
1023 (LPWSTR)(bIcon ? RT_GROUP_ICON : RT_GROUP_CURSOR));
1024
1025 /* We let FindResource, LoadResource, etc. call SetLastError */
1026 if(!hrsrc)
1027 goto done;
1028
1029 handle = LoadResource(hinst, hrsrc);
1030 if(!handle)
1031 goto done;
1032
1033 dir = LockResource(handle);
1034 if(!dir)
1035 goto done;
1036
1037 wResId = LookupIconIdFromDirectoryEx((PBYTE)dir, bIcon, cxDesired, cyDesired, fuLoad & LR_MONOCHROME);
1038 FreeResource(handle);
1039
1040 /* Get the relevant resource pointer */
1041 hrsrc = FindResourceW(
1042 hinst,
1043 MAKEINTRESOURCEW(wResId),
1044 (LPWSTR)(bIcon ? RT_ICON : RT_CURSOR));
1045 if(!hrsrc)
1046 goto done;
1047
1048 handle = LoadResource(hinst, hrsrc);
1049 if(!handle)
1050 goto done;
1051
1052 bits = LockResource(handle);
1053 if(!bits)
1054 {
1055 FreeResource(handle);
1056 goto done;
1057 }
1058
1059 ZeroMemory(&cursorData, sizeof(cursorData));
1060
1061 if(dir->idType == 2)
1062 {
1063 /* idType == 2 for cursor resources */
1064 SHORT* ptr = (SHORT*)bits;
1065 cursorData.xHotspot = ptr[0];
1066 cursorData.yHotspot = ptr[1];
1067 bits += 2*sizeof(SHORT);
1068 }
1069 cursorData.cx = cxDesired;
1070 cursorData.cy = cyDesired;
1071 cursorData.rt = (USHORT)((ULONG_PTR)(bIcon ? RT_ICON : RT_CURSOR));
1072
1073 /* Get the bitmaps */
1074 bStatus = CURSORICON_GetCursorDataFromBMI(
1075 &cursorData,
1076 (BITMAPINFO*)bits);
1077
1078 FreeResource( handle );
1079
1080 if(!bStatus)
1081 goto done;
1082
1083 /* This is from resource */
1084 cursorData.CURSORF_flags = CURSORF_FROMRESOURCE;
1085
1086 /* Create the handle */
1087 hCurIcon = NtUserxCreateEmptyCurObject(bIcon ? 0 : 1);
1088 if(!hCurIcon)
1089 {
1090 goto end_error;
1091 }
1092
1093 /* Tell win32k */
1094 if(fuLoad & LR_SHARED)
1095 {
1096 cursorData.CURSORF_flags |= CURSORF_LRSHARED;
1097 bStatus = NtUserSetCursorIconData(hCurIcon, &ustrModule, &ustrRsrc, &cursorData);
1098 }
1099 else
1100 bStatus = NtUserSetCursorIconData(hCurIcon, NULL, NULL, &cursorData);
1101
1102 if(!bStatus)
1103 {
1104 NtUserDestroyCursor(hCurIcon, TRUE);
1105 goto end_error;
1106 }
1107
1108 done:
1109 if(ustrModule.Buffer)
1110 HeapFree(GetProcessHeap(), 0, ustrModule.Buffer);
1111 return hCurIcon;
1112
1113 end_error:
1114 if(ustrModule.Buffer)
1115 HeapFree(GetProcessHeap(), 0, ustrModule.Buffer);
1116 DeleteObject(cursorData.hbmMask);
1117 if(cursorData.hbmColor) DeleteObject(cursorData.hbmColor);
1118 if(cursorData.hbmAlpha) DeleteObject(cursorData.hbmAlpha);
1119
1120 return NULL;
1121 }
1122
1123 static
1124 HBITMAP
1125 BITMAP_CopyImage(
1126 _In_ HBITMAP hnd,
1127 _In_ int desiredx,
1128 _In_ int desiredy,
1129 _In_ UINT flags
1130 )
1131 {
1132 HBITMAP res = NULL;
1133 DIBSECTION ds;
1134 int objSize;
1135 BITMAPINFO * bi;
1136
1137 objSize = GetObjectW( hnd, sizeof(ds), &ds );
1138 if (!objSize) return 0;
1139 if ((desiredx < 0) || (desiredy < 0)) return 0;
1140
1141 if (flags & LR_COPYFROMRESOURCE)
1142 {
1143 FIXME("The flag LR_COPYFROMRESOURCE is not implemented for bitmaps\n");
1144 }
1145
1146 if (flags & LR_COPYRETURNORG)
1147 {
1148 FIXME("The flag LR_COPYRETURNORG is not implemented for bitmaps\n");
1149 }
1150
1151 if (desiredx == 0) desiredx = ds.dsBm.bmWidth;
1152 if (desiredy == 0) desiredy = ds.dsBm.bmHeight;
1153
1154 /* Allocate memory for a BITMAPINFOHEADER structure and a
1155 color table. The maximum number of colors in a color table
1156 is 256 which corresponds to a bitmap with depth 8.
1157 Bitmaps with higher depths don't have color tables. */
1158 bi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1159 if (!bi) return 0;
1160
1161 bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
1162 bi->bmiHeader.biPlanes = ds.dsBm.bmPlanes;
1163 bi->bmiHeader.biBitCount = ds.dsBm.bmBitsPixel;
1164 bi->bmiHeader.biCompression = BI_RGB;
1165
1166 if (flags & LR_CREATEDIBSECTION)
1167 {
1168 /* Create a DIB section. LR_MONOCHROME is ignored */
1169 void * bits;
1170 HDC dc = CreateCompatibleDC(NULL);
1171
1172 if (objSize == sizeof(DIBSECTION))
1173 {
1174 /* The source bitmap is a DIB.
1175 Get its attributes to create an exact copy */
1176 memcpy(bi, &ds.dsBmih, sizeof(BITMAPINFOHEADER));
1177 }
1178
1179 bi->bmiHeader.biWidth = desiredx;
1180 bi->bmiHeader.biHeight = desiredy;
1181
1182 /* Get the color table or the color masks */
1183 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
1184
1185 res = CreateDIBSection(dc, bi, DIB_RGB_COLORS, &bits, NULL, 0);
1186 DeleteDC(dc);
1187 }
1188 else
1189 {
1190 /* Create a device-dependent bitmap */
1191
1192 BOOL monochrome = (flags & LR_MONOCHROME);
1193
1194 if (objSize == sizeof(DIBSECTION))
1195 {
1196 /* The source bitmap is a DIB section.
1197 Get its attributes */
1198 HDC dc = CreateCompatibleDC(NULL);
1199 bi->bmiHeader.biWidth = ds.dsBm.bmWidth;
1200 bi->bmiHeader.biHeight = ds.dsBm.bmHeight;
1201 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
1202 DeleteDC(dc);
1203
1204 if (!monochrome && ds.dsBm.bmBitsPixel == 1)
1205 {
1206 /* Look if the colors of the DIB are black and white */
1207
1208 monochrome =
1209 (bi->bmiColors[0].rgbRed == 0xff
1210 && bi->bmiColors[0].rgbGreen == 0xff
1211 && bi->bmiColors[0].rgbBlue == 0xff
1212 && bi->bmiColors[0].rgbReserved == 0
1213 && bi->bmiColors[1].rgbRed == 0
1214 && bi->bmiColors[1].rgbGreen == 0
1215 && bi->bmiColors[1].rgbBlue == 0
1216 && bi->bmiColors[1].rgbReserved == 0)
1217 ||
1218 (bi->bmiColors[0].rgbRed == 0
1219 && bi->bmiColors[0].rgbGreen == 0
1220 && bi->bmiColors[0].rgbBlue == 0
1221 && bi->bmiColors[0].rgbReserved == 0
1222 && bi->bmiColors[1].rgbRed == 0xff
1223 && bi->bmiColors[1].rgbGreen == 0xff
1224 && bi->bmiColors[1].rgbBlue == 0xff
1225 && bi->bmiColors[1].rgbReserved == 0);
1226 }
1227 }
1228 else if (!monochrome)
1229 {
1230 monochrome = ds.dsBm.bmBitsPixel == 1;
1231 }
1232
1233 if (monochrome)
1234 {
1235 res = CreateBitmap(desiredx, desiredy, 1, 1, NULL);
1236 }
1237 else
1238 {
1239 HDC screenDC = GetDC(NULL);
1240 res = CreateCompatibleBitmap(screenDC, desiredx, desiredy);
1241 ReleaseDC(NULL, screenDC);
1242 }
1243 }
1244
1245 if (res)
1246 {
1247 /* Only copy the bitmap if it's a DIB section or if it's
1248 compatible to the screen */
1249 BOOL copyContents;
1250
1251 if (objSize == sizeof(DIBSECTION))
1252 {
1253 copyContents = TRUE;
1254 }
1255 else
1256 {
1257 HDC screenDC = GetDC(NULL);
1258 int screen_depth = GetDeviceCaps(screenDC, BITSPIXEL);
1259 ReleaseDC(NULL, screenDC);
1260
1261 copyContents = (ds.dsBm.bmBitsPixel == 1 || ds.dsBm.bmBitsPixel == screen_depth);
1262 }
1263
1264 if (copyContents)
1265 {
1266 /* The source bitmap may already be selected in a device context,
1267 use GetDIBits/StretchDIBits and not StretchBlt */
1268
1269 HDC dc;
1270 void * bits;
1271
1272 dc = CreateCompatibleDC(NULL);
1273
1274 bi->bmiHeader.biWidth = ds.dsBm.bmWidth;
1275 bi->bmiHeader.biHeight = ds.dsBm.bmHeight;
1276 bi->bmiHeader.biSizeImage = 0;
1277 bi->bmiHeader.biClrUsed = 0;
1278 bi->bmiHeader.biClrImportant = 0;
1279
1280 /* Fill in biSizeImage */
1281 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
1282 bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bi->bmiHeader.biSizeImage);
1283
1284 if (bits)
1285 {
1286 HBITMAP oldBmp;
1287
1288 /* Get the image bits of the source bitmap */
1289 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, bits, bi, DIB_RGB_COLORS);
1290
1291 /* Copy it to the destination bitmap */
1292 oldBmp = SelectObject(dc, res);
1293 StretchDIBits(dc, 0, 0, desiredx, desiredy,
1294 0, 0, ds.dsBm.bmWidth, ds.dsBm.bmHeight,
1295 bits, bi, DIB_RGB_COLORS, SRCCOPY);
1296 SelectObject(dc, oldBmp);
1297
1298 HeapFree(GetProcessHeap(), 0, bits);
1299 }
1300
1301 DeleteDC(dc);
1302 }
1303
1304 if (flags & LR_COPYDELETEORG)
1305 {
1306 DeleteObject(hnd);
1307 }
1308 }
1309 HeapFree(GetProcessHeap(), 0, bi);
1310 return res;
1311 }
1312
1313 static
1314 HICON
1315 CURSORICON_CopyImage(
1316 _In_ HICON hicon,
1317 _In_ BOOL bIcon,
1318 _In_ int cxDesired,
1319 _In_ int cyDesired,
1320 _In_ UINT fuFlags
1321 )
1322 {
1323 HICON ret = NULL;
1324 ICONINFO ii;
1325
1326 if(fuFlags & LR_COPYFROMRESOURCE)
1327 {
1328 /* Get the icon module/resource names */
1329 UNICODE_STRING ustrModule;
1330 UNICODE_STRING ustrRsrc;
1331 PVOID pvBuf;
1332 HMODULE hModule;
1333
1334 ustrModule.MaximumLength = MAX_PATH * sizeof(WCHAR);
1335 ustrRsrc.MaximumLength = 256;
1336
1337 ustrModule.Buffer = HeapAlloc(GetProcessHeap(), 0, ustrModule.MaximumLength);
1338 if(!ustrModule.Buffer)
1339 {
1340 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1341 return NULL;
1342 }
1343 /* Keep track of the buffer for the resource, NtUserGetIconInfo might overwrite it */
1344 pvBuf = HeapAlloc(GetProcessHeap(), 0, ustrRsrc.MaximumLength);
1345 if(!pvBuf)
1346 {
1347 HeapFree(GetProcessHeap(), 0, ustrModule.Buffer);
1348 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1349 return NULL;
1350 }
1351 ustrRsrc.Buffer = pvBuf;
1352
1353 do
1354 {
1355 if(!NtUserGetIconInfo(hicon, NULL, &ustrModule, &ustrRsrc, NULL, FALSE))
1356 {
1357 HeapFree(GetProcessHeap(), 0, ustrModule.Buffer);
1358 HeapFree(GetProcessHeap(), 0, pvBuf);
1359 return NULL;
1360 }
1361
1362 if((ustrModule.Length < ustrModule.MaximumLength) && (ustrRsrc.Length < ustrRsrc.MaximumLength))
1363 {
1364 /* Buffers were big enough */
1365 break;
1366 }
1367
1368 /* Find which buffer were too small */
1369 if(ustrModule.Length == ustrModule.MaximumLength)
1370 {
1371 PWSTR newBuffer;
1372 ustrModule.MaximumLength *= 2;
1373 newBuffer = HeapReAlloc(GetProcessHeap(), 0, ustrModule.Buffer, ustrModule.MaximumLength);
1374 if(!ustrModule.Buffer)
1375 {
1376 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1377 goto leave;
1378 }
1379 ustrModule.Buffer = newBuffer;
1380 }
1381
1382 if(ustrRsrc.Length == ustrRsrc.MaximumLength)
1383 {
1384 ustrRsrc.MaximumLength *= 2;
1385 pvBuf = HeapReAlloc(GetProcessHeap(), 0, ustrRsrc.Buffer, ustrRsrc.MaximumLength);
1386 if(!pvBuf)
1387 {
1388 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1389 goto leave;
1390 }
1391 ustrRsrc.Buffer = pvBuf;
1392 }
1393 } while(TRUE);
1394
1395 /* NULL-terminate our strings */
1396 ustrModule.Buffer[ustrModule.Length/sizeof(WCHAR)] = 0;
1397 if(!IS_INTRESOURCE(ustrRsrc.Buffer))
1398 ustrRsrc.Buffer[ustrRsrc.Length/sizeof(WCHAR)] = 0;
1399
1400 /* Get the module handle */
1401 if(!GetModuleHandleExW(0, ustrModule.Buffer, &hModule))
1402 {
1403 /* This hould never happen */
1404 ERR("Invalid handle?.\n");
1405 SetLastError(ERROR_INVALID_PARAMETER);
1406 goto leave;
1407 }
1408
1409 /* Call the relevant function */
1410 ret = CURSORICON_LoadImageW(hModule, ustrRsrc.Buffer, cxDesired, cyDesired, fuFlags & LR_DEFAULTSIZE, bIcon);
1411
1412 FreeLibrary(hModule);
1413
1414 /* If we're here, that means that the passed icon is shared. Don't destroy it, even if LR_COPYDELETEORG is specified */
1415 leave:
1416 HeapFree(GetProcessHeap(), 0, ustrModule.Buffer);
1417 HeapFree(GetProcessHeap(), 0, pvBuf);
1418
1419 TRACE("Returning 0x%08x.\n", ret);
1420
1421 return ret;
1422 }
1423
1424 /* This is a regular copy */
1425 if(fuFlags & ~LR_COPYDELETEORG)
1426 FIXME("Unimplemented flags: 0x%08x\n", fuFlags);
1427
1428 if(!GetIconInfo(hicon, &ii))
1429 {
1430 ERR("GetIconInfo failed.\n");
1431 return NULL;
1432 }
1433
1434 ret = CreateIconIndirect(&ii);
1435
1436 DeleteObject(ii.hbmMask);
1437 if(ii.hbmColor) DeleteObject(ii.hbmColor);
1438
1439 if(ret && (fuFlags & LR_COPYDELETEORG))
1440 DestroyIcon(hicon);
1441
1442 return hicon;
1443 }
1444
1445 NTSTATUS WINAPI
1446 User32CallCopyImageFromKernel(PVOID Arguments, ULONG ArgumentLength)
1447 {
1448 PCOPYIMAGE_CALLBACK_ARGUMENTS Common;
1449 HANDLE Result;
1450 Common = (PCOPYIMAGE_CALLBACK_ARGUMENTS) Arguments;
1451
1452 Result = CopyImage(Common->hImage,
1453 Common->uType,
1454 Common->cxDesired,
1455 Common->cyDesired,
1456 Common->fuFlags);
1457
1458 return ZwCallbackReturn(&Result, sizeof(HANDLE), STATUS_SUCCESS);
1459 }
1460
1461
1462 /************* PUBLIC FUNCTIONS *******************/
1463
1464 HANDLE WINAPI CopyImage(
1465 _In_ HANDLE hImage,
1466 _In_ UINT uType,
1467 _In_ int cxDesired,
1468 _In_ int cyDesired,
1469 _In_ UINT fuFlags
1470 )
1471 {
1472 TRACE("hImage=%p, uType=%u, cxDesired=%d, cyDesired=%d, fuFlags=%x\n",
1473 hImage, uType, cxDesired, cyDesired, fuFlags);
1474 switch(uType)
1475 {
1476 case IMAGE_BITMAP:
1477 return BITMAP_CopyImage(hImage, cxDesired, cyDesired, fuFlags);
1478 case IMAGE_CURSOR:
1479 case IMAGE_ICON:
1480 return CURSORICON_CopyImage(hImage, uType == IMAGE_ICON, cxDesired, cyDesired, fuFlags);
1481 default:
1482 SetLastError(ERROR_INVALID_PARAMETER);
1483 break;
1484 }
1485 return NULL;
1486 }
1487
1488 HICON WINAPI CopyIcon(
1489 _In_ HICON hIcon
1490 )
1491 {
1492 UNIMPLEMENTED;
1493 return NULL;
1494 }
1495
1496 BOOL WINAPI DrawIcon(
1497 _In_ HDC hDC,
1498 _In_ int X,
1499 _In_ int Y,
1500 _In_ HICON hIcon
1501 )
1502 {
1503 return DrawIconEx(hDC, X, Y, hIcon, 0, 0, 0, NULL, DI_NORMAL | DI_COMPAT | DI_DEFAULTSIZE);
1504 }
1505
1506 BOOL WINAPI DrawIconEx(
1507 _In_ HDC hdc,
1508 _In_ int xLeft,
1509 _In_ int yTop,
1510 _In_ HICON hIcon,
1511 _In_ int cxWidth,
1512 _In_ int cyWidth,
1513 _In_ UINT istepIfAniCur,
1514 _In_opt_ HBRUSH hbrFlickerFreeDraw,
1515 _In_ UINT diFlags
1516 )
1517 {
1518 return NtUserDrawIconEx(hdc, xLeft, yTop, hIcon, cxWidth, cyWidth,
1519 istepIfAniCur, hbrFlickerFreeDraw, diFlags,
1520 0, 0);
1521 }
1522
1523 BOOL WINAPI GetIconInfo(
1524 _In_ HICON hIcon,
1525 _Out_ PICONINFO piconinfo
1526 )
1527 {
1528 return NtUserGetIconInfo(hIcon, piconinfo, NULL, NULL, NULL, FALSE);
1529 }
1530
1531 BOOL WINAPI DestroyIcon(
1532 _In_ HICON hIcon
1533 )
1534 {
1535 return NtUserDestroyCursor(hIcon, FALSE);
1536 }
1537
1538 HICON WINAPI LoadIconA(
1539 _In_opt_ HINSTANCE hInstance,
1540 _In_ LPCSTR lpIconName
1541 )
1542 {
1543 TRACE("%p, %s\n", hInstance, debugstr_a(lpIconName));
1544
1545 return LoadImageA(hInstance,
1546 lpIconName,
1547 IMAGE_ICON,
1548 0,
1549 0,
1550 LR_SHARED | LR_DEFAULTSIZE );
1551 }
1552
1553 HICON WINAPI LoadIconW(
1554 _In_opt_ HINSTANCE hInstance,
1555 _In_ LPCWSTR lpIconName
1556 )
1557 {
1558 TRACE("%p, %s\n", hInstance, debugstr_w(lpIconName));
1559
1560 return LoadImageW(hInstance,
1561 lpIconName,
1562 IMAGE_ICON,
1563 0,
1564 0,
1565 LR_SHARED | LR_DEFAULTSIZE );
1566 }
1567
1568 HCURSOR WINAPI LoadCursorA(
1569 _In_opt_ HINSTANCE hInstance,
1570 _In_ LPCSTR lpCursorName
1571 )
1572 {
1573 TRACE("%p, %s\n", hInstance, debugstr_a(lpCursorName));
1574
1575 return LoadImageA(hInstance,
1576 lpCursorName,
1577 IMAGE_CURSOR,
1578 0,
1579 0,
1580 LR_SHARED | LR_DEFAULTSIZE );
1581 }
1582
1583 HCURSOR WINAPI LoadCursorW(
1584 _In_opt_ HINSTANCE hInstance,
1585 _In_ LPCWSTR lpCursorName
1586 )
1587 {
1588 TRACE("%p, %s\n", hInstance, debugstr_w(lpCursorName));
1589
1590 return LoadImageW(hInstance,
1591 lpCursorName,
1592 IMAGE_CURSOR,
1593 0,
1594 0,
1595 LR_SHARED | LR_DEFAULTSIZE );
1596 }
1597
1598 HCURSOR WINAPI LoadCursorFromFileA(
1599 _In_ LPCSTR lpFileName
1600 )
1601 {
1602 TRACE("%s\n", debugstr_a(lpFileName));
1603
1604 return LoadImageA(NULL,
1605 lpFileName,
1606 IMAGE_CURSOR,
1607 0,
1608 0,
1609 LR_LOADFROMFILE | LR_DEFAULTSIZE );
1610 }
1611
1612 HCURSOR WINAPI LoadCursorFromFileW(
1613 _In_ LPCWSTR lpFileName
1614 )
1615 {
1616 TRACE("%s\n", debugstr_w(lpFileName));
1617
1618 return LoadImageW(NULL,
1619 lpFileName,
1620 IMAGE_CURSOR,
1621 0,
1622 0,
1623 LR_LOADFROMFILE | LR_DEFAULTSIZE );
1624 }
1625
1626 HBITMAP WINAPI LoadBitmapA(
1627 _In_opt_ HINSTANCE hInstance,
1628 _In_ LPCSTR lpBitmapName
1629 )
1630 {
1631 TRACE("%p, %s\n", hInstance, debugstr_a(lpBitmapName));
1632
1633 return LoadImageA(hInstance,
1634 lpBitmapName,
1635 IMAGE_BITMAP,
1636 0,
1637 0,
1638 0);
1639 }
1640
1641 HBITMAP WINAPI LoadBitmapW(
1642 _In_opt_ HINSTANCE hInstance,
1643 _In_ LPCWSTR lpBitmapName
1644 )
1645 {
1646 TRACE("%p, %s\n", hInstance, debugstr_w(lpBitmapName));
1647
1648 return LoadImageW(hInstance,
1649 lpBitmapName,
1650 IMAGE_BITMAP,
1651 0,
1652 0,
1653 0);
1654 }
1655
1656 HANDLE WINAPI LoadImageA(
1657 _In_opt_ HINSTANCE hinst,
1658 _In_ LPCSTR lpszName,
1659 _In_ UINT uType,
1660 _In_ int cxDesired,
1661 _In_ int cyDesired,
1662 _In_ UINT fuLoad
1663 )
1664 {
1665 HANDLE res;
1666 LPWSTR u_name;
1667 DWORD len;
1668
1669 if (IS_INTRESOURCE(lpszName))
1670 return LoadImageW(hinst, (LPCWSTR)lpszName, uType, cxDesired, cyDesired, fuLoad);
1671
1672 len = MultiByteToWideChar( CP_ACP, 0, lpszName, -1, NULL, 0 );
1673 u_name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
1674 MultiByteToWideChar( CP_ACP, 0, lpszName, -1, u_name, len );
1675
1676 res = LoadImageW(hinst, u_name, uType, cxDesired, cyDesired, fuLoad);
1677 HeapFree(GetProcessHeap(), 0, u_name);
1678 return res;
1679 }
1680
1681 HANDLE WINAPI LoadImageW(
1682 _In_opt_ HINSTANCE hinst,
1683 _In_ LPCWSTR lpszName,
1684 _In_ UINT uType,
1685 _In_ int cxDesired,
1686 _In_ int cyDesired,
1687 _In_ UINT fuLoad
1688 )
1689 {
1690 /* Redirect to each implementation */
1691 switch(uType)
1692 {
1693 case IMAGE_BITMAP:
1694 return BITMAP_LoadImageW(hinst, lpszName, cxDesired, cyDesired, fuLoad);
1695 case IMAGE_CURSOR:
1696 case IMAGE_ICON:
1697 return CURSORICON_LoadImageW(hinst, lpszName, cxDesired, cyDesired, fuLoad, uType == IMAGE_ICON);
1698 default:
1699 SetLastError(ERROR_INVALID_PARAMETER);
1700 break;
1701 }
1702 return NULL;
1703 }
1704
1705 int WINAPI LookupIconIdFromDirectory(
1706 _In_ PBYTE presbits,
1707 _In_ BOOL fIcon
1708 )
1709 {
1710 return LookupIconIdFromDirectoryEx( presbits, fIcon,
1711 fIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
1712 fIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), fIcon ? 0 : LR_MONOCHROME );
1713 }
1714
1715 int WINAPI LookupIconIdFromDirectoryEx(
1716 _In_ PBYTE presbits,
1717 _In_ BOOL fIcon,
1718 _In_ int cxDesired,
1719 _In_ int cyDesired,
1720 _In_ UINT Flags
1721 )
1722 {
1723 WORD bppDesired;
1724 CURSORICONDIR* dir = (CURSORICONDIR*)presbits;
1725 CURSORICONDIRENTRY* entry;
1726 int i, numMatch, iIndex = -1;
1727 WORD width, height;
1728 USHORT bitcount;
1729 ULONG cxyDiff, cxyDiffTmp;
1730
1731 TRACE("%p, %x, %i, %i, %x.\n", presbits, fIcon, cxDesired, cyDesired, Flags);
1732
1733 if(!(dir && !dir->idReserved && (dir->idType & 3)))
1734 {
1735 WARN("Invalid resource.\n");
1736 return 0;
1737 }
1738
1739 if(Flags & LR_MONOCHROME)
1740 bppDesired = 1;
1741 else
1742 {
1743 HDC icScreen;
1744 icScreen = CreateICW(DISPLAYW, NULL, NULL, NULL);
1745 if(!icScreen)
1746 return FALSE;
1747
1748 bppDesired = GetDeviceCaps(icScreen, BITSPIXEL);
1749 DeleteDC(icScreen);
1750 }
1751
1752 if(!cxDesired)
1753 cxDesired = GetSystemMetrics(fIcon ? SM_CXICON : SM_CXCURSOR);
1754 if(!cyDesired)
1755 cyDesired = GetSystemMetrics(fIcon ? SM_CYICON : SM_CYCURSOR);
1756
1757 /* Find the best match for the desired size */
1758 cxyDiff = 0xFFFFFFFF;
1759 numMatch = 0;
1760 for(i = 0; i < dir->idCount; i++)
1761 {
1762 entry = &dir->idEntries[i];
1763 width = fIcon ? entry->ResInfo.icon.bWidth : entry->ResInfo.cursor.wWidth;
1764 /* Height is twice as big in cursor resources */
1765 height = fIcon ? entry->ResInfo.icon.bHeight : entry->ResInfo.cursor.wHeight/2;
1766 /* 0 represents 256 */
1767 if(!width) width = 256;
1768 if(!height) height = 256;
1769 /* Let it be a 1-norm */
1770 cxyDiffTmp = max(abs(width - cxDesired), abs(height - cyDesired));
1771 if( cxyDiffTmp > cxyDiff)
1772 continue;
1773 if( cxyDiffTmp == cxyDiff)
1774 {
1775 numMatch++;
1776 continue;
1777 }
1778 iIndex = i;
1779 numMatch = 1;
1780 cxyDiff = cxyDiffTmp;
1781 }
1782
1783 if(numMatch == 1)
1784 {
1785 /* Only one entry fit the asked dimensions */
1786 return dir->idEntries[iIndex].wResId;
1787 }
1788
1789 bitcount = 0;
1790 iIndex = -1;
1791 /* Now find the entry with the best depth */
1792 for(i = 0; i < dir->idCount; i++)
1793 {
1794 entry = &dir->idEntries[i];
1795 width = fIcon ? entry->ResInfo.icon.bWidth : entry->ResInfo.cursor.wWidth;
1796 height = fIcon ? entry->ResInfo.icon.bHeight : entry->ResInfo.cursor.wHeight/2;
1797 /* 0 represents 256 */
1798 if(!width) width = 256;
1799 if(!height) height = 256;
1800 /* Check if this is the best match we had */
1801 cxyDiffTmp = max(abs(width - cxDesired), abs(height - cyDesired));
1802 if(cxyDiffTmp != cxyDiff)
1803 continue;
1804 /* Exact match? */
1805 if(entry->wBitCount == bppDesired)
1806 return entry->wResId;
1807 /* We take the highest possible but smaller than the display depth */
1808 if((entry->wBitCount > bitcount) && (entry->wBitCount < bppDesired))
1809 {
1810 iIndex = i;
1811 bitcount = entry->wBitCount;
1812 }
1813 }
1814
1815 if(iIndex >= 0)
1816 return dir->idEntries[iIndex].wResId;
1817
1818 /* No inferior or equal depth available. Get the smallest one */
1819 bitcount = 0x7FFF;
1820 for(i = 0; i < dir->idCount; i++)
1821 {
1822 entry = &dir->idEntries[i];
1823 width = fIcon ? entry->ResInfo.icon.bWidth : entry->ResInfo.cursor.wWidth;
1824 height = fIcon ? entry->ResInfo.icon.bHeight : entry->ResInfo.cursor.wHeight/2;
1825 /* 0 represents 256 */
1826 if(!width) width = 256;
1827 if(!height) height = 256;
1828 /* Check if this is the best match we had */
1829 cxyDiffTmp = max(abs(width - cxDesired), abs(height - cyDesired));
1830 if(cxyDiffTmp != cxyDiff)
1831 continue;
1832 /* Check the bit depth */
1833 if(entry->wBitCount < bitcount)
1834 {
1835 iIndex = i;
1836 bitcount = entry->wBitCount;
1837 }
1838 }
1839
1840 return dir->idEntries[iIndex].wResId;
1841 }
1842
1843 HICON WINAPI CreateIcon(
1844 _In_opt_ HINSTANCE hInstance,
1845 _In_ int nWidth,
1846 _In_ int nHeight,
1847 _In_ BYTE cPlanes,
1848 _In_ BYTE cBitsPixel,
1849 _In_ const BYTE *lpbANDbits,
1850 _In_ const BYTE *lpbXORbits
1851 )
1852 {
1853 ICONINFO iinfo;
1854 HICON hIcon;
1855
1856 TRACE_(icon)("%dx%d, planes %d, bpp %d, xor %p, and %p\n",
1857 nWidth, nHeight, cPlanes, cBitsPixel, lpbXORbits, lpbANDbits);
1858
1859 iinfo.fIcon = TRUE;
1860 iinfo.xHotspot = nWidth / 2;
1861 iinfo.yHotspot = nHeight / 2;
1862 if (cPlanes * cBitsPixel > 1)
1863 {
1864 iinfo.hbmColor = CreateBitmap( nWidth, nHeight, cPlanes, cBitsPixel, lpbXORbits );
1865 iinfo.hbmMask = CreateBitmap( nWidth, nHeight, 1, 1, lpbANDbits );
1866 }
1867 else
1868 {
1869 iinfo.hbmMask = CreateBitmap( nWidth, nHeight * 2, 1, 1, lpbANDbits );
1870 iinfo.hbmColor = NULL;
1871 }
1872
1873 hIcon = CreateIconIndirect( &iinfo );
1874
1875 DeleteObject( iinfo.hbmMask );
1876 if (iinfo.hbmColor) DeleteObject( iinfo.hbmColor );
1877
1878 return hIcon;
1879 }
1880
1881 HICON WINAPI CreateIconFromResource(
1882 _In_ PBYTE presbits,
1883 _In_ DWORD dwResSize,
1884 _In_ BOOL fIcon,
1885 _In_ DWORD dwVer
1886 )
1887 {
1888 return CreateIconFromResourceEx( presbits, dwResSize, fIcon, dwVer, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
1889 }
1890
1891 HICON WINAPI CreateIconFromResourceEx(
1892 _In_ PBYTE pbIconBits,
1893 _In_ DWORD cbIconBits,
1894 _In_ BOOL fIcon,
1895 _In_ DWORD dwVersion,
1896 _In_ int cxDesired,
1897 _In_ int cyDesired,
1898 _In_ UINT uFlags
1899 )
1900 {
1901 CURSORDATA cursorData;
1902 HICON hIcon;
1903
1904 TRACE("%p, %lu, %lu, %lu, %i, %i, %lu.\n", pbIconBits, cbIconBits, fIcon, dwVersion, cxDesired, cyDesired, uFlags);
1905
1906 if(uFlags & ~LR_DEFAULTSIZE)
1907 FIXME("uFlags 0x%08x ignored.\n", uFlags & ~LR_DEFAULTSIZE);
1908
1909 if(uFlags & LR_DEFAULTSIZE)
1910 {
1911 if(!cxDesired) cxDesired = GetSystemMetrics(fIcon ? SM_CXICON : SM_CXCURSOR);
1912 if(!cyDesired) cyDesired = GetSystemMetrics(fIcon ? SM_CYICON : SM_CYCURSOR);
1913 }
1914
1915 /* Check if this is an animated cursor */
1916 if(!memcmp(pbIconBits, "RIFF", 4))
1917 {
1918 UNIMPLEMENTED;
1919 return NULL;
1920 }
1921
1922 ZeroMemory(&cursorData, sizeof(cursorData));
1923 cursorData.cx = cxDesired;
1924 cursorData.cy = cyDesired;
1925 cursorData.rt = (USHORT)((ULONG_PTR)(fIcon ? RT_ICON : RT_CURSOR));
1926 if(!fIcon)
1927 {
1928 WORD* pt = (WORD*)pbIconBits;
1929 cursorData.xHotspot = *pt++;
1930 cursorData.yHotspot = *pt++;
1931 pbIconBits = (PBYTE)pt;
1932 }
1933
1934 if(!CURSORICON_GetCursorDataFromBMI(&cursorData, (BITMAPINFO*)pbIconBits))
1935 {
1936 ERR("Couldn't fill the CURSORDATA structure.\n");
1937 return NULL;
1938 }
1939
1940 hIcon = NtUserxCreateEmptyCurObject(fIcon ? 0 : 1);
1941 if(!hIcon)
1942 goto end_error;
1943
1944 if(!NtUserSetCursorIconData(hIcon, NULL, NULL, &cursorData))
1945 {
1946 ERR("NtUserSetCursorIconData failed.\n");
1947 NtUserDestroyCursor(hIcon, TRUE);
1948 goto end_error;
1949 }
1950
1951 return hIcon;
1952
1953 /* Clean up */
1954 end_error:
1955 DeleteObject(cursorData.hbmMask);
1956 if(cursorData.hbmColor) DeleteObject(cursorData.hbmColor);
1957 if(cursorData.hbmAlpha) DeleteObject(cursorData.hbmAlpha);
1958
1959 return NULL;
1960 }
1961
1962 HICON WINAPI CreateIconIndirect(
1963 _In_ PICONINFO piconinfo
1964 )
1965 {
1966 /* As simple as creating a handle, and let win32k deal with the bitmaps */
1967 HICON hiconRet;
1968 CURSORDATA cursorData;
1969
1970 TRACE("%p.\n", piconinfo);
1971
1972 if(!CURSORICON_GetCursorDataFromIconInfo(&cursorData, piconinfo))
1973 return NULL;
1974
1975 hiconRet = NtUserxCreateEmptyCurObject(piconinfo->fIcon ? 0 : 1);
1976 if(!hiconRet)
1977 goto end_error;
1978
1979 if(!NtUserSetCursorIconData(hiconRet, NULL, NULL, &cursorData))
1980 {
1981 NtUserDestroyCursor(hiconRet, FALSE);
1982 goto end_error;
1983 }
1984
1985 TRACE("Returning 0x%08x.\n", hiconRet);
1986
1987 return hiconRet;
1988
1989 end_error:
1990 /* Clean up */
1991 DeleteObject(cursorData.hbmMask);
1992 if(cursorData.hbmColor) DeleteObject(cursorData.hbmColor);
1993 if(cursorData.hbmAlpha) DeleteObject(cursorData.hbmAlpha);
1994
1995 return NULL;
1996 }
1997
1998 HCURSOR WINAPI CreateCursor(
1999 _In_opt_ HINSTANCE hInst,
2000 _In_ int xHotSpot,
2001 _In_ int yHotSpot,
2002 _In_ int nWidth,
2003 _In_ int nHeight,
2004 _In_ const VOID *pvANDPlane,
2005 _In_ const VOID *pvXORPlane
2006 )
2007 {
2008 ICONINFO info;
2009 HCURSOR hCursor;
2010
2011 TRACE_(cursor)("%dx%d spot=%d,%d xor=%p and=%p\n",
2012 nWidth, nHeight, xHotSpot, yHotSpot, pvXORPlane, pvANDPlane);
2013
2014 info.fIcon = FALSE;
2015 info.xHotspot = xHotSpot;
2016 info.yHotspot = yHotSpot;
2017 info.hbmMask = CreateBitmap( nWidth, nHeight, 1, 1, pvANDPlane );
2018 info.hbmColor = CreateBitmap( nWidth, nHeight, 1, 1, pvXORPlane );
2019 hCursor = CreateIconIndirect( &info );
2020 DeleteObject( info.hbmMask );
2021 DeleteObject( info.hbmColor );
2022 return hCursor;
2023 }
2024
2025 BOOL WINAPI SetSystemCursor(
2026 _In_ HCURSOR hcur,
2027 _In_ DWORD id
2028 )
2029 {
2030 UNIMPLEMENTED;
2031 return FALSE;
2032 }
2033
2034 BOOL WINAPI SetCursorPos(
2035 _In_ int X,
2036 _In_ int Y
2037 )
2038 {
2039 return NtUserxSetCursorPos(X,Y);
2040 }
2041
2042 BOOL WINAPI GetCursorPos(
2043 _Out_ LPPOINT lpPoint
2044 )
2045 {
2046 return NtUserxGetCursorPos(lpPoint);
2047 }
2048
2049 int WINAPI ShowCursor(
2050 _In_ BOOL bShow
2051 )
2052 {
2053 return NtUserxShowCursor(bShow);
2054 }
2055
2056 HCURSOR WINAPI GetCursor(void)
2057 {
2058 return (HCURSOR)NtUserGetThreadState(THREADSTATE_GETCURSOR);
2059 }
2060
2061 BOOL WINAPI DestroyCursor(
2062 _In_ HCURSOR hCursor
2063 )
2064 {
2065 return NtUserDestroyCursor(hCursor, FALSE);
2066 }