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