[FORMATTING]
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / cursoricon.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 /*
21 * We handle two types of cursors/icons:
22 * - Private
23 * Loaded without LR_SHARED flag
24 * Private to a process
25 * Can be deleted by calling NtDestroyCursorIcon()
26 * CurIcon->hModule, CurIcon->hRsrc and CurIcon->hGroupRsrc set to NULL
27 * - Shared
28 * Loaded with LR_SHARED flag
29 * Possibly shared by multiple processes
30 * Immune to NtDestroyCursorIcon()
31 * CurIcon->hModule, CurIcon->hRsrc and CurIcon->hGroupRsrc are valid
32 * There's a M:N relationship between processes and (shared) cursor/icons.
33 * A process can have multiple cursor/icons and a cursor/icon can be used
34 * by multiple processes. To keep track of this we keep a list of all
35 * cursor/icons (CurIconList) and per cursor/icon we keep a list of
36 * CURICON_PROCESS structs starting at CurIcon->ProcessList.
37 */
38
39 #include <w32k.h>
40
41 #define NDEBUG
42 #include <debug.h>
43
44 static PAGED_LOOKASIDE_LIST gProcessLookasideList;
45 static LIST_ENTRY gCurIconList;
46
47 BOOL FASTCALL
48 IntGetCursorLocation(PWINSTATION_OBJECT WinSta, POINT *loc)
49 {
50 loc->x = gpsi->ptCursor.x;
51 loc->y = gpsi->ptCursor.y;
52
53 return TRUE;
54 }
55
56 /* This function creates a reference for the object! */
57 PCURICON_OBJECT FASTCALL UserGetCurIconObject(HCURSOR hCurIcon)
58 {
59 PCURICON_OBJECT CurIcon;
60
61 if (!hCurIcon)
62 {
63 SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
64 return NULL;
65 }
66
67 CurIcon = (PCURICON_OBJECT)UserReferenceObjectByHandle(hCurIcon, otCursorIcon);
68 if (!CurIcon)
69 {
70 /* we never set ERROR_INVALID_ICON_HANDLE. lets hope noone ever checks for it */
71 SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
72 return NULL;
73 }
74
75 ASSERT(USER_BODY_TO_HEADER(CurIcon)->RefCount >= 1);
76 return CurIcon;
77 }
78
79
80 #define COLORCURSORS_ALLOWED FALSE
81 HCURSOR FASTCALL
82 IntSetCursor(PWINSTATION_OBJECT WinSta, PCURICON_OBJECT NewCursor,
83 BOOL ForceChange)
84 {
85 SURFACE *psurf;
86 SURFOBJ *pso;
87 PDEVINFO DevInfo;
88 PSURFACE MaskBmpObj = NULL;
89 PSYSTEM_CURSORINFO CurInfo;
90 PCURICON_OBJECT OldCursor;
91 HCURSOR Ret = (HCURSOR)0;
92 HBITMAP hMask = 0;
93 SURFOBJ *soMask = NULL, *soColor = NULL;
94 XLATEOBJ *XlateObj = NULL;
95 HDC Screen;
96 PDC dc;
97 ULONG Status;
98
99 CurInfo = IntGetSysCursorInfo(WinSta);
100 OldCursor = CurInfo->CurrentCursorObject;
101 if (OldCursor)
102 {
103 Ret = (HCURSOR)OldCursor->Self;
104 }
105
106 if (!ForceChange && OldCursor == NewCursor)
107 {
108 return Ret;
109 }
110
111 if (!(Screen = IntGetScreenDC()))
112 {
113 return (HCURSOR)0;
114 }
115 /* FIXME use the desktop's HDC instead of using ScreenDeviceContext */
116 dc = DC_LockDc(Screen);
117
118 if (!dc)
119 {
120 return Ret;
121 }
122 DevInfo = (PDEVINFO)&dc->ppdev->DevInfo;
123
124 psurf = dc->dclevel.pSurface;
125 if (!psurf)
126 {
127 DC_UnlockDc(dc);
128 return (HCURSOR)0;
129 }
130 pso = &psurf->SurfObj;
131
132 if (!NewCursor)
133 {
134 if (CurInfo->CurrentCursorObject || ForceChange)
135 {
136 if (CurInfo->CurrentCursorObject)
137 {
138 UserDereferenceObject(CurInfo->CurrentCursorObject);
139 if (CurInfo->ShowingCursor)
140 {
141 DPRINT("Removing pointer!\n");
142 /* Remove the cursor if it was displayed */
143 IntEngMovePointer(pso, -1, -1, &GDIDEV(pso)->Pointer.Exclude);
144 }
145 }
146
147 CurInfo->CurrentCursorObject = NewCursor; /* i.e. CurrentCursorObject = NULL */
148 CurInfo->ShowingCursor = 0;
149 }
150
151 DC_UnlockDc(dc);
152 return Ret;
153 }
154
155 /* TODO: Fixme. Logic is screwed above */
156
157 MaskBmpObj = SURFACE_LockSurface(NewCursor->IconInfo.hbmMask);
158 if (MaskBmpObj)
159 {
160 const int maskBpp = BitsPerFormat(MaskBmpObj->SurfObj.iBitmapFormat);
161 SURFACE_UnlockSurface(MaskBmpObj);
162 if (maskBpp != 1)
163 {
164 DPRINT1("SetCursor: The Mask bitmap must have 1BPP!\n");
165 DC_UnlockDc(dc);
166 return Ret;
167 }
168
169 if ((DevInfo->flGraphicsCaps2 & GCAPS2_ALPHACURSOR) &&
170 pso->iBitmapFormat >= BMF_16BPP &&
171 pso->iBitmapFormat <= BMF_32BPP &&
172 NewCursor->Shadow && COLORCURSORS_ALLOWED)
173 {
174 /* FIXME - Create a color pointer, only 32bit bitmap, set alpha bits!
175 Do not pass a mask bitmap to DrvSetPointerShape()!
176 Create a XLATEOBJ that describes the colors of the bitmap. */
177 DPRINT1("SetCursor: (Colored) alpha cursors are not supported!\n");
178 }
179 else
180 {
181 if (NewCursor->IconInfo.hbmColor
182 && COLORCURSORS_ALLOWED)
183 {
184 /* FIXME - Create a color pointer, create only one 32bit bitmap!
185 Do not pass a mask bitmap to DrvSetPointerShape()!
186 Create a XLATEOBJ that describes the colors of the bitmap.
187 (16bit bitmaps are propably allowed) */
188 DPRINT1("SetCursor: Cursors with colors are not supported!\n");
189 }
190 else
191 {
192 MaskBmpObj = SURFACE_LockSurface(NewCursor->IconInfo.hbmMask);
193 if (MaskBmpObj)
194 {
195 RECTL DestRect = {0, 0, MaskBmpObj->SurfObj.sizlBitmap.cx, MaskBmpObj->SurfObj.sizlBitmap.cy};
196 POINTL SourcePoint = {0, 0};
197
198 /*
199 * NOTE: For now we create the cursor in top-down bitmap,
200 * because VMware driver rejects it otherwise. This should
201 * be fixed later.
202 */
203 hMask = EngCreateBitmap(
204 MaskBmpObj->SurfObj.sizlBitmap, abs(MaskBmpObj->SurfObj.lDelta),
205 MaskBmpObj->SurfObj.iBitmapFormat, BMF_TOPDOWN,
206 NULL);
207 if (!hMask)
208 {
209 SURFACE_UnlockSurface(MaskBmpObj);
210 DC_UnlockDc(dc);
211 return (HCURSOR)0;
212 }
213 soMask = EngLockSurface((HSURF)hMask);
214 IntEngCopyBits(soMask, &MaskBmpObj->SurfObj, NULL, NULL,
215 &DestRect, &SourcePoint);
216 SURFACE_UnlockSurface(MaskBmpObj);
217 }
218 }
219 }
220 CurInfo->ShowingCursor = CURSOR_SHOWING;
221 CurInfo->CurrentCursorObject = NewCursor;
222 UserReferenceObject(NewCursor);
223 }
224 else
225 {
226 CurInfo->ShowingCursor = 0;
227 CurInfo->CurrentCursorObject = NULL;
228 }
229
230 /* OldCursor is not in use anymore */
231 if (OldCursor)
232 {
233 UserDereferenceObject(OldCursor);
234 }
235
236 Status = IntEngSetPointerShape(pso,
237 soMask,
238 soColor,
239 XlateObj,
240 NewCursor->IconInfo.xHotspot,
241 NewCursor->IconInfo.yHotspot,
242 gpsi->ptCursor.x,
243 gpsi->ptCursor.y,
244 &(GDIDEV(pso)->Pointer.Exclude),
245 SPS_CHANGE);
246
247 if (Status != SPS_ACCEPT_NOEXCLUDE)
248 {
249 DPRINT1("IntEngSetPointerShape returned %lx\n", Status);
250 }
251
252 if (hMask)
253 {
254 EngUnlockSurface(soMask);
255 EngDeleteSurface((HSURF)hMask);
256 }
257 if (XlateObj)
258 {
259 EngDeleteXlate(XlateObj);
260 }
261
262 DC_UnlockDc(dc);
263 return Ret;
264 }
265
266 BOOL FASTCALL
267 IntSetupCurIconHandles(PWINSTATION_OBJECT WinSta)
268 {
269 ExInitializePagedLookasideList(&gProcessLookasideList,
270 NULL,
271 NULL,
272 0,
273 sizeof(CURICON_PROCESS),
274 TAG_DIB,
275 128);
276 InitializeListHead(&gCurIconList);
277
278 return TRUE;
279 }
280
281 /*
282 * We have to register that this object is in use by the current
283 * process. The only way to do that seems to be to walk the list
284 * of cursor/icon objects starting at W32Process->CursorIconListHead.
285 * If the object is already present in the list, we don't have to do
286 * anything, if it's not present we add it and inc the ProcessCount
287 * in the object. Having to walk the list kind of sucks, but that's
288 * life...
289 */
290 static BOOLEAN FASTCALL
291 ReferenceCurIconByProcess(PCURICON_OBJECT CurIcon)
292 {
293 PPROCESSINFO Win32Process;
294 PCURICON_PROCESS Current;
295
296 Win32Process = PsGetCurrentProcessWin32Process();
297
298 LIST_FOR_EACH(Current, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
299 {
300 if (Current->Process == Win32Process)
301 {
302 /* Already registered for this process */
303 return TRUE;
304 }
305 }
306
307 /* Not registered yet */
308 Current = ExAllocateFromPagedLookasideList(&gProcessLookasideList);
309 if (NULL == Current)
310 {
311 return FALSE;
312 }
313 InsertHeadList(&CurIcon->ProcessList, &Current->ListEntry);
314 Current->Process = Win32Process;
315
316 return TRUE;
317 }
318
319 PCURICON_OBJECT FASTCALL
320 IntFindExistingCurIconObject(PWINSTATION_OBJECT WinSta, HMODULE hModule,
321 HRSRC hRsrc, LONG cx, LONG cy)
322 {
323 PCURICON_OBJECT CurIcon;
324
325 LIST_FOR_EACH(CurIcon, &gCurIconList, CURICON_OBJECT, ListEntry)
326 {
327
328 // if(NT_SUCCESS(UserReferenceObjectByPointer(Object, otCursorIcon))) //<- huh????
329 // UserReferenceObject( CurIcon);
330 // {
331 if ((CurIcon->hModule == hModule) && (CurIcon->hRsrc == hRsrc))
332 {
333 if (cx && ((cx != CurIcon->Size.cx) || (cy != CurIcon->Size.cy)))
334 {
335 // UserDereferenceObject(CurIcon);
336 continue;
337 }
338 if (! ReferenceCurIconByProcess(CurIcon))
339 {
340 return NULL;
341 }
342
343 return CurIcon;
344 }
345 // }
346 // UserDereferenceObject(CurIcon);
347
348 }
349
350 return NULL;
351 }
352
353 PCURICON_OBJECT FASTCALL
354 IntCreateCurIconHandle(PWINSTATION_OBJECT WinSta)
355 {
356 PCURICON_OBJECT CurIcon;
357 HANDLE hCurIcon;
358
359 CurIcon = UserCreateObject(gHandleTable, &hCurIcon, otCursorIcon, sizeof(CURICON_OBJECT));
360
361 if (!CurIcon)
362 {
363 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
364 return FALSE;
365 }
366
367 CurIcon->Self = hCurIcon;
368 InitializeListHead(&CurIcon->ProcessList);
369
370 if (! ReferenceCurIconByProcess(CurIcon))
371 {
372 DPRINT1("Failed to add process\n");
373 UserDeleteObject(hCurIcon, otCursorIcon);
374 UserDereferenceObject(CurIcon);
375 return NULL;
376 }
377
378 InsertHeadList(&gCurIconList, &CurIcon->ListEntry);
379
380 return CurIcon;
381 }
382
383 BOOLEAN FASTCALL
384 IntDestroyCurIconObject(PWINSTATION_OBJECT WinSta, PCURICON_OBJECT CurIcon, BOOL ProcessCleanup)
385 {
386 PSYSTEM_CURSORINFO CurInfo;
387 HBITMAP bmpMask, bmpColor;
388 BOOLEAN Ret;
389 PCURICON_PROCESS Current = NULL;
390 PPROCESSINFO W32Process = PsGetCurrentProcessWin32Process();
391
392 /* Private objects can only be destroyed by their own process */
393 if (NULL == CurIcon->hModule)
394 {
395 ASSERT(CurIcon->ProcessList.Flink->Flink == &CurIcon->ProcessList);
396 Current = CONTAINING_RECORD(CurIcon->ProcessList.Flink, CURICON_PROCESS, ListEntry);
397 if (Current->Process != W32Process)
398 {
399 DPRINT1("Trying to destroy private icon/cursor of another process\n");
400 return FALSE;
401 }
402 }
403 else if (! ProcessCleanup)
404 {
405 DPRINT("Trying to destroy shared icon/cursor\n");
406 return FALSE;
407 }
408
409 /* Now find this process in the list of processes referencing this object and
410 remove it from that list */
411 LIST_FOR_EACH(Current, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
412 {
413 if (Current->Process == W32Process)
414 {
415 RemoveEntryList(&Current->ListEntry);
416 break;
417 }
418 }
419
420 ExFreeToPagedLookasideList(&gProcessLookasideList, Current);
421
422 /* If there are still processes referencing this object we can't destroy it yet */
423 if (! IsListEmpty(&CurIcon->ProcessList))
424 {
425 return TRUE;
426 }
427
428
429 if (! ProcessCleanup)
430 {
431 RemoveEntryList(&CurIcon->ListEntry);
432 }
433
434 CurInfo = IntGetSysCursorInfo(WinSta);
435
436 if (CurInfo->CurrentCursorObject == CurIcon)
437 {
438 /* Hide the cursor if we're destroying the current cursor */
439 IntSetCursor(WinSta, NULL, TRUE);
440 }
441
442 bmpMask = CurIcon->IconInfo.hbmMask;
443 bmpColor = CurIcon->IconInfo.hbmColor;
444
445 /* delete bitmaps */
446 if (bmpMask)
447 {
448 GDIOBJ_SetOwnership(bmpMask, PsGetCurrentProcess());
449 GreDeleteObject(bmpMask);
450 CurIcon->IconInfo.hbmMask = NULL;
451 }
452 if (bmpColor)
453 {
454 GDIOBJ_SetOwnership(bmpColor, PsGetCurrentProcess());
455 GreDeleteObject(bmpColor);
456 CurIcon->IconInfo.hbmColor = NULL;
457 }
458
459 /* We were given a pointer, no need to keep the reference anylonger! */
460 UserDereferenceObject(CurIcon);
461 Ret = UserDeleteObject(CurIcon->Self, otCursorIcon);
462
463 return Ret;
464 }
465
466 VOID FASTCALL
467 IntCleanupCurIcons(struct _EPROCESS *Process, PPROCESSINFO Win32Process)
468 {
469 PWINSTATION_OBJECT WinSta;
470 PCURICON_OBJECT CurIcon, tmp;
471 PCURICON_PROCESS ProcessData;
472
473 WinSta = IntGetWinStaObj();
474 if (WinSta == NULL)
475 {
476 return;
477 }
478
479 LIST_FOR_EACH_SAFE(CurIcon, tmp, &gCurIconList, CURICON_OBJECT, ListEntry)
480 {
481 UserReferenceObject(CurIcon);
482 // if(NT_SUCCESS(UserReferenceObjectByPointer(Object, otCursorIcon)))
483 {
484 LIST_FOR_EACH(ProcessData, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
485 {
486 if (Win32Process == ProcessData->Process)
487 {
488 RemoveEntryList(&CurIcon->ListEntry);
489 IntDestroyCurIconObject(WinSta, CurIcon, TRUE);
490 CurIcon = NULL;
491 break;
492 }
493 }
494
495 // UserDereferenceObject(Object);
496 }
497
498 if (CurIcon)
499 {
500 UserDereferenceObject(CurIcon);
501 }
502 }
503
504 ObDereferenceObject(WinSta);
505 }
506
507 /*
508 * @implemented
509 */
510 HANDLE
511 APIENTRY
512 NtUserCreateCursorIconHandle(PICONINFO IconInfo OPTIONAL, BOOL Indirect)
513 {
514 PCURICON_OBJECT CurIcon;
515 PWINSTATION_OBJECT WinSta;
516 PSURFACE psurfBmp;
517 NTSTATUS Status;
518 HANDLE Ret;
519 DECLARE_RETURN(HANDLE);
520
521 DPRINT("Enter NtUserCreateCursorIconHandle\n");
522 UserEnterExclusive();
523
524 WinSta = IntGetWinStaObj();
525 if (WinSta == NULL)
526 {
527 RETURN((HANDLE)0);
528 }
529
530 if (!(CurIcon = IntCreateCurIconHandle(WinSta)))
531 {
532 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
533 ObDereferenceObject(WinSta);
534 RETURN((HANDLE)0);
535 }
536
537 Ret = CurIcon->Self;
538
539 if (IconInfo)
540 {
541 Status = MmCopyFromCaller(&CurIcon->IconInfo, IconInfo, sizeof(ICONINFO));
542 if (NT_SUCCESS(Status))
543 {
544 /* Copy bitmaps and size info */
545 if (Indirect)
546 {
547 CurIcon->IconInfo.hbmMask = BITMAP_CopyBitmap(CurIcon->IconInfo.hbmMask);
548 CurIcon->IconInfo.hbmColor = BITMAP_CopyBitmap(CurIcon->IconInfo.hbmColor);
549 }
550 if (CurIcon->IconInfo.hbmColor &&
551 (psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmColor)))
552 {
553 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
554 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
555 SURFACE_UnlockSurface(psurfBmp);
556 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmColor, NULL);
557 }
558 if (CurIcon->IconInfo.hbmMask &&
559 (psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmMask)))
560 {
561 if (CurIcon->IconInfo.hbmColor == NULL)
562 {
563 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
564 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy >> 1;
565 }
566 SURFACE_UnlockSurface(psurfBmp);
567 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmMask, NULL);
568 }
569
570 /* Calculate icon hotspot */
571 if (CurIcon->IconInfo.fIcon == TRUE)
572 {
573 CurIcon->IconInfo.xHotspot = CurIcon->Size.cx >> 1;
574 CurIcon->IconInfo.yHotspot = CurIcon->Size.cy >> 1;
575 }
576 }
577 else
578 {
579 SetLastNtError(Status);
580 /* FIXME - Don't exit here */
581 }
582 }
583
584 UserDereferenceObject(CurIcon);
585 ObDereferenceObject(WinSta);
586 RETURN(Ret);
587
588 CLEANUP:
589 DPRINT("Leave NtUserCreateCursorIconHandle, ret=%i\n",_ret_);
590 UserLeave();
591 END_CLEANUP;
592 }
593
594 /*
595 * @implemented
596 */
597 BOOL
598 APIENTRY
599 NtUserGetIconInfo(
600 HANDLE hCurIcon,
601 PICONINFO IconInfo,
602 PUNICODE_STRING lpInstName, // optional
603 PUNICODE_STRING lpResName, // optional
604 LPDWORD pbpp, // optional
605 BOOL bInternal)
606 {
607 ICONINFO ii;
608 PCURICON_OBJECT CurIcon;
609 PWINSTATION_OBJECT WinSta;
610 NTSTATUS Status = STATUS_SUCCESS;
611 BOOL Ret = FALSE;
612 DECLARE_RETURN(BOOL);
613
614 DPRINT("Enter NtUserGetIconInfo\n");
615 UserEnterExclusive();
616
617 if (!IconInfo)
618 {
619 SetLastWin32Error(ERROR_INVALID_PARAMETER);
620 RETURN(FALSE);
621 }
622
623 WinSta = IntGetWinStaObj();
624 if (WinSta == NULL)
625 {
626 RETURN(FALSE);
627 }
628
629 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
630 {
631 ObDereferenceObject(WinSta);
632 RETURN(FALSE);
633 }
634
635 RtlCopyMemory(&ii, &CurIcon->IconInfo, sizeof(ICONINFO));
636
637 /* Copy bitmaps */
638 ii.hbmMask = BITMAP_CopyBitmap(CurIcon->IconInfo.hbmMask);
639 ii.hbmColor = BITMAP_CopyBitmap(CurIcon->IconInfo.hbmColor);
640
641 /* Copy fields */
642 _SEH2_TRY
643 {
644 ProbeForWrite(IconInfo, sizeof(ICONINFO), 1);
645 RtlCopyMemory(IconInfo, &ii, sizeof(ICONINFO));
646
647 if (pbpp)
648 {
649 PSURFACE psurfBmp;
650 int colorBpp = 0;
651
652 ProbeForWrite(pbpp, sizeof(DWORD), 1);
653
654 psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmColor);
655 if (psurfBmp)
656 {
657 colorBpp = BitsPerFormat(psurfBmp->SurfObj.iBitmapFormat);
658 SURFACE_UnlockSurface(psurfBmp);
659 }
660
661 RtlCopyMemory(pbpp, &colorBpp, sizeof(DWORD));
662 }
663
664 }
665 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
666 {
667 Status = _SEH2_GetExceptionCode();
668 }
669 _SEH2_END
670
671 if (NT_SUCCESS(Status))
672 Ret = TRUE;
673 else
674 SetLastNtError(Status);
675
676 UserDereferenceObject(CurIcon);
677 ObDereferenceObject(WinSta);
678 RETURN(Ret);
679
680 CLEANUP:
681 DPRINT("Leave NtUserGetIconInfo, ret=%i\n",_ret_);
682 UserLeave();
683 END_CLEANUP;
684 }
685
686
687 /*
688 * @implemented
689 */
690 BOOL
691 APIENTRY
692 NtUserGetIconSize(
693 HANDLE hCurIcon,
694 UINT istepIfAniCur,
695 PLONG plcx, // &size.cx
696 PLONG plcy) // &size.cy
697 {
698 PCURICON_OBJECT CurIcon;
699 NTSTATUS Status = STATUS_SUCCESS;
700 BOOL bRet = FALSE;
701
702 DPRINT("Enter NtUserGetIconSize\n");
703 UserEnterExclusive();
704
705 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
706 {
707 goto cleanup;
708 }
709
710 _SEH2_TRY
711 {
712 ProbeForWrite(plcx, sizeof(LONG), 1);
713 RtlCopyMemory(plcx, &CurIcon->Size.cx, sizeof(LONG));
714 ProbeForWrite(plcy, sizeof(LONG), 1);
715 RtlCopyMemory(plcy, &CurIcon->Size.cy, sizeof(LONG));
716 }
717 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
718 {
719 Status = _SEH2_GetExceptionCode();
720 }
721 _SEH2_END
722
723 if (NT_SUCCESS(Status))
724 bRet = TRUE;
725 else
726 SetLastNtError(Status); // maybe not, test this
727
728 UserDereferenceObject(CurIcon);
729
730 cleanup:
731 DPRINT("Leave NtUserGetIconSize, ret=%i\n", bRet);
732 UserLeave();
733 return bRet;
734 }
735
736
737 /*
738 * @unimplemented
739 */
740 DWORD
741 APIENTRY
742 NtUserGetCursorFrameInfo(
743 DWORD Unknown0,
744 DWORD Unknown1,
745 DWORD Unknown2,
746 DWORD Unknown3)
747 {
748 UNIMPLEMENTED
749
750 return 0;
751 }
752
753
754 /*
755 * @implemented
756 */
757 BOOL
758 APIENTRY
759 NtUserGetCursorInfo(
760 PCURSORINFO pci)
761 {
762 CURSORINFO SafeCi;
763 PSYSTEM_CURSORINFO CurInfo;
764 PWINSTATION_OBJECT WinSta;
765 NTSTATUS Status = STATUS_SUCCESS;
766 PCURICON_OBJECT CurIcon;
767 BOOL Ret = FALSE;
768 DECLARE_RETURN(BOOL);
769
770 DPRINT("Enter NtUserGetCursorInfo\n");
771 UserEnterExclusive();
772
773 WinSta = IntGetWinStaObj();
774 if (WinSta == NULL)
775 {
776 RETURN(FALSE);
777 }
778
779 CurInfo = IntGetSysCursorInfo(WinSta);
780 CurIcon = (PCURICON_OBJECT)CurInfo->CurrentCursorObject;
781
782 SafeCi.cbSize = sizeof(CURSORINFO);
783 SafeCi.flags = ((CurInfo->ShowingCursor && CurIcon) ? CURSOR_SHOWING : 0);
784 SafeCi.hCursor = (CurIcon ? (HCURSOR)CurIcon->Self : (HCURSOR)0);
785
786 IntGetCursorLocation(WinSta, &SafeCi.ptScreenPos);
787
788 _SEH2_TRY
789 {
790 if (pci->cbSize == sizeof(CURSORINFO))
791 {
792 ProbeForWrite(pci, sizeof(CURSORINFO), 1);
793 RtlCopyMemory(pci, &SafeCi, sizeof(CURSORINFO));
794 Ret = TRUE;
795 }
796 else
797 {
798 SetLastWin32Error(ERROR_INVALID_PARAMETER);
799 }
800 }
801 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
802 {
803 Status = _SEH2_GetExceptionCode();
804 }
805 _SEH2_END;
806 if (!NT_SUCCESS(Status))
807 {
808 SetLastNtError(Status);
809 }
810
811 ObDereferenceObject(WinSta);
812 RETURN(Ret);
813
814 CLEANUP:
815 DPRINT("Leave NtUserGetCursorInfo, ret=%i\n",_ret_);
816 UserLeave();
817 END_CLEANUP;
818 }
819
820
821 /*
822 * @implemented
823 */
824 BOOL
825 APIENTRY
826 NtUserClipCursor(
827 RECTL *UnsafeRect)
828 {
829 /* FIXME - check if process has WINSTA_WRITEATTRIBUTES */
830
831 PWINSTATION_OBJECT WinSta;
832 PSYSTEM_CURSORINFO CurInfo;
833 RECTL Rect;
834 PWINDOW_OBJECT DesktopWindow = NULL;
835 POINT MousePos = {0};
836 DECLARE_RETURN(BOOL);
837
838 DPRINT("Enter NtUserClipCursor\n");
839 UserEnterExclusive();
840
841 WinSta = IntGetWinStaObj();
842 if (WinSta == NULL)
843 {
844 RETURN(FALSE);
845 }
846
847 if (NULL != UnsafeRect && ! NT_SUCCESS(MmCopyFromCaller(&Rect, UnsafeRect, sizeof(RECT))))
848 {
849 ObDereferenceObject(WinSta);
850 SetLastWin32Error(ERROR_INVALID_PARAMETER);
851 RETURN(FALSE);
852 }
853
854 CurInfo = IntGetSysCursorInfo(WinSta);
855 IntGetCursorLocation(WinSta, &MousePos);
856
857 if (WinSta->ActiveDesktop)
858 DesktopWindow = UserGetWindowObject(WinSta->ActiveDesktop->DesktopWindow);
859
860 if ((Rect.right > Rect.left) && (Rect.bottom > Rect.top)
861 && DesktopWindow && UnsafeRect != NULL)
862 {
863 MOUSEINPUT mi;
864
865 CurInfo->CursorClipInfo.IsClipped = TRUE;
866 CurInfo->CursorClipInfo.Left = max(Rect.left, DesktopWindow->Wnd->rcWindow.left);
867 CurInfo->CursorClipInfo.Top = max(Rect.top, DesktopWindow->Wnd->rcWindow.top);
868 CurInfo->CursorClipInfo.Right = min(Rect.right - 1, DesktopWindow->Wnd->rcWindow.right - 1);
869 CurInfo->CursorClipInfo.Bottom = min(Rect.bottom - 1, DesktopWindow->Wnd->rcWindow.bottom - 1);
870
871 mi.dx = MousePos.x;
872 mi.dy = MousePos.y;
873 mi.mouseData = 0;
874 mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
875 mi.time = 0;
876 mi.dwExtraInfo = 0;
877 IntMouseInput(&mi);
878
879 RETURN(TRUE);
880 }
881
882 CurInfo->CursorClipInfo.IsClipped = FALSE;
883 ObDereferenceObject(WinSta);
884
885 RETURN(TRUE);
886
887 CLEANUP:
888 DPRINT("Leave NtUserClipCursor, ret=%i\n",_ret_);
889 UserLeave();
890 END_CLEANUP;
891 }
892
893
894 /*
895 * @implemented
896 */
897 BOOL
898 APIENTRY
899 NtUserDestroyCursor(
900 HANDLE hCurIcon,
901 DWORD Unknown)
902 {
903 PWINSTATION_OBJECT WinSta;
904 PCURICON_OBJECT CurIcon;
905 BOOL ret;
906 DECLARE_RETURN(BOOL);
907
908 DPRINT("Enter NtUserDestroyCursorIcon\n");
909 UserEnterExclusive();
910
911 WinSta = IntGetWinStaObj();
912 if (WinSta == NULL)
913 {
914 RETURN(FALSE);
915 }
916
917 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
918 {
919 ObDereferenceObject(WinSta);
920 RETURN(FALSE);
921 }
922
923 ret = IntDestroyCurIconObject(WinSta, CurIcon, FALSE);
924 /* Note: IntDestroyCurIconObject will remove our reference for us! */
925
926 ObDereferenceObject(WinSta);
927 RETURN(ret);
928
929 CLEANUP:
930 DPRINT("Leave NtUserDestroyCursorIcon, ret=%i\n",_ret_);
931 UserLeave();
932 END_CLEANUP;
933 }
934
935
936 /*
937 * @implemented
938 */
939 HICON
940 APIENTRY
941 NtUserFindExistingCursorIcon(
942 HMODULE hModule,
943 HRSRC hRsrc,
944 LONG cx,
945 LONG cy)
946 {
947 PCURICON_OBJECT CurIcon;
948 PWINSTATION_OBJECT WinSta;
949 HANDLE Ret = (HANDLE)0;
950 DECLARE_RETURN(HICON);
951
952 DPRINT("Enter NtUserFindExistingCursorIcon\n");
953 UserEnterExclusive();
954
955 WinSta = IntGetWinStaObj();
956 if (WinSta == NULL)
957 {
958 RETURN(Ret);
959 }
960
961 CurIcon = IntFindExistingCurIconObject(WinSta, hModule, hRsrc, cx, cy);
962 if (CurIcon)
963 {
964 Ret = CurIcon->Self;
965
966 // IntReleaseCurIconObject(CurIcon);//faxme: is this correct? does IntFindExistingCurIconObject add a ref?
967 ObDereferenceObject(WinSta);
968 RETURN(Ret);
969 }
970
971 SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
972 ObDereferenceObject(WinSta);
973 RETURN((HANDLE)0);
974
975 CLEANUP:
976 DPRINT("Leave NtUserFindExistingCursorIcon, ret=%i\n",_ret_);
977 UserLeave();
978 END_CLEANUP;
979 }
980
981
982 /*
983 * @implemented
984 */
985 BOOL
986 APIENTRY
987 NtUserGetClipCursor(
988 RECTL *lpRect)
989 {
990 /* FIXME - check if process has WINSTA_READATTRIBUTES */
991 PSYSTEM_CURSORINFO CurInfo;
992 PWINSTATION_OBJECT WinSta;
993 RECTL Rect;
994 NTSTATUS Status;
995 DECLARE_RETURN(BOOL);
996
997 DPRINT("Enter NtUserGetClipCursor\n");
998 UserEnterExclusive();
999
1000 if (!lpRect)
1001 RETURN(FALSE);
1002
1003 WinSta = IntGetWinStaObj();
1004 if (WinSta == NULL)
1005 {
1006 RETURN(FALSE);
1007 }
1008
1009 CurInfo = IntGetSysCursorInfo(WinSta);
1010 if (CurInfo->CursorClipInfo.IsClipped)
1011 {
1012 Rect.left = CurInfo->CursorClipInfo.Left;
1013 Rect.top = CurInfo->CursorClipInfo.Top;
1014 Rect.right = CurInfo->CursorClipInfo.Right;
1015 Rect.bottom = CurInfo->CursorClipInfo.Bottom;
1016 }
1017 else
1018 {
1019 Rect.left = 0;
1020 Rect.top = 0;
1021 Rect.right = UserGetSystemMetrics(SM_CXSCREEN);
1022 Rect.bottom = UserGetSystemMetrics(SM_CYSCREEN);
1023 }
1024
1025 Status = MmCopyToCaller(lpRect, &Rect, sizeof(RECT));
1026 if (!NT_SUCCESS(Status))
1027 {
1028 ObDereferenceObject(WinSta);
1029 SetLastNtError(Status);
1030 RETURN(FALSE);
1031 }
1032
1033 ObDereferenceObject(WinSta);
1034
1035 RETURN(TRUE);
1036
1037 CLEANUP:
1038 DPRINT("Leave NtUserGetClipCursor, ret=%i\n",_ret_);
1039 UserLeave();
1040 END_CLEANUP;
1041 }
1042
1043
1044 /*
1045 * @implemented
1046 */
1047 HCURSOR
1048 APIENTRY
1049 NtUserSetCursor(
1050 HCURSOR hCursor)
1051 {
1052 PCURICON_OBJECT CurIcon;
1053 HICON OldCursor;
1054 PWINSTATION_OBJECT WinSta;
1055 DECLARE_RETURN(HCURSOR);
1056
1057 DPRINT("Enter NtUserSetCursor\n");
1058 UserEnterExclusive();
1059
1060 WinSta = IntGetWinStaObj();
1061 if (WinSta == NULL)
1062 {
1063 RETURN(NULL);
1064 }
1065
1066 if (hCursor)
1067 {
1068 if (!(CurIcon = UserGetCurIconObject(hCursor)))
1069 {
1070 ObDereferenceObject(WinSta);
1071 RETURN(NULL);
1072 }
1073 }
1074 else
1075 {
1076 CurIcon = NULL;
1077 }
1078
1079 OldCursor = IntSetCursor(WinSta, CurIcon, FALSE);
1080
1081 if (CurIcon)
1082 {
1083 UserDereferenceObject(CurIcon);
1084 }
1085 ObDereferenceObject(WinSta);
1086
1087 RETURN(OldCursor);
1088
1089 CLEANUP:
1090 DPRINT("Leave NtUserSetCursor, ret=%i\n",_ret_);
1091 UserLeave();
1092 END_CLEANUP;
1093 }
1094
1095
1096 /*
1097 * @implemented
1098 */
1099 BOOL
1100 APIENTRY
1101 NtUserSetCursorContents(
1102 HANDLE hCurIcon,
1103 PICONINFO UnsafeIconInfo)
1104 {
1105 PCURICON_OBJECT CurIcon;
1106 ICONINFO IconInfo;
1107 PSURFACE psurfBmp;
1108 PWINSTATION_OBJECT WinSta;
1109 NTSTATUS Status;
1110 BOOL Ret = FALSE;
1111 DECLARE_RETURN(BOOL);
1112
1113 DPRINT("Enter NtUserSetCursorContents\n");
1114 UserEnterExclusive();
1115
1116 WinSta = IntGetWinStaObj();
1117 if (WinSta == NULL)
1118 {
1119 RETURN(FALSE);
1120 }
1121
1122 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
1123 {
1124 ObDereferenceObject(WinSta);
1125 RETURN(FALSE);
1126 }
1127
1128 /* Copy fields */
1129 Status = MmCopyFromCaller(&IconInfo, UnsafeIconInfo, sizeof(ICONINFO));
1130 if (!NT_SUCCESS(Status))
1131 {
1132 SetLastNtError(Status);
1133 goto done;
1134 }
1135
1136 /* Delete old bitmaps */
1137 if (CurIcon->IconInfo.hbmColor != IconInfo.hbmColor)
1138 {
1139 GreDeleteObject(CurIcon->IconInfo.hbmColor);
1140 }
1141 if (CurIcon->IconInfo.hbmMask != IconInfo.hbmMask)
1142 {
1143 GreDeleteObject(CurIcon->IconInfo.hbmMask);
1144 }
1145
1146 /* Copy new IconInfo field */
1147 CurIcon->IconInfo = IconInfo;
1148
1149 psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmColor);
1150 if (psurfBmp)
1151 {
1152 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
1153 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
1154 SURFACE_UnlockSurface(psurfBmp);
1155 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmColor, NULL);
1156 }
1157 else
1158 {
1159 psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmMask);
1160 if (!psurfBmp)
1161 goto done;
1162
1163 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
1164 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy / 2;
1165
1166 SURFACE_UnlockSurface(psurfBmp);
1167 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmMask, NULL);
1168 }
1169
1170 Ret = TRUE;
1171
1172 done:
1173
1174 if (CurIcon)
1175 {
1176 UserDereferenceObject(CurIcon);
1177 }
1178 ObDereferenceObject(WinSta);
1179 RETURN(Ret);
1180
1181 CLEANUP:
1182 DPRINT("Leave NtUserSetCursorContents, ret=%i\n",_ret_);
1183 UserLeave();
1184 END_CLEANUP;
1185 }
1186
1187
1188 /*
1189 * @implemented
1190 */
1191 #if 0
1192 BOOL
1193 APIENTRY
1194 NtUserSetCursorIconData(
1195 HANDLE Handle,
1196 HMODULE hModule,
1197 PUNICODE_STRING pstrResName,
1198 PICONINFO pIconInfo)
1199 {
1200 PCURICON_OBJECT CurIcon;
1201 PWINSTATION_OBJECT WinSta;
1202 PSURFACE psurfBmp;
1203 NTSTATUS Status = STATUS_SUCCESS;
1204 BOOL Ret = FALSE;
1205 DECLARE_RETURN(BOOL);
1206
1207 DPRINT("Enter NtUserSetCursorIconData\n");
1208 UserEnterExclusive();
1209
1210 WinSta = IntGetWinStaObj();
1211 if (WinSta == NULL)
1212 {
1213 RETURN(FALSE);
1214 }
1215
1216 if (!(CurIcon = UserGetCurIconObject(Handle)))
1217 {
1218 ObDereferenceObject(WinSta);
1219 RETURN(FALSE);
1220 }
1221
1222 CurIcon->hModule = hModule;
1223 CurIcon->hRsrc = NULL; //hRsrc;
1224 CurIcon->hGroupRsrc = NULL; //hGroupRsrc;
1225
1226 _SEH2_TRY
1227 {
1228 ProbeForRead(pIconInfo, sizeof(ICONINFO), 1);
1229 RtlCopyMemory(&CurIcon->IconInfo, pIconInfo, sizeof(ICONINFO));
1230
1231 CurIcon->IconInfo.hbmMask = BITMAP_CopyBitmap(pIconInfo->hbmMask);
1232 CurIcon->IconInfo.hbmColor = BITMAP_CopyBitmap(pIconInfo->hbmColor);
1233
1234 if (CurIcon->IconInfo.hbmColor)
1235 {
1236 if ((psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmColor)))
1237 {
1238 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
1239 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
1240 SURFACE_UnlockSurface(psurfBmp);
1241 GDIOBJ_SetOwnership(GdiHandleTable, CurIcon->IconInfo.hbmMask, NULL);
1242 }
1243 }
1244 if (CurIcon->IconInfo.hbmMask)
1245 {
1246 if (CurIcon->IconInfo.hbmColor == NULL)
1247 {
1248 if ((psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmMask)))
1249 {
1250 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
1251 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
1252 SURFACE_UnlockSurface(psurfBmp);
1253 }
1254 }
1255 GDIOBJ_SetOwnership(GdiHandleTable, CurIcon->IconInfo.hbmMask, NULL);
1256 }
1257 }
1258 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1259 {
1260 Status = _SEH2_GetExceptionCode();
1261 }
1262 _SEH2_END
1263
1264 if (!NT_SUCCESS(Status))
1265 SetLastNtError(Status);
1266 else
1267 Ret = TRUE;
1268
1269 UserDereferenceObject(CurIcon);
1270 ObDereferenceObject(WinSta);
1271 RETURN(Ret);
1272
1273 CLEANUP:
1274 DPRINT("Leave NtUserSetCursorIconData, ret=%i\n",_ret_);
1275 UserLeave();
1276 END_CLEANUP;
1277 }
1278 #else
1279 BOOL
1280 APIENTRY
1281 NtUserSetCursorIconData(
1282 HANDLE hCurIcon,
1283 PBOOL fIcon,
1284 POINT *Hotspot,
1285 HMODULE hModule,
1286 HRSRC hRsrc,
1287 HRSRC hGroupRsrc)
1288 {
1289 PCURICON_OBJECT CurIcon;
1290 PWINSTATION_OBJECT WinSta;
1291 NTSTATUS Status;
1292 POINT SafeHotspot;
1293 BOOL Ret = FALSE;
1294 DECLARE_RETURN(BOOL);
1295
1296 DPRINT("Enter NtUserSetCursorIconData\n");
1297 UserEnterExclusive();
1298
1299 WinSta = IntGetWinStaObj();
1300 if (WinSta == NULL)
1301 {
1302 RETURN(FALSE);
1303 }
1304
1305 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
1306 {
1307 ObDereferenceObject(WinSta);
1308 RETURN(FALSE);
1309 }
1310
1311 CurIcon->hModule = hModule;
1312 CurIcon->hRsrc = hRsrc;
1313 CurIcon->hGroupRsrc = hGroupRsrc;
1314
1315 /* Copy fields */
1316 if (fIcon)
1317 {
1318 Status = MmCopyFromCaller(&CurIcon->IconInfo.fIcon, fIcon, sizeof(BOOL));
1319 if (!NT_SUCCESS(Status))
1320 {
1321 SetLastNtError(Status);
1322 goto done;
1323 }
1324 }
1325 else
1326 {
1327 if (!Hotspot)
1328 Ret = TRUE;
1329 }
1330
1331 if (Hotspot)
1332 {
1333 Status = MmCopyFromCaller(&SafeHotspot, Hotspot, sizeof(POINT));
1334 if (NT_SUCCESS(Status))
1335 {
1336 CurIcon->IconInfo.xHotspot = SafeHotspot.x;
1337 CurIcon->IconInfo.yHotspot = SafeHotspot.y;
1338
1339 Ret = TRUE;
1340 }
1341 else
1342 SetLastNtError(Status);
1343 }
1344
1345 if (!fIcon && !Hotspot)
1346 {
1347 Ret = TRUE;
1348 }
1349
1350 done:
1351 UserDereferenceObject(CurIcon);
1352 ObDereferenceObject(WinSta);
1353 RETURN(Ret);
1354
1355
1356 CLEANUP:
1357 DPRINT("Leave NtUserSetCursorIconData, ret=%i\n",_ret_);
1358 UserLeave();
1359 END_CLEANUP;
1360 }
1361 #endif
1362
1363 /*
1364 * @unimplemented
1365 */
1366 BOOL
1367 APIENTRY
1368 NtUserSetSystemCursor(
1369 HCURSOR hcur,
1370 DWORD id)
1371 {
1372 return FALSE;
1373 }
1374
1375 BOOL
1376 UserDrawIconEx(
1377 HDC hDc,
1378 INT xLeft,
1379 INT yTop,
1380 PCURICON_OBJECT pIcon,
1381 INT cxWidth,
1382 INT cyHeight,
1383 UINT istepIfAniCur,
1384 HBRUSH hbrFlickerFreeDraw,
1385 UINT diFlags)
1386 {
1387 BOOL Ret = FALSE;
1388 HBITMAP hbmMask, hbmColor;
1389 BITMAP bmpMask, bmpColor;
1390 BOOL DoFlickerFree;
1391 SIZE IconSize;
1392
1393 HDC hdcOff;
1394 HGDIOBJ hOldOffBrush = 0;
1395 HGDIOBJ hOldOffBmp = 0;
1396 HBITMAP hbmOff = 0;
1397 HDC hdcMask = 0;
1398 HGDIOBJ hOldMask = NULL;
1399 HDC hdcImage = 0;
1400 HGDIOBJ hOldImage = NULL;
1401 BOOL bAlpha = FALSE;
1402
1403 hbmMask = pIcon->IconInfo.hbmMask;
1404 hbmColor = pIcon->IconInfo.hbmColor;
1405
1406 if (istepIfAniCur)
1407 DPRINT1("NtUserDrawIconEx: istepIfAniCur is not supported!\n");
1408
1409 if (!hbmMask || !IntGdiGetObject(hbmMask, sizeof(BITMAP), (PVOID)&bmpMask))
1410 {
1411 return FALSE;
1412 }
1413
1414 if (hbmColor && !IntGdiGetObject(hbmColor, sizeof(BITMAP), (PVOID)&bmpColor))
1415 {
1416 return FALSE;
1417 }
1418
1419 if (hbmColor)
1420 {
1421 IconSize.cx = bmpColor.bmWidth;
1422 IconSize.cy = bmpColor.bmHeight;
1423 }
1424 else
1425 {
1426 IconSize.cx = bmpMask.bmWidth;
1427 IconSize.cy = bmpMask.bmHeight / 2;
1428 }
1429
1430 /* NtGdiCreateCompatibleBitmap will create a monochrome bitmap
1431 when cxWidth or cyHeight is 0 */
1432 if ((bmpColor.bmBitsPixel == 32) && (cxWidth != 0) && (cyHeight != 0))
1433 {
1434 SURFACE *psurfOff = NULL;
1435 PFN_DIB_GetPixel fnSource_GetPixel = NULL;
1436 INT x, y;
1437
1438 /* In order to correctly display 32 bit icons Windows first scans the image,
1439 because information about transparency is not stored in any image's headers */
1440 psurfOff = SURFACE_LockSurface(hbmColor ? hbmColor : hbmMask);
1441 if (psurfOff)
1442 {
1443 fnSource_GetPixel = DibFunctionsForBitmapFormat[psurfOff->SurfObj.iBitmapFormat].DIB_GetPixel;
1444 if (fnSource_GetPixel)
1445 {
1446 for (x = 0; x < psurfOff->SurfObj.sizlBitmap.cx; x++)
1447 {
1448 for (y = 0; y < psurfOff->SurfObj.sizlBitmap.cy; y++)
1449 {
1450 bAlpha = ((BYTE)(fnSource_GetPixel(&psurfOff->SurfObj, x, y) >> 24) & 0xff);
1451 if (bAlpha)
1452 break;
1453 }
1454 if (bAlpha)
1455 break;
1456 }
1457 }
1458 SURFACE_UnlockSurface(psurfOff);
1459 }
1460 }
1461
1462 if (!diFlags)
1463 diFlags = DI_NORMAL;
1464
1465 if (!cxWidth)
1466 cxWidth = ((diFlags & DI_DEFAULTSIZE) ?
1467 UserGetSystemMetrics(SM_CXICON) : IconSize.cx);
1468
1469 if (!cyHeight)
1470 cyHeight = ((diFlags & DI_DEFAULTSIZE) ?
1471 UserGetSystemMetrics(SM_CYICON) : IconSize.cy);
1472
1473 DoFlickerFree = (hbrFlickerFreeDraw &&
1474 (GDI_HANDLE_GET_TYPE(hbrFlickerFreeDraw) == GDI_OBJECT_TYPE_BRUSH));
1475
1476 if (DoFlickerFree || bAlpha)
1477 {
1478 RECTL r;
1479 BITMAP bm;
1480 SURFACE *psurfOff = NULL;
1481
1482 r.right = cxWidth;
1483 r.bottom = cyHeight;
1484
1485 hdcOff = NtGdiCreateCompatibleDC(hDc);
1486 if (!hdcOff)
1487 {
1488 DPRINT1("NtGdiCreateCompatibleDC() failed!\n");
1489 return FALSE;
1490 }
1491
1492 hbmOff = NtGdiCreateCompatibleBitmap(hDc, cxWidth, cyHeight);
1493 if (!hbmOff)
1494 {
1495 DPRINT1("NtGdiCreateCompatibleBitmap() failed!\n");
1496 goto cleanup;
1497 }
1498
1499 /* make sure we have a 32 bit offscreen bitmap
1500 otherwise we can't do alpha blending */
1501 psurfOff = SURFACE_LockSurface(hbmOff);
1502 if (psurfOff == NULL)
1503 {
1504 DPRINT1("BITMAPOBJ_LockBitmap() failed!\n");
1505 goto cleanup;
1506 }
1507 BITMAP_GetObject(psurfOff, sizeof(BITMAP), (PVOID)&bm);
1508
1509 if (bm.bmBitsPixel != 32)
1510 bAlpha = FALSE;
1511
1512 SURFACE_UnlockSurface(psurfOff);
1513
1514 hOldOffBmp = NtGdiSelectBitmap(hdcOff, hbmOff);
1515 if (!hOldOffBmp)
1516 {
1517 DPRINT1("NtGdiSelectBitmap() failed!\n");
1518 goto cleanup;
1519 }
1520
1521 if (DoFlickerFree)
1522 {
1523 hOldOffBrush = NtGdiSelectBrush(hdcOff, hbrFlickerFreeDraw);
1524 if (!hOldOffBrush)
1525 {
1526 DPRINT1("NtGdiSelectBrush() failed!\n");
1527 goto cleanup;
1528 }
1529
1530 NtGdiPatBlt(hdcOff, 0, 0, r.right, r.bottom, PATCOPY);
1531 }
1532 }
1533 else
1534 hdcOff = hDc;
1535
1536 if (diFlags & DI_IMAGE)
1537 {
1538 hdcImage = NtGdiCreateCompatibleDC(hDc);
1539 if (!hdcImage)
1540 {
1541 DPRINT1("NtGdiCreateCompatibleDC() failed!\n");
1542 goto cleanup;
1543 }
1544 hOldImage = NtGdiSelectBitmap(hdcImage, (hbmColor ? hbmColor : hbmMask));
1545 if (!hOldImage)
1546 {
1547 DPRINT("NtGdiSelectBitmap() failed!\n");
1548 goto cleanup;
1549 }
1550 }
1551
1552 /* If DI_IMAGE flag is specified and hbmMask exists, then always use mask for drawing */
1553 if (diFlags & DI_MASK || (diFlags & DI_IMAGE && hbmMask))
1554 {
1555 hdcMask = NtGdiCreateCompatibleDC(hDc);
1556 if (!hdcMask)
1557 {
1558 DPRINT1("NtGdiCreateCompatibleDC() failed!\n");
1559 goto cleanup;
1560 }
1561
1562 hOldMask = NtGdiSelectBitmap(hdcMask, hbmMask);
1563 if (!hOldMask)
1564 {
1565 DPRINT("NtGdiSelectBitmap() failed!\n");
1566 goto cleanup;
1567 }
1568 }
1569
1570 if (hdcMask || hdcImage)
1571 {
1572 GreStretchBltMask(hdcOff,
1573 (DoFlickerFree || bAlpha) ? 0 : xLeft,
1574 (DoFlickerFree || bAlpha) ? 0 : yTop,
1575 cxWidth,
1576 cyHeight,
1577 hdcImage ? hdcImage : hdcMask,
1578 0,
1579 ((diFlags & DI_MASK && !(diFlags & DI_IMAGE)) ||
1580 (diFlags & DI_IMAGE && hbmColor) ? 0 : IconSize.cy),
1581 IconSize.cx,
1582 IconSize.cy,
1583 SRCCOPY,
1584 0,
1585 hdcImage ? hdcMask : NULL);
1586 }
1587
1588 if (hOldMask) NtGdiSelectBitmap(hdcMask, hOldMask);
1589 if (hOldImage) NtGdiSelectBitmap(hdcImage, hOldImage);
1590 if (hdcImage) NtGdiDeleteObjectApp(hdcImage);
1591 if (hdcMask) NtGdiDeleteObjectApp(hdcMask);
1592
1593 if (bAlpha)
1594 {
1595 BITMAP bm;
1596 SURFACE *psurfOff = NULL;
1597 PBYTE pBits = NULL;
1598 BLENDFUNCTION BlendFunc;
1599 DWORD Pixel;
1600 BYTE Red, Green, Blue, Alpha;
1601 DWORD Count = 0;
1602 INT i, j;
1603
1604 psurfOff = SURFACE_LockSurface(hbmOff);
1605 if (psurfOff == NULL)
1606 {
1607 DPRINT1("BITMAPOBJ_LockBitmap() failed!\n");
1608 goto cleanup;
1609 }
1610 BITMAP_GetObject(psurfOff, sizeof(BITMAP), (PVOID)&bm);
1611
1612 pBits = ExAllocatePoolWithTag(PagedPool, bm.bmWidthBytes * abs(bm.bmHeight), TAG_BITMAP);
1613 if (pBits == NULL)
1614 {
1615 DPRINT1("ExAllocatePoolWithTag() failed!\n");
1616 SURFACE_UnlockSurface(psurfOff);
1617 goto cleanup;
1618 }
1619
1620 /* get icon bits */
1621 IntGetBitmapBits(psurfOff, bm.bmWidthBytes * abs(bm.bmHeight), pBits);
1622
1623 /* premultiply with the alpha channel value */
1624 for (i = 0; i < cyHeight; i++)
1625 {
1626 for (j = 0; j < cxWidth; j++)
1627 {
1628 Pixel = *(DWORD *)(pBits + Count);
1629
1630 Alpha = ((BYTE)(Pixel >> 24) & 0xff);
1631
1632 Red = (((BYTE)(Pixel >> 0)) * Alpha) / 0xff;
1633 Green = (((BYTE)(Pixel >> 8)) * Alpha) / 0xff;
1634 Blue = (((BYTE)(Pixel >> 16)) * Alpha) / 0xff;
1635
1636 *(DWORD *)(pBits + Count) = (DWORD)(Red | (Green << 8) | (Blue << 16) | (Alpha << 24));
1637
1638 Count += sizeof(DWORD);
1639 }
1640 }
1641
1642 /* set icon bits */
1643 IntSetBitmapBits(psurfOff, bm.bmWidthBytes * abs(bm.bmHeight), pBits);
1644 ExFreePoolWithTag(pBits, TAG_BITMAP);
1645
1646 SURFACE_UnlockSurface(psurfOff);
1647
1648 BlendFunc.BlendOp = AC_SRC_OVER;
1649 BlendFunc.BlendFlags = 0;
1650 BlendFunc.SourceConstantAlpha = 255;
1651 BlendFunc.AlphaFormat = AC_SRC_ALPHA;
1652
1653 NtGdiAlphaBlend(hDc, xLeft, yTop, cxWidth, cyHeight,
1654 hdcOff, 0, 0, cxWidth, cyHeight, BlendFunc, 0);
1655 }
1656 else if (DoFlickerFree)
1657 {
1658 NtGdiBitBlt(hDc, xLeft, yTop, cxWidth,
1659 cyHeight, hdcOff, 0, 0, SRCCOPY, 0, 0);
1660 }
1661
1662 Ret = TRUE;
1663
1664 cleanup:
1665 if (DoFlickerFree || bAlpha)
1666 {
1667 if (hOldOffBmp) NtGdiSelectBitmap(hdcOff, hOldOffBmp);
1668 if (hOldOffBrush) NtGdiSelectBrush(hdcOff, hOldOffBrush);
1669 if (hbmOff) GreDeleteObject(hbmOff);
1670 if (hdcOff) NtGdiDeleteObjectApp(hdcOff);
1671 }
1672
1673 return Ret;
1674 }
1675
1676 /*
1677 * @implemented
1678 */
1679 BOOL
1680 APIENTRY
1681 NtUserDrawIconEx(
1682 HDC hdc,
1683 int xLeft,
1684 int yTop,
1685 HICON hIcon,
1686 int cxWidth,
1687 int cyHeight,
1688 UINT istepIfAniCur,
1689 HBRUSH hbrFlickerFreeDraw,
1690 UINT diFlags,
1691 DWORD Unknown0,
1692 DWORD Unknown1)
1693 {
1694 PCURICON_OBJECT pIcon;
1695 BOOL Ret;
1696
1697 DPRINT("Enter NtUserDrawIconEx\n");
1698 UserEnterExclusive();
1699
1700 if (!(pIcon = UserGetCurIconObject(hIcon)))
1701 {
1702 DPRINT1("UserGetCurIconObject() failed!\n");
1703 UserLeave();
1704 return FALSE;
1705 }
1706
1707 Ret = UserDrawIconEx(hdc,
1708 xLeft,
1709 yTop,
1710 pIcon,
1711 cxWidth,
1712 cyHeight,
1713 istepIfAniCur,
1714 hbrFlickerFreeDraw,
1715 diFlags);
1716
1717 UserDereferenceObject(pIcon);
1718
1719 UserLeave();
1720 return Ret;
1721 }
1722
1723 /* Called from NtUserCallOneParam with Routine ONEPARAM_ROUTINE_SHOWCURSOR
1724 * User32 macro NtUserShowCursor */
1725 int
1726 APIENTRY
1727 UserShowCursor(BOOL bShow)
1728 {
1729 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1730 PWINSTATION_OBJECT WinSta = pti->Desktop->WindowStation;
1731 PSYSTEM_CURSORINFO CurInfo;
1732
1733 HDC Screen;
1734 PDC dc;
1735 SURFOBJ *SurfObj;
1736 SURFACE *psurfDc;
1737 PDEVOBJ *ppdev;
1738 GDIPOINTER *pgp;
1739 int showpointer=0;
1740
1741 if (!(Screen = IntGetScreenDC()))
1742 {
1743 return showpointer; /* No mouse */
1744 }
1745
1746 dc = DC_LockDc(Screen);
1747
1748 if (!dc)
1749 {
1750 return showpointer; /* No mouse */
1751 }
1752
1753 psurfDc = dc->dclevel.pSurface;
1754
1755 if (!psurfDc)
1756 {
1757 DC_UnlockDc(dc);
1758 return showpointer; /* No Mouse */
1759 }
1760
1761 SurfObj = &psurfDc->SurfObj;
1762 if (SurfObj == NULL)
1763 {
1764 DC_UnlockDc(dc);
1765 return showpointer; /* No mouse */
1766 }
1767
1768 ppdev = GDIDEV(SurfObj);
1769
1770 if (ppdev == NULL)
1771 {
1772 DC_UnlockDc(dc);
1773 return showpointer; /* No mouse */
1774 }
1775
1776 pgp = &ppdev->Pointer;
1777
1778 CurInfo = IntGetSysCursorInfo(WinSta);
1779
1780 if (bShow == FALSE)
1781 {
1782 pgp->ShowPointer--;
1783 showpointer = pgp->ShowPointer;
1784
1785 if (showpointer >= 0)
1786 {
1787 //ppdev->SafetyRemoveCount = 1;
1788 //ppdev->SafetyRemoveLevel = 1;
1789 IntEngMovePointer(SurfObj,-1,-1,NULL);
1790 CurInfo->ShowingCursor = 0;
1791 }
1792
1793 }
1794 else
1795 {
1796 pgp->ShowPointer++;
1797 showpointer = pgp->ShowPointer;
1798
1799 /* Show Cursor */
1800 if (showpointer < 0)
1801 {
1802 //ppdev->SafetyRemoveCount = 0;
1803 //ppdev->SafetyRemoveLevel = 0;
1804 IntEngMovePointer(SurfObj,-1,-1,NULL);
1805 CurInfo->ShowingCursor = CURSOR_SHOWING;
1806 }
1807 }
1808
1809 DC_UnlockDc(dc);
1810 return showpointer;
1811 }