xref: /reactos/win32ss/user/ntuser/cursoricon.c (revision 80733143)
1 /*
2  * COPYRIGHT:        See COPYING in the top level directory
3  * PROJECT:          ReactOS Win32k subsystem
4  * PURPOSE:          Cursor and icon functions
5  * FILE:             win32ss/user/ntuser/cursoricon.c
6  * PROGRAMER:        ReactOS Team
7  */
8 /*
9  * We handle two types of cursors/icons:
10  * - Private
11  *   Loaded without LR_SHARED flag
12  *   Private to a process
13  *   Can be deleted by calling NtDestroyCursorIcon()
14  *   CurIcon->hModule, CurIcon->hRsrc and CurIcon->hGroupRsrc set to NULL
15  * - Shared
16  *   Loaded with LR_SHARED flag
17  *   Possibly shared by multiple processes
18  *   Immune to NtDestroyCursorIcon()
19  *   CurIcon->hModule, CurIcon->hRsrc and CurIcon->hGroupRsrc are valid
20  */
21 
22 #include <win32k.h>
23 DBG_DEFAULT_CHANNEL(UserIcon);
24 
25 SYSTEM_CURSORINFO gSysCursorInfo;
26 
27 PCURICON_OBJECT gcurFirst = NULL; // After all is done, this should be WINLOGO!
28 
29 //
30 //   System Cursors
31 //
32 SYSTEMCURICO gasyscur[] = {
33     {OCR_NORMAL,     NULL},
34     {OCR_IBEAM,      NULL},
35     {OCR_WAIT,       NULL},
36     {OCR_CROSS,      NULL},
37     {OCR_UP,         NULL},
38     {OCR_ICON,       NULL},
39     {OCR_SIZE,       NULL},
40     {OCR_SIZENWSE,   NULL},
41     {OCR_SIZENESW,   NULL},
42     {OCR_SIZEWE,     NULL},
43     {OCR_SIZENS,     NULL},
44     {OCR_SIZEALL,    NULL},
45     {OCR_NO,         NULL},
46     {OCR_HAND,       NULL},
47     {OCR_APPSTARTING,NULL},
48     {OCR_HELP,       NULL},
49     };
50 
51 //
52 //   System Icons
53 //
54 SYSTEMCURICO gasysico[] = {
55     {OIC_SAMPLE, NULL},
56     {OIC_HAND,   NULL},
57     {OIC_QUES,   NULL},
58     {OIC_BANG,   NULL},
59     {OIC_NOTE,   NULL},
60     {OIC_WINLOGO,NULL},
61     };
62 
63 BOOL
64 InitCursorImpl(VOID)
65 {
66     gSysCursorInfo.Enabled = FALSE;
67     gSysCursorInfo.ButtonsDown = 0;
68     gSysCursorInfo.bClipped = FALSE;
69     gSysCursorInfo.LastBtnDown = 0;
70     gSysCursorInfo.CurrentCursorObject = NULL;
71     gSysCursorInfo.ShowingCursor = -1;
72     gSysCursorInfo.ClickLockActive = FALSE;
73     gSysCursorInfo.ClickLockTime = 0;
74 
75     return TRUE;
76 }
77 
78 static
79 VOID
80 IntInsertCursorIntoList(
81     _Inout_ PCURICON_OBJECT pcur)
82 {
83     PPROCESSINFO ppi = pcur->head.ppi;
84     PCURICON_OBJECT *ppcurHead;
85     NT_ASSERT((pcur->CURSORF_flags & (CURSORF_GLOBAL|CURSORF_LRSHARED)) != 0);
86     NT_ASSERT((pcur->CURSORF_flags & CURSORF_LINKED) == 0);
87 
88     /* Get the right list head */
89     ppcurHead = (pcur->CURSORF_flags & CURSORF_GLOBAL) ?
90         &gcurFirst : &ppi->pCursorCache;
91 
92     UserReferenceObject(pcur);
93     pcur->pcurNext = *ppcurHead;
94     *ppcurHead = pcur;
95     pcur->CURSORF_flags |= CURSORF_LINKED;
96 }
97 
98 // FIXME: should think about using a LIST_ENTRY!
99 static
100 VOID
101 IntRemoveCursorFromList(
102     _Inout_ PCURICON_OBJECT pcur)
103 {
104     PPROCESSINFO ppi = pcur->head.ppi;
105     PCURICON_OBJECT *ppcurHead;
106     PCURICON_OBJECT *ppcur;
107     NT_ASSERT((pcur->CURSORF_flags & (CURSORF_GLOBAL|CURSORF_LRSHARED)) != 0);
108     NT_ASSERT((pcur->CURSORF_flags & CURSORF_LINKED) != 0);
109 
110     /* Get the right list head */
111     ppcurHead = (pcur->CURSORF_flags & CURSORF_GLOBAL) ?
112         &gcurFirst : &ppi->pCursorCache;
113 
114     /* Loop all cursors in the cache */
115     for (ppcur = ppcurHead;
116          (*ppcur) != NULL;
117          ppcur = &(*ppcur)->pcurNext)
118     {
119         /* Check if this is the one we are looking for */
120         if ((*ppcur) == pcur)
121         {
122             /* Remove it from the list */
123             (*ppcur) = pcur->pcurNext;
124 
125             /* Dereference it */
126             UserDereferenceObject(pcur);
127             pcur->CURSORF_flags &= ~CURSORF_LINKED;
128             return;
129         }
130     }
131 
132     /* We did not find it, this must not happen */
133     NT_ASSERT(FALSE);
134 }
135 
136 VOID
137 IntLoadSystenIcons(HICON hcur, DWORD id)
138 {
139     PCURICON_OBJECT pcur;
140     int i;
141     PPROCESSINFO ppi;
142 
143     if (hcur)
144     {
145         pcur = UserGetCurIconObject(hcur);
146         if (!pcur)
147         {
148             EngSetLastError(ERROR_INVALID_CURSOR_HANDLE);
149             return;
150         }
151 
152         ppi = PsGetCurrentProcessWin32Process();
153 
154         if (!(ppi->W32PF_flags & W32PF_CREATEDWINORDC))
155            return;
156 
157         // Set Small Window Icon and do not link.
158         if ( id == OIC_WINLOGO+1 )
159         {
160             pcur->CURSORF_flags |= CURSORF_GLOBAL;
161             UserReferenceObject(pcur);
162             pcur->head.ppi = NULL;
163             return;
164         }
165 
166         for (i = 0 ; i < 6; i++)
167         {
168             if (gasysico[i].type == id)
169             {
170                 gasysico[i].handle = pcur;
171                 pcur->CURSORF_flags |= CURSORF_GLOBAL;
172 
173                 //
174                 //  The active switch between LR shared and Global public.
175                 //  This is hacked around to support this while at the initial system start up.
176                 //
177                 pcur->head.ppi = NULL;
178 
179                 IntInsertCursorIntoList(pcur);
180                 return;
181             }
182         }
183     }
184 }
185 
186 PSYSTEM_CURSORINFO
187 IntGetSysCursorInfo(VOID)
188 {
189     return &gSysCursorInfo;
190 }
191 
192 FORCEINLINE
193 BOOL
194 is_icon(PCURICON_OBJECT object)
195 {
196     return MAKEINTRESOURCE(object->rt) == RT_ICON;
197 }
198 
199 /* This function creates a reference for the object! */
200 PCURICON_OBJECT FASTCALL UserGetCurIconObject(HCURSOR hCurIcon)
201 {
202     PCURICON_OBJECT CurIcon;
203 
204     if (!hCurIcon)
205     {
206         EngSetLastError(ERROR_INVALID_CURSOR_HANDLE);
207         return NULL;
208     }
209 
210     if (UserObjectInDestroy(hCurIcon))
211     {
212         WARN("Requesting invalid/destroyed cursor.\n");
213         EngSetLastError(ERROR_INVALID_CURSOR_HANDLE);
214         return NULL;
215     }
216 
217     CurIcon = (PCURICON_OBJECT)UserReferenceObjectByHandle(hCurIcon, TYPE_CURSOR);
218     if (!CurIcon)
219     {
220         /* We never set ERROR_INVALID_ICON_HANDLE. lets hope noone ever checks for it */
221         EngSetLastError(ERROR_INVALID_CURSOR_HANDLE);
222         return NULL;
223     }
224 
225     ASSERT(CurIcon->head.cLockObj >= 1);
226     return CurIcon;
227 }
228 
229 PCURICON_OBJECT
230 IntSystemSetCursor(PCURICON_OBJECT pcurNew)
231 {
232     PCURICON_OBJECT pcurOld = UserSetCursor(pcurNew, FALSE);
233     if (pcurNew) UserReferenceObject(pcurNew);
234     if (pcurOld) UserDereferenceObject(pcurOld);
235     return pcurOld;
236 }
237 
238 BOOL UserSetCursorPos( INT x, INT y, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook)
239 {
240     PWND DesktopWindow;
241     PSYSTEM_CURSORINFO CurInfo;
242     MSG Msg;
243     RECTL rcClip;
244     POINT pt;
245 
246     if (!(DesktopWindow = UserGetDesktopWindow()))
247     {
248         return FALSE;
249     }
250 
251     CurInfo = IntGetSysCursorInfo();
252 
253     /* Clip cursor position */
254     if (!CurInfo->bClipped)
255         rcClip = DesktopWindow->rcClient;
256     else
257         rcClip = CurInfo->rcClip;
258 
259     if (x >= rcClip.right)  x = rcClip.right - 1;
260     if (x < rcClip.left)    x = rcClip.left;
261     if (y >= rcClip.bottom) y = rcClip.bottom - 1;
262     if (y < rcClip.top)     y = rcClip.top;
263 
264     pt.x = x;
265     pt.y = y;
266 
267     /* 1. Generate a mouse move message, this sets the htEx and Track Window too. */
268     Msg.message = WM_MOUSEMOVE;
269     Msg.wParam = UserGetMouseButtonsState();
270     Msg.lParam = MAKELPARAM(x, y);
271     Msg.pt = pt;
272     co_MsqInsertMouseMessage(&Msg, flags, dwExtraInfo, Hook);
273 
274     /* 2. Store the new cursor position */
275     gpsi->ptCursor = pt;
276 
277     return TRUE;
278 }
279 
280 HANDLE
281 IntCreateCurIconHandle(BOOLEAN Animated)
282 {
283     PCURICON_OBJECT CurIcon;
284     HANDLE hCurIcon;
285 
286     CurIcon = UserCreateObject(
287         gHandleTable,
288         NULL,
289         GetW32ThreadInfo(),
290         &hCurIcon,
291         TYPE_CURSOR,
292         Animated ? sizeof(ACON) : sizeof(CURICON_OBJECT));
293 
294     if (!CurIcon)
295     {
296         EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
297         return FALSE;
298     }
299 
300     if (Animated)
301     {
302         /* We MUST set this flag, to track whether this is an ACON! */
303         CurIcon->CURSORF_flags |= CURSORF_ACON;
304     }
305 
306     NT_ASSERT(CurIcon->pcurNext == NULL);
307     UserDereferenceObject(CurIcon);
308 
309     return hCurIcon;
310 }
311 
312 BOOLEAN
313 IntDestroyCurIconObject(
314     _In_ PVOID Object)
315 {
316     PCURICON_OBJECT CurIcon = Object;
317 
318     /* Check if the cursor is in a list */
319     if (CurIcon->CURSORF_flags & CURSORF_LINKED)
320     {
321         /* Remove the cursor from it's list */
322         IntRemoveCursorFromList(CurIcon);
323     }
324 
325     /* We just mark the handle as being destroyed.
326      * Deleting all the stuff will be deferred to the actual struct free. */
327     UserDeleteObject(CurIcon->head.h, TYPE_CURSOR);
328     return TRUE;
329 }
330 
331 VOID
332 FreeCurIconObject(
333     _In_ PVOID Object)
334 {
335     PCURICON_OBJECT CurIcon = Object;
336 
337     if (!(CurIcon->CURSORF_flags & CURSORF_ACON))
338     {
339         HBITMAP bmpMask = CurIcon->hbmMask;
340         HBITMAP bmpColor = CurIcon->hbmColor;
341         HBITMAP bmpAlpha = CurIcon->hbmAlpha;
342 
343         /* Delete bitmaps */
344         if (bmpMask)
345         {
346             GreSetObjectOwner(bmpMask, GDI_OBJ_HMGR_POWNED);
347             NT_VERIFY(GreDeleteObject(bmpMask) == TRUE);
348             CurIcon->hbmMask = NULL;
349         }
350         if (bmpColor)
351         {
352             GreSetObjectOwner(bmpColor, GDI_OBJ_HMGR_POWNED);
353             NT_VERIFY(GreDeleteObject(bmpColor) == TRUE);
354             CurIcon->hbmColor = NULL;
355         }
356         if (bmpAlpha)
357         {
358             GreSetObjectOwner(bmpAlpha, GDI_OBJ_HMGR_POWNED);
359             NT_VERIFY(GreDeleteObject(bmpAlpha) == TRUE);
360             CurIcon->hbmAlpha = NULL;
361         }
362     }
363     else
364     {
365         PACON AniCurIcon = (PACON)CurIcon;
366         UINT i;
367 
368         for (i = 0; i < AniCurIcon->cpcur; i++)
369         {
370             UserDereferenceObject(AniCurIcon->aspcur[i]);
371             NT_VERIFY(IntDestroyCurIconObject(AniCurIcon->aspcur[i]) == TRUE);
372         }
373         ExFreePoolWithTag(AniCurIcon->aspcur, USERTAG_CURSOR);
374     }
375 
376     if (CurIcon->CURSORF_flags & CURSORF_LRSHARED)
377     {
378         if (!IS_INTRESOURCE(CurIcon->strName.Buffer))
379             ExFreePoolWithTag(CurIcon->strName.Buffer, TAG_STRING);
380         if (CurIcon->atomModName)
381             RtlDeleteAtomFromAtomTable(gAtomTable, CurIcon->atomModName);
382         CurIcon->strName.Buffer = NULL;
383         CurIcon->atomModName = 0;
384     }
385 
386     /* Finally free the thing */
387     FreeProcMarkObject(CurIcon);
388 }
389 
390 VOID FASTCALL
391 IntCleanupCurIconCache(PPROCESSINFO Win32Process)
392 {
393     PCURICON_OBJECT CurIcon;
394 
395     /* Run through the list of icon objects */
396     while (Win32Process->pCursorCache)
397     {
398         CurIcon = Win32Process->pCursorCache;
399         Win32Process->pCursorCache = CurIcon->pcurNext;
400         UserDereferenceObject(CurIcon);
401     }
402 }
403 
404 /*
405  * @implemented
406  */
407 _Success_(return != FALSE)
408 BOOL
409 NTAPI
410 NtUserGetIconInfo(
411     _In_ HANDLE hCurIcon,
412     _Out_opt_ PICONINFO IconInfo,
413     _Inout_opt_ PUNICODE_STRING lpModule,
414     _Inout_opt_ PUNICODE_STRING lpResName,
415     _Out_opt_ LPDWORD pbpp,
416     _In_ BOOL bInternal)
417 {
418     ICONINFO ii;
419     PCURICON_OBJECT CurIcon;
420     NTSTATUS Status = STATUS_SUCCESS;
421     BOOL Ret = FALSE;
422     DWORD colorBpp = 0;
423 
424     TRACE("Enter NtUserGetIconInfo\n");
425 
426     /* Check if something was actually asked */
427     if (!IconInfo && !lpModule && !lpResName)
428     {
429         WARN("Nothing to fill.\n");
430         EngSetLastError(ERROR_INVALID_PARAMETER);
431         return FALSE;
432     }
433 
434     UserEnterExclusive();
435 
436     if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
437     {
438         WARN("UserGetIconObject(0x%p) Failed.\n", hCurIcon);
439         UserLeave();
440         return FALSE;
441     }
442 
443     /* Give back the icon information */
444     if (IconInfo)
445     {
446         PCURICON_OBJECT FrameCurIcon = CurIcon;
447         if (CurIcon->CURSORF_flags & CURSORF_ACON)
448         {
449             /* Get information from first frame. */
450             FrameCurIcon = ((PACON)CurIcon)->aspcur[0];
451         }
452 
453         /* Fill data */
454         ii.fIcon = is_icon(FrameCurIcon);
455         ii.xHotspot = FrameCurIcon->xHotspot;
456         ii.yHotspot = FrameCurIcon->yHotspot;
457 
458         /* Copy bitmaps */
459         ii.hbmMask = BITMAP_CopyBitmap(FrameCurIcon->hbmMask);
460         GreSetObjectOwner(ii.hbmMask, GDI_OBJ_HMGR_POWNED);
461         ii.hbmColor = BITMAP_CopyBitmap(FrameCurIcon->hbmColor);
462         GreSetObjectOwner(ii.hbmColor, GDI_OBJ_HMGR_POWNED);
463         colorBpp = FrameCurIcon->bpp;
464 
465         /* Copy fields */
466         _SEH2_TRY
467         {
468             ProbeForWrite(IconInfo, sizeof(ICONINFO), 1);
469             RtlCopyMemory(IconInfo, &ii, sizeof(ICONINFO));
470 
471             if (pbpp)
472             {
473                 ProbeForWrite(pbpp, sizeof(DWORD), 1);
474                 *pbpp = colorBpp;
475             }
476         }
477         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
478         {
479             Status = _SEH2_GetExceptionCode();
480         }
481         _SEH2_END
482 
483         if (!NT_SUCCESS(Status))
484         {
485             WARN("Status: 0x%08lx\n", Status);
486             SetLastNtError(Status);
487             goto leave;
488         }
489     }
490 
491     /* Give back the module name */
492     if (lpModule)
493     {
494         ULONG BufLen = 0;
495         if (!CurIcon->atomModName)
496             goto leave;
497 
498         RtlQueryAtomInAtomTable(gAtomTable, CurIcon->atomModName, NULL, NULL, NULL, &BufLen);
499         /* Get the module name from the atom table */
500         _SEH2_TRY
501         {
502             BufLen += sizeof(WCHAR);
503             if (BufLen > (lpModule->MaximumLength))
504             {
505                 lpModule->Length = 0;
506                 lpModule->MaximumLength = BufLen;
507             }
508             else
509             {
510                 ProbeForWrite(lpModule->Buffer, lpModule->MaximumLength, 1);
511                 BufLen = lpModule->MaximumLength;
512                 RtlQueryAtomInAtomTable(gAtomTable, CurIcon->atomModName, NULL, NULL, lpModule->Buffer, &BufLen);
513                 lpModule->Length = BufLen;
514             }
515         }
516         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
517         {
518             Status = _SEH2_GetExceptionCode();
519         }
520         _SEH2_END
521 
522         if (!NT_SUCCESS(Status))
523         {
524             SetLastNtError(Status);
525             goto leave;
526         }
527     }
528 
529     if (lpResName)
530     {
531         if (!CurIcon->strName.Buffer)
532             goto leave;
533 
534         /* Copy it */
535         _SEH2_TRY
536         {
537             ProbeForWrite(lpResName, sizeof(UNICODE_STRING), 1);
538             if (IS_INTRESOURCE(CurIcon->strName.Buffer))
539             {
540                 lpResName->Buffer = CurIcon->strName.Buffer;
541                 lpResName->Length = 0;
542                 lpResName->MaximumLength = 0;
543             }
544             else if (lpResName->MaximumLength < CurIcon->strName.MaximumLength)
545             {
546                 lpResName->Length = 0;
547                 lpResName->MaximumLength = CurIcon->strName.MaximumLength;
548             }
549             else
550             {
551                 ProbeForWrite(lpResName->Buffer, lpResName->MaximumLength, 1);
552                 RtlCopyMemory(lpResName->Buffer, CurIcon->strName.Buffer, CurIcon->strName.Length);
553                 lpResName->Length = CurIcon->strName.Length;
554             }
555         }
556         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
557         {
558             Status = _SEH2_GetExceptionCode();
559         }
560         _SEH2_END
561     }
562 
563     if (!NT_SUCCESS(Status))
564     {
565         SetLastNtError(Status);
566         goto leave;
567     }
568 
569     Ret = TRUE;
570 
571 leave:
572     UserDereferenceObject(CurIcon);
573 
574     TRACE("Leave NtUserGetIconInfo, ret=%i\n", Ret);
575     UserLeave();
576 
577     return Ret;
578 }
579 
580 
581 /*
582  * @implemented
583  */
584 BOOL
585 APIENTRY
586 NtUserGetIconSize(
587     HANDLE hCurIcon,
588     UINT istepIfAniCur,
589     PLONG plcx,       // &size.cx
590     PLONG plcy)       // &size.cy
591 {
592     PCURICON_OBJECT CurIcon;
593     NTSTATUS Status = STATUS_SUCCESS;
594     BOOL bRet = FALSE;
595 
596     TRACE("Enter NtUserGetIconSize\n");
597     UserEnterShared();
598 
599     if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
600     {
601         goto cleanup;
602     }
603 
604     if (CurIcon->CURSORF_flags & CURSORF_ACON)
605     {
606         /* Use first frame for animated cursors */
607         PACON AniCurIcon = (PACON)CurIcon;
608         CurIcon = AniCurIcon->aspcur[0];
609         UserDereferenceObject(AniCurIcon);
610         UserReferenceObject(CurIcon);
611     }
612 
613     _SEH2_TRY
614     {
615         ProbeForWrite(plcx, sizeof(LONG), 1);
616         *plcx = CurIcon->cx;
617         ProbeForWrite(plcy, sizeof(LONG), 1);
618         *plcy = CurIcon->cy;
619     }
620     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
621     {
622         Status = _SEH2_GetExceptionCode();
623     }
624     _SEH2_END
625 
626     if (NT_SUCCESS(Status))
627         bRet = TRUE;
628     else
629         SetLastNtError(Status); // Maybe not, test this
630 
631     UserDereferenceObject(CurIcon);
632 
633 cleanup:
634     TRACE("Leave NtUserGetIconSize, ret=%i\n", bRet);
635     UserLeave();
636     return bRet;
637 }
638 
639 
640 /*
641  * @implemented
642  */
643 BOOL
644 APIENTRY
645 NtUserGetCursorInfo(
646     PCURSORINFO pci)
647 {
648     CURSORINFO SafeCi;
649     PSYSTEM_CURSORINFO CurInfo;
650     NTSTATUS Status = STATUS_SUCCESS;
651     PCURICON_OBJECT CurIcon;
652     BOOL Ret = FALSE;
653     DECLARE_RETURN(BOOL);
654 
655     TRACE("Enter NtUserGetCursorInfo\n");
656     UserEnterShared();
657 
658     CurInfo = IntGetSysCursorInfo();
659     CurIcon = (PCURICON_OBJECT)CurInfo->CurrentCursorObject;
660 
661     SafeCi.cbSize = sizeof(CURSORINFO);
662     SafeCi.flags = ((CurIcon && CurInfo->ShowingCursor >= 0) ? CURSOR_SHOWING : 0);
663     SafeCi.hCursor = (CurIcon ? CurIcon->head.h : NULL);
664 
665     SafeCi.ptScreenPos = gpsi->ptCursor;
666 
667     _SEH2_TRY
668     {
669         if (pci->cbSize == sizeof(CURSORINFO))
670         {
671             ProbeForWrite(pci, sizeof(CURSORINFO), 1);
672             RtlCopyMemory(pci, &SafeCi, sizeof(CURSORINFO));
673             Ret = TRUE;
674         }
675         else
676         {
677             EngSetLastError(ERROR_INVALID_PARAMETER);
678         }
679     }
680     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
681     {
682         Status = _SEH2_GetExceptionCode();
683     }
684     _SEH2_END;
685     if (!NT_SUCCESS(Status))
686     {
687         SetLastNtError(Status);
688     }
689 
690     RETURN(Ret);
691 
692 CLEANUP:
693     TRACE("Leave NtUserGetCursorInfo, ret=%i\n",_ret_);
694     UserLeave();
695     END_CLEANUP;
696 }
697 
698 BOOL
699 APIENTRY
700 UserClipCursor(
701     RECTL *prcl)
702 {
703     PSYSTEM_CURSORINFO CurInfo;
704     PWND DesktopWindow = NULL;
705 
706     if (!CheckWinstaAttributeAccess(WINSTA_WRITEATTRIBUTES))
707     {
708         return FALSE;
709     }
710 
711     CurInfo = IntGetSysCursorInfo();
712 
713     DesktopWindow = UserGetDesktopWindow();
714 
715     if (prcl != NULL && DesktopWindow != NULL)
716     {
717         if (prcl->right < prcl->left || prcl->bottom < prcl->top)
718         {
719             EngSetLastError(ERROR_INVALID_PARAMETER);
720             return FALSE;
721         }
722 
723         CurInfo->bClipped = TRUE;
724 
725         /* Set nw cliping region. Note: we can't use RECTL_bIntersectRect because
726            it sets rect to 0 0 0 0 when it's empty. For more info see monitor winetest */
727         CurInfo->rcClip.left = max(prcl->left, DesktopWindow->rcWindow.left);
728         CurInfo->rcClip.right = min(prcl->right, DesktopWindow->rcWindow.right);
729         if (CurInfo->rcClip.right < CurInfo->rcClip.left)
730             CurInfo->rcClip.right = CurInfo->rcClip.left;
731 
732         CurInfo->rcClip.top = max(prcl->top, DesktopWindow->rcWindow.top);
733         CurInfo->rcClip.bottom = min(prcl->bottom, DesktopWindow->rcWindow.bottom);
734         if (CurInfo->rcClip.bottom < CurInfo->rcClip.top)
735             CurInfo->rcClip.bottom = CurInfo->rcClip.top;
736 
737         /* Make sure cursor is in clipping region */
738         UserSetCursorPos(gpsi->ptCursor.x, gpsi->ptCursor.y, 0, 0, FALSE);
739     }
740     else
741     {
742         CurInfo->bClipped = FALSE;
743     }
744 
745     return TRUE;
746 }
747 
748 /*
749  * @implemented
750  */
751 BOOL
752 APIENTRY
753 NtUserClipCursor(
754     RECTL *prcl)
755 {
756     RECTL rclLocal;
757     BOOL bResult;
758 
759     if (prcl)
760     {
761         _SEH2_TRY
762         {
763             /* Probe and copy rect */
764             ProbeForRead(prcl, sizeof(RECTL), 1);
765             rclLocal = *prcl;
766         }
767         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
768         {
769             EngSetLastError(ERROR_INVALID_PARAMETER);
770             _SEH2_YIELD(return FALSE;)
771         }
772         _SEH2_END
773 
774         prcl = &rclLocal;
775     }
776 
777     UserEnterExclusive();
778 
779     /* Call the internal function */
780     bResult = UserClipCursor(prcl);
781 
782     UserLeave();
783 
784     return bResult;
785 }
786 
787 
788 /*
789  * @implemented
790  */
791 BOOL
792 APIENTRY
793 NtUserDestroyCursor(
794   _In_   HANDLE hCurIcon,
795   _In_   BOOL bForce)
796 {
797     BOOL ret;
798     PCURICON_OBJECT CurIcon = NULL;
799 
800     TRACE("Enter NtUserDestroyCursorIcon (%p, %i)\n", hCurIcon, bForce);
801     UserEnterExclusive();
802 
803     CurIcon = UserGetCurIconObject(hCurIcon);
804     if (!CurIcon)
805     {
806         ret = FALSE;
807         goto leave;
808     }
809 
810     if (!bForce)
811     {
812         /* Can not destroy global objects */
813         if (CurIcon->head.ppi == NULL)
814         {
815            ERR("Trying to delete global cursor!\n");
816            ret = TRUE;
817            goto leave;
818         }
819 
820         /* Maybe we have good reasons not to destroy this object */
821         if (CurIcon->head.ppi != PsGetCurrentProcessWin32Process())
822         {
823             /* No way, you're not touching my cursor */
824             ret = FALSE;
825             goto leave;
826         }
827 
828         if (CurIcon->CURSORF_flags & CURSORF_CURRENT)
829         {
830             WARN("Trying to delete current cursor!\n");
831             ret = FALSE;
832             goto leave;
833         }
834 
835         if (CurIcon->CURSORF_flags & CURSORF_LRSHARED)
836         {
837             WARN("Trying to delete shared cursor.\n");
838             /* This one is not an error */
839             ret = TRUE;
840             goto leave;
841         }
842     }
843 
844     /* Destroy the handle */
845     ret = IntDestroyCurIconObject(CurIcon);
846 
847 leave:
848     if (CurIcon)
849         UserDereferenceObject(CurIcon);
850     TRACE("Leave NtUserDestroyCursorIcon, ret=%i\n", ret);
851     UserLeave();
852     return ret;
853 }
854 
855 
856 /*
857  * @implemented
858  */
859 HICON
860 NTAPI
861 NtUserFindExistingCursorIcon(
862   _In_  PUNICODE_STRING pustrModule,
863   _In_  PUNICODE_STRING pustrRsrc,
864   _In_  FINDEXISTINGCURICONPARAM* param)
865 {
866     PCURICON_OBJECT CurIcon;
867     HICON Ret = NULL;
868     UNICODE_STRING ustrModuleSafe, ustrRsrcSafe;
869     FINDEXISTINGCURICONPARAM paramSafe;
870     NTSTATUS Status;
871     PPROCESSINFO pProcInfo = PsGetCurrentProcessWin32Process();
872     RTL_ATOM atomModName;
873 
874     TRACE("Enter NtUserFindExistingCursorIcon\n");
875 
876     _SEH2_TRY
877     {
878         ProbeForRead(param, sizeof(*param), 1);
879         RtlCopyMemory(&paramSafe, param, sizeof(paramSafe));
880     }
881     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
882     {
883         Status = _SEH2_GetExceptionCode();
884     }
885     _SEH2_END
886 
887     /* Capture resource name (it can be an INTRESOURCE == ATOM) */
888     Status = ProbeAndCaptureUnicodeStringOrAtom(&ustrRsrcSafe, pustrRsrc);
889     if (!NT_SUCCESS(Status))
890         return NULL;
891     Status = ProbeAndCaptureUnicodeString(&ustrModuleSafe, UserMode, pustrModule);
892     if (!NT_SUCCESS(Status))
893         goto done;
894     Status = RtlLookupAtomInAtomTable(gAtomTable, ustrModuleSafe.Buffer, &atomModName);
895     ReleaseCapturedUnicodeString(&ustrModuleSafe, UserMode);
896     if (!NT_SUCCESS(Status))
897     {
898         /* The module is not in the atom table. No chance to find the cursor */
899         goto done;
900     }
901 
902     UserEnterShared();
903     CurIcon = pProcInfo->pCursorCache;
904     while (CurIcon)
905     {
906         /* Icon/cursor */
907         if (paramSafe.bIcon != is_icon(CurIcon))
908         {
909             CurIcon = CurIcon->pcurNext;
910             continue;
911         }
912         /* See if module names match */
913         if (atomModName == CurIcon->atomModName)
914         {
915             /* They do. Now see if this is the same resource */
916             if (IS_INTRESOURCE(CurIcon->strName.Buffer) != IS_INTRESOURCE(ustrRsrcSafe.Buffer))
917             {
918                 /* One is an INT resource and the other is not -> no match */
919                 CurIcon = CurIcon->pcurNext;
920                 continue;
921             }
922 
923             if (IS_INTRESOURCE(CurIcon->strName.Buffer))
924             {
925                 if (CurIcon->strName.Buffer == ustrRsrcSafe.Buffer)
926                 {
927                     /* INT resources match */
928                     break;
929                 }
930             }
931             else if (RtlCompareUnicodeString(&ustrRsrcSafe, &CurIcon->strName, TRUE) == 0)
932             {
933                 /* Resource name strings match */
934                 break;
935             }
936         }
937         CurIcon = CurIcon->pcurNext;
938     }
939 
940     /* Now search Global Cursors or Icons. */
941     if (CurIcon == NULL)
942     {
943         CurIcon = gcurFirst;
944         while (CurIcon)
945         {
946             /* Icon/cursor */
947             if (paramSafe.bIcon != is_icon(CurIcon))
948             {
949                 CurIcon = CurIcon->pcurNext;
950                 continue;
951             }
952             /* See if module names match */
953             if (atomModName == CurIcon->atomModName)
954             {
955                 /* They do. Now see if this is the same resource */
956                 if (IS_INTRESOURCE(CurIcon->strName.Buffer) != IS_INTRESOURCE(ustrRsrcSafe.Buffer))
957                 {
958                     /* One is an INT resource and the other is not -> no match */
959                     CurIcon = CurIcon->pcurNext;
960                     continue;
961                 }
962                 if (IS_INTRESOURCE(CurIcon->strName.Buffer))
963                 {
964                     if (CurIcon->strName.Buffer == ustrRsrcSafe.Buffer)
965                     {
966                         /* INT resources match */
967                         break;
968                     }
969                 }
970                 else if (RtlCompareUnicodeString(&ustrRsrcSafe, &CurIcon->strName, TRUE) == 0)
971                 {
972                     /* Resource name strings match */
973                     break;
974                 }
975             }
976             CurIcon = CurIcon->pcurNext;
977         }
978     }
979     if (CurIcon)
980         Ret = CurIcon->head.h;
981     UserLeave();
982 
983 done:
984     if (!IS_INTRESOURCE(ustrRsrcSafe.Buffer))
985         ExFreePoolWithTag(ustrRsrcSafe.Buffer, TAG_STRING);
986 
987     return Ret;
988 }
989 
990 
991 /*
992  * @implemented
993  */
994 BOOL
995 APIENTRY
996 NtUserGetClipCursor(
997     RECTL *lpRect)
998 {
999     PSYSTEM_CURSORINFO CurInfo;
1000     RECTL Rect;
1001     NTSTATUS Status;
1002     DECLARE_RETURN(BOOL);
1003 
1004     TRACE("Enter NtUserGetClipCursor\n");
1005     UserEnterShared();
1006 
1007     if (!CheckWinstaAttributeAccess(WINSTA_READATTRIBUTES))
1008     {
1009         RETURN(FALSE);
1010     }
1011 
1012     if (!lpRect)
1013         RETURN(FALSE);
1014 
1015     CurInfo = IntGetSysCursorInfo();
1016     if (CurInfo->bClipped)
1017     {
1018         Rect = CurInfo->rcClip;
1019     }
1020     else
1021     {
1022         Rect.left = 0;
1023         Rect.top = 0;
1024         Rect.right = UserGetSystemMetrics(SM_CXSCREEN);
1025         Rect.bottom = UserGetSystemMetrics(SM_CYSCREEN);
1026     }
1027 
1028     Status = MmCopyToCaller(lpRect, &Rect, sizeof(RECT));
1029     if (!NT_SUCCESS(Status))
1030     {
1031         SetLastNtError(Status);
1032         RETURN(FALSE);
1033     }
1034 
1035     RETURN(TRUE);
1036 
1037 CLEANUP:
1038     TRACE("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 pcurOld, pcurNew;
1053     HCURSOR hOldCursor = NULL;
1054 
1055     TRACE("Enter NtUserSetCursor: %p\n", hCursor);
1056     UserEnterExclusive();
1057 
1058     if (hCursor)
1059     {
1060         pcurNew = UserGetCurIconObject(hCursor);
1061         if (!pcurNew)
1062         {
1063             EngSetLastError(ERROR_INVALID_CURSOR_HANDLE);
1064             goto leave;
1065         }
1066         pcurNew->CURSORF_flags |= CURSORF_CURRENT;
1067     }
1068     else
1069     {
1070         pcurNew = NULL;
1071     }
1072 
1073     pcurOld = UserSetCursor(pcurNew, FALSE);
1074 
1075     // If returning an old cursor than validate it, Justin Case!
1076     if ( pcurOld &&
1077         (pcurOld = UserGetObjectNoErr(gHandleTable, UserHMGetHandle(pcurOld), TYPE_CURSOR)))
1078     {
1079         hOldCursor = UserHMGetHandle(pcurOld);
1080     /*
1081         Problem:
1082 
1083         System Global Cursors start out having at least 2 lock counts. If a system
1084         cursor is the default cursor and is returned to the caller twice in its
1085         life, the count will reach zero. Causing an assert to occur in objects.
1086 
1087         This fixes a SeaMonkey crash while the mouse crosses a boundary.
1088      */
1089         if (pcurOld->CURSORF_flags & CURSORF_GLOBAL)
1090         {
1091            TRACE("Returning Global Cursor hcur %p\n",hOldCursor);
1092 
1093            /*if (pcurOld->head.cLockObj > 2) // Throttle down to 2.
1094            {
1095               UserDereferenceObject(pcurOld);
1096            }
1097 
1098            goto leave;*/
1099         }
1100 
1101         /* See if it was destroyed in the meantime */
1102         if (UserObjectInDestroy(hOldCursor))
1103             hOldCursor = NULL;
1104         pcurOld->CURSORF_flags &= ~CURSORF_CURRENT;
1105         UserDereferenceObject(pcurOld);
1106     }
1107 
1108 leave:
1109     UserLeave();
1110     return hOldCursor;
1111 }
1112 
1113 
1114 /*
1115  * @unimplemented
1116  */
1117 BOOL
1118 APIENTRY
1119 NtUserSetCursorContents(
1120     HANDLE hCurIcon,
1121     PICONINFO UnsafeIconInfo)
1122 {
1123     FIXME(" is UNIMPLEMENTED.\n");
1124     return FALSE;
1125 }
1126 
1127 
1128 static
1129 BOOL
1130 IntSetCursorData(
1131     _Inout_ PCURICON_OBJECT pcur,
1132     _In_opt_ PUNICODE_STRING pustrName,
1133     _In_ ATOM atomModName,
1134     _In_ const CURSORDATA* pcursordata)
1135 {
1136     /* Check if the CURSORF_ACON is also set in the cursor data */
1137     if (pcursordata->CURSORF_flags & CURSORF_ACON)
1138     {
1139         ERR("Mismatch in CURSORF_flags! cursor: 0x%08lx, data:  0x%08lx\n",
1140             pcur->CURSORF_flags, pcursordata->CURSORF_flags);
1141         return FALSE;
1142     }
1143 
1144     /* Check if this cursor was already set */
1145     if (pcur->hbmMask != NULL)
1146     {
1147         ERR("Cursor data already set!\n");
1148         return FALSE;
1149     }
1150 
1151     /* We need a mask */
1152     if (pcursordata->hbmMask == NULL)
1153     {
1154         ERR("NtUserSetCursorIconData was got no hbmMask.\n");
1155         EngSetLastError(ERROR_INVALID_PARAMETER);
1156         return FALSE;
1157     }
1158 
1159     /* Take ownership of the mask bitmap */
1160     if (!GreSetBitmapOwner(pcursordata->hbmMask, GDI_OBJ_HMGR_PUBLIC))
1161     {
1162         ERR("Failed to set ownership of hbmMask %p.\n", pcursordata->hbmMask);
1163         return FALSE;
1164     }
1165 
1166     /* Check if we have a color bitmap */
1167     if (pcursordata->hbmColor)
1168     {
1169         /* Take ownership of the color bitmap */
1170         if (!GreSetBitmapOwner(pcursordata->hbmColor, GDI_OBJ_HMGR_PUBLIC))
1171         {
1172             ERR("Failed to set ownership of hbmColor %p.\n", pcursordata->hbmColor);
1173             GreSetBitmapOwner(pcursordata->hbmMask, GDI_OBJ_HMGR_POWNED);
1174             return FALSE;
1175         }
1176     }
1177 
1178     /* Check if we have an alpha bitmap */
1179     if (pcursordata->hbmAlpha)
1180     {
1181         /* Take ownership of the alpha bitmap */
1182         if (!GreSetBitmapOwner(pcursordata->hbmAlpha, GDI_OBJ_HMGR_PUBLIC))
1183         {
1184             ERR("Failed to set ownership of hbmAlpha %p.\n", pcursordata->hbmAlpha);
1185             GreSetBitmapOwner(pcursordata->hbmMask, GDI_OBJ_HMGR_POWNED);
1186             if (pcursordata->hbmColor)
1187             {
1188                 GreSetBitmapOwner(pcursordata->hbmColor, GDI_OBJ_HMGR_POWNED);
1189             }
1190             return FALSE;
1191         }
1192     }
1193 
1194     /* Free the old name (Must be NULL atm, but later we might allow this) */
1195     NT_ASSERT(pcur->strName.Buffer == NULL);
1196     if (pcur->strName.Buffer != NULL)
1197     {
1198         if (!IS_INTRESOURCE(pcur->strName.Buffer))
1199         {
1200             ExFreePoolWithTag(pcur->strName.Buffer, TAG_STRING);
1201         }
1202         RtlInitEmptyUnicodeString(&pcur->strName, NULL, 0);
1203     }
1204 
1205     /* Free the module atom */
1206     if (pcur->atomModName != 0)
1207     {
1208         NT_VERIFY(NT_SUCCESS(RtlDeleteAtomFromAtomTable(gAtomTable, pcur->atomModName)));
1209     }
1210 
1211     /* Now set the new cursor data */
1212     pcur->atomModName = atomModName;
1213     pcur->rt = pcursordata->rt;
1214     pcur->CURSORF_flags = pcursordata->CURSORF_flags & CURSORF_USER_MASK;
1215     pcur->xHotspot = pcursordata->xHotspot;
1216     pcur->yHotspot = pcursordata->yHotspot;
1217     pcur->hbmMask = pcursordata->hbmMask;
1218     pcur->hbmColor = pcursordata->hbmColor;
1219     pcur->hbmAlpha = pcursordata->hbmAlpha;
1220     pcur->rcBounds.left = 0;
1221     pcur->rcBounds.top = 0;
1222     pcur->rcBounds.right = pcursordata->cx;
1223     pcur->rcBounds.bottom = pcursordata->cy;
1224     pcur->hbmUserAlpha = pcursordata->hbmUserAlpha;
1225     pcur->bpp = pcursordata->bpp;
1226     pcur->cx = pcursordata->cx;
1227     pcur->cy = pcursordata->cy;
1228     if (pustrName != NULL)
1229     {
1230         pcur->strName = *pustrName;
1231     }
1232 
1233     return TRUE;
1234 }
1235 
1236 static
1237 BOOL
1238 IntSetAconData(
1239     _Inout_ PACON pacon,
1240     _In_opt_ PUNICODE_STRING pustrName,
1241     _In_ ATOM atomModName,
1242     _In_ const CURSORDATA *pcursordata)
1243 {
1244     PCURICON_OBJECT *aspcur;
1245     DWORD *aicur;
1246     INT *ajifRate;
1247     PCURSORDATA pcdFrame;
1248     HCURSOR hcurFrame;
1249     UINT cjSize, i;
1250 
1251     NT_ASSERT((pacon->CURSORF_flags & CURSORF_ACON) != 0);
1252     NT_ASSERT((pacon->CURSORF_flags & CURSORF_ACONFRAME) == 0);
1253     NT_ASSERT((ULONG_PTR)pcursordata->aspcur > MmUserProbeAddress);
1254     NT_ASSERT((ULONG_PTR)pcursordata->aicur > MmUserProbeAddress);
1255     NT_ASSERT((ULONG_PTR)pcursordata->ajifRate > MmUserProbeAddress);
1256     NT_ASSERT((pcursordata->CURSORF_flags & ~CURSORF_USER_MASK) == 0);
1257     NT_ASSERT(pcursordata->cpcur > 0);
1258     NT_ASSERT(pcursordata->cicur > 0);
1259 
1260     /* Check if the CURSORF_ACON is also set in the cursor data */
1261     if (!(pcursordata->CURSORF_flags & CURSORF_ACON))
1262     {
1263         ERR("Mismatch in CURSORF_flags! acon: 0x%08lx, data:  0x%08lx\n",
1264             pacon->CURSORF_flags, pcursordata->CURSORF_flags);
1265         return FALSE;
1266     }
1267 
1268     /* Check if this acon was already set */
1269     if (pacon->aspcur != NULL)
1270     {
1271         ERR("Acon data already set!\n");
1272         return FALSE;
1273     }
1274 
1275     /* Loop all frames indexes */
1276     for (i = 0; i < pcursordata->cicur; i++)
1277     {
1278         /* Check if the index is within the range of the frames */
1279         if (pcursordata->aicur[i] >= pcursordata->cpcur)
1280         {
1281             ERR("aicur[%lu] is out or range. Got %lu, cpcur = %u\n",
1282                 i, pcursordata->aicur[i], pcursordata->cpcur);
1283             return FALSE;
1284         }
1285 
1286         /* FIXME: check the JIF rates? */
1287     }
1288 
1289     /* Calculate size: one cursor object for each frame, and a frame
1290        index and jiffies for each "step" */
1291     cjSize = (pcursordata->cpcur * sizeof(CURICON_OBJECT*)) +
1292              (pcursordata->cicur * sizeof(DWORD)) +
1293              (pcursordata->cicur * sizeof(INT));
1294 
1295     /* Allocate a buffer */
1296     aspcur = ExAllocatePoolWithTag(PagedPool, cjSize, USERTAG_CURSOR);
1297     if (aspcur == NULL)
1298     {
1299         ERR("Failed to allocate memory (cpcur = %u, cicur = %u)\n",
1300             pcursordata->cpcur, pcursordata->cicur);
1301         return FALSE;
1302     }
1303 
1304     /* Set the pointers */
1305     aicur = (DWORD*)&aspcur[pcursordata->cpcur];
1306     ajifRate = (INT*)&aicur[pcursordata->cicur];
1307 
1308     /* Copy the values */
1309     RtlCopyMemory(aicur, pcursordata->aicur, pcursordata->cicur * sizeof(DWORD));
1310     RtlCopyMemory(ajifRate, pcursordata->ajifRate, pcursordata->cicur * sizeof(INT));
1311 
1312     /* Zero out the array, so we can handle cleanup */
1313     RtlZeroMemory(aspcur, pcursordata->cpcur * sizeof(PCURICON_OBJECT));
1314 
1315     /* Get a pointer to the cursor data for each frame */
1316     pcdFrame = pcursordata->aspcur;
1317 
1318     /* Create the cursors */
1319     for (i = 0; i < pcursordata->cpcur; i++)
1320     {
1321         /* Create a cursor for this frame */
1322         hcurFrame = IntCreateCurIconHandle(FALSE);
1323         if (hcurFrame == NULL)
1324         {
1325             ERR("Failed to create a cursor for frame %u\n", i);
1326             goto Cleanup;
1327         }
1328 
1329         /* Get a pointer to the frame cursor */
1330         aspcur[i] = UserGetCurIconObject(hcurFrame);
1331         _PRAGMA_WARNING_SUPPRESS(__WARNING_READ_OVERRUN);
1332         NT_ASSERT(aspcur[i] != NULL);
1333 
1334         /* Check if the flags are valid */
1335         if (pcdFrame->CURSORF_flags & ~(CURSORF_USER_MASK|CURSORF_ACONFRAME))
1336         {
1337             ERR("Invalid flags for acon frame %u: 0x%08lx\n",
1338                 i, pcdFrame->CURSORF_flags);
1339             goto Cleanup;
1340         }
1341 
1342         /* Set the cursor data for this frame */
1343         if (!IntSetCursorData(aspcur[i], NULL, 0, &pcdFrame[i]))
1344         {
1345             ERR("Failed to set cursor data for frame %u\n", i);
1346             goto Cleanup;
1347         }
1348 
1349         /* Mark this cursor as an acon frame */
1350         aspcur[i]->CURSORF_flags |= CURSORF_ACONFRAME;
1351     }
1352 
1353     /* Free the old name (Must be NULL atm.) */
1354     NT_ASSERT(pacon->strName.Buffer == NULL);
1355     if (pacon->strName.Buffer != NULL)
1356     {
1357         if (!IS_INTRESOURCE(pacon->strName.Buffer))
1358         {
1359             ExFreePoolWithTag(pacon->strName.Buffer, TAG_STRING);
1360         }
1361         RtlInitEmptyUnicodeString(&pacon->strName, NULL, 0);
1362     }
1363 
1364     /* Free the module atom */
1365     if (pacon->atomModName != 0)
1366     {
1367         NT_VERIFY(NT_SUCCESS(RtlDeleteAtomFromAtomTable(gAtomTable, pacon->atomModName)));
1368     }
1369 
1370     /* Free the previous frames */
1371     if (pacon->aspcur != NULL)
1372     {
1373         for (i = 0; i < pacon->cpcur; i++)
1374         {
1375             UserDereferenceObject(pacon->aspcur[i]);
1376             NT_VERIFY(IntDestroyCurIconObject(pacon->aspcur[i]) == TRUE);
1377         }
1378         ExFreePoolWithTag(pacon->aspcur, USERTAG_CURSOR);
1379     }
1380 
1381     /* Finally set the data in the acon */
1382     pacon->atomModName = atomModName;
1383     pacon->rt = pcursordata->rt;
1384     pacon->CURSORF_flags = pcursordata->CURSORF_flags & CURSORF_USER_MASK;
1385     pacon->cpcur = pcursordata->cpcur;
1386     pacon->cicur = pcursordata->cicur;
1387     pacon->aspcur = aspcur;
1388     pacon->aicur = aicur;
1389     pacon->ajifRate = ajifRate;
1390     pacon->iicur = 0;
1391     if (pustrName != NULL)
1392     {
1393         pacon->strName = *pustrName;
1394     }
1395 
1396     return TRUE;
1397 
1398 Cleanup:
1399 
1400     /* Clean up the cursors we created */
1401     for (i = 0; i < pcursordata->cpcur; i++)
1402     {
1403         if (aspcur[i] == NULL)
1404             break;
1405 
1406         /* Destroy this cursor */
1407         UserDereferenceObject(aspcur[i]);
1408         NT_VERIFY(IntDestroyCurIconObject(aspcur[i]) == TRUE);
1409     }
1410 
1411     /* Delete the allocated structure */
1412     ExFreePoolWithTag(aspcur, USERTAG_CURSOR);
1413 
1414     return FALSE;
1415 }
1416 
1417 BOOL
1418 APIENTRY
1419 UserSetCursorIconData(
1420     _In_ HCURSOR hcursor,
1421     _In_opt_ PUNICODE_STRING pustrModule,
1422     _In_opt_ PUNICODE_STRING pustrRsrc,
1423     _In_ PCURSORDATA pcursordata)
1424 {
1425     PCURICON_OBJECT pcur;
1426     ATOM atomModName;
1427     NTSTATUS status;
1428     BOOL bResult;
1429 
1430     /* Do we have a module name? */
1431     if (pustrModule != NULL)
1432     {
1433         /* Create an atom for the module name */
1434         status = RtlAddAtomToAtomTable(gAtomTable,
1435                                        pustrModule->Buffer,
1436                                        &atomModName);
1437         if (!NT_SUCCESS(status))
1438         {
1439             ERR("Failed to create atom from module name '%wZ': 0x%08lx\n",
1440                 pustrModule, status);
1441             return FALSE;
1442         }
1443     }
1444     else
1445     {
1446         /* No module name atom */
1447         atomModName = 0;
1448     }
1449 
1450     /* Reference the cursor */
1451     pcur = UserGetCurIconObject(hcursor);
1452     if (pcur == NULL)
1453     {
1454         ERR("Failed to reference cursor %p\n", hcursor);
1455         bResult = FALSE;
1456         goto Exit;
1457     }
1458 
1459     /* Check if this is an acon */
1460     if (pcur->CURSORF_flags & CURSORF_ACON)
1461     {
1462         bResult = IntSetAconData((PACON)pcur,
1463                                  pustrRsrc,
1464                                  atomModName,
1465                                  pcursordata);
1466     }
1467     else
1468     {
1469         bResult = IntSetCursorData(pcur,
1470                                    pustrRsrc,
1471                                    atomModName,
1472                                    pcursordata);
1473     }
1474 
1475 Exit:
1476 
1477     /* Check if we had success */
1478     if (bResult != FALSE)
1479     {
1480         /* Check if this is an LRSHARED cursor now */
1481         if (pcur->CURSORF_flags & CURSORF_LRSHARED)
1482         {
1483             /* Insert the cursor into the list. */
1484             IntInsertCursorIntoList(pcur);
1485         }
1486     }
1487     else
1488     {
1489         /* Cleanup on failure */
1490         if (atomModName != 0)
1491         {
1492             NT_VERIFY(NT_SUCCESS(RtlDeleteAtomFromAtomTable(gAtomTable, atomModName)));
1493         }
1494     }
1495 
1496     /* Dereference the cursor and return the result */
1497     if (pcur)
1498         UserDereferenceObject(pcur);
1499 
1500     return bResult;
1501 }
1502 
1503 
1504 /*
1505  * @implemented
1506  */
1507 __kernel_entry
1508 BOOL
1509 APIENTRY
1510 NtUserSetCursorIconData(
1511     _In_ HCURSOR hcursor,
1512     _In_opt_ PUNICODE_STRING pustrModule,
1513     _In_opt_ PUNICODE_STRING pustrRsrc,
1514     _In_ const CURSORDATA* pCursorData)
1515 {
1516     CURSORDATA cursordata;
1517     UNICODE_STRING ustrModule, ustrRsrc;
1518     _SEH2_VOLATILE PVOID pvBuffer;
1519     CURSORDATA* aspcur;
1520     DWORD* aicur;
1521     PINT ajifRate;
1522     UINT cjSize;
1523     NTSTATUS status;
1524     BOOL bResult = FALSE;
1525 
1526     TRACE("Enter NtUserSetCursorIconData\n");
1527 
1528     /* Initialize buffer, so we can handle cleanup */
1529     ustrRsrc.Buffer = NULL;
1530     ustrModule.Buffer = NULL;
1531     pvBuffer = NULL;
1532 
1533     _SEH2_TRY
1534     {
1535         /* Probe and capture the cursor data structure */
1536         ProbeForRead(pCursorData, sizeof(*pCursorData), 1);
1537         cursordata = *pCursorData;
1538 
1539         /* Check if this is an animated cursor */
1540         if (cursordata.CURSORF_flags & CURSORF_ACON)
1541         {
1542             /* Check of the range is ok */
1543             if ((cursordata.cpcur == 0) || (cursordata.cicur == 0) ||
1544                 (cursordata.cpcur > 1000) || (cursordata.cicur > 1000))
1545             {
1546                 ERR("Range error (cpcur = %u, cicur = %u)\n",
1547                     cursordata.cpcur, cursordata.cicur);
1548                 goto Exit;
1549             }
1550 
1551             /* Calculate size: one cursor data structure for each frame,
1552                and a frame index and jiffies for each "step" */
1553             cjSize = (cursordata.cpcur * sizeof(CURSORDATA)) +
1554                      (cursordata.cicur * sizeof(DWORD)) +
1555                      (cursordata.cicur * sizeof(INT));
1556 
1557             /* Allocate a buffer */
1558             pvBuffer = ExAllocatePoolWithTag(PagedPool, cjSize, USERTAG_CURSOR);
1559             if (pvBuffer == NULL)
1560             {
1561                 ERR("Failed to allocate memory (cpcur = %u, cicur = %u)\n",
1562                     cursordata.cpcur, cursordata.cicur);
1563                 goto Exit;
1564             }
1565 
1566             /* Calculate the kernel mode pointers */
1567             aspcur = (CURSORDATA*)pvBuffer;
1568             aicur = (DWORD*)&aspcur[cursordata.cpcur];
1569             ajifRate = (INT*)&aicur[cursordata.cicur];
1570 
1571             /* Probe and copy aspcur */
1572             ProbeForRead(cursordata.aspcur, cursordata.cpcur * sizeof(CURSORDATA), 1);
1573             RtlCopyMemory(aspcur,
1574                           cursordata.aspcur,
1575                           cursordata.cpcur * sizeof(CURSORDATA));
1576 
1577             /* Probe and copy aicur */
1578             ProbeForRead(cursordata.aicur, cursordata.cicur * sizeof(DWORD), 1);
1579             RtlCopyMemory(aicur,
1580                           cursordata.aicur,
1581                           cursordata.cicur * sizeof(DWORD));
1582 
1583             /* Probe and copy ajifRate */
1584             ProbeForRead(cursordata.ajifRate, cursordata.cicur * sizeof(INT), 1);
1585             RtlCopyMemory(ajifRate,
1586                           cursordata.ajifRate,
1587                           cursordata.cicur * sizeof(INT));
1588 
1589             /* Set the new pointers */
1590             cursordata.aspcur = aspcur;
1591             cursordata.aicur = aicur;
1592             cursordata.ajifRate = ajifRate;
1593         }
1594         else
1595         {
1596             /* This is a standard cursor, we don't use the pointers */
1597             cursordata.aspcur = NULL;
1598             cursordata.aicur = NULL;
1599             cursordata.ajifRate = NULL;
1600         }
1601     }
1602     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1603     {
1604         SetLastNtError(_SEH2_GetExceptionCode());
1605         goto Exit;
1606     }
1607     _SEH2_END
1608 
1609     /* Check if we got a module name */
1610     if (pustrModule != NULL)
1611     {
1612         /* Capture the name */
1613         status = ProbeAndCaptureUnicodeString(&ustrModule, UserMode, pustrModule);
1614         if (!NT_SUCCESS(status))
1615         {
1616             ERR("Failed to copy pustrModule: status 0x%08lx\n", status);
1617             goto Exit;
1618         }
1619     }
1620 
1621     /* Check if we got a resource name */
1622     if (pustrRsrc != NULL)
1623     {
1624         /* We use this function, because INTRESOURCEs and ATOMs are the same */
1625         status = ProbeAndCaptureUnicodeStringOrAtom(&ustrRsrc, pustrRsrc);
1626         if (!NT_SUCCESS(status))
1627         {
1628             ERR("Failed to copy pustrRsrc: status 0x%08lx\n", status);
1629             goto Exit;
1630         }
1631     }
1632 
1633     /* Make sure the caller doesn't give us invalid flags */
1634     if (cursordata.CURSORF_flags & ~CURSORF_USER_MASK)
1635     {
1636         ERR("Invalid cursor flags: 0x%08lx\n", cursordata.CURSORF_flags);
1637         goto Exit;
1638     }
1639 
1640     /* Acquire the global user lock */
1641     UserEnterExclusive();
1642 
1643     /* Call the internal function */
1644     bResult = UserSetCursorIconData(hcursor,
1645                                     pustrModule ? &ustrModule : NULL,
1646                                     pustrRsrc ? &ustrRsrc : NULL,
1647                                     &cursordata);
1648 
1649     /* Release the global user lock */
1650     UserLeave();
1651 
1652 Exit:
1653 
1654     /* Free the captured module name */
1655     if ((ustrModule.Buffer != NULL) && !IS_INTRESOURCE(ustrModule.Buffer))
1656     {
1657         ReleaseCapturedUnicodeString(&ustrModule, UserMode);
1658     }
1659 
1660     if (pvBuffer != NULL)
1661     {
1662         ExFreePoolWithTag(pvBuffer, USERTAG_CURSOR);
1663     }
1664 
1665     /* Additional cleanup on failure */
1666     if (bResult == FALSE)
1667     {
1668         if (ustrRsrc.Buffer != NULL)
1669         {
1670             ExFreePoolWithTag(ustrRsrc.Buffer, TAG_STRING);
1671         }
1672     }
1673 
1674     TRACE("Leave NtUserSetCursorIconData, bResult = %i\n", bResult);
1675 
1676     return bResult;
1677 }
1678 
1679 /* Mostly inspired from wine code.
1680  * We use low level functions because:
1681  *  - at this point, the icon bitmap could have a different bit depth than the DC,
1682  *    making it thus impossible to use NtCreateCompatibleDC and selecting the bitmap.
1683  *    This happens after a mode setting change.
1684  *  - it avoids massive GDI objects locking when only the destination surface needs it.
1685  *  - It makes (small) performance gains.
1686  */
1687 BOOL
1688 UserDrawIconEx(
1689     HDC hDc,
1690     INT xLeft,
1691     INT yTop,
1692     PCURICON_OBJECT pIcon,
1693     INT cxWidth,
1694     INT cyHeight,
1695     UINT istepIfAniCur,
1696     HBRUSH hbrFlickerFreeDraw,
1697     UINT diFlags)
1698 {
1699     PSURFACE psurfDest, psurfMask, psurfColor; //, psurfOffScreen = NULL;
1700     PDC pdc = NULL;
1701     BOOL Ret = FALSE;
1702     HBITMAP hbmMask, hbmColor, hbmAlpha;
1703     BOOL bOffScreen;
1704     RECTL rcDest, rcSrc;
1705     CLIPOBJ* pdcClipObj = NULL;
1706     EXLATEOBJ exlo;
1707 
1708     /* Stupid case */
1709     if ((diFlags & DI_NORMAL) == 0)
1710     {
1711         ERR("DrawIconEx called without mask or color bitmap to draw.\n");
1712         return FALSE;
1713     }
1714 
1715     if (pIcon->CURSORF_flags & CURSORF_ACON)
1716     {
1717         ACON* pAcon = (ACON*)pIcon;
1718         if (istepIfAniCur >= pAcon->cicur)
1719         {
1720             ERR("NtUserDrawIconEx: istepIfAniCur too big!\n");
1721             return FALSE;
1722         }
1723         pIcon = pAcon->aspcur[pAcon->aicur[istepIfAniCur]];
1724     }
1725 
1726     hbmMask = pIcon->hbmMask;
1727     hbmColor = pIcon->hbmColor;
1728     hbmAlpha = pIcon->hbmAlpha;
1729 
1730     /*
1731      * Get our objects.
1732      * Shared locks are enough, we are only reading those bitmaps
1733      */
1734     psurfMask = SURFACE_ShareLockSurface(hbmMask);
1735     if (psurfMask == NULL)
1736     {
1737         ERR("Unable to lock the mask surface.\n");
1738         return FALSE;
1739     }
1740 
1741     /* Color bitmap is not mandatory */
1742     if (hbmColor == NULL)
1743     {
1744         /* But then the mask bitmap must have the information in it's bottom half */
1745         ASSERT(psurfMask->SurfObj.sizlBitmap.cy == 2*pIcon->cy);
1746         psurfColor = NULL;
1747     }
1748     else if ((psurfColor = SURFACE_ShareLockSurface(hbmColor)) == NULL)
1749     {
1750         ERR("Unable to lock the color bitmap.\n");
1751         SURFACE_ShareUnlockSurface(psurfMask);
1752         return FALSE;
1753     }
1754 
1755     pdc = DC_LockDc(hDc);
1756     if (!pdc)
1757     {
1758         ERR("Could not lock the destination DC.\n");
1759         SURFACE_ShareUnlockSurface(psurfMask);
1760         if (psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
1761         return FALSE;
1762     }
1763 
1764     /* Fix width parameter, if needed */
1765     if (!cxWidth)
1766     {
1767         if (diFlags & DI_DEFAULTSIZE)
1768             cxWidth = is_icon(pIcon) ?
1769                 UserGetSystemMetrics(SM_CXICON) : UserGetSystemMetrics(SM_CXCURSOR);
1770         else
1771             cxWidth = pIcon->cx;
1772     }
1773 
1774     /* Fix height parameter, if needed */
1775     if (!cyHeight)
1776     {
1777         if (diFlags & DI_DEFAULTSIZE)
1778             cyHeight = is_icon(pIcon) ?
1779                 UserGetSystemMetrics(SM_CYICON) : UserGetSystemMetrics(SM_CYCURSOR);
1780         else
1781             cyHeight = pIcon->cy;
1782     }
1783 
1784     /* Calculate destination rectangle */
1785     RECTL_vSetRect(&rcDest, xLeft, yTop, xLeft + cxWidth, yTop + cyHeight);
1786     IntLPtoDP(pdc, (LPPOINT)&rcDest, 2);
1787     RECTL_vOffsetRect(&rcDest, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y);
1788 
1789     /* Prepare the underlying surface */
1790     DC_vPrepareDCsForBlit(pdc, &rcDest, NULL, NULL);
1791 
1792     /* We now have our destination surface and rectangle */
1793     psurfDest = pdc->dclevel.pSurface;
1794 
1795     if (psurfDest == NULL)
1796     {
1797         /* Empty DC */
1798         DC_vFinishBlit(pdc, NULL);
1799         DC_UnlockDc(pdc);
1800         SURFACE_ShareUnlockSurface(psurfMask);
1801         if (psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
1802         return FALSE;
1803     }
1804 
1805     /* Set source rect */
1806     RECTL_vSetRect(&rcSrc, 0, 0, pIcon->cx, pIcon->cy);
1807 
1808     /* Should we render off-screen? */
1809     bOffScreen = hbrFlickerFreeDraw &&
1810         (GDI_HANDLE_GET_TYPE(hbrFlickerFreeDraw) == GDI_OBJECT_TYPE_BRUSH);
1811 
1812     if (bOffScreen)
1813     {
1814         /* Yes: Allocate and paint the offscreen surface */
1815         EBRUSHOBJ eboFill;
1816         PBRUSH pbrush = BRUSH_ShareLockBrush(hbrFlickerFreeDraw);
1817 
1818         TRACE("Performing off-screen rendering.\n");
1819 
1820         if (!pbrush)
1821         {
1822             ERR("Failed to get brush object.\n");
1823             goto Cleanup;
1824         }
1825 
1826 #if 0 //We lock the hdc surface during the whole function it makes no sense to use an offscreen surface for "flicker free" drawing
1827         psurfOffScreen = SURFACE_AllocSurface(STYPE_BITMAP,
1828             cxWidth, cyHeight, psurfDest->SurfObj.iBitmapFormat,
1829             0, 0, NULL);
1830         if (!psurfOffScreen)
1831         {
1832             ERR("Failed to allocate the off-screen surface.\n");
1833             BRUSH_ShareUnlockBrush(pbrush);
1834             goto Cleanup;
1835         }
1836 
1837         /* Paint the brush */
1838         EBRUSHOBJ_vInit(&eboFill, pbrush, psurfOffScreen, 0x00FFFFFF, 0, NULL);
1839         RECTL_vSetRect(&rcDest, 0, 0, cxWidth, cyHeight);
1840 
1841         Ret = IntEngBitBlt(&psurfOffScreen->SurfObj,
1842             NULL,
1843             NULL,
1844             NULL,
1845             NULL,
1846             &rcDest,
1847             NULL,
1848             NULL,
1849             &eboFill.BrushObject,
1850             &pbrush->ptOrigin,
1851             ROP4_PATCOPY);
1852 
1853         /* Clean up everything */
1854         EBRUSHOBJ_vCleanup(&eboFill);
1855         BRUSH_ShareUnlockBrush(pbrush);
1856 
1857         if (!Ret)
1858         {
1859             ERR("Failed to paint the off-screen surface.\n");
1860             goto Cleanup;
1861         }
1862 
1863         /* We now have our destination surface */
1864         psurfDest = psurfOffScreen;
1865 #else
1866         pdcClipObj = (CLIPOBJ *)&pdc->co;
1867         /* Paint the brush */
1868         EBRUSHOBJ_vInit(&eboFill, pbrush, psurfDest, 0x00FFFFFF, 0, NULL);
1869 
1870         Ret = IntEngBitBlt(&psurfDest->SurfObj,
1871             NULL,
1872             NULL,
1873             pdcClipObj,
1874             NULL,
1875             &rcDest,
1876             NULL,
1877             NULL,
1878             &eboFill.BrushObject,
1879             &pbrush->ptOrigin,
1880             ROP4_PATCOPY);
1881 
1882         /* Clean up everything */
1883         EBRUSHOBJ_vCleanup(&eboFill);
1884         BRUSH_ShareUnlockBrush(pbrush);
1885 
1886         if (!Ret)
1887         {
1888             ERR("Failed to paint the off-screen surface.\n");
1889             goto Cleanup;
1890         }
1891 #endif
1892     }
1893     else
1894     {
1895         /* We directly draw to the DC */
1896         TRACE("Performing on screen rendering.\n");
1897         pdcClipObj = (CLIPOBJ *)&pdc->co;
1898         // psurfOffScreen = NULL;
1899     }
1900 
1901     /* Now do the rendering */
1902     if (hbmAlpha && ((diFlags & DI_NORMAL) == DI_NORMAL))
1903     {
1904         BLENDOBJ blendobj = { {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA } };
1905         PSURFACE psurf = NULL;
1906 
1907         psurf = SURFACE_ShareLockSurface(hbmAlpha);
1908         if (!psurf)
1909         {
1910             ERR("SURFACE_LockSurface failed!\n");
1911             goto NoAlpha;
1912         }
1913 
1914         /* Initialize color translation object */
1915         EXLATEOBJ_vInitialize(&exlo, psurf->ppal, psurfDest->ppal, 0xFFFFFFFF, 0xFFFFFFFF, 0);
1916 
1917         /* Now do it */
1918         Ret = IntEngAlphaBlend(&psurfDest->SurfObj,
1919                                &psurf->SurfObj,
1920                                pdcClipObj,
1921                                &exlo.xlo,
1922                                &rcDest,
1923                                &rcSrc,
1924                                &blendobj);
1925 
1926         EXLATEOBJ_vCleanup(&exlo);
1927         SURFACE_ShareUnlockSurface(psurf);
1928         if (Ret) goto done;
1929         ERR("NtGdiAlphaBlend failed!\n");
1930     }
1931 NoAlpha:
1932     if (diFlags & DI_MASK)
1933     {
1934         DWORD rop4 = (diFlags & DI_IMAGE) ? ROP4_SRCAND : ROP4_SRCCOPY;
1935 
1936         EXLATEOBJ_vInitSrcMonoXlate(&exlo, psurfDest->ppal, 0x00FFFFFF, 0);
1937 
1938         Ret = IntEngStretchBlt(&psurfDest->SurfObj,
1939                                &psurfMask->SurfObj,
1940                                NULL,
1941                                pdcClipObj,
1942                                &exlo.xlo,
1943                                NULL,
1944                                &rcDest,
1945                                &rcSrc,
1946                                NULL,
1947                                NULL,
1948                                NULL,
1949                                rop4);
1950 
1951         EXLATEOBJ_vCleanup(&exlo);
1952 
1953         if (!Ret)
1954         {
1955             ERR("Failed to mask the bitmap data.\n");
1956             goto Cleanup;
1957         }
1958     }
1959 
1960     if (diFlags & DI_IMAGE)
1961     {
1962         if (psurfColor)
1963         {
1964             DWORD rop4 = (diFlags & DI_MASK) ? ROP4_SRCINVERT : ROP4_SRCCOPY ;
1965 
1966             EXLATEOBJ_vInitialize(&exlo, psurfColor->ppal, psurfDest->ppal, 0x00FFFFFF, 0x00FFFFFF, 0);
1967 
1968             Ret = IntEngStretchBlt(&psurfDest->SurfObj,
1969                                    &psurfColor->SurfObj,
1970                                    NULL,
1971                                    pdcClipObj,
1972                                    &exlo.xlo,
1973                                    NULL,
1974                                    &rcDest,
1975                                    &rcSrc,
1976                                    NULL,
1977                                    NULL,
1978                                    NULL,
1979                                    rop4);
1980 
1981             EXLATEOBJ_vCleanup(&exlo);
1982 
1983             if (!Ret)
1984             {
1985                 ERR("Failed to render the icon bitmap.\n");
1986                 goto Cleanup;
1987             }
1988         }
1989         else
1990         {
1991             /* Mask bitmap holds the information in its bottom half */
1992             DWORD rop4 = (diFlags & DI_MASK) ? ROP4_SRCINVERT : ROP4_SRCCOPY;
1993             RECTL_vOffsetRect(&rcSrc, 0, pIcon->cy);
1994 
1995             EXLATEOBJ_vInitSrcMonoXlate(&exlo, psurfDest->ppal, 0x00FFFFFF, 0);
1996 
1997             Ret = IntEngStretchBlt(&psurfDest->SurfObj,
1998                                    &psurfMask->SurfObj,
1999                                    NULL,
2000                                    pdcClipObj,
2001                                    &exlo.xlo,
2002                                    NULL,
2003                                    &rcDest,
2004                                    &rcSrc,
2005                                    NULL,
2006                                    NULL,
2007                                    NULL,
2008                                    rop4);
2009 
2010             EXLATEOBJ_vCleanup(&exlo);
2011 
2012             if (!Ret)
2013             {
2014                 ERR("Failed to render the icon bitmap.\n");
2015                 goto Cleanup;
2016             }
2017         }
2018     }
2019 
2020 done:
2021 #if 0
2022     /* We're done. Was it a double buffered draw ? */
2023     if (bOffScreen)
2024     {
2025         /* Yes. Draw it back to our DC */
2026         POINTL ptSrc = {0, 0};
2027 
2028         /* Calculate destination rectangle */
2029         RECTL_vSetRect(&rcDest, xLeft, yTop, xLeft + cxWidth, yTop + cyHeight);
2030         IntLPtoDP(pdc, (LPPOINT)&rcDest, 2);
2031         RECTL_vOffsetRect(&rcDest, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y);
2032 
2033         /* Get the clip object */
2034         pdcClipObj = pdc->rosdc.CombinedClip;
2035 
2036         /* We now have our destination surface and rectangle */
2037         psurfDest = pdc->dclevel.pSurface;
2038 
2039         /* Color translation */
2040         EXLATEOBJ_vInitialize(&exlo, psurfOffScreen->ppal, psurfDest->ppal, 0x00FFFFFF, 0x00FFFFFF, 0);
2041 
2042         /* Blt it! */
2043         Ret = IntEngBitBlt(&psurfDest->SurfObj,
2044                            &psurfOffScreen->SurfObj,
2045                            NULL,
2046                            pdcClipObj,
2047                            &exlo.xlo,
2048                            &rcDest,
2049                            &ptSrc,
2050                            NULL,
2051                            NULL,
2052                            NULL,
2053                            ROP4_SRCCOPY);
2054 
2055         EXLATEOBJ_vCleanup(&exlo);
2056     }
2057 #endif
2058 Cleanup:
2059     if (pdc)
2060     {
2061         DC_vFinishBlit(pdc, NULL);
2062         DC_UnlockDc(pdc);
2063     }
2064 
2065 #if 0
2066     /* Delete off screen rendering surface */
2067     if (psurfOffScreen)
2068         GDIOBJ_vDeleteObject(&psurfOffScreen->BaseObject);
2069 #endif
2070 
2071     /* Unlock other surfaces */
2072     SURFACE_ShareUnlockSurface(psurfMask);
2073     if (psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
2074 
2075     return Ret;
2076 }
2077 
2078 /*
2079  * @implemented
2080  */
2081 BOOL
2082 APIENTRY
2083 NtUserDrawIconEx(
2084     HDC hdc,
2085     int xLeft,
2086     int yTop,
2087     HICON hIcon,
2088     int cxWidth,
2089     int cyHeight,
2090     UINT istepIfAniCur,
2091     HBRUSH hbrFlickerFreeDraw,
2092     UINT diFlags,
2093     BOOL bMetaHDC, // When TRUE, GDI functions need to be handled in User32!
2094     PVOID pDIXData)
2095 {
2096     PCURICON_OBJECT pIcon;
2097     BOOL Ret;
2098 
2099     TRACE("Enter NtUserDrawIconEx\n");
2100     UserEnterExclusive();
2101 
2102     if (!(pIcon = UserGetCurIconObject(hIcon)))
2103     {
2104         ERR("UserGetCurIconObject(0x%p) failed!\n", hIcon);
2105         UserLeave();
2106         return FALSE;
2107     }
2108 
2109     Ret = UserDrawIconEx(hdc,
2110                          xLeft,
2111                          yTop,
2112                          pIcon,
2113                          cxWidth,
2114                          cyHeight,
2115                          istepIfAniCur,
2116                          hbrFlickerFreeDraw,
2117                          diFlags);
2118 
2119     UserDereferenceObject(pIcon);
2120 
2121     UserLeave();
2122     return Ret;
2123 }
2124 
2125 /*
2126  * @unimplemented
2127  */
2128 HCURSOR
2129 NTAPI
2130 NtUserGetCursorFrameInfo(
2131     HCURSOR hCursor,
2132     DWORD istep,
2133     INT* rate_jiffies,
2134     DWORD* num_steps)
2135 {
2136     PCURICON_OBJECT CurIcon;
2137     HCURSOR ret;
2138     INT jiffies = 0;
2139     DWORD steps = 1;
2140     NTSTATUS Status = STATUS_SUCCESS;
2141 
2142     TRACE("Enter NtUserGetCursorFrameInfo\n");
2143     UserEnterShared();
2144 
2145     if (!(CurIcon = UserGetCurIconObject(hCursor)))
2146     {
2147         UserLeave();
2148         return NULL;
2149     }
2150 
2151     ret = CurIcon->head.h;
2152 
2153     if (CurIcon->CURSORF_flags & CURSORF_ACON)
2154     {
2155         PACON AniCurIcon = (PACON)CurIcon;
2156         if (istep >= AniCurIcon->cicur)
2157         {
2158             UserDereferenceObject(CurIcon);
2159             UserLeave();
2160             return NULL;
2161         }
2162         jiffies = AniCurIcon->ajifRate[istep];
2163         steps = AniCurIcon->cicur;
2164         ret = AniCurIcon->aspcur[AniCurIcon->aicur[istep]]->head.h;
2165     }
2166 
2167     _SEH2_TRY
2168     {
2169         ProbeForWrite(rate_jiffies, sizeof(INT), 1);
2170         ProbeForWrite(num_steps, sizeof(DWORD), 1);
2171         *rate_jiffies = jiffies;
2172         *num_steps = steps;
2173     }
2174     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2175     {
2176         Status = _SEH2_GetExceptionCode();
2177     }
2178     _SEH2_END
2179 
2180     if (!NT_SUCCESS(Status))
2181     {
2182         WARN("Status: 0x%08lx\n", Status);
2183         SetLastNtError(Status);
2184         ret = NULL;
2185     }
2186 
2187     UserDereferenceObject(CurIcon);
2188     UserLeave();
2189 
2190     TRACE("Leaving NtUserGetCursorFrameInfo, ret = 0x%p\n", ret);
2191 
2192     return ret;
2193 }
2194 
2195 /*
2196  * @implemented
2197  */
2198 BOOL
2199 APIENTRY
2200 NtUserSetSystemCursor(
2201     HCURSOR hcur,
2202     DWORD id)
2203 {
2204     PCURICON_OBJECT pcur, pcurOrig = NULL;
2205     int i;
2206     PPROCESSINFO ppi;
2207     BOOL Ret = FALSE;
2208     UserEnterExclusive();
2209 
2210     if (!CheckWinstaAttributeAccess(WINSTA_WRITEATTRIBUTES))
2211     {
2212         goto Exit;
2213     }
2214 
2215     if (hcur)
2216     {
2217         pcur = UserGetCurIconObject(hcur);
2218         if (!pcur)
2219         {
2220             EngSetLastError(ERROR_INVALID_CURSOR_HANDLE);
2221             goto Exit;
2222         }
2223 
2224         ppi = PsGetCurrentProcessWin32Process();
2225 
2226         for (i = 0 ; i < 16; i++)
2227         {
2228            if (gasyscur[i].type == id)
2229            {
2230               pcurOrig = gasyscur[i].handle;
2231 
2232               if (pcurOrig) break;
2233 
2234               if (ppi->W32PF_flags & W32PF_CREATEDWINORDC)
2235               {
2236                  gasyscur[i].handle = pcur;
2237                  pcur->CURSORF_flags |= CURSORF_GLOBAL;
2238                  pcur->head.ppi = NULL;
2239                  IntInsertCursorIntoList(pcur);
2240                  Ret = TRUE;
2241               }
2242               break;
2243            }
2244         }
2245         if (pcurOrig)
2246         {
2247            FIXME("Need to copy cursor data or do something! pcurOrig %p new pcur %p\n",pcurOrig,pcur);
2248         }
2249     }
2250 Exit:
2251     UserLeave();
2252     return Ret;
2253 }
2254 
2255 /* EOF */
2256