436021715a8816f14a3a8be1864ec2cb9026a8d8
[reactos.git] / win32ss / user / ntuser / cursoricon_new.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 BOOL
28 InitCursorImpl(VOID)
29 {
30 gSysCursorInfo.Enabled = FALSE;
31 gSysCursorInfo.ButtonsDown = 0;
32 gSysCursorInfo.bClipped = FALSE;
33 gSysCursorInfo.LastBtnDown = 0;
34 gSysCursorInfo.CurrentCursorObject = NULL;
35 gSysCursorInfo.ShowingCursor = -1;
36 gSysCursorInfo.ClickLockActive = FALSE;
37 gSysCursorInfo.ClickLockTime = 0;
38
39 return TRUE;
40 }
41
42 PSYSTEM_CURSORINFO
43 IntGetSysCursorInfo()
44 {
45 return &gSysCursorInfo;
46 }
47
48 FORCEINLINE
49 BOOL
50 is_icon(PCURICON_OBJECT object)
51 {
52 return MAKEINTRESOURCE(object->rt) == RT_ICON;
53 }
54
55 /* This function creates a reference for the object! */
56 PCURICON_OBJECT FASTCALL UserGetCurIconObject(HCURSOR hCurIcon)
57 {
58 PCURICON_OBJECT CurIcon;
59
60 if (!hCurIcon)
61 {
62 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE);
63 return NULL;
64 }
65
66 if(UserObjectInDestroy(hCurIcon))
67 {
68 ERR("Requesting destroyed cursor.\n");
69 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE);
70 return NULL;
71 }
72
73 CurIcon = (PCURICON_OBJECT)UserReferenceObjectByHandle(hCurIcon, TYPE_CURSOR);
74 if (!CurIcon)
75 {
76 /* We never set ERROR_INVALID_ICON_HANDLE. lets hope noone ever checks for it */
77 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE);
78 return NULL;
79 }
80
81 ASSERT(CurIcon->head.cLockObj >= 1);
82 return CurIcon;
83 }
84
85 BOOL UserSetCursorPos( INT x, INT y, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook)
86 {
87 PWND DesktopWindow;
88 PSYSTEM_CURSORINFO CurInfo;
89 MSG Msg;
90 RECTL rcClip;
91 POINT pt;
92
93 if(!(DesktopWindow = UserGetDesktopWindow()))
94 {
95 return FALSE;
96 }
97
98 CurInfo = IntGetSysCursorInfo();
99
100 /* Clip cursor position */
101 if (!CurInfo->bClipped)
102 rcClip = DesktopWindow->rcClient;
103 else
104 rcClip = CurInfo->rcClip;
105
106 if(x >= rcClip.right) x = rcClip.right - 1;
107 if(x < rcClip.left) x = rcClip.left;
108 if(y >= rcClip.bottom) y = rcClip.bottom - 1;
109 if(y < rcClip.top) y = rcClip.top;
110
111 pt.x = x;
112 pt.y = y;
113
114 /* 1. Generate a mouse move message, this sets the htEx and Track Window too. */
115 Msg.message = WM_MOUSEMOVE;
116 Msg.wParam = UserGetMouseButtonsState();
117 Msg.lParam = MAKELPARAM(x, y);
118 Msg.pt = pt;
119 co_MsqInsertMouseMessage(&Msg, flags, dwExtraInfo, Hook);
120
121 /* 2. Store the new cursor position */
122 gpsi->ptCursor = pt;
123
124 return TRUE;
125 }
126
127 HANDLE
128 IntCreateCurIconHandle(BOOLEAN Animated)
129 {
130 PCURICON_OBJECT CurIcon;
131 HANDLE hCurIcon;
132
133 CurIcon = UserCreateObject(
134 gHandleTable,
135 NULL,
136 GetW32ThreadInfo(),
137 &hCurIcon,
138 TYPE_CURSOR,
139 Animated ? sizeof(ACON) : sizeof(CURICON_OBJECT));
140
141 if (!CurIcon)
142 {
143 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
144 return FALSE;
145 }
146
147 UserDereferenceObject(CurIcon);
148
149 return hCurIcon;
150 }
151
152 BOOLEAN
153 IntDestroyCurIconObject(
154 _In_ PVOID Object)
155 {
156 PCURICON_OBJECT CurIcon = Object;
157
158 /* We just mark the handle as being destroyed.
159 * Deleting all the stuff will be deferred to the actual struct free. */
160 return UserDeleteObject(CurIcon->head.h, TYPE_CURSOR);
161 }
162
163 void
164 FreeCurIconObject(
165 _In_ PVOID Object)
166 {
167 PCURICON_OBJECT CurIcon = Object;
168
169 if(!(CurIcon->CURSORF_flags & CURSORF_ACON))
170 {
171 HBITMAP bmpMask = CurIcon->hbmMask;
172 HBITMAP bmpColor = CurIcon->hbmColor;
173 HBITMAP bmpAlpha = CurIcon->hbmAlpha;
174
175 /* Delete bitmaps */
176 if (bmpMask)
177 {
178 GreSetObjectOwner(bmpMask, GDI_OBJ_HMGR_POWNED);
179 GreDeleteObject(bmpMask);
180 CurIcon->hbmMask = NULL;
181 }
182 if (bmpColor)
183 {
184 GreSetObjectOwner(bmpColor, GDI_OBJ_HMGR_POWNED);
185 GreDeleteObject(bmpColor);
186 CurIcon->hbmColor = NULL;
187 }
188 if (bmpAlpha)
189 {
190 GreSetObjectOwner(bmpAlpha, GDI_OBJ_HMGR_POWNED);
191 GreDeleteObject(bmpAlpha);
192 CurIcon->hbmAlpha = NULL;
193 }
194 }
195 else
196 {
197 PACON AniCurIcon = (PACON)CurIcon;
198 UINT i;
199
200 for(i = 0; i < AniCurIcon->cpcur; i++)
201 IntDestroyCurIconObject(AniCurIcon->aspcur[i]);
202 ExFreePoolWithTag(AniCurIcon->aspcur, USERTAG_CURSOR);
203 }
204
205 if (CurIcon->CURSORF_flags & CURSORF_LRSHARED)
206 {
207 PPROCESSINFO ppi;
208
209 if (!IS_INTRESOURCE(CurIcon->strName.Buffer))
210 ExFreePoolWithTag(CurIcon->strName.Buffer, TAG_STRING);
211 if (CurIcon->atomModName)
212 RtlDeleteAtomFromAtomTable(gAtomTable, CurIcon->atomModName);
213 CurIcon->strName.Buffer = NULL;
214 CurIcon->atomModName = 0;
215
216 /* Try finding it in its process cache */
217 ppi = CurIcon->head.ppi;
218 if (ppi->pCursorCache == CurIcon)
219 ppi->pCursorCache = CurIcon->pcurNext;
220 else
221 {
222 PCURICON_OBJECT CacheCurIcon= ppi->pCursorCache;
223 while (CacheCurIcon)
224 {
225 if (CacheCurIcon->pcurNext == CurIcon)
226 {
227 CacheCurIcon->pcurNext = CurIcon->pcurNext;
228 break;
229 }
230 CacheCurIcon = CacheCurIcon->pcurNext;
231 }
232 }
233 }
234
235 /* Finally free the thing */
236 FreeProcMarkObject(CurIcon);
237 }
238
239 VOID FASTCALL
240 IntCleanupCurIconCache(PPROCESSINFO Win32Process)
241 {
242 PCURICON_OBJECT CurIcon;
243
244 /* Run through the list of icon objects */
245 while (Win32Process->pCursorCache)
246 {
247 CurIcon = Win32Process->pCursorCache;
248 Win32Process->pCursorCache = CurIcon->pcurNext;
249 UserDereferenceObject(CurIcon);
250 }
251 }
252
253 /*
254 * @implemented
255 */
256 BOOL
257 APIENTRY
258 NtUserGetIconInfo(
259 _In_ HANDLE hCurIcon,
260 _Out_opt_ PICONINFO IconInfo,
261 _Out_opt_ PUNICODE_STRING lpModule, // Optional
262 _Out_opt_ PUNICODE_STRING lpResName, // Optional
263 _Out_opt_ LPDWORD pbpp, // Optional
264 _In_ BOOL bInternal)
265 {
266 ICONINFO ii;
267 PCURICON_OBJECT CurIcon;
268 NTSTATUS Status = STATUS_SUCCESS;
269 BOOL Ret = FALSE;
270 DWORD colorBpp = 0;
271
272 TRACE("Enter NtUserGetIconInfo\n");
273
274 /* Check if something was actually asked */
275 if (!IconInfo && !lpModule && !lpResName)
276 {
277 WARN("Nothing to fill.\n");
278 EngSetLastError(ERROR_INVALID_PARAMETER);
279 return FALSE;
280 }
281
282 UserEnterExclusive();
283
284 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
285 {
286 WARN("UserGetIconObject(0x%08x) Failed.\n", hCurIcon);
287 UserLeave();
288 return FALSE;
289 }
290
291 /* Give back the icon information */
292 if(IconInfo)
293 {
294 PCURICON_OBJECT FrameCurIcon = CurIcon;
295 if(CurIcon->CURSORF_flags & CURSORF_ACON)
296 {
297 /* Get information from first frame. */
298 FrameCurIcon = ((PACON)CurIcon)->aspcur[0];
299 }
300
301 /* Fill data */
302 ii.fIcon = is_icon(FrameCurIcon);
303 ii.xHotspot = FrameCurIcon->xHotspot;
304 ii.yHotspot = FrameCurIcon->yHotspot;
305
306 /* Copy bitmaps */
307 ii.hbmMask = BITMAP_CopyBitmap(FrameCurIcon->hbmMask);
308 GreSetObjectOwner(ii.hbmMask, GDI_OBJ_HMGR_POWNED);
309 ii.hbmColor = BITMAP_CopyBitmap(FrameCurIcon->hbmColor);
310 GreSetObjectOwner(ii.hbmColor, GDI_OBJ_HMGR_POWNED);
311 colorBpp = FrameCurIcon->bpp;
312
313 /* Copy fields */
314 _SEH2_TRY
315 {
316 ProbeForWrite(IconInfo, sizeof(ICONINFO), 1);
317 RtlCopyMemory(IconInfo, &ii, sizeof(ICONINFO));
318
319 if (pbpp)
320 {
321 ProbeForWrite(pbpp, sizeof(DWORD), 1);
322 *pbpp = colorBpp;
323 }
324 }
325 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
326 {
327 Status = _SEH2_GetExceptionCode();
328 }
329 _SEH2_END
330
331 if (!NT_SUCCESS(Status))
332 {
333 WARN("Status: 0x%08x.\n", Status);
334 SetLastNtError(Status);
335 goto leave;
336 }
337 }
338
339 /* Give back the module name */
340 if(lpModule)
341 {
342 ULONG BufLen = 0;
343 if (!CurIcon->atomModName)
344 goto leave;
345
346 RtlQueryAtomInAtomTable(gAtomTable, CurIcon->atomModName, NULL, NULL, NULL, &BufLen);
347 /* Get the module name from the atom table */
348 _SEH2_TRY
349 {
350 if (BufLen > (lpModule->MaximumLength * sizeof(WCHAR)))
351 {
352 lpModule->Length = 0;
353 }
354 else
355 {
356 ProbeForWrite(lpModule->Buffer, lpModule->MaximumLength, 1);
357 BufLen = lpModule->MaximumLength * sizeof(WCHAR);
358 RtlQueryAtomInAtomTable(gAtomTable, CurIcon->atomModName, NULL, NULL, lpModule->Buffer, &BufLen);
359 lpModule->Length = BufLen/sizeof(WCHAR);
360 }
361 }
362 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
363 {
364 Status = _SEH2_GetExceptionCode();
365 }
366 _SEH2_END
367
368 if (!NT_SUCCESS(Status))
369 {
370 SetLastNtError(Status);
371 goto leave;
372 }
373 }
374
375 if (lpResName)
376 {
377 if (!CurIcon->strName.Buffer)
378 goto leave;
379
380 /* Copy it */
381 _SEH2_TRY
382 {
383 ProbeForWrite(lpResName, sizeof(UNICODE_STRING), 1);
384 if (IS_INTRESOURCE(CurIcon->strName.Buffer))
385 {
386 lpResName->Buffer = CurIcon->strName.Buffer;
387 lpResName->Length = 0;
388 }
389 else if (lpResName->MaximumLength < CurIcon->strName.Length)
390 {
391 lpResName->Length = 0;
392 }
393 else
394 {
395 ProbeForWrite(lpResName->Buffer, lpResName->MaximumLength * sizeof(WCHAR), 1);
396 RtlCopyMemory(lpResName->Buffer, CurIcon->strName.Buffer, lpResName->Length);
397 }
398 }
399 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
400 {
401 Status = _SEH2_GetExceptionCode();
402 }
403 _SEH2_END
404 }
405
406 if (!NT_SUCCESS(Status))
407 {
408 SetLastNtError(Status);
409 goto leave;
410 }
411
412 Ret = TRUE;
413
414 leave:
415 UserDereferenceObject(CurIcon);
416
417 TRACE("Leave NtUserGetIconInfo, ret=%i\n", Ret);
418 UserLeave();
419
420 return Ret;
421 }
422
423
424 /*
425 * @implemented
426 */
427 BOOL
428 APIENTRY
429 NtUserGetIconSize(
430 HANDLE hCurIcon,
431 UINT istepIfAniCur,
432 PLONG plcx, // &size.cx
433 PLONG plcy) // &size.cy
434 {
435 PCURICON_OBJECT CurIcon;
436 NTSTATUS Status = STATUS_SUCCESS;
437 BOOL bRet = FALSE;
438
439 TRACE("Enter NtUserGetIconSize\n");
440 UserEnterExclusive();
441
442 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
443 {
444 goto cleanup;
445 }
446
447 if(CurIcon->CURSORF_flags & CURSORF_ACON)
448 {
449 /* Use first frame for animated cursors */
450 PACON AniCurIcon = (PACON)CurIcon;
451 CurIcon = AniCurIcon->aspcur[0];
452 UserDereferenceObject(AniCurIcon);
453 UserReferenceObject(CurIcon);
454 }
455
456 _SEH2_TRY
457 {
458 ProbeForWrite(plcx, sizeof(LONG), 1);
459 *plcx = CurIcon->cx;
460 ProbeForWrite(plcy, sizeof(LONG), 1);
461 *plcy = CurIcon->cy;
462 }
463 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
464 {
465 Status = _SEH2_GetExceptionCode();
466 }
467 _SEH2_END
468
469 if (NT_SUCCESS(Status))
470 bRet = TRUE;
471 else
472 SetLastNtError(Status); // Maybe not, test this
473
474 UserDereferenceObject(CurIcon);
475
476 cleanup:
477 TRACE("Leave NtUserGetIconSize, ret=%i\n", bRet);
478 UserLeave();
479 return bRet;
480 }
481
482
483 /*
484 * @implemented
485 */
486 BOOL
487 APIENTRY
488 NtUserGetCursorInfo(
489 PCURSORINFO pci)
490 {
491 CURSORINFO SafeCi;
492 PSYSTEM_CURSORINFO CurInfo;
493 NTSTATUS Status = STATUS_SUCCESS;
494 PCURICON_OBJECT CurIcon;
495 BOOL Ret = FALSE;
496 DECLARE_RETURN(BOOL);
497
498 TRACE("Enter NtUserGetCursorInfo\n");
499 UserEnterExclusive();
500
501 CurInfo = IntGetSysCursorInfo();
502 CurIcon = (PCURICON_OBJECT)CurInfo->CurrentCursorObject;
503
504 SafeCi.cbSize = sizeof(CURSORINFO);
505 SafeCi.flags = ((CurIcon && CurInfo->ShowingCursor >= 0) ? CURSOR_SHOWING : 0);
506 SafeCi.hCursor = (CurIcon ? CurIcon->head.h : NULL);
507
508 SafeCi.ptScreenPos = gpsi->ptCursor;
509
510 _SEH2_TRY
511 {
512 if (pci->cbSize == sizeof(CURSORINFO))
513 {
514 ProbeForWrite(pci, sizeof(CURSORINFO), 1);
515 RtlCopyMemory(pci, &SafeCi, sizeof(CURSORINFO));
516 Ret = TRUE;
517 }
518 else
519 {
520 EngSetLastError(ERROR_INVALID_PARAMETER);
521 }
522 }
523 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
524 {
525 Status = _SEH2_GetExceptionCode();
526 }
527 _SEH2_END;
528 if (!NT_SUCCESS(Status))
529 {
530 SetLastNtError(Status);
531 }
532
533 RETURN(Ret);
534
535 CLEANUP:
536 TRACE("Leave NtUserGetCursorInfo, ret=%i\n",_ret_);
537 UserLeave();
538 END_CLEANUP;
539 }
540
541 BOOL
542 APIENTRY
543 UserClipCursor(
544 RECTL *prcl)
545 {
546 /* FIXME: Check if process has WINSTA_WRITEATTRIBUTES */
547 PSYSTEM_CURSORINFO CurInfo;
548 PWND DesktopWindow = NULL;
549
550 CurInfo = IntGetSysCursorInfo();
551
552 DesktopWindow = UserGetDesktopWindow();
553
554 if (prcl != NULL && DesktopWindow != NULL)
555 {
556 if (prcl->right < prcl->left || prcl->bottom < prcl->top)
557 {
558 EngSetLastError(ERROR_INVALID_PARAMETER);
559 return FALSE;
560 }
561
562 CurInfo->bClipped = TRUE;
563
564 /* Set nw cliping region. Note: we can't use RECTL_bIntersectRect because
565 it sets rect to 0 0 0 0 when it's empty. For more info see monitor winetest */
566 CurInfo->rcClip.left = max(prcl->left, DesktopWindow->rcWindow.left);
567 CurInfo->rcClip.right = min(prcl->right, DesktopWindow->rcWindow.right);
568 if (CurInfo->rcClip.right < CurInfo->rcClip.left)
569 CurInfo->rcClip.right = CurInfo->rcClip.left;
570
571 CurInfo->rcClip.top = max(prcl->top, DesktopWindow->rcWindow.top);
572 CurInfo->rcClip.bottom = min(prcl->bottom, DesktopWindow->rcWindow.bottom);
573 if (CurInfo->rcClip.bottom < CurInfo->rcClip.top)
574 CurInfo->rcClip.bottom = CurInfo->rcClip.top;
575
576 /* Make sure cursor is in clipping region */
577 UserSetCursorPos(gpsi->ptCursor.x, gpsi->ptCursor.y, 0, 0, FALSE);
578 }
579 else
580 {
581 CurInfo->bClipped = FALSE;
582 }
583
584 return TRUE;
585 }
586
587 /*
588 * @implemented
589 */
590 BOOL
591 APIENTRY
592 NtUserClipCursor(
593 RECTL *prcl)
594 {
595 RECTL rclLocal;
596 BOOL bResult;
597
598 if (prcl)
599 {
600 _SEH2_TRY
601 {
602 /* Probe and copy rect */
603 ProbeForRead(prcl, sizeof(RECTL), 1);
604 rclLocal = *prcl;
605 }
606 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
607 {
608 EngSetLastError(ERROR_INVALID_PARAMETER);
609 _SEH2_YIELD(return FALSE;)
610 }
611 _SEH2_END
612
613 prcl = &rclLocal;
614 }
615
616 UserEnterExclusive();
617
618 /* Call the internal function */
619 bResult = UserClipCursor(prcl);
620
621 UserLeave();
622
623 return bResult;
624 }
625
626
627 /*
628 * @implemented
629 */
630 BOOL
631 APIENTRY
632 NtUserDestroyCursor(
633 _In_ HANDLE hCurIcon,
634 _In_ BOOL bForce)
635 {
636 BOOL ret;
637
638 TRACE("Enter NtUserDestroyCursorIcon\n");
639 UserEnterExclusive();
640
641 if (!bForce)
642 {
643 /* Maybe we have good reasons not to destroy this object */
644 PCURICON_OBJECT CurIcon = UserGetCurIconObject(hCurIcon);
645 ULONG Flags;
646 if (!CurIcon)
647 {
648 ret = FALSE;
649 goto leave;
650 }
651
652 if (CurIcon->head.ppi != PsGetCurrentProcessWin32Process())
653 {
654 /* No way, you're not touching my cursor */
655 ret = FALSE;
656 UserDereferenceObject(CurIcon);
657 goto leave;
658 }
659
660 Flags = CurIcon->CURSORF_flags;
661 UserDereferenceObject(CurIcon);
662
663 if (Flags & CURSORF_CURRENT)
664 {
665 WARN("Trying to delete current cursor!\n");
666 ret = FALSE;
667 goto leave;
668 }
669
670 if (Flags & CURSORF_LRSHARED)
671 {
672 WARN("Trying to delete shared cursor.\n");
673 /* This one is not an error */
674 ret = TRUE;
675 goto leave;
676 }
677 }
678
679 /* Destroy the handle */
680 ret = UserDeleteObject(hCurIcon, TYPE_CURSOR);
681
682 leave:
683 TRACE("Leave NtUserDestroyCursorIcon, ret=%i\n", ret);
684 UserLeave();
685 return ret;
686 }
687
688
689 /*
690 * @implemented
691 */
692 HICON
693 NTAPI
694 NtUserFindExistingCursorIcon(
695 _In_ PUNICODE_STRING pustrModule,
696 _In_ PUNICODE_STRING pustrRsrc,
697 _In_ FINDEXISTINGCURICONPARAM* param)
698 {
699 PCURICON_OBJECT CurIcon;
700 HICON Ret = NULL;
701 UNICODE_STRING ustrModuleSafe, ustrRsrcSafe;
702 FINDEXISTINGCURICONPARAM paramSafe;
703 NTSTATUS Status;
704 PPROCESSINFO pProcInfo = PsGetCurrentProcessWin32Process();
705 RTL_ATOM atomModName;
706
707 TRACE("Enter NtUserFindExistingCursorIcon\n");
708
709
710 _SEH2_TRY
711 {
712 ProbeForRead(param, sizeof(*param), 1);
713 RtlCopyMemory(&paramSafe, param, sizeof(paramSafe));
714 }
715 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
716 {
717 Status = _SEH2_GetExceptionCode();
718 }
719 _SEH2_END
720
721 /* Capture resource name (it can be an INTRESOURCE == ATOM) */
722 Status = ProbeAndCaptureUnicodeStringOrAtom(&ustrRsrcSafe, pustrRsrc);
723 if(!NT_SUCCESS(Status))
724 return NULL;
725 Status = ProbeAndCaptureUnicodeString(&ustrModuleSafe, UserMode, pustrModule);
726 if(!NT_SUCCESS(Status))
727 goto done;
728 Status = RtlLookupAtomInAtomTable(gAtomTable, ustrModuleSafe.Buffer, &atomModName);
729 ReleaseCapturedUnicodeString(&ustrModuleSafe, UserMode);
730 if(!NT_SUCCESS(Status))
731 {
732 /* The module is not in the atom table. No chance to find the cursor */
733 goto done;
734 }
735
736 UserEnterExclusive();
737 CurIcon = pProcInfo->pCursorCache;
738 while(CurIcon)
739 {
740 /* Icon/cursor */
741 if (paramSafe.bIcon != is_icon(CurIcon))
742 {
743 CurIcon = CurIcon->pcurNext;
744 continue;
745 }
746 /* See if module names match */
747 if (atomModName == CurIcon->atomModName)
748 {
749 /* They do. Now see if this is the same resource */
750 if (IS_INTRESOURCE(CurIcon->strName.Buffer) != IS_INTRESOURCE(ustrRsrcSafe.Buffer))
751 {
752 /* One is an INT resource and the other is not -> no match */
753 CurIcon = CurIcon->pcurNext;
754 continue;
755 }
756
757 if (IS_INTRESOURCE(CurIcon->strName.Buffer))
758 {
759 if (CurIcon->strName.Buffer == ustrRsrcSafe.Buffer)
760 {
761 /* INT resources match */
762 break;
763 }
764 }
765 else if (RtlCompareUnicodeString(&ustrRsrcSafe, &CurIcon->strName, TRUE) == 0)
766 {
767 /* Resource name strings match */
768 break;
769 }
770 }
771 CurIcon = CurIcon->pcurNext;
772 }
773 if(CurIcon)
774 Ret = CurIcon->head.h;
775 UserLeave();
776
777 done:
778 if(!IS_INTRESOURCE(ustrRsrcSafe.Buffer))
779 ExFreePoolWithTag(ustrRsrcSafe.Buffer, TAG_STRING);
780
781 return Ret;
782 }
783
784
785 /*
786 * @implemented
787 */
788 BOOL
789 APIENTRY
790 NtUserGetClipCursor(
791 RECTL *lpRect)
792 {
793 /* FIXME: Check if process has WINSTA_READATTRIBUTES */
794 PSYSTEM_CURSORINFO CurInfo;
795 RECTL Rect;
796 NTSTATUS Status;
797 DECLARE_RETURN(BOOL);
798
799 TRACE("Enter NtUserGetClipCursor\n");
800 UserEnterExclusive();
801
802 if (!lpRect)
803 RETURN(FALSE);
804
805 CurInfo = IntGetSysCursorInfo();
806 if (CurInfo->bClipped)
807 {
808 Rect = CurInfo->rcClip;
809 }
810 else
811 {
812 Rect.left = 0;
813 Rect.top = 0;
814 Rect.right = UserGetSystemMetrics(SM_CXSCREEN);
815 Rect.bottom = UserGetSystemMetrics(SM_CYSCREEN);
816 }
817
818 Status = MmCopyToCaller(lpRect, &Rect, sizeof(RECT));
819 if (!NT_SUCCESS(Status))
820 {
821 SetLastNtError(Status);
822 RETURN(FALSE);
823 }
824
825 RETURN(TRUE);
826
827 CLEANUP:
828 TRACE("Leave NtUserGetClipCursor, ret=%i\n",_ret_);
829 UserLeave();
830 END_CLEANUP;
831 }
832
833
834 /*
835 * @implemented
836 */
837 HCURSOR
838 APIENTRY
839 NtUserSetCursor(
840 HCURSOR hCursor)
841 {
842 PCURICON_OBJECT pcurOld, pcurNew;
843 HCURSOR hOldCursor = NULL;
844
845 TRACE("Enter NtUserSetCursor\n");
846 UserEnterExclusive();
847
848 if (hCursor)
849 {
850 pcurNew = UserGetCurIconObject(hCursor);
851 if (!pcurNew)
852 {
853 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE);
854 goto leave;
855 }
856 pcurNew->CURSORF_flags |= CURSORF_CURRENT;
857 }
858 else
859 {
860 pcurNew = NULL;
861 }
862
863 pcurOld = UserSetCursor(pcurNew, FALSE);
864 if (pcurOld)
865 {
866 pcurOld->CURSORF_flags &= ~CURSORF_CURRENT;
867 UserDereferenceObject(pcurOld);
868 }
869
870 leave:
871 UserLeave();
872 return hOldCursor;
873 }
874
875
876 /*
877 * @unimplemented
878 */
879 BOOL
880 APIENTRY
881 NtUserSetCursorContents(
882 HANDLE hCurIcon,
883 PICONINFO UnsafeIconInfo)
884 {
885 FIXME(" is UNIMPLEMENTED.\n");
886 return FALSE;
887 }
888
889
890 /*
891 * @implemented
892 */
893 BOOL
894 APIENTRY
895 NtUserSetCursorIconData(
896 _In_ HCURSOR Handle,
897 _In_opt_ PUNICODE_STRING pustrModule,
898 _In_opt_ PUNICODE_STRING pustrRsrc,
899 _In_ const CURSORDATA* pCursorData)
900 {
901 PCURICON_OBJECT CurIcon;
902 NTSTATUS Status = STATUS_SUCCESS;
903 BOOLEAN Ret = FALSE;
904 BOOLEAN IsShared = FALSE, IsAnim = FALSE;
905 DWORD numFrames;
906 UINT i = 0;
907
908 TRACE("Enter NtUserSetCursorIconData\n");
909
910 UserEnterExclusive();
911
912 if (!(CurIcon = UserGetCurIconObject(Handle)))
913 {
914 UserLeave();
915 EngSetLastError(ERROR_INVALID_HANDLE);
916 return FALSE;
917 }
918
919 _SEH2_TRY
920 {
921 ProbeForRead(pCursorData, sizeof(*pCursorData), 1);
922 if(pCursorData->CURSORF_flags & CURSORF_ACON)
923 {
924 /* This is an animated cursor */
925 PACON AniCurIcon = (PACON)CurIcon;
926 DWORD numSteps;
927
928 numFrames = AniCurIcon->cpcur = pCursorData->cpcur;
929 numSteps = AniCurIcon->cicur = pCursorData->cicur;
930 AniCurIcon->iicur = pCursorData->iicur;
931 AniCurIcon->rt = pCursorData->rt;
932
933 /* Calculate size: one cursor object for each frame, and a frame index and jiffies for each "step" */
934 AniCurIcon->aspcur = ExAllocatePoolWithTag(PagedPool | POOL_RAISE_IF_ALLOCATION_FAILURE, /* Let SEH catch allocation failures */
935 numFrames * sizeof(CURICON_OBJECT*) + numSteps * (sizeof(DWORD) + sizeof(INT)),
936 USERTAG_CURSOR);
937 AniCurIcon->aicur = (DWORD*)(AniCurIcon->aspcur + numFrames);
938 AniCurIcon->ajifRate = (INT*)(AniCurIcon->aicur + numSteps);
939
940 RtlZeroMemory(AniCurIcon->aspcur, numFrames * sizeof(CURICON_OBJECT*));
941
942 ProbeForRead(pCursorData->aicur, numSteps * sizeof(DWORD), 1);
943 RtlCopyMemory(AniCurIcon->aicur, pCursorData->aicur, numSteps * sizeof(DWORD));
944 ProbeForRead(pCursorData->ajifRate, numSteps * sizeof(INT), 1);
945 RtlCopyMemory(AniCurIcon->ajifRate, pCursorData->ajifRate, numSteps * sizeof(INT));
946
947 AniCurIcon->CURSORF_flags = pCursorData->CURSORF_flags;
948 pCursorData = pCursorData->aspcur;
949
950 IsAnim = TRUE;
951 }
952 else
953 {
954 CurIcon->xHotspot = pCursorData->xHotspot;
955 CurIcon->yHotspot = pCursorData->yHotspot;
956 CurIcon->cx = pCursorData->cx;
957 CurIcon->cy = pCursorData->cy;
958 CurIcon->rt = pCursorData->rt;
959 CurIcon->bpp = pCursorData->bpp;
960 CurIcon->hbmMask = pCursorData->hbmMask;
961 CurIcon->hbmColor = pCursorData->hbmColor;
962 CurIcon->hbmAlpha = pCursorData->hbmAlpha;
963 CurIcon->CURSORF_flags = pCursorData->CURSORF_flags;
964 }
965 }
966 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
967 {
968 Status = _SEH2_GetExceptionCode();
969 }
970 _SEH2_END
971
972 if (!NT_SUCCESS(Status))
973 {
974 SetLastNtError(Status);
975 goto done;
976 }
977
978 if(IsAnim)
979 {
980 PACON AniCurIcon = (PACON)CurIcon;
981 /* This is an animated cursor. Create a cursor object for each frame and set up the data */
982 for(i = 0; i < numFrames; i++)
983 {
984 HANDLE hCurFrame = IntCreateCurIconHandle(FALSE);
985 if(!NtUserSetCursorIconData(hCurFrame, NULL, NULL, pCursorData))
986 goto done;
987 AniCurIcon->aspcur[i] = UserGetCurIconObject(hCurFrame);
988 if(!AniCurIcon->aspcur[i])
989 goto done;
990 pCursorData++;
991 }
992 }
993
994 if(CurIcon->CURSORF_flags & CURSORF_LRSHARED)
995 {
996 IsShared = TRUE;
997 if(pustrRsrc && pustrModule)
998 {
999 UNICODE_STRING ustrModuleSafe;
1000 /* We use this convenient function, because INTRESOURCEs and ATOMs are the same */
1001 Status = ProbeAndCaptureUnicodeStringOrAtom(&CurIcon->strName, pustrRsrc);
1002 if(!NT_SUCCESS(Status))
1003 goto done;
1004 Status = ProbeAndCaptureUnicodeString(&ustrModuleSafe, UserMode, pustrModule);
1005 if(!NT_SUCCESS(Status))
1006 goto done;
1007 Status = RtlAddAtomToAtomTable(gAtomTable, ustrModuleSafe.Buffer, &CurIcon->atomModName);
1008 ReleaseCapturedUnicodeString(&ustrModuleSafe, UserMode);
1009 if(!NT_SUCCESS(Status))
1010 goto done;
1011 }
1012 }
1013
1014 if(!CurIcon->hbmMask)
1015 {
1016 ERR("NtUserSetCursorIconData was got no hbmMask.\n");
1017 EngSetLastError(ERROR_INVALID_PARAMETER);
1018 goto done;
1019 }
1020
1021 GreSetObjectOwner(CurIcon->hbmMask, GDI_OBJ_HMGR_PUBLIC);
1022
1023 if(CurIcon->hbmColor)
1024 GreSetObjectOwner(CurIcon->hbmColor, GDI_OBJ_HMGR_PUBLIC);
1025
1026 if(CurIcon->hbmAlpha)
1027 GreSetObjectOwner(CurIcon->hbmAlpha, GDI_OBJ_HMGR_PUBLIC);
1028
1029 if(IsShared)
1030 {
1031 /* Update process cache in case of shared cursor */
1032 PPROCESSINFO ppi = CurIcon->head.ppi;
1033 UserReferenceObject(CurIcon);
1034 CurIcon->pcurNext = ppi->pCursorCache;
1035 ppi->pCursorCache = CurIcon;
1036 }
1037
1038 Ret = TRUE;
1039
1040 done:
1041 if(!Ret && IsShared)
1042 {
1043 if(!IS_INTRESOURCE(CurIcon->strName.Buffer))
1044 ExFreePoolWithTag(CurIcon->strName.Buffer, TAG_STRING);
1045 }
1046
1047 if(!Ret && IsAnim)
1048 {
1049 PACON AniCurIcon = (PACON)CurIcon;
1050 for(i = 0; i < numFrames; i++)
1051 {
1052 if(AniCurIcon->aspcur[i])
1053 IntDestroyCurIconObject(AniCurIcon->aspcur[i]);
1054 }
1055 AniCurIcon->cicur = 0;
1056 AniCurIcon->cpcur = 0;
1057 ExFreePoolWithTag(AniCurIcon->aspcur, USERTAG_CURSOR);
1058 AniCurIcon->aspcur = NULL;
1059 AniCurIcon->aicur = NULL;
1060 AniCurIcon->ajifRate = NULL;
1061 }
1062
1063 UserDereferenceObject(CurIcon);
1064 TRACE("Leave NtUserSetCursorIconData, ret=%i\n",Ret);
1065 UserLeave();
1066
1067 return Ret;
1068 }
1069
1070 /* Mostly inspired from wine code.
1071 * We use low level functions because:
1072 * - at this point, the icon bitmap could have a different bit depth than the DC,
1073 * making it thus impossible to use NtCreateCompatibleDC and selecting the bitmap.
1074 * This happens after a mode setting change.
1075 * - it avoids massive GDI objects locking when only the destination surface needs it.
1076 * - It makes (small) performance gains.
1077 */
1078 BOOL
1079 UserDrawIconEx(
1080 HDC hDc,
1081 INT xLeft,
1082 INT yTop,
1083 PCURICON_OBJECT pIcon,
1084 INT cxWidth,
1085 INT cyHeight,
1086 UINT istepIfAniCur,
1087 HBRUSH hbrFlickerFreeDraw,
1088 UINT diFlags)
1089 {
1090 PSURFACE psurfDest, psurfMask, psurfColor; //, psurfOffScreen = NULL;
1091 PDC pdc = NULL;
1092 BOOL Ret = FALSE;
1093 HBITMAP hbmMask, hbmColor, hbmAlpha;
1094 BOOL bOffScreen;
1095 RECTL rcDest, rcSrc;
1096 CLIPOBJ* pdcClipObj = NULL;
1097 EXLATEOBJ exlo;
1098
1099 /* Stupid case */
1100 if((diFlags & DI_NORMAL) == 0)
1101 {
1102 ERR("DrawIconEx called without mask or color bitmap to draw.\n");
1103 return FALSE;
1104 }
1105
1106 if (pIcon->CURSORF_flags & CURSORF_ACON)
1107 {
1108 ACON* pAcon = (ACON*)pIcon;
1109 if(istepIfAniCur >= pAcon->cicur)
1110 {
1111 ERR("NtUserDrawIconEx: istepIfAniCur too big!\n");
1112 return FALSE;
1113 }
1114 pIcon = pAcon->aspcur[pAcon->aicur[istepIfAniCur]];
1115 }
1116
1117 hbmMask = pIcon->hbmMask;
1118 hbmColor = pIcon->hbmColor;
1119 hbmAlpha = pIcon->hbmAlpha;
1120
1121 /*
1122 * Get our objects.
1123 * Shared locks are enough, we are only reading those bitmaps
1124 */
1125 psurfMask = SURFACE_ShareLockSurface(hbmMask);
1126 if(psurfMask == NULL)
1127 {
1128 ERR("Unable to lock the mask surface.\n");
1129 return FALSE;
1130 }
1131
1132 /* Color bitmap is not mandatory */
1133 if(hbmColor == NULL)
1134 {
1135 /* But then the mask bitmap must have the information in it's bottom half */
1136 ASSERT(psurfMask->SurfObj.sizlBitmap.cy == 2*pIcon->cy);
1137 psurfColor = NULL;
1138 }
1139 else if ((psurfColor = SURFACE_ShareLockSurface(hbmColor)) == NULL)
1140 {
1141 ERR("Unable to lock the color bitmap.\n");
1142 SURFACE_ShareUnlockSurface(psurfMask);
1143 return FALSE;
1144 }
1145
1146 pdc = DC_LockDc(hDc);
1147 if(!pdc)
1148 {
1149 ERR("Could not lock the destination DC.\n");
1150 SURFACE_ShareUnlockSurface(psurfMask);
1151 if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
1152 return FALSE;
1153 }
1154 /* Calculate destination rectangle */
1155 RECTL_vSetRect(&rcDest, xLeft, yTop, xLeft + cxWidth, yTop + cyHeight);
1156 IntLPtoDP(pdc, (LPPOINT)&rcDest, 2);
1157 RECTL_vOffsetRect(&rcDest, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y);
1158
1159 /* Prepare the underlying surface */
1160 DC_vPrepareDCsForBlit(pdc, &rcDest, NULL, NULL);
1161
1162 /* We now have our destination surface and rectangle */
1163 psurfDest = pdc->dclevel.pSurface;
1164
1165 if(psurfDest == NULL)
1166 {
1167 /* Empty DC */
1168 DC_vFinishBlit(pdc, NULL);
1169 DC_UnlockDc(pdc);
1170 SURFACE_ShareUnlockSurface(psurfMask);
1171 if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
1172 return FALSE;
1173 }
1174
1175 /* Set source rect */
1176 RECTL_vSetRect(&rcSrc, 0, 0, pIcon->cx, pIcon->cy);
1177
1178 /* Fix width parameter, if needed */
1179 if (!cxWidth)
1180 {
1181 if(diFlags & DI_DEFAULTSIZE)
1182 cxWidth = is_icon(pIcon) ?
1183 UserGetSystemMetrics(SM_CXICON) : UserGetSystemMetrics(SM_CXCURSOR);
1184 else
1185 cxWidth = pIcon->cx;
1186 }
1187
1188 /* Fix height parameter, if needed */
1189 if (!cyHeight)
1190 {
1191 if(diFlags & DI_DEFAULTSIZE)
1192 cyHeight = is_icon(pIcon) ?
1193 UserGetSystemMetrics(SM_CYICON) : UserGetSystemMetrics(SM_CYCURSOR);
1194 else
1195 cyHeight = pIcon->cy;
1196 }
1197
1198 /* Should we render off-screen? */
1199 bOffScreen = hbrFlickerFreeDraw &&
1200 (GDI_HANDLE_GET_TYPE(hbrFlickerFreeDraw) == GDI_OBJECT_TYPE_BRUSH);
1201
1202 if (bOffScreen)
1203 {
1204 /* Yes: Allocate and paint the offscreen surface */
1205 EBRUSHOBJ eboFill;
1206 PBRUSH pbrush = BRUSH_ShareLockBrush(hbrFlickerFreeDraw);
1207
1208 TRACE("Performing off-screen rendering.\n");
1209
1210 if(!pbrush)
1211 {
1212 ERR("Failed to get brush object.\n");
1213 goto Cleanup;
1214 }
1215
1216 #if 0 //We lock the hdc surface during the whole function it makes no sense to use an offscreen surface for "flicker free" drawing
1217 psurfOffScreen = SURFACE_AllocSurface(STYPE_BITMAP,
1218 cxWidth, cyHeight, psurfDest->SurfObj.iBitmapFormat,
1219 0, 0, NULL);
1220 if(!psurfOffScreen)
1221 {
1222 ERR("Failed to allocate the off-screen surface.\n");
1223 BRUSH_ShareUnlockBrush(pbrush);
1224 goto Cleanup;
1225 }
1226
1227 /* Paint the brush */
1228 EBRUSHOBJ_vInit(&eboFill, pbrush, psurfOffScreen, 0x00FFFFFF, 0, NULL);
1229 RECTL_vSetRect(&rcDest, 0, 0, cxWidth, cyHeight);
1230
1231 Ret = IntEngBitBlt(&psurfOffScreen->SurfObj,
1232 NULL,
1233 NULL,
1234 NULL,
1235 NULL,
1236 &rcDest,
1237 NULL,
1238 NULL,
1239 &eboFill.BrushObject,
1240 &pbrush->ptOrigin,
1241 ROP4_PATCOPY);
1242
1243 /* Clean up everything */
1244 EBRUSHOBJ_vCleanup(&eboFill);
1245 BRUSH_ShareUnlockBrush(pbrush);
1246
1247 if(!Ret)
1248 {
1249 ERR("Failed to paint the off-screen surface.\n");
1250 goto Cleanup;
1251 }
1252
1253 /* We now have our destination surface */
1254 psurfDest = psurfOffScreen;
1255 #else
1256 pdcClipObj = &pdc->co.ClipObj;
1257 /* Paint the brush */
1258 EBRUSHOBJ_vInit(&eboFill, pbrush, psurfDest, 0x00FFFFFF, 0, NULL);
1259
1260 Ret = IntEngBitBlt(&psurfDest->SurfObj,
1261 NULL,
1262 NULL,
1263 pdcClipObj,
1264 NULL,
1265 &rcDest,
1266 NULL,
1267 NULL,
1268 &eboFill.BrushObject,
1269 &pbrush->ptOrigin,
1270 ROP4_PATCOPY);
1271
1272 /* Clean up everything */
1273 EBRUSHOBJ_vCleanup(&eboFill);
1274 BRUSH_ShareUnlockBrush(pbrush);
1275
1276 if(!Ret)
1277 {
1278 ERR("Failed to paint the off-screen surface.\n");
1279 goto Cleanup;
1280 }
1281 #endif
1282 }
1283 else
1284 {
1285 /* We directly draw to the DC */
1286 TRACE("Performing on screen rendering.\n");
1287 pdcClipObj = &pdc->co.ClipObj;
1288 // psurfOffScreen = NULL;
1289 }
1290
1291 /* Now do the rendering */
1292 if(hbmAlpha && ((diFlags & DI_NORMAL) == DI_NORMAL))
1293 {
1294 BLENDOBJ blendobj = { {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA } };
1295 PSURFACE psurf = NULL;
1296
1297 psurf = SURFACE_ShareLockSurface(hbmAlpha);
1298 if(!psurf)
1299 {
1300 ERR("SURFACE_LockSurface failed!\n");
1301 goto NoAlpha;
1302 }
1303
1304 /* Initialize color translation object */
1305 EXLATEOBJ_vInitialize(&exlo, psurf->ppal, psurfDest->ppal, 0xFFFFFFFF, 0xFFFFFFFF, 0);
1306
1307 /* Now do it */
1308 Ret = IntEngAlphaBlend(&psurfDest->SurfObj,
1309 &psurf->SurfObj,
1310 pdcClipObj,
1311 &exlo.xlo,
1312 &rcDest,
1313 &rcSrc,
1314 &blendobj);
1315
1316 EXLATEOBJ_vCleanup(&exlo);
1317 SURFACE_ShareUnlockSurface(psurf);
1318 if(Ret) goto done;
1319 ERR("NtGdiAlphaBlend failed!\n");
1320 }
1321 NoAlpha:
1322 if (diFlags & DI_MASK)
1323 {
1324 DWORD rop4 = (diFlags & DI_IMAGE) ? ROP4_SRCAND : ROP4_SRCCOPY;
1325
1326 EXLATEOBJ_vInitSrcMonoXlate(&exlo, psurfDest->ppal, 0x00FFFFFF, 0);
1327
1328 Ret = IntEngStretchBlt(&psurfDest->SurfObj,
1329 &psurfMask->SurfObj,
1330 NULL,
1331 pdcClipObj,
1332 &exlo.xlo,
1333 NULL,
1334 &rcDest,
1335 &rcSrc,
1336 NULL,
1337 NULL,
1338 NULL,
1339 rop4);
1340
1341 EXLATEOBJ_vCleanup(&exlo);
1342
1343 if(!Ret)
1344 {
1345 ERR("Failed to mask the bitmap data.\n");
1346 goto Cleanup;
1347 }
1348 }
1349
1350 if(diFlags & DI_IMAGE)
1351 {
1352 if (psurfColor)
1353 {
1354 DWORD rop4 = (diFlags & DI_MASK) ? ROP4_SRCINVERT : ROP4_SRCCOPY ;
1355
1356 EXLATEOBJ_vInitialize(&exlo, psurfColor->ppal, psurfDest->ppal, 0x00FFFFFF, 0x00FFFFFF, 0);
1357
1358 Ret = IntEngStretchBlt(&psurfDest->SurfObj,
1359 &psurfColor->SurfObj,
1360 NULL,
1361 pdcClipObj,
1362 &exlo.xlo,
1363 NULL,
1364 &rcDest,
1365 &rcSrc,
1366 NULL,
1367 NULL,
1368 NULL,
1369 rop4);
1370
1371 EXLATEOBJ_vCleanup(&exlo);
1372
1373 if(!Ret)
1374 {
1375 ERR("Failed to render the icon bitmap.\n");
1376 goto Cleanup;
1377 }
1378 }
1379 else
1380 {
1381 /* Mask bitmap holds the information in its bottom half */
1382 DWORD rop4 = (diFlags & DI_MASK) ? ROP4_SRCINVERT : ROP4_SRCCOPY;
1383 RECTL_vOffsetRect(&rcSrc, 0, pIcon->cy);
1384
1385 EXLATEOBJ_vInitSrcMonoXlate(&exlo, psurfDest->ppal, 0x00FFFFFF, 0);
1386
1387 Ret = IntEngStretchBlt(&psurfDest->SurfObj,
1388 &psurfMask->SurfObj,
1389 NULL,
1390 pdcClipObj,
1391 &exlo.xlo,
1392 NULL,
1393 &rcDest,
1394 &rcSrc,
1395 NULL,
1396 NULL,
1397 NULL,
1398 rop4);
1399
1400 EXLATEOBJ_vCleanup(&exlo);
1401
1402 if(!Ret)
1403 {
1404 ERR("Failed to render the icon bitmap.\n");
1405 goto Cleanup;
1406 }
1407 }
1408 }
1409
1410 done:
1411 #if 0
1412 /* We're done. Was it a double buffered draw ? */
1413 if(bOffScreen)
1414 {
1415 /* Yes. Draw it back to our DC */
1416 POINTL ptSrc = {0, 0};
1417
1418 /* Calculate destination rectangle */
1419 RECTL_vSetRect(&rcDest, xLeft, yTop, xLeft + cxWidth, yTop + cyHeight);
1420 IntLPtoDP(pdc, (LPPOINT)&rcDest, 2);
1421 RECTL_vOffsetRect(&rcDest, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y);
1422
1423 /* Get the clip object */
1424 pdcClipObj = pdc->rosdc.CombinedClip;
1425
1426 /* We now have our destination surface and rectangle */
1427 psurfDest = pdc->dclevel.pSurface;
1428
1429 /* Color translation */
1430 EXLATEOBJ_vInitialize(&exlo, psurfOffScreen->ppal, psurfDest->ppal, 0x00FFFFFF, 0x00FFFFFF, 0);
1431
1432 /* Blt it! */
1433 Ret = IntEngBitBlt(&psurfDest->SurfObj,
1434 &psurfOffScreen->SurfObj,
1435 NULL,
1436 pdcClipObj,
1437 &exlo.xlo,
1438 &rcDest,
1439 &ptSrc,
1440 NULL,
1441 NULL,
1442 NULL,
1443 ROP4_SRCCOPY);
1444
1445 EXLATEOBJ_vCleanup(&exlo);
1446 }
1447 #endif
1448 Cleanup:
1449 if(pdc)
1450 {
1451 DC_vFinishBlit(pdc, NULL);
1452 DC_UnlockDc(pdc);
1453 }
1454
1455 #if 0
1456 /* Delete off screen rendering surface */
1457 if(psurfOffScreen)
1458 GDIOBJ_vDeleteObject(&psurfOffScreen->BaseObject);
1459 #endif
1460
1461 /* Unlock other surfaces */
1462 SURFACE_ShareUnlockSurface(psurfMask);
1463 if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
1464
1465 return Ret;
1466 }
1467
1468 /*
1469 * @implemented
1470 */
1471 BOOL
1472 APIENTRY
1473 NtUserDrawIconEx(
1474 HDC hdc,
1475 int xLeft,
1476 int yTop,
1477 HICON hIcon,
1478 int cxWidth,
1479 int cyHeight,
1480 UINT istepIfAniCur,
1481 HBRUSH hbrFlickerFreeDraw,
1482 UINT diFlags,
1483 BOOL bMetaHDC, // When TRUE, GDI functions need to be handled in User32!
1484 PVOID pDIXData)
1485 {
1486 PCURICON_OBJECT pIcon;
1487 BOOL Ret;
1488
1489 TRACE("Enter NtUserDrawIconEx\n");
1490 UserEnterExclusive();
1491
1492 if (!(pIcon = UserGetCurIconObject(hIcon)))
1493 {
1494 ERR("UserGetCurIconObject(0x%08x) failed!\n", hIcon);
1495 UserLeave();
1496 return FALSE;
1497 }
1498
1499 Ret = UserDrawIconEx(hdc,
1500 xLeft,
1501 yTop,
1502 pIcon,
1503 cxWidth,
1504 cyHeight,
1505 istepIfAniCur,
1506 hbrFlickerFreeDraw,
1507 diFlags);
1508
1509 UserDereferenceObject(pIcon);
1510
1511 UserLeave();
1512 return Ret;
1513 }
1514
1515 /*
1516 * @unimplemented
1517 */
1518 HCURSOR
1519 NTAPI
1520 NtUserGetCursorFrameInfo(
1521 HCURSOR hCursor,
1522 DWORD istep,
1523 INT* rate_jiffies,
1524 DWORD* num_steps)
1525 {
1526 PCURICON_OBJECT CurIcon;
1527 HCURSOR ret;
1528 INT jiffies = 0;
1529 DWORD steps = 1;
1530 NTSTATUS Status = STATUS_SUCCESS;
1531
1532 TRACE("Enter NtUserGetCursorFrameInfo\n");
1533 UserEnterExclusive();
1534
1535 if (!(CurIcon = UserGetCurIconObject(hCursor)))
1536 {
1537 UserLeave();
1538 return NULL;
1539 }
1540
1541 ret = CurIcon->head.h;
1542
1543 if(CurIcon->CURSORF_flags & CURSORF_ACON)
1544 {
1545 PACON AniCurIcon = (PACON)CurIcon;
1546 if(istep >= AniCurIcon->cicur)
1547 {
1548 UserDereferenceObject(CurIcon);
1549 UserLeave();
1550 return NULL;
1551 }
1552 jiffies = AniCurIcon->ajifRate[istep];
1553 steps = AniCurIcon->cicur;
1554 ret = AniCurIcon->aspcur[AniCurIcon->aicur[istep]]->head.h;
1555 }
1556
1557 _SEH2_TRY
1558 {
1559 ProbeForWrite(rate_jiffies, sizeof(INT), 1);
1560 ProbeForWrite(num_steps, sizeof(DWORD), 1);
1561 *rate_jiffies = jiffies;
1562 *num_steps = steps;
1563 }
1564 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1565 {
1566 Status = _SEH2_GetExceptionCode();
1567 }
1568 _SEH2_END
1569
1570 if (!NT_SUCCESS(Status))
1571 {
1572 WARN("Status: 0x%08x.\n", Status);
1573 SetLastNtError(Status);
1574 ret = NULL;
1575 }
1576
1577 UserDereferenceObject(CurIcon);
1578 UserLeave();
1579
1580 TRACE("Leaving NtUserGetCursorFrameInfo, ret = 0x%08x\n", ret);
1581
1582 return ret;
1583 }
1584
1585 /* EOF */