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