- Less STDCALL, more WINAPI/NTAPI/APIENTRY
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / cursoricon.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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 <w32k.h>
40
41 #define NDEBUG
42 #include <debug.h>
43
44 static PAGED_LOOKASIDE_LIST gProcessLookasideList;
45 static LIST_ENTRY gCurIconList;
46
47 /* Look up the location of the cursor in the GDIDEVICE structure
48 * when all we know is the window station object
49 * Actually doesn't use the window station, but should... */
50 BOOL FASTCALL
51 IntGetCursorLocation(PWINSTATION_OBJECT WinSta, POINT *loc)
52 {
53 HDC hDC;
54 PDC dc;
55 GDIDEVICE *GDIDevice;
56
57 #if 1
58 /* FIXME - get the screen dc from the window station or desktop */
59 if (!(hDC = IntGetScreenDC()))
60 return FALSE;
61 #endif
62
63 if (!(dc = DC_LockDc(hDC)))
64 return FALSE;
65 GDIDevice = (GDIDEVICE *)dc->pPDev;
66 DC_UnlockDc(dc);
67
68 loc->x = GDIDevice->Pointer.Pos.x;
69 loc->y = GDIDevice->Pointer.Pos.y;
70
71 return TRUE;
72 }
73
74 /* This function creates a reference for the object! */
75 PCURICON_OBJECT FASTCALL UserGetCurIconObject(HCURSOR hCurIcon)
76 {
77 PCURICON_OBJECT CurIcon;
78
79 if (!hCurIcon)
80 {
81 SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
82 return NULL;
83 }
84
85 CurIcon = (PCURICON_OBJECT)UserReferenceObjectByHandle(hCurIcon, otCursorIcon);
86 if (!CurIcon)
87 {
88 /* we never set ERROR_INVALID_ICON_HANDLE. lets hope noone ever checks for it */
89 SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
90 return NULL;
91 }
92
93 ASSERT(USER_BODY_TO_HEADER(CurIcon)->RefCount >= 1);
94 return CurIcon;
95 }
96
97
98 #define COLORCURSORS_ALLOWED FALSE
99 HCURSOR FASTCALL
100 IntSetCursor(PWINSTATION_OBJECT WinSta, PCURICON_OBJECT NewCursor,
101 BOOL ForceChange)
102 {
103 BITMAPOBJ *BitmapObj;
104 SURFOBJ *SurfObj;
105 PDEVINFO DevInfo;
106 PBITMAPOBJ MaskBmpObj = NULL;
107 PSYSTEM_CURSORINFO CurInfo;
108 PCURICON_OBJECT OldCursor;
109 HCURSOR Ret = (HCURSOR)0;
110 HBITMAP dcbmp;
111 HBITMAP hMask = 0;
112 SURFOBJ *soMask = NULL, *soColor = NULL;
113 XLATEOBJ *XlateObj = NULL;
114 HDC Screen;
115 PDC dc;
116
117 CurInfo = IntGetSysCursorInfo(WinSta);
118 OldCursor = CurInfo->CurrentCursorObject;
119 if (OldCursor)
120 {
121 Ret = (HCURSOR)OldCursor->Self;
122 }
123
124 if (!ForceChange && OldCursor == NewCursor)
125 {
126 return Ret;
127 }
128
129 if(!(Screen = IntGetScreenDC()))
130 {
131 return (HCURSOR)0;
132 }
133 /* FIXME use the desktop's HDC instead of using ScreenDeviceContext */
134 dc = DC_LockDc(Screen);
135
136 if (!dc)
137 {
138 return Ret;
139 }
140 dcbmp = dc->w.hBitmap;
141 DevInfo = (PDEVINFO)&((GDIDEVICE *)dc->pPDev)->DevInfo;
142 DC_UnlockDc(dc);
143
144 BitmapObj = BITMAPOBJ_LockBitmap(dcbmp);
145 if (!BitmapObj)
146 return (HCURSOR)0;
147 SurfObj = &BitmapObj->SurfObj;
148
149 if (!NewCursor)
150 {
151 if (CurInfo->CurrentCursorObject || ForceChange)
152 {
153 if (CurInfo->CurrentCursorObject)
154 {
155 UserDereferenceObject(CurInfo->CurrentCursorObject);
156 if (CurInfo->ShowingCursor)
157 {
158 DPRINT1("Removing pointer!\n");
159 /* Remove the cursor if it was displayed */
160 IntEngMovePointer(SurfObj, -1, -1, &GDIDEV(SurfObj)->Pointer.Exclude);
161 }
162 }
163
164 GDIDEV(SurfObj)->Pointer.Status = SPS_ACCEPT_NOEXCLUDE;
165
166 CurInfo->CurrentCursorObject = NewCursor; /* i.e. CurrentCursorObject = NULL */
167 CurInfo->ShowingCursor = 0;
168 }
169
170 BITMAPOBJ_UnlockBitmap(BitmapObj);
171 return Ret;
172 }
173
174 /* TODO: Fixme. Logic is screwed above */
175
176 MaskBmpObj = BITMAPOBJ_LockBitmap(NewCursor->IconInfo.hbmMask);
177 if (MaskBmpObj)
178 {
179 const int maskBpp = BitsPerFormat(MaskBmpObj->SurfObj.iBitmapFormat);
180 BITMAPOBJ_UnlockBitmap(MaskBmpObj);
181 if (maskBpp != 1)
182 {
183 DPRINT1("SetCursor: The Mask bitmap must have 1BPP!\n");
184 BITMAPOBJ_UnlockBitmap(BitmapObj);
185 return Ret;
186 }
187
188 if ((DevInfo->flGraphicsCaps2 & GCAPS2_ALPHACURSOR) &&
189 SurfObj->iBitmapFormat >= BMF_16BPP &&
190 SurfObj->iBitmapFormat <= BMF_32BPP &&
191 NewCursor->Shadow && COLORCURSORS_ALLOWED)
192 {
193 /* FIXME - Create a color pointer, only 32bit bitmap, set alpha bits!
194 Do not pass a mask bitmap to DrvSetPointerShape()!
195 Create a XLATEOBJ that describes the colors of the bitmap. */
196 DPRINT1("SetCursor: (Colored) alpha cursors are not supported!\n");
197 }
198 else
199 {
200 if(NewCursor->IconInfo.hbmColor
201 && COLORCURSORS_ALLOWED)
202 {
203 /* FIXME - Create a color pointer, create only one 32bit bitmap!
204 Do not pass a mask bitmap to DrvSetPointerShape()!
205 Create a XLATEOBJ that describes the colors of the bitmap.
206 (16bit bitmaps are propably allowed) */
207 DPRINT1("SetCursor: Cursors with colors are not supported!\n");
208 }
209 else
210 {
211 MaskBmpObj = BITMAPOBJ_LockBitmap(NewCursor->IconInfo.hbmMask);
212 if(MaskBmpObj)
213 {
214 RECTL DestRect = {0, 0, MaskBmpObj->SurfObj.sizlBitmap.cx, MaskBmpObj->SurfObj.sizlBitmap.cy};
215 POINTL SourcePoint = {0, 0};
216
217 /*
218 * NOTE: For now we create the cursor in top-down bitmap,
219 * because VMware driver rejects it otherwise. This should
220 * be fixed later.
221 */
222 hMask = EngCreateBitmap(
223 MaskBmpObj->SurfObj.sizlBitmap, abs(MaskBmpObj->SurfObj.lDelta),
224 MaskBmpObj->SurfObj.iBitmapFormat, BMF_TOPDOWN,
225 NULL);
226 if ( !hMask )
227 {
228 BITMAPOBJ_UnlockBitmap(MaskBmpObj);
229 BITMAPOBJ_UnlockBitmap(BitmapObj);
230 return (HCURSOR)0;
231 }
232 soMask = EngLockSurface((HSURF)hMask);
233 EngCopyBits(soMask, &MaskBmpObj->SurfObj, NULL, NULL,
234 &DestRect, &SourcePoint);
235 BITMAPOBJ_UnlockBitmap(MaskBmpObj);
236 }
237 }
238 }
239 CurInfo->ShowingCursor = CURSOR_SHOWING;
240 CurInfo->CurrentCursorObject = NewCursor;
241 UserReferenceObject(NewCursor);
242 }
243 else
244 {
245 CurInfo->ShowingCursor = 0;
246 CurInfo->CurrentCursorObject = NULL;
247 }
248
249 /* OldCursor is not in use anymore */
250 if (OldCursor)
251 {
252 UserDereferenceObject(OldCursor);
253 }
254
255 if (GDIDEVFUNCS(SurfObj).SetPointerShape)
256 {
257 GDIDEV(SurfObj)->Pointer.Status =
258 GDIDEVFUNCS(SurfObj).SetPointerShape(
259 SurfObj, soMask, soColor, XlateObj,
260 NewCursor->IconInfo.xHotspot,
261 NewCursor->IconInfo.yHotspot,
262 GDIDEV(SurfObj)->Pointer.Pos.x,
263 GDIDEV(SurfObj)->Pointer.Pos.y,
264 &(GDIDEV(SurfObj)->Pointer.Exclude),
265 SPS_CHANGE);
266 DPRINT("SetCursor: DrvSetPointerShape() returned %x\n",
267 GDIDEV(SurfObj)->Pointer.Status);
268 }
269 else
270 {
271 GDIDEV(SurfObj)->Pointer.Status = SPS_DECLINE;
272 }
273
274 if(GDIDEV(SurfObj)->Pointer.Status == SPS_DECLINE)
275 {
276 GDIDEV(SurfObj)->Pointer.Status = EngSetPointerShape(
277 SurfObj, soMask, soColor, XlateObj,
278 NewCursor->IconInfo.xHotspot,
279 NewCursor->IconInfo.yHotspot,
280 GDIDEV(SurfObj)->Pointer.Pos.x,
281 GDIDEV(SurfObj)->Pointer.Pos.y,
282 &(GDIDEV(SurfObj)->Pointer.Exclude),
283 SPS_CHANGE);
284 GDIDEV(SurfObj)->Pointer.MovePointer = NULL;
285 }
286 else
287 {
288 GDIDEV(SurfObj)->Pointer.MovePointer = GDIDEVFUNCS(SurfObj).MovePointer;
289 }
290
291 BITMAPOBJ_UnlockBitmap(BitmapObj);
292 if(hMask)
293 {
294 EngUnlockSurface(soMask);
295 EngDeleteSurface((HSURF)hMask);
296 }
297 if(XlateObj)
298 {
299 EngDeleteXlate(XlateObj);
300 }
301
302 if(GDIDEV(SurfObj)->Pointer.Status == SPS_ERROR)
303 DPRINT1("SetCursor: DrvSetPointerShape() returned SPS_ERROR\n");
304
305 return Ret;
306 }
307
308 BOOL FASTCALL
309 IntSetupCurIconHandles(PWINSTATION_OBJECT WinSta)
310 {
311 ExInitializePagedLookasideList(&gProcessLookasideList,
312 NULL,
313 NULL,
314 0,
315 sizeof(CURICON_PROCESS),
316 TAG_DIB,
317 128);
318 InitializeListHead(&gCurIconList);
319
320 return TRUE;
321 }
322
323 /*
324 * We have to register that this object is in use by the current
325 * process. The only way to do that seems to be to walk the list
326 * of cursor/icon objects starting at W32Process->CursorIconListHead.
327 * If the object is already present in the list, we don't have to do
328 * anything, if it's not present we add it and inc the ProcessCount
329 * in the object. Having to walk the list kind of sucks, but that's
330 * life...
331 */
332 static BOOLEAN FASTCALL
333 ReferenceCurIconByProcess(PCURICON_OBJECT CurIcon)
334 {
335 PW32PROCESS Win32Process;
336 PCURICON_PROCESS Current;
337
338 Win32Process = PsGetCurrentProcessWin32Process();
339
340 LIST_FOR_EACH(Current, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
341 {
342 if (Current->Process == Win32Process)
343 {
344 /* Already registered for this process */
345 return TRUE;
346 }
347 }
348
349 /* Not registered yet */
350 Current = ExAllocateFromPagedLookasideList(&gProcessLookasideList);
351 if (NULL == Current)
352 {
353 return FALSE;
354 }
355 InsertHeadList(&CurIcon->ProcessList, &Current->ListEntry);
356 Current->Process = Win32Process;
357
358 return TRUE;
359 }
360
361 PCURICON_OBJECT FASTCALL
362 IntFindExistingCurIconObject(PWINSTATION_OBJECT WinSta, HMODULE hModule,
363 HRSRC hRsrc, LONG cx, LONG cy)
364 {
365 PCURICON_OBJECT CurIcon;
366
367 LIST_FOR_EACH(CurIcon, &gCurIconList, CURICON_OBJECT, ListEntry)
368 {
369
370 // if(NT_SUCCESS(UserReferenceObjectByPointer(Object, otCursorIcon))) //<- huh????
371 // UserReferenceObject( CurIcon);
372 // {
373 if((CurIcon->hModule == hModule) && (CurIcon->hRsrc == hRsrc))
374 {
375 if(cx && ((cx != CurIcon->Size.cx) || (cy != CurIcon->Size.cy)))
376 {
377 // UserDereferenceObject(CurIcon);
378 continue;
379 }
380 if (! ReferenceCurIconByProcess(CurIcon))
381 {
382 return NULL;
383 }
384
385 return CurIcon;
386 }
387 // }
388 // UserDereferenceObject(CurIcon);
389
390 }
391
392 return NULL;
393 }
394
395 PCURICON_OBJECT FASTCALL
396 IntCreateCurIconHandle(PWINSTATION_OBJECT WinSta)
397 {
398 PCURICON_OBJECT CurIcon;
399 HANDLE hCurIcon;
400
401 CurIcon = UserCreateObject(gHandleTable, &hCurIcon, otCursorIcon, sizeof(CURICON_OBJECT));
402
403 if(!CurIcon)
404 {
405 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
406 return FALSE;
407 }
408
409 CurIcon->Self = hCurIcon;
410 InitializeListHead(&CurIcon->ProcessList);
411
412 if (! ReferenceCurIconByProcess(CurIcon))
413 {
414 DPRINT1("Failed to add process\n");
415 UserDeleteObject(hCurIcon, otCursorIcon);
416 UserDereferenceObject(CurIcon);
417 return NULL;
418 }
419
420 InsertHeadList(&gCurIconList, &CurIcon->ListEntry);
421
422 return CurIcon;
423 }
424
425 BOOLEAN FASTCALL
426 IntDestroyCurIconObject(PWINSTATION_OBJECT WinSta, PCURICON_OBJECT CurIcon, BOOL ProcessCleanup)
427 {
428 PSYSTEM_CURSORINFO CurInfo;
429 HBITMAP bmpMask, bmpColor;
430 BOOLEAN Ret;
431 PCURICON_PROCESS Current = NULL;
432 PW32PROCESS W32Process = PsGetCurrentProcessWin32Process();
433
434 /* Private objects can only be destroyed by their own process */
435 if (NULL == CurIcon->hModule)
436 {
437 ASSERT(CurIcon->ProcessList.Flink->Flink == &CurIcon->ProcessList);
438 Current = CONTAINING_RECORD(CurIcon->ProcessList.Flink, CURICON_PROCESS, ListEntry);
439 if (Current->Process != W32Process)
440 {
441 DPRINT1("Trying to destroy private icon/cursor of another process\n");
442 return FALSE;
443 }
444 }
445 else if (! ProcessCleanup)
446 {
447 DPRINT("Trying to destroy shared icon/cursor\n");
448 return FALSE;
449 }
450
451 /* Now find this process in the list of processes referencing this object and
452 remove it from that list */
453 LIST_FOR_EACH(Current, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
454 {
455 if (Current->Process == W32Process)
456 {
457 RemoveEntryList(&Current->ListEntry);
458 break;
459 }
460 }
461
462 ExFreeToPagedLookasideList(&gProcessLookasideList, Current);
463
464 /* If there are still processes referencing this object we can't destroy it yet */
465 if (! IsListEmpty(&CurIcon->ProcessList))
466 {
467 return TRUE;
468 }
469
470
471 if (! ProcessCleanup)
472 {
473 RemoveEntryList(&CurIcon->ListEntry);
474 }
475
476 CurInfo = IntGetSysCursorInfo(WinSta);
477
478 if (CurInfo->CurrentCursorObject == CurIcon)
479 {
480 /* Hide the cursor if we're destroying the current cursor */
481 IntSetCursor(WinSta, NULL, TRUE);
482 }
483
484 bmpMask = CurIcon->IconInfo.hbmMask;
485 bmpColor = CurIcon->IconInfo.hbmColor;
486
487 /* delete bitmaps */
488 if(bmpMask)
489 {
490 GDIOBJ_SetOwnership(bmpMask, PsGetCurrentProcess());
491 NtGdiDeleteObject(bmpMask);
492 CurIcon->IconInfo.hbmMask = NULL;
493 }
494 if(bmpColor)
495 {
496 GDIOBJ_SetOwnership(bmpColor, PsGetCurrentProcess());
497 NtGdiDeleteObject(bmpColor);
498 CurIcon->IconInfo.hbmColor = NULL;
499 }
500
501 /* We were given a pointer, no need to keep the reference anylonger! */
502 UserDereferenceObject(CurIcon);
503 Ret = UserDeleteObject(CurIcon->Self, otCursorIcon);
504
505 return Ret;
506 }
507
508 VOID FASTCALL
509 IntCleanupCurIcons(struct _EPROCESS *Process, PW32PROCESS Win32Process)
510 {
511 PWINSTATION_OBJECT WinSta;
512 PCURICON_OBJECT CurIcon, tmp;
513 PCURICON_PROCESS ProcessData;
514
515 WinSta = IntGetWinStaObj();
516 if(WinSta == NULL)
517 {
518 return;
519 }
520
521 LIST_FOR_EACH_SAFE(CurIcon, tmp, &gCurIconList, CURICON_OBJECT, ListEntry)
522 {
523 UserReferenceObject(CurIcon);
524 // if(NT_SUCCESS(UserReferenceObjectByPointer(Object, otCursorIcon)))
525 {
526 LIST_FOR_EACH(ProcessData, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
527 {
528 if (Win32Process == ProcessData->Process)
529 {
530 RemoveEntryList(&CurIcon->ListEntry);
531 IntDestroyCurIconObject(WinSta, CurIcon, TRUE);
532 CurIcon = NULL;
533 break;
534 }
535 }
536
537 // UserDereferenceObject(Object);
538 }
539
540 if (CurIcon)
541 {
542 UserDereferenceObject(CurIcon);
543 }
544 }
545
546 ObDereferenceObject(WinSta);
547 }
548
549 /*
550 * @implemented
551 */
552 HANDLE
553 APIENTRY
554 NtUserCreateCursorIconHandle(PICONINFO IconInfo OPTIONAL, BOOL Indirect)
555 {
556 PCURICON_OBJECT CurIcon;
557 PWINSTATION_OBJECT WinSta;
558 PBITMAPOBJ bmp;
559 NTSTATUS Status;
560 HANDLE Ret;
561 DECLARE_RETURN(HANDLE);
562
563 DPRINT("Enter NtUserCreateCursorIconHandle\n");
564 UserEnterExclusive();
565
566 WinSta = IntGetWinStaObj();
567 if(WinSta == NULL)
568 {
569 RETURN( (HANDLE)0);
570 }
571
572 if (!(CurIcon = IntCreateCurIconHandle(WinSta)))
573 {
574 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
575 ObDereferenceObject(WinSta);
576 RETURN( (HANDLE)0);
577 }
578
579 Ret = CurIcon->Self;
580
581 if(IconInfo)
582 {
583 Status = MmCopyFromCaller(&CurIcon->IconInfo, IconInfo, sizeof(ICONINFO));
584 if(NT_SUCCESS(Status))
585 {
586 if(Indirect)
587 {
588 CurIcon->IconInfo.hbmMask = BITMAPOBJ_CopyBitmap(CurIcon->IconInfo.hbmMask);
589 CurIcon->IconInfo.hbmColor = BITMAPOBJ_CopyBitmap(CurIcon->IconInfo.hbmColor);
590 }
591 if(CurIcon->IconInfo.hbmColor &&
592 (bmp = BITMAPOBJ_LockBitmap(CurIcon->IconInfo.hbmColor)))
593 {
594 CurIcon->Size.cx = bmp->SurfObj.sizlBitmap.cx;
595 CurIcon->Size.cy = bmp->SurfObj.sizlBitmap.cy;
596 BITMAPOBJ_UnlockBitmap(bmp);
597 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmColor, NULL);
598 }
599 if(CurIcon->IconInfo.hbmMask &&
600 (bmp = BITMAPOBJ_LockBitmap(CurIcon->IconInfo.hbmMask)))
601 {
602 if (CurIcon->IconInfo.hbmColor == NULL)
603 {
604 CurIcon->Size.cx = bmp->SurfObj.sizlBitmap.cx;
605 CurIcon->Size.cy = bmp->SurfObj.sizlBitmap.cy / 2;
606 }
607 BITMAPOBJ_UnlockBitmap(bmp);
608 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmMask, NULL);
609 }
610 }
611 else
612 {
613 SetLastNtError(Status);
614 /* FIXME - Don't exit here */
615 }
616 }
617
618 UserDereferenceObject(CurIcon);
619 ObDereferenceObject(WinSta);
620 RETURN( Ret);
621
622 CLEANUP:
623 DPRINT("Leave NtUserCreateCursorIconHandle, ret=%i\n",_ret_);
624 UserLeave();
625 END_CLEANUP;
626 }
627
628 /*
629 * @implemented
630 */
631 BOOL
632 APIENTRY
633 NtUserGetIconInfo(
634 HANDLE hCurIcon,
635 PICONINFO IconInfo,
636 PUNICODE_STRING lpInstName, // optional
637 PUNICODE_STRING lpResName, // optional
638 LPDWORD pbpp, // optional
639 BOOL bInternal)
640 {
641 ICONINFO ii;
642 PCURICON_OBJECT CurIcon;
643 PWINSTATION_OBJECT WinSta;
644 NTSTATUS Status = STATUS_SUCCESS;
645 BOOL Ret = FALSE;
646 DECLARE_RETURN(BOOL);
647
648 DPRINT("Enter NtUserGetIconInfo\n");
649 UserEnterExclusive();
650
651 if(!IconInfo)
652 {
653 SetLastWin32Error(ERROR_INVALID_PARAMETER);
654 RETURN(FALSE);
655 }
656
657 WinSta = IntGetWinStaObj();
658 if(WinSta == NULL)
659 {
660 RETURN( FALSE);
661 }
662
663 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
664 {
665 ObDereferenceObject(WinSta);
666 RETURN( FALSE);
667 }
668
669 RtlCopyMemory(&ii, &CurIcon->IconInfo, sizeof(ICONINFO));
670
671 /* Copy bitmaps */
672 ii.hbmMask = BITMAPOBJ_CopyBitmap(CurIcon->IconInfo.hbmMask);
673 ii.hbmColor = BITMAPOBJ_CopyBitmap(CurIcon->IconInfo.hbmColor);
674
675 /* Copy fields */
676 _SEH_TRY
677 {
678 ProbeForWrite(IconInfo, sizeof(ICONINFO), 1);
679 RtlCopyMemory(IconInfo, &ii, sizeof(ICONINFO));
680
681 if (pbpp)
682 {
683 PBITMAPOBJ bmp;
684 int colorBpp = 0;
685
686 ProbeForWrite(pbpp, sizeof(DWORD), 1);
687
688 bmp = BITMAPOBJ_LockBitmap(CurIcon->IconInfo.hbmColor);
689 if (bmp)
690 {
691 colorBpp = BitsPerFormat(bmp->SurfObj.iBitmapFormat);
692 BITMAPOBJ_UnlockBitmap(bmp);
693 }
694
695 RtlCopyMemory(pbpp, &colorBpp, sizeof(DWORD));
696 }
697
698 }
699 _SEH_HANDLE
700 {
701 Status = _SEH_GetExceptionCode();
702 }
703 _SEH_END
704
705 if (NT_SUCCESS(Status))
706 Ret = TRUE;
707 else
708 SetLastNtError(Status);
709
710 UserDereferenceObject(CurIcon);
711 ObDereferenceObject(WinSta);
712 RETURN( Ret);
713
714 CLEANUP:
715 DPRINT("Leave NtUserGetIconInfo, ret=%i\n",_ret_);
716 UserLeave();
717 END_CLEANUP;
718 }
719
720
721 /*
722 * @implemented
723 */
724 BOOL
725 APIENTRY
726 NtUserGetIconSize(
727 HANDLE hCurIcon,
728 UINT istepIfAniCur,
729 PLONG plcx, // &size.cx
730 PLONG plcy) // &size.cy
731 {
732 PCURICON_OBJECT CurIcon;
733 NTSTATUS Status = STATUS_SUCCESS;
734 BOOL bRet = FALSE;
735
736 DPRINT("Enter NtUserGetIconSize\n");
737 UserEnterExclusive();
738
739 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
740 {
741 goto cleanup;
742 }
743
744 _SEH_TRY
745 {
746 ProbeForWrite(plcx, sizeof(LONG), 1);
747 RtlCopyMemory(plcx, &CurIcon->Size.cx, sizeof(LONG));
748 ProbeForWrite(plcy, sizeof(LONG), 1);
749 RtlCopyMemory(plcy, &CurIcon->Size.cy, sizeof(LONG));
750 }
751 _SEH_HANDLE
752 {
753 Status = _SEH_GetExceptionCode();
754 }
755 _SEH_END
756
757 if(NT_SUCCESS(Status))
758 bRet = TRUE;
759 else
760 SetLastNtError(Status); // maybe not, test this
761
762 UserDereferenceObject(CurIcon);
763
764 cleanup:
765 DPRINT("Leave NtUserGetIconSize, ret=%i\n", bRet);
766 UserLeave();
767 return bRet;
768 }
769
770
771 /*
772 * @unimplemented
773 */
774 DWORD
775 APIENTRY
776 NtUserGetCursorFrameInfo(
777 DWORD Unknown0,
778 DWORD Unknown1,
779 DWORD Unknown2,
780 DWORD Unknown3)
781 {
782 UNIMPLEMENTED
783
784 return 0;
785 }
786
787
788 /*
789 * @implemented
790 */
791 BOOL
792 APIENTRY
793 NtUserGetCursorInfo(
794 PCURSORINFO pci)
795 {
796 CURSORINFO SafeCi;
797 PSYSTEM_CURSORINFO CurInfo;
798 PWINSTATION_OBJECT WinSta;
799 NTSTATUS Status;
800 PCURICON_OBJECT CurIcon;
801 HDC hDC;
802 DECLARE_RETURN(BOOL);
803
804 DPRINT("Enter NtUserGetCursorInfo\n");
805 UserEnterExclusive();
806
807 #if 1
808
809
810 /* FIXME - get the screen dc from the window station or desktop */
811 if (!(hDC = IntGetScreenDC()))
812 {
813 RETURN( FALSE);
814 }
815 #endif
816
817 Status = MmCopyFromCaller(&SafeCi.cbSize, pci, sizeof(DWORD));
818 if(!NT_SUCCESS(Status))
819 {
820 SetLastNtError(Status);
821 RETURN( FALSE);
822 }
823
824 if(SafeCi.cbSize != sizeof(CURSORINFO))
825 {
826 SetLastWin32Error(ERROR_INVALID_PARAMETER);
827 RETURN( FALSE);
828 }
829
830 WinSta = IntGetWinStaObj();
831 if(WinSta == NULL)
832 {
833 RETURN( FALSE);
834 }
835
836 CurInfo = IntGetSysCursorInfo(WinSta);
837 CurIcon = (PCURICON_OBJECT)CurInfo->CurrentCursorObject;
838
839 SafeCi.flags = ((CurInfo->ShowingCursor && CurIcon) ? CURSOR_SHOWING : 0);
840 SafeCi.hCursor = (CurIcon ? (HCURSOR)CurIcon->Self : (HCURSOR)0);
841
842 IntGetCursorLocation(WinSta, &SafeCi.ptScreenPos);
843
844 Status = MmCopyToCaller(pci, &SafeCi, sizeof(CURSORINFO));
845 if(!NT_SUCCESS(Status))
846 {
847 ObDereferenceObject(WinSta);
848 SetLastNtError(Status);
849 RETURN( FALSE);
850 }
851
852 ObDereferenceObject(WinSta);
853 RETURN( TRUE);
854
855 CLEANUP:
856 DPRINT("Leave NtUserGetCursorInfo, ret=%i\n",_ret_);
857 UserLeave();
858 END_CLEANUP;
859 }
860
861
862 /*
863 * @implemented
864 */
865 BOOL
866 APIENTRY
867 NtUserClipCursor(
868 RECT *UnsafeRect)
869 {
870 /* FIXME - check if process has WINSTA_WRITEATTRIBUTES */
871
872 PWINSTATION_OBJECT WinSta;
873 PSYSTEM_CURSORINFO CurInfo;
874 RECT Rect;
875 PWINDOW_OBJECT DesktopWindow = NULL;
876 POINT MousePos = {0};
877 DECLARE_RETURN(BOOL);
878
879 DPRINT("Enter NtUserClipCursor\n");
880 UserEnterExclusive();
881
882 WinSta = IntGetWinStaObj();
883 if (WinSta == NULL)
884 {
885 RETURN( FALSE);
886 }
887
888 if (NULL != UnsafeRect && ! NT_SUCCESS(MmCopyFromCaller(&Rect, UnsafeRect, sizeof(RECT))))
889 {
890 ObDereferenceObject(WinSta);
891 SetLastWin32Error(ERROR_INVALID_PARAMETER);
892 RETURN( FALSE);
893 }
894
895 CurInfo = IntGetSysCursorInfo(WinSta);
896 IntGetCursorLocation(WinSta, &MousePos);
897
898 if(WinSta->ActiveDesktop)
899 DesktopWindow = UserGetWindowObject(WinSta->ActiveDesktop->DesktopWindow);
900
901 if((Rect.right > Rect.left) && (Rect.bottom > Rect.top)
902 && DesktopWindow && UnsafeRect != NULL)
903 {
904 MOUSEINPUT mi;
905
906 CurInfo->CursorClipInfo.IsClipped = TRUE;
907 CurInfo->CursorClipInfo.Left = max(Rect.left, DesktopWindow->Wnd->WindowRect.left);
908 CurInfo->CursorClipInfo.Top = max(Rect.top, DesktopWindow->Wnd->WindowRect.top);
909 CurInfo->CursorClipInfo.Right = min(Rect.right - 1, DesktopWindow->Wnd->WindowRect.right - 1);
910 CurInfo->CursorClipInfo.Bottom = min(Rect.bottom - 1, DesktopWindow->Wnd->WindowRect.bottom - 1);
911
912 mi.dx = MousePos.x;
913 mi.dy = MousePos.y;
914 mi.mouseData = 0;
915 mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
916 mi.time = 0;
917 mi.dwExtraInfo = 0;
918 IntMouseInput(&mi);
919
920 RETURN( TRUE);
921 }
922
923 CurInfo->CursorClipInfo.IsClipped = FALSE;
924 ObDereferenceObject(WinSta);
925
926 RETURN( TRUE);
927
928 CLEANUP:
929 DPRINT("Leave NtUserClipCursor, ret=%i\n",_ret_);
930 UserLeave();
931 END_CLEANUP;
932 }
933
934
935 /*
936 * @implemented
937 */
938 BOOL
939 APIENTRY
940 NtUserDestroyCursor(
941 HANDLE hCurIcon,
942 DWORD Unknown)
943 {
944 PWINSTATION_OBJECT WinSta;
945 PCURICON_OBJECT CurIcon;
946 BOOL ret;
947 DECLARE_RETURN(BOOL);
948
949 DPRINT("Enter NtUserDestroyCursorIcon\n");
950 UserEnterExclusive();
951
952 WinSta = IntGetWinStaObj();
953 if(WinSta == NULL)
954 {
955 RETURN( FALSE);
956 }
957
958 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
959 {
960 ObDereferenceObject(WinSta);
961 RETURN(FALSE);
962 }
963
964 ret = IntDestroyCurIconObject(WinSta, CurIcon, FALSE);
965 /* Note: IntDestroyCurIconObject will remove our reference for us! */
966
967 ObDereferenceObject(WinSta);
968 RETURN(ret);
969
970 CLEANUP:
971 DPRINT("Leave NtUserDestroyCursorIcon, ret=%i\n",_ret_);
972 UserLeave();
973 END_CLEANUP;
974 }
975
976
977 /*
978 * @implemented
979 */
980 HICON
981 APIENTRY
982 NtUserFindExistingCursorIcon(
983 HMODULE hModule,
984 HRSRC hRsrc,
985 LONG cx,
986 LONG cy)
987 {
988 PCURICON_OBJECT CurIcon;
989 PWINSTATION_OBJECT WinSta;
990 HANDLE Ret = (HANDLE)0;
991 DECLARE_RETURN(HICON);
992
993 DPRINT("Enter NtUserFindExistingCursorIcon\n");
994 UserEnterExclusive();
995
996 WinSta = IntGetWinStaObj();
997 if(WinSta == NULL)
998 {
999 RETURN( Ret);
1000 }
1001
1002 CurIcon = IntFindExistingCurIconObject(WinSta, hModule, hRsrc, cx, cy);
1003 if(CurIcon)
1004 {
1005 Ret = CurIcon->Self;
1006
1007 // IntReleaseCurIconObject(CurIcon);//faxme: is this correct? does IntFindExistingCurIconObject add a ref?
1008 ObDereferenceObject(WinSta);
1009 RETURN( Ret);
1010 }
1011
1012 SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
1013 ObDereferenceObject(WinSta);
1014 RETURN( (HANDLE)0);
1015
1016 CLEANUP:
1017 DPRINT("Leave NtUserFindExistingCursorIcon, ret=%i\n",_ret_);
1018 UserLeave();
1019 END_CLEANUP;
1020 }
1021
1022
1023 /*
1024 * @implemented
1025 */
1026 BOOL
1027 APIENTRY
1028 NtUserGetClipCursor(
1029 RECT *lpRect)
1030 {
1031 /* FIXME - check if process has WINSTA_READATTRIBUTES */
1032 PSYSTEM_CURSORINFO CurInfo;
1033 PWINSTATION_OBJECT WinSta;
1034 RECT Rect;
1035 NTSTATUS Status;
1036 DECLARE_RETURN(BOOL);
1037
1038 DPRINT("Enter NtUserGetClipCursor\n");
1039 UserEnterExclusive();
1040
1041 if(!lpRect)
1042 RETURN( FALSE);
1043
1044 WinSta = IntGetWinStaObj();
1045 if (WinSta == NULL)
1046 {
1047 RETURN( FALSE);
1048 }
1049
1050 CurInfo = IntGetSysCursorInfo(WinSta);
1051 if(CurInfo->CursorClipInfo.IsClipped)
1052 {
1053 Rect.left = CurInfo->CursorClipInfo.Left;
1054 Rect.top = CurInfo->CursorClipInfo.Top;
1055 Rect.right = CurInfo->CursorClipInfo.Right;
1056 Rect.bottom = CurInfo->CursorClipInfo.Bottom;
1057 }
1058 else
1059 {
1060 Rect.left = 0;
1061 Rect.top = 0;
1062 Rect.right = UserGetSystemMetrics(SM_CXSCREEN);
1063 Rect.bottom = UserGetSystemMetrics(SM_CYSCREEN);
1064 }
1065
1066 Status = MmCopyToCaller((PRECT)lpRect, &Rect, sizeof(RECT));
1067 if(!NT_SUCCESS(Status))
1068 {
1069 ObDereferenceObject(WinSta);
1070 SetLastNtError(Status);
1071 RETURN( FALSE);
1072 }
1073
1074 ObDereferenceObject(WinSta);
1075
1076 RETURN( TRUE);
1077
1078 CLEANUP:
1079 DPRINT("Leave NtUserGetClipCursor, ret=%i\n",_ret_);
1080 UserLeave();
1081 END_CLEANUP;
1082 }
1083
1084
1085 /*
1086 * @implemented
1087 */
1088 HCURSOR
1089 APIENTRY
1090 NtUserSetCursor(
1091 HCURSOR hCursor)
1092 {
1093 PCURICON_OBJECT CurIcon;
1094 HICON OldCursor;
1095 PWINSTATION_OBJECT WinSta;
1096 DECLARE_RETURN(HCURSOR);
1097
1098 DPRINT("Enter NtUserSetCursor\n");
1099 UserEnterExclusive();
1100
1101 WinSta = IntGetWinStaObj();
1102 if(WinSta == NULL)
1103 {
1104 RETURN(NULL);
1105 }
1106
1107 if(hCursor)
1108 {
1109 if(!(CurIcon = UserGetCurIconObject(hCursor)))
1110 {
1111 ObDereferenceObject(WinSta);
1112 RETURN(NULL);
1113 }
1114 }
1115 else
1116 {
1117 CurIcon = NULL;
1118 }
1119
1120 OldCursor = IntSetCursor(WinSta, CurIcon, FALSE);
1121
1122 if(CurIcon)
1123 {
1124 UserDereferenceObject(CurIcon);
1125 }
1126 ObDereferenceObject(WinSta);
1127
1128 RETURN(OldCursor);
1129
1130 CLEANUP:
1131 DPRINT("Leave NtUserSetCursor, ret=%i\n",_ret_);
1132 UserLeave();
1133 END_CLEANUP;
1134 }
1135
1136
1137 /*
1138 * @implemented
1139 */
1140 BOOL
1141 APIENTRY
1142 NtUserSetCursorContents(
1143 HANDLE hCurIcon,
1144 PICONINFO UnsafeIconInfo)
1145 {
1146 PCURICON_OBJECT CurIcon;
1147 ICONINFO IconInfo;
1148 PBITMAPOBJ bmp;
1149 PWINSTATION_OBJECT WinSta;
1150 NTSTATUS Status;
1151 BOOL Ret = FALSE;
1152 DECLARE_RETURN(BOOL);
1153
1154 DPRINT("Enter NtUserSetCursorContents\n");
1155 UserEnterExclusive();
1156
1157 WinSta = IntGetWinStaObj();
1158 if(WinSta == NULL)
1159 {
1160 RETURN( FALSE);
1161 }
1162
1163 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
1164 {
1165 ObDereferenceObject(WinSta);
1166 RETURN(FALSE);
1167 }
1168
1169 /* Copy fields */
1170 Status = MmCopyFromCaller(&IconInfo, UnsafeIconInfo, sizeof(ICONINFO));
1171 if(!NT_SUCCESS(Status))
1172 {
1173 SetLastNtError(Status);
1174 goto done;
1175 }
1176
1177 /* Delete old bitmaps */
1178 if (CurIcon->IconInfo.hbmColor != IconInfo.hbmColor)
1179 {
1180 NtGdiDeleteObject(CurIcon->IconInfo.hbmColor);
1181 }
1182 if (CurIcon->IconInfo.hbmMask != IconInfo.hbmMask)
1183 {
1184 NtGdiDeleteObject(CurIcon->IconInfo.hbmMask);
1185 }
1186
1187 /* Copy new IconInfo field */
1188 CurIcon->IconInfo = IconInfo;
1189
1190 bmp = BITMAPOBJ_LockBitmap(CurIcon->IconInfo.hbmColor);
1191 if(bmp)
1192 {
1193 CurIcon->Size.cx = bmp->SurfObj.sizlBitmap.cx;
1194 CurIcon->Size.cy = bmp->SurfObj.sizlBitmap.cy;
1195 BITMAPOBJ_UnlockBitmap(bmp);
1196 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmColor, NULL);
1197 }
1198 else
1199 {
1200 bmp = BITMAPOBJ_LockBitmap(CurIcon->IconInfo.hbmMask);
1201 if(!bmp)
1202 goto done;
1203
1204 CurIcon->Size.cx = bmp->SurfObj.sizlBitmap.cx;
1205 CurIcon->Size.cy = bmp->SurfObj.sizlBitmap.cy / 2;
1206
1207 BITMAPOBJ_UnlockBitmap(bmp);
1208 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmMask, NULL);
1209 }
1210
1211 Ret = TRUE;
1212
1213 done:
1214
1215 if (CurIcon)
1216 {
1217 UserDereferenceObject(CurIcon);
1218 }
1219 ObDereferenceObject(WinSta);
1220 RETURN( Ret);
1221
1222 CLEANUP:
1223 DPRINT("Leave NtUserSetCursorContents, ret=%i\n",_ret_);
1224 UserLeave();
1225 END_CLEANUP;
1226 }
1227
1228
1229 /*
1230 * @implemented
1231 */
1232 #if 0
1233 BOOL
1234 APIENTRY
1235 NtUserSetCursorIconData(
1236 HANDLE Handle,
1237 HMODULE hModule,
1238 PUNICODE_STRING pstrResName,
1239 PICONINFO pIconInfo)
1240 {
1241 PCURICON_OBJECT CurIcon;
1242 PWINSTATION_OBJECT WinSta;
1243 PBITMAPOBJ pBmpObj;
1244 NTSTATUS Status = STATUS_SUCCESS;
1245 BOOL Ret = FALSE;
1246 DECLARE_RETURN(BOOL);
1247
1248 DPRINT("Enter NtUserSetCursorIconData\n");
1249 UserEnterExclusive();
1250
1251 WinSta = IntGetWinStaObj();
1252 if(WinSta == NULL)
1253 {
1254 RETURN( FALSE);
1255 }
1256
1257 if(!(CurIcon = UserGetCurIconObject(Handle)))
1258 {
1259 ObDereferenceObject(WinSta);
1260 RETURN(FALSE);
1261 }
1262
1263 CurIcon->hModule = hModule;
1264 CurIcon->hRsrc = NULL; //hRsrc;
1265 CurIcon->hGroupRsrc = NULL; //hGroupRsrc;
1266
1267 _SEH_TRY
1268 {
1269 ProbeForRead(pIconInfo, sizeof(ICONINFO), 1);
1270 RtlCopyMemory(&CurIcon->IconInfo, pIconInfo, sizeof(ICONINFO));
1271
1272 CurIcon->IconInfo.hbmMask = BITMAPOBJ_CopyBitmap(pIconInfo->hbmMask);
1273 CurIcon->IconInfo.hbmColor = BITMAPOBJ_CopyBitmap(pIconInfo->hbmColor);
1274
1275 if (CurIcon->IconInfo.hbmColor)
1276 {
1277 if ((pBmpObj = BITMAPOBJ_LockBitmap(CurIcon->IconInfo.hbmColor)))
1278 {
1279 CurIcon->Size.cx = pBmpObj->SurfObj.sizlBitmap.cx;
1280 CurIcon->Size.cy = pBmpObj->SurfObj.sizlBitmap.cy;
1281 BITMAPOBJ_UnlockBitmap(pBmpObj);
1282 GDIOBJ_SetOwnership(GdiHandleTable, CurIcon->IconInfo.hbmMask, NULL);
1283 }
1284 }
1285 if (CurIcon->IconInfo.hbmMask)
1286 {
1287 if (CurIcon->IconInfo.hbmColor == NULL)
1288 {
1289 if ((pBmpObj = BITMAPOBJ_LockBitmap(CurIcon->IconInfo.hbmMask)))
1290 {
1291 CurIcon->Size.cx = pBmpObj->SurfObj.sizlBitmap.cx;
1292 CurIcon->Size.cy = pBmpObj->SurfObj.sizlBitmap.cy;
1293 BITMAPOBJ_UnlockBitmap(pBmpObj);
1294 }
1295 }
1296 GDIOBJ_SetOwnership(GdiHandleTable, CurIcon->IconInfo.hbmMask, NULL);
1297 }
1298 }
1299 _SEH_HANDLE
1300 {
1301 Status = _SEH_GetExceptionCode();
1302 }
1303 _SEH_END
1304
1305 if(!NT_SUCCESS(Status))
1306 SetLastNtError(Status);
1307 else
1308 Ret = TRUE;
1309
1310 UserDereferenceObject(CurIcon);
1311 ObDereferenceObject(WinSta);
1312 RETURN( Ret);
1313
1314 CLEANUP:
1315 DPRINT("Leave NtUserSetCursorIconData, ret=%i\n",_ret_);
1316 UserLeave();
1317 END_CLEANUP;
1318 }
1319 #else
1320 BOOL
1321 APIENTRY
1322 NtUserSetCursorIconData(
1323 HANDLE hCurIcon,
1324 PBOOL fIcon,
1325 POINT *Hotspot,
1326 HMODULE hModule,
1327 HRSRC hRsrc,
1328 HRSRC hGroupRsrc)
1329 {
1330 PCURICON_OBJECT CurIcon;
1331 PWINSTATION_OBJECT WinSta;
1332 NTSTATUS Status;
1333 POINT SafeHotspot;
1334 BOOL Ret = FALSE;
1335 DECLARE_RETURN(BOOL);
1336
1337 DPRINT("Enter NtUserSetCursorIconData\n");
1338 UserEnterExclusive();
1339
1340 WinSta = IntGetWinStaObj();
1341 if(WinSta == NULL)
1342 {
1343 RETURN( FALSE);
1344 }
1345
1346 if(!(CurIcon = UserGetCurIconObject(hCurIcon)))
1347 {
1348 ObDereferenceObject(WinSta);
1349 RETURN(FALSE);
1350 }
1351
1352 CurIcon->hModule = hModule;
1353 CurIcon->hRsrc = hRsrc;
1354 CurIcon->hGroupRsrc = hGroupRsrc;
1355
1356 /* Copy fields */
1357 if(fIcon)
1358 {
1359 Status = MmCopyFromCaller(&CurIcon->IconInfo.fIcon, fIcon, sizeof(BOOL));
1360 if(!NT_SUCCESS(Status))
1361 {
1362 SetLastNtError(Status);
1363 goto done;
1364 }
1365 }
1366 else
1367 {
1368 if(!Hotspot)
1369 Ret = TRUE;
1370 }
1371
1372 if(Hotspot)
1373 {
1374 Status = MmCopyFromCaller(&SafeHotspot, Hotspot, sizeof(POINT));
1375 if(NT_SUCCESS(Status))
1376 {
1377 CurIcon->IconInfo.xHotspot = SafeHotspot.x;
1378 CurIcon->IconInfo.yHotspot = SafeHotspot.y;
1379
1380 Ret = TRUE;
1381 }
1382 else
1383 SetLastNtError(Status);
1384 }
1385
1386 if(!fIcon && !Hotspot)
1387 {
1388 Ret = TRUE;
1389 }
1390
1391 done:
1392 UserDereferenceObject(CurIcon);
1393 ObDereferenceObject(WinSta);
1394 RETURN( Ret);
1395
1396
1397 CLEANUP:
1398 DPRINT("Leave NtUserSetCursorIconData, ret=%i\n",_ret_);
1399 UserLeave();
1400 END_CLEANUP;
1401 }
1402 #endif
1403
1404 /*
1405 * @unimplemented
1406 */
1407 BOOL
1408 APIENTRY
1409 NtUserSetSystemCursor(
1410 HCURSOR hcur,
1411 DWORD id)
1412 {
1413 return FALSE;
1414 }
1415
1416
1417 #define STRETCH_CAN_SRCCOPY_ONLY
1418
1419 #ifdef STRETCH_CAN_SRCCOPY_ONLY
1420 void
1421 FASTCALL
1422 DoStretchBlt(HDC DcDest, int XDest, int YDest, int WidthDest, int HeightDest,
1423 HDC DcSrc, int XSrc, int YSrc, int WidthSrc, int HeightSrc,
1424 DWORD Rop3, BOOL Color)
1425 {
1426 HDC DcStretched;
1427 HBITMAP BitmapStretched;
1428 HBITMAP OldBitmap;
1429
1430 if (WidthDest == WidthSrc && HeightDest == HeightSrc)
1431 {
1432 NtGdiBitBlt(DcDest, XDest, YDest, WidthDest, HeightDest,
1433 DcSrc, XSrc, YSrc, Rop3, 0, 0);
1434 }
1435 else if (SRCCOPY == Rop3)
1436 {
1437 NtGdiStretchBlt(DcDest, XDest, YDest, WidthDest, HeightDest,
1438 DcSrc, XSrc, YSrc, WidthSrc, HeightSrc,
1439 Rop3, 0);
1440 }
1441 else
1442 {
1443 DcStretched = NtGdiCreateCompatibleDC(DcSrc);
1444 if (NULL == DcStretched)
1445 {
1446 DPRINT1("Failed to create compatible DC\n");
1447 return;
1448 }
1449 if (Color)
1450 {
1451 BitmapStretched = NtGdiCreateCompatibleBitmap(DcDest, WidthDest,
1452 HeightDest);
1453 }
1454 else
1455 {
1456 BitmapStretched = IntGdiCreateBitmap(WidthDest, HeightDest, 1, 1, NULL);
1457 }
1458 if (NULL == BitmapStretched)
1459 {
1460 NtGdiDeleteObjectApp(DcStretched);
1461 DPRINT1("Failed to create temporary bitmap\n");
1462 return;
1463 }
1464 OldBitmap = NtGdiSelectBitmap(DcStretched, BitmapStretched);
1465 if (NULL == OldBitmap)
1466 {
1467 NtGdiDeleteObject(BitmapStretched);
1468 NtGdiDeleteObjectApp(DcStretched);
1469 DPRINT1("Failed to create temporary bitmap\n");
1470 return;
1471 }
1472 if (! NtGdiStretchBlt(DcStretched, 0, 0, WidthDest, HeightDest,
1473 DcSrc, XSrc, YSrc, WidthSrc, HeightSrc,
1474 SRCCOPY, 0) ||
1475 ! NtGdiBitBlt(DcDest, XDest, YDest, WidthDest, HeightDest,
1476 DcStretched, 0, 0, Rop3, 0, 0))
1477 {
1478 DPRINT1("Failed to blt\n");
1479 }
1480 NtGdiSelectBitmap(DcStretched, OldBitmap);
1481 NtGdiDeleteObject(BitmapStretched);
1482 NtGdiDeleteObjectApp(DcStretched);
1483 }
1484 }
1485 #else
1486 #define DoStretchBlt(DcDest, XDest, YDest, WidthDest, HeightDest, \
1487 DcSrc, XSrc, YSrc, WidthSrc, HeightSrc, Rop3, Color) \
1488 NtGdiStretchBlt((DcDest), (XDest), (YDest), (WidthDest), (HeightDest), \
1489 (DcSrc), (XSrc), (YSrc), (WidthSrc), (HeightSrc), \
1490 (Rop3), 0)
1491 #endif /* STRETCH_CAN_SRCCOPY_ONLY */
1492
1493 BOOL
1494 UserDrawIconEx(
1495 HDC hDc,
1496 INT xLeft,
1497 INT yTop,
1498 PCURICON_OBJECT pIcon,
1499 INT cxWidth,
1500 INT cyHeight,
1501 UINT istepIfAniCur,
1502 HBRUSH hbrFlickerFreeDraw,
1503 UINT diFlags)
1504 {
1505 BOOL Ret = FALSE;
1506 HBITMAP hbmMask, hbmColor;
1507 BITMAP bmpMask, bmpColor;
1508 COLORREF oldFg, oldBg;
1509 BOOL DoFlickerFree;
1510 INT nStretchMode;
1511 SIZE IconSize;
1512
1513 HDC hdcOff;
1514 HGDIOBJ hOldOffBrush = 0;
1515 HGDIOBJ hOldOffBmp = 0;
1516 HBITMAP hbmOff = 0;
1517 HDC hdcMem = 0;
1518 HGDIOBJ hOldMem;
1519 BOOL bAlpha = FALSE;
1520
1521 hbmMask = pIcon->IconInfo.hbmMask;
1522 hbmColor = pIcon->IconInfo.hbmColor;
1523
1524 if (istepIfAniCur)
1525 DPRINT1("NtUserDrawIconEx: istepIfAniCur is not supported!\n");
1526
1527 if (!hbmMask || !IntGdiGetObject(hbmMask, sizeof(BITMAP), (PVOID)&bmpMask))
1528 {
1529 return FALSE;
1530 }
1531
1532 if (hbmColor && !IntGdiGetObject(hbmColor, sizeof(BITMAP), (PVOID)&bmpColor))
1533 {
1534 return FALSE;
1535 }
1536
1537 if (hbmColor)
1538 {
1539 IconSize.cx = bmpColor.bmWidth;
1540 IconSize.cy = bmpColor.bmHeight;
1541 }
1542 else
1543 {
1544 IconSize.cx = bmpMask.bmWidth;
1545 IconSize.cy = bmpMask.bmHeight / 2;
1546 }
1547
1548 /* NtGdiCreateCompatibleBitmap will create a monochrome bitmap
1549 when cxWidth or cyHeight is 0 */
1550 if ((bmpColor.bmBitsPixel == 32) && (cxWidth != 0) && (cyHeight != 0))
1551 {
1552 bAlpha = TRUE;
1553 }
1554
1555 if (!diFlags)
1556 diFlags = DI_NORMAL;
1557
1558 if (!cxWidth)
1559 cxWidth = ((diFlags & DI_DEFAULTSIZE) ?
1560 UserGetSystemMetrics(SM_CXICON) : IconSize.cx);
1561
1562 if (!cyHeight)
1563 cyHeight = ((diFlags & DI_DEFAULTSIZE) ?
1564 UserGetSystemMetrics(SM_CYICON) : IconSize.cy);
1565
1566 DoFlickerFree = (hbrFlickerFreeDraw &&
1567 (GDI_HANDLE_GET_TYPE(hbrFlickerFreeDraw) == GDI_OBJECT_TYPE_BRUSH));
1568
1569 if (DoFlickerFree || bAlpha)
1570 {
1571 RECT r;
1572 BITMAP bm;
1573 BITMAPOBJ *BitmapObj = NULL;
1574
1575 r.right = cxWidth;
1576 r.bottom = cyHeight;
1577
1578 hdcOff = NtGdiCreateCompatibleDC(hDc);
1579 if (!hdcOff)
1580 {
1581 DPRINT1("NtGdiCreateCompatibleDC() failed!\n");
1582 return FALSE;
1583 }
1584
1585 hbmOff = NtGdiCreateCompatibleBitmap(hDc, cxWidth, cyHeight);
1586 if (!hbmOff)
1587 {
1588 DPRINT1("NtGdiCreateCompatibleBitmap() failed!\n");
1589 goto cleanup;
1590 }
1591
1592 /* make sure we have a 32 bit offscreen bitmap
1593 otherwise we can't do alpha blending */
1594 BitmapObj = BITMAPOBJ_LockBitmap(hbmOff);
1595 if (BitmapObj == NULL)
1596 {
1597 DPRINT1("GDIOBJ_LockObj() failed!\n");
1598 goto cleanup;
1599 }
1600 BITMAP_GetObject(BitmapObj, sizeof(BITMAP), (PVOID)&bm);
1601
1602 if (bm.bmBitsPixel != 32)
1603 bAlpha = FALSE;
1604
1605 BITMAPOBJ_UnlockBitmap(BitmapObj);
1606
1607 hOldOffBmp = NtGdiSelectBitmap(hdcOff, hbmOff);
1608 if (!hOldOffBmp)
1609 {
1610 DPRINT1("NtGdiSelectBitmap() failed!\n");
1611 goto cleanup;
1612 }
1613
1614 if (DoFlickerFree)
1615 {
1616 hOldOffBrush = NtGdiSelectBrush(hdcOff, hbrFlickerFreeDraw);
1617 if (!hOldOffBrush)
1618 {
1619 DPRINT1("NtGdiSelectBitmap() failed!\n");
1620 goto cleanup;
1621 }
1622
1623 NtGdiPatBlt(hdcOff, 0, 0, r.right, r.bottom, PATCOPY);
1624 }
1625 }
1626 else
1627 hdcOff = hDc;
1628
1629 hdcMem = NtGdiCreateCompatibleDC(hDc);
1630 if (!hdcMem)
1631 {
1632 DPRINT1("NtGdiCreateCompatibleDC() failed!\n");
1633 goto cleanup;
1634 }
1635
1636 nStretchMode = IntGdiSetStretchBltMode(hdcOff, STRETCH_DELETESCANS);
1637
1638 oldFg = IntGdiSetTextColor(hdcOff, RGB(0, 0, 0));
1639 oldBg = IntGdiSetBkColor(hdcOff, RGB(255, 255, 255));
1640
1641 if (diFlags & DI_MASK)
1642 {
1643 hOldMem = NtGdiSelectBitmap(hdcMem, hbmMask);
1644 if (!hOldMem)
1645 {
1646 DPRINT("NtGdiSelectBitmap() failed!\n");
1647 goto cleanup;
1648 }
1649
1650 DoStretchBlt(hdcOff, (DoFlickerFree ? 0 : xLeft),
1651 (DoFlickerFree ? 0 : yTop), cxWidth, cyHeight, hdcMem,
1652 0, 0, IconSize.cx, IconSize.cy,
1653 ((diFlags & DI_IMAGE) ? SRCAND : SRCCOPY), FALSE);
1654
1655 if (!hbmColor && (bmpMask.bmHeight == 2 * bmpMask.bmWidth)
1656 && (diFlags & DI_IMAGE))
1657 {
1658 DoStretchBlt(hdcOff, (DoFlickerFree ? 0 : xLeft),
1659 (DoFlickerFree ? 0 : yTop), cxWidth, cyHeight, hdcMem,
1660 0, IconSize.cy, IconSize.cx, IconSize.cy, SRCINVERT,
1661 FALSE);
1662
1663 diFlags &= ~DI_IMAGE;
1664 }
1665
1666 NtGdiSelectBitmap(hdcMem, hOldMem);
1667 }
1668
1669 if(diFlags & DI_IMAGE)
1670 {
1671 hOldMem = NtGdiSelectBitmap(hdcMem, (hbmColor ? hbmColor : hbmMask));
1672
1673 DoStretchBlt(hdcOff, (DoFlickerFree ? 0 : xLeft),
1674 (DoFlickerFree ? 0 : yTop), cxWidth, cyHeight, hdcMem,
1675 0, (hbmColor ? 0 : IconSize.cy), IconSize.cx, IconSize.cy,
1676 ((diFlags & DI_MASK) ? SRCINVERT : SRCCOPY),
1677 NULL != hbmColor);
1678
1679 NtGdiSelectBitmap(hdcMem, hOldMem);
1680 }
1681
1682 if (bAlpha)
1683 {
1684 BITMAP bm;
1685 BITMAPOBJ *BitmapObj = NULL;
1686 PBYTE pBits = NULL;
1687 BLENDFUNCTION BlendFunc;
1688 DWORD Pixel;
1689 BYTE Red, Green, Blue, Alpha;
1690 DWORD Count = 0;
1691 INT i, j;
1692
1693 BitmapObj = BITMAPOBJ_LockBitmap(hbmOff);
1694 if (BitmapObj == NULL)
1695 {
1696 DPRINT1("GDIOBJ_LockObj() failed!\n");
1697 goto cleanup;
1698 }
1699 BITMAP_GetObject(BitmapObj, sizeof(BITMAP), (PVOID)&bm);
1700
1701 pBits = ExAllocatePoolWithTag(PagedPool, bm.bmWidthBytes * abs(bm.bmHeight), TAG_BITMAP);
1702 if (pBits == NULL)
1703 {
1704 DPRINT1("ExAllocatePoolWithTag() failed!\n");
1705 BITMAPOBJ_UnlockBitmap(BitmapObj);
1706 goto cleanup;
1707 }
1708
1709 /* get icon bits */
1710 IntGetBitmapBits(BitmapObj, bm.bmWidthBytes * abs(bm.bmHeight), pBits);
1711
1712 /* premultiply with the alpha channel value */
1713 for (i = 0; i < cyHeight; i++)
1714 {
1715 for (j = 0; j < cxWidth; j++)
1716 {
1717 Pixel = *(DWORD *)(pBits + Count);
1718
1719 Alpha = ((BYTE)(Pixel >> 24) & 0xff);
1720
1721 Red = (((BYTE)(Pixel >> 0)) * Alpha) / 0xff;
1722 Green = (((BYTE)(Pixel >> 8)) * Alpha) / 0xff;
1723 Blue = (((BYTE)(Pixel >> 16)) * Alpha) / 0xff;
1724
1725 *(DWORD *)(pBits + Count) = (DWORD)(Red | (Green << 8) | (Blue << 16) | (Alpha << 24));
1726
1727 Count += sizeof (DWORD);
1728 }
1729 }
1730
1731 /* set icon bits */
1732 IntSetBitmapBits(BitmapObj, bm.bmWidthBytes * abs(bm.bmHeight), pBits);
1733 ExFreePoolWithTag(pBits, TAG_BITMAP);
1734
1735 BITMAPOBJ_UnlockBitmap(BitmapObj);
1736
1737 BlendFunc.BlendOp = AC_SRC_OVER;
1738 BlendFunc.BlendFlags = 0;
1739 BlendFunc.SourceConstantAlpha = 255;
1740 BlendFunc.AlphaFormat = AC_SRC_ALPHA;
1741
1742 NtGdiAlphaBlend(hDc, xLeft, yTop, cxWidth, cyHeight,
1743 hdcOff, 0, 0, cxWidth, cyHeight, BlendFunc, 0);
1744 }
1745 else if (DoFlickerFree)
1746 {
1747 NtGdiBitBlt(hDc, xLeft, yTop, cxWidth,
1748 cyHeight, hdcOff, 0, 0, SRCCOPY, 0, 0);
1749 }
1750
1751 IntGdiSetTextColor(hdcOff, oldFg);
1752 IntGdiSetBkColor(hdcOff, oldBg);
1753 IntGdiSetStretchBltMode(hdcOff, nStretchMode);
1754
1755 Ret = TRUE;
1756
1757 cleanup:
1758 if(DoFlickerFree || bAlpha)
1759 {
1760 if(hOldOffBmp) NtGdiSelectBitmap(hdcOff, hOldOffBmp);
1761 if(hOldOffBrush) NtGdiSelectBrush(hdcOff, hOldOffBrush);
1762 if(hbmOff) NtGdiDeleteObject(hbmOff);
1763 if(hdcOff) NtGdiDeleteObjectApp(hdcOff);
1764 }
1765
1766 if(hdcMem) NtGdiDeleteObjectApp(hdcMem);
1767 return Ret;
1768 }
1769
1770 /*
1771 * @implemented
1772 */
1773 BOOL
1774 APIENTRY
1775 NtUserDrawIconEx(
1776 HDC hdc,
1777 int xLeft,
1778 int yTop,
1779 HICON hIcon,
1780 int cxWidth,
1781 int cyHeight,
1782 UINT istepIfAniCur,
1783 HBRUSH hbrFlickerFreeDraw,
1784 UINT diFlags,
1785 DWORD Unknown0,
1786 DWORD Unknown1)
1787 {
1788 PCURICON_OBJECT pIcon;
1789 BOOL Ret;
1790
1791 DPRINT("Enter NtUserDrawIconEx\n");
1792 UserEnterExclusive();
1793
1794 if(!(pIcon = UserGetCurIconObject(hIcon)))
1795 {
1796 DPRINT1("UserGetCurIconObject() failed!\n");
1797 UserLeave();
1798 return FALSE;
1799 }
1800
1801 Ret = UserDrawIconEx(hdc,
1802 xLeft,
1803 yTop,
1804 pIcon,
1805 cxWidth,
1806 cyHeight,
1807 istepIfAniCur,
1808 hbrFlickerFreeDraw,
1809 diFlags);
1810
1811 UserDereferenceObject(pIcon);
1812
1813 UserLeave();
1814 return Ret;
1815 }
1816
1817 /* Called from NtUserCallOneParam with Routine ONEPARAM_ROUTINE_SHOWCURSOR
1818 * User32 macro NtUserShowCursor */
1819 int
1820 APIENTRY
1821 UserShowCursor(BOOL bShow)
1822 {
1823 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1824 PWINSTATION_OBJECT WinSta = pti->Desktop->WindowStation;
1825 PSYSTEM_CURSORINFO CurInfo;
1826
1827 HDC Screen;
1828 PDC dc;
1829 HBITMAP dcbmp;
1830 SURFOBJ *SurfObj;
1831 BITMAPOBJ *BitmapObj;
1832 GDIDEVICE *ppdev;
1833 GDIPOINTER *pgp;
1834 int showpointer=0;
1835
1836 if(!(Screen = IntGetScreenDC()))
1837 {
1838 return showpointer; /* No mouse */
1839 }
1840
1841 dc = DC_LockDc(Screen);
1842
1843 if (!dc)
1844 {
1845 return showpointer; /* No mouse */
1846 }
1847
1848 dcbmp = dc->w.hBitmap;
1849 DC_UnlockDc(dc);
1850
1851 BitmapObj = BITMAPOBJ_LockBitmap(dcbmp);
1852 if ( !BitmapObj )
1853 {
1854 return showpointer; /* No Mouse */
1855 }
1856
1857 SurfObj = &BitmapObj->SurfObj;
1858 if (SurfObj == NULL)
1859 {
1860 BITMAPOBJ_UnlockBitmap(BitmapObj);
1861 return showpointer; /* No mouse */
1862 }
1863
1864 ppdev = GDIDEV(SurfObj);
1865
1866 if(ppdev == NULL)
1867 {
1868 BITMAPOBJ_UnlockBitmap(BitmapObj);
1869 return showpointer; /* No mouse */
1870 }
1871
1872 pgp = &ppdev->Pointer;
1873
1874 CurInfo = IntGetSysCursorInfo(WinSta);
1875
1876 if (bShow == FALSE)
1877 {
1878 pgp->ShowPointer--;
1879 showpointer = pgp->ShowPointer;
1880
1881 if (showpointer >= 0)
1882 {
1883 //ppdev->SafetyRemoveCount = 1;
1884 //ppdev->SafetyRemoveLevel = 1;
1885 EngMovePointer(SurfObj,-1,-1,NULL);
1886 CurInfo->ShowingCursor = 0;
1887 }
1888
1889 }
1890 else
1891 {
1892 pgp->ShowPointer++;
1893 showpointer = pgp->ShowPointer;
1894
1895 /* Show Cursor */
1896 if (showpointer < 0)
1897 {
1898 //ppdev->SafetyRemoveCount = 0;
1899 //ppdev->SafetyRemoveLevel = 0;
1900 EngMovePointer(SurfObj,-1,-1,NULL);
1901 CurInfo->ShowingCursor = CURSOR_SHOWING;
1902 }
1903 }
1904
1905 BITMAPOBJ_UnlockBitmap(BitmapObj);
1906 return showpointer;
1907 }