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