diff --git a/win32ss/user/ntuser/csr.c b/win32ss/user/ntuser/csr.c index 7893cb53c01..93fffc0e7e2 100644 --- a/win32ss/user/ntuser/csr.c +++ b/win32ss/user/ntuser/csr.c @@ -14,6 +14,7 @@ DBG_DEFAULT_CHANNEL(UserCsr); PEPROCESS gpepCSRSS = NULL; PVOID CsrApiPort = NULL; +DWORD gdwPendingSystemThreads = 0; VOID InitCsrProcess(VOID /*IN PEPROCESS CsrProcess*/) @@ -197,4 +198,83 @@ CsrClientCallServer(IN OUT PCSR_API_MESSAGE ApiMessage, return ApiMessage->Status; } +/* + * UserSystemThreadProc + * + * Called form dedicated thread in CSRSS. RIT is started in context of this + * thread because it needs valid Win32 process with TEB initialized. + */ +DWORD UserSystemThreadProc(BOOL bRemoteProcess) +{ + DWORD Type; + + if (!gdwPendingSystemThreads) + { + ERR("gdwPendingSystemThreads is 0!\n"); + return 0; + } + + /* Decide which thread this will be */ + if (gdwPendingSystemThreads & ST_RIT) + Type = ST_RIT; + else if (gdwPendingSystemThreads & ST_DESKTOP_THREAD) + Type = ST_DESKTOP_THREAD; + else + Type = ST_GHOST_THREAD; + + ASSERT(Type); + + /* We will handle one of these threads right here so unmark it as pending */ + gdwPendingSystemThreads &= ~Type; + + UserLeave(); + + TRACE("UserSystemThreadProc: %d\n", Type); + + switch (Type) + { + case ST_RIT: RawInputThreadMain(); break; + case ST_DESKTOP_THREAD: DesktopThreadMain(); break; + case ST_GHOST_THREAD: UserGhostThreadEntry(); break; + default: ERR("Wrong type: %x\n", Type); + } + + UserEnterShared(); + + return 0; +} + +BOOL UserCreateSystemThread(DWORD Type) +{ + USER_API_MESSAGE ApiMessage; + PUSER_CREATE_SYSTEM_THREAD pCreateThreadRequest = &ApiMessage.Data.CreateSystemThreadRequest; + + TRACE("UserCreateSystemThread: %d\n", Type); + + ASSERT(UserIsEnteredExclusive()); + + if (gdwPendingSystemThreads & Type) + { + ERR("System thread 0x%x already pending for creation\n", Type); + return TRUE; + } + + /* We can't pass a parameter to the new thread so mark what the new thread needs to do */ + gdwPendingSystemThreads |= Type; + + /* Ask winsrv to create a new system thread. This new thread will enter win32k again calling UserSystemThreadProc */ + pCreateThreadRequest->bRemote = FALSE; + CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage, + NULL, + CSR_CREATE_API_NUMBER(USERSRV_SERVERDLL_INDEX, UserpCreateSystemThreads), + sizeof(USER_CREATE_SYSTEM_THREAD)); + if (!NT_SUCCESS(ApiMessage.Status)) + { + ERR("Csr call failed!\n"); + return FALSE; + } + + return TRUE; +} + /* EOF */ diff --git a/win32ss/user/ntuser/csr.h b/win32ss/user/ntuser/csr.h index 8359e733a2e..ac1ef10bc9a 100644 --- a/win32ss/user/ntuser/csr.h +++ b/win32ss/user/ntuser/csr.h @@ -32,4 +32,11 @@ CsrClientCallServer(IN OUT PCSR_API_MESSAGE ApiMessage, IN CSR_API_NUMBER ApiNumber, IN ULONG DataLength); +#define ST_RIT (1<<0) +#define ST_DESKTOP_THREAD (1<<1) +#define ST_GHOST_THREAD (1<<2) + +DWORD UserSystemThreadProc(BOOL bRemoteProcess); +BOOL UserCreateSystemThread(DWORD Type); + /* EOF */ diff --git a/win32ss/user/ntuser/desktop.c b/win32ss/user/ntuser/desktop.c index 4cfdde9af7c..e0661982260 100644 --- a/win32ss/user/ntuser/desktop.c +++ b/win32ss/user/ntuser/desktop.c @@ -36,6 +36,7 @@ PDESKTOP gpdeskInputDesktop = NULL; HDC ScreenDeviceContext = NULL; PTHREADINFO gptiDesktopThread = NULL; HCURSOR gDesktopCursor = NULL; +PKEVENT gpDesktopThreadStartedEvent = NULL; /* OBJECT CALLBACKS **********************************************************/ @@ -243,6 +244,22 @@ InitDesktopImpl(VOID) ExDesktopObjectType->TypeInfo.DefaultNonPagedPoolCharge = sizeof(DESKTOP); ExDesktopObjectType->TypeInfo.GenericMapping = IntDesktopMapping; ExDesktopObjectType->TypeInfo.ValidAccessMask = DESKTOP_ALL_ACCESS; + + /* Allocate memory for the event structure */ + gpDesktopThreadStartedEvent = ExAllocatePoolWithTag(NonPagedPool, + sizeof(KEVENT), + USERTAG_EVENT); + if (!gpDesktopThreadStartedEvent) + { + ERR("Failed to allocate event!\n"); + return STATUS_NO_MEMORY; + } + + /* Initialize the kernel event */ + KeInitializeEvent(gpDesktopThreadStartedEvent, + SynchronizationEvent, + FALSE); + return STATUS_SUCCESS; } @@ -1501,6 +1518,8 @@ VOID NTAPI DesktopThreadMain(VOID) classes will be allocated from the shared heap */ UserRegisterSystemClasses(); + KeSetEvent(gpDesktopThreadStartedEvent, IO_NO_INCREMENT, FALSE); + while (TRUE) { Ret = co_IntGetPeekMessage(&Msg, 0, 0, 0, PM_REMOVE, TRUE); diff --git a/win32ss/user/ntuser/desktop.h b/win32ss/user/ntuser/desktop.h index 0e1950ff645..6f15bb12a30 100644 --- a/win32ss/user/ntuser/desktop.h +++ b/win32ss/user/ntuser/desktop.h @@ -86,6 +86,7 @@ extern PCLS DesktopWindowClass; extern HDC ScreenDeviceContext; extern PTHREADINFO gptiForeground; extern PTHREADINFO gptiDesktopThread; +extern PKEVENT gpDesktopThreadStartedEvent; typedef struct _SHELL_HOOK_WINDOW { diff --git a/win32ss/user/ntuser/ghost.c b/win32ss/user/ntuser/ghost.c index 3342fea1557..fcb70a4c77c 100644 --- a/win32ss/user/ntuser/ghost.c +++ b/win32ss/user/ntuser/ghost.c @@ -11,9 +11,34 @@ #define NDEBUG #include +DBG_DEFAULT_CHANNEL(UserInput); + static UNICODE_STRING GhostClass = RTL_CONSTANT_STRING(GHOSTCLASSNAME); static UNICODE_STRING GhostProp = RTL_CONSTANT_STRING(GHOST_PROP); +PTHREADINFO gptiGhostThread = NULL; + +/* + * GhostThreadMain + * + * Creates ghost windows and exits when no non-responsive window remains. + */ +VOID NTAPI +UserGhostThreadEntry(VOID) +{ + TRACE("Ghost thread started\n"); + + UserEnterExclusive(); + + gptiGhostThread = PsGetCurrentThreadWin32Thread(); + + //TODO: Implement. This thread should handle all ghost windows and exit when no ghost window is needed. + + gptiGhostThread = NULL; + + UserLeave(); +} + BOOL FASTCALL IntIsGhostWindow(PWND Window) { BOOLEAN Ret = FALSE; @@ -161,18 +186,10 @@ BOOL FASTCALL IntMakeHungWindowGhosted(HWND hwndHung) return FALSE; // already ghosting } - // TODO: - // 1. Create a thread. - // 2. Create a ghost window in the thread. - // 3. Do message loop in the thread - { - static int bWarnedOnce = 0; - if (!bWarnedOnce) - { - bWarnedOnce++; - STUB; - } - } + // TODO: Find a way to pass the hwnd of pHungWnd to the ghost thread as we can't pass parameters directly - return FALSE; + if (!gptiGhostThread) + UserCreateSystemThread(ST_GHOST_THREAD); + + return TRUE; } diff --git a/win32ss/user/ntuser/ghost.h b/win32ss/user/ntuser/ghost.h index cd7b45ce5c3..97466583351 100644 --- a/win32ss/user/ntuser/ghost.h +++ b/win32ss/user/ntuser/ghost.h @@ -1 +1,3 @@ BOOL FASTCALL IntMakeHungWindowGhosted(HWND hwndHung); +VOID NTAPI UserGhostThreadEntry(VOID); + diff --git a/win32ss/user/ntuser/input.c b/win32ss/user/ntuser/input.c index 509fcda6e96..e4dbbabba07 100644 --- a/win32ss/user/ntuser/input.c +++ b/win32ss/user/ntuser/input.c @@ -138,6 +138,7 @@ RawInputThreadMain(VOID) MOUSE_INPUT_DATA MouseInput; KEYBOARD_INPUT_DATA KeyInput; PVOID ShutdownEvent; + HWINSTA hWinSta; ByteOffset.QuadPart = (LONGLONG)0; //WaitTimeout.QuadPart = (LONGLONG)(-10000000); @@ -151,6 +152,23 @@ RawInputThreadMain(VOID) KeSetPriorityThread(&PsGetCurrentThread()->Tcb, LOW_REALTIME_PRIORITY + 3); + Status = ObOpenObjectByPointer(InputWindowStation, + 0, + NULL, + MAXIMUM_ALLOWED, + ExWindowStationObjectType, + UserMode, + (PHANDLE)&hWinSta); + if (NT_SUCCESS(Status)) + { + UserSetProcessWindowStation(hWinSta); + } + else + { + ASSERT(FALSE); + /* Failed to open the interactive winsta! What now? */ + } + UserEnterExclusive(); StartTheTimers(); UserLeave(); @@ -330,29 +348,6 @@ RawInputThreadMain(VOID) ERR("Raw Input Thread Exit!\n"); } -/* - * CreateSystemThreads - * - * Called form dedicated thread in CSRSS. RIT is started in context of this - * thread because it needs valid Win32 process with TEB initialized. - */ -DWORD NTAPI -CreateSystemThreads(UINT Type) -{ - UserLeave(); - - switch (Type) - { - case 0: RawInputThreadMain(); break; - case 1: DesktopThreadMain(); break; - default: ERR("Wrong type: %x\n", Type); - } - - UserEnterShared(); - - return 0; -} - /* * InitInputImpl * diff --git a/win32ss/user/ntuser/input.h b/win32ss/user/ntuser/input.h index 715a0b95ee7..2c2e50c4efa 100644 --- a/win32ss/user/ntuser/input.h +++ b/win32ss/user/ntuser/input.h @@ -60,8 +60,8 @@ extern PATTACHINFO gpai; /* General */ INIT_FUNCTION NTSTATUS NTAPI InitInputImpl(VOID); +VOID NTAPI RawInputThreadMain(VOID); BOOL FASTCALL IntBlockInput(PTHREADINFO W32Thread, BOOL BlockIt); -DWORD NTAPI CreateSystemThreads(UINT Type); NTSTATUS FASTCALL UserAttachThreadInput(PTHREADINFO,PTHREADINFO,BOOL); BOOL FASTCALL IsRemoveAttachThread(PTHREADINFO); VOID FASTCALL DoTheScreenSaver(VOID); diff --git a/win32ss/user/ntuser/simplecall.c b/win32ss/user/ntuser/simplecall.c index 9356415c462..179d58bcdec 100644 --- a/win32ss/user/ntuser/simplecall.c +++ b/win32ss/user/ntuser/simplecall.c @@ -392,7 +392,7 @@ NtUserCallOneParam( break; case ONEPARAM_ROUTINE_CREATESYSTEMTHREADS: - Result = CreateSystemThreads(Param); + Result = UserSystemThreadProc(Param); break; case ONEPARAM_ROUTINE_LOCKFOREGNDWINDOW: diff --git a/win32ss/user/ntuser/winsta.c b/win32ss/user/ntuser/winsta.c index 12a1b90d3ad..63325fe8004 100644 --- a/win32ss/user/ntuser/winsta.c +++ b/win32ss/user/ntuser/winsta.c @@ -497,7 +497,20 @@ IntCreateWindowStation( InputWindowStation = WindowStation; WindowStation->Flags &= ~WSS_NOIO; + InitCursorImpl(); + + UserCreateSystemThread(ST_DESKTOP_THREAD); + UserCreateSystemThread(ST_RIT); + + /* Desktop functions require the desktop thread running so wait for it to initialize */ + UserLeaveCo(); + KeWaitForSingleObject(gpDesktopThreadStartedEvent, + UserRequest, + UserMode, + FALSE, + NULL); + UserEnterCo(); } else { @@ -742,6 +755,8 @@ NtUserCreateWindowStation( return NULL; } + UserEnterExclusive(); + /* Create the window station */ Status = IntCreateWindowStation(&hWinSta, ObjectAttributes, @@ -753,6 +768,8 @@ NtUserCreateWindowStation( Unknown4, Unknown5, Unknown6); + UserLeave(); + if (NT_SUCCESS(Status)) { TRACE("NtUserCreateWindowStation created window station '%wZ' with handle 0x%p\n", diff --git a/win32ss/user/winsrv/usersrv/init.c b/win32ss/user/winsrv/usersrv/init.c index d70209e6882..2c38825bbe4 100644 --- a/win32ss/user/winsrv/usersrv/init.c +++ b/win32ss/user/winsrv/usersrv/init.c @@ -121,8 +121,13 @@ CreateSystemThreads(PVOID pParam) CSR_API(SrvCreateSystemThreads) { - DPRINT1("%s not yet implemented\n", __FUNCTION__); - return STATUS_NOT_IMPLEMENTED; + NTSTATUS Status = CsrExecServerThread(CreateSystemThreads, 0); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Cannot start system thread!\n"); + } + + return Status; } CSR_API(SrvActivateDebugger) @@ -282,38 +287,6 @@ CSR_SERVER_DLL_INIT(UserServerDllInitialization) return Status; } -/*** From win32csr... See r54125 ***/ - { - HANDLE ServerThread; - CLIENT_ID ClientId; - UINT i; - - /* Start the Raw Input Thread and the Desktop Thread */ - for (i = 0; i < 2; ++i) - { - Status = RtlCreateUserThread(NtCurrentProcess(), - NULL, - TRUE, - 0, - 0, - 0, - CreateSystemThreads, - UlongToPtr(i), - &ServerThread, - &ClientId); - if (NT_SUCCESS(Status)) - { - NtResumeThread(ServerThread, NULL); - NtClose(ServerThread); - } - else - { - DPRINT1("Cannot start Raw Input Thread!\n"); - } - } - } -/*** END - From win32csr... ***/ - /* All done */ return STATUS_SUCCESS; }