[NTOSKRNL/USERINIT/WIN32K]
[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 static WCHAR s_wszSafeMode[] = L"Safe Mode";
1350 int len;
1351 COLORREF color_old;
1352 UINT align_old;
1353 int mode_old;
1354 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1355 PWINSTATION_OBJECT WinSta = pti->rpdesk->rpwinstaParent;
1356 DECLARE_RETURN(BOOL);
1357
1358 UserEnterExclusive();
1359 DPRINT("Enter NtUserPaintDesktop\n");
1360
1361 GdiGetClipBox(hDC, &Rect);
1362
1363 hWndDesktop = IntGetDesktopWindow();
1364
1365 WndDesktop = UserGetWindowObject(hWndDesktop);
1366 if (!WndDesktop)
1367 {
1368 RETURN(FALSE);
1369 }
1370
1371 if (!UserGetSystemMetrics(SM_CLEANBOOT))
1372 {
1373 DesktopBrush = (HBRUSH)WndDesktop->pcls->hbrBackground;
1374
1375 /*
1376 * Paint desktop background
1377 */
1378 if (WinSta->hbmWallpaper != NULL)
1379 {
1380 SIZE sz;
1381 int x, y;
1382 HDC hWallpaperDC;
1383
1384 sz.cx = WndDesktop->rcWindow.right - WndDesktop->rcWindow.left;
1385 sz.cy = WndDesktop->rcWindow.bottom - WndDesktop->rcWindow.top;
1386
1387 if (WinSta->WallpaperMode == wmStretch ||
1388 WinSta->WallpaperMode == wmTile)
1389 {
1390 x = 0;
1391 y = 0;
1392 }
1393 else
1394 {
1395 /* Find the upper left corner, can be negtive if the bitmap is bigger then the screen */
1396 x = (sz.cx / 2) - (WinSta->cxWallpaper / 2);
1397 y = (sz.cy / 2) - (WinSta->cyWallpaper / 2);
1398 }
1399
1400 hWallpaperDC = NtGdiCreateCompatibleDC(hDC);
1401 if(hWallpaperDC != NULL)
1402 {
1403 HBITMAP hOldBitmap;
1404
1405 /* fill in the area that the bitmap is not going to cover */
1406 if (x > 0 || y > 0)
1407 {
1408 /* FIXME - clip out the bitmap
1409 can be replaced with "NtGdiPatBlt(hDC, x, y, WinSta->cxWallpaper, WinSta->cyWallpaper, PATCOPY | DSTINVERT);"
1410 once we support DSTINVERT */
1411 PreviousBrush = NtGdiSelectBrush(hDC, DesktopBrush);
1412 NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right, Rect.bottom, PATCOPY);
1413 NtGdiSelectBrush(hDC, PreviousBrush);
1414 }
1415
1416 /*Do not fill the background after it is painted no matter the size of the picture */
1417 doPatBlt = FALSE;
1418
1419 hOldBitmap = NtGdiSelectBitmap(hWallpaperDC, WinSta->hbmWallpaper);
1420
1421 if (WinSta->WallpaperMode == wmStretch)
1422 {
1423 if(Rect.right && Rect.bottom)
1424 NtGdiStretchBlt(hDC,
1425 x,
1426 y,
1427 sz.cx,
1428 sz.cy,
1429 hWallpaperDC,
1430 0,
1431 0,
1432 WinSta->cxWallpaper,
1433 WinSta->cyWallpaper,
1434 SRCCOPY,
1435 0);
1436
1437 }
1438 else if (WinSta->WallpaperMode == wmTile)
1439 {
1440 /* paint the bitmap across the screen then down */
1441 for(y = 0; y < Rect.bottom; y += WinSta->cyWallpaper)
1442 {
1443 for(x = 0; x < Rect.right; x += WinSta->cxWallpaper)
1444 {
1445 NtGdiBitBlt(hDC,
1446 x,
1447 y,
1448 WinSta->cxWallpaper,
1449 WinSta->cyWallpaper,
1450 hWallpaperDC,
1451 0,
1452 0,
1453 SRCCOPY,
1454 0,
1455 0);
1456 }
1457 }
1458 }
1459 else
1460 {
1461 NtGdiBitBlt(hDC,
1462 x,
1463 y,
1464 WinSta->cxWallpaper,
1465 WinSta->cyWallpaper,
1466 hWallpaperDC,
1467 0,
1468 0,
1469 SRCCOPY,
1470 0,
1471 0);
1472 }
1473 NtGdiSelectBitmap(hWallpaperDC, hOldBitmap);
1474 NtGdiDeleteObjectApp(hWallpaperDC);
1475 }
1476 }
1477 }
1478 else
1479 {
1480 /* Black desktop background in Safe Mode */
1481 DesktopBrush = StockObjects[BLACK_BRUSH];
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||UserGetSystemMetrics(SM_CLEANBOOT))
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 if(!UserGetSystemMetrics(SM_CLEANBOOT))
1523 {
1524 GreExtTextOutW(hDC, rect.right-16, rect.bottom-48, 0, NULL, s_wszVersion, len, NULL, 0);
1525 }
1526 else
1527 {
1528 /* Safe Mode */
1529 /* Version information text in top center */
1530 IntGdiSetTextAlign(hDC, TA_CENTER|TA_TOP);
1531 GreExtTextOutW(hDC, (rect.right+rect.left)/2, rect.top, 0, NULL, s_wszVersion, len, NULL, 0);
1532 /* Safe Mode text in corners */
1533 len = wcslen(s_wszSafeMode);
1534 IntGdiSetTextAlign(hDC, TA_RIGHT|TA_TOP);
1535 GreExtTextOutW(hDC, rect.right, rect.top, 0, NULL, s_wszSafeMode, len, NULL, 0);
1536 IntGdiSetTextAlign(hDC, TA_RIGHT|TA_BASELINE);
1537 GreExtTextOutW(hDC, rect.right, rect.bottom, 0, NULL, s_wszSafeMode, len, NULL, 0);
1538 IntGdiSetTextAlign(hDC, TA_LEFT|TA_TOP);
1539 GreExtTextOutW(hDC, rect.left, rect.top, 0, NULL, s_wszSafeMode, len, NULL, 0);
1540 IntGdiSetTextAlign(hDC, TA_LEFT|TA_BASELINE);
1541 GreExtTextOutW(hDC, rect.left, rect.bottom, 0, NULL, s_wszSafeMode, len, NULL, 0);
1542
1543 }
1544
1545
1546 IntGdiSetBkMode(hDC, mode_old);
1547 IntGdiSetTextAlign(hDC, align_old);
1548 IntGdiSetTextColor(hDC, color_old);
1549 }
1550 }
1551
1552 RETURN(TRUE);
1553
1554 CLEANUP:
1555 DPRINT("Leave NtUserPaintDesktop, ret=%i\n",_ret_);
1556 UserLeave();
1557 END_CLEANUP;
1558 }
1559
1560
1561 /*
1562 * NtUserSwitchDesktop
1563 *
1564 * Sets the current input (interactive) desktop.
1565 *
1566 * Parameters
1567 * hDesktop
1568 * Handle to desktop.
1569 *
1570 * Return Value
1571 * Status
1572 *
1573 * Status
1574 * @unimplemented
1575 */
1576
1577 BOOL APIENTRY
1578 NtUserSwitchDesktop(HDESK hDesktop)
1579 {
1580 PDESKTOP DesktopObject;
1581 NTSTATUS Status;
1582 DECLARE_RETURN(BOOL);
1583
1584 UserEnterExclusive();
1585 DPRINT("Enter NtUserSwitchDesktop\n");
1586
1587 DPRINT("About to switch desktop (0x%X)\n", hDesktop);
1588
1589 Status = IntValidateDesktopHandle(
1590 hDesktop,
1591 UserMode,
1592 0,
1593 &DesktopObject);
1594
1595 if (!NT_SUCCESS(Status))
1596 {
1597 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
1598 RETURN(FALSE);
1599 }
1600
1601 /*
1602 * Don't allow applications switch the desktop if it's locked, unless the caller
1603 * is the logon application itself
1604 */
1605 if((DesktopObject->rpwinstaParent->Flags & WSS_LOCKED) &&
1606 LogonProcess != NULL && LogonProcess != PsGetCurrentProcessWin32Process())
1607 {
1608 ObDereferenceObject(DesktopObject);
1609 DPRINT1("Switching desktop 0x%x denied because the work station is locked!\n", hDesktop);
1610 RETURN(FALSE);
1611 }
1612
1613 if(DesktopObject->rpwinstaParent != InputWindowStation)
1614 {
1615 ObDereferenceObject(DesktopObject);
1616 DPRINT1("Switching desktop 0x%x denied because desktop doesn't belong to the interactive winsta!\n", hDesktop);
1617 RETURN(FALSE);
1618 }
1619
1620 /* FIXME: Fail if the process is associated with a secured
1621 desktop such as Winlogon or Screen-Saver */
1622 /* FIXME: Connect to input device */
1623
1624 /* Set the active desktop in the desktop's window station. */
1625 InputWindowStation->ActiveDesktop = DesktopObject;
1626
1627 /* Set the global state. */
1628 InputDesktop = DesktopObject;
1629 InputDesktopHandle = hDesktop;
1630
1631 ObDereferenceObject(DesktopObject);
1632
1633 RETURN(TRUE);
1634
1635 CLEANUP:
1636 DPRINT("Leave NtUserSwitchDesktop, ret=%i\n",_ret_);
1637 UserLeave();
1638 END_CLEANUP;
1639 }
1640
1641 /*
1642 * NtUserGetThreadDesktop
1643 *
1644 * Status
1645 * @implemented
1646 */
1647
1648 HDESK APIENTRY
1649 NtUserGetThreadDesktop(DWORD dwThreadId, DWORD Unknown1)
1650 {
1651 NTSTATUS Status;
1652 PETHREAD Thread;
1653 PDESKTOP DesktopObject;
1654 HDESK Ret, hThreadDesktop;
1655 OBJECT_HANDLE_INFORMATION HandleInformation;
1656 DECLARE_RETURN(HDESK);
1657
1658 UserEnterExclusive();
1659 DPRINT("Enter NtUserGetThreadDesktop\n");
1660
1661 if(!dwThreadId)
1662 {
1663 EngSetLastError(ERROR_INVALID_PARAMETER);
1664 RETURN(0);
1665 }
1666
1667 Status = PsLookupThreadByThreadId((HANDLE)(DWORD_PTR)dwThreadId, &Thread);
1668 if(!NT_SUCCESS(Status))
1669 {
1670 EngSetLastError(ERROR_INVALID_PARAMETER);
1671 RETURN(0);
1672 }
1673
1674 if(Thread->ThreadsProcess == PsGetCurrentProcess())
1675 {
1676 /* just return the handle, we queried the desktop handle of a thread running
1677 in the same context */
1678 Ret = ((PTHREADINFO)Thread->Tcb.Win32Thread)->hdesk;
1679 ObDereferenceObject(Thread);
1680 RETURN(Ret);
1681 }
1682
1683 /* get the desktop handle and the desktop of the thread */
1684 if(!(hThreadDesktop = ((PTHREADINFO)Thread->Tcb.Win32Thread)->hdesk) ||
1685 !(DesktopObject = ((PTHREADINFO)Thread->Tcb.Win32Thread)->rpdesk))
1686 {
1687 ObDereferenceObject(Thread);
1688 DPRINT1("Desktop information of thread 0x%x broken!?\n", dwThreadId);
1689 RETURN(NULL);
1690 }
1691
1692 /* we could just use DesktopObject instead of looking up the handle, but latter
1693 may be a bit safer (e.g. when the desktop is being destroyed */
1694 /* switch into the context of the thread we're trying to get the desktop from,
1695 so we can use the handle */
1696 KeAttachProcess(&Thread->ThreadsProcess->Pcb);
1697 Status = ObReferenceObjectByHandle(hThreadDesktop,
1698 GENERIC_ALL,
1699 ExDesktopObjectType,
1700 UserMode,
1701 (PVOID*)&DesktopObject,
1702 &HandleInformation);
1703 KeDetachProcess();
1704
1705 /* the handle couldn't be found, there's nothing to get... */
1706 if(!NT_SUCCESS(Status))
1707 {
1708 ObDereferenceObject(Thread);
1709 RETURN(NULL);
1710 }
1711
1712 /* lookup our handle table if we can find a handle to the desktop object,
1713 if not, create one */
1714 Ret = IntGetDesktopObjectHandle(DesktopObject);
1715
1716 /* all done, we got a valid handle to the desktop */
1717 ObDereferenceObject(DesktopObject);
1718 ObDereferenceObject(Thread);
1719 RETURN(Ret);
1720
1721 CLEANUP:
1722 DPRINT("Leave NtUserGetThreadDesktop, ret=%i\n",_ret_);
1723 UserLeave();
1724 END_CLEANUP;
1725 }
1726
1727 static NTSTATUS
1728 IntUnmapDesktopView(IN PDESKTOP DesktopObject)
1729 {
1730 PTHREADINFO ti;
1731 PPROCESSINFO CurrentWin32Process;
1732 PW32HEAP_USER_MAPPING HeapMapping, *PrevLink;
1733 NTSTATUS Status = STATUS_SUCCESS;
1734
1735 TRACE("DO %p\n");
1736
1737 CurrentWin32Process = PsGetCurrentProcessWin32Process();
1738 PrevLink = &CurrentWin32Process->HeapMappings.Next;
1739
1740 /* unmap if we're the last thread using the desktop */
1741 HeapMapping = *PrevLink;
1742 while (HeapMapping != NULL)
1743 {
1744 if (HeapMapping->KernelMapping == (PVOID)DesktopObject->pheapDesktop)
1745 {
1746 if (--HeapMapping->Count == 0)
1747 {
1748 *PrevLink = HeapMapping->Next;
1749
1750 Status = MmUnmapViewOfSection(PsGetCurrentProcess(),
1751 HeapMapping->UserMapping);
1752
1753 ObDereferenceObject(DesktopObject);
1754
1755 UserHeapFree(HeapMapping);
1756 break;
1757 }
1758 }
1759
1760 PrevLink = &HeapMapping->Next;
1761 HeapMapping = HeapMapping->Next;
1762 }
1763
1764 ti = GetW32ThreadInfo();
1765 if (ti != NULL)
1766 {
1767 GetWin32ClientInfo()->pDeskInfo = NULL;
1768 }
1769 GetWin32ClientInfo()->ulClientDelta = 0;
1770
1771 return Status;
1772 }
1773
1774 static NTSTATUS
1775 IntMapDesktopView(IN PDESKTOP DesktopObject)
1776 {
1777 PPROCESSINFO CurrentWin32Process;
1778 PW32HEAP_USER_MAPPING HeapMapping, *PrevLink;
1779 PVOID UserBase = NULL;
1780 SIZE_T ViewSize = 0;
1781 LARGE_INTEGER Offset;
1782 NTSTATUS Status;
1783
1784 CurrentWin32Process = PsGetCurrentProcessWin32Process();
1785 PrevLink = &CurrentWin32Process->HeapMappings.Next;
1786
1787 /* find out if another thread already mapped the desktop heap */
1788 HeapMapping = *PrevLink;
1789 while (HeapMapping != NULL)
1790 {
1791 if (HeapMapping->KernelMapping == (PVOID)DesktopObject->pheapDesktop)
1792 {
1793 HeapMapping->Count++;
1794 return STATUS_SUCCESS;
1795 }
1796
1797 PrevLink = &HeapMapping->Next;
1798 HeapMapping = HeapMapping->Next;
1799 }
1800
1801 /* we're the first, map the heap */
1802 DPRINT("Noone mapped the desktop heap %p yet, so - map it!\n", DesktopObject->pheapDesktop);
1803 Offset.QuadPart = 0;
1804 Status = MmMapViewOfSection(DesktopObject->hsectionDesktop,
1805 PsGetCurrentProcess(),
1806 &UserBase,
1807 0,
1808 0,
1809 &Offset,
1810 &ViewSize,
1811 ViewUnmap,
1812 SEC_NO_CHANGE,
1813 PAGE_EXECUTE_READ); /* would prefer PAGE_READONLY, but thanks to RTL heaps... */
1814 if (!NT_SUCCESS(Status))
1815 {
1816 DPRINT1("Failed to map desktop\n");
1817 return Status;
1818 }
1819
1820 /* add the mapping */
1821 HeapMapping = UserHeapAlloc(sizeof(W32HEAP_USER_MAPPING));
1822 if (HeapMapping == NULL)
1823 {
1824 MmUnmapViewOfSection(PsGetCurrentProcess(),
1825 UserBase);
1826 DPRINT1("UserHeapAlloc() failed!\n");
1827 return STATUS_NO_MEMORY;
1828 }
1829
1830 HeapMapping->Next = NULL;
1831 HeapMapping->KernelMapping = (PVOID)DesktopObject->pheapDesktop;
1832 HeapMapping->UserMapping = UserBase;
1833 HeapMapping->Limit = ViewSize;
1834 HeapMapping->Count = 1;
1835 *PrevLink = HeapMapping;
1836
1837 ObReferenceObject(DesktopObject);
1838
1839 return STATUS_SUCCESS;
1840 }
1841
1842 BOOL
1843 IntSetThreadDesktop(IN HDESK hDesktop,
1844 IN BOOL FreeOnFailure)
1845 {
1846 PDESKTOP DesktopObject = NULL, OldDesktop;
1847 HDESK hOldDesktop;
1848 PTHREADINFO W32Thread;
1849 NTSTATUS Status;
1850 BOOL MapHeap;
1851 CLIENTTHREADINFO ctiSave;
1852
1853 DPRINT("IntSetThreadDesktop() , FOF=%d\n", FreeOnFailure);
1854 MapHeap = (PsGetCurrentProcess() != PsInitialSystemProcess);
1855 W32Thread = PsGetCurrentThreadWin32Thread();
1856
1857 if(hDesktop != NULL)
1858 {
1859 /* Validate the new desktop. */
1860 Status = IntValidateDesktopHandle(
1861 hDesktop,
1862 UserMode,
1863 0,
1864 &DesktopObject);
1865
1866 if (!NT_SUCCESS(Status))
1867 {
1868 DPRINT1("Validation of desktop handle (0x%X) failed\n", hDesktop);
1869 return FALSE;
1870 }
1871
1872 if (W32Thread->rpdesk == DesktopObject)
1873 {
1874 /* Nothing to do */
1875 ObDereferenceObject(DesktopObject);
1876 return TRUE;
1877 }
1878
1879 }
1880
1881 if (!IsListEmpty(&W32Thread->WindowListHead))
1882 {
1883 DPRINT1("Attempted to change thread desktop although the thread has windows!\n");
1884 EngSetLastError(ERROR_BUSY);
1885 return FALSE;
1886 }
1887
1888 OldDesktop = W32Thread->rpdesk;
1889 hOldDesktop = W32Thread->hdesk;
1890
1891 W32Thread->rpdesk = DesktopObject;
1892 W32Thread->hdesk = hDesktop;
1893
1894 if (MapHeap && DesktopObject != NULL)
1895 {
1896 Status = IntMapDesktopView(DesktopObject);
1897 if (!NT_SUCCESS(Status))
1898 {
1899 SetLastNtError(Status);
1900 return FALSE;
1901 }
1902 W32Thread->pDeskInfo = DesktopObject->pDeskInfo;
1903 }
1904
1905 RtlZeroMemory(&ctiSave, sizeof(CLIENTTHREADINFO));
1906
1907 if (W32Thread->pcti && OldDesktop && NtCurrentTeb())
1908 {
1909 RtlCopyMemory(&ctiSave, W32Thread->pcti, sizeof(CLIENTTHREADINFO));
1910 DPRINT("Free ClientThreadInfo\n");
1911 DesktopHeapFree(OldDesktop, W32Thread->pcti);
1912 W32Thread->pcti = NULL;
1913 }
1914
1915 if (!W32Thread->pcti && DesktopObject && NtCurrentTeb())
1916 {
1917 DPRINT("Allocate ClientThreadInfo\n");
1918 W32Thread->pcti = DesktopHeapAlloc( DesktopObject,
1919 sizeof(CLIENTTHREADINFO));
1920 RtlCopyMemory(W32Thread->pcti, &ctiSave, sizeof(CLIENTTHREADINFO));
1921 }
1922
1923 if (NtCurrentTeb())
1924 {
1925 PCLIENTINFO pci = GetWin32ClientInfo();
1926 pci->ulClientDelta = DesktopHeapGetUserDelta();
1927 if (DesktopObject)
1928 {
1929 pci->pDeskInfo = (PVOID)((ULONG_PTR)DesktopObject->pDeskInfo - pci->ulClientDelta);
1930 if (W32Thread->pcti) pci->pClientThreadInfo = (PVOID)((ULONG_PTR)W32Thread->pcti - pci->ulClientDelta);
1931 }
1932 }
1933
1934 if (OldDesktop != NULL &&
1935 !IntCheckProcessDesktopClasses(OldDesktop,
1936 FreeOnFailure))
1937 {
1938 DPRINT1("Failed to move process classes to shared heap!\n");
1939
1940 /* failed to move desktop classes to the shared heap,
1941 unmap the view and return the error */
1942 if (MapHeap && DesktopObject != NULL)
1943 IntUnmapDesktopView(DesktopObject);
1944
1945 return FALSE;
1946 }
1947
1948 /* Remove the thread from the old desktop's list */
1949 RemoveEntryList(&W32Thread->PtiLink);
1950
1951 if (DesktopObject != NULL)
1952 {
1953 ObReferenceObject(DesktopObject);
1954 /* Insert into new desktop's list */
1955 InsertTailList(&DesktopObject->PtiList, &W32Thread->PtiLink);
1956 }
1957
1958 /* Close the old desktop */
1959 if (OldDesktop != NULL)
1960 {
1961 if (MapHeap)
1962 {
1963 IntUnmapDesktopView(OldDesktop);
1964 }
1965
1966 ObDereferenceObject(OldDesktop);
1967 }
1968
1969 if (hOldDesktop != NULL)
1970 {
1971 ZwClose(hOldDesktop);
1972 }
1973
1974 return TRUE;
1975 }
1976
1977 /*
1978 * NtUserSetThreadDesktop
1979 *
1980 * Status
1981 * @implemented
1982 */
1983
1984 BOOL APIENTRY
1985 NtUserSetThreadDesktop(HDESK hDesktop)
1986 {
1987 BOOL ret;
1988
1989 UserEnterExclusive();
1990
1991 ret = IntSetThreadDesktop(hDesktop, FALSE);
1992
1993 UserLeave();
1994
1995 return ret;
1996 }
1997
1998 /* EOF */