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