Use correct context.
[reactos.git] / reactos / subsys / win32k / ntuser / desktop.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 * $Id: desktop.c,v 1.23 2004/11/06 22:28:11 gvg Exp $
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: Desktops
24 * FILE: subsys/win32k/ntuser/desktop.c
25 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
26 * REVISION HISTORY:
27 * 06-06-2001 CSH Created
28 */
29
30 /* INCLUDES ******************************************************************/
31 #include <w32k.h>
32
33 #if 0
34 /* not yet defined in w32api... */
35 NTSTATUS STDCALL
36 ObFindHandleForObject(IN PEPROCESS Process,
37 IN PVOID Object,
38 IN POBJECT_TYPE ObjectType,
39 IN POBJECT_HANDLE_INFORMATION HandleInformation,
40 OUT PHANDLE Handle);
41 #else
42 #define ObFindHandleForObject(Process, Object, ObjectType, HandleInformation, Handle) \
43 (STATUS_UNSUCCESSFUL)
44 #endif
45
46 /* GLOBALS *******************************************************************/
47
48 /* Currently active desktop */
49 PDESKTOP_OBJECT InputDesktop = NULL;
50 HDESK InputDesktopHandle = NULL;
51 HDC ScreenDeviceContext = NULL;
52
53 /* INITALIZATION FUNCTIONS ****************************************************/
54
55 NTSTATUS FASTCALL
56 InitDesktopImpl(VOID)
57 {
58 return STATUS_SUCCESS;
59 }
60
61 NTSTATUS FASTCALL
62 CleanupDesktopImpl(VOID)
63 {
64 return STATUS_SUCCESS;
65 }
66
67 /* PRIVATE FUNCTIONS **********************************************************/
68
69 /*
70 * IntValidateDesktopHandle
71 *
72 * Validates the desktop handle.
73 *
74 * Remarks
75 * If the function succeeds, the handle remains referenced. If the
76 * fucntion fails, last error is set.
77 */
78
79 NTSTATUS FASTCALL
80 IntValidateDesktopHandle(
81 HDESK Desktop,
82 KPROCESSOR_MODE AccessMode,
83 ACCESS_MASK DesiredAccess,
84 PDESKTOP_OBJECT *Object)
85 {
86 NTSTATUS Status;
87
88 Status = ObReferenceObjectByHandle(
89 Desktop,
90 DesiredAccess,
91 ExDesktopObjectType,
92 AccessMode,
93 (PVOID*)Object,
94 NULL);
95
96 if (!NT_SUCCESS(Status))
97 SetLastNtError(Status);
98
99 return Status;
100 }
101
102 VOID FASTCALL
103 IntGetDesktopWorkArea(PDESKTOP_OBJECT Desktop, PRECT Rect)
104 {
105 PRECT Ret;
106
107 ASSERT(Desktop);
108
109 Ret = &Desktop->WorkArea;
110 if((Ret->right == -1) && ScreenDeviceContext)
111 {
112 PDC dc;
113 BITMAPOBJ *BitmapObj;
114 dc = DC_LockDc(ScreenDeviceContext);
115 BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
116 if(BitmapObj)
117 {
118 Ret->right = BitmapObj->SurfObj.sizlBitmap.cx;
119 Ret->bottom = BitmapObj->SurfObj.sizlBitmap.cy;
120 BITMAPOBJ_UnlockBitmap(dc->w.hBitmap);
121 }
122 DC_UnlockDc(ScreenDeviceContext);
123 }
124
125 if(Rect)
126 {
127 *Rect = *Ret;
128 }
129 }
130
131 PDESKTOP_OBJECT FASTCALL
132 IntGetActiveDesktop(VOID)
133 {
134 return InputDesktop;
135 }
136
137 /*
138 * returns or creates a handle to the desktop object
139 */
140 HDESK FASTCALL
141 IntGetDesktopObjectHandle(PDESKTOP_OBJECT DesktopObject)
142 {
143 NTSTATUS Status;
144 HDESK Ret;
145
146 ASSERT(DesktopObject);
147
148 Status = ObFindHandleForObject(PsGetCurrentProcess(),
149 DesktopObject,
150 ExDesktopObjectType,
151 NULL,
152 (PHANDLE)&Ret);
153
154 if(!NT_SUCCESS(Status))
155 {
156 Status = ObOpenObjectByPointer(DesktopObject,
157 0,
158 NULL,
159 0,
160 ExDesktopObjectType,
161 UserMode,
162 (PHANDLE)&Ret);
163 if(!NT_SUCCESS(Status))
164 {
165 /* unable to create a handle */
166 DPRINT1("Unable to create a desktop handle\n");
167 return NULL;
168 }
169 }
170
171 return Ret;
172 }
173
174 PUSER_MESSAGE_QUEUE FASTCALL
175 IntGetFocusMessageQueue(VOID)
176 {
177 PDESKTOP_OBJECT pdo = IntGetActiveDesktop();
178 if (!pdo)
179 {
180 DPRINT("No active desktop\n");
181 return(NULL);
182 }
183 return (PUSER_MESSAGE_QUEUE)pdo->ActiveMessageQueue;
184 }
185
186 VOID FASTCALL
187 IntSetFocusMessageQueue(PUSER_MESSAGE_QUEUE NewQueue)
188 {
189 PUSER_MESSAGE_QUEUE Old;
190 PDESKTOP_OBJECT pdo = IntGetActiveDesktop();
191 if (!pdo)
192 {
193 DPRINT("No active desktop\n");
194 return;
195 }
196 if(NewQueue != NULL)
197 {
198 if(NewQueue->Desktop != NULL)
199 {
200 DPRINT("Message Queue already attached to another desktop!\n");
201 return;
202 }
203 IntReferenceMessageQueue(NewQueue);
204 InterlockedExchange((LONG*)&NewQueue->Desktop, (LONG)pdo);
205 }
206 Old = (PUSER_MESSAGE_QUEUE)InterlockedExchange((LONG*)&pdo->ActiveMessageQueue, (LONG)NewQueue);
207 if(Old != NULL)
208 {
209 InterlockedExchange((LONG*)&Old->Desktop, 0);
210 IntDereferenceMessageQueue(Old);
211 }
212 }
213
214 HWND FASTCALL IntGetDesktopWindow(VOID)
215 {
216 PDESKTOP_OBJECT pdo = IntGetActiveDesktop();
217 if (!pdo)
218 {
219 DPRINT("No active desktop\n");
220 return NULL;
221 }
222 return pdo->DesktopWindow;
223 }
224
225 HWND FASTCALL IntGetCurrentThreadDesktopWindow(VOID)
226 {
227 PDESKTOP_OBJECT pdo = PsGetWin32Thread()->Desktop;
228 if (NULL == pdo)
229 {
230 DPRINT1("Thread doesn't have a desktop\n");
231 return NULL;
232 }
233 return pdo->DesktopWindow;
234 }
235
236 /* PUBLIC FUNCTIONS ***********************************************************/
237
238 NTSTATUS FASTCALL
239 IntShowDesktop(PDESKTOP_OBJECT Desktop, ULONG Width, ULONG Height)
240 {
241 CSRSS_API_REQUEST Request;
242 CSRSS_API_REPLY Reply;
243
244 Request.Type = CSRSS_SHOW_DESKTOP;
245 Request.Data.ShowDesktopRequest.DesktopWindow = Desktop->DesktopWindow;
246 Request.Data.ShowDesktopRequest.Width = Width;
247 Request.Data.ShowDesktopRequest.Height = Height;
248
249 return CsrNotify(&Request, &Reply);
250 }
251
252 NTSTATUS FASTCALL
253 IntHideDesktop(PDESKTOP_OBJECT Desktop)
254 {
255 #if 0
256 CSRSS_API_REQUEST Request;
257 CSRSS_API_REPLY Reply;
258
259 Request.Type = CSRSS_HIDE_DESKTOP;
260 Request.Data.HideDesktopRequest.DesktopWindow = Desktop->DesktopWindow;
261
262 return NotifyCsrss(&Request, &Reply);
263 #else
264 PWINDOW_OBJECT DesktopWindow;
265
266 DesktopWindow = IntGetWindowObject(Desktop->DesktopWindow);
267 if (! DesktopWindow)
268 {
269 return ERROR_INVALID_WINDOW_HANDLE;
270 }
271 DesktopWindow->Style &= ~WS_VISIBLE;
272
273 return STATUS_SUCCESS;
274 #endif
275 }
276
277 /*
278 * NtUserCreateDesktop
279 *
280 * Creates a new desktop.
281 *
282 * Parameters
283 * lpszDesktopName
284 * Name of the new desktop.
285 *
286 * dwFlags
287 * Interaction flags.
288 *
289 * dwDesiredAccess
290 * Requested type of access.
291 *
292 * lpSecurity
293 * Security descriptor.
294 *
295 * hWindowStation
296 * Handle to window station on which to create the desktop.
297 *
298 * Return Value
299 * If the function succeeds, the return value is a handle to the newly
300 * created desktop. If the specified desktop already exists, the function
301 * succeeds and returns a handle to the existing desktop. When you are
302 * finished using the handle, call the CloseDesktop function to close it.
303 * If the function fails, the return value is NULL.
304 *
305 * Status
306 * @implemented
307 */
308
309 HDESK STDCALL
310 NtUserCreateDesktop(
311 PUNICODE_STRING lpszDesktopName,
312 DWORD dwFlags,
313 ACCESS_MASK dwDesiredAccess,
314 LPSECURITY_ATTRIBUTES lpSecurity,
315 HWINSTA hWindowStation)
316 {
317 OBJECT_ATTRIBUTES ObjectAttributes;
318 PWINSTATION_OBJECT WinStaObject;
319 PDESKTOP_OBJECT DesktopObject;
320 UNICODE_STRING DesktopName;
321 NTSTATUS Status;
322 HDESK Desktop;
323 CSRSS_API_REQUEST Request;
324 CSRSS_API_REPLY Reply;
325
326 Status = IntValidateWindowStationHandle(
327 hWindowStation,
328 KernelMode,
329 0,
330 &WinStaObject);
331
332 if (! NT_SUCCESS(Status))
333 {
334 DPRINT1("Failed validation of window station handle (0x%X)\n",
335 hWindowStation);
336 SetLastNtError(Status);
337 return NULL;
338 }
339
340 if (! IntGetFullWindowStationName(&DesktopName, &WinStaObject->Name,
341 lpszDesktopName))
342 {
343 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
344 ObDereferenceObject(WinStaObject);
345 return NULL;
346 }
347
348 ObDereferenceObject(WinStaObject);
349
350 /*
351 * Try to open already existing desktop
352 */
353
354 DPRINT("Trying to open desktop (%wZ)\n", &DesktopName);
355
356 /* Initialize ObjectAttributes for the desktop object */
357 InitializeObjectAttributes(
358 &ObjectAttributes,
359 &DesktopName,
360 0,
361 NULL,
362 NULL);
363
364 Status = ObOpenObjectByName(
365 &ObjectAttributes,
366 ExDesktopObjectType,
367 NULL,
368 UserMode,
369 dwDesiredAccess,
370 NULL,
371 (HANDLE*)&Desktop);
372
373 if (NT_SUCCESS(Status))
374 {
375 DPRINT("Successfully opened desktop (%wZ)\n", &DesktopName);
376 ExFreePool(DesktopName.Buffer);
377 return Desktop;
378 }
379
380 /*
381 * No existing desktop found, try to create new one
382 */
383
384 Status = ObCreateObject(
385 ExGetPreviousMode(),
386 ExDesktopObjectType,
387 &ObjectAttributes,
388 ExGetPreviousMode(),
389 NULL,
390 sizeof(DESKTOP_OBJECT),
391 0,
392 0,
393 (PVOID*)&DesktopObject);
394
395 if (! NT_SUCCESS(Status))
396 {
397 DPRINT1("Failed creating desktop (%wZ)\n", &DesktopName);
398 ExFreePool(DesktopName.Buffer);
399 SetLastNtError(STATUS_UNSUCCESSFUL);
400 return NULL;
401 }
402
403 // init desktop area
404 DesktopObject->WorkArea.left = 0;
405 DesktopObject->WorkArea.top = 0;
406 DesktopObject->WorkArea.right = -1;
407 DesktopObject->WorkArea.bottom = -1;
408 IntGetDesktopWorkArea(DesktopObject, NULL);
409
410 /* Initialize some local (to win32k) desktop state. */
411 DesktopObject->ActiveMessageQueue = NULL;
412
413 Status = ObInsertObject(
414 (PVOID)DesktopObject,
415 NULL,
416 STANDARD_RIGHTS_REQUIRED,
417 0,
418 NULL,
419 (HANDLE*)&Desktop);
420
421 ObDereferenceObject(DesktopObject);
422 ExFreePool(DesktopName.Buffer);
423
424 if (! NT_SUCCESS(Status))
425 {
426 DPRINT1("Failed to create desktop handle\n");
427 SetLastNtError(Status);
428 return NULL;
429 }
430
431 Request.Type = CSRSS_CREATE_DESKTOP;
432 memcpy(Request.Data.CreateDesktopRequest.DesktopName, lpszDesktopName->Buffer,
433 lpszDesktopName->Length);
434 Request.Data.CreateDesktopRequest.DesktopName[lpszDesktopName->Length / sizeof(WCHAR)] = L'\0';
435
436 Status = CsrNotify(&Request, &Reply);
437 if (! NT_SUCCESS(Status))
438 {
439 DPRINT1("Failed to notify CSRSS about new desktop\n");
440 ZwClose(Desktop);
441 SetLastNtError(Status);
442 return NULL;
443 }
444
445 return Desktop;
446 }
447
448 /*
449 * NtUserOpenDesktop
450 *
451 * Opens an existing desktop.
452 *
453 * Parameters
454 * lpszDesktopName
455 * Name of the existing desktop.
456 *
457 * dwFlags
458 * Interaction flags.
459 *
460 * dwDesiredAccess
461 * Requested type of access.
462 *
463 * Return Value
464 * Handle to the desktop or zero on failure.
465 *
466 * Status
467 * @implemented
468 */
469
470 HDESK STDCALL
471 NtUserOpenDesktop(
472 PUNICODE_STRING lpszDesktopName,
473 DWORD dwFlags,
474 ACCESS_MASK dwDesiredAccess)
475 {
476 OBJECT_ATTRIBUTES ObjectAttributes;
477 PWINSTATION_OBJECT WinStaObject;
478 UNICODE_STRING DesktopName;
479 NTSTATUS Status;
480 HDESK Desktop;
481
482 /*
483 * Validate the window station handle and compose the fully
484 * qualified desktop name
485 */
486
487 Status = IntValidateWindowStationHandle(
488 PROCESS_WINDOW_STATION(),
489 KernelMode,
490 0,
491 &WinStaObject);
492
493 if (!NT_SUCCESS(Status))
494 {
495 DPRINT("Failed validation of window station handle (0x%X)\n",
496 PROCESS_WINDOW_STATION());
497 SetLastNtError(Status);
498 return 0;
499 }
500
501 if (!IntGetFullWindowStationName(&DesktopName, &WinStaObject->Name,
502 lpszDesktopName))
503 {
504 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
505 ObDereferenceObject(WinStaObject);
506 return 0;
507 }
508
509 ObDereferenceObject(WinStaObject);
510
511 DPRINT("Trying to open desktop station (%wZ)\n", &DesktopName);
512
513 /* Initialize ObjectAttributes for the desktop object */
514 InitializeObjectAttributes(
515 &ObjectAttributes,
516 &DesktopName,
517 0,
518 NULL,
519 NULL);
520
521 Status = ObOpenObjectByName(
522 &ObjectAttributes,
523 ExDesktopObjectType,
524 NULL,
525 UserMode,
526 dwDesiredAccess,
527 NULL,
528 (HANDLE*)&Desktop);
529
530 if (!NT_SUCCESS(Status))
531 {
532 SetLastNtError(Status);
533 ExFreePool(DesktopName.Buffer);
534 return 0;
535 }
536
537 DPRINT("Successfully opened desktop (%wZ)\n", &DesktopName);
538 ExFreePool(DesktopName.Buffer);
539
540 return Desktop;
541 }
542
543 /*
544 * NtUserOpenInputDesktop
545 *
546 * Opens the input (interactive) desktop.
547 *
548 * Parameters
549 * dwFlags
550 * Interaction flags.
551 *
552 * fInherit
553 * Inheritance option.
554 *
555 * dwDesiredAccess
556 * Requested type of access.
557 *
558 * Return Value
559 * Handle to the input desktop or zero on failure.
560 *
561 * Status
562 * @implemented
563 */
564
565 HDESK STDCALL
566 NtUserOpenInputDesktop(
567 DWORD dwFlags,
568 BOOL fInherit,
569 ACCESS_MASK dwDesiredAccess)
570 {
571 PDESKTOP_OBJECT Object;
572 NTSTATUS Status;
573 HDESK Desktop;
574
575 DPRINT("About to open input desktop\n");
576
577 /* Get a pointer to the desktop object */
578
579 Status = IntValidateDesktopHandle(
580 InputDesktopHandle,
581 UserMode,
582 0,
583 &Object);
584
585 if (!NT_SUCCESS(Status))
586 {
587 DPRINT("Validation of input desktop handle (0x%X) failed\n", InputDesktop);
588 return (HDESK)0;
589 }
590
591 /* Create a new handle to the object */
592
593 Status = ObOpenObjectByPointer(
594 Object,
595 0,
596 NULL,
597 dwDesiredAccess,
598 ExDesktopObjectType,
599 UserMode,
600 (HANDLE*)&Desktop);
601
602 ObDereferenceObject(Object);
603
604 if (NT_SUCCESS(Status))
605 {
606 DPRINT("Successfully opened input desktop\n");
607 return (HDESK)Desktop;
608 }
609
610 SetLastNtError(Status);
611 return (HDESK)0;
612 }
613
614 /*
615 * NtUserCloseDesktop
616 *
617 * Closes a desktop handle.
618 *
619 * Parameters
620 * hDesktop
621 * Handle to the desktop.
622 *
623 * Return Value
624 * Status
625 *
626 * Remarks
627 * The desktop handle can be created with NtUserCreateDesktop or
628 * NtUserOpenDesktop. This function will fail if any thread in the calling
629 * process is using the specified desktop handle or if the handle refers
630 * to the initial desktop of the calling process.
631 *
632 * Status
633 * @implemented
634 */
635
636 BOOL STDCALL
637 NtUserCloseDesktop(HDESK hDesktop)
638 {
639 PDESKTOP_OBJECT Object;
640 NTSTATUS Status;
641
642 DPRINT("About to close desktop handle (0x%X)\n", hDesktop);
643
644 Status = IntValidateDesktopHandle(
645 hDesktop,
646 UserMode,
647 0,
648 &Object);
649
650 if (!NT_SUCCESS(Status))
651 {
652 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
653 return FALSE;
654 }
655
656 ObDereferenceObject(Object);
657
658 DPRINT("Closing desktop handle (0x%X)\n", hDesktop);
659
660 Status = ZwClose(hDesktop);
661 if (!NT_SUCCESS(Status))
662 {
663 SetLastNtError(Status);
664 return FALSE;
665 }
666
667 return TRUE;
668 }
669
670
671 static int GetSystemVersionString(LPWSTR buffer)
672 {
673 RTL_OSVERSIONINFOEXW versionInfo;
674 int len;
675
676 versionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
677
678 if (!NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW)&versionInfo)))
679 return 0;
680
681 if (versionInfo.dwMajorVersion <= 4)
682 len = swprintf(buffer,
683 L"ReactOS Version %d.%d %s Build %d",
684 versionInfo.dwMajorVersion, versionInfo.dwMinorVersion,
685 versionInfo.szCSDVersion, versionInfo.dwBuildNumber&0xFFFF);
686 else
687 len = swprintf(buffer,
688 L"ReactOS %s (Build %d)",
689 versionInfo.szCSDVersion, versionInfo.dwBuildNumber&0xFFFF);
690
691 return len;
692 }
693
694 static NTSTATUS STDCALL PaintDesktopVersionCallback(
695 IN PWSTR ValueName, IN ULONG ValueType,
696 IN PVOID ValueData, IN ULONG ValueLength,
697 IN PVOID Context, IN PVOID EntryContext
698 )
699 {
700 DPRINT("PaintDesktopVersionCallback ValueType=%d ValueLength=%d\n", ValueType, ValueLength);
701
702 if (ValueType==REG_DWORD && ValueLength==sizeof(DWORD))
703 *((DWORD*)EntryContext) = *(DWORD*)ValueData;
704
705 return STATUS_SUCCESS;
706 }
707
708 /*
709 * NtUserPaintDesktop
710 *
711 * The NtUserPaintDesktop function fills the clipping region in the
712 * specified device context with the desktop pattern or wallpaper. The
713 * function is provided primarily for shell desktops.
714 *
715 * Parameters
716 * hDC
717 * Handle to the device context.
718 *
719 * Status
720 * @implemented
721 */
722
723 BOOL STDCALL
724 NtUserPaintDesktop(HDC hDC)
725 {
726 RECT Rect;
727 HBRUSH DesktopBrush, PreviousBrush;
728 HWND hWndDesktop;
729 BOOL doPatBlt = TRUE;
730
731 RTL_QUERY_REGISTRY_TABLE queryTable[2];
732 DWORD displayVersion;
733 NTSTATUS status;
734 int len;
735
736 PWINSTATION_OBJECT WinSta = PsGetWin32Thread()->Desktop->WindowStation;
737
738 IntGdiGetClipBox(hDC, &Rect);
739
740 hWndDesktop = IntGetDesktopWindow();
741 DesktopBrush = (HBRUSH)NtUserGetClassLong(hWndDesktop, GCL_HBRBACKGROUND, FALSE);
742
743 /*
744 * Paint desktop background
745 */
746
747 if(WinSta->hbmWallpaper != NULL)
748 {
749 PWINDOW_OBJECT DeskWin;
750
751 if((DeskWin = IntGetWindowObject(hWndDesktop)))
752 {
753 SIZE sz;
754 int x, y;
755 HDC hWallpaperDC;
756
757 sz.cx = DeskWin->WindowRect.right - DeskWin->WindowRect.left;
758 sz.cy = DeskWin->WindowRect.bottom - DeskWin->WindowRect.top;
759 IntReleaseWindowObject(DeskWin);
760
761 x = (sz.cx / 2) - (WinSta->cxWallpaper / 2);
762 y = (sz.cy / 2) - (WinSta->cyWallpaper / 2);
763
764 hWallpaperDC = NtGdiCreateCompatableDC(hDC);
765 if(hWallpaperDC != NULL)
766 {
767 HBITMAP hOldBitmap;
768
769 if(x > 0 || y > 0)
770 {
771 /* FIXME - clip out the bitmap */
772 PreviousBrush = NtGdiSelectObject(hDC, DesktopBrush);
773 NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right, Rect.bottom, PATCOPY);
774 NtGdiSelectObject(hDC, PreviousBrush);
775 }
776 else
777 doPatBlt = FALSE;
778
779 hOldBitmap = NtGdiSelectObject(hWallpaperDC, WinSta->hbmWallpaper);
780 NtGdiBitBlt(hDC, x, y, WinSta->cxWallpaper, WinSta->cyWallpaper, hWallpaperDC, 0, 0, SRCCOPY);
781 NtGdiSelectObject(hWallpaperDC, hOldBitmap);
782
783 NtGdiDeleteDC(hWallpaperDC);
784 }
785 }
786 }
787
788 if (doPatBlt) {
789 PreviousBrush = NtGdiSelectObject(hDC, DesktopBrush);
790 NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right, Rect.bottom, PATCOPY);
791 NtGdiSelectObject(hDC, PreviousBrush);
792 }
793
794 /*
795 * Display system version on the desktop background
796 */
797
798 RtlZeroMemory(queryTable, sizeof(queryTable));
799
800 queryTable[0].QueryRoutine = PaintDesktopVersionCallback;
801 queryTable[0].Name = L"PaintDesktopVersion";
802 queryTable[0].EntryContext = &displayVersion;
803
804 /* query the "PaintDesktopVersion" flag in the "Control Panel\Desktop" key */
805 status = RtlQueryRegistryValues(RTL_REGISTRY_USER, L"Control Panel\\Desktop", queryTable, NULL, NULL);
806
807 if (!NT_SUCCESS(status)) {
808 DPRINT1("RtlQueryRegistryValues failed for PaintDesktopVersion: status=%x\n", status);
809 displayVersion = 0;
810 }
811 DPRINT("PaintDesktopVersion=%d\n", displayVersion);
812
813 if (displayVersion) {
814 static WCHAR s_wszVersion[256] = {0};
815 RECT rect;
816
817 if (*s_wszVersion)
818 len = wcslen(s_wszVersion);
819 else
820 len = GetSystemVersionString(s_wszVersion);
821
822 if (len) {
823 if (!NtUserSystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0)) {
824 rect.right = NtUserGetSystemMetrics(SM_CXSCREEN);
825 rect.bottom = NtUserGetSystemMetrics(SM_CYSCREEN);
826 }
827
828 COLORREF color_old = NtGdiSetTextColor(hDC, RGB(255,255,255));
829 UINT align_old = NtGdiSetTextAlign(hDC, TA_RIGHT);
830 int mode_old = NtGdiSetBkMode(hDC, TRANSPARENT);
831
832 NtGdiTextOut(hDC, rect.right-16, rect.bottom-48, s_wszVersion, len);
833
834 NtGdiSetBkMode(hDC, mode_old);
835 NtGdiSetTextAlign(hDC, align_old);
836 NtGdiSetTextColor(hDC, color_old);
837 }
838 }
839
840 return TRUE;
841 }
842
843
844 /*
845 * NtUserSwitchDesktop
846 *
847 * Sets the current input (interactive) desktop.
848 *
849 * Parameters
850 * hDesktop
851 * Handle to desktop.
852 *
853 * Return Value
854 * Status
855 *
856 * Status
857 * @unimplemented
858 */
859
860 BOOL STDCALL
861 NtUserSwitchDesktop(HDESK hDesktop)
862 {
863 PDESKTOP_OBJECT DesktopObject;
864 NTSTATUS Status;
865
866 DPRINT("About to switch desktop (0x%X)\n", hDesktop);
867
868 Status = IntValidateDesktopHandle(
869 hDesktop,
870 UserMode,
871 0,
872 &DesktopObject);
873
874 if (!NT_SUCCESS(Status))
875 {
876 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
877 return FALSE;
878 }
879
880 /*
881 * Don't allow applications switch the desktop if it's locked, unless the caller
882 * is the logon application itself
883 */
884 if((DesktopObject->WindowStation->Flags & WSS_LOCKED) &&
885 LogonProcess != NULL && LogonProcess != PsGetWin32Process())
886 {
887 ObDereferenceObject(DesktopObject);
888 DPRINT1("Switching desktop 0x%x denied because the work station is locked!\n", hDesktop);
889 return FALSE;
890 }
891
892 /* FIXME: Fail if the desktop belong to an invisible window station */
893 /* FIXME: Fail if the process is associated with a secured
894 desktop such as Winlogon or Screen-Saver */
895 /* FIXME: Connect to input device */
896
897 /* Set the active desktop in the desktop's window station. */
898 DesktopObject->WindowStation->ActiveDesktop = DesktopObject;
899
900 /* Set the global state. */
901 InputDesktop = DesktopObject;
902 InputDesktopHandle = hDesktop;
903 InputWindowStation = DesktopObject->WindowStation;
904
905 ObDereferenceObject(DesktopObject);
906
907 return TRUE;
908 }
909
910 /*
911 * NtUserResolveDesktopForWOW
912 *
913 * Status
914 * @unimplemented
915 */
916
917 DWORD STDCALL
918 NtUserResolveDesktopForWOW(DWORD Unknown0)
919 {
920 UNIMPLEMENTED
921 return 0;
922 }
923
924 /*
925 * NtUserGetThreadDesktop
926 *
927 * Status
928 * @implemented
929 */
930
931 HDESK STDCALL
932 NtUserGetThreadDesktop(DWORD dwThreadId, DWORD Unknown1)
933 {
934 NTSTATUS Status;
935 PETHREAD Thread;
936 PDESKTOP_OBJECT DesktopObject;
937 HDESK Ret, hThreadDesktop;
938 OBJECT_HANDLE_INFORMATION HandleInformation;
939
940 if(!dwThreadId)
941 {
942 SetLastWin32Error(ERROR_INVALID_PARAMETER);
943 return 0;
944 }
945
946 Status = PsLookupThreadByThreadId((PVOID)dwThreadId, &Thread);
947 if(!NT_SUCCESS(Status))
948 {
949 SetLastWin32Error(ERROR_INVALID_PARAMETER);
950 return 0;
951 }
952
953 if(Thread->ThreadsProcess == PsGetCurrentProcess())
954 {
955 /* just return the handle, we queried the desktop handle of a thread running
956 in the same context */
957 Ret = Thread->Tcb.Win32Thread->hDesktop;
958 ObDereferenceObject(Thread);
959 return Ret;
960 }
961
962 /* get the desktop handle and the desktop of the thread */
963 if(!(hThreadDesktop = Thread->Tcb.Win32Thread->hDesktop) ||
964 !(DesktopObject = Thread->Tcb.Win32Thread->Desktop))
965 {
966 ObDereferenceObject(Thread);
967 DPRINT1("Desktop information of thread 0x%x broken!?\n", dwThreadId);
968 return NULL;
969 }
970
971 /* we could just use DesktopObject instead of looking up the handle, but latter
972 may be a bit safer (e.g. when the desktop is being destroyed */
973 /* switch into the context of the thread we're trying to get the desktop from,
974 so we can use the handle */
975 KeAttachProcess(Thread->ThreadsProcess);
976 Status = ObReferenceObjectByHandle(hThreadDesktop,
977 GENERIC_ALL,
978 ExDesktopObjectType,
979 UserMode,
980 (PVOID*)&DesktopObject,
981 &HandleInformation);
982 KeDetachProcess();
983
984 /* the handle couldn't be found, there's nothing to get... */
985 if(!NT_SUCCESS(Status))
986 {
987 ObDereferenceObject(Thread);
988 return NULL;
989 }
990
991 /* lookup our handle table if we can find a handle to the desktop object,
992 if not, create one */
993 Ret = IntGetDesktopObjectHandle(DesktopObject);
994
995 /* all done, we got a valid handle to the desktop */
996 ObDereferenceObject(DesktopObject);
997 ObDereferenceObject(Thread);
998 return Ret;
999 }
1000
1001 /*
1002 * NtUserSetThreadDesktop
1003 *
1004 * Status
1005 * @implemented
1006 */
1007
1008 BOOL STDCALL
1009 NtUserSetThreadDesktop(HDESK hDesktop)
1010 {
1011 PW32THREAD W32Thread;
1012 PDESKTOP_OBJECT DesktopObject;
1013 NTSTATUS Status;
1014
1015 /* Validate the new desktop. */
1016 Status = IntValidateDesktopHandle(
1017 hDesktop,
1018 UserMode,
1019 0,
1020 &DesktopObject);
1021
1022 if (!NT_SUCCESS(Status))
1023 {
1024 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
1025 return FALSE;
1026 }
1027
1028 W32Thread = PsGetWin32Thread();
1029 /* Check for setting the same desktop as before. */
1030 if (DesktopObject == W32Thread->Desktop)
1031 {
1032 W32Thread->hDesktop = hDesktop;
1033 ObDereferenceObject(DesktopObject);
1034 return TRUE;
1035 }
1036
1037 /* FIXME: Should check here to see if the thread has any windows. */
1038
1039 if (W32Thread->Desktop != NULL)
1040 {
1041 ObDereferenceObject(W32Thread->Desktop);
1042 }
1043
1044 W32Thread->Desktop = DesktopObject;
1045 W32Thread->hDesktop = hDesktop;
1046
1047 return TRUE;
1048 }
1049
1050 /* EOF */