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