336f48d28aece9a62bef723d2579f2e47908bbd6
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / desktop.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Desktops
5 * FILE: subsystems/win32/win32k/ntuser/desktop.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * REVISION HISTORY:
8 * 06-06-2001 CSH Created
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <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 DPRINT("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 co_IntSendMessageNoWait(*cursor, MsgType, Message, lParam);
744 }
745
746 ExFreePool(HwndList);
747 }
748
749 }
750
751 /*
752 * Add the window to the ShellHookWindows list. The windows
753 * on that list get notifications that are important to shell
754 * type applications.
755 *
756 * TODO: Validate the window? I'm not sure if sending these messages to
757 * an unsuspecting application that is not your own is a nice thing to do.
758 */
759 BOOL IntRegisterShellHookWindow(HWND hWnd)
760 {
761 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
762 PDESKTOP Desktop = pti->rpdesk;
763 PSHELL_HOOK_WINDOW Entry;
764
765 DPRINT("IntRegisterShellHookWindow\n");
766
767 /* First deregister the window, so we can be sure it's never twice in the
768 * list.
769 */
770 IntDeRegisterShellHookWindow(hWnd);
771
772 Entry = ExAllocatePoolWithTag(PagedPool,
773 sizeof(SHELL_HOOK_WINDOW),
774 TAG_WINSTA);
775
776 if (!Entry)
777 return FALSE;
778
779 Entry->hWnd = hWnd;
780
781 InsertTailList(&Desktop->ShellHookWindows, &Entry->ListEntry);
782
783 return TRUE;
784 }
785
786 /*
787 * Remove the window from the ShellHookWindows list. The windows
788 * on that list get notifications that are important to shell
789 * type applications.
790 */
791 BOOL IntDeRegisterShellHookWindow(HWND hWnd)
792 {
793 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
794 PDESKTOP Desktop = pti->rpdesk;
795 PSHELL_HOOK_WINDOW Current;
796
797 LIST_FOR_EACH(Current, &Desktop->ShellHookWindows, SHELL_HOOK_WINDOW, ListEntry)
798 {
799 if (Current->hWnd == hWnd)
800 {
801 RemoveEntryList(&Current->ListEntry);
802 ExFreePool(Current);
803 return TRUE;
804 }
805 }
806
807 return FALSE;
808 }
809
810 static VOID
811 IntFreeDesktopHeap(IN OUT PDESKTOP Desktop)
812 {
813 if (Desktop->hsectionDesktop != NULL)
814 {
815 ObDereferenceObject(Desktop->hsectionDesktop);
816 Desktop->hsectionDesktop = NULL;
817 }
818 }
819 /* SYSCALLS *******************************************************************/
820
821 /*
822 * NtUserCreateDesktop
823 *
824 * Creates a new desktop.
825 *
826 * Parameters
827 * poaAttribs
828 * Object Attributes.
829 *
830 * lpszDesktopDevice
831 * Name of the device.
832 *
833 * pDeviceMode
834 * Device Mode.
835 *
836 * dwFlags
837 * Interaction flags.
838 *
839 * dwDesiredAccess
840 * Requested type of access.
841 *
842 *
843 * Return Value
844 * If the function succeeds, the return value is a handle to the newly
845 * created desktop. If the specified desktop already exists, the function
846 * succeeds and returns a handle to the existing desktop. When you are
847 * finished using the handle, call the CloseDesktop function to close it.
848 * If the function fails, the return value is NULL.
849 *
850 * Status
851 * @implemented
852 */
853
854 HDESK APIENTRY
855 NtUserCreateDesktop(
856 POBJECT_ATTRIBUTES poa,
857 PUNICODE_STRING lpszDesktopDevice,
858 LPDEVMODEW lpdmw,
859 DWORD dwFlags,
860 ACCESS_MASK dwDesiredAccess)
861 {
862 OBJECT_ATTRIBUTES ObjectAttributes;
863 PTHREADINFO W32Thread;
864 PWINSTATION_OBJECT WinStaObject;
865 PDESKTOP DesktopObject;
866 UNICODE_STRING DesktopName;
867 NTSTATUS Status = STATUS_SUCCESS;
868 HDESK Desktop;
869 CSR_API_MESSAGE Request;
870 PVOID DesktopHeapSystemBase = NULL;
871 SIZE_T DesktopInfoSize;
872 UNICODE_STRING SafeDesktopName;
873 ULONG DummyContext;
874 ULONG_PTR HeapSize = 4 * 1024 * 1024; /* FIXME */
875 HWINSTA hWindowStation = NULL ;
876 PUNICODE_STRING lpszDesktopName = NULL;
877 UNICODE_STRING ClassName, MenuName;
878 LARGE_STRING WindowName;
879 BOOL NoHooks = FALSE;
880 PWND pWnd = NULL;
881 CREATESTRUCTW Cs;
882 INT i;
883 PTHREADINFO ptiCurrent;
884 DECLARE_RETURN(HDESK);
885
886 DPRINT("Enter NtUserCreateDesktop: %wZ\n", lpszDesktopName);
887 UserEnterExclusive();
888
889 ptiCurrent = PsGetCurrentThreadWin32Thread();
890 if (ptiCurrent)
891 {
892 /* Turn off hooks when calling any CreateWindowEx from inside win32k. */
893 NoHooks = (ptiCurrent->TIF_flags & TIF_DISABLEHOOKS);
894 ptiCurrent->TIF_flags |= TIF_DISABLEHOOKS;
895 }
896
897 _SEH2_TRY
898 {
899 ProbeForRead( poa,
900 sizeof(OBJECT_ATTRIBUTES),
901 1);
902
903 hWindowStation = poa->RootDirectory;
904 lpszDesktopName = poa->ObjectName;
905 }
906 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
907 {
908 Status =_SEH2_GetExceptionCode();
909 }
910 _SEH2_END
911
912 if (! NT_SUCCESS(Status))
913 {
914 DPRINT1("Failed reading Object Attributes from user space.\n");
915 SetLastNtError(Status);
916 RETURN( NULL);
917 }
918
919 Status = IntValidateWindowStationHandle(
920 hWindowStation,
921 KernelMode,
922 0, /* FIXME - WINSTA_CREATEDESKTOP */
923 &WinStaObject);
924
925 if (! NT_SUCCESS(Status))
926 {
927 DPRINT1("Failed validation of window station handle (0x%X), cannot create desktop %wZ\n",
928 hWindowStation, lpszDesktopName);
929 SetLastNtError(Status);
930 RETURN( NULL);
931 }
932 if(lpszDesktopName != NULL)
933 {
934 Status = IntSafeCopyUnicodeString(&SafeDesktopName, lpszDesktopName);
935 if(!NT_SUCCESS(Status))
936 {
937 SetLastNtError(Status);
938 RETURN( NULL);
939 }
940 }
941 else
942 {
943 RtlInitUnicodeString(&SafeDesktopName, NULL);
944 }
945
946 if (! IntGetFullWindowStationName(&DesktopName, &WinStaObject->Name,
947 &SafeDesktopName))
948 {
949 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
950 ObDereferenceObject(WinStaObject);
951 if (lpszDesktopName)
952 ExFreePoolWithTag(SafeDesktopName.Buffer, TAG_STRING);
953 RETURN( NULL);
954 }
955 if (lpszDesktopName)
956 ExFreePoolWithTag(SafeDesktopName.Buffer, TAG_STRING);
957 ObDereferenceObject(WinStaObject);
958
959 /*
960 * Try to open already existing desktop
961 */
962
963 DPRINT("Trying to open desktop (%wZ)\n", &DesktopName);
964
965 /* Initialize ObjectAttributes for the desktop object */
966 InitializeObjectAttributes(
967 &ObjectAttributes,
968 &DesktopName,
969 0,
970 NULL,
971 NULL);
972
973 Status = ObOpenObjectByName(
974 &ObjectAttributes,
975 ExDesktopObjectType,
976 KernelMode,
977 NULL,
978 dwDesiredAccess,
979 (PVOID)&DummyContext,
980 (HANDLE*)&Desktop);
981 if (!NT_SUCCESS(Status)) RETURN(NULL);
982 if (Status == STATUS_OBJECT_NAME_EXISTS)
983 {
984 ExFreePoolWithTag(DesktopName.Buffer, TAG_STRING);
985 RETURN( Desktop);
986 }
987
988 /* Reference the desktop */
989 Status = ObReferenceObjectByHandle(Desktop,
990 0,
991 ExDesktopObjectType,
992 KernelMode,
993 (PVOID)&DesktopObject,
994 NULL);
995 if (!NT_SUCCESS(Status)) RETURN(NULL);
996
997 DesktopObject->hsectionDesktop = NULL;
998 DesktopObject->pheapDesktop = UserCreateHeap(&DesktopObject->hsectionDesktop,
999 &DesktopHeapSystemBase,
1000 HeapSize);
1001 if (DesktopObject->pheapDesktop == NULL)
1002 {
1003 ObDereferenceObject(DesktopObject);
1004 DPRINT1("Failed to create desktop heap!\n");
1005 RETURN(NULL);
1006 }
1007
1008 DesktopInfoSize = FIELD_OFFSET(DESKTOPINFO,
1009 szDesktopName[(lpszDesktopName->Length / sizeof(WCHAR)) + 1]);
1010
1011 DesktopObject->pDeskInfo = RtlAllocateHeap(DesktopObject->pheapDesktop,
1012 HEAP_NO_SERIALIZE,
1013 DesktopInfoSize);
1014
1015 if (DesktopObject->pDeskInfo == NULL)
1016 {
1017 ObDereferenceObject(DesktopObject);
1018 DPRINT1("Failed to create the DESKTOP structure!\n");
1019 RETURN(NULL);
1020 }
1021
1022 RtlZeroMemory(DesktopObject->pDeskInfo,
1023 DesktopInfoSize);
1024
1025 DesktopObject->pDeskInfo->pvDesktopBase = DesktopHeapSystemBase;
1026 DesktopObject->pDeskInfo->pvDesktopLimit = (PVOID)((ULONG_PTR)DesktopHeapSystemBase + HeapSize);
1027 RtlCopyMemory(DesktopObject->pDeskInfo->szDesktopName,
1028 lpszDesktopName->Buffer,
1029 lpszDesktopName->Length);
1030
1031 /* Initialize some local (to win32k) desktop state. */
1032 InitializeListHead(&DesktopObject->PtiList);
1033 DesktopObject->ActiveMessageQueue = NULL;
1034 /* Setup Global Hooks. */
1035 for (i = 0; i < NB_HOOKS; i++)
1036 {
1037 InitializeListHead(&DesktopObject->pDeskInfo->aphkStart[i]);
1038 }
1039 ExFreePoolWithTag(DesktopName.Buffer, TAG_STRING);
1040
1041 if (! NT_SUCCESS(Status))
1042 {
1043 DPRINT1("Failed to create desktop handle\n");
1044 SetLastNtError(Status);
1045 RETURN( NULL);
1046 }
1047
1048 /*
1049 * Create a handle for CSRSS and notify CSRSS for Creating Desktop Window.
1050 *
1051 * Honestly, I believe this is a cleverly written hack that allowed ReactOS
1052 * to function at the beginning of the project by ramroding the GUI into
1053 * operation and making the desktop window work from user space.
1054 * (jt)
1055 */
1056 Request.Type = MAKE_CSR_API(CREATE_DESKTOP, CSR_GUI);
1057 Status = CsrInsertObject(Desktop,
1058 GENERIC_ALL,
1059 (HANDLE*)&Request.Data.CreateDesktopRequest.DesktopHandle);
1060 if (! NT_SUCCESS(Status))
1061 {
1062 DPRINT1("Failed to create desktop handle for CSRSS\n");
1063 ZwClose(Desktop);
1064 SetLastNtError(Status);
1065 RETURN( NULL);
1066 }
1067
1068 Status = co_CsrNotify(&Request);
1069 if (! NT_SUCCESS(Status))
1070 {
1071 CsrCloseHandle(Request.Data.CreateDesktopRequest.DesktopHandle);
1072 DPRINT1("Failed to notify CSRSS about new desktop\n");
1073 ZwClose(Desktop);
1074 SetLastNtError(Status);
1075 RETURN( NULL);
1076 }
1077
1078 W32Thread = PsGetCurrentThreadWin32Thread();
1079
1080 if (!W32Thread->rpdesk) IntSetThreadDesktop(DesktopObject,FALSE);
1081
1082 /*
1083 Based on wine/server/window.c in get_desktop_window.
1084 */
1085
1086 ClassName.Buffer = ((PWSTR)((ULONG_PTR)(WORD)(gpsi->atomSysClass[ICLS_HWNDMESSAGE])));
1087 ClassName.Length = 0;
1088 RtlZeroMemory(&MenuName, sizeof(MenuName));
1089 RtlZeroMemory(&WindowName, sizeof(WindowName));
1090
1091 RtlZeroMemory(&Cs, sizeof(Cs));
1092 Cs.cx = Cs.cy = 100;
1093 Cs.style = WS_POPUP|WS_CLIPCHILDREN;
1094 Cs.hInstance = hModClient;
1095 Cs.lpszName = (LPCWSTR) &WindowName;
1096 Cs.lpszClass = (LPCWSTR) &ClassName;
1097
1098 pWnd = co_UserCreateWindowEx(&Cs, &ClassName, &WindowName);
1099 if (!pWnd)
1100 {
1101 DPRINT1("Failed to create Message window handle\n");
1102 }
1103 else
1104 {
1105 DesktopObject->spwndMessage = pWnd;
1106 }
1107
1108 RETURN( Desktop);
1109
1110 CLEANUP:
1111 if (!NoHooks && ptiCurrent) ptiCurrent->TIF_flags &= ~TIF_DISABLEHOOKS;
1112 DPRINT("Leave NtUserCreateDesktop, ret=%i\n",_ret_);
1113 UserLeave();
1114 END_CLEANUP;
1115 }
1116
1117 /*
1118 * NtUserOpenDesktop
1119 *
1120 * Opens an existing desktop.
1121 *
1122 * Parameters
1123 * lpszDesktopName
1124 * Name of the existing desktop.
1125 *
1126 * dwFlags
1127 * Interaction flags.
1128 *
1129 * dwDesiredAccess
1130 * Requested type of access.
1131 *
1132 * Return Value
1133 * Handle to the desktop or zero on failure.
1134 *
1135 * Status
1136 * @implemented
1137 */
1138
1139 HDESK APIENTRY
1140 NtUserOpenDesktop(
1141 PUNICODE_STRING lpszDesktopName,
1142 DWORD dwFlags,
1143 ACCESS_MASK dwDesiredAccess)
1144 {
1145 OBJECT_ATTRIBUTES ObjectAttributes;
1146 HWINSTA WinSta;
1147 PWINSTATION_OBJECT WinStaObject;
1148 UNICODE_STRING DesktopName;
1149 UNICODE_STRING SafeDesktopName;
1150 NTSTATUS Status;
1151 HDESK Desktop;
1152 BOOL Result;
1153 DECLARE_RETURN(HDESK);
1154
1155 DPRINT("Enter NtUserOpenDesktop: %wZ\n", lpszDesktopName);
1156 UserEnterExclusive();
1157
1158 /*
1159 * Validate the window station handle and compose the fully
1160 * qualified desktop name
1161 */
1162
1163 WinSta = UserGetProcessWindowStation();
1164 Status = IntValidateWindowStationHandle(
1165 WinSta,
1166 KernelMode,
1167 0,
1168 &WinStaObject);
1169
1170 if (!NT_SUCCESS(Status))
1171 {
1172 DPRINT1("Failed validation of window station handle (0x%X)\n", WinSta);
1173 SetLastNtError(Status);
1174 RETURN( 0);
1175 }
1176
1177 if(lpszDesktopName != NULL)
1178 {
1179 Status = IntSafeCopyUnicodeString(&SafeDesktopName, lpszDesktopName);
1180 if(!NT_SUCCESS(Status))
1181 {
1182 SetLastNtError(Status);
1183 RETURN( NULL);
1184 }
1185 }
1186 else
1187 {
1188 RtlInitUnicodeString(&SafeDesktopName, NULL);
1189 }
1190
1191 Result = IntGetFullWindowStationName(&DesktopName, &WinStaObject->Name,
1192 &SafeDesktopName);
1193
1194 if (lpszDesktopName)
1195 ExFreePoolWithTag(SafeDesktopName.Buffer, TAG_STRING);
1196 ObDereferenceObject(WinStaObject);
1197
1198
1199 if (!Result)
1200 {
1201 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
1202 RETURN( 0);
1203 }
1204
1205
1206 DPRINT("Trying to open desktop (%wZ)\n", &DesktopName);
1207
1208 /* Initialize ObjectAttributes for the desktop object */
1209 InitializeObjectAttributes(
1210 &ObjectAttributes,
1211 &DesktopName,
1212 0,
1213 NULL,
1214 NULL);
1215
1216 Status = ObOpenObjectByName(
1217 &ObjectAttributes,
1218 ExDesktopObjectType,
1219 KernelMode,
1220 NULL,
1221 dwDesiredAccess,
1222 NULL,
1223 (HANDLE*)&Desktop);
1224
1225 if (!NT_SUCCESS(Status))
1226 {
1227 SetLastNtError(Status);
1228 ExFreePool(DesktopName.Buffer);
1229 RETURN( 0);
1230 }
1231
1232 DPRINT("Successfully opened desktop (%wZ)\n", &DesktopName);
1233 ExFreePool(DesktopName.Buffer);
1234
1235 RETURN( Desktop);
1236
1237 CLEANUP:
1238 DPRINT("Leave NtUserOpenDesktop, ret=%i\n",_ret_);
1239 UserLeave();
1240 END_CLEANUP;
1241 }
1242
1243 /*
1244 * NtUserOpenInputDesktop
1245 *
1246 * Opens the input (interactive) desktop.
1247 *
1248 * Parameters
1249 * dwFlags
1250 * Interaction flags.
1251 *
1252 * fInherit
1253 * Inheritance option.
1254 *
1255 * dwDesiredAccess
1256 * Requested type of access.
1257 *
1258 * Return Value
1259 * Handle to the input desktop or zero on failure.
1260 *
1261 * Status
1262 * @implemented
1263 */
1264
1265 HDESK APIENTRY
1266 NtUserOpenInputDesktop(
1267 DWORD dwFlags,
1268 BOOL fInherit,
1269 ACCESS_MASK dwDesiredAccess)
1270 {
1271 PDESKTOP Object;
1272 NTSTATUS Status;
1273 HDESK Desktop;
1274 DECLARE_RETURN(HDESK);
1275
1276 DPRINT("Enter NtUserOpenInputDesktop\n");
1277 UserEnterExclusive();
1278
1279 DPRINT("About to open input desktop\n");
1280
1281 /* Get a pointer to the desktop object */
1282
1283 Status = IntValidateDesktopHandle(
1284 InputDesktopHandle,
1285 UserMode,
1286 0,
1287 &Object);
1288
1289 if (!NT_SUCCESS(Status))
1290 {
1291 DPRINT("Validation of input desktop handle (0x%X) failed\n", InputDesktop);
1292 RETURN((HDESK)0);
1293 }
1294
1295 /* Create a new handle to the object */
1296
1297 Status = ObOpenObjectByPointer(
1298 Object,
1299 0,
1300 NULL,
1301 dwDesiredAccess,
1302 ExDesktopObjectType,
1303 UserMode,
1304 (HANDLE*)&Desktop);
1305
1306 ObDereferenceObject(Object);
1307
1308 if (NT_SUCCESS(Status))
1309 {
1310 DPRINT("Successfully opened input desktop\n");
1311 RETURN((HDESK)Desktop);
1312 }
1313
1314 SetLastNtError(Status);
1315 RETURN((HDESK)0);
1316
1317 CLEANUP:
1318 DPRINT("Leave NtUserOpenInputDesktop, ret=%i\n",_ret_);
1319 UserLeave();
1320 END_CLEANUP;
1321 }
1322
1323 /*
1324 * NtUserCloseDesktop
1325 *
1326 * Closes a desktop handle.
1327 *
1328 * Parameters
1329 * hDesktop
1330 * Handle to the desktop.
1331 *
1332 * Return Value
1333 * Status
1334 *
1335 * Remarks
1336 * The desktop handle can be created with NtUserCreateDesktop or
1337 * NtUserOpenDesktop. This function will fail if any thread in the calling
1338 * process is using the specified desktop handle or if the handle refers
1339 * to the initial desktop of the calling process.
1340 *
1341 * Status
1342 * @implemented
1343 */
1344
1345 BOOL APIENTRY
1346 NtUserCloseDesktop(HDESK hDesktop)
1347 {
1348 PDESKTOP Object;
1349 NTSTATUS Status;
1350 DECLARE_RETURN(BOOL);
1351
1352 DPRINT("Enter NtUserCloseDesktop\n");
1353 UserEnterExclusive();
1354
1355 DPRINT("About to close desktop handle (0x%X)\n", hDesktop);
1356
1357 Status = IntValidateDesktopHandle(
1358 hDesktop,
1359 UserMode,
1360 0,
1361 &Object);
1362
1363 if (!NT_SUCCESS(Status))
1364 {
1365 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
1366 RETURN(FALSE);
1367 }
1368
1369 ObDereferenceObject(Object);
1370
1371 DPRINT("Closing desktop handle (0x%X)\n", hDesktop);
1372
1373 Status = ZwClose(hDesktop);
1374 if (!NT_SUCCESS(Status))
1375 {
1376 SetLastNtError(Status);
1377 RETURN(FALSE);
1378 }
1379
1380 RETURN(TRUE);
1381
1382 CLEANUP:
1383 DPRINT("Leave NtUserCloseDesktop, ret=%i\n",_ret_);
1384 UserLeave();
1385 END_CLEANUP;
1386 }
1387
1388
1389
1390
1391 /*
1392 * NtUserPaintDesktop
1393 *
1394 * The NtUserPaintDesktop function fills the clipping region in the
1395 * specified device context with the desktop pattern or wallpaper. The
1396 * function is provided primarily for shell desktops.
1397 *
1398 * Parameters
1399 * hDC
1400 * Handle to the device context.
1401 *
1402 * Status
1403 * @implemented
1404 */
1405
1406 BOOL APIENTRY
1407 NtUserPaintDesktop(HDC hDC)
1408 {
1409 RECTL Rect;
1410 HBRUSH DesktopBrush, PreviousBrush;
1411 HWND hWndDesktop;
1412 BOOL doPatBlt = TRUE;
1413 PWND WndDesktop;
1414 int len;
1415 COLORREF color_old;
1416 UINT align_old;
1417 int mode_old;
1418 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1419 PWINSTATION_OBJECT WinSta = pti->rpdesk->rpwinstaParent;
1420 DECLARE_RETURN(BOOL);
1421
1422 UserEnterExclusive();
1423 DPRINT("Enter NtUserPaintDesktop\n");
1424
1425 GdiGetClipBox(hDC, &Rect);
1426
1427 hWndDesktop = IntGetDesktopWindow();
1428
1429 WndDesktop = UserGetWindowObject(hWndDesktop);
1430 if (!WndDesktop)
1431 {
1432 RETURN(FALSE);
1433 }
1434
1435 DesktopBrush = (HBRUSH)WndDesktop->pcls->hbrBackground;
1436
1437
1438 /*
1439 * Paint desktop background
1440 */
1441
1442 if (WinSta->hbmWallpaper != NULL)
1443 {
1444 PWND DeskWin;
1445
1446 DeskWin = UserGetWindowObject(hWndDesktop);
1447
1448 if (DeskWin)
1449 {
1450 SIZE sz;
1451 int x, y;
1452 HDC hWallpaperDC;
1453
1454 sz.cx = DeskWin->rcWindow.right - DeskWin->rcWindow.left;
1455 sz.cy = DeskWin->rcWindow.bottom - DeskWin->rcWindow.top;
1456
1457 if (WinSta->WallpaperMode == wmStretch ||
1458 WinSta->WallpaperMode == wmTile)
1459 {
1460 x = 0;
1461 y = 0;
1462 }
1463 else
1464 {
1465 /* Find the upper left corner, can be negtive if the bitmap is bigger then the screen */
1466 x = (sz.cx / 2) - (WinSta->cxWallpaper / 2);
1467 y = (sz.cy / 2) - (WinSta->cyWallpaper / 2);
1468 }
1469
1470 hWallpaperDC = NtGdiCreateCompatibleDC(hDC);
1471 if(hWallpaperDC != NULL)
1472 {
1473 HBITMAP hOldBitmap;
1474
1475 /* fill in the area that the bitmap is not going to cover */
1476 if (x > 0 || y > 0)
1477 {
1478 /* FIXME - clip out the bitmap
1479 can be replaced with "NtGdiPatBlt(hDC, x, y, WinSta->cxWallpaper, WinSta->cyWallpaper, PATCOPY | DSTINVERT);"
1480 once we support DSTINVERT */
1481 PreviousBrush = NtGdiSelectBrush(hDC, DesktopBrush);
1482 NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right, Rect.bottom, PATCOPY);
1483 NtGdiSelectBrush(hDC, PreviousBrush);
1484 }
1485
1486 /*Do not fill the background after it is painted no matter the size of the picture */
1487 doPatBlt = FALSE;
1488
1489 hOldBitmap = NtGdiSelectBitmap(hWallpaperDC, WinSta->hbmWallpaper);
1490
1491 if (WinSta->WallpaperMode == wmStretch)
1492 {
1493 if(Rect.right && Rect.bottom)
1494 NtGdiStretchBlt(hDC,
1495 x,
1496 y,
1497 sz.cx,
1498 sz.cy,
1499 hWallpaperDC,
1500 0,
1501 0,
1502 WinSta->cxWallpaper,
1503 WinSta->cyWallpaper,
1504 SRCCOPY,
1505 0);
1506
1507 }
1508 else if (WinSta->WallpaperMode == wmTile)
1509 {
1510 /* paint the bitmap across the screen then down */
1511 for(y = 0; y < Rect.bottom; y += WinSta->cyWallpaper)
1512 {
1513 for(x = 0; x < Rect.right; x += WinSta->cxWallpaper)
1514 {
1515 NtGdiBitBlt(hDC,
1516 x,
1517 y,
1518 WinSta->cxWallpaper,
1519 WinSta->cyWallpaper,
1520 hWallpaperDC,
1521 0,
1522 0,
1523 SRCCOPY,
1524 0,
1525 0);
1526 }
1527 }
1528 }
1529 else
1530 {
1531 NtGdiBitBlt(hDC,
1532 x,
1533 y,
1534 WinSta->cxWallpaper,
1535 WinSta->cyWallpaper,
1536 hWallpaperDC,
1537 0,
1538 0,
1539 SRCCOPY,
1540 0,
1541 0);
1542 }
1543 NtGdiSelectBitmap(hWallpaperDC, hOldBitmap);
1544 NtGdiDeleteObjectApp(hWallpaperDC);
1545 }
1546 }
1547 }
1548
1549 /* Back ground is set to none, clear the screen */
1550 if (doPatBlt)
1551 {
1552 PreviousBrush = NtGdiSelectBrush(hDC, DesktopBrush);
1553 NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right, Rect.bottom, PATCOPY);
1554 NtGdiSelectBrush(hDC, PreviousBrush);
1555 }
1556
1557 /*
1558 * Display system version on the desktop background
1559 */
1560
1561 if (g_PaintDesktopVersion)
1562 {
1563 static WCHAR s_wszVersion[256] = {0};
1564 RECTL rect;
1565
1566 if (*s_wszVersion)
1567 {
1568 len = wcslen(s_wszVersion);
1569 }
1570 else
1571 {
1572 len = GetSystemVersionString(s_wszVersion);
1573 }
1574
1575 if (len)
1576 {
1577 if (!UserSystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0))
1578 {
1579 rect.right = UserGetSystemMetrics(SM_CXSCREEN);
1580 rect.bottom = UserGetSystemMetrics(SM_CYSCREEN);
1581 }
1582
1583 color_old = IntGdiSetTextColor(hDC, RGB(255,255,255));
1584 align_old = IntGdiSetTextAlign(hDC, TA_RIGHT);
1585 mode_old = IntGdiSetBkMode(hDC, TRANSPARENT);
1586
1587 GreExtTextOutW(hDC, rect.right-16, rect.bottom-48, 0, NULL, s_wszVersion, len, NULL, 0);
1588
1589 IntGdiSetBkMode(hDC, mode_old);
1590 IntGdiSetTextAlign(hDC, align_old);
1591 IntGdiSetTextColor(hDC, color_old);
1592 }
1593 }
1594
1595 RETURN(TRUE);
1596
1597 CLEANUP:
1598 DPRINT("Leave NtUserPaintDesktop, ret=%i\n",_ret_);
1599 UserLeave();
1600 END_CLEANUP;
1601 }
1602
1603
1604 /*
1605 * NtUserSwitchDesktop
1606 *
1607 * Sets the current input (interactive) desktop.
1608 *
1609 * Parameters
1610 * hDesktop
1611 * Handle to desktop.
1612 *
1613 * Return Value
1614 * Status
1615 *
1616 * Status
1617 * @unimplemented
1618 */
1619
1620 BOOL APIENTRY
1621 NtUserSwitchDesktop(HDESK hDesktop)
1622 {
1623 PDESKTOP DesktopObject;
1624 NTSTATUS Status;
1625 DECLARE_RETURN(BOOL);
1626
1627 UserEnterExclusive();
1628 DPRINT("Enter NtUserSwitchDesktop\n");
1629
1630 DPRINT("About to switch desktop (0x%X)\n", hDesktop);
1631
1632 Status = IntValidateDesktopHandle(
1633 hDesktop,
1634 UserMode,
1635 0,
1636 &DesktopObject);
1637
1638 if (!NT_SUCCESS(Status))
1639 {
1640 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
1641 RETURN(FALSE);
1642 }
1643
1644 /*
1645 * Don't allow applications switch the desktop if it's locked, unless the caller
1646 * is the logon application itself
1647 */
1648 if((DesktopObject->rpwinstaParent->Flags & WSS_LOCKED) &&
1649 LogonProcess != NULL && LogonProcess != PsGetCurrentProcessWin32Process())
1650 {
1651 ObDereferenceObject(DesktopObject);
1652 DPRINT1("Switching desktop 0x%x denied because the work station is locked!\n", hDesktop);
1653 RETURN(FALSE);
1654 }
1655
1656 if(DesktopObject->rpwinstaParent != InputWindowStation)
1657 {
1658 ObDereferenceObject(DesktopObject);
1659 DPRINT1("Switching desktop 0x%x denied because desktop doesn't belong to the interactive winsta!\n", hDesktop);
1660 RETURN(FALSE);
1661 }
1662
1663 /* FIXME: Fail if the process is associated with a secured
1664 desktop such as Winlogon or Screen-Saver */
1665 /* FIXME: Connect to input device */
1666
1667 /* Set the active desktop in the desktop's window station. */
1668 InputWindowStation->ActiveDesktop = DesktopObject;
1669
1670 /* Set the global state. */
1671 InputDesktop = DesktopObject;
1672 InputDesktopHandle = hDesktop;
1673
1674 ObDereferenceObject(DesktopObject);
1675
1676 RETURN(TRUE);
1677
1678 CLEANUP:
1679 DPRINT("Leave NtUserSwitchDesktop, ret=%i\n",_ret_);
1680 UserLeave();
1681 END_CLEANUP;
1682 }
1683
1684 /*
1685 * NtUserGetThreadDesktop
1686 *
1687 * Status
1688 * @implemented
1689 */
1690
1691 HDESK APIENTRY
1692 NtUserGetThreadDesktop(DWORD dwThreadId, DWORD Unknown1)
1693 {
1694 NTSTATUS Status;
1695 PETHREAD Thread;
1696 PDESKTOP DesktopObject;
1697 HDESK Ret, hThreadDesktop;
1698 OBJECT_HANDLE_INFORMATION HandleInformation;
1699 DECLARE_RETURN(HDESK);
1700
1701 UserEnterExclusive();
1702 DPRINT("Enter NtUserGetThreadDesktop\n");
1703
1704 if(!dwThreadId)
1705 {
1706 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1707 RETURN(0);
1708 }
1709
1710 Status = PsLookupThreadByThreadId((HANDLE)(DWORD_PTR)dwThreadId, &Thread);
1711 if(!NT_SUCCESS(Status))
1712 {
1713 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1714 RETURN(0);
1715 }
1716
1717 if(Thread->ThreadsProcess == PsGetCurrentProcess())
1718 {
1719 /* just return the handle, we queried the desktop handle of a thread running
1720 in the same context */
1721 Ret = ((PTHREADINFO)Thread->Tcb.Win32Thread)->hdesk;
1722 ObDereferenceObject(Thread);
1723 RETURN(Ret);
1724 }
1725
1726 /* get the desktop handle and the desktop of the thread */
1727 if(!(hThreadDesktop = ((PTHREADINFO)Thread->Tcb.Win32Thread)->hdesk) ||
1728 !(DesktopObject = ((PTHREADINFO)Thread->Tcb.Win32Thread)->rpdesk))
1729 {
1730 ObDereferenceObject(Thread);
1731 DPRINT1("Desktop information of thread 0x%x broken!?\n", dwThreadId);
1732 RETURN(NULL);
1733 }
1734
1735 /* we could just use DesktopObject instead of looking up the handle, but latter
1736 may be a bit safer (e.g. when the desktop is being destroyed */
1737 /* switch into the context of the thread we're trying to get the desktop from,
1738 so we can use the handle */
1739 KeAttachProcess(&Thread->ThreadsProcess->Pcb);
1740 Status = ObReferenceObjectByHandle(hThreadDesktop,
1741 GENERIC_ALL,
1742 ExDesktopObjectType,
1743 UserMode,
1744 (PVOID*)&DesktopObject,
1745 &HandleInformation);
1746 KeDetachProcess();
1747
1748 /* the handle couldn't be found, there's nothing to get... */
1749 if(!NT_SUCCESS(Status))
1750 {
1751 ObDereferenceObject(Thread);
1752 RETURN(NULL);
1753 }
1754
1755 /* lookup our handle table if we can find a handle to the desktop object,
1756 if not, create one */
1757 Ret = IntGetDesktopObjectHandle(DesktopObject);
1758
1759 /* all done, we got a valid handle to the desktop */
1760 ObDereferenceObject(DesktopObject);
1761 ObDereferenceObject(Thread);
1762 RETURN(Ret);
1763
1764 CLEANUP:
1765 DPRINT("Leave NtUserGetThreadDesktop, ret=%i\n",_ret_);
1766 UserLeave();
1767 END_CLEANUP;
1768 }
1769
1770 static NTSTATUS
1771 IntUnmapDesktopView(IN PDESKTOP DesktopObject)
1772 {
1773 PTHREADINFO ti;
1774 PPROCESSINFO CurrentWin32Process;
1775 PW32HEAP_USER_MAPPING HeapMapping, *PrevLink;
1776 NTSTATUS Status = STATUS_SUCCESS;
1777
1778 TRACE("DO %p\n");
1779
1780 CurrentWin32Process = PsGetCurrentProcessWin32Process();
1781 PrevLink = &CurrentWin32Process->HeapMappings.Next;
1782
1783 /* unmap if we're the last thread using the desktop */
1784 HeapMapping = *PrevLink;
1785 while (HeapMapping != NULL)
1786 {
1787 if (HeapMapping->KernelMapping == (PVOID)DesktopObject->pheapDesktop)
1788 {
1789 if (--HeapMapping->Count == 0)
1790 {
1791 *PrevLink = HeapMapping->Next;
1792
1793 Status = MmUnmapViewOfSection(PsGetCurrentProcess(),
1794 HeapMapping->UserMapping);
1795
1796 ObDereferenceObject(DesktopObject);
1797
1798 UserHeapFree(HeapMapping);
1799 break;
1800 }
1801 }
1802
1803 PrevLink = &HeapMapping->Next;
1804 HeapMapping = HeapMapping->Next;
1805 }
1806
1807 ti = GetW32ThreadInfo();
1808 if (ti != NULL)
1809 {
1810 GetWin32ClientInfo()->pDeskInfo = NULL;
1811 }
1812 GetWin32ClientInfo()->ulClientDelta = 0;
1813
1814 return Status;
1815 }
1816
1817 static NTSTATUS
1818 IntMapDesktopView(IN PDESKTOP DesktopObject)
1819 {
1820 PPROCESSINFO CurrentWin32Process;
1821 PW32HEAP_USER_MAPPING HeapMapping, *PrevLink;
1822 PVOID UserBase = NULL;
1823 SIZE_T ViewSize = 0;
1824 LARGE_INTEGER Offset;
1825 NTSTATUS Status;
1826
1827 CurrentWin32Process = PsGetCurrentProcessWin32Process();
1828 PrevLink = &CurrentWin32Process->HeapMappings.Next;
1829
1830 /* find out if another thread already mapped the desktop heap */
1831 HeapMapping = *PrevLink;
1832 while (HeapMapping != NULL)
1833 {
1834 if (HeapMapping->KernelMapping == (PVOID)DesktopObject->pheapDesktop)
1835 {
1836 HeapMapping->Count++;
1837 return STATUS_SUCCESS;
1838 }
1839
1840 PrevLink = &HeapMapping->Next;
1841 HeapMapping = HeapMapping->Next;
1842 }
1843
1844 /* we're the first, map the heap */
1845 DPRINT("Noone mapped the desktop heap %p yet, so - map it!\n", DesktopObject->pheapDesktop);
1846 Offset.QuadPart = 0;
1847 Status = MmMapViewOfSection(DesktopObject->hsectionDesktop,
1848 PsGetCurrentProcess(),
1849 &UserBase,
1850 0,
1851 0,
1852 &Offset,
1853 &ViewSize,
1854 ViewUnmap,
1855 SEC_NO_CHANGE,
1856 PAGE_EXECUTE_READ); /* would prefer PAGE_READONLY, but thanks to RTL heaps... */
1857 if (!NT_SUCCESS(Status))
1858 {
1859 DPRINT1("Failed to map desktop\n");
1860 return Status;
1861 }
1862
1863 /* add the mapping */
1864 HeapMapping = UserHeapAlloc(sizeof(W32HEAP_USER_MAPPING));
1865 if (HeapMapping == NULL)
1866 {
1867 MmUnmapViewOfSection(PsGetCurrentProcess(),
1868 UserBase);
1869 DPRINT1("UserHeapAlloc() failed!\n");
1870 return STATUS_NO_MEMORY;
1871 }
1872
1873 HeapMapping->Next = NULL;
1874 HeapMapping->KernelMapping = (PVOID)DesktopObject->pheapDesktop;
1875 HeapMapping->UserMapping = UserBase;
1876 HeapMapping->Limit = ViewSize;
1877 HeapMapping->Count = 1;
1878 *PrevLink = HeapMapping;
1879
1880 ObReferenceObject(DesktopObject);
1881
1882 return STATUS_SUCCESS;
1883 }
1884
1885 BOOL
1886 IntSetThreadDesktop(IN PDESKTOP DesktopObject,
1887 IN BOOL FreeOnFailure)
1888 {
1889 PDESKTOP OldDesktop;
1890 PTHREADINFO W32Thread;
1891 NTSTATUS Status;
1892 BOOL MapHeap;
1893 CLIENTTHREADINFO ctiSave;
1894
1895 DPRINT("IntSetThreadDesktop() DO=%p, FOF=%d\n", DesktopObject, FreeOnFailure);
1896 MapHeap = (PsGetCurrentProcess() != PsInitialSystemProcess);
1897 W32Thread = PsGetCurrentThreadWin32Thread();
1898
1899 if (W32Thread->rpdesk != DesktopObject)
1900 {
1901 OldDesktop = W32Thread->rpdesk;
1902
1903 if (!IsListEmpty(&W32Thread->WindowListHead))
1904 {
1905 DPRINT1("Attempted to change thread desktop although the thread has windows!\n");
1906 SetLastWin32Error(ERROR_BUSY);
1907 return FALSE;
1908 }
1909
1910 W32Thread->rpdesk = DesktopObject;
1911
1912 if (MapHeap && DesktopObject != NULL)
1913 {
1914 Status = IntMapDesktopView(DesktopObject);
1915 if (!NT_SUCCESS(Status))
1916 {
1917 SetLastNtError(Status);
1918 return FALSE;
1919 }
1920 W32Thread->pDeskInfo = DesktopObject->pDeskInfo;
1921 }
1922
1923 RtlZeroMemory(&ctiSave, sizeof(CLIENTTHREADINFO));
1924
1925 if (W32Thread->pcti && OldDesktop && NtCurrentTeb())
1926 {
1927 RtlCopyMemory(&ctiSave, W32Thread->pcti, sizeof(CLIENTTHREADINFO));
1928 DPRINT("Free ClientThreadInfo\n");
1929 DesktopHeapFree(OldDesktop, W32Thread->pcti);
1930 W32Thread->pcti = NULL;
1931 }
1932
1933 if (!W32Thread->pcti && DesktopObject && NtCurrentTeb())
1934 {
1935 DPRINT("Allocate ClientThreadInfo\n");
1936 W32Thread->pcti = DesktopHeapAlloc( DesktopObject,
1937 sizeof(CLIENTTHREADINFO));
1938 RtlCopyMemory(W32Thread->pcti, &ctiSave, sizeof(CLIENTTHREADINFO));
1939 }
1940
1941 if (NtCurrentTeb())
1942 {
1943 PCLIENTINFO pci = GetWin32ClientInfo();
1944 pci->ulClientDelta = DesktopHeapGetUserDelta();
1945 if (DesktopObject)
1946 {
1947 pci->pDeskInfo = (PVOID)((ULONG_PTR)DesktopObject->pDeskInfo - pci->ulClientDelta);
1948 if (W32Thread->pcti) pci->pClientThreadInfo = (PVOID)((ULONG_PTR)W32Thread->pcti - pci->ulClientDelta);
1949 }
1950 }
1951
1952 if (OldDesktop != NULL &&
1953 !IntCheckProcessDesktopClasses(OldDesktop,
1954 FreeOnFailure))
1955 {
1956 DPRINT1("Failed to move process classes to shared heap!\n");
1957
1958 /* failed to move desktop classes to the shared heap,
1959 unmap the view and return the error */
1960 if (MapHeap && DesktopObject != NULL)
1961 IntUnmapDesktopView(DesktopObject);
1962
1963 return FALSE;
1964 }
1965
1966 /* Remove the thread from the old desktop's list */
1967 RemoveEntryList(&W32Thread->PtiLink);
1968
1969 if (DesktopObject != NULL)
1970 {
1971 ObReferenceObject(DesktopObject);
1972 /* Insert into new desktop's list */
1973 InsertTailList(&DesktopObject->PtiList, &W32Thread->PtiLink);
1974 }
1975
1976 if (OldDesktop != NULL)
1977 {
1978 if (MapHeap)
1979 {
1980 IntUnmapDesktopView(OldDesktop);
1981 }
1982
1983 ObDereferenceObject(OldDesktop);
1984 }
1985 }
1986
1987 return TRUE;
1988 }
1989
1990 /*
1991 * NtUserSetThreadDesktop
1992 *
1993 * Status
1994 * @implemented
1995 */
1996
1997 BOOL APIENTRY
1998 NtUserSetThreadDesktop(HDESK hDesktop)
1999 {
2000 PDESKTOP DesktopObject;
2001 NTSTATUS Status;
2002 DECLARE_RETURN(BOOL);
2003
2004 UserEnterExclusive();
2005 DPRINT("Enter NtUserSetThreadDesktop\n");
2006
2007 /* Validate the new desktop. */
2008 Status = IntValidateDesktopHandle(
2009 hDesktop,
2010 UserMode,
2011 0,
2012 &DesktopObject);
2013
2014 if (!NT_SUCCESS(Status))
2015 {
2016 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
2017 RETURN(FALSE);
2018 }
2019
2020 /* FIXME: Should check here to see if the thread has any windows. */
2021
2022 if (!IntSetThreadDesktop(DesktopObject,
2023 FALSE))
2024 {
2025 RETURN(FALSE);
2026 }
2027
2028 RETURN(TRUE);
2029
2030 CLEANUP:
2031 DPRINT("Leave NtUserSetThreadDesktop, ret=%i\n",_ret_);
2032 UserLeave();
2033 END_CLEANUP;
2034 }
2035
2036 /* EOF */