457e0cc1d58d874400839b1311babe5c206d4a33
[reactos.git] / reactos / win32ss / user / ntuser / cursoricon.c
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%08x.\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%lx\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': %0x8lx\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 = &pdc->co.ClipObj;
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 = &pdc->co.ClipObj;
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%08x.\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 */