Revert, thx Thomas, wasnt sure.
[reactos.git] / reactos / subsys / 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->GDIDevice;
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
75 static
76 PCURICON_OBJECT FASTCALL UserGetCurIconObject(HCURSOR hCurIcon)
77 {
78 PCURICON_OBJECT CurIcon;
79
80 if (!hCurIcon)
81 {
82 SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
83 return NULL;
84 }
85
86 CurIcon = (PCURICON_OBJECT)UserGetObject(&gHandleTable, hCurIcon, otCursorIcon);
87 if (!CurIcon)
88 {
89 /* we never set ERROR_INVALID_ICON_HANDLE. lets hope noone ever checks for it */
90 SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
91 return NULL;
92 }
93
94 ASSERT(USER_BODY_TO_HEADER(CurIcon)->RefCount >= 0);
95 return CurIcon;
96 }
97
98
99 #define COLORCURSORS_ALLOWED FALSE
100 HCURSOR FASTCALL
101 IntSetCursor(PWINSTATION_OBJECT WinSta, PCURICON_OBJECT NewCursor,
102 BOOL ForceChange)
103 {
104 BITMAPOBJ *BitmapObj;
105 SURFOBJ *SurfObj;
106 PDEVINFO DevInfo;
107 PBITMAPOBJ MaskBmpObj = NULL;
108 PSYSTEM_CURSORINFO CurInfo;
109 PCURICON_OBJECT OldCursor;
110 HCURSOR Ret = (HCURSOR)0;
111 HBITMAP dcbmp, hColor = (HBITMAP)0;
112 HBITMAP hMask = 0;
113 SURFOBJ *soMask = NULL, *soColor = NULL;
114 XLATEOBJ *XlateObj = NULL;
115 HDC Screen;
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 else
129 {
130 if(!(Screen = IntGetScreenDC()))
131 {
132 return (HCURSOR)0;
133 }
134 /* FIXME use the desktop's HDC instead of using ScreenDeviceContext */
135 PDC dc = DC_LockDc(Screen);
136
137 if (!dc)
138 {
139 return Ret;
140 }
141 dcbmp = dc->w.hBitmap;
142 DevInfo = dc->DevInfo;
143 DC_UnlockDc(dc);
144
145 BitmapObj = BITMAPOBJ_LockBitmap(dcbmp);
146 if ( !BitmapObj )
147 return (HCURSOR)0;
148 SurfObj = &BitmapObj->SurfObj;
149 ASSERT(SurfObj);
150 }
151
152 if (!NewCursor && (CurInfo->CurrentCursorObject || ForceChange))
153 {
154 if (NULL != CurInfo->CurrentCursorObject && CurInfo->ShowingCursor)
155 {
156 /* Remove the cursor if it was displayed */
157 IntEngMovePointer(SurfObj, -1, -1, &GDIDEV(SurfObj)->Pointer.Exclude);
158 }
159
160 GDIDEV(SurfObj)->Pointer.Status = SPS_ACCEPT_NOEXCLUDE;
161
162 CurInfo->CurrentCursorObject = NewCursor; /* i.e. CurrentCursorObject = NULL */
163 CurInfo->ShowingCursor = 0;
164 BITMAPOBJ_UnlockBitmap(BitmapObj);
165 return Ret;
166 }
167
168 if (!NewCursor)
169 {
170 BITMAPOBJ_UnlockBitmap(BitmapObj);
171 return Ret;
172 }
173
174 /* TODO: Fixme. Logic is screwed above */
175
176 ASSERT(NewCursor);
177 MaskBmpObj = BITMAPOBJ_LockBitmap(NewCursor->IconInfo.hbmMask);
178 if (MaskBmpObj)
179 {
180 const int maskBpp = BitsPerFormat(MaskBmpObj->SurfObj.iBitmapFormat);
181 BITMAPOBJ_UnlockBitmap(MaskBmpObj);
182 if (maskBpp != 1)
183 {
184 DPRINT1("SetCursor: The Mask bitmap must have 1BPP!\n");
185 BITMAPOBJ_UnlockBitmap(BitmapObj);
186 return Ret;
187 }
188
189 if ((DevInfo->flGraphicsCaps2 & GCAPS2_ALPHACURSOR) &&
190 SurfObj->iBitmapFormat >= BMF_16BPP &&
191 SurfObj->iBitmapFormat <= BMF_32BPP &&
192 NewCursor->Shadow && COLORCURSORS_ALLOWED)
193 {
194 /* FIXME - Create a color pointer, only 32bit bitmap, set alpha bits!
195 Do not pass a mask bitmap to DrvSetPointerShape()!
196 Create a XLATEOBJ that describes the colors of the bitmap. */
197 DPRINT1("SetCursor: (Colored) alpha cursors are not supported!\n");
198 }
199 else
200 {
201 if(NewCursor->IconInfo.hbmColor
202 && COLORCURSORS_ALLOWED)
203 {
204 /* FIXME - Create a color pointer, create only one 32bit bitmap!
205 Do not pass a mask bitmap to DrvSetPointerShape()!
206 Create a XLATEOBJ that describes the colors of the bitmap.
207 (16bit bitmaps are propably allowed) */
208 DPRINT1("SetCursor: Cursors with colors are not supported!\n");
209 }
210 else
211 {
212 MaskBmpObj = BITMAPOBJ_LockBitmap(NewCursor->IconInfo.hbmMask);
213 if(MaskBmpObj)
214 {
215 RECTL DestRect = {0, 0, MaskBmpObj->SurfObj.sizlBitmap.cx, MaskBmpObj->SurfObj.sizlBitmap.cy};
216 POINTL SourcePoint = {0, 0};
217
218 /*
219 * NOTE: For now we create the cursor in top-down bitmap,
220 * because VMware driver rejects it otherwise. This should
221 * be fixed later.
222 */
223 hMask = EngCreateBitmap(
224 MaskBmpObj->SurfObj.sizlBitmap, abs(MaskBmpObj->SurfObj.lDelta),
225 MaskBmpObj->SurfObj.iBitmapFormat, BMF_TOPDOWN,
226 NULL);
227 if ( !hMask )
228 {
229 BITMAPOBJ_UnlockBitmap(MaskBmpObj);
230 BITMAPOBJ_UnlockBitmap(BitmapObj);
231 return (HCURSOR)0;
232 }
233 soMask = EngLockSurface((HSURF)hMask);
234 EngCopyBits(soMask, &MaskBmpObj->SurfObj, NULL, NULL,
235 &DestRect, &SourcePoint);
236 BITMAPOBJ_UnlockBitmap(MaskBmpObj);
237 }
238 }
239 }
240 CurInfo->ShowingCursor = CURSOR_SHOWING;
241 CurInfo->CurrentCursorObject = NewCursor;
242 }
243 else
244 {
245 CurInfo->ShowingCursor = 0;
246 CurInfo->CurrentCursorObject = NULL;
247 }
248
249 if (GDIDEVFUNCS(SurfObj).SetPointerShape)
250 {
251 GDIDEV(SurfObj)->Pointer.Status =
252 GDIDEVFUNCS(SurfObj).SetPointerShape(
253 SurfObj, soMask, soColor, XlateObj,
254 NewCursor->IconInfo.xHotspot,
255 NewCursor->IconInfo.yHotspot,
256 GDIDEV(SurfObj)->Pointer.Pos.x,
257 GDIDEV(SurfObj)->Pointer.Pos.y,
258 &(GDIDEV(SurfObj)->Pointer.Exclude),
259 SPS_CHANGE);
260 DPRINT("SetCursor: DrvSetPointerShape() returned %x\n",
261 GDIDEV(SurfObj)->Pointer.Status);
262 }
263 else
264 {
265 GDIDEV(SurfObj)->Pointer.Status = SPS_DECLINE;
266 }
267
268 if(GDIDEV(SurfObj)->Pointer.Status == SPS_DECLINE)
269 {
270 GDIDEV(SurfObj)->Pointer.Status = EngSetPointerShape(
271 SurfObj, soMask, soColor, XlateObj,
272 NewCursor->IconInfo.xHotspot,
273 NewCursor->IconInfo.yHotspot,
274 GDIDEV(SurfObj)->Pointer.Pos.x,
275 GDIDEV(SurfObj)->Pointer.Pos.y,
276 &(GDIDEV(SurfObj)->Pointer.Exclude),
277 SPS_CHANGE);
278 GDIDEV(SurfObj)->Pointer.MovePointer = NULL;
279 }
280 else
281 {
282 GDIDEV(SurfObj)->Pointer.MovePointer = GDIDEVFUNCS(SurfObj).MovePointer;
283 }
284
285 BITMAPOBJ_UnlockBitmap(BitmapObj);
286 if(hMask)
287 {
288 EngUnlockSurface(soMask);
289 EngDeleteSurface((HSURF)hMask);
290 }
291 if(hColor)
292 {
293 EngDeleteSurface((HSURF)hColor);
294 }
295 if(XlateObj)
296 {
297 EngDeleteXlate(XlateObj);
298 }
299
300 if(GDIDEV(SurfObj)->Pointer.Status == SPS_ERROR)
301 DPRINT1("SetCursor: DrvSetPointerShape() returned SPS_ERROR\n");
302
303 return Ret;
304 }
305
306 BOOL FASTCALL
307 IntSetupCurIconHandles(PWINSTATION_OBJECT WinSta)
308 {
309 ExInitializePagedLookasideList(&gProcessLookasideList,
310 NULL,
311 NULL,
312 0,
313 sizeof(CURICON_PROCESS),
314 0,
315 128);
316 InitializeListHead(&gCurIconList);
317
318 return TRUE;
319 }
320
321 /*
322 * We have to register that this object is in use by the current
323 * process. The only way to do that seems to be to walk the list
324 * of cursor/icon objects starting at W32Process->CursorIconListHead.
325 * If the object is already present in the list, we don't have to do
326 * anything, if it's not present we add it and inc the ProcessCount
327 * in the object. Having to walk the list kind of sucks, but that's
328 * life...
329 */
330 static BOOLEAN FASTCALL
331 ReferenceCurIconByProcess(PCURICON_OBJECT CurIcon)
332 {
333 PW32PROCESS Win32Process;
334 PCURICON_PROCESS Current;
335
336 Win32Process = PsGetWin32Process();
337
338 LIST_FOR_EACH(Current, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
339 {
340 if (Current->Process == Win32Process)
341 {
342 /* Already registered for this process */
343 return TRUE;
344 }
345 }
346
347 /* Not registered yet */
348 Current = ExAllocateFromPagedLookasideList(&gProcessLookasideList);
349 if (NULL == Current)
350 {
351 return FALSE;
352 }
353 InsertHeadList(&CurIcon->ProcessList, &Current->ListEntry);
354 Current->Process = Win32Process;
355
356 return TRUE;
357 }
358
359 PCURICON_OBJECT FASTCALL
360 IntFindExistingCurIconObject(PWINSTATION_OBJECT WinSta, HMODULE hModule,
361 HRSRC hRsrc, LONG cx, LONG cy)
362 {
363 PCURICON_OBJECT CurIcon;
364
365 LIST_FOR_EACH(CurIcon, &gCurIconList, CURICON_OBJECT, ListEntry)
366 {
367
368 // if(NT_SUCCESS(ObmReferenceObjectByPointer(Object, otCursorIcon))) //<- huh????
369 // ObmReferenceObject( CurIcon);
370 // {
371 if((CurIcon->hModule == hModule) && (CurIcon->hRsrc == hRsrc))
372 {
373 if(cx && ((cx != CurIcon->Size.cx) || (cy != CurIcon->Size.cy)))
374 {
375 // ObmDereferenceObject(CurIcon);
376 continue;
377 }
378 if (! ReferenceCurIconByProcess(CurIcon))
379 {
380 return NULL;
381 }
382
383 return CurIcon;
384 }
385 // }
386 // ObmDereferenceObject(CurIcon);
387
388 }
389
390 return NULL;
391 }
392
393 PCURICON_OBJECT FASTCALL
394 IntCreateCurIconHandle(PWINSTATION_OBJECT WinSta)
395 {
396 PCURICON_OBJECT CurIcon;
397 HANDLE hCurIcon;
398
399 CurIcon = ObmCreateObject(&gHandleTable, &hCurIcon, otCursorIcon, sizeof(CURICON_OBJECT));
400
401 if(!CurIcon)
402 {
403 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
404 return FALSE;
405 }
406
407 CurIcon->Self = hCurIcon;
408 InitializeListHead(&CurIcon->ProcessList);
409
410 if (! ReferenceCurIconByProcess(CurIcon))
411 {
412 DPRINT1("Failed to add process\n");
413 ObmDeleteObject(hCurIcon, otCursorIcon);
414 ObmDereferenceObject(CurIcon);
415 return NULL;
416 }
417
418 InsertHeadList(&gCurIconList, &CurIcon->ListEntry);
419
420 ObmDereferenceObject(CurIcon);
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 = PsGetWin32Process();
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 Ret = ObmDeleteObject(CurIcon->Self, otCursorIcon);
488
489 /* delete bitmaps */
490 if(bmpMask)
491 {
492 GDIOBJ_SetOwnership(bmpMask, PsGetCurrentProcess());
493 NtGdiDeleteObject(bmpMask);
494 }
495 if(bmpColor)
496 {
497 GDIOBJ_SetOwnership(bmpColor, PsGetCurrentProcess());
498 NtGdiDeleteObject(bmpColor);
499 }
500
501 return Ret;
502 }
503
504 VOID FASTCALL
505 IntCleanupCurIcons(struct _EPROCESS *Process, PW32PROCESS Win32Process)
506 {
507 PWINSTATION_OBJECT WinSta;
508 PCURICON_OBJECT CurIcon, tmp;
509 PCURICON_PROCESS ProcessData;
510
511 WinSta = IntGetWinStaObj();
512 if(WinSta == NULL)
513 {
514 return;
515 }
516
517 LIST_FOR_EACH_SAFE(CurIcon, tmp, &gCurIconList, CURICON_OBJECT, ListEntry)
518 {
519 // ObmReferenceObject(CurIcon);
520 // if(NT_SUCCESS(ObmReferenceObjectByPointer(Object, otCursorIcon)))
521 {
522 LIST_FOR_EACH(ProcessData, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
523 {
524 if (Win32Process == ProcessData->Process)
525 {
526 RemoveEntryList(&CurIcon->ListEntry);
527 IntDestroyCurIconObject(WinSta, CurIcon, TRUE);
528 break;
529 }
530 }
531
532 // ObmDereferenceObject(Object);
533 }
534
535
536 }
537
538 ObDereferenceObject(WinSta);
539 }
540
541 /*
542 * @implemented
543 */
544 HANDLE
545 STDCALL
546 NtUserCreateCursorIconHandle(PICONINFO IconInfo OPTIONAL, BOOL Indirect)
547 {
548 PCURICON_OBJECT CurIcon;
549 PWINSTATION_OBJECT WinSta;
550 PBITMAPOBJ bmp;
551 NTSTATUS Status;
552 HANDLE Ret;
553 DECLARE_RETURN(HANDLE);
554
555 DPRINT("Enter NtUserCreateCursorIconHandle\n");
556 UserEnterExclusive();
557
558 WinSta = IntGetWinStaObj();
559 if(WinSta == NULL)
560 {
561 RETURN( (HANDLE)0);
562 }
563
564 if (!(CurIcon = IntCreateCurIconHandle(WinSta)))
565 {
566 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
567 ObDereferenceObject(WinSta);
568 RETURN( (HANDLE)0);
569 }
570
571 Ret = CurIcon->Self;
572
573 if(IconInfo)
574 {
575 Status = MmCopyFromCaller(&CurIcon->IconInfo, IconInfo, sizeof(ICONINFO));
576 if(NT_SUCCESS(Status))
577 {
578 if(Indirect)
579 {
580 CurIcon->IconInfo.hbmMask = BITMAPOBJ_CopyBitmap(CurIcon->IconInfo.hbmMask);
581 CurIcon->IconInfo.hbmColor = BITMAPOBJ_CopyBitmap(CurIcon->IconInfo.hbmColor);
582 }
583 if(CurIcon->IconInfo.hbmColor &&
584 (bmp = BITMAPOBJ_LockBitmap(CurIcon->IconInfo.hbmColor)))
585 {
586 CurIcon->Size.cx = bmp->SurfObj.sizlBitmap.cx;
587 CurIcon->Size.cy = bmp->SurfObj.sizlBitmap.cy;
588 BITMAPOBJ_UnlockBitmap(bmp);
589 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmColor, NULL);
590 }
591 if(CurIcon->IconInfo.hbmMask &&
592 (bmp = BITMAPOBJ_LockBitmap(CurIcon->IconInfo.hbmMask)))
593 {
594 if (CurIcon->IconInfo.hbmColor == NULL)
595 {
596 CurIcon->Size.cx = bmp->SurfObj.sizlBitmap.cx;
597 CurIcon->Size.cy = bmp->SurfObj.sizlBitmap.cy / 2;
598 }
599 BITMAPOBJ_UnlockBitmap(bmp);
600 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmMask, NULL);
601 }
602 }
603 else
604 {
605 SetLastNtError(Status);
606 /* FIXME - Don't exit here */
607 }
608 }
609
610 ObDereferenceObject(WinSta);
611 RETURN( Ret);
612
613 CLEANUP:
614 DPRINT("Leave NtUserCreateCursorIconHandle, ret=%i\n",_ret_);
615 UserLeave();
616 END_CLEANUP;
617 }
618
619 /*
620 * @implemented
621 */
622 BOOL
623 STDCALL
624 NtUserGetCursorIconInfo(
625 HANDLE hCurIcon,
626 PICONINFO IconInfo)
627 {
628 ICONINFO ii;
629 PCURICON_OBJECT CurIcon;
630 PWINSTATION_OBJECT WinSta;
631 NTSTATUS Status;
632 BOOL Ret = FALSE;
633 DECLARE_RETURN(BOOL);
634
635 DPRINT("Enter NtUserGetCursorIconInfo\n");
636 UserEnterExclusive();
637
638 if(!IconInfo)
639 {
640 SetLastWin32Error(ERROR_INVALID_PARAMETER);
641 RETURN(FALSE);
642 }
643
644 WinSta = IntGetWinStaObj();
645 if(WinSta == NULL)
646 {
647 RETURN( FALSE);
648 }
649
650 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
651 {
652 ObDereferenceObject(WinSta);
653 RETURN( FALSE);
654 }
655
656 RtlCopyMemory(&ii, &CurIcon->IconInfo, sizeof(ICONINFO));
657
658 /* Copy bitmaps */
659 ii.hbmMask = BITMAPOBJ_CopyBitmap(ii.hbmMask);
660 ii.hbmColor = BITMAPOBJ_CopyBitmap(ii.hbmColor);
661
662 /* Copy fields */
663 Status = MmCopyToCaller(IconInfo, &ii, sizeof(ICONINFO));
664 if(NT_SUCCESS(Status))
665 Ret = TRUE;
666 else
667 SetLastNtError(Status);
668
669 ObDereferenceObject(WinSta);
670 RETURN( Ret);
671
672 CLEANUP:
673 DPRINT("Leave NtUserGetCursorIconInfo, ret=%i\n",_ret_);
674 UserLeave();
675 END_CLEANUP;
676 }
677
678
679 /*
680 * @implemented
681 */
682 BOOL
683 STDCALL
684 NtUserGetCursorIconSize(
685 HANDLE hCurIcon,
686 BOOL *fIcon,
687 SIZE *Size)
688 {
689 PCURICON_OBJECT CurIcon;
690 PBITMAPOBJ bmp;
691 PWINSTATION_OBJECT WinSta;
692 NTSTATUS Status;
693 BOOL Ret = FALSE;
694 SIZE SafeSize;
695 DECLARE_RETURN(BOOL);
696
697 DPRINT("Enter NtUserGetCursorIconSize\n");
698 UserEnterExclusive();
699
700 WinSta = IntGetWinStaObj();
701 if(WinSta == NULL)
702 {
703 RETURN( FALSE);
704 }
705
706 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
707 {
708 ObDereferenceObject(WinSta);
709 RETURN(FALSE);
710 }
711
712 /* Copy fields */
713 Status = MmCopyToCaller(fIcon, &CurIcon->IconInfo.fIcon, sizeof(BOOL));
714 if(!NT_SUCCESS(Status))
715 {
716 SetLastNtError(Status);
717 goto done;
718 }
719
720 bmp = BITMAPOBJ_LockBitmap(CurIcon->IconInfo.hbmColor);
721 if(!bmp)
722 goto done;
723
724 SafeSize.cx = bmp->SurfObj.sizlBitmap.cx;
725 SafeSize.cy = bmp->SurfObj.sizlBitmap.cy;
726 Status = MmCopyToCaller(Size, &SafeSize, sizeof(SIZE));
727 if(NT_SUCCESS(Status))
728 Ret = TRUE;
729 else
730 SetLastNtError(Status);
731
732 BITMAPOBJ_UnlockBitmap(bmp);
733
734 done:
735 ObDereferenceObject(WinSta);
736 RETURN( Ret);
737
738 CLEANUP:
739 DPRINT("Leave NtUserGetCursorIconSize, ret=%i\n",_ret_);
740 UserLeave();
741 END_CLEANUP;
742 }
743
744
745 /*
746 * @unimplemented
747 */
748 DWORD
749 STDCALL
750 NtUserGetCursorFrameInfo(
751 DWORD Unknown0,
752 DWORD Unknown1,
753 DWORD Unknown2,
754 DWORD Unknown3)
755 {
756 UNIMPLEMENTED
757
758 return 0;
759 }
760
761
762 /*
763 * @implemented
764 */
765 BOOL
766 STDCALL
767 NtUserGetCursorInfo(
768 PCURSORINFO pci)
769 {
770 CURSORINFO SafeCi;
771 PSYSTEM_CURSORINFO CurInfo;
772 PWINSTATION_OBJECT WinSta;
773 NTSTATUS Status;
774 PCURICON_OBJECT CurIcon;
775 DECLARE_RETURN(BOOL);
776
777 DPRINT("Enter NtUserGetCursorInfo\n");
778 UserEnterExclusive();
779
780 #if 1
781
782 HDC hDC;
783
784 /* FIXME - get the screen dc from the window station or desktop */
785 if (!(hDC = IntGetScreenDC()))
786 {
787 RETURN( FALSE);
788 }
789 #endif
790
791 Status = MmCopyFromCaller(&SafeCi.cbSize, pci, sizeof(DWORD));
792 if(!NT_SUCCESS(Status))
793 {
794 SetLastNtError(Status);
795 RETURN( FALSE);
796 }
797
798 if(SafeCi.cbSize != sizeof(CURSORINFO))
799 {
800 SetLastWin32Error(ERROR_INVALID_PARAMETER);
801 RETURN( FALSE);
802 }
803
804 WinSta = IntGetWinStaObj();
805 if(WinSta == NULL)
806 {
807 RETURN( FALSE);
808 }
809
810 CurInfo = IntGetSysCursorInfo(WinSta);
811 CurIcon = (PCURICON_OBJECT)CurInfo->CurrentCursorObject;
812
813 SafeCi.flags = ((CurInfo->ShowingCursor && CurIcon) ? CURSOR_SHOWING : 0);
814 SafeCi.hCursor = (CurIcon ? (HCURSOR)CurIcon->Self : (HCURSOR)0);
815
816 IntGetCursorLocation(WinSta, &SafeCi.ptScreenPos);
817
818 Status = MmCopyToCaller(pci, &SafeCi, sizeof(CURSORINFO));
819 if(!NT_SUCCESS(Status))
820 {
821 ObDereferenceObject(WinSta);
822 SetLastNtError(Status);
823 RETURN( FALSE);
824 }
825
826 ObDereferenceObject(WinSta);
827 RETURN( TRUE);
828
829 CLEANUP:
830 DPRINT("Leave NtUserGetCursorInfo, ret=%i\n",_ret_);
831 UserLeave();
832 END_CLEANUP;
833 }
834
835
836 /*
837 * @implemented
838 */
839 BOOL
840 STDCALL
841 NtUserClipCursor(
842 RECT *UnsafeRect)
843 {
844 /* FIXME - check if process has WINSTA_WRITEATTRIBUTES */
845
846 PWINSTATION_OBJECT WinSta;
847 PSYSTEM_CURSORINFO CurInfo;
848 RECT Rect;
849 PWINDOW_OBJECT DesktopWindow = NULL;
850 POINT MousePos = {0};
851 DECLARE_RETURN(BOOL);
852
853 DPRINT("Enter NtUserClipCursor\n");
854 UserEnterExclusive();
855
856 WinSta = IntGetWinStaObj();
857 if (WinSta == NULL)
858 {
859 RETURN( FALSE);
860 }
861
862 if (NULL != UnsafeRect && ! NT_SUCCESS(MmCopyFromCaller(&Rect, UnsafeRect, sizeof(RECT))))
863 {
864 ObDereferenceObject(WinSta);
865 SetLastWin32Error(ERROR_INVALID_PARAMETER);
866 RETURN( FALSE);
867 }
868
869 CurInfo = IntGetSysCursorInfo(WinSta);
870 IntGetCursorLocation(WinSta, &MousePos);
871
872 if(WinSta->ActiveDesktop)
873 DesktopWindow = UserGetWindowObject(WinSta->ActiveDesktop->DesktopWindow);
874
875 if((Rect.right > Rect.left) && (Rect.bottom > Rect.top)
876 && DesktopWindow && UnsafeRect != NULL)
877 {
878 MOUSEINPUT mi;
879
880 CurInfo->CursorClipInfo.IsClipped = TRUE;
881 CurInfo->CursorClipInfo.Left = max(Rect.left, DesktopWindow->WindowRect.left);
882 CurInfo->CursorClipInfo.Top = max(Rect.top, DesktopWindow->WindowRect.top);
883 CurInfo->CursorClipInfo.Right = min(Rect.right - 1, DesktopWindow->WindowRect.right - 1);
884 CurInfo->CursorClipInfo.Bottom = min(Rect.bottom - 1, DesktopWindow->WindowRect.bottom - 1);
885
886 mi.dx = MousePos.x;
887 mi.dy = MousePos.y;
888 mi.mouseData = 0;
889 mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
890 mi.time = 0;
891 mi.dwExtraInfo = 0;
892 IntMouseInput(&mi);
893
894 RETURN( TRUE);
895 }
896
897 CurInfo->CursorClipInfo.IsClipped = FALSE;
898 ObDereferenceObject(WinSta);
899
900 RETURN( TRUE);
901
902 CLEANUP:
903 DPRINT("Leave NtUserClipCursor, ret=%i\n",_ret_);
904 UserLeave();
905 END_CLEANUP;
906 }
907
908
909 /*
910 * @implemented
911 */
912 BOOL
913 STDCALL
914 NtUserDestroyCursorIcon(
915 HANDLE hCurIcon,
916 DWORD Unknown)
917 {
918 PWINSTATION_OBJECT WinSta;
919 PCURICON_OBJECT CurIcon;
920 BOOL ret;
921 DECLARE_RETURN(BOOL);
922
923 DPRINT("Enter NtUserDestroyCursorIcon\n");
924 UserEnterExclusive();
925
926 WinSta = IntGetWinStaObj();
927 if(WinSta == NULL)
928 {
929 RETURN( FALSE);
930 }
931
932 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
933 {
934 ObDereferenceObject(WinSta);
935 RETURN(FALSE);
936 }
937
938 ret = IntDestroyCurIconObject(WinSta, CurIcon, FALSE);
939
940 ObDereferenceObject(WinSta);
941 RETURN(ret);
942
943 CLEANUP:
944 DPRINT("Leave NtUserDestroyCursorIcon, ret=%i\n",_ret_);
945 UserLeave();
946 END_CLEANUP;
947 }
948
949
950 /*
951 * @implemented
952 */
953 HICON
954 STDCALL
955 NtUserFindExistingCursorIcon(
956 HMODULE hModule,
957 HRSRC hRsrc,
958 LONG cx,
959 LONG cy)
960 {
961 PCURICON_OBJECT CurIcon;
962 PWINSTATION_OBJECT WinSta;
963 HANDLE Ret = (HANDLE)0;
964 DECLARE_RETURN(HICON);
965
966 DPRINT("Enter NtUserFindExistingCursorIcon\n");
967 UserEnterExclusive();
968
969 WinSta = IntGetWinStaObj();
970 if(WinSta == NULL)
971 {
972 RETURN( Ret);
973 }
974
975 CurIcon = IntFindExistingCurIconObject(WinSta, hModule, hRsrc, cx, cy);
976 if(CurIcon)
977 {
978 Ret = CurIcon->Self;
979
980 // IntReleaseCurIconObject(CurIcon);//faxme: is this correct? does IntFindExistingCurIconObject add a ref?
981 ObDereferenceObject(WinSta);
982 RETURN( Ret);
983 }
984
985 SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
986 ObDereferenceObject(WinSta);
987 RETURN( (HANDLE)0);
988
989 CLEANUP:
990 DPRINT("Leave NtUserFindExistingCursorIcon, ret=%i\n",_ret_);
991 UserLeave();
992 END_CLEANUP;
993 }
994
995
996 /*
997 * @implemented
998 */
999 BOOL
1000 STDCALL
1001 NtUserGetClipCursor(
1002 RECT *lpRect)
1003 {
1004 /* FIXME - check if process has WINSTA_READATTRIBUTES */
1005 PSYSTEM_CURSORINFO CurInfo;
1006 PWINSTATION_OBJECT WinSta;
1007 RECT Rect;
1008 NTSTATUS Status;
1009 DECLARE_RETURN(BOOL);
1010
1011 DPRINT("Enter NtUserGetClipCursor\n");
1012 UserEnterExclusive();
1013
1014 if(!lpRect)
1015 RETURN( FALSE);
1016
1017 WinSta = IntGetWinStaObj();
1018 if (WinSta == NULL)
1019 {
1020 RETURN( FALSE);
1021 }
1022
1023 CurInfo = IntGetSysCursorInfo(WinSta);
1024 if(CurInfo->CursorClipInfo.IsClipped)
1025 {
1026 Rect.left = CurInfo->CursorClipInfo.Left;
1027 Rect.top = CurInfo->CursorClipInfo.Top;
1028 Rect.right = CurInfo->CursorClipInfo.Right;
1029 Rect.bottom = CurInfo->CursorClipInfo.Bottom;
1030 }
1031 else
1032 {
1033 Rect.left = 0;
1034 Rect.top = 0;
1035 Rect.right = UserGetSystemMetrics(SM_CXSCREEN);
1036 Rect.bottom = UserGetSystemMetrics(SM_CYSCREEN);
1037 }
1038
1039 Status = MmCopyToCaller((PRECT)lpRect, &Rect, sizeof(RECT));
1040 if(!NT_SUCCESS(Status))
1041 {
1042 ObDereferenceObject(WinSta);
1043 SetLastNtError(Status);
1044 RETURN( FALSE);
1045 }
1046
1047 ObDereferenceObject(WinSta);
1048
1049 RETURN( TRUE);
1050
1051 CLEANUP:
1052 DPRINT("Leave NtUserGetClipCursor, ret=%i\n",_ret_);
1053 UserLeave();
1054 END_CLEANUP;
1055 }
1056
1057
1058 /*
1059 * @implemented
1060 */
1061 HCURSOR
1062 STDCALL
1063 NtUserSetCursor(
1064 HCURSOR hCursor)
1065 {
1066 PCURICON_OBJECT CurIcon;
1067 HICON OldCursor;
1068 PWINSTATION_OBJECT WinSta;
1069 DECLARE_RETURN(HCURSOR);
1070
1071 DPRINT("Enter NtUserSetCursor\n");
1072 UserEnterExclusive();
1073
1074 WinSta = IntGetWinStaObj();
1075 if(WinSta == NULL)
1076 {
1077 RETURN(NULL);
1078 }
1079
1080 if(!(CurIcon = UserGetCurIconObject(hCursor)))
1081 {
1082 ObDereferenceObject(WinSta);
1083 RETURN(NULL);
1084 }
1085
1086 OldCursor = IntSetCursor(WinSta, CurIcon, FALSE);
1087
1088 ObDereferenceObject(WinSta);
1089
1090 RETURN(OldCursor);
1091
1092 CLEANUP:
1093 DPRINT("Leave NtUserSetCursor, ret=%i\n",_ret_);
1094 UserLeave();
1095 END_CLEANUP;
1096 }
1097
1098
1099 /*
1100 * @implemented
1101 */
1102 BOOL
1103 STDCALL
1104 NtUserSetCursorIconContents(
1105 HANDLE hCurIcon,
1106 PICONINFO IconInfo)
1107 {
1108 PCURICON_OBJECT CurIcon;
1109 PBITMAPOBJ bmp;
1110 PWINSTATION_OBJECT WinSta;
1111 NTSTATUS Status;
1112 BOOL Ret = FALSE;
1113 DECLARE_RETURN(BOOL);
1114
1115 DPRINT("Enter NtUserSetCursorIconContents\n");
1116 UserEnterExclusive();
1117
1118 WinSta = IntGetWinStaObj();
1119 if(WinSta == NULL)
1120 {
1121 RETURN( FALSE);
1122 }
1123
1124 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
1125 {
1126 ObDereferenceObject(WinSta);
1127 RETURN(FALSE);
1128 }
1129
1130 /* Copy fields */
1131 Status = MmCopyFromCaller(&CurIcon->IconInfo, IconInfo, sizeof(ICONINFO));
1132 if(!NT_SUCCESS(Status))
1133 {
1134 SetLastNtError(Status);
1135 goto done;
1136 }
1137
1138 bmp = BITMAPOBJ_LockBitmap(CurIcon->IconInfo.hbmColor);
1139 if(bmp)
1140 {
1141 CurIcon->Size.cx = bmp->SurfObj.sizlBitmap.cx;
1142 CurIcon->Size.cy = bmp->SurfObj.sizlBitmap.cy;
1143 BITMAPOBJ_UnlockBitmap(bmp);
1144 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmColor, NULL);
1145 }
1146 else
1147 {
1148 bmp = BITMAPOBJ_LockBitmap(CurIcon->IconInfo.hbmMask);
1149 if(!bmp)
1150 goto done;
1151
1152 CurIcon->Size.cx = bmp->SurfObj.sizlBitmap.cx;
1153 CurIcon->Size.cy = bmp->SurfObj.sizlBitmap.cy / 2;
1154
1155 BITMAPOBJ_UnlockBitmap(bmp);
1156 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmMask, NULL);
1157 }
1158
1159 Ret = TRUE;
1160
1161 done:
1162
1163 ObDereferenceObject(WinSta);
1164 RETURN( Ret);
1165
1166 CLEANUP:
1167 DPRINT("Leave NtUserSetCursorIconContents, ret=%i\n",_ret_);
1168 UserLeave();
1169 END_CLEANUP;
1170 }
1171
1172
1173 /*
1174 * @implemented
1175 */
1176 BOOL
1177 STDCALL
1178 NtUserSetCursorIconData(
1179 HANDLE hCurIcon,
1180 PBOOL fIcon,
1181 POINT *Hotspot,
1182 HMODULE hModule,
1183 HRSRC hRsrc,
1184 HRSRC hGroupRsrc)
1185 {
1186 PCURICON_OBJECT CurIcon;
1187 PWINSTATION_OBJECT WinSta;
1188 NTSTATUS Status;
1189 POINT SafeHotspot;
1190 BOOL Ret = FALSE;
1191 DECLARE_RETURN(BOOL);
1192
1193 DPRINT("Enter NtUserSetCursorIconData\n");
1194 UserEnterExclusive();
1195
1196 WinSta = IntGetWinStaObj();
1197 if(WinSta == NULL)
1198 {
1199 RETURN( FALSE);
1200 }
1201
1202 if(!(CurIcon = UserGetCurIconObject(hCurIcon)))
1203 {
1204 ObDereferenceObject(WinSta);
1205 RETURN(FALSE);
1206 }
1207
1208 CurIcon->hModule = hModule;
1209 CurIcon->hRsrc = hRsrc;
1210 CurIcon->hGroupRsrc = hGroupRsrc;
1211
1212 /* Copy fields */
1213 if(fIcon)
1214 {
1215 Status = MmCopyFromCaller(&CurIcon->IconInfo.fIcon, fIcon, sizeof(BOOL));
1216 if(!NT_SUCCESS(Status))
1217 {
1218 SetLastNtError(Status);
1219 goto done;
1220 }
1221 }
1222 else
1223 {
1224 if(!Hotspot)
1225 Ret = TRUE;
1226 }
1227
1228 if(Hotspot)
1229 {
1230 Status = MmCopyFromCaller(&SafeHotspot, Hotspot, sizeof(POINT));
1231 if(NT_SUCCESS(Status))
1232 {
1233 CurIcon->IconInfo.xHotspot = SafeHotspot.x;
1234 CurIcon->IconInfo.yHotspot = SafeHotspot.y;
1235
1236 Ret = TRUE;
1237 }
1238 else
1239 SetLastNtError(Status);
1240 }
1241
1242 if(!fIcon && !Hotspot)
1243 {
1244 Ret = TRUE;
1245 }
1246
1247 done:
1248 ObDereferenceObject(WinSta);
1249 RETURN( Ret);
1250
1251
1252 CLEANUP:
1253 DPRINT("Leave NtUserSetCursorIconData, ret=%i\n",_ret_);
1254 UserLeave();
1255 END_CLEANUP;
1256 }
1257
1258
1259 /*
1260 * @unimplemented
1261 */
1262 BOOL
1263 STDCALL
1264 NtUserSetSystemCursor(
1265 HCURSOR hcur,
1266 DWORD id)
1267 {
1268 return FALSE;
1269 }
1270
1271
1272 #define STRETCH_CAN_SRCCOPY_ONLY
1273
1274 #ifdef STRETCH_CAN_SRCCOPY_ONLY
1275 void
1276 FASTCALL
1277 DoStretchBlt(HDC DcDest, int XDest, int YDest, int WidthDest, int HeightDest,
1278 HDC DcSrc, int XSrc, int YSrc, int WidthSrc, int HeightSrc,
1279 DWORD Rop3, BOOL Color)
1280 {
1281 HDC DcStretched;
1282 HBITMAP BitmapStretched;
1283 HBITMAP OldBitmap;
1284
1285 if (WidthDest == WidthSrc && HeightDest == HeightSrc)
1286 {
1287 NtGdiBitBlt(DcDest, XDest, YDest, WidthDest, HeightDest,
1288 DcSrc, XSrc, YSrc, Rop3, 0, 0);
1289 }
1290 else if (SRCCOPY == Rop3)
1291 {
1292 NtGdiStretchBlt(DcDest, XDest, YDest, WidthDest, HeightDest,
1293 DcSrc, XSrc, YSrc, WidthSrc, HeightSrc,
1294 Rop3, 0);
1295 }
1296 else
1297 {
1298 DcStretched = NtGdiCreateCompatibleDC(DcSrc);
1299 if (NULL == DcStretched)
1300 {
1301 DPRINT1("Failed to create compatible DC\n");
1302 return;
1303 }
1304 if (Color)
1305 {
1306 BitmapStretched = NtGdiCreateCompatibleBitmap(DcDest, WidthDest,
1307 HeightDest);
1308 }
1309 else
1310 {
1311 BitmapStretched = NtGdiCreateBitmap(WidthDest, HeightDest, 1, 1, NULL);
1312 }
1313 if (NULL == BitmapStretched)
1314 {
1315 NtGdiDeleteDC(DcStretched);
1316 DPRINT1("Failed to create temporary bitmap\n");
1317 return;
1318 }
1319 OldBitmap = NtGdiSelectObject(DcStretched, BitmapStretched);
1320 if (NULL == OldBitmap)
1321 {
1322 NtGdiDeleteObject(BitmapStretched);
1323 NtGdiDeleteDC(DcStretched);
1324 DPRINT1("Failed to create temporary bitmap\n");
1325 return;
1326 }
1327 if (! NtGdiStretchBlt(DcStretched, 0, 0, WidthDest, HeightDest,
1328 DcSrc, XSrc, YSrc, WidthSrc, HeightSrc,
1329 SRCCOPY, 0) ||
1330 ! NtGdiBitBlt(DcDest, XDest, YDest, WidthDest, HeightDest,
1331 DcStretched, 0, 0, Rop3, 0, 0))
1332 {
1333 DPRINT1("Failed to blt\n");
1334 }
1335 NtGdiSelectObject(DcStretched, OldBitmap);
1336 NtGdiDeleteObject(BitmapStretched);
1337 NtGdiDeleteDC(DcStretched);
1338 }
1339 }
1340 #else
1341 #define DoStretchBlt(DcDest, XDest, YDest, WidthDest, HeightDest, \
1342 DcSrc, XSrc, YSrc, WidthSrc, HeightSrc, Rop3, Color) \
1343 NtGdiStretchBlt((DcDest), (XDest), (YDest), (WidthDest), (HeightDest), \
1344 (DcSrc), (XSrc), (YSrc), (WidthSrc), (HeightSrc), \
1345 (Rop3), 0)
1346 #endif /* STRETCH_CAN_SRCCOPY_ONLY */
1347
1348 /*
1349 * @implemented
1350 */
1351 BOOL
1352 STDCALL
1353 NtUserDrawIconEx(
1354 HDC hdc,
1355 int xLeft,
1356 int yTop,
1357 HICON hIcon,
1358 int cxWidth,
1359 int cyHeight,
1360 UINT istepIfAniCur,
1361 HBRUSH hbrFlickerFreeDraw,
1362 UINT diFlags,
1363 DWORD Unknown0,
1364 DWORD Unknown1)
1365 {
1366 PCURICON_OBJECT CurIcon;
1367 PWINSTATION_OBJECT WinSta;
1368 HBITMAP hbmMask, hbmColor;
1369 BITMAP bmpMask, bmpColor;
1370 BOOL DoFlickerFree;
1371 SIZE IconSize;
1372 COLORREF oldFg, oldBg;
1373 HDC hdcMem, hdcOff = (HDC)0;
1374 HBITMAP hbmOff = (HBITMAP)0;
1375 HGDIOBJ hOldOffBrush = 0, hOldOffBmp = 0, hOldMem;
1376 BOOL Ret = FALSE;
1377 INT nStretchMode;
1378
1379 DECLARE_RETURN(BOOL);
1380
1381 DPRINT("Enter NtUserDrawIconEx\n");
1382 UserEnterExclusive();
1383
1384 WinSta = IntGetWinStaObj();
1385 if(WinSta == NULL)
1386 {
1387 RETURN( FALSE);
1388 }
1389
1390 if (!(CurIcon = UserGetCurIconObject(hIcon)))
1391 {
1392 ObDereferenceObject(WinSta);
1393 RETURN(FALSE);
1394 }
1395
1396 hbmMask = CurIcon->IconInfo.hbmMask;
1397 hbmColor = CurIcon->IconInfo.hbmColor;
1398
1399 if(istepIfAniCur)
1400 DPRINT1("NtUserDrawIconEx: istepIfAniCur is not supported!\n");
1401
1402 if(!hbmMask || !IntGdiGetObject(hbmMask, sizeof(BITMAP), &bmpMask))
1403 goto done;
1404
1405 if(hbmColor && !IntGdiGetObject(hbmColor, sizeof(BITMAP), &bmpColor))
1406 goto done;
1407
1408 if(hbmColor)
1409 {
1410 IconSize.cx = bmpColor.bmWidth;
1411 IconSize.cy = bmpColor.bmHeight;
1412 }
1413 else
1414 {
1415 IconSize.cx = bmpMask.bmWidth;
1416 IconSize.cy = bmpMask.bmHeight / 2;
1417 }
1418
1419 if(!diFlags)
1420 diFlags = DI_NORMAL;
1421
1422 if(!cxWidth)
1423 cxWidth = ((diFlags & DI_DEFAULTSIZE) ? UserGetSystemMetrics(SM_CXICON) : IconSize.cx);
1424 if(!cyHeight)
1425 cyHeight = ((diFlags & DI_DEFAULTSIZE) ? UserGetSystemMetrics(SM_CYICON) : IconSize.cy);
1426
1427 DoFlickerFree = (hbrFlickerFreeDraw && (NtGdiGetObjectType(hbrFlickerFreeDraw) == OBJ_BRUSH));
1428
1429 if(DoFlickerFree)
1430 {
1431 RECT r;
1432 r.right = cxWidth;
1433 r.bottom = cyHeight;
1434
1435 hdcOff = NtGdiCreateCompatibleDC(hdc);
1436 if(!hdcOff)
1437 goto done;
1438
1439 hbmOff = NtGdiCreateCompatibleBitmap(hdc, cxWidth, cyHeight);
1440 if(!hbmOff)
1441 {
1442 NtGdiDeleteDC(hdcOff);
1443 goto done;
1444 }
1445 hOldOffBrush = NtGdiSelectObject(hdcOff, hbrFlickerFreeDraw);
1446 hOldOffBmp = NtGdiSelectObject(hdcOff, hbmOff);
1447 NtGdiPatBlt(hdcOff, 0, 0, r.right, r.bottom, PATCOPY);
1448 NtGdiSelectObject(hdcOff, hbmOff);
1449 }
1450
1451 hdcMem = NtGdiCreateCompatibleDC(hdc);
1452 if(!hdcMem)
1453 goto cleanup;
1454
1455 if(!DoFlickerFree)
1456 hdcOff = hdc;
1457
1458 nStretchMode = NtGdiSetStretchBltMode(hdcOff, STRETCH_DELETESCANS);
1459
1460 oldFg = NtGdiSetTextColor(hdcOff, RGB(0, 0, 0));
1461 oldBg = NtGdiSetBkColor(hdcOff, RGB(255, 255, 255));
1462
1463 if(diFlags & DI_MASK)
1464 {
1465 hOldMem = NtGdiSelectObject(hdcMem, hbmMask);
1466
1467 DoStretchBlt(hdcOff, (DoFlickerFree ? 0 : xLeft),
1468 (DoFlickerFree ? 0 : yTop), cxWidth, cyHeight, hdcMem,
1469 0, 0, IconSize.cx, IconSize.cy,
1470 ((diFlags & DI_IMAGE) ? SRCAND : SRCCOPY), FALSE);
1471
1472 if(!hbmColor && (bmpMask.bmHeight == 2 * bmpMask.bmWidth) && (diFlags & DI_IMAGE))
1473 {
1474 DoStretchBlt(hdcOff, (DoFlickerFree ? 0 : xLeft),
1475 (DoFlickerFree ? 0 : yTop), cxWidth, cyHeight, hdcMem,
1476 0, IconSize.cy, IconSize.cx, IconSize.cy, SRCINVERT,
1477 FALSE);
1478
1479 diFlags &= ~DI_IMAGE;
1480 }
1481 NtGdiSelectObject(hdcMem, hOldMem);
1482 }
1483
1484 if(diFlags & DI_IMAGE)
1485 {
1486 hOldMem = NtGdiSelectObject(hdcMem, (hbmColor ? hbmColor : hbmMask));
1487
1488 DoStretchBlt(hdcOff, (DoFlickerFree ? 0 : xLeft),
1489 (DoFlickerFree ? 0 : yTop), cxWidth, cyHeight, hdcMem,
1490 0, (hbmColor ? 0 : IconSize.cy), IconSize.cx, IconSize.cy,
1491 ((diFlags & DI_MASK) ? SRCINVERT : SRCCOPY),
1492 NULL != hbmColor);
1493
1494 NtGdiSelectObject(hdcMem, hOldMem);
1495 }
1496
1497 if(DoFlickerFree)
1498 NtGdiBitBlt(hdc, xLeft, yTop, cxWidth, cyHeight, hdcOff, 0, 0, SRCCOPY, 0, 0);
1499
1500 NtGdiSetTextColor(hdcOff, oldFg);
1501 NtGdiSetBkColor(hdcOff, oldBg);
1502
1503 NtGdiSetStretchBltMode(hdcOff, nStretchMode);
1504
1505 Ret = TRUE;
1506
1507 cleanup:
1508 if(DoFlickerFree)
1509 {
1510
1511 NtGdiSelectObject(hdcOff, hOldOffBmp);
1512 NtGdiSelectObject(hdcOff, hOldOffBrush);
1513 NtGdiDeleteObject(hbmOff);
1514 NtGdiDeleteDC(hdcOff);
1515 }
1516 if(hdcMem)
1517 NtGdiDeleteDC(hdcMem);
1518
1519 done:
1520 ObDereferenceObject(WinSta);
1521
1522 RETURN( Ret);
1523
1524 CLEANUP:
1525 DPRINT("Leave NtUserDrawIconEx, ret=%i\n",_ret_);
1526 UserLeave();
1527 END_CLEANUP;
1528 }
1529