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