Sync with trunk (48237)
[reactos.git] / 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 <win32k.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 RtlZeroMemory(Desktop, sizeof(DESKTOP));
146 InitializeListHead(&Desktop->ShellHookWindows);
147 Desktop->rpwinstaParent = (PWINSTATION_OBJECT)ParseObject;
148
149 /* Put the desktop on the window station's list of associated desktops */
150 InsertTailList(&Desktop->rpwinstaParent->DesktopListHead,
151 &Desktop->ListEntry);
152
153 /* Set the desktop object and return success */
154 *Object = Desktop;
155 return STATUS_SUCCESS;
156 }
157
158 VOID APIENTRY
159 IntDesktopObjectDelete(PWIN32_DELETEMETHOD_PARAMETERS Parameters)
160 {
161 PDESKTOP Desktop = (PDESKTOP)Parameters->Object;
162
163 DPRINT("Deleting desktop (0x%X)\n", Desktop);
164
165 /* Remove the desktop from the window station's list of associcated desktops */
166 RemoveEntryList(&Desktop->ListEntry);
167
168 IntFreeDesktopHeap(Desktop);
169 }
170
171 /* PRIVATE FUNCTIONS **********************************************************/
172
173 NTSTATUS
174 FASTCALL
175 InitDesktopImpl(VOID)
176 {
177 /* Set Desktop Object Attributes */
178 ExDesktopObjectType->TypeInfo.DefaultNonPagedPoolCharge = sizeof(DESKTOP);
179 ExDesktopObjectType->TypeInfo.GenericMapping = IntDesktopMapping;
180 return STATUS_SUCCESS;
181 }
182
183 NTSTATUS
184 FASTCALL
185 CleanupDesktopImpl(VOID)
186 {
187 return STATUS_SUCCESS;
188 }
189
190 static int GetSystemVersionString(LPWSTR buffer)
191 {
192 RTL_OSVERSIONINFOEXW versionInfo;
193 int len;
194
195 versionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
196
197 if (!NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW)&versionInfo)))
198 return 0;
199
200 if (versionInfo.dwMajorVersion <= 4)
201 len = swprintf(buffer,
202 L"ReactOS Version %d.%d %s Build %d",
203 versionInfo.dwMajorVersion, versionInfo.dwMinorVersion,
204 versionInfo.szCSDVersion, versionInfo.dwBuildNumber&0xFFFF);
205 else
206 len = swprintf(buffer,
207 L"ReactOS %s (Build %d)",
208 versionInfo.szCSDVersion, versionInfo.dwBuildNumber&0xFFFF);
209
210 return len;
211 }
212
213
214 NTSTATUS FASTCALL
215 IntParseDesktopPath(PEPROCESS Process,
216 PUNICODE_STRING DesktopPath,
217 HWINSTA *hWinSta,
218 HDESK *hDesktop)
219 {
220 OBJECT_ATTRIBUTES ObjectAttributes;
221 UNICODE_STRING WinSta, Desktop, FullName;
222 BOOL DesktopPresent = FALSE;
223 BOOL WinStaPresent = FALSE;
224 NTSTATUS Status;
225
226 ASSERT(hWinSta);
227
228 *hWinSta = NULL;
229
230 if(hDesktop != NULL)
231 {
232 *hDesktop = NULL;
233 }
234
235 RtlInitUnicodeString(&WinSta, NULL);
236 RtlInitUnicodeString(&Desktop, NULL);
237
238 if(DesktopPath != NULL && DesktopPath->Buffer != NULL && DesktopPath->Length > sizeof(WCHAR))
239 {
240 PWCHAR c = DesktopPath->Buffer;
241 USHORT wl = 0;
242 USHORT l = DesktopPath->Length;
243
244 /*
245 * Parse the desktop path string which can be in the form "WinSta\Desktop"
246 * or just "Desktop". In latter case WinSta0 will be used.
247 */
248
249 while(l > 0)
250 {
251 if(*c == L'\\')
252 {
253 wl = (ULONG_PTR)c - (ULONG_PTR)DesktopPath->Buffer;
254 break;
255 }
256 l -= sizeof(WCHAR);
257 c++;
258 }
259
260 if(wl > 0)
261 {
262 WinSta.Length = wl;
263 WinSta.MaximumLength = wl + sizeof(WCHAR);
264 WinSta.Buffer = DesktopPath->Buffer;
265
266 WinStaPresent = TRUE;
267 c++;
268 }
269
270 Desktop.Length = DesktopPath->Length - wl;
271 if(wl > 0)
272 {
273 Desktop.Length -= sizeof(WCHAR);
274 }
275 if(Desktop.Length > 0)
276 {
277 Desktop.MaximumLength = Desktop.Length + sizeof(WCHAR);
278 Desktop.Buffer = ((wl > 0) ? c : DesktopPath->Buffer);
279 DesktopPresent = TRUE;
280 }
281 }
282
283 if(!WinStaPresent)
284 {
285 #if 0
286 /* search the process handle table for (inherited) window station
287 handles, use a more appropriate one than WinSta0 if possible. */
288 if (!ObFindHandleForObject(Process,
289 NULL,
290 ExWindowStationObjectType,
291 NULL,
292 (PHANDLE)hWinSta))
293 #endif
294 {
295 /* we had no luck searching for opened handles, use WinSta0 now */
296 RtlInitUnicodeString(&WinSta, L"WinSta0");
297 }
298 }
299
300 if(!DesktopPresent && hDesktop != NULL)
301 {
302 #if 0
303 /* search the process handle table for (inherited) desktop
304 handles, use a more appropriate one than Default if possible. */
305 if (!ObFindHandleForObject(Process,
306 NULL,
307 ExDesktopObjectType,
308 NULL,
309 (PHANDLE)hDesktop))
310 #endif
311 {
312 /* we had no luck searching for opened handles, use Desktop now */
313 RtlInitUnicodeString(&Desktop, L"Default");
314 }
315 }
316
317 if(*hWinSta == NULL)
318 {
319 if(!IntGetFullWindowStationName(&FullName, &WinSta, NULL))
320 {
321 return STATUS_INSUFFICIENT_RESOURCES;
322 }
323
324 /* open the window station */
325 InitializeObjectAttributes(&ObjectAttributes,
326 &FullName,
327 OBJ_CASE_INSENSITIVE,
328 NULL,
329 NULL);
330
331 Status = ObOpenObjectByName(&ObjectAttributes,
332 ExWindowStationObjectType,
333 KernelMode,
334 NULL,
335 0,
336 NULL,
337 (HANDLE*)hWinSta);
338
339 ExFreePoolWithTag(FullName.Buffer, TAG_STRING);
340
341 if(!NT_SUCCESS(Status))
342 {
343 SetLastNtError(Status);
344 DPRINT("Failed to reference window station %wZ PID: %d!\n", &WinSta, PsGetCurrentProcessId());
345 return Status;
346 }
347 }
348
349 if(hDesktop != NULL && *hDesktop == NULL)
350 {
351 if(!IntGetFullWindowStationName(&FullName, &WinSta, &Desktop))
352 {
353 NtClose(*hWinSta);
354 *hWinSta = NULL;
355 return STATUS_INSUFFICIENT_RESOURCES;
356 }
357
358 /* open the desktop object */
359 InitializeObjectAttributes(&ObjectAttributes,
360 &FullName,
361 OBJ_CASE_INSENSITIVE,
362 NULL,
363 NULL);
364
365 Status = ObOpenObjectByName(&ObjectAttributes,
366 ExDesktopObjectType,
367 KernelMode,
368 NULL,
369 0,
370 NULL,
371 (HANDLE*)hDesktop);
372
373 ExFreePoolWithTag(FullName.Buffer, TAG_STRING);
374
375 if(!NT_SUCCESS(Status))
376 {
377 *hDesktop = NULL;
378 NtClose(*hWinSta);
379 *hWinSta = NULL;
380 SetLastNtError(Status);
381 DPRINT("Failed to reference desktop %wZ PID: %d!\n", &Desktop, PsGetCurrentProcessId());
382 return Status;
383 }
384 }
385
386 return STATUS_SUCCESS;
387 }
388
389 /*
390 * IntValidateDesktopHandle
391 *
392 * Validates the desktop handle.
393 *
394 * Remarks
395 * If the function succeeds, the handle remains referenced. If the
396 * fucntion fails, last error is set.
397 */
398
399 NTSTATUS FASTCALL
400 IntValidateDesktopHandle(
401 HDESK Desktop,
402 KPROCESSOR_MODE AccessMode,
403 ACCESS_MASK DesiredAccess,
404 PDESKTOP *Object)
405 {
406 NTSTATUS Status;
407
408 Status = ObReferenceObjectByHandle(
409 Desktop,
410 DesiredAccess,
411 ExDesktopObjectType,
412 AccessMode,
413 (PVOID*)Object,
414 NULL);
415
416 if (!NT_SUCCESS(Status))
417 SetLastNtError(Status);
418
419 return Status;
420 }
421
422 PDESKTOP FASTCALL
423 IntGetActiveDesktop(VOID)
424 {
425 return InputDesktop;
426 }
427
428 /*
429 * returns or creates a handle to the desktop object
430 */
431 HDESK FASTCALL
432 IntGetDesktopObjectHandle(PDESKTOP DesktopObject)
433 {
434 NTSTATUS Status;
435 HDESK Ret;
436
437 ASSERT(DesktopObject);
438
439 if (!ObFindHandleForObject(PsGetCurrentProcess(),
440 DesktopObject,
441 ExDesktopObjectType,
442 NULL,
443 (PHANDLE)&Ret))
444 {
445 Status = ObOpenObjectByPointer(DesktopObject,
446 0,
447 NULL,
448 0,
449 ExDesktopObjectType,
450 UserMode,
451 (PHANDLE)&Ret);
452 if(!NT_SUCCESS(Status))
453 {
454 /* unable to create a handle */
455 DPRINT1("Unable to create a desktop handle\n");
456 return NULL;
457 }
458 }
459 else
460 {
461 DPRINT1("Got handle: %lx\n", Ret);
462 }
463
464 return Ret;
465 }
466
467 PUSER_MESSAGE_QUEUE FASTCALL
468 IntGetFocusMessageQueue(VOID)
469 {
470 PDESKTOP pdo = IntGetActiveDesktop();
471 if (!pdo)
472 {
473 DPRINT("No active desktop\n");
474 return(NULL);
475 }
476 return (PUSER_MESSAGE_QUEUE)pdo->ActiveMessageQueue;
477 }
478
479 VOID FASTCALL
480 IntSetFocusMessageQueue(PUSER_MESSAGE_QUEUE NewQueue)
481 {
482 PUSER_MESSAGE_QUEUE Old;
483 PDESKTOP pdo = IntGetActiveDesktop();
484 if (!pdo)
485 {
486 DPRINT("No active desktop\n");
487 return;
488 }
489 if(NewQueue != NULL)
490 {
491 if(NewQueue->Desktop != NULL)
492 {
493 DPRINT("Message Queue already attached to another desktop!\n");
494 return;
495 }
496 IntReferenceMessageQueue(NewQueue);
497 (void)InterlockedExchangePointer((PVOID*)&NewQueue->Desktop, pdo);
498 }
499 Old = (PUSER_MESSAGE_QUEUE)InterlockedExchangePointer((PVOID*)&pdo->ActiveMessageQueue, NewQueue);
500 if(Old != NULL)
501 {
502 (void)InterlockedExchangePointer((PVOID*)&Old->Desktop, 0);
503 IntDereferenceMessageQueue(Old);
504 }
505 }
506
507 HWND FASTCALL IntGetDesktopWindow(VOID)
508 {
509 PDESKTOP pdo = IntGetActiveDesktop();
510 if (!pdo)
511 {
512 DPRINT("No active desktop\n");
513 return NULL;
514 }
515 return pdo->DesktopWindow;
516 }
517
518 PWINDOW_OBJECT FASTCALL UserGetDesktopWindow(VOID)
519 {
520 PDESKTOP pdo = IntGetActiveDesktop();
521
522 if (!pdo)
523 {
524 DPRINT("No active desktop\n");
525 return NULL;
526 }
527
528 return UserGetWindowObject(pdo->DesktopWindow);
529 }
530
531 HWND FASTCALL IntGetMessageWindow(VOID)
532 {
533 PDESKTOP pdo = IntGetActiveDesktop();
534
535 if (!pdo)
536 {
537 DPRINT("No active desktop\n");
538 return NULL;
539 }
540 return pdo->spwndMessage->head.h;
541 }
542
543 HWND FASTCALL IntGetCurrentThreadDesktopWindow(VOID)
544 {
545 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
546 PDESKTOP pdo = pti->rpdesk;
547 if (NULL == pdo)
548 {
549 DPRINT1("Thread doesn't have a desktop\n");
550 return NULL;
551 }
552 return pdo->DesktopWindow;
553 }
554
555 BOOL FASTCALL IntDesktopUpdatePerUserSettings(BOOL bEnable)
556 {
557 if (bEnable)
558 {
559 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
560 NTSTATUS Status;
561
562 RtlZeroMemory(QueryTable, sizeof(QueryTable));
563
564 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
565 QueryTable[0].Name = L"PaintDesktopVersion";
566 QueryTable[0].EntryContext = &g_PaintDesktopVersion;
567
568 /* Query the "PaintDesktopVersion" flag in the "Control Panel\Desktop" key */
569 Status = RtlQueryRegistryValues(RTL_REGISTRY_USER,
570 L"Control Panel\\Desktop",
571 QueryTable, NULL, NULL);
572 if (!NT_SUCCESS(Status))
573 {
574 DPRINT1("RtlQueryRegistryValues failed for PaintDesktopVersion (%x)\n",
575 Status);
576 g_PaintDesktopVersion = FALSE;
577 return FALSE;
578 }
579
580 DPRINT("PaintDesktopVersion = %d\n", g_PaintDesktopVersion);
581
582 return TRUE;
583 }
584 else
585 {
586 g_PaintDesktopVersion = FALSE;
587 return TRUE;
588 }
589 }
590
591 /* PUBLIC FUNCTIONS ***********************************************************/
592
593 HDC FASTCALL
594 UserGetDesktopDC(ULONG DcType, BOOL EmptyDC, BOOL ValidatehWnd)
595 {
596 PWINDOW_OBJECT DesktopObject = 0;
597 HDC DesktopHDC = 0;
598
599 if (DcType == DC_TYPE_DIRECT)
600 {
601 DesktopObject = UserGetDesktopWindow();
602 DesktopHDC = (HDC)UserGetWindowDC(DesktopObject);
603 }
604 else
605 {
606 HDEV hDev;
607 hDev = (HDEV)pPrimarySurface;
608 DesktopHDC = IntGdiCreateDisplayDC(hDev, DcType, EmptyDC);
609 }
610
611 return DesktopHDC;
612 }
613
614 VOID APIENTRY
615 UserRedrawDesktop()
616 {
617 PWINDOW_OBJECT Window = NULL;
618
619 Window = UserGetDesktopWindow();
620
621 IntInvalidateWindows( Window,
622 Window->hrgnUpdate,
623 RDW_FRAME |
624 RDW_ERASE |
625 RDW_INVALIDATE |
626 RDW_ALLCHILDREN);
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 PWND 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 = ExAllocatePoolWithTag(PagedPool, sizeof(HWND) * (entries + 1), USERTAG_WINDOWLIST); /* 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->rpdesk;
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->rpdesk;
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->hsectionDesktop != NULL)
819 {
820 ObDereferenceObject(Desktop->hsectionDesktop);
821 Desktop->hsectionDesktop = NULL;
822 }
823 }
824 /* SYSCALLS *******************************************************************/
825
826 /*
827 * NtUserCreateDesktop
828 *
829 * Creates a new desktop.
830 *
831 * Parameters
832 * poaAttribs
833 * Object Attributes.
834 *
835 * lpszDesktopDevice
836 * Name of the device.
837 *
838 * pDeviceMode
839 * Device Mode.
840 *
841 * dwFlags
842 * Interaction flags.
843 *
844 * dwDesiredAccess
845 * Requested type of access.
846 *
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 POBJECT_ATTRIBUTES poa,
862 PUNICODE_STRING lpszDesktopDevice,
863 LPDEVMODEW lpdmw,
864 DWORD dwFlags,
865 ACCESS_MASK dwDesiredAccess)
866 {
867 OBJECT_ATTRIBUTES ObjectAttributes;
868 PTHREADINFO W32Thread;
869 PWINSTATION_OBJECT WinStaObject;
870 PDESKTOP DesktopObject;
871 UNICODE_STRING DesktopName;
872 NTSTATUS Status = STATUS_SUCCESS;
873 HDESK Desktop;
874 CSR_API_MESSAGE Request;
875 PVOID DesktopHeapSystemBase = NULL;
876 SIZE_T DesktopInfoSize;
877 UNICODE_STRING SafeDesktopName;
878 ULONG DummyContext;
879 ULONG_PTR HeapSize = 4 * 1024 * 1024; /* FIXME */
880 HWINSTA hWindowStation = NULL ;
881 PUNICODE_STRING lpszDesktopName = NULL;
882 UNICODE_STRING ClassName, MenuName;
883 LARGE_STRING WindowName;
884 PWND pWnd = NULL;
885 CREATESTRUCTW Cs;
886 DECLARE_RETURN(HDESK);
887
888 DPRINT("Enter NtUserCreateDesktop: %wZ\n", lpszDesktopName);
889 UserEnterExclusive();
890
891 _SEH2_TRY
892 {
893 ProbeForRead( poa,
894 sizeof(OBJECT_ATTRIBUTES),
895 1);
896
897 hWindowStation = poa->RootDirectory;
898 lpszDesktopName = poa->ObjectName;
899 }
900 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
901 {
902 Status =_SEH2_GetExceptionCode();
903 }
904 _SEH2_END
905
906 if (! NT_SUCCESS(Status))
907 {
908 DPRINT1("Failed reading Object Attributes from user space.\n");
909 SetLastNtError(Status);
910 RETURN( NULL);
911 }
912
913 Status = IntValidateWindowStationHandle(
914 hWindowStation,
915 KernelMode,
916 0, /* FIXME - WINSTA_CREATEDESKTOP */
917 &WinStaObject);
918
919 if (! NT_SUCCESS(Status))
920 {
921 DPRINT1("Failed validation of window station handle (0x%X), cannot create desktop %wZ\n",
922 hWindowStation, lpszDesktopName);
923 SetLastNtError(Status);
924 RETURN( NULL);
925 }
926 if(lpszDesktopName != NULL)
927 {
928 Status = IntSafeCopyUnicodeString(&SafeDesktopName, lpszDesktopName);
929 if(!NT_SUCCESS(Status))
930 {
931 SetLastNtError(Status);
932 RETURN( NULL);
933 }
934 }
935 else
936 {
937 RtlInitUnicodeString(&SafeDesktopName, NULL);
938 }
939
940 if (! IntGetFullWindowStationName(&DesktopName, &WinStaObject->Name,
941 &SafeDesktopName))
942 {
943 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
944 ObDereferenceObject(WinStaObject);
945 if (lpszDesktopName)
946 ExFreePoolWithTag(SafeDesktopName.Buffer, TAG_STRING);
947 RETURN( NULL);
948 }
949 if (lpszDesktopName)
950 ExFreePoolWithTag(SafeDesktopName.Buffer, TAG_STRING);
951 ObDereferenceObject(WinStaObject);
952
953 /*
954 * Try to open already existing desktop
955 */
956
957 DPRINT("Trying to open desktop (%wZ)\n", &DesktopName);
958
959 /* Initialize ObjectAttributes for the desktop object */
960 InitializeObjectAttributes(
961 &ObjectAttributes,
962 &DesktopName,
963 0,
964 NULL,
965 NULL);
966
967 Status = ObOpenObjectByName(
968 &ObjectAttributes,
969 ExDesktopObjectType,
970 KernelMode,
971 NULL,
972 dwDesiredAccess,
973 (PVOID)&DummyContext,
974 (HANDLE*)&Desktop);
975 if (!NT_SUCCESS(Status)) RETURN(NULL);
976 if (Status == STATUS_OBJECT_NAME_EXISTS)
977 {
978 ExFreePoolWithTag(DesktopName.Buffer, TAG_STRING);
979 RETURN( Desktop);
980 }
981
982 /* Reference the desktop */
983 Status = ObReferenceObjectByHandle(Desktop,
984 0,
985 ExDesktopObjectType,
986 KernelMode,
987 (PVOID)&DesktopObject,
988 NULL);
989 if (!NT_SUCCESS(Status)) RETURN(NULL);
990
991 DesktopObject->hsectionDesktop = NULL;
992 DesktopObject->pheapDesktop = UserCreateHeap(&DesktopObject->hsectionDesktop,
993 &DesktopHeapSystemBase,
994 HeapSize);
995 if (DesktopObject->pheapDesktop == NULL)
996 {
997 ObDereferenceObject(DesktopObject);
998 DPRINT1("Failed to create desktop heap!\n");
999 RETURN(NULL);
1000 }
1001
1002 DesktopInfoSize = FIELD_OFFSET(DESKTOPINFO,
1003 szDesktopName[(lpszDesktopName->Length / sizeof(WCHAR)) + 1]);
1004
1005 DesktopObject->pDeskInfo = RtlAllocateHeap(DesktopObject->pheapDesktop,
1006 HEAP_NO_SERIALIZE,
1007 DesktopInfoSize);
1008
1009 if (DesktopObject->pDeskInfo == NULL)
1010 {
1011 ObDereferenceObject(DesktopObject);
1012 DPRINT1("Failed to create the DESKTOP structure!\n");
1013 RETURN(NULL);
1014 }
1015
1016 RtlZeroMemory(DesktopObject->pDeskInfo,
1017 DesktopInfoSize);
1018
1019 DesktopObject->pDeskInfo->pvDesktopBase = DesktopHeapSystemBase;
1020 DesktopObject->pDeskInfo->pvDesktopLimit = (PVOID)((ULONG_PTR)DesktopHeapSystemBase + HeapSize);
1021 RtlCopyMemory(DesktopObject->pDeskInfo->szDesktopName,
1022 lpszDesktopName->Buffer,
1023 lpszDesktopName->Length);
1024
1025 /* Initialize some local (to win32k) desktop state. */
1026 InitializeListHead(&DesktopObject->PtiList);
1027 DesktopObject->ActiveMessageQueue = NULL;
1028 ExFreePoolWithTag(DesktopName.Buffer, TAG_STRING);
1029
1030 if (! NT_SUCCESS(Status))
1031 {
1032 DPRINT1("Failed to create desktop handle\n");
1033 SetLastNtError(Status);
1034 RETURN( NULL);
1035 }
1036
1037 /*
1038 * Create a handle for CSRSS and notify CSRSS for Creating Desktop Window.
1039 *
1040 * Honestly, I believe this is a cleverly written hack that allowed ReactOS
1041 * to function at the beginning of the project by ramroding the GUI into
1042 * operation and making the desktop window work from user space.
1043 * (jt)
1044 */
1045 Request.Type = MAKE_CSR_API(CREATE_DESKTOP, CSR_GUI);
1046 Status = CsrInsertObject(Desktop,
1047 GENERIC_ALL,
1048 (HANDLE*)&Request.Data.CreateDesktopRequest.DesktopHandle);
1049 if (! NT_SUCCESS(Status))
1050 {
1051 DPRINT1("Failed to create desktop handle for CSRSS\n");
1052 ZwClose(Desktop);
1053 SetLastNtError(Status);
1054 RETURN( NULL);
1055 }
1056
1057 Status = co_CsrNotify(&Request);
1058 if (! NT_SUCCESS(Status))
1059 {
1060 CsrCloseHandle(Request.Data.CreateDesktopRequest.DesktopHandle);
1061 DPRINT1("Failed to notify CSRSS about new desktop\n");
1062 ZwClose(Desktop);
1063 SetLastNtError(Status);
1064 RETURN( NULL);
1065 }
1066
1067 W32Thread = PsGetCurrentThreadWin32Thread();
1068
1069 if (!W32Thread->rpdesk) IntSetThreadDesktop(DesktopObject,FALSE);
1070
1071 /*
1072 Based on wine/server/window.c in get_desktop_window.
1073 */
1074
1075 ClassName.Buffer = ((PWSTR)((ULONG_PTR)(WORD)(gpsi->atomSysClass[ICLS_HWNDMESSAGE])));
1076 ClassName.Length = 0;
1077 RtlZeroMemory(&MenuName, sizeof(MenuName));
1078 RtlZeroMemory(&WindowName, sizeof(WindowName));
1079
1080 RtlZeroMemory(&Cs, sizeof(Cs));
1081 Cs.cx = Cs.cy = 100;
1082 Cs.style = WS_POPUP|WS_CLIPCHILDREN;
1083 Cs.hInstance = hModClient;
1084 Cs.lpszName = (LPCWSTR) &WindowName;
1085 Cs.lpszClass = (LPCWSTR) &ClassName;
1086
1087 pWnd = co_UserCreateWindowEx(&Cs, &ClassName, &WindowName);
1088 if (!pWnd)
1089 {
1090 DPRINT1("Failed to create Message window handle\n");
1091 }
1092 else
1093 {
1094 DesktopObject->spwndMessage = pWnd;
1095 }
1096
1097 RETURN( Desktop);
1098
1099 CLEANUP:
1100 DPRINT("Leave NtUserCreateDesktop, ret=%i\n",_ret_);
1101 UserLeave();
1102 END_CLEANUP;
1103 }
1104
1105 /*
1106 * NtUserOpenDesktop
1107 *
1108 * Opens an existing desktop.
1109 *
1110 * Parameters
1111 * lpszDesktopName
1112 * Name of the existing desktop.
1113 *
1114 * dwFlags
1115 * Interaction flags.
1116 *
1117 * dwDesiredAccess
1118 * Requested type of access.
1119 *
1120 * Return Value
1121 * Handle to the desktop or zero on failure.
1122 *
1123 * Status
1124 * @implemented
1125 */
1126
1127 HDESK APIENTRY
1128 NtUserOpenDesktop(
1129 PUNICODE_STRING lpszDesktopName,
1130 DWORD dwFlags,
1131 ACCESS_MASK dwDesiredAccess)
1132 {
1133 OBJECT_ATTRIBUTES ObjectAttributes;
1134 HWINSTA WinSta;
1135 PWINSTATION_OBJECT WinStaObject;
1136 UNICODE_STRING DesktopName;
1137 UNICODE_STRING SafeDesktopName;
1138 NTSTATUS Status;
1139 HDESK Desktop;
1140 BOOL Result;
1141 DECLARE_RETURN(HDESK);
1142
1143 DPRINT("Enter NtUserOpenDesktop: %wZ\n", lpszDesktopName);
1144 UserEnterExclusive();
1145
1146 /*
1147 * Validate the window station handle and compose the fully
1148 * qualified desktop name
1149 */
1150
1151 WinSta = UserGetProcessWindowStation();
1152 Status = IntValidateWindowStationHandle(
1153 WinSta,
1154 KernelMode,
1155 0,
1156 &WinStaObject);
1157
1158 if (!NT_SUCCESS(Status))
1159 {
1160 DPRINT1("Failed validation of window station handle (0x%X)\n", WinSta);
1161 SetLastNtError(Status);
1162 RETURN( 0);
1163 }
1164
1165 if(lpszDesktopName != NULL)
1166 {
1167 Status = IntSafeCopyUnicodeString(&SafeDesktopName, lpszDesktopName);
1168 if(!NT_SUCCESS(Status))
1169 {
1170 SetLastNtError(Status);
1171 RETURN( NULL);
1172 }
1173 }
1174 else
1175 {
1176 RtlInitUnicodeString(&SafeDesktopName, NULL);
1177 }
1178
1179 Result = IntGetFullWindowStationName(&DesktopName, &WinStaObject->Name,
1180 &SafeDesktopName);
1181
1182 if (lpszDesktopName)
1183 ExFreePoolWithTag(SafeDesktopName.Buffer, TAG_STRING);
1184 ObDereferenceObject(WinStaObject);
1185
1186
1187 if (!Result)
1188 {
1189 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
1190 RETURN( 0);
1191 }
1192
1193
1194 DPRINT("Trying to open desktop (%wZ)\n", &DesktopName);
1195
1196 /* Initialize ObjectAttributes for the desktop object */
1197 InitializeObjectAttributes(
1198 &ObjectAttributes,
1199 &DesktopName,
1200 0,
1201 NULL,
1202 NULL);
1203
1204 Status = ObOpenObjectByName(
1205 &ObjectAttributes,
1206 ExDesktopObjectType,
1207 KernelMode,
1208 NULL,
1209 dwDesiredAccess,
1210 NULL,
1211 (HANDLE*)&Desktop);
1212
1213 if (!NT_SUCCESS(Status))
1214 {
1215 SetLastNtError(Status);
1216 ExFreePool(DesktopName.Buffer);
1217 RETURN( 0);
1218 }
1219
1220 DPRINT("Successfully opened desktop (%wZ)\n", &DesktopName);
1221 ExFreePool(DesktopName.Buffer);
1222
1223 RETURN( Desktop);
1224
1225 CLEANUP:
1226 DPRINT("Leave NtUserOpenDesktop, ret=%i\n",_ret_);
1227 UserLeave();
1228 END_CLEANUP;
1229 }
1230
1231 /*
1232 * NtUserOpenInputDesktop
1233 *
1234 * Opens the input (interactive) desktop.
1235 *
1236 * Parameters
1237 * dwFlags
1238 * Interaction flags.
1239 *
1240 * fInherit
1241 * Inheritance option.
1242 *
1243 * dwDesiredAccess
1244 * Requested type of access.
1245 *
1246 * Return Value
1247 * Handle to the input desktop or zero on failure.
1248 *
1249 * Status
1250 * @implemented
1251 */
1252
1253 HDESK APIENTRY
1254 NtUserOpenInputDesktop(
1255 DWORD dwFlags,
1256 BOOL fInherit,
1257 ACCESS_MASK dwDesiredAccess)
1258 {
1259 PDESKTOP Object;
1260 NTSTATUS Status;
1261 HDESK Desktop;
1262 DECLARE_RETURN(HDESK);
1263
1264 DPRINT("Enter NtUserOpenInputDesktop\n");
1265 UserEnterExclusive();
1266
1267 DPRINT("About to open input desktop\n");
1268
1269 /* Get a pointer to the desktop object */
1270
1271 Status = IntValidateDesktopHandle(
1272 InputDesktopHandle,
1273 UserMode,
1274 0,
1275 &Object);
1276
1277 if (!NT_SUCCESS(Status))
1278 {
1279 DPRINT("Validation of input desktop handle (0x%X) failed\n", InputDesktop);
1280 RETURN((HDESK)0);
1281 }
1282
1283 /* Create a new handle to the object */
1284
1285 Status = ObOpenObjectByPointer(
1286 Object,
1287 0,
1288 NULL,
1289 dwDesiredAccess,
1290 ExDesktopObjectType,
1291 UserMode,
1292 (HANDLE*)&Desktop);
1293
1294 ObDereferenceObject(Object);
1295
1296 if (NT_SUCCESS(Status))
1297 {
1298 DPRINT("Successfully opened input desktop\n");
1299 RETURN((HDESK)Desktop);
1300 }
1301
1302 SetLastNtError(Status);
1303 RETURN((HDESK)0);
1304
1305 CLEANUP:
1306 DPRINT("Leave NtUserOpenInputDesktop, ret=%i\n",_ret_);
1307 UserLeave();
1308 END_CLEANUP;
1309 }
1310
1311 /*
1312 * NtUserCloseDesktop
1313 *
1314 * Closes a desktop handle.
1315 *
1316 * Parameters
1317 * hDesktop
1318 * Handle to the desktop.
1319 *
1320 * Return Value
1321 * Status
1322 *
1323 * Remarks
1324 * The desktop handle can be created with NtUserCreateDesktop or
1325 * NtUserOpenDesktop. This function will fail if any thread in the calling
1326 * process is using the specified desktop handle or if the handle refers
1327 * to the initial desktop of the calling process.
1328 *
1329 * Status
1330 * @implemented
1331 */
1332
1333 BOOL APIENTRY
1334 NtUserCloseDesktop(HDESK hDesktop)
1335 {
1336 PDESKTOP Object;
1337 NTSTATUS Status;
1338 DECLARE_RETURN(BOOL);
1339
1340 DPRINT("Enter NtUserCloseDesktop\n");
1341 UserEnterExclusive();
1342
1343 DPRINT("About to close desktop handle (0x%X)\n", hDesktop);
1344
1345 Status = IntValidateDesktopHandle(
1346 hDesktop,
1347 UserMode,
1348 0,
1349 &Object);
1350
1351 if (!NT_SUCCESS(Status))
1352 {
1353 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
1354 RETURN(FALSE);
1355 }
1356
1357 ObDereferenceObject(Object);
1358
1359 DPRINT("Closing desktop handle (0x%X)\n", hDesktop);
1360
1361 Status = ZwClose(hDesktop);
1362 if (!NT_SUCCESS(Status))
1363 {
1364 SetLastNtError(Status);
1365 RETURN(FALSE);
1366 }
1367
1368 RETURN(TRUE);
1369
1370 CLEANUP:
1371 DPRINT("Leave NtUserCloseDesktop, ret=%i\n",_ret_);
1372 UserLeave();
1373 END_CLEANUP;
1374 }
1375
1376
1377
1378
1379 /*
1380 * NtUserPaintDesktop
1381 *
1382 * The NtUserPaintDesktop function fills the clipping region in the
1383 * specified device context with the desktop pattern or wallpaper. The
1384 * function is provided primarily for shell desktops.
1385 *
1386 * Parameters
1387 * hDC
1388 * Handle to the device context.
1389 *
1390 * Status
1391 * @implemented
1392 */
1393
1394 BOOL APIENTRY
1395 NtUserPaintDesktop(HDC hDC)
1396 {
1397 RECTL Rect;
1398 HBRUSH DesktopBrush, PreviousBrush;
1399 HWND hWndDesktop;
1400 BOOL doPatBlt = TRUE;
1401 PWINDOW_OBJECT WndDesktop;
1402 int len;
1403 COLORREF color_old;
1404 UINT align_old;
1405 int mode_old;
1406 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1407 PWINSTATION_OBJECT WinSta = pti->rpdesk->rpwinstaParent;
1408 DECLARE_RETURN(BOOL);
1409
1410 UserEnterExclusive();
1411 DPRINT("Enter NtUserPaintDesktop\n");
1412
1413 GdiGetClipBox(hDC, &Rect);
1414
1415 hWndDesktop = IntGetDesktopWindow();
1416
1417 WndDesktop = UserGetWindowObject(hWndDesktop);
1418 if (!WndDesktop)
1419 {
1420 RETURN(FALSE);
1421 }
1422
1423 DesktopBrush = (HBRUSH)WndDesktop->Wnd->pcls->hbrBackground;
1424
1425
1426 /*
1427 * Paint desktop background
1428 */
1429
1430 if (WinSta->hbmWallpaper != NULL)
1431 {
1432 PWINDOW_OBJECT DeskWin;
1433
1434 DeskWin = UserGetWindowObject(hWndDesktop);
1435
1436 if (DeskWin)
1437 {
1438 SIZE sz;
1439 int x, y;
1440 HDC hWallpaperDC;
1441
1442 sz.cx = DeskWin->Wnd->rcWindow.right - DeskWin->Wnd->rcWindow.left;
1443 sz.cy = DeskWin->Wnd->rcWindow.bottom - DeskWin->Wnd->rcWindow.top;
1444
1445 if (WinSta->WallpaperMode == wmStretch ||
1446 WinSta->WallpaperMode == wmTile)
1447 {
1448 x = 0;
1449 y = 0;
1450 }
1451 else
1452 {
1453 /* Find the upper left corner, can be negtive if the bitmap is bigger then the screen */
1454 x = (sz.cx / 2) - (WinSta->cxWallpaper / 2);
1455 y = (sz.cy / 2) - (WinSta->cyWallpaper / 2);
1456 }
1457
1458 hWallpaperDC = NtGdiCreateCompatibleDC(hDC);
1459 if(hWallpaperDC != NULL)
1460 {
1461 HBITMAP hOldBitmap;
1462
1463 /* fill in the area that the bitmap is not going to cover */
1464 if (x > 0 || y > 0)
1465 {
1466 /* FIXME - clip out the bitmap
1467 can be replaced with "NtGdiPatBlt(hDC, x, y, WinSta->cxWallpaper, WinSta->cyWallpaper, PATCOPY | DSTINVERT);"
1468 once we support DSTINVERT */
1469 PreviousBrush = NtGdiSelectBrush(hDC, DesktopBrush);
1470 NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right, Rect.bottom, PATCOPY);
1471 NtGdiSelectBrush(hDC, PreviousBrush);
1472 }
1473
1474 /*Do not fill the background after it is painted no matter the size of the picture */
1475 doPatBlt = FALSE;
1476
1477 hOldBitmap = NtGdiSelectBitmap(hWallpaperDC, WinSta->hbmWallpaper);
1478
1479 if (WinSta->WallpaperMode == wmStretch)
1480 {
1481 if(Rect.right && Rect.bottom)
1482 NtGdiStretchBlt(hDC,
1483 x,
1484 y,
1485 sz.cx,
1486 sz.cy,
1487 hWallpaperDC,
1488 0,
1489 0,
1490 WinSta->cxWallpaper,
1491 WinSta->cyWallpaper,
1492 SRCCOPY,
1493 0);
1494
1495 }
1496 else if (WinSta->WallpaperMode == wmTile)
1497 {
1498 /* paint the bitmap across the screen then down */
1499 for(y = 0; y < Rect.bottom; y += WinSta->cyWallpaper)
1500 {
1501 for(x = 0; x < Rect.right; x += WinSta->cxWallpaper)
1502 {
1503 NtGdiBitBlt(hDC,
1504 x,
1505 y,
1506 WinSta->cxWallpaper,
1507 WinSta->cyWallpaper,
1508 hWallpaperDC,
1509 0,
1510 0,
1511 SRCCOPY,
1512 0,
1513 0);
1514 }
1515 }
1516 }
1517 else
1518 {
1519 NtGdiBitBlt(hDC,
1520 x,
1521 y,
1522 WinSta->cxWallpaper,
1523 WinSta->cyWallpaper,
1524 hWallpaperDC,
1525 0,
1526 0,
1527 SRCCOPY,
1528 0,
1529 0);
1530 }
1531 NtGdiSelectBitmap(hWallpaperDC, hOldBitmap);
1532 NtGdiDeleteObjectApp(hWallpaperDC);
1533 }
1534 }
1535 }
1536
1537 /* Back ground is set to none, clear the screen */
1538 if (doPatBlt)
1539 {
1540 PreviousBrush = NtGdiSelectBrush(hDC, DesktopBrush);
1541 NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right, Rect.bottom, PATCOPY);
1542 NtGdiSelectBrush(hDC, PreviousBrush);
1543 }
1544
1545 /*
1546 * Display system version on the desktop background
1547 */
1548
1549 if (g_PaintDesktopVersion)
1550 {
1551 static WCHAR s_wszVersion[256] = {0};
1552 RECTL rect;
1553
1554 if (*s_wszVersion)
1555 {
1556 len = wcslen(s_wszVersion);
1557 }
1558 else
1559 {
1560 len = GetSystemVersionString(s_wszVersion);
1561 }
1562
1563 if (len)
1564 {
1565 if (!UserSystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0))
1566 {
1567 rect.right = UserGetSystemMetrics(SM_CXSCREEN);
1568 rect.bottom = UserGetSystemMetrics(SM_CYSCREEN);
1569 }
1570
1571 color_old = IntGdiSetTextColor(hDC, RGB(255,255,255));
1572 align_old = IntGdiSetTextAlign(hDC, TA_RIGHT);
1573 mode_old = IntGdiSetBkMode(hDC, TRANSPARENT);
1574
1575 GreExtTextOutW(hDC, rect.right-16, rect.bottom-48, 0, NULL, s_wszVersion, len, NULL, 0);
1576
1577 IntGdiSetBkMode(hDC, mode_old);
1578 IntGdiSetTextAlign(hDC, align_old);
1579 IntGdiSetTextColor(hDC, color_old);
1580 }
1581 }
1582
1583 RETURN(TRUE);
1584
1585 CLEANUP:
1586 DPRINT("Leave NtUserPaintDesktop, ret=%i\n",_ret_);
1587 UserLeave();
1588 END_CLEANUP;
1589 }
1590
1591
1592 /*
1593 * NtUserSwitchDesktop
1594 *
1595 * Sets the current input (interactive) desktop.
1596 *
1597 * Parameters
1598 * hDesktop
1599 * Handle to desktop.
1600 *
1601 * Return Value
1602 * Status
1603 *
1604 * Status
1605 * @unimplemented
1606 */
1607
1608 BOOL APIENTRY
1609 NtUserSwitchDesktop(HDESK hDesktop)
1610 {
1611 PDESKTOP DesktopObject;
1612 NTSTATUS Status;
1613 DECLARE_RETURN(BOOL);
1614
1615 UserEnterExclusive();
1616 DPRINT("Enter NtUserSwitchDesktop\n");
1617
1618 DPRINT("About to switch desktop (0x%X)\n", hDesktop);
1619
1620 Status = IntValidateDesktopHandle(
1621 hDesktop,
1622 UserMode,
1623 0,
1624 &DesktopObject);
1625
1626 if (!NT_SUCCESS(Status))
1627 {
1628 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
1629 RETURN(FALSE);
1630 }
1631
1632 /*
1633 * Don't allow applications switch the desktop if it's locked, unless the caller
1634 * is the logon application itself
1635 */
1636 if((DesktopObject->rpwinstaParent->Flags & WSS_LOCKED) &&
1637 LogonProcess != NULL && LogonProcess != PsGetCurrentProcessWin32Process())
1638 {
1639 ObDereferenceObject(DesktopObject);
1640 DPRINT1("Switching desktop 0x%x denied because the work station is locked!\n", hDesktop);
1641 RETURN(FALSE);
1642 }
1643
1644 if(DesktopObject->rpwinstaParent != InputWindowStation)
1645 {
1646 ObDereferenceObject(DesktopObject);
1647 DPRINT1("Switching desktop 0x%x denied because desktop doesn't belong to the interactive winsta!\n", hDesktop);
1648 RETURN(FALSE);
1649 }
1650
1651 /* FIXME: Fail if the process is associated with a secured
1652 desktop such as Winlogon or Screen-Saver */
1653 /* FIXME: Connect to input device */
1654
1655 /* Set the active desktop in the desktop's window station. */
1656 InputWindowStation->ActiveDesktop = DesktopObject;
1657
1658 /* Set the global state. */
1659 InputDesktop = DesktopObject;
1660 InputDesktopHandle = hDesktop;
1661
1662 ObDereferenceObject(DesktopObject);
1663
1664 RETURN(TRUE);
1665
1666 CLEANUP:
1667 DPRINT("Leave NtUserSwitchDesktop, ret=%i\n",_ret_);
1668 UserLeave();
1669 END_CLEANUP;
1670 }
1671
1672 /*
1673 * NtUserResolveDesktopForWOW
1674 *
1675 * Status
1676 * @unimplemented
1677 */
1678
1679 DWORD APIENTRY
1680 NtUserResolveDesktopForWOW(DWORD Unknown0)
1681 {
1682 UNIMPLEMENTED
1683 return 0;
1684 }
1685
1686 /*
1687 * NtUserGetThreadDesktop
1688 *
1689 * Status
1690 * @implemented
1691 */
1692
1693 HDESK APIENTRY
1694 NtUserGetThreadDesktop(DWORD dwThreadId, DWORD Unknown1)
1695 {
1696 NTSTATUS Status;
1697 PETHREAD Thread;
1698 PDESKTOP DesktopObject;
1699 HDESK Ret, hThreadDesktop;
1700 OBJECT_HANDLE_INFORMATION HandleInformation;
1701 DECLARE_RETURN(HDESK);
1702
1703 UserEnterExclusive();
1704 DPRINT("Enter NtUserGetThreadDesktop\n");
1705
1706 if(!dwThreadId)
1707 {
1708 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1709 RETURN(0);
1710 }
1711
1712 Status = PsLookupThreadByThreadId((HANDLE)(DWORD_PTR)dwThreadId, &Thread);
1713 if(!NT_SUCCESS(Status))
1714 {
1715 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1716 RETURN(0);
1717 }
1718
1719 if(Thread->ThreadsProcess == PsGetCurrentProcess())
1720 {
1721 /* just return the handle, we queried the desktop handle of a thread running
1722 in the same context */
1723 Ret = ((PTHREADINFO)Thread->Tcb.Win32Thread)->hdesk;
1724 ObDereferenceObject(Thread);
1725 RETURN(Ret);
1726 }
1727
1728 /* get the desktop handle and the desktop of the thread */
1729 if(!(hThreadDesktop = ((PTHREADINFO)Thread->Tcb.Win32Thread)->hdesk) ||
1730 !(DesktopObject = ((PTHREADINFO)Thread->Tcb.Win32Thread)->rpdesk))
1731 {
1732 ObDereferenceObject(Thread);
1733 DPRINT1("Desktop information of thread 0x%x broken!?\n", dwThreadId);
1734 RETURN(NULL);
1735 }
1736
1737 /* we could just use DesktopObject instead of looking up the handle, but latter
1738 may be a bit safer (e.g. when the desktop is being destroyed */
1739 /* switch into the context of the thread we're trying to get the desktop from,
1740 so we can use the handle */
1741 KeAttachProcess(&Thread->ThreadsProcess->Pcb);
1742 Status = ObReferenceObjectByHandle(hThreadDesktop,
1743 GENERIC_ALL,
1744 ExDesktopObjectType,
1745 UserMode,
1746 (PVOID*)&DesktopObject,
1747 &HandleInformation);
1748 KeDetachProcess();
1749
1750 /* the handle couldn't be found, there's nothing to get... */
1751 if(!NT_SUCCESS(Status))
1752 {
1753 ObDereferenceObject(Thread);
1754 RETURN(NULL);
1755 }
1756
1757 /* lookup our handle table if we can find a handle to the desktop object,
1758 if not, create one */
1759 Ret = IntGetDesktopObjectHandle(DesktopObject);
1760
1761 /* all done, we got a valid handle to the desktop */
1762 ObDereferenceObject(DesktopObject);
1763 ObDereferenceObject(Thread);
1764 RETURN(Ret);
1765
1766 CLEANUP:
1767 DPRINT("Leave NtUserGetThreadDesktop, ret=%i\n",_ret_);
1768 UserLeave();
1769 END_CLEANUP;
1770 }
1771
1772 static NTSTATUS
1773 IntUnmapDesktopView(IN PDESKTOP DesktopObject)
1774 {
1775 PTHREADINFO ti;
1776 PPROCESSINFO CurrentWin32Process;
1777 PW32HEAP_USER_MAPPING HeapMapping, *PrevLink;
1778 NTSTATUS Status = STATUS_SUCCESS;
1779
1780 TRACE("DO %p\n");
1781
1782 CurrentWin32Process = PsGetCurrentProcessWin32Process();
1783 PrevLink = &CurrentWin32Process->HeapMappings.Next;
1784
1785 /* unmap if we're the last thread using the desktop */
1786 HeapMapping = *PrevLink;
1787 while (HeapMapping != NULL)
1788 {
1789 if (HeapMapping->KernelMapping == (PVOID)DesktopObject->pheapDesktop)
1790 {
1791 if (--HeapMapping->Count == 0)
1792 {
1793 *PrevLink = HeapMapping->Next;
1794
1795 Status = MmUnmapViewOfSection(PsGetCurrentProcess(),
1796 HeapMapping->UserMapping);
1797
1798 ObDereferenceObject(DesktopObject);
1799
1800 UserHeapFree(HeapMapping);
1801 break;
1802 }
1803 }
1804
1805 PrevLink = &HeapMapping->Next;
1806 HeapMapping = HeapMapping->Next;
1807 }
1808
1809 ti = GetW32ThreadInfo();
1810 if (ti != NULL)
1811 {
1812 GetWin32ClientInfo()->pDeskInfo = NULL;
1813 }
1814 GetWin32ClientInfo()->ulClientDelta = 0;
1815
1816 return Status;
1817 }
1818
1819 static NTSTATUS
1820 IntMapDesktopView(IN PDESKTOP DesktopObject)
1821 {
1822 PTHREADINFO ti;
1823 PPROCESSINFO CurrentWin32Process;
1824 PW32HEAP_USER_MAPPING HeapMapping, *PrevLink;
1825 PVOID UserBase = NULL;
1826 SIZE_T ViewSize = 0;
1827 LARGE_INTEGER Offset;
1828 NTSTATUS Status;
1829
1830 CurrentWin32Process = PsGetCurrentProcessWin32Process();
1831 PrevLink = &CurrentWin32Process->HeapMappings.Next;
1832
1833 /* find out if another thread already mapped the desktop heap */
1834 HeapMapping = *PrevLink;
1835 while (HeapMapping != NULL)
1836 {
1837 if (HeapMapping->KernelMapping == (PVOID)DesktopObject->pheapDesktop)
1838 {
1839 HeapMapping->Count++;
1840 return STATUS_SUCCESS;
1841 }
1842
1843 PrevLink = &HeapMapping->Next;
1844 HeapMapping = HeapMapping->Next;
1845 }
1846
1847 /* we're the first, map the heap */
1848 DPRINT("Noone mapped the desktop heap %p yet, so - map it!\n", DesktopObject->pheapDesktop);
1849 Offset.QuadPart = 0;
1850 Status = MmMapViewOfSection(DesktopObject->hsectionDesktop,
1851 PsGetCurrentProcess(),
1852 &UserBase,
1853 0,
1854 0,
1855 &Offset,
1856 &ViewSize,
1857 ViewUnmap,
1858 SEC_NO_CHANGE,
1859 PAGE_EXECUTE_READ); /* would prefer PAGE_READONLY, but thanks to RTL heaps... */
1860 if (!NT_SUCCESS(Status))
1861 {
1862 DPRINT1("Failed to map desktop\n");
1863 return Status;
1864 }
1865
1866 /* add the mapping */
1867 HeapMapping = UserHeapAlloc(sizeof(W32HEAP_USER_MAPPING));
1868 if (HeapMapping == NULL)
1869 {
1870 MmUnmapViewOfSection(PsGetCurrentProcess(),
1871 UserBase);
1872 DPRINT1("UserHeapAlloc() failed!\n");
1873 return STATUS_NO_MEMORY;
1874 }
1875
1876 HeapMapping->Next = NULL;
1877 HeapMapping->KernelMapping = (PVOID)DesktopObject->pheapDesktop;
1878 HeapMapping->UserMapping = UserBase;
1879 HeapMapping->Limit = ViewSize;
1880 HeapMapping->Count = 1;
1881 *PrevLink = HeapMapping;
1882
1883 ObReferenceObject(DesktopObject);
1884
1885 /* create a W32THREADINFO structure if not already done, or update it */
1886 ti = GetW32ThreadInfo();
1887 GetWin32ClientInfo()->ulClientDelta = DesktopHeapGetUserDelta();
1888 if (ti != NULL)
1889 {
1890 if (GetWin32ClientInfo()->pDeskInfo == NULL)
1891 {
1892 GetWin32ClientInfo()->pDeskInfo =
1893 (PVOID)((ULONG_PTR)DesktopObject->pDeskInfo -
1894 GetWin32ClientInfo()->ulClientDelta);
1895 }
1896 }
1897
1898 return STATUS_SUCCESS;
1899 }
1900
1901 BOOL
1902 IntSetThreadDesktop(IN PDESKTOP DesktopObject,
1903 IN BOOL FreeOnFailure)
1904 {
1905 PDESKTOP OldDesktop;
1906 PTHREADINFO W32Thread;
1907 NTSTATUS Status;
1908 BOOL MapHeap;
1909
1910 DPRINT("IntSetThreadDesktop() DO=%p, FOF=%d\n", DesktopObject, FreeOnFailure);
1911 MapHeap = (PsGetCurrentProcess() != PsInitialSystemProcess);
1912 W32Thread = PsGetCurrentThreadWin32Thread();
1913
1914 if (W32Thread->rpdesk != DesktopObject)
1915 {
1916 OldDesktop = W32Thread->rpdesk;
1917
1918 if (!IsListEmpty(&W32Thread->WindowListHead))
1919 {
1920 DPRINT1("Attempted to change thread desktop although the thread has windows!\n");
1921 SetLastWin32Error(ERROR_BUSY);
1922 return FALSE;
1923 }
1924
1925 W32Thread->rpdesk = DesktopObject;
1926
1927 if (MapHeap && DesktopObject != NULL)
1928 {
1929 Status = IntMapDesktopView(DesktopObject);
1930 if (!NT_SUCCESS(Status))
1931 {
1932 SetLastNtError(Status);
1933 return FALSE;
1934 }
1935 }
1936
1937 /* Hack for system threads */
1938 if (NtCurrentTeb())
1939 {
1940 PCLIENTINFO pci = GetWin32ClientInfo();
1941 pci->ulClientDelta = DesktopHeapGetUserDelta();
1942 if (DesktopObject)
1943 {
1944 pci->pDeskInfo = (PVOID)((ULONG_PTR)DesktopObject->pDeskInfo - pci->ulClientDelta);
1945 }
1946 }
1947
1948 if (OldDesktop != NULL &&
1949 !IntCheckProcessDesktopClasses(OldDesktop,
1950 FreeOnFailure))
1951 {
1952 DPRINT1("Failed to move process classes to shared heap!\n");
1953
1954 /* failed to move desktop classes to the shared heap,
1955 unmap the view and return the error */
1956 if (MapHeap && DesktopObject != NULL)
1957 IntUnmapDesktopView(DesktopObject);
1958
1959 return FALSE;
1960 }
1961
1962 /* Remove the thread from the old desktop's list */
1963 RemoveEntryList(&W32Thread->PtiLink);
1964
1965 if (DesktopObject != NULL)
1966 {
1967 ObReferenceObject(DesktopObject);
1968 /* Insert into new desktop's list */
1969 InsertTailList(&DesktopObject->PtiList, &W32Thread->PtiLink);
1970 }
1971
1972 if (OldDesktop != NULL)
1973 {
1974 if (MapHeap)
1975 {
1976 IntUnmapDesktopView(OldDesktop);
1977 }
1978
1979 ObDereferenceObject(OldDesktop);
1980 }
1981 }
1982
1983 return TRUE;
1984 }
1985
1986 /*
1987 * NtUserSetThreadDesktop
1988 *
1989 * Status
1990 * @implemented
1991 */
1992
1993 BOOL APIENTRY
1994 NtUserSetThreadDesktop(HDESK hDesktop)
1995 {
1996 PDESKTOP DesktopObject;
1997 NTSTATUS Status;
1998 DECLARE_RETURN(BOOL);
1999
2000 UserEnterExclusive();
2001 DPRINT("Enter NtUserSetThreadDesktop\n");
2002
2003 /* Validate the new desktop. */
2004 Status = IntValidateDesktopHandle(
2005 hDesktop,
2006 UserMode,
2007 0,
2008 &DesktopObject);
2009
2010 if (!NT_SUCCESS(Status))
2011 {
2012 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
2013 RETURN(FALSE);
2014 }
2015
2016 /* FIXME: Should check here to see if the thread has any windows. */
2017
2018 if (!IntSetThreadDesktop(DesktopObject,
2019 FALSE))
2020 {
2021 RETURN(FALSE);
2022 }
2023
2024 RETURN(TRUE);
2025
2026 CLEANUP:
2027 DPRINT("Leave NtUserSetThreadDesktop, ret=%i\n",_ret_);
2028 UserLeave();
2029 END_CLEANUP;
2030 }
2031
2032 /* EOF */