build win32k with NDK, finally\!
[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$
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 /* GLOBALS *******************************************************************/
34
35 /* Currently active desktop */
36 PDESKTOP_OBJECT InputDesktop = NULL;
37 HDESK InputDesktopHandle = NULL;
38 HDC ScreenDeviceContext = NULL;
39
40 BOOL g_PaintDesktopVersion = FALSE;
41
42 /* INITALIZATION FUNCTIONS ****************************************************/
43
44 NTSTATUS FASTCALL
45 InitDesktopImpl(VOID)
46 {
47 return STATUS_SUCCESS;
48 }
49
50 NTSTATUS FASTCALL
51 CleanupDesktopImpl(VOID)
52 {
53 return STATUS_SUCCESS;
54 }
55
56 /* OBJECT CALLBACKS **********************************************************/
57
58 NTSTATUS STDCALL
59 IntDesktopObjectCreate(PVOID ObjectBody,
60 PVOID Parent,
61 PWSTR RemainingPath,
62 struct _OBJECT_ATTRIBUTES* ObjectAttributes)
63 {
64 PDESKTOP_OBJECT Desktop = (PDESKTOP_OBJECT)ObjectBody;
65 UNICODE_STRING UnicodeString;
66
67 DPRINT("Creating desktop (0x%X) Name (%S)\n", Desktop, RemainingPath);
68 if (RemainingPath == NULL)
69 {
70 return STATUS_SUCCESS;
71 }
72
73 if (wcschr((RemainingPath + 1), '\\') != NULL)
74 {
75 return STATUS_UNSUCCESSFUL;
76 }
77
78 RtlInitUnicodeString(&UnicodeString, (RemainingPath + 1));
79
80
81
82 KeInitializeSpinLock(&Desktop->Lock);
83 InitializeListHead(&Desktop->ShellHookWindows);
84
85 Desktop->WindowStation = (PWINSTATION_OBJECT)Parent;
86
87 /* Put the desktop on the window station's list of associcated desktops */
88 ExInterlockedInsertTailList(
89 &Desktop->WindowStation->DesktopListHead,
90 &Desktop->ListEntry,
91 &Desktop->WindowStation->Lock);
92
93 return RtlCreateUnicodeString(&Desktop->Name, UnicodeString.Buffer);
94 }
95
96 VOID STDCALL
97 IntDesktopObjectDelete(PVOID DeletedObject)
98 {
99 PDESKTOP_OBJECT Desktop = (PDESKTOP_OBJECT)DeletedObject;
100 KIRQL OldIrql;
101
102 DPRINT("Deleting desktop (0x%X)\n", Desktop);
103
104 /* Remove the desktop from the window station's list of associcated desktops */
105 KeAcquireSpinLock(&Desktop->WindowStation->Lock, &OldIrql);
106 RemoveEntryList(&Desktop->ListEntry);
107 KeReleaseSpinLock(&Desktop->WindowStation->Lock, OldIrql);
108
109 RtlFreeUnicodeString(&Desktop->Name);
110 }
111
112 /* PRIVATE FUNCTIONS **********************************************************/
113
114 NTSTATUS FASTCALL
115 IntParseDesktopPath(PEPROCESS Process,
116 PUNICODE_STRING DesktopPath,
117 HWINSTA *hWinSta,
118 HDESK *hDesktop)
119 {
120 OBJECT_ATTRIBUTES ObjectAttributes;
121 UNICODE_STRING WinSta, Desktop, FullName;
122 BOOL DesktopPresent = FALSE;
123 BOOL WinStaPresent = FALSE;
124 NTSTATUS Status;
125
126 ASSERT(hWinSta);
127
128 *hWinSta = NULL;
129
130 if(hDesktop != NULL)
131 {
132 *hDesktop = NULL;
133 }
134
135 RtlInitUnicodeString(&WinSta, NULL);
136 RtlInitUnicodeString(&Desktop, NULL);
137
138 if(DesktopPath != NULL && DesktopPath->Buffer != NULL && DesktopPath->Length > sizeof(WCHAR))
139 {
140 PWCHAR c = DesktopPath->Buffer;
141 USHORT wl = 0;
142 USHORT l = DesktopPath->Length;
143
144 /*
145 * Parse the desktop path string which can be in the form "WinSta\Desktop"
146 * or just "Desktop". In latter case WinSta0 will be used.
147 */
148
149 while(l > 0)
150 {
151 if(*c == L'\\')
152 {
153 wl = (ULONG_PTR)c - (ULONG_PTR)DesktopPath->Buffer;
154 break;
155 }
156 l -= sizeof(WCHAR);
157 c++;
158 }
159
160 if(wl > 0)
161 {
162 WinSta.Length = wl;
163 WinSta.MaximumLength = wl + sizeof(WCHAR);
164 WinSta.Buffer = DesktopPath->Buffer;
165
166 WinStaPresent = TRUE;
167 c++;
168 }
169
170 Desktop.Length = DesktopPath->Length - wl;
171 if(wl > 0)
172 {
173 Desktop.Length -= sizeof(WCHAR);
174 }
175 if(Desktop.Length > 0)
176 {
177 Desktop.MaximumLength = Desktop.Length + sizeof(WCHAR);
178 Desktop.Buffer = ((wl > 0) ? c : DesktopPath->Buffer);
179 DesktopPresent = TRUE;
180 }
181 }
182
183 if(!WinStaPresent)
184 {
185 /* search the process handle table for (inherited) window station
186 handles, use a more appropriate one than WinSta0 if possible. */
187 Status = ObFindHandleForObject(Process,
188 NULL,
189 ExWindowStationObjectType,
190 NULL,
191 (PHANDLE)hWinSta);
192 if(!NT_SUCCESS(Status))
193 {
194 /* we had no luck searching for opened handles, use WinSta0 now */
195 RtlInitUnicodeString(&WinSta, L"WinSta0");
196 }
197 }
198
199 if(!DesktopPresent && hDesktop != NULL)
200 {
201 /* search the process handle table for (inherited) desktop
202 handles, use a more appropriate one than Default if possible. */
203 Status = ObFindHandleForObject(Process,
204 NULL,
205 ExDesktopObjectType,
206 NULL,
207 (PHANDLE)hDesktop);
208 if(!NT_SUCCESS(Status))
209 {
210 /* we had no luck searching for opened handles, use Desktop now */
211 RtlInitUnicodeString(&Desktop, L"Default");
212 }
213 }
214
215 if(*hWinSta == NULL)
216 {
217 if(!IntGetFullWindowStationName(&FullName, &WinSta, NULL))
218 {
219 return STATUS_INSUFFICIENT_RESOURCES;
220 }
221
222 /* open the window station */
223 InitializeObjectAttributes(&ObjectAttributes,
224 &FullName,
225 OBJ_CASE_INSENSITIVE,
226 NULL,
227 NULL);
228
229 Status = ObOpenObjectByName(&ObjectAttributes,
230 ExWindowStationObjectType,
231 NULL,
232 UserMode,
233 0,
234 NULL,
235 (HANDLE*)hWinSta);
236
237 RtlFreeUnicodeString(&FullName);
238
239 if(!NT_SUCCESS(Status))
240 {
241 SetLastNtError(Status);
242 DPRINT("Failed to reference window station %wZ PID: %d!\n", &WinSta, PsGetCurrentProcessId());
243 return Status;
244 }
245 }
246
247 if(hDesktop != NULL && *hDesktop == NULL)
248 {
249 if(!IntGetFullWindowStationName(&FullName, &WinSta, &Desktop))
250 {
251 NtClose(*hWinSta);
252 *hWinSta = NULL;
253 return STATUS_INSUFFICIENT_RESOURCES;
254 }
255
256 /* open the desktop object */
257 InitializeObjectAttributes(&ObjectAttributes,
258 &FullName,
259 OBJ_CASE_INSENSITIVE,
260 NULL,
261 NULL);
262
263 Status = ObOpenObjectByName(&ObjectAttributes,
264 ExDesktopObjectType,
265 NULL,
266 UserMode,
267 0,
268 NULL,
269 (HANDLE*)hDesktop);
270
271 RtlFreeUnicodeString(&FullName);
272
273 if(!NT_SUCCESS(Status))
274 {
275 *hDesktop = NULL;
276 NtClose(*hWinSta);
277 *hWinSta = NULL;
278 SetLastNtError(Status);
279 DPRINT("Failed to reference desktop %wZ PID: %d!\n", &Desktop, PsGetCurrentProcessId());
280 return Status;
281 }
282 }
283
284 return STATUS_SUCCESS;
285 }
286
287 /*
288 * IntValidateDesktopHandle
289 *
290 * Validates the desktop handle.
291 *
292 * Remarks
293 * If the function succeeds, the handle remains referenced. If the
294 * fucntion fails, last error is set.
295 */
296
297 NTSTATUS FASTCALL
298 IntValidateDesktopHandle(
299 HDESK Desktop,
300 KPROCESSOR_MODE AccessMode,
301 ACCESS_MASK DesiredAccess,
302 PDESKTOP_OBJECT *Object)
303 {
304 NTSTATUS Status;
305
306 Status = ObReferenceObjectByHandle(
307 Desktop,
308 DesiredAccess,
309 ExDesktopObjectType,
310 AccessMode,
311 (PVOID*)Object,
312 NULL);
313
314 if (!NT_SUCCESS(Status))
315 SetLastNtError(Status);
316
317 return Status;
318 }
319
320 VOID FASTCALL
321 IntGetDesktopWorkArea(PDESKTOP_OBJECT Desktop, PRECT Rect)
322 {
323 PRECT Ret;
324
325 ASSERT(Desktop);
326
327 Ret = &Desktop->WorkArea;
328 if((Ret->right == -1) && ScreenDeviceContext)
329 {
330 PDC dc;
331 BITMAPOBJ *BitmapObj;
332 dc = DC_LockDc(ScreenDeviceContext);
333 /* FIXME - Handle dc == NULL!!!! */
334 BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
335 if(BitmapObj)
336 {
337 Ret->right = BitmapObj->SurfObj.sizlBitmap.cx;
338 Ret->bottom = BitmapObj->SurfObj.sizlBitmap.cy;
339 BITMAPOBJ_UnlockBitmap(BitmapObj);
340 }
341 DC_UnlockDc(dc);
342 }
343
344 if(Rect)
345 {
346 *Rect = *Ret;
347 }
348 }
349
350 PDESKTOP_OBJECT FASTCALL
351 IntGetActiveDesktop(VOID)
352 {
353 return InputDesktop;
354 }
355
356 /*
357 * returns or creates a handle to the desktop object
358 */
359 HDESK FASTCALL
360 IntGetDesktopObjectHandle(PDESKTOP_OBJECT DesktopObject)
361 {
362 NTSTATUS Status;
363 HDESK Ret;
364
365 ASSERT(DesktopObject);
366
367 Status = ObFindHandleForObject(PsGetCurrentProcess(),
368 DesktopObject,
369 ExDesktopObjectType,
370 NULL,
371 (PHANDLE)&Ret);
372
373 if(!NT_SUCCESS(Status))
374 {
375 Status = ObOpenObjectByPointer(DesktopObject,
376 0,
377 NULL,
378 0,
379 ExDesktopObjectType,
380 UserMode,
381 (PHANDLE)&Ret);
382 if(!NT_SUCCESS(Status))
383 {
384 /* unable to create a handle */
385 DPRINT1("Unable to create a desktop handle\n");
386 return NULL;
387 }
388 }
389
390 return Ret;
391 }
392
393 PUSER_MESSAGE_QUEUE FASTCALL
394 IntGetFocusMessageQueue(VOID)
395 {
396 PDESKTOP_OBJECT pdo = IntGetActiveDesktop();
397 if (!pdo)
398 {
399 DPRINT("No active desktop\n");
400 return(NULL);
401 }
402 return (PUSER_MESSAGE_QUEUE)pdo->ActiveMessageQueue;
403 }
404
405 VOID FASTCALL
406 IntSetFocusMessageQueue(PUSER_MESSAGE_QUEUE NewQueue)
407 {
408 PUSER_MESSAGE_QUEUE Old;
409 PDESKTOP_OBJECT pdo = IntGetActiveDesktop();
410 if (!pdo)
411 {
412 DPRINT("No active desktop\n");
413 return;
414 }
415 if(NewQueue != NULL)
416 {
417 if(NewQueue->Desktop != NULL)
418 {
419 DPRINT("Message Queue already attached to another desktop!\n");
420 return;
421 }
422 IntReferenceMessageQueue(NewQueue);
423 InterlockedExchange((LONG*)&NewQueue->Desktop, (LONG)pdo);
424 }
425 Old = (PUSER_MESSAGE_QUEUE)InterlockedExchange((LONG*)&pdo->ActiveMessageQueue, (LONG)NewQueue);
426 if(Old != NULL)
427 {
428 InterlockedExchange((LONG*)&Old->Desktop, 0);
429 IntDereferenceMessageQueue(Old);
430 }
431 }
432
433 HWND FASTCALL IntGetDesktopWindow(VOID)
434 {
435 PDESKTOP_OBJECT pdo = IntGetActiveDesktop();
436 if (!pdo)
437 {
438 DPRINT("No active desktop\n");
439 return NULL;
440 }
441 return pdo->DesktopWindow;
442 }
443
444 HWND FASTCALL IntGetCurrentThreadDesktopWindow(VOID)
445 {
446 PDESKTOP_OBJECT pdo = PsGetWin32Thread()->Desktop;
447 if (NULL == pdo)
448 {
449 DPRINT1("Thread doesn't have a desktop\n");
450 return NULL;
451 }
452 return pdo->DesktopWindow;
453 }
454
455 BOOL FASTCALL IntDesktopUpdatePerUserSettings(BOOL bEnable)
456 {
457 if (bEnable)
458 {
459 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
460 NTSTATUS Status;
461
462 RtlZeroMemory(QueryTable, sizeof(QueryTable));
463
464 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
465 QueryTable[0].Name = L"PaintDesktopVersion";
466 QueryTable[0].EntryContext = &g_PaintDesktopVersion;
467
468 /* Query the "PaintDesktopVersion" flag in the "Control Panel\Desktop" key */
469 Status = RtlQueryRegistryValues(RTL_REGISTRY_USER,
470 L"Control Panel\\Desktop",
471 QueryTable, NULL, NULL);
472 if (!NT_SUCCESS(Status))
473 {
474 DPRINT1("RtlQueryRegistryValues failed for PaintDesktopVersion (%x)\n",
475 Status);
476 g_PaintDesktopVersion = FALSE;
477 return FALSE;
478 }
479
480 DPRINT("PaintDesktopVersion = %d\n", g_PaintDesktopVersion);
481
482 return TRUE;
483 }
484 else
485 {
486 g_PaintDesktopVersion = FALSE;
487 return TRUE;
488 }
489 }
490
491 /* PUBLIC FUNCTIONS ***********************************************************/
492
493 NTSTATUS FASTCALL
494 IntShowDesktop(PDESKTOP_OBJECT Desktop, ULONG Width, ULONG Height)
495 {
496 CSR_API_MESSAGE Request;
497
498 Request.Type = MAKE_CSR_API(SHOW_DESKTOP, CSR_GUI);
499 Request.Data.ShowDesktopRequest.DesktopWindow = Desktop->DesktopWindow;
500 Request.Data.ShowDesktopRequest.Width = Width;
501 Request.Data.ShowDesktopRequest.Height = Height;
502
503 return CsrNotify(&Request);
504 }
505
506 NTSTATUS FASTCALL
507 IntHideDesktop(PDESKTOP_OBJECT Desktop)
508 {
509 #if 0
510 CSRSS_API_REQUEST Request;
511 CSRSS_API_REPLY Reply;
512
513 Request.Type = CSRSS_HIDE_DESKTOP;
514 Request.Data.HideDesktopRequest.DesktopWindow = Desktop->DesktopWindow;
515
516 return NotifyCsrss(&Request, &Reply);
517 #else
518 PWINDOW_OBJECT DesktopWindow;
519
520 DesktopWindow = IntGetWindowObject(Desktop->DesktopWindow);
521 if (! DesktopWindow)
522 {
523 return ERROR_INVALID_WINDOW_HANDLE;
524 }
525 DesktopWindow->Style &= ~WS_VISIBLE;
526
527 return STATUS_SUCCESS;
528 #endif
529 }
530
531 /*
532 * Send the Message to the windows registered for ShellHook
533 * notifications. The lParam contents depend on the Message. See
534 * MSDN for more details (RegisterShellHookWindow)
535 */
536 VOID IntShellHookNotify(WPARAM Message, LPARAM lParam)
537 {
538 PDESKTOP_OBJECT Desktop = IntGetActiveDesktop();
539 PLIST_ENTRY Entry, Entry2;
540 PSHELL_HOOK_WINDOW Current;
541 KIRQL OldLevel;
542
543 static UINT MsgType = 0;
544
545 if (!MsgType) {
546
547 /* Too bad, this doesn't work.*/
548 #if 0
549 UNICODE_STRING Str;
550 RtlInitUnicodeString(&Str, L"SHELLHOOK");
551 MsgType = NtUserRegisterWindowMessage(&Str);
552 #endif
553 MsgType = IntAddAtom(L"SHELLHOOK");
554
555 DPRINT("MsgType = %x\n", MsgType);
556 if (!MsgType)
557 DPRINT1("LastError: %x\n", GetLastNtError());
558 }
559
560 if (!Desktop) {
561 DPRINT1("IntShellHookNotify: No desktop!\n");
562 return;
563 }
564
565 /* We have to do some tricks because the list could change
566 * between calls, and we can't keep the lock during the call
567 */
568
569 KeAcquireSpinLock(&Desktop->Lock, &OldLevel);
570 Entry = Desktop->ShellHookWindows.Flink;
571 while (Entry != &Desktop->ShellHookWindows) {
572 Current = CONTAINING_RECORD(Entry, SHELL_HOOK_WINDOW, ListEntry);
573 KeReleaseSpinLock(&Desktop->Lock, OldLevel);
574
575 DPRINT("Sending notify\n");
576 IntPostOrSendMessage(Current->hWnd,
577 MsgType,
578 Message,
579 lParam);
580
581 /* Loop again to find the window we were sending to. If it doesn't
582 * exist anymore, we just stop. This could leave an infinite loop
583 * if a window is removed and readded to the list. That's quite
584 * unlikely though.
585 */
586
587 KeAcquireSpinLock(&Desktop->Lock, &OldLevel);
588 Entry2 = Desktop->ShellHookWindows.Flink;
589 while (Entry2 != Entry &&
590 Entry2 != &Desktop->ShellHookWindows) {
591 Entry2 = Entry2->Flink;
592 }
593
594 if (Entry2 == Entry)
595 Entry = Entry->Flink;
596 else
597 break;
598 }
599 KeReleaseSpinLock(&Desktop->Lock, OldLevel);
600 }
601
602 /*
603 * Add the window to the ShellHookWindows list. The windows
604 * on that list get notifications that are important to shell
605 * type applications.
606 *
607 * TODO: Validate the window? I'm not sure if sending these messages to
608 * an unsuspecting application that is not your own is a nice thing to do.
609 */
610 BOOL IntRegisterShellHookWindow(HWND hWnd)
611 {
612 PDESKTOP_OBJECT Desktop = PsGetWin32Thread()->Desktop;
613 PSHELL_HOOK_WINDOW Entry;
614 KIRQL OldLevel;
615
616 DPRINT("IntRegisterShellHookWindow\n");
617
618 /* First deregister the window, so we can be sure it's never twice in the
619 * list.
620 */
621 IntDeRegisterShellHookWindow(hWnd);
622
623 Entry = ExAllocatePoolWithTag(NonPagedPool,
624 sizeof(SHELL_HOOK_WINDOW),
625 TAG_WINSTA);
626 /* We have to walk this structure with while holding a spinlock, so we
627 * need NonPagedPool */
628
629 if (!Entry)
630 return FALSE;
631
632 Entry->hWnd = hWnd;
633
634 KeAcquireSpinLock(&Desktop->Lock, &OldLevel);
635 InsertTailList(&Desktop->ShellHookWindows, &Entry->ListEntry);
636 KeReleaseSpinLock(&Desktop->Lock, OldLevel);
637
638 return TRUE;
639 }
640
641 /*
642 * Remove the window from the ShellHookWindows list. The windows
643 * on that list get notifications that are important to shell
644 * type applications.
645 */
646 BOOL IntDeRegisterShellHookWindow(HWND hWnd)
647 {
648 PDESKTOP_OBJECT Desktop = PsGetWin32Thread()->Desktop;
649 PLIST_ENTRY Entry;
650 PSHELL_HOOK_WINDOW Current;
651 KIRQL OldLevel;
652
653 KeAcquireSpinLock(&Desktop->Lock, &OldLevel);
654
655 Entry = Desktop->ShellHookWindows.Flink;
656 while (Entry != &Desktop->ShellHookWindows) {
657 Current = CONTAINING_RECORD(Entry, SHELL_HOOK_WINDOW, ListEntry);
658 if (Current->hWnd == hWnd) {
659 RemoveEntryList(Entry);
660 KeReleaseSpinLock(&Desktop->Lock, OldLevel);
661 ExFreePool(Entry);
662 return TRUE;
663 }
664 Entry = Entry->Flink;
665 }
666
667 KeReleaseSpinLock(&Desktop->Lock, OldLevel);
668
669 return FALSE;
670 }
671
672 /*
673 * NtUserCreateDesktop
674 *
675 * Creates a new desktop.
676 *
677 * Parameters
678 * lpszDesktopName
679 * Name of the new desktop.
680 *
681 * dwFlags
682 * Interaction flags.
683 *
684 * dwDesiredAccess
685 * Requested type of access.
686 *
687 * lpSecurity
688 * Security descriptor.
689 *
690 * hWindowStation
691 * Handle to window station on which to create the desktop.
692 *
693 * Return Value
694 * If the function succeeds, the return value is a handle to the newly
695 * created desktop. If the specified desktop already exists, the function
696 * succeeds and returns a handle to the existing desktop. When you are
697 * finished using the handle, call the CloseDesktop function to close it.
698 * If the function fails, the return value is NULL.
699 *
700 * Status
701 * @implemented
702 */
703
704 HDESK STDCALL
705 NtUserCreateDesktop(
706 PUNICODE_STRING lpszDesktopName,
707 DWORD dwFlags,
708 ACCESS_MASK dwDesiredAccess,
709 LPSECURITY_ATTRIBUTES lpSecurity,
710 HWINSTA hWindowStation)
711 {
712 OBJECT_ATTRIBUTES ObjectAttributes;
713 PWINSTATION_OBJECT WinStaObject;
714 PDESKTOP_OBJECT DesktopObject;
715 UNICODE_STRING DesktopName;
716 NTSTATUS Status;
717 HDESK Desktop;
718 CSR_API_MESSAGE Request;
719
720 DPRINT("CreateDesktop: %wZ\n", lpszDesktopName);
721
722 Status = IntValidateWindowStationHandle(
723 hWindowStation,
724 KernelMode,
725 0, /* FIXME - WINSTA_CREATEDESKTOP */
726 &WinStaObject);
727
728 if (! NT_SUCCESS(Status))
729 {
730 DPRINT1("Failed validation of window station handle (0x%X), cannot create desktop %wZ\n",
731 hWindowStation, lpszDesktopName);
732 SetLastNtError(Status);
733 return NULL;
734 }
735
736 if (! IntGetFullWindowStationName(&DesktopName, &WinStaObject->Name,
737 lpszDesktopName))
738 {
739 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
740 ObDereferenceObject(WinStaObject);
741 return NULL;
742 }
743
744 ObDereferenceObject(WinStaObject);
745
746 /*
747 * Try to open already existing desktop
748 */
749
750 DPRINT("Trying to open desktop (%wZ)\n", &DesktopName);
751
752 /* Initialize ObjectAttributes for the desktop object */
753 InitializeObjectAttributes(
754 &ObjectAttributes,
755 &DesktopName,
756 0,
757 NULL,
758 NULL);
759
760 Status = ObOpenObjectByName(
761 &ObjectAttributes,
762 ExDesktopObjectType,
763 NULL,
764 UserMode,
765 dwDesiredAccess,
766 NULL,
767 (HANDLE*)&Desktop);
768
769 if (NT_SUCCESS(Status))
770 {
771 DPRINT("Successfully opened desktop (%wZ)\n", &DesktopName);
772 ExFreePool(DesktopName.Buffer);
773 return Desktop;
774 }
775
776 /*
777 * No existing desktop found, try to create new one
778 */
779
780 Status = ObCreateObject(
781 KernelMode,
782 ExDesktopObjectType,
783 &ObjectAttributes,
784 ExGetPreviousMode(),
785 NULL,
786 sizeof(DESKTOP_OBJECT),
787 0,
788 0,
789 (PVOID*)&DesktopObject);
790
791 if (! NT_SUCCESS(Status))
792 {
793 DPRINT1("Failed creating desktop (%wZ)\n", &DesktopName);
794 ExFreePool(DesktopName.Buffer);
795 SetLastNtError(STATUS_UNSUCCESSFUL);
796 return NULL;
797 }
798
799 // init desktop area
800 DesktopObject->WorkArea.left = 0;
801 DesktopObject->WorkArea.top = 0;
802 DesktopObject->WorkArea.right = -1;
803 DesktopObject->WorkArea.bottom = -1;
804 IntGetDesktopWorkArea(DesktopObject, NULL);
805
806 /* Initialize some local (to win32k) desktop state. */
807 DesktopObject->ActiveMessageQueue = NULL;
808
809 Status = ObInsertObject(
810 (PVOID)DesktopObject,
811 NULL,
812 STANDARD_RIGHTS_REQUIRED,
813 0,
814 NULL,
815 (HANDLE*)&Desktop);
816
817 ObDereferenceObject(DesktopObject);
818 ExFreePool(DesktopName.Buffer);
819
820 if (! NT_SUCCESS(Status))
821 {
822 DPRINT1("Failed to create desktop handle\n");
823 SetLastNtError(Status);
824 return NULL;
825 }
826
827 /*
828 * Create a handle for CSRSS and notify CSRSS
829 */
830 Request.Type = MAKE_CSR_API(CREATE_DESKTOP, CSR_GUI);
831 Status = CsrInsertObject(Desktop,
832 GENERIC_ALL,
833 (HANDLE*)&Request.Data.CreateDesktopRequest.DesktopHandle);
834 if (! NT_SUCCESS(Status))
835 {
836 DPRINT1("Failed to create desktop handle for CSRSS\n");
837 ZwClose(Desktop);
838 SetLastNtError(Status);
839 return NULL;
840 }
841
842 Status = CsrNotify(&Request);
843 if (! NT_SUCCESS(Status))
844 {
845 CsrCloseHandle(Request.Data.CreateDesktopRequest.DesktopHandle);
846 DPRINT1("Failed to notify CSRSS about new desktop\n");
847 ZwClose(Desktop);
848 SetLastNtError(Status);
849 return NULL;
850 }
851
852 return Desktop;
853 }
854
855 /*
856 * NtUserOpenDesktop
857 *
858 * Opens an existing desktop.
859 *
860 * Parameters
861 * lpszDesktopName
862 * Name of the existing desktop.
863 *
864 * dwFlags
865 * Interaction flags.
866 *
867 * dwDesiredAccess
868 * Requested type of access.
869 *
870 * Return Value
871 * Handle to the desktop or zero on failure.
872 *
873 * Status
874 * @implemented
875 */
876
877 HDESK STDCALL
878 NtUserOpenDesktop(
879 PUNICODE_STRING lpszDesktopName,
880 DWORD dwFlags,
881 ACCESS_MASK dwDesiredAccess)
882 {
883 OBJECT_ATTRIBUTES ObjectAttributes;
884 PWINSTATION_OBJECT WinStaObject;
885 UNICODE_STRING DesktopName;
886 NTSTATUS Status;
887 HDESK Desktop;
888
889 /*
890 * Validate the window station handle and compose the fully
891 * qualified desktop name
892 */
893
894 Status = IntValidateWindowStationHandle(
895 PsGetCurrentProcess()->Win32WindowStation,
896 KernelMode,
897 0,
898 &WinStaObject);
899
900 if (!NT_SUCCESS(Status))
901 {
902 DPRINT1("Failed validation of window station handle (0x%X)\n",
903 PsGetCurrentProcess()->Win32WindowStation);
904 SetLastNtError(Status);
905 return 0;
906 }
907
908 if (!IntGetFullWindowStationName(&DesktopName, &WinStaObject->Name,
909 lpszDesktopName))
910 {
911 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
912 ObDereferenceObject(WinStaObject);
913 return 0;
914 }
915
916 ObDereferenceObject(WinStaObject);
917
918 DPRINT1("Trying to open desktop (%wZ)\n", &DesktopName);
919
920 /* Initialize ObjectAttributes for the desktop object */
921 InitializeObjectAttributes(
922 &ObjectAttributes,
923 &DesktopName,
924 0,
925 NULL,
926 NULL);
927
928 Status = ObOpenObjectByName(
929 &ObjectAttributes,
930 ExDesktopObjectType,
931 NULL,
932 UserMode,
933 dwDesiredAccess,
934 NULL,
935 (HANDLE*)&Desktop);
936
937 if (!NT_SUCCESS(Status))
938 {
939 SetLastNtError(Status);
940 ExFreePool(DesktopName.Buffer);
941 return 0;
942 }
943
944 DPRINT("Successfully opened desktop (%wZ)\n", &DesktopName);
945 ExFreePool(DesktopName.Buffer);
946
947 return Desktop;
948 }
949
950 /*
951 * NtUserOpenInputDesktop
952 *
953 * Opens the input (interactive) desktop.
954 *
955 * Parameters
956 * dwFlags
957 * Interaction flags.
958 *
959 * fInherit
960 * Inheritance option.
961 *
962 * dwDesiredAccess
963 * Requested type of access.
964 *
965 * Return Value
966 * Handle to the input desktop or zero on failure.
967 *
968 * Status
969 * @implemented
970 */
971
972 HDESK STDCALL
973 NtUserOpenInputDesktop(
974 DWORD dwFlags,
975 BOOL fInherit,
976 ACCESS_MASK dwDesiredAccess)
977 {
978 PDESKTOP_OBJECT Object;
979 NTSTATUS Status;
980 HDESK Desktop;
981
982 DPRINT("About to open input desktop\n");
983
984 /* Get a pointer to the desktop object */
985
986 Status = IntValidateDesktopHandle(
987 InputDesktopHandle,
988 UserMode,
989 0,
990 &Object);
991
992 if (!NT_SUCCESS(Status))
993 {
994 DPRINT("Validation of input desktop handle (0x%X) failed\n", InputDesktop);
995 return (HDESK)0;
996 }
997
998 /* Create a new handle to the object */
999
1000 Status = ObOpenObjectByPointer(
1001 Object,
1002 0,
1003 NULL,
1004 dwDesiredAccess,
1005 ExDesktopObjectType,
1006 UserMode,
1007 (HANDLE*)&Desktop);
1008
1009 ObDereferenceObject(Object);
1010
1011 if (NT_SUCCESS(Status))
1012 {
1013 DPRINT("Successfully opened input desktop\n");
1014 return (HDESK)Desktop;
1015 }
1016
1017 SetLastNtError(Status);
1018 return (HDESK)0;
1019 }
1020
1021 /*
1022 * NtUserCloseDesktop
1023 *
1024 * Closes a desktop handle.
1025 *
1026 * Parameters
1027 * hDesktop
1028 * Handle to the desktop.
1029 *
1030 * Return Value
1031 * Status
1032 *
1033 * Remarks
1034 * The desktop handle can be created with NtUserCreateDesktop or
1035 * NtUserOpenDesktop. This function will fail if any thread in the calling
1036 * process is using the specified desktop handle or if the handle refers
1037 * to the initial desktop of the calling process.
1038 *
1039 * Status
1040 * @implemented
1041 */
1042
1043 BOOL STDCALL
1044 NtUserCloseDesktop(HDESK hDesktop)
1045 {
1046 PDESKTOP_OBJECT Object;
1047 NTSTATUS Status;
1048
1049 DPRINT("About to close desktop handle (0x%X)\n", hDesktop);
1050
1051 Status = IntValidateDesktopHandle(
1052 hDesktop,
1053 UserMode,
1054 0,
1055 &Object);
1056
1057 if (!NT_SUCCESS(Status))
1058 {
1059 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
1060 return FALSE;
1061 }
1062
1063 ObDereferenceObject(Object);
1064
1065 DPRINT("Closing desktop handle (0x%X)\n", hDesktop);
1066
1067 Status = ZwClose(hDesktop);
1068 if (!NT_SUCCESS(Status))
1069 {
1070 SetLastNtError(Status);
1071 return FALSE;
1072 }
1073
1074 return TRUE;
1075 }
1076
1077
1078 static int GetSystemVersionString(LPWSTR buffer)
1079 {
1080 RTL_OSVERSIONINFOEXW versionInfo;
1081 int len;
1082
1083 versionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
1084
1085 if (!NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW)&versionInfo)))
1086 return 0;
1087
1088 if (versionInfo.dwMajorVersion <= 4)
1089 len = swprintf(buffer,
1090 L"ReactOS Version %d.%d %s Build %d",
1091 versionInfo.dwMajorVersion, versionInfo.dwMinorVersion,
1092 versionInfo.szCSDVersion, versionInfo.dwBuildNumber&0xFFFF);
1093 else
1094 len = swprintf(buffer,
1095 L"ReactOS %s (Build %d)",
1096 versionInfo.szCSDVersion, versionInfo.dwBuildNumber&0xFFFF);
1097
1098 return len;
1099 }
1100
1101 /*
1102 * NtUserPaintDesktop
1103 *
1104 * The NtUserPaintDesktop function fills the clipping region in the
1105 * specified device context with the desktop pattern or wallpaper. The
1106 * function is provided primarily for shell desktops.
1107 *
1108 * Parameters
1109 * hDC
1110 * Handle to the device context.
1111 *
1112 * Status
1113 * @implemented
1114 */
1115
1116 BOOL STDCALL
1117 NtUserPaintDesktop(HDC hDC)
1118 {
1119 RECT Rect;
1120 HBRUSH DesktopBrush, PreviousBrush;
1121 HWND hWndDesktop;
1122 BOOL doPatBlt = TRUE;
1123 int len;
1124
1125 PWINSTATION_OBJECT WinSta = PsGetWin32Thread()->Desktop->WindowStation;
1126
1127 IntGdiGetClipBox(hDC, &Rect);
1128
1129 hWndDesktop = IntGetDesktopWindow();
1130 DesktopBrush = (HBRUSH)NtUserGetClassLong(hWndDesktop, GCL_HBRBACKGROUND, FALSE);
1131
1132 /*
1133 * Paint desktop background
1134 */
1135
1136 if(WinSta->hbmWallpaper != NULL)
1137 {
1138 PWINDOW_OBJECT DeskWin;
1139
1140 if((DeskWin = IntGetWindowObject(hWndDesktop)))
1141 {
1142 SIZE sz;
1143 int x, y;
1144 HDC hWallpaperDC;
1145
1146 sz.cx = DeskWin->WindowRect.right - DeskWin->WindowRect.left;
1147 sz.cy = DeskWin->WindowRect.bottom - DeskWin->WindowRect.top;
1148 IntReleaseWindowObject(DeskWin);
1149
1150 x = (sz.cx / 2) - (WinSta->cxWallpaper / 2);
1151 y = (sz.cy / 2) - (WinSta->cyWallpaper / 2);
1152
1153 hWallpaperDC = NtGdiCreateCompatableDC(hDC);
1154 if(hWallpaperDC != NULL)
1155 {
1156 HBITMAP hOldBitmap;
1157
1158 if(x > 0 || y > 0)
1159 {
1160 /* FIXME - clip out the bitmap */
1161 PreviousBrush = NtGdiSelectObject(hDC, DesktopBrush);
1162 NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right, Rect.bottom, PATCOPY);
1163 NtGdiSelectObject(hDC, PreviousBrush);
1164 }
1165 else
1166 doPatBlt = FALSE;
1167
1168 hOldBitmap = NtGdiSelectObject(hWallpaperDC, WinSta->hbmWallpaper);
1169 NtGdiBitBlt(hDC, x, y, WinSta->cxWallpaper, WinSta->cyWallpaper, hWallpaperDC, 0, 0, SRCCOPY);
1170 NtGdiSelectObject(hWallpaperDC, hOldBitmap);
1171
1172 NtGdiDeleteDC(hWallpaperDC);
1173 }
1174 }
1175 }
1176
1177 if (doPatBlt) {
1178 PreviousBrush = NtGdiSelectObject(hDC, DesktopBrush);
1179 NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right, Rect.bottom, PATCOPY);
1180 NtGdiSelectObject(hDC, PreviousBrush);
1181 }
1182
1183 /*
1184 * Display system version on the desktop background
1185 */
1186
1187 if (g_PaintDesktopVersion) {
1188 static WCHAR s_wszVersion[256] = {0};
1189 RECT rect;
1190
1191 if (*s_wszVersion)
1192 len = wcslen(s_wszVersion);
1193 else
1194 len = GetSystemVersionString(s_wszVersion);
1195
1196 if (len) {
1197 if (!NtUserSystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0)) {
1198 rect.right = NtUserGetSystemMetrics(SM_CXSCREEN);
1199 rect.bottom = NtUserGetSystemMetrics(SM_CYSCREEN);
1200 }
1201
1202 COLORREF color_old = NtGdiSetTextColor(hDC, RGB(255,255,255));
1203 UINT align_old = NtGdiSetTextAlign(hDC, TA_RIGHT);
1204 int mode_old = NtGdiSetBkMode(hDC, TRANSPARENT);
1205
1206 NtGdiTextOut(hDC, rect.right-16, rect.bottom-48, s_wszVersion, len);
1207
1208 NtGdiSetBkMode(hDC, mode_old);
1209 NtGdiSetTextAlign(hDC, align_old);
1210 NtGdiSetTextColor(hDC, color_old);
1211 }
1212 }
1213
1214 return TRUE;
1215 }
1216
1217
1218 /*
1219 * NtUserSwitchDesktop
1220 *
1221 * Sets the current input (interactive) desktop.
1222 *
1223 * Parameters
1224 * hDesktop
1225 * Handle to desktop.
1226 *
1227 * Return Value
1228 * Status
1229 *
1230 * Status
1231 * @unimplemented
1232 */
1233
1234 BOOL STDCALL
1235 NtUserSwitchDesktop(HDESK hDesktop)
1236 {
1237 PDESKTOP_OBJECT DesktopObject;
1238 NTSTATUS Status;
1239
1240 DPRINT("About to switch desktop (0x%X)\n", hDesktop);
1241
1242 Status = IntValidateDesktopHandle(
1243 hDesktop,
1244 UserMode,
1245 0,
1246 &DesktopObject);
1247
1248 if (!NT_SUCCESS(Status))
1249 {
1250 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
1251 return FALSE;
1252 }
1253
1254 /*
1255 * Don't allow applications switch the desktop if it's locked, unless the caller
1256 * is the logon application itself
1257 */
1258 if((DesktopObject->WindowStation->Flags & WSS_LOCKED) &&
1259 LogonProcess != NULL && LogonProcess != PsGetWin32Process())
1260 {
1261 ObDereferenceObject(DesktopObject);
1262 DPRINT1("Switching desktop 0x%x denied because the work station is locked!\n", hDesktop);
1263 return FALSE;
1264 }
1265
1266 /* FIXME: Fail if the desktop belong to an invisible window station */
1267 /* FIXME: Fail if the process is associated with a secured
1268 desktop such as Winlogon or Screen-Saver */
1269 /* FIXME: Connect to input device */
1270
1271 /* Set the active desktop in the desktop's window station. */
1272 DesktopObject->WindowStation->ActiveDesktop = DesktopObject;
1273
1274 /* Set the global state. */
1275 InputDesktop = DesktopObject;
1276 InputDesktopHandle = hDesktop;
1277 InputWindowStation = DesktopObject->WindowStation;
1278
1279 ObDereferenceObject(DesktopObject);
1280
1281 return TRUE;
1282 }
1283
1284 /*
1285 * NtUserResolveDesktopForWOW
1286 *
1287 * Status
1288 * @unimplemented
1289 */
1290
1291 DWORD STDCALL
1292 NtUserResolveDesktopForWOW(DWORD Unknown0)
1293 {
1294 UNIMPLEMENTED
1295 return 0;
1296 }
1297
1298 /*
1299 * NtUserGetThreadDesktop
1300 *
1301 * Status
1302 * @implemented
1303 */
1304
1305 HDESK STDCALL
1306 NtUserGetThreadDesktop(DWORD dwThreadId, DWORD Unknown1)
1307 {
1308 NTSTATUS Status;
1309 PETHREAD Thread;
1310 PDESKTOP_OBJECT DesktopObject;
1311 HDESK Ret, hThreadDesktop;
1312 OBJECT_HANDLE_INFORMATION HandleInformation;
1313
1314 if(!dwThreadId)
1315 {
1316 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1317 return 0;
1318 }
1319
1320 Status = PsLookupThreadByThreadId((HANDLE)dwThreadId, &Thread);
1321 if(!NT_SUCCESS(Status))
1322 {
1323 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1324 return 0;
1325 }
1326
1327 if(Thread->ThreadsProcess == PsGetCurrentProcess())
1328 {
1329 /* just return the handle, we queried the desktop handle of a thread running
1330 in the same context */
1331 Ret = Thread->Tcb.Win32Thread->hDesktop;
1332 ObDereferenceObject(Thread);
1333 return Ret;
1334 }
1335
1336 /* get the desktop handle and the desktop of the thread */
1337 if(!(hThreadDesktop = Thread->Tcb.Win32Thread->hDesktop) ||
1338 !(DesktopObject = Thread->Tcb.Win32Thread->Desktop))
1339 {
1340 ObDereferenceObject(Thread);
1341 DPRINT1("Desktop information of thread 0x%x broken!?\n", dwThreadId);
1342 return NULL;
1343 }
1344
1345 /* we could just use DesktopObject instead of looking up the handle, but latter
1346 may be a bit safer (e.g. when the desktop is being destroyed */
1347 /* switch into the context of the thread we're trying to get the desktop from,
1348 so we can use the handle */
1349 KeAttachProcess(&Thread->ThreadsProcess->Pcb);
1350 Status = ObReferenceObjectByHandle(hThreadDesktop,
1351 GENERIC_ALL,
1352 ExDesktopObjectType,
1353 UserMode,
1354 (PVOID*)&DesktopObject,
1355 &HandleInformation);
1356 KeDetachProcess();
1357
1358 /* the handle couldn't be found, there's nothing to get... */
1359 if(!NT_SUCCESS(Status))
1360 {
1361 ObDereferenceObject(Thread);
1362 return NULL;
1363 }
1364
1365 /* lookup our handle table if we can find a handle to the desktop object,
1366 if not, create one */
1367 Ret = IntGetDesktopObjectHandle(DesktopObject);
1368
1369 /* all done, we got a valid handle to the desktop */
1370 ObDereferenceObject(DesktopObject);
1371 ObDereferenceObject(Thread);
1372 return Ret;
1373 }
1374
1375 /*
1376 * NtUserSetThreadDesktop
1377 *
1378 * Status
1379 * @implemented
1380 */
1381
1382 BOOL STDCALL
1383 NtUserSetThreadDesktop(HDESK hDesktop)
1384 {
1385 PW32THREAD W32Thread;
1386 PDESKTOP_OBJECT DesktopObject;
1387 NTSTATUS Status;
1388
1389 /* Validate the new desktop. */
1390 Status = IntValidateDesktopHandle(
1391 hDesktop,
1392 UserMode,
1393 0,
1394 &DesktopObject);
1395
1396 if (!NT_SUCCESS(Status))
1397 {
1398 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
1399 return FALSE;
1400 }
1401
1402 W32Thread = PsGetWin32Thread();
1403
1404 /* FIXME: Should check here to see if the thread has any windows. */
1405
1406 if (W32Thread->Desktop != NULL)
1407 {
1408 ObDereferenceObject(W32Thread->Desktop);
1409 }
1410
1411 W32Thread->Desktop = DesktopObject;
1412 W32Thread->hDesktop = hDesktop;
1413
1414 return TRUE;
1415 }
1416
1417 /* EOF */