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