move from branch
[reactos.git] / reactos / subsystems / win32 / 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
32 #include <w32k.h>
33
34 //#define YDEBUG
35 #include <wine/debug.h>
36
37 static
38 VOID
39 IntFreeDesktopHeap(
40 IN OUT PDESKTOP_OBJECT Desktop
41 );
42
43 /* GLOBALS *******************************************************************/
44
45 /* Currently active desktop */
46 PDESKTOP_OBJECT InputDesktop = NULL;
47 HDESK InputDesktopHandle = NULL;
48 HDC ScreenDeviceContext = NULL;
49 BOOL g_PaintDesktopVersion = FALSE;
50
51 GENERIC_MAPPING IntDesktopMapping =
52 {
53 STANDARD_RIGHTS_READ | DESKTOP_ENUMERATE |
54 DESKTOP_READOBJECTS,
55 STANDARD_RIGHTS_WRITE | DESKTOP_CREATEMENU |
56 DESKTOP_CREATEWINDOW |
57 DESKTOP_HOOKCONTROL |
58 DESKTOP_JOURNALPLAYBACK |
59 DESKTOP_JOURNALRECORD |
60 DESKTOP_WRITEOBJECTS,
61 STANDARD_RIGHTS_EXECUTE | DESKTOP_SWITCHDESKTOP,
62 STANDARD_RIGHTS_REQUIRED | DESKTOP_CREATEMENU |
63 DESKTOP_CREATEWINDOW |
64 DESKTOP_ENUMERATE |
65 DESKTOP_HOOKCONTROL |
66 DESKTOP_JOURNALPLAYBACK |
67 DESKTOP_JOURNALRECORD |
68 DESKTOP_READOBJECTS |
69 DESKTOP_SWITCHDESKTOP |
70 DESKTOP_WRITEOBJECTS
71 };
72
73 /* OBJECT CALLBACKS **********************************************************/
74
75 NTSTATUS
76 NTAPI
77 IntDesktopObjectParse(IN PVOID ParseObject,
78 IN PVOID ObjectType,
79 IN OUT PACCESS_STATE AccessState,
80 IN KPROCESSOR_MODE AccessMode,
81 IN ULONG Attributes,
82 IN OUT PUNICODE_STRING CompleteName,
83 IN OUT PUNICODE_STRING RemainingName,
84 IN OUT PVOID Context OPTIONAL,
85 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
86 OUT PVOID *Object)
87 {
88 NTSTATUS Status;
89 PDESKTOP_OBJECT Desktop;
90 OBJECT_ATTRIBUTES ObjectAttributes;
91 PLIST_ENTRY NextEntry, ListHead;
92 PWINSTATION_OBJECT WinStaObject = (PWINSTATION_OBJECT)ParseObject;
93 PUNICODE_STRING DesktopName;
94
95 /* Set the list pointers and loop the window station */
96 ListHead = &WinStaObject->DesktopListHead;
97 NextEntry = ListHead->Flink;
98 while (NextEntry != ListHead)
99 {
100 /* Get the current desktop */
101 Desktop = CONTAINING_RECORD(NextEntry, DESKTOP_OBJECT, ListEntry);
102
103 /* Get its name */
104 DesktopName = GET_DESKTOP_NAME(Desktop);
105 if (DesktopName)
106 {
107 /* Compare the name */
108 if (RtlEqualUnicodeString(RemainingName,
109 DesktopName,
110 (Attributes & OBJ_CASE_INSENSITIVE)))
111 {
112 /* We found a match. Did this come from a create? */
113 if (Context)
114 {
115 /* Unless OPEN_IF was given, fail with an error */
116 if (!(Attributes & OBJ_OPENIF))
117 {
118 /* Name collision */
119 return STATUS_OBJECT_NAME_COLLISION;
120 }
121 else
122 {
123 /* Otherwise, return with a warning only */
124 Status = STATUS_OBJECT_NAME_EXISTS;
125 }
126 }
127 else
128 {
129 /* This was a real open, so this is OK */
130 Status = STATUS_SUCCESS;
131 }
132
133 /* Reference the desktop and return it */
134 ObReferenceObject(Desktop);
135 *Object = Desktop;
136 return Status;
137 }
138 }
139
140 /* Go to the next desktop */
141 NextEntry = NextEntry->Flink;
142 }
143
144 /* If we got here but this isn't a create, then fail */
145 if (!Context) return STATUS_OBJECT_NAME_NOT_FOUND;
146
147 /* Create the desktop object */
148 InitializeObjectAttributes(&ObjectAttributes, RemainingName, 0, NULL, NULL);
149 Status = ObCreateObject(KernelMode,
150 ExDesktopObjectType,
151 &ObjectAttributes,
152 KernelMode,
153 NULL,
154 sizeof(DESKTOP_OBJECT),
155 0,
156 0,
157 (PVOID)&Desktop);
158 if (!NT_SUCCESS(Status)) return Status;
159
160 /* Initialize shell hook window list and set the parent */
161 InitializeListHead(&Desktop->ShellHookWindows);
162 Desktop->WindowStation = (PWINSTATION_OBJECT)ParseObject;
163
164 /* Put the desktop on the window station's list of associated desktops */
165 InsertTailList(&Desktop->WindowStation->DesktopListHead,
166 &Desktop->ListEntry);
167
168 /* Set the desktop object and return success */
169 *Object = Desktop;
170 return STATUS_SUCCESS;
171 }
172
173 VOID STDCALL
174 IntDesktopObjectDelete(PWIN32_DELETEMETHOD_PARAMETERS Parameters)
175 {
176 PDESKTOP_OBJECT Desktop = (PDESKTOP_OBJECT)Parameters->Object;
177
178 DPRINT("Deleting desktop (0x%X)\n", Desktop);
179
180 /* Remove the desktop from the window station's list of associcated desktops */
181 RemoveEntryList(&Desktop->ListEntry);
182
183 IntFreeDesktopHeap(Desktop);
184 }
185
186 /* PRIVATE FUNCTIONS **********************************************************/
187
188 NTSTATUS
189 FASTCALL
190 InitDesktopImpl(VOID)
191 {
192 /* Set Desktop Object Attributes */
193 ExDesktopObjectType->TypeInfo.DefaultNonPagedPoolCharge = sizeof(DESKTOP_OBJECT);
194 ExDesktopObjectType->TypeInfo.GenericMapping = IntDesktopMapping;
195 return STATUS_SUCCESS;
196 }
197
198 NTSTATUS
199 FASTCALL
200 CleanupDesktopImpl(VOID)
201 {
202 return STATUS_SUCCESS;
203 }
204
205 static int GetSystemVersionString(LPWSTR buffer)
206 {
207 RTL_OSVERSIONINFOEXW versionInfo;
208 int len;
209
210 versionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
211
212 if (!NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW)&versionInfo)))
213 return 0;
214
215 if (versionInfo.dwMajorVersion <= 4)
216 len = swprintf(buffer,
217 L"ReactOS Version %d.%d %s Build %d",
218 versionInfo.dwMajorVersion, versionInfo.dwMinorVersion,
219 versionInfo.szCSDVersion, versionInfo.dwBuildNumber&0xFFFF);
220 else
221 len = swprintf(buffer,
222 L"ReactOS %s (Build %d)",
223 versionInfo.szCSDVersion, versionInfo.dwBuildNumber&0xFFFF);
224
225 return len;
226 }
227
228
229 NTSTATUS FASTCALL
230 IntParseDesktopPath(PEPROCESS Process,
231 PUNICODE_STRING DesktopPath,
232 HWINSTA *hWinSta,
233 HDESK *hDesktop)
234 {
235 OBJECT_ATTRIBUTES ObjectAttributes;
236 UNICODE_STRING WinSta, Desktop, FullName;
237 BOOL DesktopPresent = FALSE;
238 BOOL WinStaPresent = FALSE;
239 NTSTATUS Status;
240
241 ASSERT(hWinSta);
242
243 *hWinSta = NULL;
244
245 if(hDesktop != NULL)
246 {
247 *hDesktop = NULL;
248 }
249
250 RtlInitUnicodeString(&WinSta, NULL);
251 RtlInitUnicodeString(&Desktop, NULL);
252
253 if(DesktopPath != NULL && DesktopPath->Buffer != NULL && DesktopPath->Length > sizeof(WCHAR))
254 {
255 PWCHAR c = DesktopPath->Buffer;
256 USHORT wl = 0;
257 USHORT l = DesktopPath->Length;
258
259 /*
260 * Parse the desktop path string which can be in the form "WinSta\Desktop"
261 * or just "Desktop". In latter case WinSta0 will be used.
262 */
263
264 while(l > 0)
265 {
266 if(*c == L'\\')
267 {
268 wl = (ULONG_PTR)c - (ULONG_PTR)DesktopPath->Buffer;
269 break;
270 }
271 l -= sizeof(WCHAR);
272 c++;
273 }
274
275 if(wl > 0)
276 {
277 WinSta.Length = wl;
278 WinSta.MaximumLength = wl + sizeof(WCHAR);
279 WinSta.Buffer = DesktopPath->Buffer;
280
281 WinStaPresent = TRUE;
282 c++;
283 }
284
285 Desktop.Length = DesktopPath->Length - wl;
286 if(wl > 0)
287 {
288 Desktop.Length -= sizeof(WCHAR);
289 }
290 if(Desktop.Length > 0)
291 {
292 Desktop.MaximumLength = Desktop.Length + sizeof(WCHAR);
293 Desktop.Buffer = ((wl > 0) ? c : DesktopPath->Buffer);
294 DesktopPresent = TRUE;
295 }
296 }
297
298 if(!WinStaPresent)
299 {
300 #if 0
301 /* search the process handle table for (inherited) window station
302 handles, use a more appropriate one than WinSta0 if possible. */
303 if (!ObFindHandleForObject(Process,
304 NULL,
305 ExWindowStationObjectType,
306 NULL,
307 (PHANDLE)hWinSta))
308 #endif
309 {
310 /* we had no luck searching for opened handles, use WinSta0 now */
311 RtlInitUnicodeString(&WinSta, L"WinSta0");
312 }
313 }
314
315 if(!DesktopPresent && hDesktop != NULL)
316 {
317 #if 0
318 /* search the process handle table for (inherited) desktop
319 handles, use a more appropriate one than Default if possible. */
320 if (!ObFindHandleForObject(Process,
321 NULL,
322 ExDesktopObjectType,
323 NULL,
324 (PHANDLE)hDesktop))
325 #endif
326 {
327 /* we had no luck searching for opened handles, use Desktop now */
328 RtlInitUnicodeString(&Desktop, L"Default");
329 }
330 }
331
332 if(*hWinSta == NULL)
333 {
334 if(!IntGetFullWindowStationName(&FullName, &WinSta, NULL))
335 {
336 return STATUS_INSUFFICIENT_RESOURCES;
337 }
338
339 /* open the window station */
340 InitializeObjectAttributes(&ObjectAttributes,
341 &FullName,
342 OBJ_CASE_INSENSITIVE,
343 NULL,
344 NULL);
345
346 Status = ObOpenObjectByName(&ObjectAttributes,
347 ExWindowStationObjectType,
348 KernelMode,
349 NULL,
350 0,
351 NULL,
352 (HANDLE*)hWinSta);
353
354 RtlFreeUnicodeString(&FullName);
355
356 if(!NT_SUCCESS(Status))
357 {
358 SetLastNtError(Status);
359 DPRINT("Failed to reference window station %wZ PID: %d!\n", &WinSta, PsGetCurrentProcessId());
360 return Status;
361 }
362 }
363
364 if(hDesktop != NULL && *hDesktop == NULL)
365 {
366 if(!IntGetFullWindowStationName(&FullName, &WinSta, &Desktop))
367 {
368 NtClose(*hWinSta);
369 *hWinSta = NULL;
370 return STATUS_INSUFFICIENT_RESOURCES;
371 }
372
373 /* open the desktop object */
374 InitializeObjectAttributes(&ObjectAttributes,
375 &FullName,
376 OBJ_CASE_INSENSITIVE,
377 NULL,
378 NULL);
379
380 Status = ObOpenObjectByName(&ObjectAttributes,
381 ExDesktopObjectType,
382 KernelMode,
383 NULL,
384 0,
385 NULL,
386 (HANDLE*)hDesktop);
387
388 RtlFreeUnicodeString(&FullName);
389
390 if(!NT_SUCCESS(Status))
391 {
392 *hDesktop = NULL;
393 NtClose(*hWinSta);
394 *hWinSta = NULL;
395 SetLastNtError(Status);
396 DPRINT("Failed to reference desktop %wZ PID: %d!\n", &Desktop, PsGetCurrentProcessId());
397 return Status;
398 }
399 }
400
401 return STATUS_SUCCESS;
402 }
403
404 /*
405 * IntValidateDesktopHandle
406 *
407 * Validates the desktop handle.
408 *
409 * Remarks
410 * If the function succeeds, the handle remains referenced. If the
411 * fucntion fails, last error is set.
412 */
413
414 NTSTATUS FASTCALL
415 IntValidateDesktopHandle(
416 HDESK Desktop,
417 KPROCESSOR_MODE AccessMode,
418 ACCESS_MASK DesiredAccess,
419 PDESKTOP_OBJECT *Object)
420 {
421 NTSTATUS Status;
422
423 Status = ObReferenceObjectByHandle(
424 Desktop,
425 DesiredAccess,
426 ExDesktopObjectType,
427 AccessMode,
428 (PVOID*)Object,
429 NULL);
430
431 if (!NT_SUCCESS(Status))
432 SetLastNtError(Status);
433
434 return Status;
435 }
436
437 VOID FASTCALL
438 IntGetDesktopWorkArea(PDESKTOP_OBJECT Desktop, PRECT Rect)
439 {
440 PRECT Ret;
441
442 ASSERT(Desktop);
443
444 Ret = &Desktop->WorkArea;
445 if((Ret->right == -1) && ScreenDeviceContext)
446 {
447 PDC dc;
448 BITMAPOBJ *BitmapObj;
449 dc = DC_LockDc(ScreenDeviceContext);
450 /* FIXME - Handle dc == NULL!!!! */
451 BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
452 if(BitmapObj)
453 {
454 Ret->right = BitmapObj->SurfObj.sizlBitmap.cx;
455 Ret->bottom = BitmapObj->SurfObj.sizlBitmap.cy;
456 BITMAPOBJ_UnlockBitmap(BitmapObj);
457 }
458 DC_UnlockDc(dc);
459 }
460
461 if(Rect)
462 {
463 *Rect = *Ret;
464 }
465 }
466
467 PDESKTOP_OBJECT FASTCALL
468 IntGetActiveDesktop(VOID)
469 {
470 return InputDesktop;
471 }
472
473 /*
474 * returns or creates a handle to the desktop object
475 */
476 HDESK FASTCALL
477 IntGetDesktopObjectHandle(PDESKTOP_OBJECT DesktopObject)
478 {
479 NTSTATUS Status;
480 HDESK Ret;
481
482 ASSERT(DesktopObject);
483
484 if (!ObFindHandleForObject(PsGetCurrentProcess(),
485 DesktopObject,
486 ExDesktopObjectType,
487 NULL,
488 (PHANDLE)&Ret))
489 {
490 Status = ObOpenObjectByPointer(DesktopObject,
491 0,
492 NULL,
493 0,
494 ExDesktopObjectType,
495 UserMode,
496 (PHANDLE)&Ret);
497 if(!NT_SUCCESS(Status))
498 {
499 /* unable to create a handle */
500 DPRINT1("Unable to create a desktop handle\n");
501 return NULL;
502 }
503 }
504 else
505 {
506 DPRINT1("Got handle: %lx\n", Ret);
507 }
508
509 return Ret;
510 }
511
512 PUSER_MESSAGE_QUEUE FASTCALL
513 IntGetFocusMessageQueue(VOID)
514 {
515 PDESKTOP_OBJECT pdo = IntGetActiveDesktop();
516 if (!pdo)
517 {
518 DPRINT("No active desktop\n");
519 return(NULL);
520 }
521 return (PUSER_MESSAGE_QUEUE)pdo->ActiveMessageQueue;
522 }
523
524 VOID FASTCALL
525 IntSetFocusMessageQueue(PUSER_MESSAGE_QUEUE NewQueue)
526 {
527 PUSER_MESSAGE_QUEUE Old;
528 PDESKTOP_OBJECT pdo = IntGetActiveDesktop();
529 if (!pdo)
530 {
531 DPRINT("No active desktop\n");
532 return;
533 }
534 if(NewQueue != NULL)
535 {
536 if(NewQueue->Desktop != NULL)
537 {
538 DPRINT("Message Queue already attached to another desktop!\n");
539 return;
540 }
541 IntReferenceMessageQueue(NewQueue);
542 InterlockedExchange((LONG*)&NewQueue->Desktop, (LONG)pdo);
543 }
544 Old = (PUSER_MESSAGE_QUEUE)InterlockedExchange((LONG*)&pdo->ActiveMessageQueue, (LONG)NewQueue);
545 if(Old != NULL)
546 {
547 InterlockedExchange((LONG*)&Old->Desktop, 0);
548 IntDereferenceMessageQueue(Old);
549 }
550 }
551
552 HWND FASTCALL IntGetDesktopWindow(VOID)
553 {
554 PDESKTOP_OBJECT pdo = IntGetActiveDesktop();
555 if (!pdo)
556 {
557 DPRINT("No active desktop\n");
558 return NULL;
559 }
560 return pdo->DesktopWindow;
561 }
562
563 PWINDOW_OBJECT FASTCALL UserGetDesktopWindow(VOID)
564 {
565 PDESKTOP_OBJECT pdo = IntGetActiveDesktop();
566
567 if (!pdo)
568 {
569 DPRINT("No active desktop\n");
570 return NULL;
571 }
572
573 return UserGetWindowObject(pdo->DesktopWindow);
574 }
575
576
577 HWND FASTCALL IntGetCurrentThreadDesktopWindow(VOID)
578 {
579 PDESKTOP_OBJECT pdo = PsGetCurrentThreadWin32Thread()->Desktop;
580 if (NULL == pdo)
581 {
582 DPRINT1("Thread doesn't have a desktop\n");
583 return NULL;
584 }
585 return pdo->DesktopWindow;
586 }
587
588 BOOL FASTCALL IntDesktopUpdatePerUserSettings(BOOL bEnable)
589 {
590 if (bEnable)
591 {
592 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
593 NTSTATUS Status;
594
595 RtlZeroMemory(QueryTable, sizeof(QueryTable));
596
597 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
598 QueryTable[0].Name = L"PaintDesktopVersion";
599 QueryTable[0].EntryContext = &g_PaintDesktopVersion;
600
601 /* Query the "PaintDesktopVersion" flag in the "Control Panel\Desktop" key */
602 Status = RtlQueryRegistryValues(RTL_REGISTRY_USER,
603 L"Control Panel\\Desktop",
604 QueryTable, NULL, NULL);
605 if (!NT_SUCCESS(Status))
606 {
607 DPRINT1("RtlQueryRegistryValues failed for PaintDesktopVersion (%x)\n",
608 Status);
609 g_PaintDesktopVersion = FALSE;
610 return FALSE;
611 }
612
613 DPRINT("PaintDesktopVersion = %d\n", g_PaintDesktopVersion);
614
615 return TRUE;
616 }
617 else
618 {
619 g_PaintDesktopVersion = FALSE;
620 return TRUE;
621 }
622 }
623
624 /* PUBLIC FUNCTIONS ***********************************************************/
625
626 NTSTATUS FASTCALL
627 co_IntShowDesktop(PDESKTOP_OBJECT Desktop, ULONG Width, ULONG Height)
628 {
629 CSR_API_MESSAGE Request;
630
631 Request.Type = MAKE_CSR_API(SHOW_DESKTOP, CSR_GUI);
632 Request.Data.ShowDesktopRequest.DesktopWindow = Desktop->DesktopWindow;
633 Request.Data.ShowDesktopRequest.Width = Width;
634 Request.Data.ShowDesktopRequest.Height = Height;
635
636 return co_CsrNotify(&Request);
637 }
638
639 NTSTATUS FASTCALL
640 IntHideDesktop(PDESKTOP_OBJECT Desktop)
641 {
642 #if 0
643 CSRSS_API_REQUEST Request;
644 CSRSS_API_REPLY Reply;
645
646 Request.Type = CSRSS_HIDE_DESKTOP;
647 Request.Data.HideDesktopRequest.DesktopWindow = Desktop->DesktopWindow;
648
649 return NotifyCsrss(&Request, &Reply);
650 #else
651
652 PWINDOW_OBJECT DesktopWindow;
653
654 DesktopWindow = IntGetWindowObject(Desktop->DesktopWindow);
655 if (! DesktopWindow)
656 {
657 return ERROR_INVALID_WINDOW_HANDLE;
658 }
659 DesktopWindow->Style &= ~WS_VISIBLE;
660
661 return STATUS_SUCCESS;
662 #endif
663 }
664
665
666
667
668 static
669 HWND* FASTCALL
670 UserBuildShellHookHwndList(PDESKTOP_OBJECT Desktop)
671 {
672 ULONG entries=0;
673 PSHELL_HOOK_WINDOW Current;
674 HWND* list;
675
676 /* fixme: if we save nb elements in desktop, we dont have to loop to find nb entries */
677 LIST_FOR_EACH(Current, &Desktop->ShellHookWindows, SHELL_HOOK_WINDOW, ListEntry)
678 entries++;
679
680 if (!entries) return NULL;
681
682 list = ExAllocatePool(PagedPool, sizeof(HWND) * (entries + 1)); /* alloc one extra for nullterm */
683 if (list)
684 {
685 HWND* cursor = list;
686
687 LIST_FOR_EACH(Current, &Desktop->ShellHookWindows, SHELL_HOOK_WINDOW, ListEntry)
688 *cursor++ = Current->hWnd;
689
690 *cursor = NULL; /* nullterm list */
691 }
692
693 return list;
694 }
695
696 /*
697 * Send the Message to the windows registered for ShellHook
698 * notifications. The lParam contents depend on the Message. See
699 * MSDN for more details (RegisterShellHookWindow)
700 */
701 VOID co_IntShellHookNotify(WPARAM Message, LPARAM lParam)
702 {
703 PDESKTOP_OBJECT Desktop = IntGetActiveDesktop();
704 HWND* HwndList;
705
706 static UINT MsgType = 0;
707
708 if (!MsgType)
709 {
710
711 /* Too bad, this doesn't work.*/
712 #if 0
713 UNICODE_STRING Str;
714 RtlInitUnicodeString(&Str, L"SHELLHOOK");
715 MsgType = UserRegisterWindowMessage(&Str);
716 #endif
717
718 MsgType = IntAddAtom(L"SHELLHOOK");
719
720 DPRINT("MsgType = %x\n", MsgType);
721 if (!MsgType)
722 DPRINT1("LastError: %x\n", GetLastNtError());
723 }
724
725 if (!Desktop)
726 {
727 DPRINT("IntShellHookNotify: No desktop!\n");
728 return;
729 }
730
731 HwndList = UserBuildShellHookHwndList(Desktop);
732 if (HwndList)
733 {
734 HWND* cursor = HwndList;
735
736 for (; *cursor; cursor++)
737 {
738 DPRINT("Sending notify\n");
739 co_IntPostOrSendMessage(*cursor,
740 MsgType,
741 Message,
742 lParam);
743 }
744
745 ExFreePool(HwndList);
746 }
747
748 }
749
750 /*
751 * Add the window to the ShellHookWindows list. The windows
752 * on that list get notifications that are important to shell
753 * type applications.
754 *
755 * TODO: Validate the window? I'm not sure if sending these messages to
756 * an unsuspecting application that is not your own is a nice thing to do.
757 */
758 BOOL IntRegisterShellHookWindow(HWND hWnd)
759 {
760 PDESKTOP_OBJECT Desktop = PsGetCurrentThreadWin32Thread()->Desktop;
761 PSHELL_HOOK_WINDOW Entry;
762
763 DPRINT("IntRegisterShellHookWindow\n");
764
765 /* First deregister the window, so we can be sure it's never twice in the
766 * list.
767 */
768 IntDeRegisterShellHookWindow(hWnd);
769
770 Entry = ExAllocatePoolWithTag(PagedPool,
771 sizeof(SHELL_HOOK_WINDOW),
772 TAG_WINSTA);
773
774 if (!Entry)
775 return FALSE;
776
777 Entry->hWnd = hWnd;
778
779 InsertTailList(&Desktop->ShellHookWindows, &Entry->ListEntry);
780
781 return TRUE;
782 }
783
784 /*
785 * Remove the window from the ShellHookWindows list. The windows
786 * on that list get notifications that are important to shell
787 * type applications.
788 */
789 BOOL IntDeRegisterShellHookWindow(HWND hWnd)
790 {
791 PDESKTOP_OBJECT Desktop = PsGetCurrentThreadWin32Thread()->Desktop;
792 PSHELL_HOOK_WINDOW Current;
793
794 LIST_FOR_EACH(Current, &Desktop->ShellHookWindows, SHELL_HOOK_WINDOW, ListEntry)
795 {
796 if (Current->hWnd == hWnd)
797 {
798 RemoveEntryList(&Current->ListEntry);
799 ExFreePool(Current);
800 return TRUE;
801 }
802 }
803
804 return FALSE;
805 }
806
807 static VOID
808 IntFreeDesktopHeap(IN OUT PDESKTOP_OBJECT Desktop)
809 {
810 if (Desktop->DesktopHeapSection != NULL)
811 {
812 ObDereferenceObject(Desktop->DesktopHeapSection);
813 Desktop->DesktopHeapSection = NULL;
814 }
815 }
816 /* SYSCALLS *******************************************************************/
817
818
819 /*
820 * NtUserCreateDesktop
821 *
822 * Creates a new desktop.
823 *
824 * Parameters
825 * lpszDesktopName
826 * Name of the new desktop.
827 *
828 * dwFlags
829 * Interaction flags.
830 *
831 * dwDesiredAccess
832 * Requested type of access.
833 *
834 * lpSecurity
835 * Security descriptor.
836 *
837 * hWindowStation
838 * Handle to window station on which to create the desktop.
839 *
840 * Return Value
841 * If the function succeeds, the return value is a handle to the newly
842 * created desktop. If the specified desktop already exists, the function
843 * succeeds and returns a handle to the existing desktop. When you are
844 * finished using the handle, call the CloseDesktop function to close it.
845 * If the function fails, the return value is NULL.
846 *
847 * Status
848 * @implemented
849 */
850
851 HDESK STDCALL
852 NtUserCreateDesktop(
853 PUNICODE_STRING lpszDesktopName,
854 DWORD dwFlags,
855 ACCESS_MASK dwDesiredAccess,
856 LPSECURITY_ATTRIBUTES lpSecurity,
857 HWINSTA hWindowStation)
858 {
859 OBJECT_ATTRIBUTES ObjectAttributes;
860 PWINSTATION_OBJECT WinStaObject;
861 PDESKTOP_OBJECT DesktopObject;
862 UNICODE_STRING DesktopName;
863 NTSTATUS Status;
864 HDESK Desktop;
865 CSR_API_MESSAGE Request;
866 PVOID DesktopHeapSystemBase = NULL;
867 SIZE_T DesktopInfoSize;
868 UNICODE_STRING SafeDesktopName;
869 ULONG DummyContext;
870 DECLARE_RETURN(HDESK);
871
872
873 DPRINT("Enter NtUserCreateDesktop: %wZ\n", lpszDesktopName);
874 UserEnterExclusive();
875
876 Status = IntValidateWindowStationHandle(
877 hWindowStation,
878 KernelMode,
879 0, /* FIXME - WINSTA_CREATEDESKTOP */
880 &WinStaObject);
881
882 if (! NT_SUCCESS(Status))
883 {
884 DPRINT1("Failed validation of window station handle (0x%X), cannot create desktop %wZ\n",
885 hWindowStation, lpszDesktopName);
886 SetLastNtError(Status);
887 RETURN( NULL);
888 }
889 if(lpszDesktopName != NULL)
890 {
891 Status = IntSafeCopyUnicodeString(&SafeDesktopName, lpszDesktopName);
892 if(!NT_SUCCESS(Status))
893 {
894 SetLastNtError(Status);
895 RETURN( NULL);
896 }
897 }
898 else
899 {
900 RtlInitUnicodeString(&SafeDesktopName, NULL);
901 }
902
903 if (! IntGetFullWindowStationName(&DesktopName, &WinStaObject->Name,
904 &SafeDesktopName))
905 {
906 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
907 ObDereferenceObject(WinStaObject);
908 RtlFreeUnicodeString(&SafeDesktopName);
909 RETURN( NULL);
910 }
911 RtlFreeUnicodeString(&SafeDesktopName);
912 ObDereferenceObject(WinStaObject);
913
914 /*
915 * Try to open already existing desktop
916 */
917
918 DPRINT("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 KernelMode,
932 NULL,
933 dwDesiredAccess,
934 (PVOID)&DummyContext,
935 (HANDLE*)&Desktop);
936 if (!NT_SUCCESS(Status)) RETURN(NULL);
937 if (Status == STATUS_OBJECT_NAME_EXISTS)
938 {
939 ExFreePool(DesktopName.Buffer);
940 RETURN( Desktop);
941 }
942
943 /* Reference the desktop */
944 Status = ObReferenceObjectByHandle(Desktop,
945 0,
946 ExDesktopObjectType,
947 KernelMode,
948 (PVOID)&DesktopObject,
949 NULL);
950 if (!NT_SUCCESS(Status)) RETURN(NULL);
951
952 DesktopObject->DesktopHeapSection = NULL;
953 DesktopObject->hDesktopHeap = UserCreateHeap(&DesktopObject->DesktopHeapSection,
954 &DesktopHeapSystemBase,
955 4 * 1024 * 1024); /* FIXME */
956 if (DesktopObject->hDesktopHeap == NULL)
957 {
958 ObDereferenceObject(DesktopObject);
959 DPRINT1("Failed to create desktop heap!\n");
960 RETURN(NULL);
961 }
962
963 DesktopInfoSize = FIELD_OFFSET(DESKTOP,
964 szDesktopName[(lpszDesktopName->Length / sizeof(WCHAR)) + 1]);
965
966 DesktopObject->DesktopInfo = RtlAllocateHeap(DesktopObject->hDesktopHeap,
967 HEAP_NO_SERIALIZE,
968 DesktopInfoSize);
969
970 if (DesktopObject->DesktopInfo == NULL)
971 {
972 ObDereferenceObject(DesktopObject);
973 DPRINT1("Failed to create the DESKTOP structure!\n");
974 RETURN(NULL);
975 }
976
977 RtlZeroMemory(DesktopObject->DesktopInfo,
978 DesktopInfoSize);
979
980 DesktopObject->DesktopInfo->hKernelHeap = DesktopObject->hDesktopHeap;
981 RtlCopyMemory(DesktopObject->DesktopInfo->szDesktopName,
982 lpszDesktopName->Buffer,
983 lpszDesktopName->Length);
984
985 // init desktop area
986 DesktopObject->WorkArea.left = 0;
987 DesktopObject->WorkArea.top = 0;
988 DesktopObject->WorkArea.right = -1;
989 DesktopObject->WorkArea.bottom = -1;
990 IntGetDesktopWorkArea(DesktopObject, NULL);
991
992 /* Initialize some local (to win32k) desktop state. */
993 DesktopObject->ActiveMessageQueue = NULL;
994 ExFreePool(DesktopName.Buffer);
995
996 if (! NT_SUCCESS(Status))
997 {
998 DPRINT1("Failed to create desktop handle\n");
999 SetLastNtError(Status);
1000 RETURN( NULL);
1001 }
1002
1003 /*
1004 * Create a handle for CSRSS and notify CSRSS
1005 */
1006 Request.Type = MAKE_CSR_API(CREATE_DESKTOP, CSR_GUI);
1007 Status = CsrInsertObject(Desktop,
1008 GENERIC_ALL,
1009 (HANDLE*)&Request.Data.CreateDesktopRequest.DesktopHandle);
1010 if (! NT_SUCCESS(Status))
1011 {
1012 DPRINT1("Failed to create desktop handle for CSRSS\n");
1013 ZwClose(Desktop);
1014 SetLastNtError(Status);
1015 RETURN( NULL);
1016 }
1017
1018 Status = co_CsrNotify(&Request);
1019 if (! NT_SUCCESS(Status))
1020 {
1021 CsrCloseHandle(Request.Data.CreateDesktopRequest.DesktopHandle);
1022 DPRINT1("Failed to notify CSRSS about new desktop\n");
1023 ZwClose(Desktop);
1024 SetLastNtError(Status);
1025 RETURN( NULL);
1026 }
1027
1028 RETURN( Desktop);
1029
1030 CLEANUP:
1031 DPRINT("Leave NtUserCreateDesktop, ret=%i\n",_ret_);
1032 UserLeave();
1033 END_CLEANUP;
1034 }
1035
1036 /*
1037 * NtUserOpenDesktop
1038 *
1039 * Opens an existing desktop.
1040 *
1041 * Parameters
1042 * lpszDesktopName
1043 * Name of the existing desktop.
1044 *
1045 * dwFlags
1046 * Interaction flags.
1047 *
1048 * dwDesiredAccess
1049 * Requested type of access.
1050 *
1051 * Return Value
1052 * Handle to the desktop or zero on failure.
1053 *
1054 * Status
1055 * @implemented
1056 */
1057
1058 HDESK STDCALL
1059 NtUserOpenDesktop(
1060 PUNICODE_STRING lpszDesktopName,
1061 DWORD dwFlags,
1062 ACCESS_MASK dwDesiredAccess)
1063 {
1064 OBJECT_ATTRIBUTES ObjectAttributes;
1065 HWINSTA WinSta;
1066 PWINSTATION_OBJECT WinStaObject;
1067 UNICODE_STRING DesktopName;
1068 UNICODE_STRING SafeDesktopName;
1069 NTSTATUS Status;
1070 HDESK Desktop;
1071 DECLARE_RETURN(HDESK);
1072
1073 DPRINT("Enter NtUserOpenDesktop: %wZ\n", lpszDesktopName);
1074 UserEnterExclusive();
1075
1076 /*
1077 * Validate the window station handle and compose the fully
1078 * qualified desktop name
1079 */
1080
1081 WinSta = UserGetProcessWindowStation();
1082 Status = IntValidateWindowStationHandle(
1083 WinSta,
1084 KernelMode,
1085 0,
1086 &WinStaObject);
1087
1088 if (!NT_SUCCESS(Status))
1089 {
1090 DPRINT1("Failed validation of window station handle (0x%X)\n", WinSta);
1091 SetLastNtError(Status);
1092 RETURN( 0);
1093 }
1094
1095 if(lpszDesktopName != NULL)
1096 {
1097 Status = IntSafeCopyUnicodeString(&SafeDesktopName, lpszDesktopName);
1098 if(!NT_SUCCESS(Status))
1099 {
1100 SetLastNtError(Status);
1101 RETURN( NULL);
1102 }
1103 }
1104 else
1105 {
1106 RtlInitUnicodeString(&SafeDesktopName, NULL);
1107 }
1108
1109 if (!IntGetFullWindowStationName(&DesktopName, &WinStaObject->Name,
1110 lpszDesktopName))
1111 {
1112 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
1113 ObDereferenceObject(WinStaObject);
1114 RtlFreeUnicodeString(&SafeDesktopName);
1115 RETURN( 0);
1116 }
1117
1118 RtlFreeUnicodeString(&SafeDesktopName);
1119 ObDereferenceObject(WinStaObject);
1120
1121 DPRINT("Trying to open desktop (%wZ)\n", &DesktopName);
1122
1123 /* Initialize ObjectAttributes for the desktop object */
1124 InitializeObjectAttributes(
1125 &ObjectAttributes,
1126 &DesktopName,
1127 0,
1128 NULL,
1129 NULL);
1130
1131 Status = ObOpenObjectByName(
1132 &ObjectAttributes,
1133 ExDesktopObjectType,
1134 KernelMode,
1135 NULL,
1136 dwDesiredAccess,
1137 NULL,
1138 (HANDLE*)&Desktop);
1139
1140 if (!NT_SUCCESS(Status))
1141 {
1142 SetLastNtError(Status);
1143 ExFreePool(DesktopName.Buffer);
1144 RETURN( 0);
1145 }
1146
1147 DPRINT("Successfully opened desktop (%wZ)\n", &DesktopName);
1148 ExFreePool(DesktopName.Buffer);
1149
1150 RETURN( Desktop);
1151
1152 CLEANUP:
1153 DPRINT("Leave NtUserOpenDesktop, ret=%i\n",_ret_);
1154 UserLeave();
1155 END_CLEANUP;
1156 }
1157
1158 /*
1159 * NtUserOpenInputDesktop
1160 *
1161 * Opens the input (interactive) desktop.
1162 *
1163 * Parameters
1164 * dwFlags
1165 * Interaction flags.
1166 *
1167 * fInherit
1168 * Inheritance option.
1169 *
1170 * dwDesiredAccess
1171 * Requested type of access.
1172 *
1173 * Return Value
1174 * Handle to the input desktop or zero on failure.
1175 *
1176 * Status
1177 * @implemented
1178 */
1179
1180 HDESK STDCALL
1181 NtUserOpenInputDesktop(
1182 DWORD dwFlags,
1183 BOOL fInherit,
1184 ACCESS_MASK dwDesiredAccess)
1185 {
1186 PDESKTOP_OBJECT Object;
1187 NTSTATUS Status;
1188 HDESK Desktop;
1189 DECLARE_RETURN(HDESK);
1190
1191 DPRINT("Enter NtUserOpenInputDesktop\n");
1192 UserEnterExclusive();
1193
1194 DPRINT("About to open input desktop\n");
1195
1196 /* Get a pointer to the desktop object */
1197
1198 Status = IntValidateDesktopHandle(
1199 InputDesktopHandle,
1200 UserMode,
1201 0,
1202 &Object);
1203
1204 if (!NT_SUCCESS(Status))
1205 {
1206 DPRINT("Validation of input desktop handle (0x%X) failed\n", InputDesktop);
1207 RETURN((HDESK)0);
1208 }
1209
1210 /* Create a new handle to the object */
1211
1212 Status = ObOpenObjectByPointer(
1213 Object,
1214 0,
1215 NULL,
1216 dwDesiredAccess,
1217 ExDesktopObjectType,
1218 UserMode,
1219 (HANDLE*)&Desktop);
1220
1221 ObDereferenceObject(Object);
1222
1223 if (NT_SUCCESS(Status))
1224 {
1225 DPRINT("Successfully opened input desktop\n");
1226 RETURN((HDESK)Desktop);
1227 }
1228
1229 SetLastNtError(Status);
1230 RETURN((HDESK)0);
1231
1232 CLEANUP:
1233 DPRINT("Leave NtUserOpenInputDesktop, ret=%i\n",_ret_);
1234 UserLeave();
1235 END_CLEANUP;
1236 }
1237
1238 /*
1239 * NtUserCloseDesktop
1240 *
1241 * Closes a desktop handle.
1242 *
1243 * Parameters
1244 * hDesktop
1245 * Handle to the desktop.
1246 *
1247 * Return Value
1248 * Status
1249 *
1250 * Remarks
1251 * The desktop handle can be created with NtUserCreateDesktop or
1252 * NtUserOpenDesktop. This function will fail if any thread in the calling
1253 * process is using the specified desktop handle or if the handle refers
1254 * to the initial desktop of the calling process.
1255 *
1256 * Status
1257 * @implemented
1258 */
1259
1260 BOOL STDCALL
1261 NtUserCloseDesktop(HDESK hDesktop)
1262 {
1263 PDESKTOP_OBJECT Object;
1264 NTSTATUS Status;
1265 DECLARE_RETURN(BOOL);
1266
1267 DPRINT("Enter NtUserCloseDesktop\n");
1268 UserEnterExclusive();
1269
1270 DPRINT("About to close desktop handle (0x%X)\n", hDesktop);
1271
1272 Status = IntValidateDesktopHandle(
1273 hDesktop,
1274 UserMode,
1275 0,
1276 &Object);
1277
1278 if (!NT_SUCCESS(Status))
1279 {
1280 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
1281 RETURN(FALSE);
1282 }
1283
1284 ObDereferenceObject(Object);
1285
1286 DPRINT("Closing desktop handle (0x%X)\n", hDesktop);
1287
1288 Status = ZwClose(hDesktop);
1289 if (!NT_SUCCESS(Status))
1290 {
1291 SetLastNtError(Status);
1292 RETURN(FALSE);
1293 }
1294
1295 RETURN(TRUE);
1296
1297 CLEANUP:
1298 DPRINT("Leave NtUserCloseDesktop, ret=%i\n",_ret_);
1299 UserLeave();
1300 END_CLEANUP;
1301 }
1302
1303
1304
1305
1306 /*
1307 * NtUserPaintDesktop
1308 *
1309 * The NtUserPaintDesktop function fills the clipping region in the
1310 * specified device context with the desktop pattern or wallpaper. The
1311 * function is provided primarily for shell desktops.
1312 *
1313 * Parameters
1314 * hDC
1315 * Handle to the device context.
1316 *
1317 * Status
1318 * @implemented
1319 */
1320
1321 BOOL STDCALL
1322 NtUserPaintDesktop(HDC hDC)
1323 {
1324 RECT Rect;
1325 HBRUSH DesktopBrush, PreviousBrush;
1326 HWND hWndDesktop;
1327 BOOL doPatBlt = TRUE;
1328 PWINDOW_OBJECT WndDesktop;
1329 int len;
1330 COLORREF color_old;
1331 UINT align_old;
1332 int mode_old;
1333 PWINSTATION_OBJECT WinSta = PsGetCurrentThreadWin32Thread()->Desktop->WindowStation;
1334 DECLARE_RETURN(BOOL);
1335
1336 UserEnterExclusive();
1337 DPRINT("Enter NtUserPaintDesktop\n");
1338
1339
1340 IntGdiGetClipBox(hDC, &Rect);
1341
1342 hWndDesktop = IntGetDesktopWindow();
1343
1344 WndDesktop = UserGetWindowObject(hWndDesktop);
1345 if (!WndDesktop)
1346 {
1347 RETURN(FALSE);
1348 }
1349
1350 DesktopBrush = (HBRUSH)UserGetClassLongPtr(WndDesktop->Class, GCL_HBRBACKGROUND, FALSE);
1351
1352
1353 /*
1354 * Paint desktop background
1355 */
1356
1357 if (WinSta->hbmWallpaper != NULL)
1358 {
1359 PWINDOW_OBJECT DeskWin;
1360
1361 DeskWin = UserGetWindowObject(hWndDesktop);
1362
1363 if (DeskWin)
1364 {
1365 SIZE sz;
1366 int x, y;
1367 HDC hWallpaperDC;
1368
1369 sz.cx = DeskWin->WindowRect.right - DeskWin->WindowRect.left;
1370 sz.cy = DeskWin->WindowRect.bottom - DeskWin->WindowRect.top;
1371
1372 if (WinSta->WallpaperMode == wmStretch ||
1373 WinSta->WallpaperMode == wmTile)
1374 {
1375 x = 0;
1376 y = 0;
1377 }
1378 else
1379 {
1380 /* Find the upper left corner, can be negtive if the bitmap is bigger then the screen */
1381 x = (sz.cx / 2) - (WinSta->cxWallpaper / 2);
1382 y = (sz.cy / 2) - (WinSta->cyWallpaper / 2);
1383 }
1384
1385 hWallpaperDC = NtGdiCreateCompatibleDC(hDC);
1386 if(hWallpaperDC != NULL)
1387 {
1388 HBITMAP hOldBitmap;
1389
1390 /* fill in the area that the bitmap is not going to cover */
1391 if (x > 0 || y > 0)
1392 {
1393 /* FIXME - clip out the bitmap
1394 can be replaced with "NtGdiPatBlt(hDC, x, y, WinSta->cxWallpaper, WinSta->cyWallpaper, PATCOPY | DSTINVERT);"
1395 once we support DSTINVERT */
1396 PreviousBrush = NtGdiSelectObject(hDC, DesktopBrush);
1397 NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right, Rect.bottom, PATCOPY);
1398 NtGdiSelectObject(hDC, PreviousBrush);
1399 }
1400
1401 /*Do not fill the background after it is painted no matter the size of the picture */
1402 doPatBlt = FALSE;
1403
1404 hOldBitmap = NtGdiSelectObject(hWallpaperDC, WinSta->hbmWallpaper);
1405
1406 if (WinSta->WallpaperMode == wmStretch)
1407 {
1408 if(Rect.right && Rect.bottom)
1409 NtGdiStretchBlt(hDC,
1410 x,
1411 y,
1412 sz.cx,
1413 sz.cy,
1414 hWallpaperDC,
1415 0,
1416 0,
1417 WinSta->cxWallpaper,
1418 WinSta->cyWallpaper,
1419 SRCCOPY,
1420 0);
1421
1422 }
1423 else if (WinSta->WallpaperMode == wmTile)
1424 {
1425 /* paint the bitmap across the screen then down */
1426 for(y = 0; y < Rect.bottom; y += WinSta->cyWallpaper)
1427 {
1428 for(x = 0; x < Rect.right; x += WinSta->cxWallpaper)
1429 {
1430 NtGdiBitBlt(hDC,
1431 x,
1432 y,
1433 WinSta->cxWallpaper,
1434 WinSta->cyWallpaper,
1435 hWallpaperDC,
1436 0,
1437 0,
1438 SRCCOPY,
1439 0,
1440 0);
1441 }
1442 }
1443 }
1444 else
1445 {
1446 NtGdiBitBlt(hDC,
1447 x,
1448 y,
1449 WinSta->cxWallpaper,
1450 WinSta->cyWallpaper,
1451 hWallpaperDC,
1452 0,
1453 0,
1454 SRCCOPY,
1455 0,
1456 0);
1457 }
1458 NtGdiSelectObject(hWallpaperDC, hOldBitmap);
1459 NtGdiDeleteObjectApp(hWallpaperDC);
1460 }
1461 }
1462 }
1463
1464 /* Back ground is set to none, clear the screen */
1465 if (doPatBlt)
1466 {
1467 PreviousBrush = NtGdiSelectObject(hDC, DesktopBrush);
1468 NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right, Rect.bottom, PATCOPY);
1469 NtGdiSelectObject(hDC, PreviousBrush);
1470 }
1471
1472 /*
1473 * Display system version on the desktop background
1474 */
1475
1476 if (g_PaintDesktopVersion)
1477 {
1478 static WCHAR s_wszVersion[256] = {0};
1479 RECT rect;
1480
1481 if (*s_wszVersion)
1482 {
1483 len = wcslen(s_wszVersion);
1484 }
1485 else
1486 {
1487 len = GetSystemVersionString(s_wszVersion);
1488 }
1489
1490 if (len)
1491 {
1492 if (!UserSystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0))
1493 {
1494 rect.right = UserGetSystemMetrics(SM_CXSCREEN);
1495 rect.bottom = UserGetSystemMetrics(SM_CYSCREEN);
1496 }
1497
1498 color_old = NtGdiSetTextColor(hDC, RGB(255,255,255));
1499 align_old = NtGdiSetTextAlign(hDC, TA_RIGHT);
1500 mode_old = NtGdiSetBkMode(hDC, TRANSPARENT);
1501
1502 NtGdiTextOut(hDC, rect.right-16, rect.bottom-48, s_wszVersion, len);
1503
1504 NtGdiSetBkMode(hDC, mode_old);
1505 NtGdiSetTextAlign(hDC, align_old);
1506 NtGdiSetTextColor(hDC, color_old);
1507 }
1508 }
1509
1510 RETURN(TRUE);
1511
1512 CLEANUP:
1513 DPRINT("Leave NtUserPaintDesktop, ret=%i\n",_ret_);
1514 UserLeave();
1515 END_CLEANUP;
1516 }
1517
1518
1519 /*
1520 * NtUserSwitchDesktop
1521 *
1522 * Sets the current input (interactive) desktop.
1523 *
1524 * Parameters
1525 * hDesktop
1526 * Handle to desktop.
1527 *
1528 * Return Value
1529 * Status
1530 *
1531 * Status
1532 * @unimplemented
1533 */
1534
1535 BOOL STDCALL
1536 NtUserSwitchDesktop(HDESK hDesktop)
1537 {
1538 PDESKTOP_OBJECT DesktopObject;
1539 NTSTATUS Status;
1540 DECLARE_RETURN(BOOL);
1541
1542 UserEnterExclusive();
1543 DPRINT("Enter NtUserSwitchDesktop\n");
1544
1545 DPRINT("About to switch desktop (0x%X)\n", hDesktop);
1546
1547 Status = IntValidateDesktopHandle(
1548 hDesktop,
1549 UserMode,
1550 0,
1551 &DesktopObject);
1552
1553 if (!NT_SUCCESS(Status))
1554 {
1555 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
1556 RETURN(FALSE);
1557 }
1558
1559 /*
1560 * Don't allow applications switch the desktop if it's locked, unless the caller
1561 * is the logon application itself
1562 */
1563 if((DesktopObject->WindowStation->Flags & WSS_LOCKED) &&
1564 LogonProcess != NULL && LogonProcess != PsGetCurrentProcessWin32Process())
1565 {
1566 ObDereferenceObject(DesktopObject);
1567 DPRINT1("Switching desktop 0x%x denied because the work station is locked!\n", hDesktop);
1568 RETURN(FALSE);
1569 }
1570
1571 /* FIXME: Fail if the desktop belong to an invisible window station */
1572 /* FIXME: Fail if the process is associated with a secured
1573 desktop such as Winlogon or Screen-Saver */
1574 /* FIXME: Connect to input device */
1575
1576 /* Set the active desktop in the desktop's window station. */
1577 DesktopObject->WindowStation->ActiveDesktop = DesktopObject;
1578
1579 /* Set the global state. */
1580 InputDesktop = DesktopObject;
1581 InputDesktopHandle = hDesktop;
1582 InputWindowStation = DesktopObject->WindowStation;
1583
1584 ObDereferenceObject(DesktopObject);
1585
1586 RETURN(TRUE);
1587
1588 CLEANUP:
1589 DPRINT("Leave NtUserSwitchDesktop, ret=%i\n",_ret_);
1590 UserLeave();
1591 END_CLEANUP;
1592 }
1593
1594 /*
1595 * NtUserResolveDesktopForWOW
1596 *
1597 * Status
1598 * @unimplemented
1599 */
1600
1601 DWORD STDCALL
1602 NtUserResolveDesktopForWOW(DWORD Unknown0)
1603 {
1604 UNIMPLEMENTED
1605 return 0;
1606 }
1607
1608 /*
1609 * NtUserGetThreadDesktop
1610 *
1611 * Status
1612 * @implemented
1613 */
1614
1615 HDESK STDCALL
1616 NtUserGetThreadDesktop(DWORD dwThreadId, DWORD Unknown1)
1617 {
1618 NTSTATUS Status;
1619 PETHREAD Thread;
1620 PDESKTOP_OBJECT DesktopObject;
1621 HDESK Ret, hThreadDesktop;
1622 OBJECT_HANDLE_INFORMATION HandleInformation;
1623 DECLARE_RETURN(HDESK);
1624
1625 UserEnterExclusive();
1626 DPRINT("Enter NtUserGetThreadDesktop\n");
1627
1628 if(!dwThreadId)
1629 {
1630 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1631 RETURN(0);
1632 }
1633
1634 Status = PsLookupThreadByThreadId((HANDLE)dwThreadId, &Thread);
1635 if(!NT_SUCCESS(Status))
1636 {
1637 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1638 RETURN(0);
1639 }
1640
1641 if(Thread->ThreadsProcess == PsGetCurrentProcess())
1642 {
1643 /* just return the handle, we queried the desktop handle of a thread running
1644 in the same context */
1645 Ret = ((PW32THREAD)Thread->Tcb.Win32Thread)->hDesktop;
1646 ObDereferenceObject(Thread);
1647 RETURN(Ret);
1648 }
1649
1650 /* get the desktop handle and the desktop of the thread */
1651 if(!(hThreadDesktop = ((PW32THREAD)Thread->Tcb.Win32Thread)->hDesktop) ||
1652 !(DesktopObject = ((PW32THREAD)Thread->Tcb.Win32Thread)->Desktop))
1653 {
1654 ObDereferenceObject(Thread);
1655 DPRINT1("Desktop information of thread 0x%x broken!?\n", dwThreadId);
1656 RETURN(NULL);
1657 }
1658
1659 /* we could just use DesktopObject instead of looking up the handle, but latter
1660 may be a bit safer (e.g. when the desktop is being destroyed */
1661 /* switch into the context of the thread we're trying to get the desktop from,
1662 so we can use the handle */
1663 KeAttachProcess(&Thread->ThreadsProcess->Pcb);
1664 Status = ObReferenceObjectByHandle(hThreadDesktop,
1665 GENERIC_ALL,
1666 ExDesktopObjectType,
1667 UserMode,
1668 (PVOID*)&DesktopObject,
1669 &HandleInformation);
1670 KeDetachProcess();
1671
1672 /* the handle couldn't be found, there's nothing to get... */
1673 if(!NT_SUCCESS(Status))
1674 {
1675 ObDereferenceObject(Thread);
1676 RETURN(NULL);
1677 }
1678
1679 /* lookup our handle table if we can find a handle to the desktop object,
1680 if not, create one */
1681 Ret = IntGetDesktopObjectHandle(DesktopObject);
1682
1683 /* all done, we got a valid handle to the desktop */
1684 ObDereferenceObject(DesktopObject);
1685 ObDereferenceObject(Thread);
1686 RETURN(Ret);
1687
1688 CLEANUP:
1689 DPRINT("Leave NtUserGetThreadDesktop, ret=%i\n",_ret_);
1690 UserLeave();
1691 END_CLEANUP;
1692 }
1693
1694 static NTSTATUS
1695 IntUnmapDesktopView(IN PDESKTOP_OBJECT DesktopObject)
1696 {
1697 PW32THREADINFO ti;
1698 PW32HEAP_USER_MAPPING HeapMapping, *PrevLink = &PsGetCurrentProcessWin32Process()->HeapMappings.Next;
1699 NTSTATUS Status = STATUS_SUCCESS;
1700
1701 TRACE("DO %p\n");
1702
1703 /* unmap if we're the last thread using the desktop */
1704 HeapMapping = *PrevLink;
1705 while (HeapMapping != NULL)
1706 {
1707 if (HeapMapping->KernelMapping == (PVOID)DesktopObject->hDesktopHeap)
1708 {
1709 if (--HeapMapping->Count == 0)
1710 {
1711 *PrevLink = HeapMapping->Next;
1712
1713 Status = MmUnmapViewOfSection(PsGetCurrentProcess(),
1714 HeapMapping->UserMapping);
1715
1716 ObDereferenceObject(DesktopObject);
1717
1718 UserHeapFree(HeapMapping);
1719 break;
1720 }
1721 }
1722
1723 PrevLink = &HeapMapping->Next;
1724 HeapMapping = HeapMapping->Next;
1725 }
1726
1727 ti = GetW32ThreadInfo();
1728 if (ti != NULL)
1729 {
1730 if (ti->Desktop == DesktopObject->DesktopInfo)
1731 {
1732 ti->Desktop = NULL;
1733 ti->DesktopHeapDelta = 0;
1734 }
1735 }
1736
1737 return Status;
1738 }
1739
1740 static NTSTATUS
1741 IntMapDesktopView(IN PDESKTOP_OBJECT DesktopObject)
1742 {
1743 PW32THREADINFO ti;
1744 PW32HEAP_USER_MAPPING HeapMapping, *PrevLink = &PsGetCurrentProcessWin32Process()->HeapMappings.Next;
1745 PVOID UserBase = NULL;
1746 ULONG ViewSize = 0;
1747 LARGE_INTEGER Offset;
1748 NTSTATUS Status;
1749
1750 /* find out if another thread already mapped the desktop heap */
1751 HeapMapping = *PrevLink;
1752 while (HeapMapping != NULL)
1753 {
1754 if (HeapMapping->KernelMapping == (PVOID)DesktopObject->hDesktopHeap)
1755 {
1756 HeapMapping->Count++;
1757 return STATUS_SUCCESS;
1758 }
1759
1760 PrevLink = &HeapMapping->Next;
1761 HeapMapping = HeapMapping->Next;
1762 }
1763
1764 /* we're the first, map the heap */
1765 DPRINT("Noone mapped the desktop heap %p yet, so - map it!\n", DesktopObject->hDesktopHeap);
1766 Offset.QuadPart = 0;
1767 Status = MmMapViewOfSection(DesktopObject->DesktopHeapSection,
1768 PsGetCurrentProcess(),
1769 &UserBase,
1770 0,
1771 0,
1772 &Offset,
1773 &ViewSize,
1774 ViewUnmap,
1775 SEC_NO_CHANGE,
1776 PAGE_EXECUTE_READ); /* would prefer PAGE_READONLY, but thanks to RTL heaps... */
1777 if (!NT_SUCCESS(Status))
1778 {
1779 DPRINT1("Failed to map desktop\n");
1780 return Status;
1781 }
1782
1783 /* add the mapping */
1784 HeapMapping = UserHeapAlloc(sizeof(W32HEAP_USER_MAPPING));
1785 if (HeapMapping == NULL)
1786 {
1787 MmUnmapViewOfSection(PsGetCurrentProcess(),
1788 UserBase);
1789 DPRINT1("UserHeapAlloc() failed!\n");
1790 return STATUS_NO_MEMORY;
1791 }
1792
1793 HeapMapping->Next = NULL;
1794 HeapMapping->KernelMapping = (PVOID)DesktopObject->hDesktopHeap;
1795 HeapMapping->UserMapping = UserBase;
1796 HeapMapping->Count = 1;
1797 *PrevLink = HeapMapping;
1798
1799 ObReferenceObject(DesktopObject);
1800
1801 /* create a W32THREADINFO structure if not already done, or update it */
1802 ti = GetW32ThreadInfo();
1803 if (ti != NULL)
1804 {
1805 if (ti->Desktop == NULL)
1806 {
1807 ti->Desktop = DesktopObject->DesktopInfo;
1808 ti->DesktopHeapDelta = DesktopHeapGetUserDelta();
1809 }
1810 }
1811
1812 return STATUS_SUCCESS;
1813 }
1814
1815 BOOL
1816 IntSetThreadDesktop(IN PDESKTOP_OBJECT DesktopObject,
1817 IN BOOL FreeOnFailure)
1818 {
1819 PDESKTOP_OBJECT OldDesktop;
1820 PW32THREAD W32Thread;
1821 NTSTATUS Status;
1822 BOOL MapHeap;
1823
1824 DPRINT("IntSetThreadDesktop() DO=%p, FOF=%d\n", DesktopObject, FreeOnFailure);
1825 MapHeap = (PsGetCurrentProcess() != PsInitialSystemProcess);
1826 W32Thread = PsGetCurrentThreadWin32Thread();
1827
1828 if (W32Thread->Desktop != DesktopObject)
1829 {
1830 OldDesktop = W32Thread->Desktop;
1831
1832 if (!IsListEmpty(&W32Thread->WindowListHead))
1833 {
1834 DPRINT1("Attempted to change thread desktop although the thread has windows!\n");
1835 SetLastWin32Error(ERROR_BUSY);
1836 return FALSE;
1837 }
1838
1839 W32Thread->Desktop = DesktopObject;
1840
1841 if (MapHeap && DesktopObject != NULL)
1842 {
1843 Status = IntMapDesktopView(DesktopObject);
1844 if (!NT_SUCCESS(Status))
1845 {
1846 SetLastNtError(Status);
1847 return FALSE;
1848 }
1849 }
1850
1851 if (OldDesktop != NULL &&
1852 !IntCheckProcessDesktopClasses(OldDesktop->DesktopInfo,
1853 FreeOnFailure))
1854 {
1855 DPRINT1("Failed to move process classes to shared heap!\n");
1856
1857 /* failed to move desktop classes to the shared heap,
1858 unmap the view and return the error */
1859 if (MapHeap && DesktopObject != NULL)
1860 IntUnmapDesktopView(DesktopObject);
1861
1862 return FALSE;
1863 }
1864
1865 if (DesktopObject != NULL)
1866 {
1867 ObReferenceObject(DesktopObject);
1868 }
1869
1870 if (OldDesktop != NULL)
1871 {
1872 if (MapHeap)
1873 {
1874 IntUnmapDesktopView(OldDesktop);
1875 }
1876
1877 ObDereferenceObject(OldDesktop);
1878
1879 /* update the thread info */
1880 if (W32Thread != NULL && W32Thread->ThreadInfo != NULL &&
1881 W32Thread->ThreadInfo->Desktop != (DesktopObject != NULL ? DesktopObject->DesktopInfo : NULL))
1882 {
1883 if (DesktopObject != NULL)
1884 {
1885 W32Thread->ThreadInfo->Desktop = DesktopObject->DesktopInfo;
1886 W32Thread->ThreadInfo->DesktopHeapDelta = DesktopHeapGetUserDelta();
1887 }
1888 else
1889 {
1890 W32Thread->ThreadInfo->Desktop = NULL;
1891 W32Thread->ThreadInfo->DesktopHeapDelta = 0;
1892 }
1893 }
1894 }
1895 }
1896
1897 return TRUE;
1898 }
1899
1900 /*
1901 * NtUserSetThreadDesktop
1902 *
1903 * Status
1904 * @implemented
1905 */
1906
1907 BOOL STDCALL
1908 NtUserSetThreadDesktop(HDESK hDesktop)
1909 {
1910 PDESKTOP_OBJECT DesktopObject;
1911 NTSTATUS Status;
1912 DECLARE_RETURN(BOOL);
1913
1914 UserEnterExclusive();
1915 DPRINT("Enter NtUserSetThreadDesktop\n");
1916
1917 /* Validate the new desktop. */
1918 Status = IntValidateDesktopHandle(
1919 hDesktop,
1920 UserMode,
1921 0,
1922 &DesktopObject);
1923
1924 if (!NT_SUCCESS(Status))
1925 {
1926 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
1927 RETURN(FALSE);
1928 }
1929
1930 /* FIXME: Should check here to see if the thread has any windows. */
1931
1932 if (!IntSetThreadDesktop(DesktopObject,
1933 FALSE))
1934 {
1935 RETURN(FALSE);
1936 }
1937
1938 RETURN(TRUE);
1939
1940 CLEANUP:
1941 DPRINT("Leave NtUserSetThreadDesktop, ret=%i\n",_ret_);
1942 UserLeave();
1943 END_CLEANUP;
1944 }
1945
1946 /* EOF */