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