#include <win32k.h>
DBG_DEFAULT_CHANNEL(UserDesktop);
-static
-VOID
-IntFreeDesktopHeap(
- IN OUT PDESKTOP Desktop
-);
+static NTSTATUS
+UserInitializeDesktop(PDESKTOP pdesk, PUNICODE_STRING DesktopName, PWINSTATION_OBJECT pwinsta);
+
+static NTSTATUS
+IntMapDesktopView(IN PDESKTOP pdesk);
+
+static NTSTATUS
+IntUnmapDesktopView(IN PDESKTOP pdesk);
+
+static VOID
+IntFreeDesktopHeap(IN PDESKTOP pdesk);
/* GLOBALS *******************************************************************/
/* Currently active desktop */
-PDESKTOP InputDesktop = NULL;
-HDESK InputDesktopHandle = NULL;
+PDESKTOP gpdeskInputDesktop = NULL;
HDC ScreenDeviceContext = NULL;
+PTHREADINFO gptiDesktopThread;
+HCURSOR gDesktopCursor = NULL;
/* OBJECT CALLBACKS **********************************************************/
sizeof(DESKTOP),
0,
0,
- (PVOID)&Desktop);
+ (PVOID*)&Desktop);
if (!NT_SUCCESS(Status)) return Status;
- /* Initialize shell hook window list and set the parent */
- RtlZeroMemory(Desktop, sizeof(DESKTOP));
- InitializeListHead(&Desktop->ShellHookWindows);
- Desktop->rpwinstaParent = (PWINSTATION_OBJECT)ParseObject;
-
- /* Put the desktop on the window station's list of associated desktops */
- InsertTailList(&Desktop->rpwinstaParent->DesktopListHead,
- &Desktop->ListEntry);
+ /* Initialize the desktop */
+ Status = UserInitializeDesktop(Desktop, RemainingName, WinStaObject);
+ if (!NT_SUCCESS(Status))
+ {
+ ObDereferenceObject(Desktop);
+ return Status;
+ }
/* Set the desktop object and return success */
*Object = Desktop;
VOID APIENTRY
IntDesktopObjectDelete(PWIN32_DELETEMETHOD_PARAMETERS Parameters)
{
- PDESKTOP Desktop = (PDESKTOP)Parameters->Object;
+ PDESKTOP pdesk = (PDESKTOP)Parameters->Object;
+
+ TRACE("Deleting desktop object 0x%p\n", pdesk);
+
+ ASSERT(pdesk->pDeskInfo->spwnd->spwndChild == NULL);
- TRACE("Deleting desktop object 0x%p\n", Desktop);
+ if (pdesk->pDeskInfo->spwnd)
+ co_UserDestroyWindow(pdesk->pDeskInfo->spwnd);
+
+ if (pdesk->spwndMessage)
+ co_UserDestroyWindow(pdesk->spwndMessage);
/* Remove the desktop from the window station's list of associcated desktops */
- RemoveEntryList(&Desktop->ListEntry);
+ RemoveEntryList(&pdesk->ListEntry);
- IntFreeDesktopHeap(Desktop);
+ /* Free the heap */
+ IntFreeDesktopHeap(pdesk);
}
NTSTATUS NTAPI
IntDesktopOkToClose(PWIN32_OKAYTOCLOSEMETHOD_PARAMETERS Parameters)
{
- PTHREADINFO pti;
-
- pti = PsGetCurrentThreadWin32Thread();
+ PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
if( pti == NULL)
{
return STATUS_SUCCESS;
}
+NTSTATUS NTAPI IntDesktopObjectOpen(PWIN32_OPENMETHOD_PARAMETERS Parameters)
+{
+ PPROCESSINFO ppi = PsGetProcessWin32Process(Parameters->Process);
+ if (ppi == NULL)
+ return STATUS_SUCCESS;
+
+ return IntMapDesktopView((PDESKTOP)Parameters->Object);
+}
+
+NTSTATUS NTAPI IntDesktopObjectClose(PWIN32_CLOSEMETHOD_PARAMETERS Parameters)
+{
+ PPROCESSINFO ppi = PsGetProcessWin32Process(Parameters->Process);
+ if (ppi == NULL)
+ {
+ /* This happens when the process leaks desktop handles.
+ * At this point the PPROCESSINFO is already destroyed */
+ return STATUS_SUCCESS;
+ }
+
+ return IntUnmapDesktopView((PDESKTOP)Parameters->Object);
+}
+
+
/* PRIVATE FUNCTIONS **********************************************************/
INIT_FUNCTION
PDESKTOP FASTCALL
IntGetActiveDesktop(VOID)
{
- return InputDesktop;
+ return gpdeskInputDesktop;
}
/*
case WM_SYSCOLORCHANGE:
co_UserRedrawWindow(Wnd, NULL, NULL, RDW_INVALIDATE|RDW_ERASE|RDW_ALLCHILDREN);
return TRUE;
+ case WM_SETCURSOR:
+ {
+ PCURICON_OBJECT pcurOld, pcurNew;
+ pcurNew = UserGetCurIconObject(gDesktopCursor);
+ if (!pcurNew)
+ {
+ return TRUE;
+ }
+ pcurOld = UserSetCursor(pcurNew, FALSE);
+ if (pcurOld)
+ {
+ UserDereferenceObject(pcurOld);
+ }
+ }
}
- return FALSE; // Not processed so go with callback.
+ return TRUE; /* We are done. Do not do any callbacks to user mode */
+}
+
+BOOL FASTCALL
+UserMessageWindowProc(PWND pwnd, UINT Msg, WPARAM wParam, LPARAM lParam, LRESULT *lResult)
+{
+ *lResult = 0;
+
+ switch(Msg)
+ {
+ case WM_NCCREATE:
+ pwnd->fnid |= FNID_MESSAGEWND;
+ *lResult = (LRESULT)TRUE;
+ break;
+ case WM_DESTROY:
+ pwnd->fnid |= FNID_DESTROY;
+ break;
+ }
+
+ return TRUE; /* We are done. Do not do any callbacks to user mode */
+}
+
+VOID NTAPI DesktopThreadMain()
+{
+ BOOL Ret;
+ MSG Msg;
+
+ gptiDesktopThread = PsGetCurrentThreadWin32Thread();
+
+ UserEnterExclusive();
+
+ /* Register system classes. This thread does not belong to any desktop so the
+ classes will be allocated from the shared heap */
+ UserRegisterSystemClasses();
+
+ while(TRUE)
+ {
+ Ret = co_IntGetPeekMessage(&Msg, 0, 0, 0, PM_REMOVE, TRUE);
+ if (Ret)
+ {
+ IntDispatchMessage(&Msg);
+ }
+ }
+
+ UserLeave();
}
HDC FASTCALL
static VOID
IntFreeDesktopHeap(IN OUT PDESKTOP Desktop)
{
+ /* FIXME: Disable until unmapping works in mm */
+#if 0
if (Desktop->pheapDesktop != NULL)
{
MmUnmapViewInSessionSpace(Desktop->pheapDesktop);
ObDereferenceObject(Desktop->hsectionDesktop);
Desktop->hsectionDesktop = NULL;
}
+#endif
}
BOOL FASTCALL
return TRUE;
}
+static NTSTATUS
+UserInitializeDesktop(PDESKTOP pdesk, PUNICODE_STRING DesktopName, PWINSTATION_OBJECT pwinsta)
+{
+ PVOID DesktopHeapSystemBase = NULL;
+ ULONG_PTR HeapSize = 400 * 1024;
+ SIZE_T DesktopInfoSize;
+ ULONG i;
+
+ TRACE("UserInitializeDesktop desktop 0x%p with name %wZ\n", pdesk, DesktopName);
+
+ RtlZeroMemory(pdesk, sizeof(DESKTOP));
+
+ /* Link the desktop with the parent window station */
+ pdesk->rpwinstaParent = pwinsta;
+ InsertTailList(&pwinsta->DesktopListHead, &pdesk->ListEntry);
+
+ /* Create the desktop heap */
+ pdesk->hsectionDesktop = NULL;
+ pdesk->pheapDesktop = UserCreateHeap(&pdesk->hsectionDesktop,
+ &DesktopHeapSystemBase,
+ HeapSize);
+ if (pdesk->pheapDesktop == NULL)
+ {
+ ERR("Failed to create desktop heap!\n");
+ return STATUS_NO_MEMORY;
+ }
+
+ /* Create DESKTOPINFO */
+ DesktopInfoSize = sizeof(DESKTOPINFO) + DesktopName->Length + sizeof(WCHAR);
+ pdesk->pDeskInfo = RtlAllocateHeap(pdesk->pheapDesktop,
+ HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY,
+ DesktopInfoSize);
+ if (pdesk->pDeskInfo == NULL)
+ {
+ ERR("Failed to create the DESKTOP structure!\n");
+ return STATUS_NO_MEMORY;
+ }
+
+ /* Initialize the DESKTOPINFO */
+ pdesk->pDeskInfo->pvDesktopBase = DesktopHeapSystemBase;
+ pdesk->pDeskInfo->pvDesktopLimit = (PVOID)((ULONG_PTR)DesktopHeapSystemBase + HeapSize);
+ RtlCopyMemory(pdesk->pDeskInfo->szDesktopName,
+ DesktopName->Buffer,
+ DesktopName->Length + sizeof(WCHAR));
+ for (i = 0; i < NB_HOOKS; i++)
+ {
+ InitializeListHead(&pdesk->pDeskInfo->aphkStart[i]);
+ }
+
+ InitializeListHead(&pdesk->ShellHookWindows);
+ InitializeListHead(&pdesk->PtiList);
+
+ return STATUS_SUCCESS;
+}
+
/* SYSCALLS *******************************************************************/
/*
DWORD dwFlags,
ACCESS_MASK dwDesiredAccess)
{
- PDESKTOP DesktopObject;
- UNICODE_STRING DesktopName;
+ PDESKTOP pdesk = NULL;
NTSTATUS Status = STATUS_SUCCESS;
- HDESK Desktop;
- CSR_API_MESSAGE Request;
- PVOID DesktopHeapSystemBase = NULL;
- SIZE_T DesktopInfoSize;
+ HDESK hdesk;
BOOLEAN Context;
- ULONG_PTR HeapSize = 400 * 1024; /* FIXME: Windows uses 200KB by default */
UNICODE_STRING ClassName;
LARGE_STRING WindowName;
BOOL NoHooks = FALSE;
PWND pWnd = NULL;
CREATESTRUCTW Cs;
- INT i;
PTHREADINFO ptiCurrent;
+ PCLS pcls;
+
DECLARE_RETURN(HDESK);
TRACE("Enter NtUserCreateDesktop\n");
UserEnterExclusive();
ptiCurrent = PsGetCurrentThreadWin32Thread();
- if (ptiCurrent)
- {
+ ASSERT(ptiCurrent);
+ ASSERT(gptiDesktopThread);
+
/* Turn off hooks when calling any CreateWindowEx from inside win32k. */
- NoHooks = (ptiCurrent->TIF_flags & TIF_DISABLEHOOKS);
- ptiCurrent->TIF_flags |= TIF_DISABLEHOOKS;
- ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
- }
- /*else
- {ERR("NtUserCreateDesktop: No ptiCurrent\n");}*/
- DesktopName.Buffer = NULL;
+ NoHooks = (ptiCurrent->TIF_flags & TIF_DISABLEHOOKS);
+ ptiCurrent->TIF_flags |= TIF_DISABLEHOOKS;
+ ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
/*
* Try to open already existing desktop
*/
-
Status = ObOpenObjectByName(
ObjectAttributes,
ExDesktopObjectType,
NULL,
dwDesiredAccess,
(PVOID)&Context,
- (HANDLE*)&Desktop);
- if (!NT_SUCCESS(Status)) RETURN(NULL);
+ (HANDLE*)&hdesk);
+ if (!NT_SUCCESS(Status))
+ {
+ ERR("ObOpenObjectByName failed to open/create desktop\n");
+ SetLastNtError(Status);
+ RETURN(NULL);
+ }
/* In case the object was not created (eg if it existed), return now */
if (Context == FALSE)
{
TRACE("NtUserCreateDesktop opened desktop %wZ\n", ObjectAttributes->ObjectName);
- RETURN( Desktop);
- }
-
- /* Capture desktop name */
- _SEH2_TRY
- {
- ProbeForRead( ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), 1);
-
- Status = IntSafeCopyUnicodeStringTerminateNULL(&DesktopName, ObjectAttributes->ObjectName);
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- Status = _SEH2_GetExceptionCode();
- }
- _SEH2_END
-
- if (! NT_SUCCESS(Status))
- {
- ERR("Failed reading Object Attributes from user space.\n");
- SetLastNtError(Status);
- RETURN( NULL);
+ RETURN( hdesk);
}
/* Reference the desktop */
- Status = ObReferenceObjectByHandle(Desktop,
+ Status = ObReferenceObjectByHandle(hdesk,
0,
ExDesktopObjectType,
KernelMode,
- (PVOID)&DesktopObject,
+ (PVOID*)&pdesk,
NULL);
if (!NT_SUCCESS(Status))
{
ERR("Failed to reference desktop object\n");
+ SetLastNtError(Status);
RETURN(NULL);
}
- TRACE("NtUserCreateDesktop created desktop 0x%p with name %wZ\n", DesktopObject, &DesktopName);
-
- DesktopObject->hsectionDesktop = NULL;
- DesktopObject->pheapDesktop = UserCreateHeap(&DesktopObject->hsectionDesktop,
- &DesktopHeapSystemBase,
- HeapSize);
- if (DesktopObject->pheapDesktop == NULL)
- {
- ObDereferenceObject(DesktopObject);
- ERR("Failed to create desktop heap!\n");
- RETURN(NULL);
- }
-
- DesktopInfoSize = sizeof(DESKTOPINFO) + DesktopName.Length + sizeof(WCHAR);
-
- DesktopObject->pDeskInfo = RtlAllocateHeap(DesktopObject->pheapDesktop,
- HEAP_NO_SERIALIZE,
- DesktopInfoSize);
+ if (!ptiCurrent->rpdesk) IntSetThreadDesktop(hdesk,FALSE);
- if (DesktopObject->pDeskInfo == NULL)
+ /* Get the desktop window class. The thread desktop does not belong to any desktop
+ * so the classes created there (including the desktop class) are allocated in the shared heap
+ * It would cause problems if we used a class that belongs to the caller
+ */
+ ClassName.Buffer = WC_DESKTOP;
+ ClassName.Length = 0;
+ pcls = IntGetAndReferenceClass(&ClassName, 0, TRUE);
+ if (pcls == NULL)
{
- ObDereferenceObject(DesktopObject);
- ERR("Failed to create the DESKTOP structure!\n");
- RETURN(NULL);
+ ASSERT(FALSE);
+ RETURN(NULL);
}
- RtlZeroMemory(DesktopObject->pDeskInfo,
- DesktopInfoSize);
-
- DesktopObject->pDeskInfo->pvDesktopBase = DesktopHeapSystemBase;
- DesktopObject->pDeskInfo->pvDesktopLimit = (PVOID)((ULONG_PTR)DesktopHeapSystemBase + HeapSize);
- RtlCopyMemory(DesktopObject->pDeskInfo->szDesktopName,
- DesktopName.Buffer,
- DesktopName.Length + sizeof(WCHAR));
-
- /* Initialize some local (to win32k) desktop state. */
- InitializeListHead(&DesktopObject->PtiList);
- DesktopObject->ActiveMessageQueue = NULL;
-
- /* Setup Global Hooks. */
- for (i = 0; i < NB_HOOKS; i++)
- {
- InitializeListHead(&DesktopObject->pDeskInfo->aphkStart[i]);
- }
+ RtlZeroMemory(&WindowName, sizeof(WindowName));
+ RtlZeroMemory(&Cs, sizeof(Cs));
+ Cs.x = UserGetSystemMetrics(SM_XVIRTUALSCREEN),
+ Cs.y = UserGetSystemMetrics(SM_YVIRTUALSCREEN),
+ Cs.cx = UserGetSystemMetrics(SM_CXVIRTUALSCREEN),
+ Cs.cy = UserGetSystemMetrics(SM_CYVIRTUALSCREEN),
+ Cs.style = WS_POPUP|WS_CLIPCHILDREN;
+ Cs.hInstance = hModClient; // hModuleWin; // Server side winproc!
+ Cs.lpszName = (LPCWSTR) &WindowName;
+ Cs.lpszClass = (LPCWSTR) &ClassName;
- /*
- * Create a handle for CSRSS and notify CSRSS for Creating Desktop Background Windows and Threads.
- */
- Request.ApiNumber = CSR_CREATE_API_NUMBER(CSR_GUI, CREATE_DESKTOP);
- Status = CsrInsertObject(Desktop,
- GENERIC_ALL,
- (HANDLE*)&Request.Data.CreateDesktopRequest.DesktopHandle);
- if (! NT_SUCCESS(Status))
+ /* Use IntCreateWindow instead of co_UserCreateWindowEx cause the later expects a thread with a desktop */
+ pWnd = IntCreateWindow(&Cs, &WindowName, pcls, NULL, NULL, NULL, pdesk);
+ if (pWnd == NULL)
{
- ERR("Failed to create desktop handle for CSRSS\n");
- ZwClose(Desktop);
- SetLastNtError(Status);
- RETURN( NULL);
+ ERR("Failed to create desktop window for the new desktop\n");
+ RETURN(NULL);
}
- Status = co_CsrNotify((PCSR_API_MESSAGE)&Request,
- sizeof(CSR_API_MESSAGE));
- if (! NT_SUCCESS(Status))
+ pdesk->DesktopWindow = pWnd->head.h;
+ pdesk->pDeskInfo->spwnd = pWnd;
+ pWnd->fnid = FNID_DESKTOP;
+
+ ClassName.Buffer = MAKEINTATOM(gpsi->atomSysClass[ICLS_HWNDMESSAGE]);
+ ClassName.Length = 0;
+ pcls = IntGetAndReferenceClass(&ClassName, 0, TRUE);
+ if (pcls == NULL)
{
- CsrCloseHandle(Request.Data.CreateDesktopRequest.DesktopHandle);
- ERR("Failed to notify CSRSS about new desktop\n");
- ZwClose(Desktop);
- SetLastNtError(Status);
- RETURN( NULL);
+ ASSERT(FALSE);
+ RETURN(NULL);
}
- if (ptiCurrent && !ptiCurrent->rpdesk) IntSetThreadDesktop(Desktop,FALSE);
-
- ClassName.Buffer = ((PWSTR)((ULONG_PTR)(WORD)(gpsi->atomSysClass[ICLS_HWNDMESSAGE])));
- ClassName.Length = 0;
RtlZeroMemory(&WindowName, sizeof(WindowName));
-
RtlZeroMemory(&Cs, sizeof(Cs));
Cs.cx = Cs.cy = 100;
Cs.style = WS_POPUP|WS_CLIPCHILDREN;
- Cs.hInstance = hModClient; // hModuleWin; // Server side winproc! Leave it to Timo to not pass on notes!
+ Cs.hInstance = hModClient; // hModuleWin; // Server side winproc!
Cs.lpszName = (LPCWSTR) &WindowName;
Cs.lpszClass = (LPCWSTR) &ClassName;
-
- pWnd = co_UserCreateWindowEx(&Cs, &ClassName, &WindowName, NULL);
- if (!pWnd)
+ pWnd = IntCreateWindow(&Cs, &WindowName, pcls, NULL, NULL, NULL, pdesk);
+ if (pWnd == NULL)
{
- ERR("Failed to create Message window handle\n");
- }
- else
- {
- DesktopObject->spwndMessage = pWnd;
+ ERR("Failed to create message window for the new desktop\n");
+ RETURN(NULL);
}
+ pdesk->spwndMessage = pWnd;
+ pWnd->fnid = FNID_MESSAGEWND;
+
/* Now,,,
if !(WinStaObject->Flags & WSF_NOIO) is (not set) for desktop input output mode (see wiki)
Create Tooltip. Saved in DesktopObject->spwndTooltip.
The rest is same as message window.
http://msdn.microsoft.com/en-us/library/bb760250(VS.85).aspx
*/
- RETURN( Desktop);
+ RETURN( hdesk);
CLEANUP:
- if(DesktopName.Buffer != NULL)
+ if (pdesk != NULL)
{
- ExFreePoolWithTag(DesktopName.Buffer, TAG_STRING);
+ ObDereferenceObject(pdesk);
}
- if (!NoHooks && ptiCurrent)
+ if (_ret_ == NULL && hdesk != NULL)
+ {
+ ObCloseHandle(hdesk, UserMode);
+ }
+ if (!NoHooks)
{
ptiCurrent->TIF_flags &= ~TIF_DISABLEHOOKS;
ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
BOOL fInherit,
ACCESS_MASK dwDesiredAccess)
{
- PDESKTOP pdesk;
NTSTATUS Status;
HDESK hdesk = NULL;
+ ULONG HandleAttributes = 0;
UserEnterExclusive();
- TRACE("Enter NtUserOpenInputDesktop InputDesktopHandle 0x%p\n",InputDesktopHandle);
+ TRACE("Enter NtUserOpenInputDesktop gpdeskInputDesktop 0x%p\n",gpdeskInputDesktop);
- /* Get a pointer to the desktop object */
- Status = IntValidateDesktopHandle(InputDesktopHandle, UserMode, 0, &pdesk);
- if (!NT_SUCCESS(Status))
- {
- ERR("Validation of input desktop handle (0x%p) failed\n", InputDesktopHandle);
- goto Exit;
- }
+ if(fInherit) HandleAttributes = OBJ_INHERIT;
/* Create a new handle to the object */
Status = ObOpenObjectByPointer(
- pdesk,
- 0,
+ gpdeskInputDesktop,
+ HandleAttributes,
NULL,
dwDesiredAccess,
ExDesktopObjectType,
UserMode,
(PHANDLE)&hdesk);
- ObDereferenceObject(pdesk);
-
if (!NT_SUCCESS(Status))
{
ERR("Failed to open input desktop object\n");
SetLastNtError(Status);
- goto Exit;
}
-Exit:
+
TRACE("NtUserOpenInputDesktop returning 0x%p\n",hdesk);
UserLeave();
return hdesk;
InputWindowStation->ActiveDesktop = pdesk;
/* Set the global state. */
- InputDesktop = pdesk;
- InputDesktopHandle = hdesk;
- TRACE("SwitchDesktop InputDesktopHandle 0x%p\n",InputDesktopHandle);
+ gpdeskInputDesktop = pdesk;
+ TRACE("SwitchDesktop gpdeskInputDesktop 0x%p\n",gpdeskInputDesktop);
ObDereferenceObject(pdesk);
RETURN(TRUE);