Sync to trunk (r46918)
[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 <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 BOOL
780 APIENTRY
781 UserClipCursor(
782 RECTL *prcl)
783 {
784 /* FIXME - check if process has WINSTA_WRITEATTRIBUTES */
785 PSYSTEM_CURSORINFO CurInfo;
786 PWINDOW_OBJECT DesktopWindow = NULL;
787
788 CurInfo = IntGetSysCursorInfo();
789
790 DesktopWindow = UserGetDesktopWindow();
791
792 if (prcl != NULL &&
793 (prcl->right > prcl->left) &&
794 (prcl->bottom > prcl->top) &&
795 DesktopWindow != NULL)
796 {
797 CurInfo->CursorClipInfo.IsClipped = TRUE;
798 CurInfo->CursorClipInfo.Left = max(prcl->left, DesktopWindow->Wnd->rcWindow.left);
799 CurInfo->CursorClipInfo.Top = max(prcl->top, DesktopWindow->Wnd->rcWindow.top);
800 CurInfo->CursorClipInfo.Right = min(prcl->right, DesktopWindow->Wnd->rcWindow.right);
801 CurInfo->CursorClipInfo.Bottom = min(prcl->bottom, DesktopWindow->Wnd->rcWindow.bottom);
802
803 UserSetCursorPos(gpsi->ptCursor.x, gpsi->ptCursor.y);
804 }
805 else
806 {
807 CurInfo->CursorClipInfo.IsClipped = FALSE;
808 }
809
810 return TRUE;
811 }
812
813 /*
814 * @implemented
815 */
816 BOOL
817 APIENTRY
818 NtUserClipCursor(
819 RECTL *prcl)
820 {
821 /* FIXME - check if process has WINSTA_WRITEATTRIBUTES */
822 RECTL rclLocal;
823 BOOL bResult;
824
825 if (prcl)
826 {
827 _SEH2_TRY
828 {
829 /* Probe and copy rect */
830 ProbeForRead(prcl, sizeof(RECTL), 1);
831 rclLocal = *prcl;
832 }
833 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
834 {
835 SetLastWin32Error(ERROR_INVALID_PARAMETER);
836 _SEH2_YIELD(return FALSE;)
837 }
838 _SEH2_END
839
840 prcl = &rclLocal;
841 }
842
843 UserEnterExclusive();
844
845 /* Call the internal function */
846 bResult = UserClipCursor(prcl);
847
848 UserLeave();
849
850 return bResult;
851 }
852
853
854 /*
855 * @implemented
856 */
857 BOOL
858 APIENTRY
859 NtUserDestroyCursor(
860 HANDLE hCurIcon,
861 DWORD Unknown)
862 {
863 PCURICON_OBJECT CurIcon;
864 BOOL ret;
865 DECLARE_RETURN(BOOL);
866
867 DPRINT("Enter NtUserDestroyCursorIcon\n");
868 UserEnterExclusive();
869
870 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
871 {
872 RETURN(FALSE);
873 }
874
875 ret = IntDestroyCurIconObject(CurIcon, FALSE);
876 /* Note: IntDestroyCurIconObject will remove our reference for us! */
877
878 RETURN(ret);
879
880 CLEANUP:
881 DPRINT("Leave NtUserDestroyCursorIcon, ret=%i\n",_ret_);
882 UserLeave();
883 END_CLEANUP;
884 }
885
886
887 /*
888 * @implemented
889 */
890 HICON
891 APIENTRY
892 NtUserFindExistingCursorIcon(
893 HMODULE hModule,
894 HRSRC hRsrc,
895 LONG cx,
896 LONG cy)
897 {
898 PCURICON_OBJECT CurIcon;
899 HANDLE Ret = (HANDLE)0;
900 DECLARE_RETURN(HICON);
901
902 DPRINT("Enter NtUserFindExistingCursorIcon\n");
903 UserEnterExclusive();
904
905 CurIcon = IntFindExistingCurIconObject(hModule, hRsrc, cx, cy);
906 if (CurIcon)
907 {
908 Ret = CurIcon->Self;
909
910 // IntReleaseCurIconObject(CurIcon);//faxme: is this correct? does IntFindExistingCurIconObject add a ref?
911 RETURN(Ret);
912 }
913
914 SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
915 RETURN((HANDLE)0);
916
917 CLEANUP:
918 DPRINT("Leave NtUserFindExistingCursorIcon, ret=%i\n",_ret_);
919 UserLeave();
920 END_CLEANUP;
921 }
922
923
924 /*
925 * @implemented
926 */
927 BOOL
928 APIENTRY
929 NtUserGetClipCursor(
930 RECTL *lpRect)
931 {
932 /* FIXME - check if process has WINSTA_READATTRIBUTES */
933 PSYSTEM_CURSORINFO CurInfo;
934 RECTL Rect;
935 NTSTATUS Status;
936 DECLARE_RETURN(BOOL);
937
938 DPRINT("Enter NtUserGetClipCursor\n");
939 UserEnterExclusive();
940
941 if (!lpRect)
942 RETURN(FALSE);
943
944 CurInfo = IntGetSysCursorInfo();
945 if (CurInfo->CursorClipInfo.IsClipped)
946 {
947 Rect.left = CurInfo->CursorClipInfo.Left;
948 Rect.top = CurInfo->CursorClipInfo.Top;
949 Rect.right = CurInfo->CursorClipInfo.Right;
950 Rect.bottom = CurInfo->CursorClipInfo.Bottom;
951 }
952 else
953 {
954 Rect.left = 0;
955 Rect.top = 0;
956 Rect.right = UserGetSystemMetrics(SM_CXSCREEN);
957 Rect.bottom = UserGetSystemMetrics(SM_CYSCREEN);
958 }
959
960 Status = MmCopyToCaller(lpRect, &Rect, sizeof(RECT));
961 if (!NT_SUCCESS(Status))
962 {
963 SetLastNtError(Status);
964 RETURN(FALSE);
965 }
966
967 RETURN(TRUE);
968
969 CLEANUP:
970 DPRINT("Leave NtUserGetClipCursor, ret=%i\n",_ret_);
971 UserLeave();
972 END_CLEANUP;
973 }
974
975
976 /*
977 * @implemented
978 */
979 HCURSOR
980 APIENTRY
981 NtUserSetCursor(
982 HCURSOR hCursor)
983 {
984 PCURICON_OBJECT CurIcon;
985 HICON OldCursor;
986 DECLARE_RETURN(HCURSOR);
987
988 DPRINT("Enter NtUserSetCursor\n");
989 UserEnterExclusive();
990
991 if (hCursor)
992 {
993 if (!(CurIcon = UserGetCurIconObject(hCursor)))
994 {
995 RETURN(NULL);
996 }
997 }
998 else
999 {
1000 CurIcon = NULL;
1001 }
1002
1003 OldCursor = UserSetCursor(CurIcon, FALSE);
1004
1005 if (CurIcon)
1006 {
1007 UserDereferenceObject(CurIcon);
1008 }
1009
1010 RETURN(OldCursor);
1011
1012 CLEANUP:
1013 DPRINT("Leave NtUserSetCursor, ret=%i\n",_ret_);
1014 UserLeave();
1015 END_CLEANUP;
1016 }
1017
1018
1019 /*
1020 * @implemented
1021 */
1022 BOOL
1023 APIENTRY
1024 NtUserSetCursorContents(
1025 HANDLE hCurIcon,
1026 PICONINFO UnsafeIconInfo)
1027 {
1028 PCURICON_OBJECT CurIcon;
1029 ICONINFO IconInfo;
1030 PSURFACE psurfBmp;
1031 NTSTATUS Status;
1032 BOOL Ret = FALSE;
1033 DECLARE_RETURN(BOOL);
1034
1035 DPRINT("Enter NtUserSetCursorContents\n");
1036 UserEnterExclusive();
1037
1038 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
1039 {
1040 RETURN(FALSE);
1041 }
1042
1043 /* Copy fields */
1044 Status = MmCopyFromCaller(&IconInfo, UnsafeIconInfo, sizeof(ICONINFO));
1045 if (!NT_SUCCESS(Status))
1046 {
1047 SetLastNtError(Status);
1048 goto done;
1049 }
1050
1051 /* Delete old bitmaps */
1052 if (CurIcon->IconInfo.hbmColor != IconInfo.hbmColor)
1053 {
1054 GreDeleteObject(CurIcon->IconInfo.hbmColor);
1055 }
1056 if (CurIcon->IconInfo.hbmMask != IconInfo.hbmMask)
1057 {
1058 GreDeleteObject(CurIcon->IconInfo.hbmMask);
1059 }
1060
1061 /* Copy new IconInfo field */
1062 CurIcon->IconInfo = IconInfo;
1063
1064 psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmColor);
1065 if (psurfBmp)
1066 {
1067 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
1068 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
1069 SURFACE_UnlockSurface(psurfBmp);
1070 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmColor, NULL);
1071 }
1072 else
1073 {
1074 psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmMask);
1075 if (!psurfBmp)
1076 goto done;
1077
1078 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
1079 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy / 2;
1080
1081 SURFACE_UnlockSurface(psurfBmp);
1082 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmMask, NULL);
1083 }
1084
1085 Ret = TRUE;
1086
1087 done:
1088
1089 if (CurIcon)
1090 {
1091 UserDereferenceObject(CurIcon);
1092 }
1093 RETURN(Ret);
1094
1095 CLEANUP:
1096 DPRINT("Leave NtUserSetCursorContents, ret=%i\n",_ret_);
1097 UserLeave();
1098 END_CLEANUP;
1099 }
1100
1101
1102 /*
1103 * @implemented
1104 */
1105 #if 0
1106 BOOL
1107 APIENTRY
1108 NtUserSetCursorIconData(
1109 HANDLE Handle,
1110 HMODULE hModule,
1111 PUNICODE_STRING pstrResName,
1112 PICONINFO pIconInfo)
1113 {
1114 PCURICON_OBJECT CurIcon;
1115 PSURFACE psurfBmp;
1116 NTSTATUS Status = STATUS_SUCCESS;
1117 BOOL Ret = FALSE;
1118 DECLARE_RETURN(BOOL);
1119
1120 DPRINT("Enter NtUserSetCursorIconData\n");
1121 UserEnterExclusive();
1122
1123 if (!(CurIcon = UserGetCurIconObject(Handle)))
1124 {
1125 RETURN(FALSE);
1126 }
1127
1128 CurIcon->hModule = hModule;
1129 CurIcon->hRsrc = NULL; //hRsrc;
1130 CurIcon->hGroupRsrc = NULL; //hGroupRsrc;
1131
1132 _SEH2_TRY
1133 {
1134 ProbeForRead(pIconInfo, sizeof(ICONINFO), 1);
1135 RtlCopyMemory(&CurIcon->IconInfo, pIconInfo, sizeof(ICONINFO));
1136
1137 CurIcon->IconInfo.hbmMask = BITMAP_CopyBitmap(pIconInfo->hbmMask);
1138 CurIcon->IconInfo.hbmColor = BITMAP_CopyBitmap(pIconInfo->hbmColor);
1139
1140 if (CurIcon->IconInfo.hbmColor)
1141 {
1142 if ((psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmColor)))
1143 {
1144 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
1145 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
1146 SURFACE_UnlockSurface(psurfBmp);
1147 GDIOBJ_SetOwnership(GdiHandleTable, CurIcon->IconInfo.hbmMask, NULL);
1148 }
1149 }
1150 if (CurIcon->IconInfo.hbmMask)
1151 {
1152 if (CurIcon->IconInfo.hbmColor == NULL)
1153 {
1154 if ((psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmMask)))
1155 {
1156 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
1157 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
1158 SURFACE_UnlockSurface(psurfBmp);
1159 }
1160 }
1161 GDIOBJ_SetOwnership(GdiHandleTable, CurIcon->IconInfo.hbmMask, NULL);
1162 }
1163 }
1164 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1165 {
1166 Status = _SEH2_GetExceptionCode();
1167 }
1168 _SEH2_END
1169
1170 if (!NT_SUCCESS(Status))
1171 SetLastNtError(Status);
1172 else
1173 Ret = TRUE;
1174
1175 UserDereferenceObject(CurIcon);
1176 RETURN(Ret);
1177
1178 CLEANUP:
1179 DPRINT("Leave NtUserSetCursorIconData, ret=%i\n",_ret_);
1180 UserLeave();
1181 END_CLEANUP;
1182 }
1183 #else
1184 BOOL
1185 APIENTRY
1186 NtUserSetCursorIconData(
1187 HANDLE hCurIcon,
1188 PBOOL fIcon,
1189 POINT *Hotspot,
1190 HMODULE hModule,
1191 HRSRC hRsrc,
1192 HRSRC hGroupRsrc)
1193 {
1194 PCURICON_OBJECT CurIcon;
1195 NTSTATUS Status;
1196 POINT SafeHotspot;
1197 BOOL Ret = FALSE;
1198 DECLARE_RETURN(BOOL);
1199
1200 DPRINT("Enter NtUserSetCursorIconData\n");
1201 UserEnterExclusive();
1202
1203 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
1204 {
1205 RETURN(FALSE);
1206 }
1207
1208 CurIcon->hModule = hModule;
1209 CurIcon->hRsrc = hRsrc;
1210 CurIcon->hGroupRsrc = hGroupRsrc;
1211
1212 /* Copy fields */
1213 if (fIcon)
1214 {
1215 Status = MmCopyFromCaller(&CurIcon->IconInfo.fIcon, fIcon, sizeof(BOOL));
1216 if (!NT_SUCCESS(Status))
1217 {
1218 SetLastNtError(Status);
1219 goto done;
1220 }
1221 }
1222 else
1223 {
1224 if (!Hotspot)
1225 Ret = TRUE;
1226 }
1227
1228 if (Hotspot)
1229 {
1230 Status = MmCopyFromCaller(&SafeHotspot, Hotspot, sizeof(POINT));
1231 if (NT_SUCCESS(Status))
1232 {
1233 CurIcon->IconInfo.xHotspot = SafeHotspot.x;
1234 CurIcon->IconInfo.yHotspot = SafeHotspot.y;
1235
1236 Ret = TRUE;
1237 }
1238 else
1239 SetLastNtError(Status);
1240 }
1241
1242 if (!fIcon && !Hotspot)
1243 {
1244 Ret = TRUE;
1245 }
1246
1247 done:
1248 UserDereferenceObject(CurIcon);
1249 RETURN(Ret);
1250
1251
1252 CLEANUP:
1253 DPRINT("Leave NtUserSetCursorIconData, ret=%i\n",_ret_);
1254 UserLeave();
1255 END_CLEANUP;
1256 }
1257 #endif
1258
1259 /*
1260 * @unimplemented
1261 */
1262 BOOL
1263 APIENTRY
1264 NtUserSetSystemCursor(
1265 HCURSOR hcur,
1266 DWORD id)
1267 {
1268 return FALSE;
1269 }
1270
1271 BOOL
1272 UserDrawIconEx(
1273 HDC hDc,
1274 INT xLeft,
1275 INT yTop,
1276 PCURICON_OBJECT pIcon,
1277 INT cxWidth,
1278 INT cyHeight,
1279 UINT istepIfAniCur,
1280 HBRUSH hbrFlickerFreeDraw,
1281 UINT diFlags)
1282 {
1283 BOOL Ret = FALSE;
1284 HBITMAP hbmMask, hbmColor;
1285 BITMAP bmpMask, bmpColor;
1286 BOOL DoFlickerFree;
1287 SIZE IconSize;
1288
1289 HDC hdcOff;
1290 HGDIOBJ hOldOffBrush = 0;
1291 HGDIOBJ hOldOffBmp = 0;
1292 HBITMAP hbmOff = 0;
1293 HDC hdcMask = 0;
1294 HGDIOBJ hOldMask = NULL;
1295 HDC hdcImage = 0;
1296 HGDIOBJ hOldImage = NULL;
1297 BOOL bAlpha = FALSE;
1298
1299 hbmMask = pIcon->IconInfo.hbmMask;
1300 hbmColor = pIcon->IconInfo.hbmColor;
1301
1302 if (istepIfAniCur)
1303 DPRINT1("NtUserDrawIconEx: istepIfAniCur is not supported!\n");
1304
1305 if (!hbmMask || !IntGdiGetObject(hbmMask, sizeof(BITMAP), (PVOID)&bmpMask))
1306 {
1307 return FALSE;
1308 }
1309
1310 if (hbmColor && !IntGdiGetObject(hbmColor, sizeof(BITMAP), (PVOID)&bmpColor))
1311 {
1312 return FALSE;
1313 }
1314
1315 if (hbmColor)
1316 {
1317 IconSize.cx = bmpColor.bmWidth;
1318 IconSize.cy = bmpColor.bmHeight;
1319 }
1320 else
1321 {
1322 IconSize.cx = bmpMask.bmWidth;
1323 IconSize.cy = bmpMask.bmHeight / 2;
1324 }
1325
1326 /* NtGdiCreateCompatibleBitmap will create a monochrome bitmap
1327 when cxWidth or cyHeight is 0 */
1328 if ((bmpColor.bmBitsPixel == 32) && (cxWidth != 0) && (cyHeight != 0))
1329 {
1330 SURFACE *psurfOff = NULL;
1331 PFN_DIB_GetPixel fnSource_GetPixel = NULL;
1332 INT x, y;
1333
1334 /* In order to correctly display 32 bit icons Windows first scans the image,
1335 because information about transparency is not stored in any image's headers */
1336 psurfOff = SURFACE_LockSurface(hbmColor ? hbmColor : hbmMask);
1337 if (psurfOff)
1338 {
1339 fnSource_GetPixel = DibFunctionsForBitmapFormat[psurfOff->SurfObj.iBitmapFormat].DIB_GetPixel;
1340 if (fnSource_GetPixel)
1341 {
1342 for (x = 0; x < psurfOff->SurfObj.sizlBitmap.cx; x++)
1343 {
1344 for (y = 0; y < psurfOff->SurfObj.sizlBitmap.cy; y++)
1345 {
1346 bAlpha = ((BYTE)(fnSource_GetPixel(&psurfOff->SurfObj, x, y) >> 24) & 0xff);
1347 if (bAlpha)
1348 break;
1349 }
1350 if (bAlpha)
1351 break;
1352 }
1353 }
1354 SURFACE_UnlockSurface(psurfOff);
1355 }
1356 }
1357
1358 if (!diFlags)
1359 diFlags = DI_NORMAL;
1360
1361 if (!cxWidth)
1362 cxWidth = ((diFlags & DI_DEFAULTSIZE) ?
1363 UserGetSystemMetrics(SM_CXICON) : IconSize.cx);
1364
1365 if (!cyHeight)
1366 cyHeight = ((diFlags & DI_DEFAULTSIZE) ?
1367 UserGetSystemMetrics(SM_CYICON) : IconSize.cy);
1368
1369 DoFlickerFree = (hbrFlickerFreeDraw &&
1370 (GDI_HANDLE_GET_TYPE(hbrFlickerFreeDraw) == GDI_OBJECT_TYPE_BRUSH));
1371
1372 if (DoFlickerFree || bAlpha)
1373 {
1374 RECTL r;
1375 BITMAP bm;
1376 SURFACE *psurfOff = NULL;
1377
1378 r.right = cxWidth;
1379 r.bottom = cyHeight;
1380
1381 hdcOff = NtGdiCreateCompatibleDC(hDc);
1382 if (!hdcOff)
1383 {
1384 DPRINT1("NtGdiCreateCompatibleDC() failed!\n");
1385 return FALSE;
1386 }
1387
1388 hbmOff = NtGdiCreateCompatibleBitmap(hDc, cxWidth, cyHeight);
1389 if (!hbmOff)
1390 {
1391 DPRINT1("NtGdiCreateCompatibleBitmap() failed!\n");
1392 goto cleanup;
1393 }
1394
1395 /* make sure we have a 32 bit offscreen bitmap
1396 otherwise we can't do alpha blending */
1397 psurfOff = SURFACE_LockSurface(hbmOff);
1398 if (psurfOff == NULL)
1399 {
1400 DPRINT1("BITMAPOBJ_LockBitmap() failed!\n");
1401 goto cleanup;
1402 }
1403 BITMAP_GetObject(psurfOff, sizeof(BITMAP), (PVOID)&bm);
1404
1405 if (bm.bmBitsPixel != 32)
1406 bAlpha = FALSE;
1407
1408 SURFACE_UnlockSurface(psurfOff);
1409
1410 hOldOffBmp = NtGdiSelectBitmap(hdcOff, hbmOff);
1411 if (!hOldOffBmp)
1412 {
1413 DPRINT1("NtGdiSelectBitmap() failed!\n");
1414 goto cleanup;
1415 }
1416
1417 if (DoFlickerFree)
1418 {
1419 hOldOffBrush = NtGdiSelectBrush(hdcOff, hbrFlickerFreeDraw);
1420 if (!hOldOffBrush)
1421 {
1422 DPRINT1("NtGdiSelectBrush() failed!\n");
1423 goto cleanup;
1424 }
1425
1426 NtGdiPatBlt(hdcOff, 0, 0, r.right, r.bottom, PATCOPY);
1427 }
1428 }
1429 else
1430 hdcOff = hDc;
1431
1432 if (diFlags & DI_IMAGE)
1433 {
1434 hdcImage = NtGdiCreateCompatibleDC(hDc);
1435 if (!hdcImage)
1436 {
1437 DPRINT1("NtGdiCreateCompatibleDC() failed!\n");
1438 goto cleanup;
1439 }
1440 hOldImage = NtGdiSelectBitmap(hdcImage, (hbmColor ? hbmColor : hbmMask));
1441 if (!hOldImage)
1442 {
1443 DPRINT("NtGdiSelectBitmap() failed!\n");
1444 goto cleanup;
1445 }
1446 }
1447
1448 /* If DI_IMAGE flag is specified and hbmMask exists, then always use mask for drawing */
1449 if (diFlags & DI_MASK || (diFlags & DI_IMAGE && hbmMask))
1450 {
1451 hdcMask = NtGdiCreateCompatibleDC(hDc);
1452 if (!hdcMask)
1453 {
1454 DPRINT1("NtGdiCreateCompatibleDC() failed!\n");
1455 goto cleanup;
1456 }
1457
1458 hOldMask = NtGdiSelectBitmap(hdcMask, hbmMask);
1459 if (!hOldMask)
1460 {
1461 DPRINT("NtGdiSelectBitmap() failed!\n");
1462 goto cleanup;
1463 }
1464 }
1465
1466 if (hdcMask || hdcImage)
1467 {
1468 GreStretchBltMask(hdcOff,
1469 (DoFlickerFree || bAlpha) ? 0 : xLeft,
1470 (DoFlickerFree || bAlpha) ? 0 : yTop,
1471 cxWidth,
1472 cyHeight,
1473 hdcImage ? hdcImage : hdcMask,
1474 0,
1475 0,
1476 IconSize.cx,
1477 IconSize.cy,
1478 SRCCOPY,
1479 0,
1480 hdcMask,
1481 0,
1482 hdcImage ? 0 : IconSize.cy);
1483 }
1484
1485 if (hOldMask) NtGdiSelectBitmap(hdcMask, hOldMask);
1486 if (hOldImage) NtGdiSelectBitmap(hdcImage, hOldImage);
1487 if (hdcImage) NtGdiDeleteObjectApp(hdcImage);
1488 if (hdcMask) NtGdiDeleteObjectApp(hdcMask);
1489
1490 if (bAlpha)
1491 {
1492 BITMAP bm;
1493 SURFACE *psurfOff = NULL;
1494 PBYTE pBits = NULL;
1495 BLENDFUNCTION BlendFunc;
1496 DWORD Pixel;
1497 BYTE Red, Green, Blue, Alpha;
1498 DWORD Count = 0;
1499 INT i, j;
1500
1501 psurfOff = SURFACE_LockSurface(hbmOff);
1502 if (psurfOff == NULL)
1503 {
1504 DPRINT1("BITMAPOBJ_LockBitmap() failed!\n");
1505 goto cleanup;
1506 }
1507 BITMAP_GetObject(psurfOff, sizeof(BITMAP), (PVOID)&bm);
1508
1509 pBits = ExAllocatePoolWithTag(PagedPool, bm.bmWidthBytes * abs(bm.bmHeight), TAG_BITMAP);
1510 if (pBits == NULL)
1511 {
1512 DPRINT1("ExAllocatePoolWithTag() failed!\n");
1513 SURFACE_UnlockSurface(psurfOff);
1514 goto cleanup;
1515 }
1516
1517 /* get icon bits */
1518 IntGetBitmapBits(psurfOff, bm.bmWidthBytes * abs(bm.bmHeight), pBits);
1519
1520 /* premultiply with the alpha channel value */
1521 for (i = 0; i < cyHeight; i++)
1522 {
1523 for (j = 0; j < cxWidth; j++)
1524 {
1525 Pixel = *(DWORD *)(pBits + Count);
1526
1527 Alpha = ((BYTE)(Pixel >> 24) & 0xff);
1528
1529 Red = (((BYTE)(Pixel >> 0)) * Alpha) / 0xff;
1530 Green = (((BYTE)(Pixel >> 8)) * Alpha) / 0xff;
1531 Blue = (((BYTE)(Pixel >> 16)) * Alpha) / 0xff;
1532
1533 *(DWORD *)(pBits + Count) = (DWORD)(Red | (Green << 8) | (Blue << 16) | (Alpha << 24));
1534
1535 Count += sizeof(DWORD);
1536 }
1537 }
1538
1539 /* set icon bits */
1540 IntSetBitmapBits(psurfOff, bm.bmWidthBytes * abs(bm.bmHeight), pBits);
1541 ExFreePoolWithTag(pBits, TAG_BITMAP);
1542
1543 SURFACE_UnlockSurface(psurfOff);
1544
1545 BlendFunc.BlendOp = AC_SRC_OVER;
1546 BlendFunc.BlendFlags = 0;
1547 BlendFunc.SourceConstantAlpha = 255;
1548 BlendFunc.AlphaFormat = AC_SRC_ALPHA;
1549
1550 NtGdiAlphaBlend(hDc, xLeft, yTop, cxWidth, cyHeight,
1551 hdcOff, 0, 0, cxWidth, cyHeight, BlendFunc, 0);
1552 }
1553 else if (DoFlickerFree)
1554 {
1555 NtGdiBitBlt(hDc, xLeft, yTop, cxWidth,
1556 cyHeight, hdcOff, 0, 0, SRCCOPY, 0, 0);
1557 }
1558
1559 Ret = TRUE;
1560
1561 cleanup:
1562 if (DoFlickerFree || bAlpha)
1563 {
1564 if (hOldOffBmp) NtGdiSelectBitmap(hdcOff, hOldOffBmp);
1565 if (hOldOffBrush) NtGdiSelectBrush(hdcOff, hOldOffBrush);
1566 if (hbmOff) GreDeleteObject(hbmOff);
1567 if (hdcOff) NtGdiDeleteObjectApp(hdcOff);
1568 }
1569
1570 return Ret;
1571 }
1572
1573 /*
1574 * @implemented
1575 */
1576 BOOL
1577 APIENTRY
1578 NtUserDrawIconEx(
1579 HDC hdc,
1580 int xLeft,
1581 int yTop,
1582 HICON hIcon,
1583 int cxWidth,
1584 int cyHeight,
1585 UINT istepIfAniCur,
1586 HBRUSH hbrFlickerFreeDraw,
1587 UINT diFlags,
1588 BOOL bMetaHDC, // When TRUE, GDI functions need to be handled in User32!
1589 PVOID pDIXData)
1590 {
1591 PCURICON_OBJECT pIcon;
1592 BOOL Ret;
1593
1594 DPRINT("Enter NtUserDrawIconEx\n");
1595 UserEnterExclusive();
1596
1597 if (!(pIcon = UserGetCurIconObject(hIcon)))
1598 {
1599 DPRINT1("UserGetCurIconObject() failed!\n");
1600 UserLeave();
1601 return FALSE;
1602 }
1603
1604 Ret = UserDrawIconEx(hdc,
1605 xLeft,
1606 yTop,
1607 pIcon,
1608 cxWidth,
1609 cyHeight,
1610 istepIfAniCur,
1611 hbrFlickerFreeDraw,
1612 diFlags);
1613
1614 UserDereferenceObject(pIcon);
1615
1616 UserLeave();
1617 return Ret;
1618 }
1619