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