03f4431e18f2269fd323cf3baa116804290be2af
[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 <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 * @implemented
496 */
497 HANDLE
498 APIENTRY
499 NtUserCreateCursorIconHandle(PICONINFO IconInfo OPTIONAL, BOOL Indirect)
500 {
501 PCURICON_OBJECT CurIcon;
502 PSURFACE psurfBmp;
503 NTSTATUS Status;
504 HANDLE Ret;
505 DECLARE_RETURN(HANDLE);
506
507 DPRINT("Enter NtUserCreateCursorIconHandle\n");
508 UserEnterExclusive();
509
510 if (!(CurIcon = IntCreateCurIconHandle()))
511 {
512 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
513 RETURN((HANDLE)0);
514 }
515
516 Ret = CurIcon->Self;
517
518 if (IconInfo)
519 {
520 Status = MmCopyFromCaller(&CurIcon->IconInfo, IconInfo, sizeof(ICONINFO));
521 if (NT_SUCCESS(Status))
522 {
523 /* Copy bitmaps and size info */
524 if (Indirect)
525 {
526 // FIXME: WTF?
527 CurIcon->IconInfo.hbmMask = BITMAP_CopyBitmap(CurIcon->IconInfo.hbmMask);
528 CurIcon->IconInfo.hbmColor = BITMAP_CopyBitmap(CurIcon->IconInfo.hbmColor);
529 }
530 if (CurIcon->IconInfo.hbmColor &&
531 (psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmColor)))
532 {
533 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
534 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
535 SURFACE_UnlockSurface(psurfBmp);
536 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmColor, NULL);
537 }
538 if (CurIcon->IconInfo.hbmMask &&
539 (psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmMask)))
540 {
541 if (CurIcon->IconInfo.hbmColor == NULL)
542 {
543 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
544 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy >> 1;
545 }
546 SURFACE_UnlockSurface(psurfBmp);
547 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmMask, NULL);
548 }
549
550 /* Calculate icon hotspot */
551 if (CurIcon->IconInfo.fIcon == TRUE)
552 {
553 CurIcon->IconInfo.xHotspot = CurIcon->Size.cx >> 1;
554 CurIcon->IconInfo.yHotspot = CurIcon->Size.cy >> 1;
555 }
556 }
557 else
558 {
559 SetLastNtError(Status);
560 /* FIXME - Don't exit here */
561 }
562 }
563
564 UserDereferenceObject(CurIcon);
565 RETURN(Ret);
566
567 CLEANUP:
568 DPRINT("Leave NtUserCreateCursorIconHandle, ret=%i\n",_ret_);
569 UserLeave();
570 END_CLEANUP;
571 }
572
573 /*
574 * @implemented
575 */
576 BOOL
577 APIENTRY
578 NtUserGetIconInfo(
579 HANDLE hCurIcon,
580 PICONINFO IconInfo,
581 PUNICODE_STRING lpInstName, // optional
582 PUNICODE_STRING lpResName, // optional
583 LPDWORD pbpp, // optional
584 BOOL bInternal)
585 {
586 ICONINFO ii;
587 PCURICON_OBJECT CurIcon;
588 NTSTATUS Status = STATUS_SUCCESS;
589 BOOL Ret = FALSE;
590 DWORD colorBpp = 0;
591
592 DPRINT("Enter NtUserGetIconInfo\n");
593 UserEnterExclusive();
594
595 if (!IconInfo)
596 {
597 SetLastWin32Error(ERROR_INVALID_PARAMETER);
598 goto leave;
599 }
600
601 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
602 {
603 goto leave;
604 }
605
606 RtlCopyMemory(&ii, &CurIcon->IconInfo, sizeof(ICONINFO));
607
608 /* Copy bitmaps */
609 ii.hbmMask = BITMAP_CopyBitmap(CurIcon->IconInfo.hbmMask);
610 ii.hbmColor = BITMAP_CopyBitmap(CurIcon->IconInfo.hbmColor);
611
612 if (pbpp)
613 {
614 PSURFACE psurfBmp;
615
616 psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmColor);
617 if (psurfBmp)
618 {
619 colorBpp = BitsPerFormat(psurfBmp->SurfObj.iBitmapFormat);
620 SURFACE_UnlockSurface(psurfBmp);
621 }
622 }
623
624 /* Copy fields */
625 _SEH2_TRY
626 {
627 ProbeForWrite(IconInfo, sizeof(ICONINFO), 1);
628 RtlCopyMemory(IconInfo, &ii, sizeof(ICONINFO));
629
630 if (pbpp)
631 {
632 ProbeForWrite(pbpp, sizeof(DWORD), 1);
633 *pbpp = colorBpp;
634 }
635 }
636 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
637 {
638 Status = _SEH2_GetExceptionCode();
639 }
640 _SEH2_END
641
642 if (NT_SUCCESS(Status))
643 Ret = TRUE;
644 else
645 SetLastNtError(Status);
646
647 UserDereferenceObject(CurIcon);
648
649 leave:
650 DPRINT("Leave NtUserGetIconInfo, ret=%i\n", Ret);
651 UserLeave();
652
653 return Ret;
654 }
655
656
657 /*
658 * @implemented
659 */
660 BOOL
661 APIENTRY
662 NtUserGetIconSize(
663 HANDLE hCurIcon,
664 UINT istepIfAniCur,
665 PLONG plcx, // &size.cx
666 PLONG plcy) // &size.cy
667 {
668 PCURICON_OBJECT CurIcon;
669 NTSTATUS Status = STATUS_SUCCESS;
670 BOOL bRet = FALSE;
671
672 DPRINT("Enter NtUserGetIconSize\n");
673 UserEnterExclusive();
674
675 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
676 {
677 goto cleanup;
678 }
679
680 _SEH2_TRY
681 {
682 ProbeForWrite(plcx, sizeof(LONG), 1);
683 RtlCopyMemory(plcx, &CurIcon->Size.cx, sizeof(LONG));
684 ProbeForWrite(plcy, sizeof(LONG), 1);
685 RtlCopyMemory(plcy, &CurIcon->Size.cy, sizeof(LONG));
686 }
687 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
688 {
689 Status = _SEH2_GetExceptionCode();
690 }
691 _SEH2_END
692
693 if (NT_SUCCESS(Status))
694 bRet = TRUE;
695 else
696 SetLastNtError(Status); // maybe not, test this
697
698 UserDereferenceObject(CurIcon);
699
700 cleanup:
701 DPRINT("Leave NtUserGetIconSize, ret=%i\n", bRet);
702 UserLeave();
703 return bRet;
704 }
705
706
707 /*
708 * @unimplemented
709 */
710 DWORD
711 APIENTRY
712 NtUserGetCursorFrameInfo(
713 DWORD Unknown0,
714 DWORD Unknown1,
715 DWORD Unknown2,
716 DWORD Unknown3)
717 {
718 UNIMPLEMENTED
719
720 return 0;
721 }
722
723
724 /*
725 * @implemented
726 */
727 BOOL
728 APIENTRY
729 NtUserGetCursorInfo(
730 PCURSORINFO pci)
731 {
732 CURSORINFO SafeCi;
733 PSYSTEM_CURSORINFO CurInfo;
734 NTSTATUS Status = STATUS_SUCCESS;
735 PCURICON_OBJECT CurIcon;
736 BOOL Ret = FALSE;
737 DECLARE_RETURN(BOOL);
738
739 DPRINT("Enter NtUserGetCursorInfo\n");
740 UserEnterExclusive();
741
742 CurInfo = IntGetSysCursorInfo();
743 CurIcon = (PCURICON_OBJECT)CurInfo->CurrentCursorObject;
744
745 SafeCi.cbSize = sizeof(CURSORINFO);
746 SafeCi.flags = ((CurInfo->ShowingCursor && CurIcon) ? CURSOR_SHOWING : 0);
747 SafeCi.hCursor = (CurIcon ? (HCURSOR)CurIcon->Self : (HCURSOR)0);
748
749 SafeCi.ptScreenPos = gpsi->ptCursor;
750
751 _SEH2_TRY
752 {
753 if (pci->cbSize == sizeof(CURSORINFO))
754 {
755 ProbeForWrite(pci, sizeof(CURSORINFO), 1);
756 RtlCopyMemory(pci, &SafeCi, sizeof(CURSORINFO));
757 Ret = TRUE;
758 }
759 else
760 {
761 SetLastWin32Error(ERROR_INVALID_PARAMETER);
762 }
763 }
764 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
765 {
766 Status = _SEH2_GetExceptionCode();
767 }
768 _SEH2_END;
769 if (!NT_SUCCESS(Status))
770 {
771 SetLastNtError(Status);
772 }
773
774 RETURN(Ret);
775
776 CLEANUP:
777 DPRINT("Leave NtUserGetCursorInfo, ret=%i\n",_ret_);
778 UserLeave();
779 END_CLEANUP;
780 }
781
782
783 /*
784 * @implemented
785 */
786 BOOL
787 APIENTRY
788 NtUserClipCursor(
789 RECTL *UnsafeRect)
790 {
791 /* FIXME - check if process has WINSTA_WRITEATTRIBUTES */
792 PSYSTEM_CURSORINFO CurInfo;
793 RECTL Rect;
794 PWINDOW_OBJECT DesktopWindow = NULL;
795 DECLARE_RETURN(BOOL);
796
797 DPRINT("Enter NtUserClipCursor\n");
798 UserEnterExclusive();
799
800 if (NULL != UnsafeRect && ! NT_SUCCESS(MmCopyFromCaller(&Rect, UnsafeRect, sizeof(RECT))))
801 {
802 SetLastWin32Error(ERROR_INVALID_PARAMETER);
803 RETURN(FALSE);
804 }
805
806 CurInfo = IntGetSysCursorInfo();
807
808 DesktopWindow = UserGetDesktopWindow();
809
810 if ((Rect.right > Rect.left) && (Rect.bottom > Rect.top)
811 && DesktopWindow && UnsafeRect != NULL)
812 {
813
814 CurInfo->CursorClipInfo.IsClipped = TRUE;
815 CurInfo->CursorClipInfo.Left = max(Rect.left, DesktopWindow->Wnd->rcWindow.left);
816 CurInfo->CursorClipInfo.Top = max(Rect.top, DesktopWindow->Wnd->rcWindow.top);
817 CurInfo->CursorClipInfo.Right = min(Rect.right, DesktopWindow->Wnd->rcWindow.right);
818 CurInfo->CursorClipInfo.Bottom = min(Rect.bottom, DesktopWindow->Wnd->rcWindow.bottom);
819
820 UserSetCursorPos(gpsi->ptCursor.x, gpsi->ptCursor.y, FALSE);
821
822 RETURN(TRUE);
823 }
824
825 CurInfo->CursorClipInfo.IsClipped = FALSE;
826 RETURN(TRUE);
827
828 CLEANUP:
829 DPRINT("Leave NtUserClipCursor, ret=%i\n",_ret_);
830 UserLeave();
831 END_CLEANUP;
832 }
833
834
835 /*
836 * @implemented
837 */
838 BOOL
839 APIENTRY
840 NtUserDestroyCursor(
841 HANDLE hCurIcon,
842 DWORD Unknown)
843 {
844 PCURICON_OBJECT CurIcon;
845 BOOL ret;
846 DECLARE_RETURN(BOOL);
847
848 DPRINT("Enter NtUserDestroyCursorIcon\n");
849 UserEnterExclusive();
850
851 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
852 {
853 RETURN(FALSE);
854 }
855
856 ret = IntDestroyCurIconObject(CurIcon, FALSE);
857 /* Note: IntDestroyCurIconObject will remove our reference for us! */
858
859 RETURN(ret);
860
861 CLEANUP:
862 DPRINT("Leave NtUserDestroyCursorIcon, ret=%i\n",_ret_);
863 UserLeave();
864 END_CLEANUP;
865 }
866
867
868 /*
869 * @implemented
870 */
871 HICON
872 APIENTRY
873 NtUserFindExistingCursorIcon(
874 HMODULE hModule,
875 HRSRC hRsrc,
876 LONG cx,
877 LONG cy)
878 {
879 PCURICON_OBJECT CurIcon;
880 HANDLE Ret = (HANDLE)0;
881 DECLARE_RETURN(HICON);
882
883 DPRINT("Enter NtUserFindExistingCursorIcon\n");
884 UserEnterExclusive();
885
886 CurIcon = IntFindExistingCurIconObject(hModule, hRsrc, cx, cy);
887 if (CurIcon)
888 {
889 Ret = CurIcon->Self;
890
891 // IntReleaseCurIconObject(CurIcon);//faxme: is this correct? does IntFindExistingCurIconObject add a ref?
892 RETURN(Ret);
893 }
894
895 SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
896 RETURN((HANDLE)0);
897
898 CLEANUP:
899 DPRINT("Leave NtUserFindExistingCursorIcon, ret=%i\n",_ret_);
900 UserLeave();
901 END_CLEANUP;
902 }
903
904
905 /*
906 * @implemented
907 */
908 BOOL
909 APIENTRY
910 NtUserGetClipCursor(
911 RECTL *lpRect)
912 {
913 /* FIXME - check if process has WINSTA_READATTRIBUTES */
914 PSYSTEM_CURSORINFO CurInfo;
915 RECTL Rect;
916 NTSTATUS Status;
917 DECLARE_RETURN(BOOL);
918
919 DPRINT("Enter NtUserGetClipCursor\n");
920 UserEnterExclusive();
921
922 if (!lpRect)
923 RETURN(FALSE);
924
925 CurInfo = IntGetSysCursorInfo();
926 if (CurInfo->CursorClipInfo.IsClipped)
927 {
928 Rect.left = CurInfo->CursorClipInfo.Left;
929 Rect.top = CurInfo->CursorClipInfo.Top;
930 Rect.right = CurInfo->CursorClipInfo.Right;
931 Rect.bottom = CurInfo->CursorClipInfo.Bottom;
932 }
933 else
934 {
935 Rect.left = 0;
936 Rect.top = 0;
937 Rect.right = UserGetSystemMetrics(SM_CXSCREEN);
938 Rect.bottom = UserGetSystemMetrics(SM_CYSCREEN);
939 }
940
941 Status = MmCopyToCaller(lpRect, &Rect, sizeof(RECT));
942 if (!NT_SUCCESS(Status))
943 {
944 SetLastNtError(Status);
945 RETURN(FALSE);
946 }
947
948 RETURN(TRUE);
949
950 CLEANUP:
951 DPRINT("Leave NtUserGetClipCursor, ret=%i\n",_ret_);
952 UserLeave();
953 END_CLEANUP;
954 }
955
956
957 /*
958 * @implemented
959 */
960 HCURSOR
961 APIENTRY
962 NtUserSetCursor(
963 HCURSOR hCursor)
964 {
965 PCURICON_OBJECT CurIcon;
966 HICON OldCursor;
967 DECLARE_RETURN(HCURSOR);
968
969 DPRINT("Enter NtUserSetCursor\n");
970 UserEnterExclusive();
971
972 if (hCursor)
973 {
974 if (!(CurIcon = UserGetCurIconObject(hCursor)))
975 {
976 RETURN(NULL);
977 }
978 }
979 else
980 {
981 CurIcon = NULL;
982 }
983
984 OldCursor = UserSetCursor(CurIcon, FALSE);
985
986 if (CurIcon)
987 {
988 UserDereferenceObject(CurIcon);
989 }
990
991 RETURN(OldCursor);
992
993 CLEANUP:
994 DPRINT("Leave NtUserSetCursor, ret=%i\n",_ret_);
995 UserLeave();
996 END_CLEANUP;
997 }
998
999
1000 /*
1001 * @implemented
1002 */
1003 BOOL
1004 APIENTRY
1005 NtUserSetCursorContents(
1006 HANDLE hCurIcon,
1007 PICONINFO UnsafeIconInfo)
1008 {
1009 PCURICON_OBJECT CurIcon;
1010 ICONINFO IconInfo;
1011 PSURFACE psurfBmp;
1012 NTSTATUS Status;
1013 BOOL Ret = FALSE;
1014 DECLARE_RETURN(BOOL);
1015
1016 DPRINT("Enter NtUserSetCursorContents\n");
1017 UserEnterExclusive();
1018
1019 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
1020 {
1021 RETURN(FALSE);
1022 }
1023
1024 /* Copy fields */
1025 Status = MmCopyFromCaller(&IconInfo, UnsafeIconInfo, sizeof(ICONINFO));
1026 if (!NT_SUCCESS(Status))
1027 {
1028 SetLastNtError(Status);
1029 goto done;
1030 }
1031
1032 /* Delete old bitmaps */
1033 if ((CurIcon->IconInfo.hbmColor)
1034 && (CurIcon->IconInfo.hbmColor != IconInfo.hbmColor))
1035 {
1036 GreDeleteObject(CurIcon->IconInfo.hbmColor);
1037 }
1038 if ((CurIcon->IconInfo.hbmMask)
1039 && (CurIcon->IconInfo.hbmMask != IconInfo.hbmMask))
1040 {
1041 GreDeleteObject(CurIcon->IconInfo.hbmMask);
1042 }
1043
1044 /* Copy new IconInfo field */
1045 CurIcon->IconInfo = IconInfo;
1046
1047 psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmColor);
1048 if (psurfBmp)
1049 {
1050 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
1051 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
1052 SURFACE_UnlockSurface(psurfBmp);
1053 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmColor, NULL);
1054 }
1055 else
1056 {
1057 psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmMask);
1058 if (!psurfBmp)
1059 goto done;
1060
1061 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
1062 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy / 2;
1063
1064 SURFACE_UnlockSurface(psurfBmp);
1065 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmMask, NULL);
1066 }
1067
1068 Ret = TRUE;
1069
1070 done:
1071
1072 if (CurIcon)
1073 {
1074 UserDereferenceObject(CurIcon);
1075 }
1076 RETURN(Ret);
1077
1078 CLEANUP:
1079 DPRINT("Leave NtUserSetCursorContents, ret=%i\n",_ret_);
1080 UserLeave();
1081 END_CLEANUP;
1082 }
1083
1084
1085 /*
1086 * @implemented
1087 */
1088 #if 0
1089 BOOL
1090 APIENTRY
1091 NtUserSetCursorIconData(
1092 HANDLE Handle,
1093 HMODULE hModule,
1094 PUNICODE_STRING pstrResName,
1095 PICONINFO pIconInfo)
1096 {
1097 PCURICON_OBJECT CurIcon;
1098 PSURFACE psurfBmp;
1099 NTSTATUS Status = STATUS_SUCCESS;
1100 BOOL Ret = FALSE;
1101 DECLARE_RETURN(BOOL);
1102
1103 DPRINT("Enter NtUserSetCursorIconData\n");
1104 UserEnterExclusive();
1105
1106 if (!(CurIcon = UserGetCurIconObject(Handle)))
1107 {
1108 RETURN(FALSE);
1109 }
1110
1111 CurIcon->hModule = hModule;
1112 CurIcon->hRsrc = NULL; //hRsrc;
1113 CurIcon->hGroupRsrc = NULL; //hGroupRsrc;
1114
1115 _SEH2_TRY
1116 {
1117 ProbeForRead(pIconInfo, sizeof(ICONINFO), 1);
1118 RtlCopyMemory(&CurIcon->IconInfo, pIconInfo, sizeof(ICONINFO));
1119
1120 CurIcon->IconInfo.hbmMask = BITMAP_CopyBitmap(pIconInfo->hbmMask);
1121 CurIcon->IconInfo.hbmColor = BITMAP_CopyBitmap(pIconInfo->hbmColor);
1122
1123 if (CurIcon->IconInfo.hbmColor)
1124 {
1125 if ((psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmColor)))
1126 {
1127 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
1128 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
1129 SURFACE_UnlockSurface(psurfBmp);
1130 GDIOBJ_SetOwnership(GdiHandleTable, CurIcon->IconInfo.hbmMask, NULL);
1131 }
1132 }
1133 if (CurIcon->IconInfo.hbmMask)
1134 {
1135 if (CurIcon->IconInfo.hbmColor == NULL)
1136 {
1137 if ((psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmMask)))
1138 {
1139 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
1140 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
1141 SURFACE_UnlockSurface(psurfBmp);
1142 }
1143 }
1144 GDIOBJ_SetOwnership(GdiHandleTable, CurIcon->IconInfo.hbmMask, NULL);
1145 }
1146 }
1147 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1148 {
1149 Status = _SEH2_GetExceptionCode();
1150 }
1151 _SEH2_END
1152
1153 if (!NT_SUCCESS(Status))
1154 SetLastNtError(Status);
1155 else
1156 Ret = TRUE;
1157
1158 UserDereferenceObject(CurIcon);
1159 RETURN(Ret);
1160
1161 CLEANUP:
1162 DPRINT("Leave NtUserSetCursorIconData, ret=%i\n",_ret_);
1163 UserLeave();
1164 END_CLEANUP;
1165 }
1166 #else
1167 BOOL
1168 APIENTRY
1169 NtUserSetCursorIconData(
1170 HANDLE hCurIcon,
1171 PBOOL fIcon,
1172 POINT *Hotspot,
1173 HMODULE hModule,
1174 HRSRC hRsrc,
1175 HRSRC hGroupRsrc)
1176 {
1177 PCURICON_OBJECT CurIcon;
1178 NTSTATUS Status;
1179 POINT SafeHotspot;
1180 BOOL Ret = FALSE;
1181 DECLARE_RETURN(BOOL);
1182
1183 DPRINT("Enter NtUserSetCursorIconData\n");
1184 UserEnterExclusive();
1185
1186 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
1187 {
1188 RETURN(FALSE);
1189 }
1190
1191 CurIcon->hModule = hModule;
1192 CurIcon->hRsrc = hRsrc;
1193 CurIcon->hGroupRsrc = hGroupRsrc;
1194
1195 /* Copy fields */
1196 if (fIcon)
1197 {
1198 Status = MmCopyFromCaller(&CurIcon->IconInfo.fIcon, fIcon, sizeof(BOOL));
1199 if (!NT_SUCCESS(Status))
1200 {
1201 SetLastNtError(Status);
1202 goto done;
1203 }
1204 }
1205 else
1206 {
1207 if (!Hotspot)
1208 Ret = TRUE;
1209 }
1210
1211 if (Hotspot)
1212 {
1213 Status = MmCopyFromCaller(&SafeHotspot, Hotspot, sizeof(POINT));
1214 if (NT_SUCCESS(Status))
1215 {
1216 CurIcon->IconInfo.xHotspot = SafeHotspot.x;
1217 CurIcon->IconInfo.yHotspot = SafeHotspot.y;
1218
1219 Ret = TRUE;
1220 }
1221 else
1222 SetLastNtError(Status);
1223 }
1224
1225 if (!fIcon && !Hotspot)
1226 {
1227 Ret = TRUE;
1228 }
1229
1230 done:
1231 if(Ret)
1232 {
1233 /* This icon is shared now */
1234 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmMask, NULL);
1235 if(CurIcon->IconInfo.hbmColor)
1236 {
1237 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmColor, NULL);
1238 }
1239 }
1240 UserDereferenceObject(CurIcon);
1241 RETURN(Ret);
1242
1243
1244 CLEANUP:
1245 DPRINT("Leave NtUserSetCursorIconData, ret=%i\n",_ret_);
1246 UserLeave();
1247 END_CLEANUP;
1248 }
1249 #endif
1250
1251 /*
1252 * @unimplemented
1253 */
1254 BOOL
1255 APIENTRY
1256 NtUserSetSystemCursor(
1257 HCURSOR hcur,
1258 DWORD id)
1259 {
1260 return FALSE;
1261 }
1262
1263 BOOL
1264 UserDrawIconEx(
1265 HDC hDc,
1266 INT xLeft,
1267 INT yTop,
1268 PCURICON_OBJECT pIcon,
1269 INT cxWidth,
1270 INT cyHeight,
1271 UINT istepIfAniCur,
1272 HBRUSH hbrFlickerFreeDraw,
1273 UINT diFlags)
1274 {
1275 BOOL Ret = FALSE;
1276 HBITMAP hbmMask, hbmColor;
1277 BITMAP bmpMask, bmpColor;
1278 BOOL DoFlickerFree;
1279 SIZE IconSize;
1280
1281 HDC hdcOff;
1282 HGDIOBJ hOldOffBrush = 0;
1283 HGDIOBJ hOldOffBmp = 0;
1284 HBITMAP hbmOff = 0;
1285 HDC hdcMask = 0;
1286 HGDIOBJ hOldMask = NULL;
1287 HDC hdcImage = 0;
1288 HGDIOBJ hOldImage = NULL;
1289 BOOL bAlpha = FALSE;
1290
1291 hbmMask = pIcon->IconInfo.hbmMask;
1292 hbmColor = pIcon->IconInfo.hbmColor;
1293
1294 if (istepIfAniCur)
1295 DPRINT1("NtUserDrawIconEx: istepIfAniCur is not supported!\n");
1296
1297 if (!hbmMask || !IntGdiGetObject(hbmMask, sizeof(BITMAP), (PVOID)&bmpMask))
1298 {
1299 return FALSE;
1300 }
1301
1302 if (hbmColor && !IntGdiGetObject(hbmColor, sizeof(BITMAP), (PVOID)&bmpColor))
1303 {
1304 return FALSE;
1305 }
1306
1307 if (hbmColor)
1308 {
1309 IconSize.cx = bmpColor.bmWidth;
1310 IconSize.cy = bmpColor.bmHeight;
1311 }
1312 else
1313 {
1314 IconSize.cx = bmpMask.bmWidth;
1315 IconSize.cy = bmpMask.bmHeight / 2;
1316 }
1317
1318 /* NtGdiCreateCompatibleBitmap will create a monochrome bitmap
1319 when cxWidth or cyHeight is 0 */
1320 if ((bmpColor.bmBitsPixel == 32) && (cxWidth != 0) && (cyHeight != 0))
1321 {
1322 SURFACE *psurfOff = NULL;
1323 PFN_DIB_GetPixel fnSource_GetPixel = NULL;
1324 INT x, y;
1325
1326 /* In order to correctly display 32 bit icons Windows first scans the image,
1327 because information about transparency is not stored in any image's headers */
1328 psurfOff = SURFACE_LockSurface(hbmColor ? hbmColor : hbmMask);
1329 if (psurfOff)
1330 {
1331 fnSource_GetPixel = DibFunctionsForBitmapFormat[psurfOff->SurfObj.iBitmapFormat].DIB_GetPixel;
1332 if (fnSource_GetPixel)
1333 {
1334 for (x = 0; x < psurfOff->SurfObj.sizlBitmap.cx; x++)
1335 {
1336 for (y = 0; y < psurfOff->SurfObj.sizlBitmap.cy; y++)
1337 {
1338 bAlpha = ((BYTE)(fnSource_GetPixel(&psurfOff->SurfObj, x, y) >> 24) & 0xff);
1339 if (bAlpha)
1340 break;
1341 }
1342 if (bAlpha)
1343 break;
1344 }
1345 }
1346 SURFACE_UnlockSurface(psurfOff);
1347 }
1348 }
1349
1350 if (!diFlags)
1351 diFlags = DI_NORMAL;
1352
1353 if (!cxWidth)
1354 cxWidth = ((diFlags & DI_DEFAULTSIZE) ?
1355 UserGetSystemMetrics(SM_CXICON) : IconSize.cx);
1356
1357 if (!cyHeight)
1358 cyHeight = ((diFlags & DI_DEFAULTSIZE) ?
1359 UserGetSystemMetrics(SM_CYICON) : IconSize.cy);
1360
1361 DoFlickerFree = (hbrFlickerFreeDraw &&
1362 (GDI_HANDLE_GET_TYPE(hbrFlickerFreeDraw) == GDI_OBJECT_TYPE_BRUSH));
1363
1364 if (DoFlickerFree || bAlpha)
1365 {
1366 RECTL r;
1367 BITMAP bm;
1368 SURFACE *psurfOff = NULL;
1369
1370 r.right = cxWidth;
1371 r.bottom = cyHeight;
1372
1373 hdcOff = NtGdiCreateCompatibleDC(hDc);
1374 if (!hdcOff)
1375 {
1376 DPRINT1("NtGdiCreateCompatibleDC() failed!\n");
1377 return FALSE;
1378 }
1379
1380 hbmOff = NtGdiCreateCompatibleBitmap(hDc, cxWidth, cyHeight);
1381 if (!hbmOff)
1382 {
1383 DPRINT1("NtGdiCreateCompatibleBitmap() failed!\n");
1384 goto cleanup;
1385 }
1386
1387 /* make sure we have a 32 bit offscreen bitmap
1388 otherwise we can't do alpha blending */
1389 psurfOff = SURFACE_LockSurface(hbmOff);
1390 if (psurfOff == NULL)
1391 {
1392 DPRINT1("BITMAPOBJ_LockBitmap() failed!\n");
1393 goto cleanup;
1394 }
1395 BITMAP_GetObject(psurfOff, sizeof(BITMAP), (PVOID)&bm);
1396
1397 if (bm.bmBitsPixel != 32)
1398 bAlpha = FALSE;
1399
1400 SURFACE_UnlockSurface(psurfOff);
1401
1402 hOldOffBmp = NtGdiSelectBitmap(hdcOff, hbmOff);
1403 if (!hOldOffBmp)
1404 {
1405 DPRINT1("NtGdiSelectBitmap() failed!\n");
1406 goto cleanup;
1407 }
1408
1409 if (DoFlickerFree)
1410 {
1411 hOldOffBrush = NtGdiSelectBrush(hdcOff, hbrFlickerFreeDraw);
1412 if (!hOldOffBrush)
1413 {
1414 DPRINT1("NtGdiSelectBrush() failed!\n");
1415 goto cleanup;
1416 }
1417
1418 NtGdiPatBlt(hdcOff, 0, 0, r.right, r.bottom, PATCOPY);
1419 }
1420 }
1421 else
1422 hdcOff = hDc;
1423
1424 if (diFlags & DI_IMAGE)
1425 {
1426 hdcImage = NtGdiCreateCompatibleDC(hDc);
1427 if (!hdcImage)
1428 {
1429 DPRINT1("NtGdiCreateCompatibleDC() failed!\n");
1430 goto cleanup;
1431 }
1432 hOldImage = NtGdiSelectBitmap(hdcImage, (hbmColor ? hbmColor : hbmMask));
1433 if (!hOldImage)
1434 {
1435 DPRINT("NtGdiSelectBitmap() failed!\n");
1436 goto cleanup;
1437 }
1438 }
1439
1440 /* If DI_IMAGE flag is specified and hbmMask exists, then always use mask for drawing */
1441 if (diFlags & DI_MASK || (diFlags & DI_IMAGE && hbmMask))
1442 {
1443 hdcMask = NtGdiCreateCompatibleDC(hDc);
1444 if (!hdcMask)
1445 {
1446 DPRINT1("NtGdiCreateCompatibleDC() failed!\n");
1447 goto cleanup;
1448 }
1449
1450 hOldMask = NtGdiSelectBitmap(hdcMask, hbmMask);
1451 if (!hOldMask)
1452 {
1453 DPRINT("NtGdiSelectBitmap() failed!\n");
1454 goto cleanup;
1455 }
1456 }
1457
1458 if (hdcMask || hdcImage)
1459 {
1460 GreStretchBltMask(hdcOff,
1461 (DoFlickerFree || bAlpha) ? 0 : xLeft,
1462 (DoFlickerFree || bAlpha) ? 0 : yTop,
1463 cxWidth,
1464 cyHeight,
1465 hdcImage ? hdcImage : hdcMask,
1466 0,
1467 0,
1468 IconSize.cx,
1469 IconSize.cy,
1470 SRCCOPY,
1471 0,
1472 hdcMask,
1473 0,
1474 hdcImage ? 0 : IconSize.cy);
1475 }
1476
1477 if (hOldMask) NtGdiSelectBitmap(hdcMask, hOldMask);
1478 if (hOldImage) NtGdiSelectBitmap(hdcImage, hOldImage);
1479 if (hdcImage) NtGdiDeleteObjectApp(hdcImage);
1480 if (hdcMask) NtGdiDeleteObjectApp(hdcMask);
1481
1482 if (bAlpha)
1483 {
1484 BITMAP bm;
1485 SURFACE *psurfOff = NULL;
1486 PBYTE pBits = NULL;
1487 BLENDFUNCTION BlendFunc;
1488 DWORD Pixel;
1489 BYTE Red, Green, Blue, Alpha;
1490 DWORD Count = 0;
1491 INT i, j;
1492
1493 psurfOff = SURFACE_LockSurface(hbmOff);
1494 if (psurfOff == NULL)
1495 {
1496 DPRINT1("BITMAPOBJ_LockBitmap() failed!\n");
1497 goto cleanup;
1498 }
1499 BITMAP_GetObject(psurfOff, sizeof(BITMAP), (PVOID)&bm);
1500
1501 pBits = ExAllocatePoolWithTag(PagedPool, bm.bmWidthBytes * abs(bm.bmHeight), TAG_BITMAP);
1502 if (pBits == NULL)
1503 {
1504 DPRINT1("ExAllocatePoolWithTag() failed!\n");
1505 SURFACE_UnlockSurface(psurfOff);
1506 goto cleanup;
1507 }
1508
1509 /* get icon bits */
1510 IntGetBitmapBits(psurfOff, bm.bmWidthBytes * abs(bm.bmHeight), pBits);
1511
1512 /* premultiply with the alpha channel value */
1513 for (i = 0; i < cyHeight; i++)
1514 {
1515 for (j = 0; j < cxWidth; j++)
1516 {
1517 Pixel = *(DWORD *)(pBits + Count);
1518
1519 Alpha = ((BYTE)(Pixel >> 24) & 0xff);
1520
1521 Red = (((BYTE)(Pixel >> 0)) * Alpha) / 0xff;
1522 Green = (((BYTE)(Pixel >> 8)) * Alpha) / 0xff;
1523 Blue = (((BYTE)(Pixel >> 16)) * Alpha) / 0xff;
1524
1525 *(DWORD *)(pBits + Count) = (DWORD)(Red | (Green << 8) | (Blue << 16) | (Alpha << 24));
1526
1527 Count += sizeof(DWORD);
1528 }
1529 }
1530
1531 /* set icon bits */
1532 IntSetBitmapBits(psurfOff, bm.bmWidthBytes * abs(bm.bmHeight), pBits);
1533 ExFreePoolWithTag(pBits, TAG_BITMAP);
1534
1535 SURFACE_UnlockSurface(psurfOff);
1536
1537 BlendFunc.BlendOp = AC_SRC_OVER;
1538 BlendFunc.BlendFlags = 0;
1539 BlendFunc.SourceConstantAlpha = 255;
1540 BlendFunc.AlphaFormat = AC_SRC_ALPHA;
1541
1542 NtGdiAlphaBlend(hDc, xLeft, yTop, cxWidth, cyHeight,
1543 hdcOff, 0, 0, cxWidth, cyHeight, BlendFunc, 0);
1544 }
1545 else if (DoFlickerFree)
1546 {
1547 NtGdiBitBlt(hDc, xLeft, yTop, cxWidth,
1548 cyHeight, hdcOff, 0, 0, SRCCOPY, 0, 0);
1549 }
1550
1551 Ret = TRUE;
1552
1553 cleanup:
1554 if (DoFlickerFree || bAlpha)
1555 {
1556 if (hOldOffBmp) NtGdiSelectBitmap(hdcOff, hOldOffBmp);
1557 if (hOldOffBrush) NtGdiSelectBrush(hdcOff, hOldOffBrush);
1558 if (hbmOff) GreDeleteObject(hbmOff);
1559 if (hdcOff) NtGdiDeleteObjectApp(hdcOff);
1560 }
1561
1562 return Ret;
1563 }
1564
1565 /*
1566 * @implemented
1567 */
1568 BOOL
1569 APIENTRY
1570 NtUserDrawIconEx(
1571 HDC hdc,
1572 int xLeft,
1573 int yTop,
1574 HICON hIcon,
1575 int cxWidth,
1576 int cyHeight,
1577 UINT istepIfAniCur,
1578 HBRUSH hbrFlickerFreeDraw,
1579 UINT diFlags,
1580 BOOL bMetaHDC, // When TRUE, GDI functions need to be handled in User32!
1581 PVOID pDIXData)
1582 {
1583 PCURICON_OBJECT pIcon;
1584 BOOL Ret;
1585
1586 DPRINT("Enter NtUserDrawIconEx\n");
1587 UserEnterExclusive();
1588
1589 if (!(pIcon = UserGetCurIconObject(hIcon)))
1590 {
1591 DPRINT1("UserGetCurIconObject() failed!\n");
1592 UserLeave();
1593 return FALSE;
1594 }
1595
1596 Ret = UserDrawIconEx(hdc,
1597 xLeft,
1598 yTop,
1599 pIcon,
1600 cxWidth,
1601 cyHeight,
1602 istepIfAniCur,
1603 hbrFlickerFreeDraw,
1604 diFlags);
1605
1606 UserDereferenceObject(pIcon);
1607
1608 UserLeave();
1609 return Ret;
1610 }
1611