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