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