[Win32k]
[reactos.git] / reactos / 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 <w32k.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 FASTCALL
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 FASTCALL
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)
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 //Generate a mouse move message
228 Msg.message = WM_MOUSEMOVE;
229 Msg.wParam = CurInfo->ButtonsDown;
230 Msg.lParam = MAKELPARAM(x, y);
231 Msg.pt = gpsi->ptCursor;
232 MsqInsertSystemMessage(&Msg);
233
234 return TRUE;
235 }
236
237 /* Called from NtUserCallOneParam with Routine ONEPARAM_ROUTINE_SHOWCURSOR
238 * User32 macro NtUserShowCursor */
239 int UserShowCursor(BOOL bShow)
240 {
241 PSYSTEM_CURSORINFO CurInfo = IntGetSysCursorInfo();
242 HDC hdcScreen;
243
244 if (!(hdcScreen = IntGetScreenDC()))
245 {
246 return 0; /* No mouse */
247 }
248
249 if (bShow == FALSE)
250 {
251 /* Check if were diplaying a cursor */
252 if (CurInfo->ShowingCursor == 1)
253 {
254 /* Remove the pointer */
255 GreMovePointer(hdcScreen, -1, -1);
256 DPRINT("Removing pointer!\n");
257 }
258 CurInfo->ShowingCursor--;
259 }
260 else
261 {
262 if (CurInfo->ShowingCursor == 0)
263 {
264 /*Show the pointer*/
265 GreMovePointer(hdcScreen, gpsi->ptCursor.x, gpsi->ptCursor.y);
266 }
267 CurInfo->ShowingCursor++;
268 }
269
270 return CurInfo->ShowingCursor;
271 }
272
273 /*
274 * We have to register that this object is in use by the current
275 * process. The only way to do that seems to be to walk the list
276 * of cursor/icon objects starting at W32Process->CursorIconListHead.
277 * If the object is already present in the list, we don't have to do
278 * anything, if it's not present we add it and inc the ProcessCount
279 * in the object. Having to walk the list kind of sucks, but that's
280 * life...
281 */
282 static BOOLEAN FASTCALL
283 ReferenceCurIconByProcess(PCURICON_OBJECT CurIcon)
284 {
285 PPROCESSINFO Win32Process;
286 PCURICON_PROCESS Current;
287
288 Win32Process = PsGetCurrentProcessWin32Process();
289
290 LIST_FOR_EACH(Current, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
291 {
292 if (Current->Process == Win32Process)
293 {
294 /* Already registered for this process */
295 return TRUE;
296 }
297 }
298
299 /* Not registered yet */
300 Current = ExAllocateFromPagedLookasideList(&gProcessLookasideList);
301 if (NULL == Current)
302 {
303 return FALSE;
304 }
305 InsertHeadList(&CurIcon->ProcessList, &Current->ListEntry);
306 Current->Process = Win32Process;
307
308 return TRUE;
309 }
310
311 PCURICON_OBJECT FASTCALL
312 IntFindExistingCurIconObject(HMODULE hModule,
313 HRSRC hRsrc, LONG cx, LONG cy)
314 {
315 PCURICON_OBJECT CurIcon;
316
317 LIST_FOR_EACH(CurIcon, &gCurIconList, CURICON_OBJECT, ListEntry)
318 {
319
320 // if(NT_SUCCESS(UserReferenceObjectByPointer(Object, otCursorIcon))) //<- huh????
321 // UserReferenceObject( CurIcon);
322 // {
323 if ((CurIcon->hModule == hModule) && (CurIcon->hRsrc == hRsrc))
324 {
325 if (cx && ((cx != CurIcon->Size.cx) || (cy != CurIcon->Size.cy)))
326 {
327 // UserDereferenceObject(CurIcon);
328 continue;
329 }
330 if (! ReferenceCurIconByProcess(CurIcon))
331 {
332 return NULL;
333 }
334
335 return CurIcon;
336 }
337 // }
338 // UserDereferenceObject(CurIcon);
339
340 }
341
342 return NULL;
343 }
344
345 PCURICON_OBJECT FASTCALL
346 IntCreateCurIconHandle()
347 {
348 PCURICON_OBJECT CurIcon;
349 HANDLE hCurIcon;
350
351 CurIcon = UserCreateObject(gHandleTable, NULL, &hCurIcon, otCursorIcon, sizeof(CURICON_OBJECT));
352
353 if (!CurIcon)
354 {
355 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
356 return FALSE;
357 }
358
359 CurIcon->Self = hCurIcon;
360 InitializeListHead(&CurIcon->ProcessList);
361
362 if (! ReferenceCurIconByProcess(CurIcon))
363 {
364 DPRINT1("Failed to add process\n");
365 UserDeleteObject(hCurIcon, otCursorIcon);
366 UserDereferenceObject(CurIcon);
367 return NULL;
368 }
369
370 InsertHeadList(&gCurIconList, &CurIcon->ListEntry);
371
372 return CurIcon;
373 }
374
375 BOOLEAN FASTCALL
376 IntDestroyCurIconObject(PCURICON_OBJECT CurIcon, BOOL ProcessCleanup)
377 {
378 PSYSTEM_CURSORINFO CurInfo;
379 HBITMAP bmpMask, bmpColor;
380 BOOLEAN Ret;
381 PCURICON_PROCESS Current = NULL;
382 PPROCESSINFO W32Process = PsGetCurrentProcessWin32Process();
383
384 /* Private objects can only be destroyed by their own process */
385 if (NULL == CurIcon->hModule)
386 {
387 ASSERT(CurIcon->ProcessList.Flink->Flink == &CurIcon->ProcessList);
388 Current = CONTAINING_RECORD(CurIcon->ProcessList.Flink, CURICON_PROCESS, ListEntry);
389 if (Current->Process != W32Process)
390 {
391 DPRINT1("Trying to destroy private icon/cursor of another process\n");
392 return FALSE;
393 }
394 }
395 else if (! ProcessCleanup)
396 {
397 DPRINT("Trying to destroy shared icon/cursor\n");
398 return FALSE;
399 }
400
401 /* Now find this process in the list of processes referencing this object and
402 remove it from that list */
403 LIST_FOR_EACH(Current, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
404 {
405 if (Current->Process == W32Process)
406 {
407 RemoveEntryList(&Current->ListEntry);
408 break;
409 }
410 }
411
412 ExFreeToPagedLookasideList(&gProcessLookasideList, Current);
413
414 /* If there are still processes referencing this object we can't destroy it yet */
415 if (! IsListEmpty(&CurIcon->ProcessList))
416 {
417 return TRUE;
418 }
419
420
421 if (! ProcessCleanup)
422 {
423 RemoveEntryList(&CurIcon->ListEntry);
424 }
425
426 CurInfo = IntGetSysCursorInfo();
427
428 if (CurInfo->CurrentCursorObject == CurIcon)
429 {
430 /* Hide the cursor if we're destroying the current cursor */
431 UserSetCursor(NULL, TRUE);
432 }
433
434 bmpMask = CurIcon->IconInfo.hbmMask;
435 bmpColor = CurIcon->IconInfo.hbmColor;
436
437 /* delete bitmaps */
438 if (bmpMask)
439 {
440 GDIOBJ_SetOwnership(bmpMask, PsGetCurrentProcess());
441 GreDeleteObject(bmpMask);
442 CurIcon->IconInfo.hbmMask = NULL;
443 }
444 if (bmpColor)
445 {
446 GDIOBJ_SetOwnership(bmpColor, PsGetCurrentProcess());
447 GreDeleteObject(bmpColor);
448 CurIcon->IconInfo.hbmColor = NULL;
449 }
450
451 /* We were given a pointer, no need to keep the reference anylonger! */
452 UserDereferenceObject(CurIcon);
453 Ret = UserDeleteObject(CurIcon->Self, otCursorIcon);
454
455 return Ret;
456 }
457
458 VOID FASTCALL
459 IntCleanupCurIcons(struct _EPROCESS *Process, PPROCESSINFO Win32Process)
460 {
461 PCURICON_OBJECT CurIcon, tmp;
462 PCURICON_PROCESS ProcessData;
463
464 LIST_FOR_EACH_SAFE(CurIcon, tmp, &gCurIconList, CURICON_OBJECT, ListEntry)
465 {
466 UserReferenceObject(CurIcon);
467 // if(NT_SUCCESS(UserReferenceObjectByPointer(Object, otCursorIcon)))
468 {
469 LIST_FOR_EACH(ProcessData, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
470 {
471 if (Win32Process == ProcessData->Process)
472 {
473 RemoveEntryList(&CurIcon->ListEntry);
474 IntDestroyCurIconObject(CurIcon, TRUE);
475 CurIcon = NULL;
476 break;
477 }
478 }
479
480 // UserDereferenceObject(Object);
481 }
482
483 if (CurIcon)
484 {
485 UserDereferenceObject(CurIcon);
486 }
487 }
488
489 }
490
491 /*
492 * @implemented
493 */
494 HANDLE
495 APIENTRY
496 NtUserCreateCursorIconHandle(PICONINFO IconInfo OPTIONAL, BOOL Indirect)
497 {
498 PCURICON_OBJECT CurIcon;
499 PSURFACE psurfBmp;
500 NTSTATUS Status;
501 HANDLE Ret;
502 DECLARE_RETURN(HANDLE);
503
504 DPRINT("Enter NtUserCreateCursorIconHandle\n");
505 UserEnterExclusive();
506
507 if (!(CurIcon = IntCreateCurIconHandle()))
508 {
509 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
510 RETURN((HANDLE)0);
511 }
512
513 Ret = CurIcon->Self;
514
515 if (IconInfo)
516 {
517 Status = MmCopyFromCaller(&CurIcon->IconInfo, IconInfo, sizeof(ICONINFO));
518 if (NT_SUCCESS(Status))
519 {
520 /* Copy bitmaps and size info */
521 if (Indirect)
522 {
523 // FIXME: WTF?
524 CurIcon->IconInfo.hbmMask = BITMAP_CopyBitmap(CurIcon->IconInfo.hbmMask);
525 CurIcon->IconInfo.hbmColor = BITMAP_CopyBitmap(CurIcon->IconInfo.hbmColor);
526 }
527 if (CurIcon->IconInfo.hbmColor &&
528 (psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmColor)))
529 {
530 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
531 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
532 SURFACE_UnlockSurface(psurfBmp);
533 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmColor, NULL);
534 }
535 if (CurIcon->IconInfo.hbmMask &&
536 (psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmMask)))
537 {
538 if (CurIcon->IconInfo.hbmColor == NULL)
539 {
540 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
541 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy >> 1;
542 }
543 SURFACE_UnlockSurface(psurfBmp);
544 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmMask, NULL);
545 }
546
547 /* Calculate icon hotspot */
548 if (CurIcon->IconInfo.fIcon == TRUE)
549 {
550 CurIcon->IconInfo.xHotspot = CurIcon->Size.cx >> 1;
551 CurIcon->IconInfo.yHotspot = CurIcon->Size.cy >> 1;
552 }
553 }
554 else
555 {
556 SetLastNtError(Status);
557 /* FIXME - Don't exit here */
558 }
559 }
560
561 UserDereferenceObject(CurIcon);
562 RETURN(Ret);
563
564 CLEANUP:
565 DPRINT("Leave NtUserCreateCursorIconHandle, ret=%i\n",_ret_);
566 UserLeave();
567 END_CLEANUP;
568 }
569
570 /*
571 * @implemented
572 */
573 BOOL
574 APIENTRY
575 NtUserGetIconInfo(
576 HANDLE hCurIcon,
577 PICONINFO IconInfo,
578 PUNICODE_STRING lpInstName, // optional
579 PUNICODE_STRING lpResName, // optional
580 LPDWORD pbpp, // optional
581 BOOL bInternal)
582 {
583 ICONINFO ii;
584 PCURICON_OBJECT CurIcon;
585 NTSTATUS Status = STATUS_SUCCESS;
586 BOOL Ret = FALSE;
587 DWORD colorBpp = 0;
588
589 DPRINT("Enter NtUserGetIconInfo\n");
590 UserEnterExclusive();
591
592 if (!IconInfo)
593 {
594 SetLastWin32Error(ERROR_INVALID_PARAMETER);
595 goto leave;
596 }
597
598 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
599 {
600 goto leave;
601 }
602
603 RtlCopyMemory(&ii, &CurIcon->IconInfo, sizeof(ICONINFO));
604
605 /* Copy bitmaps */
606 ii.hbmMask = BITMAP_CopyBitmap(CurIcon->IconInfo.hbmMask);
607 ii.hbmColor = BITMAP_CopyBitmap(CurIcon->IconInfo.hbmColor);
608
609 if (pbpp)
610 {
611 PSURFACE psurfBmp;
612
613 psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmColor);
614 if (psurfBmp)
615 {
616 colorBpp = BitsPerFormat(psurfBmp->SurfObj.iBitmapFormat);
617 SURFACE_UnlockSurface(psurfBmp);
618 }
619 }
620
621 /* Copy fields */
622 _SEH2_TRY
623 {
624 ProbeForWrite(IconInfo, sizeof(ICONINFO), 1);
625 RtlCopyMemory(IconInfo, &ii, sizeof(ICONINFO));
626
627 if (pbpp)
628 {
629 ProbeForWrite(pbpp, sizeof(DWORD), 1);
630 *pbpp = colorBpp;
631 }
632 }
633 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
634 {
635 Status = _SEH2_GetExceptionCode();
636 }
637 _SEH2_END
638
639 if (NT_SUCCESS(Status))
640 Ret = TRUE;
641 else
642 SetLastNtError(Status);
643
644 UserDereferenceObject(CurIcon);
645
646 leave:
647 DPRINT("Leave NtUserGetIconInfo, ret=%i\n", Ret);
648 UserLeave();
649
650 return Ret;
651 }
652
653
654 /*
655 * @implemented
656 */
657 BOOL
658 APIENTRY
659 NtUserGetIconSize(
660 HANDLE hCurIcon,
661 UINT istepIfAniCur,
662 PLONG plcx, // &size.cx
663 PLONG plcy) // &size.cy
664 {
665 PCURICON_OBJECT CurIcon;
666 NTSTATUS Status = STATUS_SUCCESS;
667 BOOL bRet = FALSE;
668
669 DPRINT("Enter NtUserGetIconSize\n");
670 UserEnterExclusive();
671
672 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
673 {
674 goto cleanup;
675 }
676
677 _SEH2_TRY
678 {
679 ProbeForWrite(plcx, sizeof(LONG), 1);
680 RtlCopyMemory(plcx, &CurIcon->Size.cx, sizeof(LONG));
681 ProbeForWrite(plcy, sizeof(LONG), 1);
682 RtlCopyMemory(plcy, &CurIcon->Size.cy, sizeof(LONG));
683 }
684 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
685 {
686 Status = _SEH2_GetExceptionCode();
687 }
688 _SEH2_END
689
690 if (NT_SUCCESS(Status))
691 bRet = TRUE;
692 else
693 SetLastNtError(Status); // maybe not, test this
694
695 UserDereferenceObject(CurIcon);
696
697 cleanup:
698 DPRINT("Leave NtUserGetIconSize, ret=%i\n", bRet);
699 UserLeave();
700 return bRet;
701 }
702
703
704 /*
705 * @unimplemented
706 */
707 DWORD
708 APIENTRY
709 NtUserGetCursorFrameInfo(
710 DWORD Unknown0,
711 DWORD Unknown1,
712 DWORD Unknown2,
713 DWORD Unknown3)
714 {
715 UNIMPLEMENTED
716
717 return 0;
718 }
719
720
721 /*
722 * @implemented
723 */
724 BOOL
725 APIENTRY
726 NtUserGetCursorInfo(
727 PCURSORINFO pci)
728 {
729 CURSORINFO SafeCi;
730 PSYSTEM_CURSORINFO CurInfo;
731 NTSTATUS Status = STATUS_SUCCESS;
732 PCURICON_OBJECT CurIcon;
733 BOOL Ret = FALSE;
734 DECLARE_RETURN(BOOL);
735
736 DPRINT("Enter NtUserGetCursorInfo\n");
737 UserEnterExclusive();
738
739 CurInfo = IntGetSysCursorInfo();
740 CurIcon = (PCURICON_OBJECT)CurInfo->CurrentCursorObject;
741
742 SafeCi.cbSize = sizeof(CURSORINFO);
743 SafeCi.flags = ((CurInfo->ShowingCursor && CurIcon) ? CURSOR_SHOWING : 0);
744 SafeCi.hCursor = (CurIcon ? (HCURSOR)CurIcon->Self : (HCURSOR)0);
745
746 SafeCi.ptScreenPos = gpsi->ptCursor;
747
748 _SEH2_TRY
749 {
750 if (pci->cbSize == sizeof(CURSORINFO))
751 {
752 ProbeForWrite(pci, sizeof(CURSORINFO), 1);
753 RtlCopyMemory(pci, &SafeCi, sizeof(CURSORINFO));
754 Ret = TRUE;
755 }
756 else
757 {
758 SetLastWin32Error(ERROR_INVALID_PARAMETER);
759 }
760 }
761 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
762 {
763 Status = _SEH2_GetExceptionCode();
764 }
765 _SEH2_END;
766 if (!NT_SUCCESS(Status))
767 {
768 SetLastNtError(Status);
769 }
770
771 RETURN(Ret);
772
773 CLEANUP:
774 DPRINT("Leave NtUserGetCursorInfo, ret=%i\n",_ret_);
775 UserLeave();
776 END_CLEANUP;
777 }
778
779
780 /*
781 * @implemented
782 */
783 BOOL
784 APIENTRY
785 NtUserClipCursor(
786 RECTL *UnsafeRect)
787 {
788 /* FIXME - check if process has WINSTA_WRITEATTRIBUTES */
789 PSYSTEM_CURSORINFO CurInfo;
790 RECTL Rect;
791 PWINDOW_OBJECT DesktopWindow = NULL;
792 DECLARE_RETURN(BOOL);
793
794 DPRINT("Enter NtUserClipCursor\n");
795 UserEnterExclusive();
796
797 if (NULL != UnsafeRect && ! NT_SUCCESS(MmCopyFromCaller(&Rect, UnsafeRect, sizeof(RECT))))
798 {
799 SetLastWin32Error(ERROR_INVALID_PARAMETER);
800 RETURN(FALSE);
801 }
802
803 CurInfo = IntGetSysCursorInfo();
804
805 DesktopWindow = UserGetDesktopWindow();
806
807 if ((Rect.right > Rect.left) && (Rect.bottom > Rect.top)
808 && DesktopWindow && UnsafeRect != NULL)
809 {
810
811 CurInfo->CursorClipInfo.IsClipped = TRUE;
812 CurInfo->CursorClipInfo.Left = max(Rect.left, DesktopWindow->Wnd->rcWindow.left);
813 CurInfo->CursorClipInfo.Top = max(Rect.top, DesktopWindow->Wnd->rcWindow.top);
814 CurInfo->CursorClipInfo.Right = min(Rect.right, DesktopWindow->Wnd->rcWindow.right);
815 CurInfo->CursorClipInfo.Bottom = min(Rect.bottom, DesktopWindow->Wnd->rcWindow.bottom);
816
817 UserSetCursorPos(gpsi->ptCursor.x, gpsi->ptCursor.y);
818
819 RETURN(TRUE);
820 }
821
822 CurInfo->CursorClipInfo.IsClipped = FALSE;
823 RETURN(TRUE);
824
825 CLEANUP:
826 DPRINT("Leave NtUserClipCursor, ret=%i\n",_ret_);
827 UserLeave();
828 END_CLEANUP;
829 }
830
831
832 /*
833 * @implemented
834 */
835 BOOL
836 APIENTRY
837 NtUserDestroyCursor(
838 HANDLE hCurIcon,
839 DWORD Unknown)
840 {
841 PCURICON_OBJECT CurIcon;
842 BOOL ret;
843 DECLARE_RETURN(BOOL);
844
845 DPRINT("Enter NtUserDestroyCursorIcon\n");
846 UserEnterExclusive();
847
848 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
849 {
850 RETURN(FALSE);
851 }
852
853 ret = IntDestroyCurIconObject(CurIcon, FALSE);
854 /* Note: IntDestroyCurIconObject will remove our reference for us! */
855
856 RETURN(ret);
857
858 CLEANUP:
859 DPRINT("Leave NtUserDestroyCursorIcon, ret=%i\n",_ret_);
860 UserLeave();
861 END_CLEANUP;
862 }
863
864
865 /*
866 * @implemented
867 */
868 HICON
869 APIENTRY
870 NtUserFindExistingCursorIcon(
871 HMODULE hModule,
872 HRSRC hRsrc,
873 LONG cx,
874 LONG cy)
875 {
876 PCURICON_OBJECT CurIcon;
877 HANDLE Ret = (HANDLE)0;
878 DECLARE_RETURN(HICON);
879
880 DPRINT("Enter NtUserFindExistingCursorIcon\n");
881 UserEnterExclusive();
882
883 CurIcon = IntFindExistingCurIconObject(hModule, hRsrc, cx, cy);
884 if (CurIcon)
885 {
886 Ret = CurIcon->Self;
887
888 // IntReleaseCurIconObject(CurIcon);//faxme: is this correct? does IntFindExistingCurIconObject add a ref?
889 RETURN(Ret);
890 }
891
892 SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
893 RETURN((HANDLE)0);
894
895 CLEANUP:
896 DPRINT("Leave NtUserFindExistingCursorIcon, ret=%i\n",_ret_);
897 UserLeave();
898 END_CLEANUP;
899 }
900
901
902 /*
903 * @implemented
904 */
905 BOOL
906 APIENTRY
907 NtUserGetClipCursor(
908 RECTL *lpRect)
909 {
910 /* FIXME - check if process has WINSTA_READATTRIBUTES */
911 PSYSTEM_CURSORINFO CurInfo;
912 RECTL Rect;
913 NTSTATUS Status;
914 DECLARE_RETURN(BOOL);
915
916 DPRINT("Enter NtUserGetClipCursor\n");
917 UserEnterExclusive();
918
919 if (!lpRect)
920 RETURN(FALSE);
921
922 CurInfo = IntGetSysCursorInfo();
923 if (CurInfo->CursorClipInfo.IsClipped)
924 {
925 Rect.left = CurInfo->CursorClipInfo.Left;
926 Rect.top = CurInfo->CursorClipInfo.Top;
927 Rect.right = CurInfo->CursorClipInfo.Right;
928 Rect.bottom = CurInfo->CursorClipInfo.Bottom;
929 }
930 else
931 {
932 Rect.left = 0;
933 Rect.top = 0;
934 Rect.right = UserGetSystemMetrics(SM_CXSCREEN);
935 Rect.bottom = UserGetSystemMetrics(SM_CYSCREEN);
936 }
937
938 Status = MmCopyToCaller(lpRect, &Rect, sizeof(RECT));
939 if (!NT_SUCCESS(Status))
940 {
941 SetLastNtError(Status);
942 RETURN(FALSE);
943 }
944
945 RETURN(TRUE);
946
947 CLEANUP:
948 DPRINT("Leave NtUserGetClipCursor, ret=%i\n",_ret_);
949 UserLeave();
950 END_CLEANUP;
951 }
952
953
954 /*
955 * @implemented
956 */
957 HCURSOR
958 APIENTRY
959 NtUserSetCursor(
960 HCURSOR hCursor)
961 {
962 PCURICON_OBJECT CurIcon;
963 HICON OldCursor;
964 DECLARE_RETURN(HCURSOR);
965
966 DPRINT("Enter NtUserSetCursor\n");
967 UserEnterExclusive();
968
969 if (hCursor)
970 {
971 if (!(CurIcon = UserGetCurIconObject(hCursor)))
972 {
973 RETURN(NULL);
974 }
975 }
976 else
977 {
978 CurIcon = NULL;
979 }
980
981 OldCursor = UserSetCursor(CurIcon, FALSE);
982
983 if (CurIcon)
984 {
985 UserDereferenceObject(CurIcon);
986 }
987
988 RETURN(OldCursor);
989
990 CLEANUP:
991 DPRINT("Leave NtUserSetCursor, ret=%i\n",_ret_);
992 UserLeave();
993 END_CLEANUP;
994 }
995
996
997 /*
998 * @implemented
999 */
1000 BOOL
1001 APIENTRY
1002 NtUserSetCursorContents(
1003 HANDLE hCurIcon,
1004 PICONINFO UnsafeIconInfo)
1005 {
1006 PCURICON_OBJECT CurIcon;
1007 ICONINFO IconInfo;
1008 PSURFACE psurfBmp;
1009 NTSTATUS Status;
1010 BOOL Ret = FALSE;
1011 DECLARE_RETURN(BOOL);
1012
1013 DPRINT("Enter NtUserSetCursorContents\n");
1014 UserEnterExclusive();
1015
1016 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
1017 {
1018 RETURN(FALSE);
1019 }
1020
1021 /* Copy fields */
1022 Status = MmCopyFromCaller(&IconInfo, UnsafeIconInfo, sizeof(ICONINFO));
1023 if (!NT_SUCCESS(Status))
1024 {
1025 SetLastNtError(Status);
1026 goto done;
1027 }
1028
1029 /* Delete old bitmaps */
1030 if (CurIcon->IconInfo.hbmColor != IconInfo.hbmColor)
1031 {
1032 GreDeleteObject(CurIcon->IconInfo.hbmColor);
1033 }
1034 if (CurIcon->IconInfo.hbmMask != IconInfo.hbmMask)
1035 {
1036 GreDeleteObject(CurIcon->IconInfo.hbmMask);
1037 }
1038
1039 /* Copy new IconInfo field */
1040 CurIcon->IconInfo = IconInfo;
1041
1042 psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmColor);
1043 if (psurfBmp)
1044 {
1045 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
1046 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
1047 SURFACE_UnlockSurface(psurfBmp);
1048 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmColor, NULL);
1049 }
1050 else
1051 {
1052 psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmMask);
1053 if (!psurfBmp)
1054 goto done;
1055
1056 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
1057 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy / 2;
1058
1059 SURFACE_UnlockSurface(psurfBmp);
1060 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmMask, NULL);
1061 }
1062
1063 Ret = TRUE;
1064
1065 done:
1066
1067 if (CurIcon)
1068 {
1069 UserDereferenceObject(CurIcon);
1070 }
1071 RETURN(Ret);
1072
1073 CLEANUP:
1074 DPRINT("Leave NtUserSetCursorContents, ret=%i\n",_ret_);
1075 UserLeave();
1076 END_CLEANUP;
1077 }
1078
1079
1080 /*
1081 * @implemented
1082 */
1083 #if 0
1084 BOOL
1085 APIENTRY
1086 NtUserSetCursorIconData(
1087 HANDLE Handle,
1088 HMODULE hModule,
1089 PUNICODE_STRING pstrResName,
1090 PICONINFO pIconInfo)
1091 {
1092 PCURICON_OBJECT CurIcon;
1093 PSURFACE psurfBmp;
1094 NTSTATUS Status = STATUS_SUCCESS;
1095 BOOL Ret = FALSE;
1096 DECLARE_RETURN(BOOL);
1097
1098 DPRINT("Enter NtUserSetCursorIconData\n");
1099 UserEnterExclusive();
1100
1101 if (!(CurIcon = UserGetCurIconObject(Handle)))
1102 {
1103 RETURN(FALSE);
1104 }
1105
1106 CurIcon->hModule = hModule;
1107 CurIcon->hRsrc = NULL; //hRsrc;
1108 CurIcon->hGroupRsrc = NULL; //hGroupRsrc;
1109
1110 _SEH2_TRY
1111 {
1112 ProbeForRead(pIconInfo, sizeof(ICONINFO), 1);
1113 RtlCopyMemory(&CurIcon->IconInfo, pIconInfo, sizeof(ICONINFO));
1114
1115 CurIcon->IconInfo.hbmMask = BITMAP_CopyBitmap(pIconInfo->hbmMask);
1116 CurIcon->IconInfo.hbmColor = BITMAP_CopyBitmap(pIconInfo->hbmColor);
1117
1118 if (CurIcon->IconInfo.hbmColor)
1119 {
1120 if ((psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmColor)))
1121 {
1122 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
1123 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
1124 SURFACE_UnlockSurface(psurfBmp);
1125 GDIOBJ_SetOwnership(GdiHandleTable, CurIcon->IconInfo.hbmMask, NULL);
1126 }
1127 }
1128 if (CurIcon->IconInfo.hbmMask)
1129 {
1130 if (CurIcon->IconInfo.hbmColor == NULL)
1131 {
1132 if ((psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmMask)))
1133 {
1134 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
1135 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
1136 SURFACE_UnlockSurface(psurfBmp);
1137 }
1138 }
1139 GDIOBJ_SetOwnership(GdiHandleTable, CurIcon->IconInfo.hbmMask, NULL);
1140 }
1141 }
1142 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1143 {
1144 Status = _SEH2_GetExceptionCode();
1145 }
1146 _SEH2_END
1147
1148 if (!NT_SUCCESS(Status))
1149 SetLastNtError(Status);
1150 else
1151 Ret = TRUE;
1152
1153 UserDereferenceObject(CurIcon);
1154 RETURN(Ret);
1155
1156 CLEANUP:
1157 DPRINT("Leave NtUserSetCursorIconData, ret=%i\n",_ret_);
1158 UserLeave();
1159 END_CLEANUP;
1160 }
1161 #else
1162 BOOL
1163 APIENTRY
1164 NtUserSetCursorIconData(
1165 HANDLE hCurIcon,
1166 PBOOL fIcon,
1167 POINT *Hotspot,
1168 HMODULE hModule,
1169 HRSRC hRsrc,
1170 HRSRC hGroupRsrc)
1171 {
1172 PCURICON_OBJECT CurIcon;
1173 NTSTATUS Status;
1174 POINT SafeHotspot;
1175 BOOL Ret = FALSE;
1176 DECLARE_RETURN(BOOL);
1177
1178 DPRINT("Enter NtUserSetCursorIconData\n");
1179 UserEnterExclusive();
1180
1181 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
1182 {
1183 RETURN(FALSE);
1184 }
1185
1186 CurIcon->hModule = hModule;
1187 CurIcon->hRsrc = hRsrc;
1188 CurIcon->hGroupRsrc = hGroupRsrc;
1189
1190 /* Copy fields */
1191 if (fIcon)
1192 {
1193 Status = MmCopyFromCaller(&CurIcon->IconInfo.fIcon, fIcon, sizeof(BOOL));
1194 if (!NT_SUCCESS(Status))
1195 {
1196 SetLastNtError(Status);
1197 goto done;
1198 }
1199 }
1200 else
1201 {
1202 if (!Hotspot)
1203 Ret = TRUE;
1204 }
1205
1206 if (Hotspot)
1207 {
1208 Status = MmCopyFromCaller(&SafeHotspot, Hotspot, sizeof(POINT));
1209 if (NT_SUCCESS(Status))
1210 {
1211 CurIcon->IconInfo.xHotspot = SafeHotspot.x;
1212 CurIcon->IconInfo.yHotspot = SafeHotspot.y;
1213
1214 Ret = TRUE;
1215 }
1216 else
1217 SetLastNtError(Status);
1218 }
1219
1220 if (!fIcon && !Hotspot)
1221 {
1222 Ret = TRUE;
1223 }
1224
1225 done:
1226 UserDereferenceObject(CurIcon);
1227 RETURN(Ret);
1228
1229
1230 CLEANUP:
1231 DPRINT("Leave NtUserSetCursorIconData, ret=%i\n",_ret_);
1232 UserLeave();
1233 END_CLEANUP;
1234 }
1235 #endif
1236
1237 /*
1238 * @unimplemented
1239 */
1240 BOOL
1241 APIENTRY
1242 NtUserSetSystemCursor(
1243 HCURSOR hcur,
1244 DWORD id)
1245 {
1246 return FALSE;
1247 }
1248
1249 BOOL
1250 UserDrawIconEx(
1251 HDC hDc,
1252 INT xLeft,
1253 INT yTop,
1254 PCURICON_OBJECT pIcon,
1255 INT cxWidth,
1256 INT cyHeight,
1257 UINT istepIfAniCur,
1258 HBRUSH hbrFlickerFreeDraw,
1259 UINT diFlags)
1260 {
1261 BOOL Ret = FALSE;
1262 HBITMAP hbmMask, hbmColor;
1263 BITMAP bmpMask, bmpColor;
1264 BOOL DoFlickerFree;
1265 SIZE IconSize;
1266
1267 HDC hdcOff;
1268 HGDIOBJ hOldOffBrush = 0;
1269 HGDIOBJ hOldOffBmp = 0;
1270 HBITMAP hbmOff = 0;
1271 HDC hdcMask = 0;
1272 HGDIOBJ hOldMask = NULL;
1273 HDC hdcImage = 0;
1274 HGDIOBJ hOldImage = NULL;
1275 BOOL bAlpha = FALSE;
1276
1277 hbmMask = pIcon->IconInfo.hbmMask;
1278 hbmColor = pIcon->IconInfo.hbmColor;
1279
1280 if (istepIfAniCur)
1281 DPRINT1("NtUserDrawIconEx: istepIfAniCur is not supported!\n");
1282
1283 if (!hbmMask || !IntGdiGetObject(hbmMask, sizeof(BITMAP), (PVOID)&bmpMask))
1284 {
1285 return FALSE;
1286 }
1287
1288 if (hbmColor && !IntGdiGetObject(hbmColor, sizeof(BITMAP), (PVOID)&bmpColor))
1289 {
1290 return FALSE;
1291 }
1292
1293 if (hbmColor)
1294 {
1295 IconSize.cx = bmpColor.bmWidth;
1296 IconSize.cy = bmpColor.bmHeight;
1297 }
1298 else
1299 {
1300 IconSize.cx = bmpMask.bmWidth;
1301 IconSize.cy = bmpMask.bmHeight / 2;
1302 }
1303
1304 /* NtGdiCreateCompatibleBitmap will create a monochrome bitmap
1305 when cxWidth or cyHeight is 0 */
1306 if ((bmpColor.bmBitsPixel == 32) && (cxWidth != 0) && (cyHeight != 0))
1307 {
1308 SURFACE *psurfOff = NULL;
1309 PFN_DIB_GetPixel fnSource_GetPixel = NULL;
1310 INT x, y;
1311
1312 /* In order to correctly display 32 bit icons Windows first scans the image,
1313 because information about transparency is not stored in any image's headers */
1314 psurfOff = SURFACE_LockSurface(hbmColor ? hbmColor : hbmMask);
1315 if (psurfOff)
1316 {
1317 fnSource_GetPixel = DibFunctionsForBitmapFormat[psurfOff->SurfObj.iBitmapFormat].DIB_GetPixel;
1318 if (fnSource_GetPixel)
1319 {
1320 for (x = 0; x < psurfOff->SurfObj.sizlBitmap.cx; x++)
1321 {
1322 for (y = 0; y < psurfOff->SurfObj.sizlBitmap.cy; y++)
1323 {
1324 bAlpha = ((BYTE)(fnSource_GetPixel(&psurfOff->SurfObj, x, y) >> 24) & 0xff);
1325 if (bAlpha)
1326 break;
1327 }
1328 if (bAlpha)
1329 break;
1330 }
1331 }
1332 SURFACE_UnlockSurface(psurfOff);
1333 }
1334 }
1335
1336 if (!diFlags)
1337 diFlags = DI_NORMAL;
1338
1339 if (!cxWidth)
1340 cxWidth = ((diFlags & DI_DEFAULTSIZE) ?
1341 UserGetSystemMetrics(SM_CXICON) : IconSize.cx);
1342
1343 if (!cyHeight)
1344 cyHeight = ((diFlags & DI_DEFAULTSIZE) ?
1345 UserGetSystemMetrics(SM_CYICON) : IconSize.cy);
1346
1347 DoFlickerFree = (hbrFlickerFreeDraw &&
1348 (GDI_HANDLE_GET_TYPE(hbrFlickerFreeDraw) == GDI_OBJECT_TYPE_BRUSH));
1349
1350 if (DoFlickerFree || bAlpha)
1351 {
1352 RECTL r;
1353 BITMAP bm;
1354 SURFACE *psurfOff = NULL;
1355
1356 r.right = cxWidth;
1357 r.bottom = cyHeight;
1358
1359 hdcOff = NtGdiCreateCompatibleDC(hDc);
1360 if (!hdcOff)
1361 {
1362 DPRINT1("NtGdiCreateCompatibleDC() failed!\n");
1363 return FALSE;
1364 }
1365
1366 hbmOff = NtGdiCreateCompatibleBitmap(hDc, cxWidth, cyHeight);
1367 if (!hbmOff)
1368 {
1369 DPRINT1("NtGdiCreateCompatibleBitmap() failed!\n");
1370 goto cleanup;
1371 }
1372
1373 /* make sure we have a 32 bit offscreen bitmap
1374 otherwise we can't do alpha blending */
1375 psurfOff = SURFACE_LockSurface(hbmOff);
1376 if (psurfOff == NULL)
1377 {
1378 DPRINT1("BITMAPOBJ_LockBitmap() failed!\n");
1379 goto cleanup;
1380 }
1381 BITMAP_GetObject(psurfOff, sizeof(BITMAP), (PVOID)&bm);
1382
1383 if (bm.bmBitsPixel != 32)
1384 bAlpha = FALSE;
1385
1386 SURFACE_UnlockSurface(psurfOff);
1387
1388 hOldOffBmp = NtGdiSelectBitmap(hdcOff, hbmOff);
1389 if (!hOldOffBmp)
1390 {
1391 DPRINT1("NtGdiSelectBitmap() failed!\n");
1392 goto cleanup;
1393 }
1394
1395 if (DoFlickerFree)
1396 {
1397 hOldOffBrush = NtGdiSelectBrush(hdcOff, hbrFlickerFreeDraw);
1398 if (!hOldOffBrush)
1399 {
1400 DPRINT1("NtGdiSelectBrush() failed!\n");
1401 goto cleanup;
1402 }
1403
1404 NtGdiPatBlt(hdcOff, 0, 0, r.right, r.bottom, PATCOPY);
1405 }
1406 }
1407 else
1408 hdcOff = hDc;
1409
1410 if (diFlags & DI_IMAGE)
1411 {
1412 hdcImage = NtGdiCreateCompatibleDC(hDc);
1413 if (!hdcImage)
1414 {
1415 DPRINT1("NtGdiCreateCompatibleDC() failed!\n");
1416 goto cleanup;
1417 }
1418 hOldImage = NtGdiSelectBitmap(hdcImage, (hbmColor ? hbmColor : hbmMask));
1419 if (!hOldImage)
1420 {
1421 DPRINT("NtGdiSelectBitmap() failed!\n");
1422 goto cleanup;
1423 }
1424 }
1425
1426 /* If DI_IMAGE flag is specified and hbmMask exists, then always use mask for drawing */
1427 if (diFlags & DI_MASK || (diFlags & DI_IMAGE && hbmMask))
1428 {
1429 hdcMask = NtGdiCreateCompatibleDC(hDc);
1430 if (!hdcMask)
1431 {
1432 DPRINT1("NtGdiCreateCompatibleDC() failed!\n");
1433 goto cleanup;
1434 }
1435
1436 hOldMask = NtGdiSelectBitmap(hdcMask, hbmMask);
1437 if (!hOldMask)
1438 {
1439 DPRINT("NtGdiSelectBitmap() failed!\n");
1440 goto cleanup;
1441 }
1442 }
1443
1444 if (hdcMask || hdcImage)
1445 {
1446 GreStretchBltMask(hdcOff,
1447 (DoFlickerFree || bAlpha) ? 0 : xLeft,
1448 (DoFlickerFree || bAlpha) ? 0 : yTop,
1449 cxWidth,
1450 cyHeight,
1451 hdcImage ? hdcImage : hdcMask,
1452 0,
1453 0,
1454 IconSize.cx,
1455 IconSize.cy,
1456 SRCCOPY,
1457 0,
1458 hdcMask,
1459 0,
1460 hdcImage ? 0 : IconSize.cy);
1461 }
1462
1463 if (hOldMask) NtGdiSelectBitmap(hdcMask, hOldMask);
1464 if (hOldImage) NtGdiSelectBitmap(hdcImage, hOldImage);
1465 if (hdcImage) NtGdiDeleteObjectApp(hdcImage);
1466 if (hdcMask) NtGdiDeleteObjectApp(hdcMask);
1467
1468 if (bAlpha)
1469 {
1470 BITMAP bm;
1471 SURFACE *psurfOff = NULL;
1472 PBYTE pBits = NULL;
1473 BLENDFUNCTION BlendFunc;
1474 DWORD Pixel;
1475 BYTE Red, Green, Blue, Alpha;
1476 DWORD Count = 0;
1477 INT i, j;
1478
1479 psurfOff = SURFACE_LockSurface(hbmOff);
1480 if (psurfOff == NULL)
1481 {
1482 DPRINT1("BITMAPOBJ_LockBitmap() failed!\n");
1483 goto cleanup;
1484 }
1485 BITMAP_GetObject(psurfOff, sizeof(BITMAP), (PVOID)&bm);
1486
1487 pBits = ExAllocatePoolWithTag(PagedPool, bm.bmWidthBytes * abs(bm.bmHeight), TAG_BITMAP);
1488 if (pBits == NULL)
1489 {
1490 DPRINT1("ExAllocatePoolWithTag() failed!\n");
1491 SURFACE_UnlockSurface(psurfOff);
1492 goto cleanup;
1493 }
1494
1495 /* get icon bits */
1496 IntGetBitmapBits(psurfOff, bm.bmWidthBytes * abs(bm.bmHeight), pBits);
1497
1498 /* premultiply with the alpha channel value */
1499 for (i = 0; i < cyHeight; i++)
1500 {
1501 for (j = 0; j < cxWidth; j++)
1502 {
1503 Pixel = *(DWORD *)(pBits + Count);
1504
1505 Alpha = ((BYTE)(Pixel >> 24) & 0xff);
1506
1507 Red = (((BYTE)(Pixel >> 0)) * Alpha) / 0xff;
1508 Green = (((BYTE)(Pixel >> 8)) * Alpha) / 0xff;
1509 Blue = (((BYTE)(Pixel >> 16)) * Alpha) / 0xff;
1510
1511 *(DWORD *)(pBits + Count) = (DWORD)(Red | (Green << 8) | (Blue << 16) | (Alpha << 24));
1512
1513 Count += sizeof(DWORD);
1514 }
1515 }
1516
1517 /* set icon bits */
1518 IntSetBitmapBits(psurfOff, bm.bmWidthBytes * abs(bm.bmHeight), pBits);
1519 ExFreePoolWithTag(pBits, TAG_BITMAP);
1520
1521 SURFACE_UnlockSurface(psurfOff);
1522
1523 BlendFunc.BlendOp = AC_SRC_OVER;
1524 BlendFunc.BlendFlags = 0;
1525 BlendFunc.SourceConstantAlpha = 255;
1526 BlendFunc.AlphaFormat = AC_SRC_ALPHA;
1527
1528 NtGdiAlphaBlend(hDc, xLeft, yTop, cxWidth, cyHeight,
1529 hdcOff, 0, 0, cxWidth, cyHeight, BlendFunc, 0);
1530 }
1531 else if (DoFlickerFree)
1532 {
1533 NtGdiBitBlt(hDc, xLeft, yTop, cxWidth,
1534 cyHeight, hdcOff, 0, 0, SRCCOPY, 0, 0);
1535 }
1536
1537 Ret = TRUE;
1538
1539 cleanup:
1540 if (DoFlickerFree || bAlpha)
1541 {
1542 if (hOldOffBmp) NtGdiSelectBitmap(hdcOff, hOldOffBmp);
1543 if (hOldOffBrush) NtGdiSelectBrush(hdcOff, hOldOffBrush);
1544 if (hbmOff) GreDeleteObject(hbmOff);
1545 if (hdcOff) NtGdiDeleteObjectApp(hdcOff);
1546 }
1547
1548 return Ret;
1549 }
1550
1551 /*
1552 * @implemented
1553 */
1554 BOOL
1555 APIENTRY
1556 NtUserDrawIconEx(
1557 HDC hdc,
1558 int xLeft,
1559 int yTop,
1560 HICON hIcon,
1561 int cxWidth,
1562 int cyHeight,
1563 UINT istepIfAniCur,
1564 HBRUSH hbrFlickerFreeDraw,
1565 UINT diFlags,
1566 BOOL bMetaHDC, // When TRUE, GDI functions need to be handled in User32!
1567 PVOID pDIXData)
1568 {
1569 PCURICON_OBJECT pIcon;
1570 BOOL Ret;
1571
1572 DPRINT("Enter NtUserDrawIconEx\n");
1573 UserEnterExclusive();
1574
1575 if (!(pIcon = UserGetCurIconObject(hIcon)))
1576 {
1577 DPRINT1("UserGetCurIconObject() failed!\n");
1578 UserLeave();
1579 return FALSE;
1580 }
1581
1582 Ret = UserDrawIconEx(hdc,
1583 xLeft,
1584 yTop,
1585 pIcon,
1586 cxWidth,
1587 cyHeight,
1588 istepIfAniCur,
1589 hbrFlickerFreeDraw,
1590 diFlags);
1591
1592 UserDereferenceObject(pIcon);
1593
1594 UserLeave();
1595 return Ret;
1596 }
1597