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