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