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