xref: /reactos/win32ss/user/ntuser/cursoricon.c (revision fd331f14)
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
InitCursorImpl(VOID)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
IntInsertCursorIntoList(_Inout_ PCURICON_OBJECT pcur)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
IntRemoveCursorFromList(_Inout_ PCURICON_OBJECT pcur)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
IntLoadSystenIcons(HICON hcur,DWORD id)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
IntGetSysCursorInfo(VOID)187 IntGetSysCursorInfo(VOID)
188 {
189     return &gSysCursorInfo;
190 }
191 
192 FORCEINLINE
193 BOOL
is_icon(PCURICON_OBJECT object)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! */
UserGetCurIconObject(HCURSOR hCurIcon)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
IntSystemSetCursor(PCURICON_OBJECT pcurNew)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 
UserSetCursorPos(INT x,INT y,DWORD flags,ULONG_PTR dwExtraInfo,BOOL Hook)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     /* Nothing to do if position did not actually change */
265     if (x == gpsi->ptCursor.x && y == gpsi->ptCursor.y)
266         return TRUE;
267 
268     pt.x = x;
269     pt.y = y;
270 
271     /* 1. Generate a mouse move message, this sets the htEx and Track Window too */
272     Msg.message = WM_MOUSEMOVE;
273     Msg.wParam = UserGetMouseButtonsState();
274     Msg.lParam = MAKELPARAM(x, y);
275     Msg.pt = pt;
276     co_MsqInsertMouseMessage(&Msg, flags, dwExtraInfo, Hook);
277 
278     /* 2. Store the new cursor position */
279     gpsi->ptCursor = pt;
280 
281     return TRUE;
282 }
283 
284 HANDLE
IntCreateCurIconHandle(BOOLEAN Animated)285 IntCreateCurIconHandle(BOOLEAN Animated)
286 {
287     PCURICON_OBJECT CurIcon;
288     HANDLE hCurIcon;
289 
290     CurIcon = UserCreateObject(
291         gHandleTable,
292         NULL,
293         GetW32ThreadInfo(),
294         &hCurIcon,
295         TYPE_CURSOR,
296         Animated ? sizeof(ACON) : sizeof(CURICON_OBJECT));
297 
298     if (!CurIcon)
299     {
300         EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
301         return FALSE;
302     }
303 
304     if (Animated)
305     {
306         /* We MUST set this flag, to track whether this is an ACON! */
307         CurIcon->CURSORF_flags |= CURSORF_ACON;
308     }
309 
310     NT_ASSERT(CurIcon->pcurNext == NULL);
311     UserDereferenceObject(CurIcon);
312 
313     return hCurIcon;
314 }
315 
316 BOOLEAN
IntDestroyCurIconObject(_In_ PVOID Object)317 IntDestroyCurIconObject(
318     _In_ PVOID Object)
319 {
320     PCURICON_OBJECT CurIcon = Object;
321 
322     /* Check if the cursor is in a list */
323     if (CurIcon->CURSORF_flags & CURSORF_LINKED)
324     {
325         /* Remove the cursor from it's list */
326         IntRemoveCursorFromList(CurIcon);
327     }
328 
329     /* We just mark the handle as being destroyed.
330      * Deleting all the stuff will be deferred to the actual struct free. */
331     UserDeleteObject(UserHMGetHandle(CurIcon), TYPE_CURSOR);
332     return TRUE;
333 }
334 
335 VOID
FreeCurIconObject(_In_ PVOID Object)336 FreeCurIconObject(
337     _In_ PVOID Object)
338 {
339     PCURICON_OBJECT CurIcon = Object;
340 
341     if (!(CurIcon->CURSORF_flags & CURSORF_ACON))
342     {
343         HBITMAP bmpMask = CurIcon->hbmMask;
344         HBITMAP bmpColor = CurIcon->hbmColor;
345         HBITMAP bmpAlpha = CurIcon->hbmAlpha;
346 
347         /* Delete bitmaps */
348         if (bmpMask)
349         {
350             GreSetObjectOwner(bmpMask, GDI_OBJ_HMGR_POWNED);
351             NT_VERIFY(GreDeleteObject(bmpMask) == TRUE);
352             CurIcon->hbmMask = NULL;
353         }
354         if (bmpColor)
355         {
356             GreSetObjectOwner(bmpColor, GDI_OBJ_HMGR_POWNED);
357             NT_VERIFY(GreDeleteObject(bmpColor) == TRUE);
358             CurIcon->hbmColor = NULL;
359         }
360         if (bmpAlpha)
361         {
362             GreSetObjectOwner(bmpAlpha, GDI_OBJ_HMGR_POWNED);
363             NT_VERIFY(GreDeleteObject(bmpAlpha) == TRUE);
364             CurIcon->hbmAlpha = NULL;
365         }
366     }
367     else
368     {
369         PACON AniCurIcon = (PACON)CurIcon;
370         UINT i;
371 
372         for (i = 0; i < AniCurIcon->cpcur; i++)
373         {
374             UserDereferenceObject(AniCurIcon->aspcur[i]);
375             NT_VERIFY(IntDestroyCurIconObject(AniCurIcon->aspcur[i]) == TRUE);
376         }
377         ExFreePoolWithTag(AniCurIcon->aspcur, USERTAG_CURSOR);
378     }
379 
380     if (CurIcon->CURSORF_flags & CURSORF_LRSHARED)
381     {
382         if (!IS_INTRESOURCE(CurIcon->strName.Buffer))
383             ExFreePoolWithTag(CurIcon->strName.Buffer, TAG_STRING);
384         if (CurIcon->atomModName)
385             RtlDeleteAtomFromAtomTable(gAtomTable, CurIcon->atomModName);
386         CurIcon->strName.Buffer = NULL;
387         CurIcon->atomModName = 0;
388     }
389 
390     /* Finally free the thing */
391     FreeProcMarkObject(CurIcon);
392 }
393 
394 VOID FASTCALL
IntCleanupCurIconCache(PPROCESSINFO Win32Process)395 IntCleanupCurIconCache(PPROCESSINFO Win32Process)
396 {
397     PCURICON_OBJECT CurIcon;
398 
399     /* Run through the list of icon objects */
400     while (Win32Process->pCursorCache)
401     {
402         CurIcon = Win32Process->pCursorCache;
403         Win32Process->pCursorCache = CurIcon->pcurNext;
404         UserDereferenceObject(CurIcon);
405     }
406 }
407 
408 /*
409  * @implemented
410  */
411 _Success_(return != FALSE)
412 BOOL
413 NTAPI
NtUserGetIconInfo(_In_ HANDLE hCurIcon,_Out_opt_ PICONINFO IconInfo,_Inout_opt_ PUNICODE_STRING lpModule,_Inout_opt_ PUNICODE_STRING lpResName,_Out_opt_ LPDWORD pbpp,_In_ BOOL bInternal)414 NtUserGetIconInfo(
415     _In_ HANDLE hCurIcon,
416     _Out_opt_ PICONINFO IconInfo,
417     _Inout_opt_ PUNICODE_STRING lpModule,
418     _Inout_opt_ PUNICODE_STRING lpResName,
419     _Out_opt_ LPDWORD pbpp,
420     _In_ BOOL bInternal)
421 {
422     ICONINFO ii;
423     PCURICON_OBJECT CurIcon;
424     NTSTATUS Status = STATUS_SUCCESS;
425     BOOL Ret = FALSE;
426     DWORD colorBpp = 0;
427 
428     TRACE("Enter NtUserGetIconInfo\n");
429 
430     /* Check if something was actually asked */
431     if (!IconInfo && !lpModule && !lpResName)
432     {
433         WARN("Nothing to fill.\n");
434         EngSetLastError(ERROR_INVALID_PARAMETER);
435         return FALSE;
436     }
437 
438     UserEnterExclusive();
439 
440     if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
441     {
442         WARN("UserGetIconObject(0x%p) Failed.\n", hCurIcon);
443         UserLeave();
444         return FALSE;
445     }
446 
447     /* Give back the icon information */
448     if (IconInfo)
449     {
450         PCURICON_OBJECT FrameCurIcon = CurIcon;
451         if (CurIcon->CURSORF_flags & CURSORF_ACON)
452         {
453             /* Get information from first frame. */
454             FrameCurIcon = ((PACON)CurIcon)->aspcur[0];
455         }
456 
457         /* Fill data */
458         ii.fIcon = is_icon(FrameCurIcon);
459         ii.xHotspot = FrameCurIcon->xHotspot;
460         ii.yHotspot = FrameCurIcon->yHotspot;
461 
462         /* Copy bitmaps */
463         ii.hbmMask = BITMAP_CopyBitmap(FrameCurIcon->hbmMask);
464         GreSetObjectOwner(ii.hbmMask, GDI_OBJ_HMGR_POWNED);
465         ii.hbmColor = BITMAP_CopyBitmap(FrameCurIcon->hbmColor);
466         GreSetObjectOwner(ii.hbmColor, GDI_OBJ_HMGR_POWNED);
467         colorBpp = FrameCurIcon->bpp;
468 
469         /* Copy fields */
470         _SEH2_TRY
471         {
472             ProbeForWrite(IconInfo, sizeof(ICONINFO), 1);
473             RtlCopyMemory(IconInfo, &ii, sizeof(ICONINFO));
474 
475             if (pbpp)
476             {
477                 ProbeForWrite(pbpp, sizeof(DWORD), 1);
478                 *pbpp = colorBpp;
479             }
480         }
481         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
482         {
483             Status = _SEH2_GetExceptionCode();
484         }
485         _SEH2_END
486 
487         if (!NT_SUCCESS(Status))
488         {
489             WARN("Status: 0x%08lx\n", Status);
490             SetLastNtError(Status);
491             goto leave;
492         }
493     }
494 
495     /* Give back the module name */
496     if (lpModule)
497     {
498         ULONG BufLen = 0;
499         if (!CurIcon->atomModName)
500             goto leave;
501 
502         RtlQueryAtomInAtomTable(gAtomTable, CurIcon->atomModName, NULL, NULL, NULL, &BufLen);
503         /* Get the module name from the atom table */
504         _SEH2_TRY
505         {
506             BufLen += sizeof(WCHAR);
507             if (BufLen > (lpModule->MaximumLength))
508             {
509                 lpModule->Length = 0;
510                 lpModule->MaximumLength = BufLen;
511             }
512             else
513             {
514                 ProbeForWrite(lpModule->Buffer, lpModule->MaximumLength, 1);
515                 BufLen = lpModule->MaximumLength;
516                 RtlQueryAtomInAtomTable(gAtomTable, CurIcon->atomModName, NULL, NULL, lpModule->Buffer, &BufLen);
517                 lpModule->Length = BufLen;
518             }
519         }
520         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
521         {
522             Status = _SEH2_GetExceptionCode();
523         }
524         _SEH2_END
525 
526         if (!NT_SUCCESS(Status))
527         {
528             SetLastNtError(Status);
529             goto leave;
530         }
531     }
532 
533     if (lpResName)
534     {
535         if (!CurIcon->strName.Buffer)
536             goto leave;
537 
538         /* Copy it */
539         _SEH2_TRY
540         {
541             ProbeForWrite(lpResName, sizeof(UNICODE_STRING), 1);
542             if (IS_INTRESOURCE(CurIcon->strName.Buffer))
543             {
544                 lpResName->Buffer = CurIcon->strName.Buffer;
545                 lpResName->Length = 0;
546                 lpResName->MaximumLength = 0;
547             }
548             else if (lpResName->MaximumLength < CurIcon->strName.MaximumLength)
549             {
550                 lpResName->Length = 0;
551                 lpResName->MaximumLength = CurIcon->strName.MaximumLength;
552             }
553             else
554             {
555                 ProbeForWrite(lpResName->Buffer, lpResName->MaximumLength, 1);
556                 RtlCopyMemory(lpResName->Buffer, CurIcon->strName.Buffer, CurIcon->strName.Length);
557                 lpResName->Length = CurIcon->strName.Length;
558             }
559         }
560         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
561         {
562             Status = _SEH2_GetExceptionCode();
563         }
564         _SEH2_END
565     }
566 
567     if (!NT_SUCCESS(Status))
568     {
569         SetLastNtError(Status);
570         goto leave;
571     }
572 
573     Ret = TRUE;
574 
575 leave:
576     UserDereferenceObject(CurIcon);
577 
578     TRACE("Leave NtUserGetIconInfo, ret=%i\n", Ret);
579     UserLeave();
580 
581     return Ret;
582 }
583 
584 
585 /*
586  * @implemented
587  */
588 BOOL
589 APIENTRY
NtUserGetIconSize(HANDLE hCurIcon,UINT istepIfAniCur,PLONG plcx,PLONG plcy)590 NtUserGetIconSize(
591     HANDLE hCurIcon,
592     UINT istepIfAniCur,
593     PLONG plcx,       // &size.cx
594     PLONG plcy)       // &size.cy
595 {
596     PCURICON_OBJECT CurIcon;
597     NTSTATUS Status = STATUS_SUCCESS;
598     BOOL bRet = FALSE;
599 
600     TRACE("Enter NtUserGetIconSize\n");
601     UserEnterShared();
602 
603     if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
604     {
605         goto cleanup;
606     }
607 
608     if (CurIcon->CURSORF_flags & CURSORF_ACON)
609     {
610         /* Use first frame for animated cursors */
611         PACON AniCurIcon = (PACON)CurIcon;
612         CurIcon = AniCurIcon->aspcur[0];
613         UserDereferenceObject(AniCurIcon);
614         UserReferenceObject(CurIcon);
615     }
616 
617     _SEH2_TRY
618     {
619         ProbeForWrite(plcx, sizeof(LONG), 1);
620         *plcx = CurIcon->cx;
621         ProbeForWrite(plcy, sizeof(LONG), 1);
622         *plcy = CurIcon->cy;
623     }
624     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
625     {
626         Status = _SEH2_GetExceptionCode();
627     }
628     _SEH2_END
629 
630     if (NT_SUCCESS(Status))
631         bRet = TRUE;
632     else
633         SetLastNtError(Status); // Maybe not, test this
634 
635     UserDereferenceObject(CurIcon);
636 
637 cleanup:
638     TRACE("Leave NtUserGetIconSize, ret=%i\n", bRet);
639     UserLeave();
640     return bRet;
641 }
642 
643 
644 /*
645  * @implemented
646  */
647 BOOL
648 APIENTRY
NtUserGetCursorInfo(PCURSORINFO pci)649 NtUserGetCursorInfo(
650     PCURSORINFO pci)
651 {
652     CURSORINFO SafeCi;
653     PSYSTEM_CURSORINFO CurInfo;
654     NTSTATUS Status = STATUS_SUCCESS;
655     PCURICON_OBJECT CurIcon;
656     BOOL Ret = FALSE;
657 
658     TRACE("Enter NtUserGetCursorInfo\n");
659     UserEnterShared();
660 
661     CurInfo = IntGetSysCursorInfo();
662     CurIcon = (PCURICON_OBJECT)CurInfo->CurrentCursorObject;
663 
664     SafeCi.cbSize = sizeof(CURSORINFO);
665     SafeCi.flags = ((CurIcon && CurInfo->ShowingCursor >= 0) ? CURSOR_SHOWING : 0);
666     SafeCi.hCursor = (CurIcon ? UserHMGetHandle(CurIcon) : NULL);
667 
668     SafeCi.ptScreenPos = gpsi->ptCursor;
669 
670     _SEH2_TRY
671     {
672         if (pci->cbSize == sizeof(CURSORINFO))
673         {
674             ProbeForWrite(pci, sizeof(CURSORINFO), 1);
675             RtlCopyMemory(pci, &SafeCi, sizeof(CURSORINFO));
676             Ret = TRUE;
677         }
678         else
679         {
680             EngSetLastError(ERROR_INVALID_PARAMETER);
681         }
682     }
683     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
684     {
685         Status = _SEH2_GetExceptionCode();
686     }
687     _SEH2_END;
688     if (!NT_SUCCESS(Status))
689     {
690         SetLastNtError(Status);
691     }
692 
693     TRACE("Leave NtUserGetCursorInfo, ret=%i\n", Ret);
694     UserLeave();
695     return Ret;
696 }
697 
698 BOOL
699 APIENTRY
UserClipCursor(RECTL * prcl)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
NtUserClipCursor(RECTL * prcl)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
NtUserDestroyCursor(_In_ HANDLE hCurIcon,_In_ BOOL bForce)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
NtUserFindExistingCursorIcon(_In_ PUNICODE_STRING pustrModule,_In_ PUNICODE_STRING pustrRsrc,_In_ FINDEXISTINGCURICONPARAM * param)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 = UserHMGetHandle(CurIcon);
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
NtUserGetClipCursor(RECTL * lpRect)996 NtUserGetClipCursor(
997     RECTL *lpRect)
998 {
999     PSYSTEM_CURSORINFO CurInfo;
1000     RECTL Rect;
1001     NTSTATUS Status;
1002     BOOL Ret = FALSE;
1003 
1004     TRACE("Enter NtUserGetClipCursor\n");
1005     UserEnterShared();
1006 
1007     if (!CheckWinstaAttributeAccess(WINSTA_READATTRIBUTES))
1008     {
1009         goto Exit; // Return FALSE
1010     }
1011 
1012     if (!lpRect)
1013         goto Exit; // 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         goto Exit; // Return FALSE
1033     }
1034 
1035     Ret = TRUE;
1036 
1037 Exit:
1038     TRACE("Leave NtUserGetClipCursor, ret=%i\n", Ret);
1039     UserLeave();
1040     return Ret;
1041 }
1042 
1043 
1044 /*
1045  * @implemented
1046  */
1047 HCURSOR
1048 APIENTRY
NtUserSetCursor(HCURSOR hCursor)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
NtUserSetCursorContents(HANDLE hCurIcon,PICONINFO UnsafeIconInfo)1119 NtUserSetCursorContents(
1120     HANDLE hCurIcon,
1121     PICONINFO UnsafeIconInfo)
1122 {
1123     FIXME(" is UNIMPLEMENTED.\n");
1124     return FALSE;
1125 }
1126 
1127 
1128 static
1129 BOOL
IntSetCursorData(_Inout_ PCURICON_OBJECT pcur,_In_opt_ PUNICODE_STRING pustrName,_In_ ATOM atomModName,_In_ const CURSORDATA * pcursordata)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
IntSetAconData(_Inout_ PACON pacon,_In_opt_ PUNICODE_STRING pustrName,_In_ ATOM atomModName,_In_ const CURSORDATA * pcursordata)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
UserSetCursorIconData(_In_ HCURSOR hcursor,_In_opt_ PUNICODE_STRING pustrModule,_In_opt_ PUNICODE_STRING pustrRsrc,_In_ PCURSORDATA pcursordata)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
NtUserSetCursorIconData(_In_ HCURSOR hcursor,_In_opt_ PUNICODE_STRING pustrModule,_In_opt_ PUNICODE_STRING pustrRsrc,_In_ const CURSORDATA * pCursorData)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             !IS_INTRESOURCE(ustrRsrc.Buffer))
1670         {
1671             ExFreePoolWithTag(ustrRsrc.Buffer, TAG_STRING);
1672         }
1673     }
1674 
1675     TRACE("Leave NtUserSetCursorIconData, bResult = %i\n", bResult);
1676 
1677     return bResult;
1678 }
1679 
1680 /* Mostly inspired from wine code.
1681  * We use low level functions because:
1682  *  - at this point, the icon bitmap could have a different bit depth than the DC,
1683  *    making it thus impossible to use NtCreateCompatibleDC and selecting the bitmap.
1684  *    This happens after a mode setting change.
1685  *  - it avoids massive GDI objects locking when only the destination surface needs it.
1686  *  - It makes (small) performance gains.
1687  */
1688 BOOL
UserDrawIconEx(HDC hDc,INT xLeft,INT yTop,PCURICON_OBJECT pIcon,INT cxWidth,INT cyHeight,UINT istepIfAniCur,HBRUSH hbrFlickerFreeDraw,UINT diFlags)1689 UserDrawIconEx(
1690     HDC hDc,
1691     INT xLeft,
1692     INT yTop,
1693     PCURICON_OBJECT pIcon,
1694     INT cxWidth,
1695     INT cyHeight,
1696     UINT istepIfAniCur,
1697     HBRUSH hbrFlickerFreeDraw,
1698     UINT diFlags)
1699 {
1700     PSURFACE psurfDest, psurfMask, psurfColor; //, psurfOffScreen = NULL;
1701     PDC pdc = NULL;
1702     BOOL Ret = FALSE;
1703     HBITMAP hbmMask, hbmColor, hbmAlpha;
1704     BOOL bOffScreen;
1705     RECTL rcDest, rcSrc;
1706     CLIPOBJ* pdcClipObj = NULL;
1707     EXLATEOBJ exlo;
1708 
1709     /* Stupid case */
1710     if ((diFlags & DI_NORMAL) == 0)
1711     {
1712         ERR("DrawIconEx called without mask or color bitmap to draw.\n");
1713         return FALSE;
1714     }
1715 
1716     if (pIcon->CURSORF_flags & CURSORF_ACON)
1717     {
1718         ACON* pAcon = (ACON*)pIcon;
1719         if (istepIfAniCur >= pAcon->cicur)
1720         {
1721             ERR("NtUserDrawIconEx: istepIfAniCur too big!\n");
1722             return FALSE;
1723         }
1724         pIcon = pAcon->aspcur[pAcon->aicur[istepIfAniCur]];
1725     }
1726 
1727     hbmMask = pIcon->hbmMask;
1728     hbmColor = pIcon->hbmColor;
1729     hbmAlpha = pIcon->hbmAlpha;
1730 
1731     /*
1732      * Get our objects.
1733      * Shared locks are enough, we are only reading those bitmaps
1734      */
1735     psurfMask = SURFACE_ShareLockSurface(hbmMask);
1736     if (psurfMask == NULL)
1737     {
1738         ERR("Unable to lock the mask surface.\n");
1739         return FALSE;
1740     }
1741 
1742     /* Color bitmap is not mandatory */
1743     if (hbmColor == NULL)
1744     {
1745         /* But then the mask bitmap must have the information in it's bottom half */
1746         ASSERT(psurfMask->SurfObj.sizlBitmap.cy == 2*pIcon->cy);
1747         psurfColor = NULL;
1748     }
1749     else if ((psurfColor = SURFACE_ShareLockSurface(hbmColor)) == NULL)
1750     {
1751         ERR("Unable to lock the color bitmap.\n");
1752         SURFACE_ShareUnlockSurface(psurfMask);
1753         return FALSE;
1754     }
1755 
1756     pdc = DC_LockDc(hDc);
1757     if (!pdc)
1758     {
1759         ERR("Could not lock the destination DC.\n");
1760         SURFACE_ShareUnlockSurface(psurfMask);
1761         if (psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
1762         return FALSE;
1763     }
1764 
1765     /* Fix width parameter, if needed */
1766     if (!cxWidth)
1767     {
1768         if (diFlags & DI_DEFAULTSIZE)
1769             cxWidth = is_icon(pIcon) ?
1770                 UserGetSystemMetrics(SM_CXICON) : UserGetSystemMetrics(SM_CXCURSOR);
1771         else
1772             cxWidth = pIcon->cx;
1773     }
1774 
1775     /* Fix height parameter, if needed */
1776     if (!cyHeight)
1777     {
1778         if (diFlags & DI_DEFAULTSIZE)
1779             cyHeight = is_icon(pIcon) ?
1780                 UserGetSystemMetrics(SM_CYICON) : UserGetSystemMetrics(SM_CYCURSOR);
1781         else
1782             cyHeight = pIcon->cy;
1783     }
1784 
1785     /* Calculate destination rectangle */
1786     RECTL_vSetRect(&rcDest, xLeft, yTop, xLeft + cxWidth, yTop + cyHeight);
1787     IntLPtoDP(pdc, (LPPOINT)&rcDest, 2);
1788     RECTL_vOffsetRect(&rcDest, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y);
1789 
1790     /* Prepare the underlying surface */
1791     DC_vPrepareDCsForBlit(pdc, &rcDest, NULL, NULL);
1792 
1793     /* We now have our destination surface and rectangle */
1794     psurfDest = pdc->dclevel.pSurface;
1795 
1796     if (psurfDest == NULL)
1797     {
1798         /* Empty DC */
1799         DC_vFinishBlit(pdc, NULL);
1800         DC_UnlockDc(pdc);
1801         SURFACE_ShareUnlockSurface(psurfMask);
1802         if (psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
1803         return FALSE;
1804     }
1805 
1806     /* Set source rect */
1807     RECTL_vSetRect(&rcSrc, 0, 0, pIcon->cx, pIcon->cy);
1808 
1809     /* Should we render off-screen? */
1810     bOffScreen = hbrFlickerFreeDraw &&
1811         (GDI_HANDLE_GET_TYPE(hbrFlickerFreeDraw) == GDI_OBJECT_TYPE_BRUSH);
1812 
1813     if (bOffScreen)
1814     {
1815         /* Yes: Allocate and paint the offscreen surface */
1816         EBRUSHOBJ eboFill;
1817         PBRUSH pbrush = BRUSH_ShareLockBrush(hbrFlickerFreeDraw);
1818 
1819         TRACE("Performing off-screen rendering.\n");
1820 
1821         if (!pbrush)
1822         {
1823             ERR("Failed to get brush object.\n");
1824             goto Cleanup;
1825         }
1826 
1827 #if 0 //We lock the hdc surface during the whole function it makes no sense to use an offscreen surface for "flicker free" drawing
1828         psurfOffScreen = SURFACE_AllocSurface(STYPE_BITMAP,
1829             cxWidth, cyHeight, psurfDest->SurfObj.iBitmapFormat,
1830             0, 0, NULL);
1831         if (!psurfOffScreen)
1832         {
1833             ERR("Failed to allocate the off-screen surface.\n");
1834             BRUSH_ShareUnlockBrush(pbrush);
1835             goto Cleanup;
1836         }
1837 
1838         /* Paint the brush */
1839         EBRUSHOBJ_vInit(&eboFill, pbrush, psurfOffScreen, 0x00FFFFFF, 0, NULL);
1840         RECTL_vSetRect(&rcDest, 0, 0, cxWidth, cyHeight);
1841 
1842         Ret = IntEngBitBlt(&psurfOffScreen->SurfObj,
1843             NULL,
1844             NULL,
1845             NULL,
1846             NULL,
1847             &rcDest,
1848             NULL,
1849             NULL,
1850             &eboFill.BrushObject,
1851             &pbrush->ptOrigin,
1852             ROP4_PATCOPY);
1853 
1854         /* Clean up everything */
1855         EBRUSHOBJ_vCleanup(&eboFill);
1856         BRUSH_ShareUnlockBrush(pbrush);
1857 
1858         if (!Ret)
1859         {
1860             ERR("Failed to paint the off-screen surface.\n");
1861             goto Cleanup;
1862         }
1863 
1864         /* We now have our destination surface */
1865         psurfDest = psurfOffScreen;
1866 #else
1867         pdcClipObj = (CLIPOBJ *)&pdc->co;
1868         /* Paint the brush */
1869         EBRUSHOBJ_vInit(&eboFill, pbrush, psurfDest, 0x00FFFFFF, 0, NULL);
1870 
1871         Ret = IntEngBitBlt(&psurfDest->SurfObj,
1872             NULL,
1873             NULL,
1874             pdcClipObj,
1875             NULL,
1876             &rcDest,
1877             NULL,
1878             NULL,
1879             &eboFill.BrushObject,
1880             &pbrush->ptOrigin,
1881             ROP4_PATCOPY);
1882 
1883         /* Clean up everything */
1884         EBRUSHOBJ_vCleanup(&eboFill);
1885         BRUSH_ShareUnlockBrush(pbrush);
1886 
1887         if (!Ret)
1888         {
1889             ERR("Failed to paint the off-screen surface.\n");
1890             goto Cleanup;
1891         }
1892 #endif
1893     }
1894     else
1895     {
1896         /* We directly draw to the DC */
1897         TRACE("Performing on screen rendering.\n");
1898         pdcClipObj = (CLIPOBJ *)&pdc->co;
1899         // psurfOffScreen = NULL;
1900     }
1901 
1902     /* Now do the rendering */
1903     if (hbmAlpha && ((diFlags & DI_NORMAL) == DI_NORMAL))
1904     {
1905         BLENDOBJ blendobj = { {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA } };
1906         PSURFACE psurf = NULL;
1907 
1908         psurf = SURFACE_ShareLockSurface(hbmAlpha);
1909         if (!psurf)
1910         {
1911             ERR("SURFACE_LockSurface failed!\n");
1912             goto NoAlpha;
1913         }
1914 
1915         /* Initialize color translation object */
1916         EXLATEOBJ_vInitialize(&exlo, psurf->ppal, psurfDest->ppal, 0xFFFFFFFF, 0xFFFFFFFF, 0);
1917 
1918         /* Now do it */
1919         Ret = IntEngAlphaBlend(&psurfDest->SurfObj,
1920                                &psurf->SurfObj,
1921                                pdcClipObj,
1922                                &exlo.xlo,
1923                                &rcDest,
1924                                &rcSrc,
1925                                &blendobj);
1926 
1927         EXLATEOBJ_vCleanup(&exlo);
1928         SURFACE_ShareUnlockSurface(psurf);
1929         if (Ret) goto done;
1930         ERR("NtGdiAlphaBlend failed!\n");
1931     }
1932 NoAlpha:
1933     if (diFlags & DI_MASK)
1934     {
1935         DWORD rop4 = (diFlags & DI_IMAGE) ? ROP4_SRCAND : ROP4_SRCCOPY;
1936 
1937         EXLATEOBJ_vInitSrcMonoXlate(&exlo, psurfDest->ppal, 0x00FFFFFF, 0);
1938 
1939         Ret = IntEngStretchBlt(&psurfDest->SurfObj,
1940                                &psurfMask->SurfObj,
1941                                NULL,
1942                                pdcClipObj,
1943                                &exlo.xlo,
1944                                NULL,
1945                                &rcDest,
1946                                &rcSrc,
1947                                NULL,
1948                                NULL,
1949                                NULL,
1950                                rop4);
1951 
1952         EXLATEOBJ_vCleanup(&exlo);
1953 
1954         if (!Ret)
1955         {
1956             ERR("Failed to mask the bitmap data.\n");
1957             goto Cleanup;
1958         }
1959     }
1960 
1961     if (diFlags & DI_IMAGE)
1962     {
1963         if (psurfColor)
1964         {
1965             DWORD rop4 = (diFlags & DI_MASK) ? ROP4_SRCINVERT : ROP4_SRCCOPY ;
1966 
1967             EXLATEOBJ_vInitialize(&exlo, psurfColor->ppal, psurfDest->ppal, 0x00FFFFFF, 0x00FFFFFF, 0);
1968 
1969             Ret = IntEngStretchBlt(&psurfDest->SurfObj,
1970                                    &psurfColor->SurfObj,
1971                                    NULL,
1972                                    pdcClipObj,
1973                                    &exlo.xlo,
1974                                    NULL,
1975                                    &rcDest,
1976                                    &rcSrc,
1977                                    NULL,
1978                                    NULL,
1979                                    NULL,
1980                                    rop4);
1981 
1982             EXLATEOBJ_vCleanup(&exlo);
1983 
1984             if (!Ret)
1985             {
1986                 ERR("Failed to render the icon bitmap.\n");
1987                 goto Cleanup;
1988             }
1989         }
1990         else
1991         {
1992             /* Mask bitmap holds the information in its bottom half */
1993             DWORD rop4 = (diFlags & DI_MASK) ? ROP4_SRCINVERT : ROP4_SRCCOPY;
1994             RECTL_vOffsetRect(&rcSrc, 0, pIcon->cy);
1995 
1996             EXLATEOBJ_vInitSrcMonoXlate(&exlo, psurfDest->ppal, 0x00FFFFFF, 0);
1997 
1998             Ret = IntEngStretchBlt(&psurfDest->SurfObj,
1999                                    &psurfMask->SurfObj,
2000                                    NULL,
2001                                    pdcClipObj,
2002                                    &exlo.xlo,
2003                                    NULL,
2004                                    &rcDest,
2005                                    &rcSrc,
2006                                    NULL,
2007                                    NULL,
2008                                    NULL,
2009                                    rop4);
2010 
2011             EXLATEOBJ_vCleanup(&exlo);
2012 
2013             if (!Ret)
2014             {
2015                 ERR("Failed to render the icon bitmap.\n");
2016                 goto Cleanup;
2017             }
2018         }
2019     }
2020 
2021 done:
2022 #if 0
2023     /* We're done. Was it a double buffered draw ? */
2024     if (bOffScreen)
2025     {
2026         /* Yes. Draw it back to our DC */
2027         POINTL ptSrc = {0, 0};
2028 
2029         /* Calculate destination rectangle */
2030         RECTL_vSetRect(&rcDest, xLeft, yTop, xLeft + cxWidth, yTop + cyHeight);
2031         IntLPtoDP(pdc, (LPPOINT)&rcDest, 2);
2032         RECTL_vOffsetRect(&rcDest, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y);
2033 
2034         /* Get the clip object */
2035         pdcClipObj = pdc->rosdc.CombinedClip;
2036 
2037         /* We now have our destination surface and rectangle */
2038         psurfDest = pdc->dclevel.pSurface;
2039 
2040         /* Color translation */
2041         EXLATEOBJ_vInitialize(&exlo, psurfOffScreen->ppal, psurfDest->ppal, 0x00FFFFFF, 0x00FFFFFF, 0);
2042 
2043         /* Blt it! */
2044         Ret = IntEngBitBlt(&psurfDest->SurfObj,
2045                            &psurfOffScreen->SurfObj,
2046                            NULL,
2047                            pdcClipObj,
2048                            &exlo.xlo,
2049                            &rcDest,
2050                            &ptSrc,
2051                            NULL,
2052                            NULL,
2053                            NULL,
2054                            ROP4_SRCCOPY);
2055 
2056         EXLATEOBJ_vCleanup(&exlo);
2057     }
2058 #endif
2059 Cleanup:
2060     if (pdc)
2061     {
2062         DC_vFinishBlit(pdc, NULL);
2063         DC_UnlockDc(pdc);
2064     }
2065 
2066 #if 0
2067     /* Delete off screen rendering surface */
2068     if (psurfOffScreen)
2069         GDIOBJ_vDeleteObject(&psurfOffScreen->BaseObject);
2070 #endif
2071 
2072     /* Unlock other surfaces */
2073     SURFACE_ShareUnlockSurface(psurfMask);
2074     if (psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
2075 
2076     return Ret;
2077 }
2078 
2079 /*
2080  * @implemented
2081  */
2082 BOOL
2083 APIENTRY
NtUserDrawIconEx(HDC hdc,int xLeft,int yTop,HICON hIcon,int cxWidth,int cyHeight,UINT istepIfAniCur,HBRUSH hbrFlickerFreeDraw,UINT diFlags,BOOL bMetaHDC,PVOID pDIXData)2084 NtUserDrawIconEx(
2085     HDC hdc,
2086     int xLeft,
2087     int yTop,
2088     HICON hIcon,
2089     int cxWidth,
2090     int cyHeight,
2091     UINT istepIfAniCur,
2092     HBRUSH hbrFlickerFreeDraw,
2093     UINT diFlags,
2094     BOOL bMetaHDC, // When TRUE, GDI functions need to be handled in User32!
2095     PVOID pDIXData)
2096 {
2097     PCURICON_OBJECT pIcon;
2098     BOOL Ret;
2099 
2100     TRACE("Enter NtUserDrawIconEx\n");
2101     UserEnterExclusive();
2102 
2103     if (!(pIcon = UserGetCurIconObject(hIcon)))
2104     {
2105         ERR("UserGetCurIconObject(0x%p) failed!\n", hIcon);
2106         UserLeave();
2107         return FALSE;
2108     }
2109 
2110     Ret = UserDrawIconEx(hdc,
2111                          xLeft,
2112                          yTop,
2113                          pIcon,
2114                          cxWidth,
2115                          cyHeight,
2116                          istepIfAniCur,
2117                          hbrFlickerFreeDraw,
2118                          diFlags);
2119 
2120     UserDereferenceObject(pIcon);
2121 
2122     UserLeave();
2123     return Ret;
2124 }
2125 
2126 /*
2127  * @unimplemented
2128  */
2129 HCURSOR
2130 NTAPI
NtUserGetCursorFrameInfo(HCURSOR hCursor,DWORD istep,INT * rate_jiffies,DWORD * num_steps)2131 NtUserGetCursorFrameInfo(
2132     HCURSOR hCursor,
2133     DWORD istep,
2134     INT* rate_jiffies,
2135     DWORD* num_steps)
2136 {
2137     PCURICON_OBJECT CurIcon;
2138     HCURSOR ret;
2139     INT jiffies = 0;
2140     DWORD steps = 1;
2141     NTSTATUS Status = STATUS_SUCCESS;
2142 
2143     TRACE("Enter NtUserGetCursorFrameInfo\n");
2144     UserEnterShared();
2145 
2146     if (!(CurIcon = UserGetCurIconObject(hCursor)))
2147     {
2148         UserLeave();
2149         return NULL;
2150     }
2151 
2152     ret = UserHMGetHandle(CurIcon);
2153 
2154     if (CurIcon->CURSORF_flags & CURSORF_ACON)
2155     {
2156         PACON AniCurIcon = (PACON)CurIcon;
2157         if (istep >= AniCurIcon->cicur)
2158         {
2159             UserDereferenceObject(CurIcon);
2160             UserLeave();
2161             return NULL;
2162         }
2163         jiffies = AniCurIcon->ajifRate[istep];
2164         steps = AniCurIcon->cicur;
2165         ret = UserHMGetHandle(AniCurIcon->aspcur[AniCurIcon->aicur[istep]]);
2166     }
2167 
2168     _SEH2_TRY
2169     {
2170         ProbeForWrite(rate_jiffies, sizeof(INT), 1);
2171         ProbeForWrite(num_steps, sizeof(DWORD), 1);
2172         *rate_jiffies = jiffies;
2173         *num_steps = steps;
2174     }
2175     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2176     {
2177         Status = _SEH2_GetExceptionCode();
2178     }
2179     _SEH2_END
2180 
2181     if (!NT_SUCCESS(Status))
2182     {
2183         WARN("Status: 0x%08lx\n", Status);
2184         SetLastNtError(Status);
2185         ret = NULL;
2186     }
2187 
2188     UserDereferenceObject(CurIcon);
2189     UserLeave();
2190 
2191     TRACE("Leaving NtUserGetCursorFrameInfo, ret = 0x%p\n", ret);
2192 
2193     return ret;
2194 }
2195 
2196 /*
2197  * @implemented
2198  */
2199 BOOL
2200 APIENTRY
NtUserSetSystemCursor(HCURSOR hcur,DWORD id)2201 NtUserSetSystemCursor(
2202     HCURSOR hcur,
2203     DWORD id)
2204 {
2205     PCURICON_OBJECT pcur, pcurOrig = NULL;
2206     int i;
2207     PPROCESSINFO ppi;
2208     BOOL Ret = FALSE;
2209     UserEnterExclusive();
2210 
2211     if (!CheckWinstaAttributeAccess(WINSTA_WRITEATTRIBUTES))
2212     {
2213         goto Exit;
2214     }
2215 
2216     if (hcur)
2217     {
2218         pcur = UserGetCurIconObject(hcur);
2219         if (!pcur)
2220         {
2221             EngSetLastError(ERROR_INVALID_CURSOR_HANDLE);
2222             goto Exit;
2223         }
2224 
2225         ppi = PsGetCurrentProcessWin32Process();
2226 
2227         for (i = 0 ; i < 16; i++)
2228         {
2229            if (gasyscur[i].type == id)
2230            {
2231               pcurOrig = gasyscur[i].handle;
2232 
2233               if (pcurOrig) break;
2234 
2235               if (ppi->W32PF_flags & W32PF_CREATEDWINORDC)
2236               {
2237                  gasyscur[i].handle = pcur;
2238                  pcur->CURSORF_flags |= CURSORF_GLOBAL;
2239                  pcur->head.ppi = NULL;
2240                  IntInsertCursorIntoList(pcur);
2241                  Ret = TRUE;
2242               }
2243               break;
2244            }
2245         }
2246         if (pcurOrig)
2247         {
2248            FIXME("Need to copy cursor data or do something! pcurOrig %p new pcur %p\n",pcurOrig,pcur);
2249         }
2250     }
2251 Exit:
2252     UserLeave();
2253     return Ret;
2254 }
2255 
2256 /* EOF */
2257