[WIN32K]
[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 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 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmMask, NULL);
526 if(CurIcon->IconInfo.hbmColor)
527 {
528 CurIcon->IconInfo.hbmColor = BITMAP_CopyBitmap(CurIcon->IconInfo.hbmColor);
529 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmColor, NULL);
530 }
531 }
532 else
533 {
534 if (CurIcon->IconInfo.hbmColor &&
535 (psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmColor)))
536 {
537 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
538 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
539 SURFACE_UnlockSurface(psurfBmp);
540 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmColor, NULL);
541 }
542 if (CurIcon->IconInfo.hbmMask &&
543 (psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmMask)))
544 {
545 if(!CurIcon->IconInfo.hbmColor)
546 {
547 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
548 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy*2;
549 }
550 SURFACE_UnlockSurface(psurfBmp);
551 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmMask, NULL);
552 }
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);
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 SIZE IconSize;
1297 INT iOldBkColor = 0, iOldTxtColor = 0;
1298
1299 HDC hMemDC, hOffDC = NULL;
1300 HGDIOBJ hOldOffBrush = 0;
1301 HGDIOBJ hOldOffBmp = 0;
1302 HBITMAP hTmpBmp = 0, hOffBmp = 0;
1303 BOOL bAlpha = FALSE;
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 if (hbmColor)
1328 {
1329 IconSize.cx = bmpColor.bmWidth;
1330 IconSize.cy = bmpColor.bmHeight;
1331 }
1332 else /* take it from mask */
1333 {
1334 IconSize.cx = bm.bmWidth;
1335 IconSize.cy = bm.bmHeight/2;
1336 }
1337
1338 if (!diFlags)
1339 diFlags = DI_NORMAL;
1340
1341 /* NtGdiCreateCompatibleBitmap will create a monochrome bitmap
1342 when cxWidth or cyHeight is 0 */
1343 if (hbmColor
1344 && (bmpColor.bmBitsPixel == 32)
1345 && (cxWidth != 0)
1346 && (cyHeight != 0)
1347 && (diFlags & DI_IMAGE))
1348 {
1349 SURFACE *psurfOff = NULL;
1350 PFN_DIB_GetPixel fnSource_GetPixel = NULL;
1351 INT x, y;
1352
1353 /* In order to correctly display 32 bit icons Windows first scans the image,
1354 because information about transparency is not stored in any image's headers */
1355 psurfOff = SURFACE_LockSurface(hbmColor);
1356 if (psurfOff)
1357 {
1358 fnSource_GetPixel = DibFunctionsForBitmapFormat[psurfOff->SurfObj.iBitmapFormat].DIB_GetPixel;
1359 if (fnSource_GetPixel)
1360 {
1361 for (x = 0; x < psurfOff->SurfObj.sizlBitmap.cx; x++)
1362 {
1363 for (y = 0; y < psurfOff->SurfObj.sizlBitmap.cy; y++)
1364 {
1365 bAlpha = ((BYTE)(fnSource_GetPixel(&psurfOff->SurfObj, x, y) >> 24) & 0xff);
1366 if (bAlpha)
1367 break;
1368 }
1369 if (bAlpha)
1370 break;
1371 }
1372 }
1373 SURFACE_UnlockSurface(psurfOff);
1374 }
1375 }
1376
1377 if (!cxWidth)
1378 cxWidth = ((diFlags & DI_DEFAULTSIZE) ?
1379 UserGetSystemMetrics(SM_CXICON) : IconSize.cx);
1380
1381 if (!cyHeight)
1382 cyHeight = ((diFlags & DI_DEFAULTSIZE) ?
1383 UserGetSystemMetrics(SM_CYICON) : IconSize.cy);
1384
1385 DoFlickerFree = (hbrFlickerFreeDraw &&
1386 (GDI_HANDLE_GET_TYPE(hbrFlickerFreeDraw) == GDI_OBJECT_TYPE_BRUSH));
1387
1388 if (DoFlickerFree)
1389 {
1390 hOffDC = NtGdiCreateCompatibleDC(hDc);
1391 if(!hOffDC)
1392 {
1393 DPRINT1("NtGdiCreateCompatibleBitmap failed!\n");
1394 Ret = FALSE;
1395 goto Cleanup ;
1396 }
1397 hOffBmp = NtGdiCreateCompatibleBitmap(hDc, cxWidth, cyHeight);
1398 if(!hOffBmp)
1399 {
1400 DPRINT1("NtGdiCreateCompatibleBitmap failed!\n");
1401 goto Cleanup ;
1402 }
1403 hOldOffBmp = NtGdiSelectBitmap(hOffDC, hOffBmp);
1404 hOldOffBrush = NtGdiSelectBrush(hOffDC, hbrFlickerFreeDraw);
1405 NtGdiPatBlt(hOffDC, 0, 0, cxWidth, cyHeight, PATCOPY);
1406 NtGdiSelectBrush(hOffDC, hOldOffBrush);
1407 }
1408 else
1409 {
1410 /* Set Background/foreground colors */
1411 iOldTxtColor = IntGdiSetTextColor(hDc, 0); //black
1412 iOldBkColor = IntGdiSetBkColor(hDc, 0x00FFFFFF); //white
1413 }
1414
1415
1416 if (hbmMask && (diFlags & DI_MASK) && !bAlpha)
1417 {
1418 hTmpBmp = NtGdiSelectBitmap(hMemDC, hbmMask);
1419 NtGdiStretchBlt(hOffDC ? hOffDC : hDc,
1420 hOffDC ? 0 : xLeft,
1421 hOffDC ? 0 : yTop,
1422 cxWidth,
1423 cyHeight,
1424 hMemDC,
1425 0,
1426 0,
1427 IconSize.cx,
1428 IconSize.cy,
1429 SRCAND,
1430 0);
1431 NtGdiSelectBitmap(hMemDC, hTmpBmp);
1432 }
1433
1434 if(diFlags & DI_IMAGE)
1435 {
1436 if (bAlpha)
1437 {
1438 BLENDFUNCTION pixelblend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
1439 DWORD Pixel;
1440 BYTE Red, Green, Blue, Alpha;
1441 DWORD Count = 0;
1442 INT i, j;
1443 PSURFACE psurf;
1444 PBYTE pBits ;
1445 HBITMAP hMemBmp = NULL;
1446
1447 pBits = ExAllocatePoolWithTag(PagedPool,
1448 bmpColor.bmWidthBytes * abs(bmpColor.bmHeight),
1449 TAG_BITMAP);
1450 if (pBits == NULL)
1451 {
1452 Ret = FALSE;
1453 goto CleanupAlpha;
1454 }
1455
1456 hMemBmp = BITMAP_CopyBitmap(hbmColor);
1457 if(!hMemBmp)
1458 {
1459 DPRINT1("BITMAP_CopyBitmap failed!");
1460 goto CleanupAlpha;
1461 }
1462
1463 psurf = SURFACE_LockSurface(hMemBmp);
1464 if(!psurf)
1465 {
1466 DPRINT1("SURFACE_LockSurface failed!\n");
1467 goto CleanupAlpha;
1468 }
1469 /* get color bits */
1470 IntGetBitmapBits(psurf,
1471 bmpColor.bmWidthBytes * abs(bmpColor.bmHeight),
1472 pBits);
1473
1474 /* premultiply with the alpha channel value */
1475 for (i = 0; i < cyHeight; i++)
1476 {
1477 for (j = 0; j < cxWidth; j++)
1478 {
1479 Pixel = *(DWORD *)(pBits + Count);
1480
1481 Alpha = ((BYTE)(Pixel >> 24) & 0xff);
1482
1483 Red = (((BYTE)(Pixel >> 0)) * Alpha) / 0xff;
1484 Green = (((BYTE)(Pixel >> 8)) * Alpha) / 0xff;
1485 Blue = (((BYTE)(Pixel >> 16)) * Alpha) / 0xff;
1486
1487 *(DWORD *)(pBits + Count) = (DWORD)(Red | (Green << 8) | (Blue << 16) | (Alpha << 24));
1488
1489 Count += sizeof(DWORD);
1490 }
1491 }
1492
1493 /* set mem bits */
1494 IntSetBitmapBits(psurf,
1495 bmpColor.bmWidthBytes * abs(bmpColor.bmHeight),
1496 pBits);
1497 SURFACE_UnlockSurface(psurf);
1498
1499 hTmpBmp = NtGdiSelectBitmap(hMemDC, hMemBmp);
1500
1501 NtGdiAlphaBlend(hOffDC ? hOffDC : hDc,
1502 hOffDC ? 0 : xLeft,
1503 hOffDC ? 0 : yTop,
1504 cxWidth,
1505 cyHeight,
1506 hMemDC,
1507 0,
1508 0,
1509 IconSize.cx,
1510 IconSize.cy,
1511 pixelblend,
1512 NULL);
1513 NtGdiSelectBitmap(hMemDC, hTmpBmp);
1514 CleanupAlpha:
1515 if(pBits) ExFreePoolWithTag(pBits, TAG_BITMAP);
1516 if(hMemBmp) NtGdiDeleteObjectApp(hMemBmp);
1517 }
1518 else if (hbmColor)
1519 {
1520 DWORD rop = (diFlags & DI_MASK) ? SRCINVERT : SRCCOPY ;
1521 hTmpBmp = NtGdiSelectBitmap(hMemDC, hbmColor);
1522 NtGdiStretchBlt(hOffDC ? hOffDC : hDc,
1523 hOffDC ? 0 : xLeft,
1524 hOffDC ? 0 : yTop,
1525 cxWidth,
1526 cyHeight,
1527 hMemDC,
1528 0,
1529 0,
1530 IconSize.cx,
1531 IconSize.cy,
1532 rop,
1533 0);
1534 NtGdiSelectBitmap(hMemDC, hTmpBmp);
1535 }
1536 }
1537
1538 if(hOffDC)
1539 {
1540 NtGdiBitBlt(hDc, xLeft, yTop, cxWidth, cyHeight, hOffDC, 0, 0, SRCCOPY, 0, 0);
1541 }
1542 else
1543 {
1544 IntGdiSetBkColor(hDc, iOldBkColor);
1545 IntGdiSetTextColor(hDc, iOldTxtColor);
1546 }
1547
1548 Ret = TRUE ;
1549
1550 Cleanup:
1551 NtGdiDeleteObjectApp(hMemDC);
1552 if(hOldOffBmp) NtGdiSelectBitmap(hOffDC, hOldOffBmp);
1553 if(hOffDC) NtGdiDeleteObjectApp(hOffDC);
1554 if(hOffBmp) NtGdiDeleteObjectApp(hOffBmp);
1555
1556 return Ret;
1557 }
1558
1559 /*
1560 * @implemented
1561 */
1562 BOOL
1563 APIENTRY
1564 NtUserDrawIconEx(
1565 HDC hdc,
1566 int xLeft,
1567 int yTop,
1568 HICON hIcon,
1569 int cxWidth,
1570 int cyHeight,
1571 UINT istepIfAniCur,
1572 HBRUSH hbrFlickerFreeDraw,
1573 UINT diFlags,
1574 BOOL bMetaHDC, // When TRUE, GDI functions need to be handled in User32!
1575 PVOID pDIXData)
1576 {
1577 PCURICON_OBJECT pIcon;
1578 BOOL Ret;
1579
1580 DPRINT("Enter NtUserDrawIconEx\n");
1581 UserEnterExclusive();
1582
1583 if (!(pIcon = UserGetCurIconObject(hIcon)))
1584 {
1585 DPRINT1("UserGetCurIconObject() failed!\n");
1586 UserLeave();
1587 return FALSE;
1588 }
1589
1590 Ret = UserDrawIconEx(hdc,
1591 xLeft,
1592 yTop,
1593 pIcon,
1594 cxWidth,
1595 cyHeight,
1596 istepIfAniCur,
1597 hbrFlickerFreeDraw,
1598 diFlags);
1599
1600 UserDereferenceObject(pIcon);
1601
1602 UserLeave();
1603 return Ret;
1604 }
1605