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