mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 10:04:49 +00:00
[WIN32K]
- Implement NtUserResolveDesktop, which opens a desktop and a window station based on a desktop path string (format: "WinSta\Desktop"). - Move NtUserConsoleControl to a more suitable file, and implement the control code that allows CSRSS to assign console input threads to given desktops. - Simplify a bit the code in NtUserSetInformationThread. [CONSRV] Turn the console input thread to a real one. There should be one such thread per desktop. When a console process is started, we open the desktop on which the process is going to start, we create a new input thread (attach it to the desktop) if needed, or reuse the existing one, and then we open the terminal on the correct desktop. CORE-9346 #resolve #comment Fixed in revision 66662. svn path=/trunk/; revision=66662
This commit is contained in:
parent
3ea483bc85
commit
444d33d50b
15 changed files with 599 additions and 210 deletions
|
@ -197,7 +197,9 @@ typedef struct _CONSRV_API_CONNECTINFO
|
|||
ULONG TitleLength;
|
||||
WCHAR ConsoleTitle[MAX_PATH + 1]; // Console title or full path to the startup shortcut
|
||||
ULONG DesktopLength;
|
||||
PWCHAR Desktop;
|
||||
PWCHAR Desktop; // Contrary to the case of CONSOLE_ALLOCCONSOLE, the
|
||||
// desktop string is allocated in the process' heap,
|
||||
// and CSR will read it via NtReadVirtualMemory.
|
||||
ULONG AppNameLength;
|
||||
WCHAR AppName[128]; // Full path of the launched app
|
||||
ULONG CurDirLength;
|
||||
|
|
|
@ -100,6 +100,7 @@ list(APPEND SOURCE
|
|||
user/ntuser/caret.c
|
||||
user/ntuser/class.c
|
||||
user/ntuser/clipboard.c
|
||||
user/ntuser/console.c
|
||||
user/ntuser/csr.c
|
||||
user/ntuser/cursoricon.c
|
||||
user/ntuser/dde.c
|
||||
|
|
|
@ -1721,11 +1721,18 @@ NtUserCloseWindowStation(
|
|||
/* Console commands for NtUserConsoleControl */
|
||||
typedef enum _CONSOLECONTROL
|
||||
{
|
||||
GuiConsoleWndClassAtom,
|
||||
ConsoleCtrlDesktopConsoleThread = 0,
|
||||
GuiConsoleWndClassAtom = 1,
|
||||
ConsoleMakePalettePublic = 5,
|
||||
ConsoleAcquireDisplayOwnership,
|
||||
} CONSOLECONTROL, *PCONSOLECONTROL;
|
||||
|
||||
typedef struct _DESKTOP_CONSOLE_THREAD
|
||||
{
|
||||
HDESK DesktopHandle;
|
||||
ULONG_PTR ThreadId;
|
||||
} DESKTOP_CONSOLE_THREAD, *PDESKTOP_CONSOLE_THREAD;
|
||||
|
||||
NTSTATUS
|
||||
APIENTRY
|
||||
NtUserConsoleControl(
|
||||
|
@ -2860,13 +2867,13 @@ NtUserRemoveProp(
|
|||
HWND hWnd,
|
||||
ATOM Atom);
|
||||
|
||||
DWORD
|
||||
NTAPI
|
||||
HDESK
|
||||
APIENTRY
|
||||
NtUserResolveDesktop(
|
||||
DWORD dwUnknown1,
|
||||
DWORD dwUnknown2,
|
||||
DWORD dwUnknown3,
|
||||
DWORD dwUnknown4);
|
||||
IN HANDLE ProcessHandle,
|
||||
IN PUNICODE_STRING DesktopPath,
|
||||
DWORD dwUnknown,
|
||||
OUT HWINSTA* phWinSta);
|
||||
|
||||
DWORD
|
||||
NTAPI
|
||||
|
|
160
reactos/win32ss/user/ntuser/console.c
Normal file
160
reactos/win32ss/user/ntuser/console.c
Normal file
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Win32k subsystem
|
||||
* PURPOSE: Console support functions for CONSRV
|
||||
* FILE: subsystems/win32/win32k/ntuser/console.c
|
||||
* PROGRAMMER: Hermes Belusca-Maito (hermes.belusca@sfr.fr)
|
||||
*/
|
||||
|
||||
#include <win32k.h>
|
||||
DBG_DEFAULT_CHANNEL(UserMisc);
|
||||
|
||||
NTSTATUS
|
||||
APIENTRY
|
||||
NtUserConsoleControl(
|
||||
IN CONSOLECONTROL ConsoleCtrl,
|
||||
IN PVOID ConsoleCtrlInfo,
|
||||
IN ULONG ConsoleCtrlInfoLength)
|
||||
{
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
|
||||
/* Allow only the Console Server to perform this operation (via CSRSS) */
|
||||
if (PsGetCurrentProcess() != gpepCSRSS)
|
||||
return STATUS_ACCESS_DENIED;
|
||||
|
||||
UserEnterExclusive();
|
||||
|
||||
switch (ConsoleCtrl)
|
||||
{
|
||||
case ConsoleCtrlDesktopConsoleThread:
|
||||
{
|
||||
DESKTOP_CONSOLE_THREAD DesktopConsoleThreadInfo;
|
||||
PDESKTOP Desktop = NULL;
|
||||
ULONG_PTR OldThreadId;
|
||||
|
||||
if (ConsoleCtrlInfoLength != sizeof(DesktopConsoleThreadInfo))
|
||||
{
|
||||
Status = STATUS_INFO_LENGTH_MISMATCH;
|
||||
break;
|
||||
}
|
||||
|
||||
_SEH2_TRY
|
||||
{
|
||||
ProbeForWrite(ConsoleCtrlInfo, ConsoleCtrlInfoLength, sizeof(USHORT));
|
||||
DesktopConsoleThreadInfo = *(PDESKTOP_CONSOLE_THREAD)ConsoleCtrlInfo;
|
||||
}
|
||||
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
Status = _SEH2_GetExceptionCode();
|
||||
_SEH2_YIELD(break);
|
||||
}
|
||||
_SEH2_END;
|
||||
|
||||
/* Reference the desktop */
|
||||
Status = ObReferenceObjectByHandle(DesktopConsoleThreadInfo.DesktopHandle,
|
||||
0,
|
||||
ExDesktopObjectType,
|
||||
UserMode,
|
||||
(PVOID*)&Desktop,
|
||||
NULL);
|
||||
if (!NT_SUCCESS(Status)) break;
|
||||
|
||||
/* Save the old thread ID, it is always returned to the caller */
|
||||
OldThreadId = Desktop->dwConsoleThreadId;
|
||||
|
||||
/* Set the new console input thread ID for this desktop if required */
|
||||
if (DesktopConsoleThreadInfo.ThreadId != (ULONG_PTR)INVALID_HANDLE_VALUE)
|
||||
{
|
||||
Desktop->dwConsoleThreadId = DesktopConsoleThreadInfo.ThreadId;
|
||||
}
|
||||
|
||||
/* Always return the old thread ID */
|
||||
DesktopConsoleThreadInfo.ThreadId = OldThreadId;
|
||||
|
||||
/* Dereference the desktop */
|
||||
ObDereferenceObject(Desktop);
|
||||
|
||||
/* Return the information back to the caller */
|
||||
_SEH2_TRY
|
||||
{
|
||||
*(PDESKTOP_CONSOLE_THREAD)ConsoleCtrlInfo = DesktopConsoleThreadInfo;
|
||||
}
|
||||
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
Status = _SEH2_GetExceptionCode();
|
||||
}
|
||||
_SEH2_END;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case GuiConsoleWndClassAtom:
|
||||
{
|
||||
if (ConsoleCtrlInfoLength != sizeof(ATOM))
|
||||
{
|
||||
Status = STATUS_INFO_LENGTH_MISMATCH;
|
||||
break;
|
||||
}
|
||||
|
||||
_SEH2_TRY
|
||||
{
|
||||
ProbeForRead(ConsoleCtrlInfo, ConsoleCtrlInfoLength, sizeof(USHORT));
|
||||
gaGuiConsoleWndClass = *(ATOM*)ConsoleCtrlInfo;
|
||||
}
|
||||
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
Status = _SEH2_GetExceptionCode();
|
||||
}
|
||||
_SEH2_END;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ConsoleMakePalettePublic:
|
||||
{
|
||||
HPALETTE hPalette;
|
||||
|
||||
if (ConsoleCtrlInfoLength != sizeof(hPalette))
|
||||
{
|
||||
Status = STATUS_INFO_LENGTH_MISMATCH;
|
||||
break;
|
||||
}
|
||||
|
||||
_SEH2_TRY
|
||||
{
|
||||
ProbeForRead(ConsoleCtrlInfo, ConsoleCtrlInfoLength, sizeof(USHORT));
|
||||
hPalette = *(HPALETTE*)ConsoleCtrlInfo;
|
||||
}
|
||||
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
Status = _SEH2_GetExceptionCode();
|
||||
_SEH2_YIELD(break);
|
||||
}
|
||||
_SEH2_END;
|
||||
|
||||
/* Make the palette handle public */
|
||||
GreSetObjectOwnerEx(hPalette,
|
||||
GDI_OBJ_HMGR_PUBLIC,
|
||||
GDIOBJFLAG_IGNOREPID);
|
||||
break;
|
||||
}
|
||||
|
||||
case ConsoleAcquireDisplayOwnership:
|
||||
{
|
||||
ERR("NtUserConsoleControl - ConsoleAcquireDisplayOwnership is UNIMPLEMENTED\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
ERR("Calling invalid control %d in NtUserConsoleControl\n", ConsoleCtrl);
|
||||
Status = STATUS_INVALID_INFO_CLASS;
|
||||
break;
|
||||
}
|
||||
|
||||
UserLeave();
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* EOF */
|
|
@ -1650,6 +1650,103 @@ NtUserPaintDesktop(HDC hDC)
|
|||
return Ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* NtUserResolveDesktop
|
||||
*
|
||||
* The NtUserResolveDesktop function retrieves handles to the desktop and
|
||||
* the window station specified by the desktop path string.
|
||||
*
|
||||
* Parameters
|
||||
* ProcessHandle
|
||||
* Handle to a user process.
|
||||
*
|
||||
* DesktopPath
|
||||
* The desktop path string.
|
||||
*
|
||||
* Return Value
|
||||
* Handle to the desktop (direct return value) and
|
||||
* handle to the associated window station (by pointer).
|
||||
* NULL in case of failure.
|
||||
*
|
||||
* Remarks
|
||||
* Callable by CSRSS only.
|
||||
*
|
||||
* Status
|
||||
* @implemented
|
||||
*/
|
||||
|
||||
HDESK
|
||||
APIENTRY
|
||||
NtUserResolveDesktop(
|
||||
IN HANDLE ProcessHandle,
|
||||
IN PUNICODE_STRING DesktopPath,
|
||||
DWORD dwUnknown,
|
||||
OUT HWINSTA* phWinSta)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
PEPROCESS Process = NULL;
|
||||
HWINSTA hWinSta = NULL;
|
||||
HDESK hDesktop = NULL;
|
||||
|
||||
/* Allow only the Console Server to perform this operation (via CSRSS) */
|
||||
if (PsGetCurrentProcess() != gpepCSRSS)
|
||||
return NULL;
|
||||
|
||||
/* Get the process object the user handle was referencing */
|
||||
Status = ObReferenceObjectByHandle(ProcessHandle,
|
||||
PROCESS_QUERY_INFORMATION,
|
||||
*PsProcessType,
|
||||
UserMode,
|
||||
(PVOID*)&Process,
|
||||
NULL);
|
||||
if (!NT_SUCCESS(Status)) return NULL;
|
||||
|
||||
// UserEnterShared();
|
||||
|
||||
_SEH2_TRY
|
||||
{
|
||||
UNICODE_STRING CapturedDesktopPath;
|
||||
|
||||
/* Capture the user desktop path string */
|
||||
Status = IntSafeCopyUnicodeStringTerminateNULL(&CapturedDesktopPath,
|
||||
DesktopPath);
|
||||
if (!NT_SUCCESS(Status)) _SEH2_YIELD(goto Quit);
|
||||
|
||||
/* Call the internal function */
|
||||
Status = IntParseDesktopPath(Process,
|
||||
&CapturedDesktopPath,
|
||||
&hWinSta,
|
||||
&hDesktop);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
ERR("IntParseDesktopPath failed, Status = 0x%08lx\n", Status);
|
||||
hWinSta = NULL;
|
||||
hDesktop = NULL;
|
||||
}
|
||||
|
||||
/* Return the window station handle */
|
||||
*phWinSta = hWinSta;
|
||||
|
||||
/* Free the captured string */
|
||||
if (CapturedDesktopPath.Buffer)
|
||||
ExFreePoolWithTag(CapturedDesktopPath.Buffer, TAG_STRING);
|
||||
}
|
||||
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
Status = _SEH2_GetExceptionCode();
|
||||
}
|
||||
_SEH2_END;
|
||||
|
||||
Quit:
|
||||
// UserLeave();
|
||||
|
||||
/* Dereference the process object */
|
||||
ObDereferenceObject(Process);
|
||||
|
||||
/* Return the desktop handle */
|
||||
return hDesktop;
|
||||
}
|
||||
|
||||
/*
|
||||
* NtUserSwitchDesktop
|
||||
*
|
||||
|
|
|
@ -23,6 +23,10 @@ typedef struct _DESKTOP
|
|||
PWIN32HEAP pheapDesktop;
|
||||
ULONG_PTR ulHeapSize;
|
||||
LIST_ENTRY PtiList;
|
||||
|
||||
/* One console input thread per desktop, maintained by CONSRV */
|
||||
DWORD dwConsoleThreadId;
|
||||
|
||||
/* Use for tracking mouse moves. */
|
||||
PWND spwndTrack;
|
||||
DWORD htEx;
|
||||
|
|
|
@ -403,92 +403,6 @@ NtUserYieldTask(VOID)
|
|||
return 0;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
APIENTRY
|
||||
NtUserConsoleControl(
|
||||
IN CONSOLECONTROL ConsoleCtrl,
|
||||
IN PVOID ConsoleCtrlInfo,
|
||||
IN ULONG ConsoleCtrlInfoLength)
|
||||
{
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
|
||||
/* Allow only the Console Server to perform this operation (via CSRSS) */
|
||||
if (PsGetCurrentProcess() != gpepCSRSS)
|
||||
return STATUS_ACCESS_DENIED;
|
||||
|
||||
UserEnterExclusive();
|
||||
|
||||
switch (ConsoleCtrl)
|
||||
{
|
||||
case GuiConsoleWndClassAtom:
|
||||
{
|
||||
if (ConsoleCtrlInfoLength != sizeof(ATOM))
|
||||
{
|
||||
Status = STATUS_INFO_LENGTH_MISMATCH;
|
||||
break;
|
||||
}
|
||||
|
||||
_SEH2_TRY
|
||||
{
|
||||
ProbeForRead(ConsoleCtrlInfo, ConsoleCtrlInfoLength, 1);
|
||||
gaGuiConsoleWndClass = *(ATOM*)ConsoleCtrlInfo;
|
||||
}
|
||||
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
Status = _SEH2_GetExceptionCode();
|
||||
}
|
||||
_SEH2_END;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ConsoleMakePalettePublic:
|
||||
{
|
||||
HPALETTE hPalette;
|
||||
|
||||
if (ConsoleCtrlInfoLength != sizeof(HPALETTE))
|
||||
{
|
||||
Status = STATUS_INFO_LENGTH_MISMATCH;
|
||||
break;
|
||||
}
|
||||
|
||||
_SEH2_TRY
|
||||
{
|
||||
ProbeForRead(ConsoleCtrlInfo, ConsoleCtrlInfoLength, 1);
|
||||
hPalette = *(HPALETTE*)ConsoleCtrlInfo;
|
||||
}
|
||||
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
Status = _SEH2_GetExceptionCode();
|
||||
}
|
||||
_SEH2_END;
|
||||
|
||||
/* Make the palette handle public */
|
||||
GreSetObjectOwnerEx(hPalette,
|
||||
GDI_OBJ_HMGR_PUBLIC,
|
||||
GDIOBJFLAG_IGNOREPID);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ConsoleAcquireDisplayOwnership:
|
||||
{
|
||||
ERR("NtUserConsoleControl - ConsoleAcquireDisplayOwnership is UNIMPLEMENTED\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
ERR("Calling invalid control %d in NtUserConsoleControl\n", ConsoleCtrl);
|
||||
Status = STATUS_INVALID_INFO_CLASS;
|
||||
break;
|
||||
}
|
||||
|
||||
UserLeave();
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
DWORD
|
||||
APIENTRY
|
||||
NtUserCreateInputContext(
|
||||
|
@ -738,15 +652,10 @@ NtUserRegisterRawInputDevices(
|
|||
return 0;
|
||||
}
|
||||
|
||||
DWORD
|
||||
APIENTRY
|
||||
NtUserResolveDesktop(
|
||||
DWORD dwUnknown1,
|
||||
DWORD dwUnknown2,
|
||||
DWORD dwUnknown3,
|
||||
DWORD dwUnknown4)
|
||||
DWORD APIENTRY
|
||||
NtUserResolveDesktopForWOW(DWORD Unknown0)
|
||||
{
|
||||
STUB;
|
||||
STUB
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -811,11 +720,11 @@ NtUserSetInformationThread(IN HANDLE ThreadHandle,
|
|||
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
Status = _SEH2_GetExceptionCode();
|
||||
_SEH2_YIELD(break);
|
||||
}
|
||||
_SEH2_END;
|
||||
|
||||
if (NT_SUCCESS(Status))
|
||||
Status = UserInitiateShutdown(Thread, &CapturedFlags);
|
||||
Status = UserInitiateShutdown(Thread, &CapturedFlags);
|
||||
|
||||
/* Return the modified value to the caller */
|
||||
_SEH2_TRY
|
||||
|
@ -853,12 +762,11 @@ NtUserSetInformationThread(IN HANDLE ThreadHandle,
|
|||
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
Status = _SEH2_GetExceptionCode();
|
||||
_SEH2_YIELD(break);
|
||||
}
|
||||
_SEH2_END;
|
||||
|
||||
if (NT_SUCCESS(Status))
|
||||
Status = UserEndShutdown(Thread, ShutdownStatus);
|
||||
|
||||
Status = UserEndShutdown(Thread, ShutdownStatus);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -884,12 +792,11 @@ NtUserSetInformationThread(IN HANDLE ThreadHandle,
|
|||
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
Status = _SEH2_GetExceptionCode();
|
||||
_SEH2_YIELD(break);
|
||||
}
|
||||
_SEH2_END;
|
||||
|
||||
if (NT_SUCCESS(Status))
|
||||
Status = InitCsrApiPort(CsrPortHandle);
|
||||
|
||||
Status = InitCsrApiPort(CsrPortHandle);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1106,20 +1013,6 @@ NtUserUpdateLayeredWindow(
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* NtUserResolveDesktopForWOW
|
||||
*
|
||||
* Status
|
||||
* @unimplemented
|
||||
*/
|
||||
|
||||
DWORD APIENTRY
|
||||
NtUserResolveDesktopForWOW(DWORD Unknown0)
|
||||
{
|
||||
STUB
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* @unimplemented
|
||||
*/
|
||||
|
|
|
@ -342,7 +342,7 @@ NTSTATUS NTAPI
|
|||
ConSrvInitTerminal(IN OUT PTERMINAL Terminal,
|
||||
IN OUT PCONSOLE_INFO ConsoleInfo,
|
||||
IN OUT PVOID ExtraConsoleInfo,
|
||||
IN ULONG ProcessId);
|
||||
IN PCSR_PROCESS ConsoleLeaderProcess);
|
||||
NTSTATUS NTAPI
|
||||
ConSrvDeinitTerminal(IN OUT PTERMINAL Terminal);
|
||||
|
||||
|
@ -513,12 +513,13 @@ NTSTATUS NTAPI
|
|||
ConSrvInitConsole(OUT PHANDLE NewConsoleHandle,
|
||||
OUT PCONSRV_CONSOLE* NewConsole,
|
||||
IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo,
|
||||
IN ULONG ConsoleLeaderProcessId)
|
||||
IN PCSR_PROCESS ConsoleLeaderProcess)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
HANDLE ConsoleHandle;
|
||||
PCONSRV_CONSOLE Console;
|
||||
CONSOLE_INFO ConsoleInfo;
|
||||
ULONG ConsoleLeaderProcessId = HandleToUlong(ConsoleLeaderProcess->ClientId.UniqueProcess);
|
||||
SIZE_T Length = 0;
|
||||
|
||||
TERMINAL Terminal; /* The ConSrv terminal for this console */
|
||||
|
@ -545,7 +546,7 @@ ConSrvInitConsole(OUT PHANDLE NewConsoleHandle,
|
|||
Status = ConSrvInitTerminal(&Terminal,
|
||||
&ConsoleInfo,
|
||||
ConsoleInitInfo,
|
||||
ConsoleLeaderProcessId);
|
||||
ConsoleLeaderProcess);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("CONSRV: Failed to initialize a terminal, Status = 0x%08lx\n", Status);
|
||||
|
|
|
@ -30,7 +30,7 @@ NTSTATUS NTAPI
|
|||
ConSrvInitConsole(OUT PHANDLE NewConsoleHandle,
|
||||
OUT struct _CONSRV_CONSOLE** /* PCONSRV_CONSOLE* */ NewConsole,
|
||||
IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo,
|
||||
IN ULONG ConsoleLeaderProcessId);
|
||||
IN PCSR_PROCESS ConsoleLeaderProcess);
|
||||
VOID NTAPI ConSrvDeleteConsole(struct _CONSRV_CONSOLE* /* PCONSRV_CONSOLE */ Console);
|
||||
|
||||
NTSTATUS
|
||||
|
|
|
@ -40,6 +40,11 @@ typedef struct _GUI_CONSOLE_DATA
|
|||
HANDLE hGuiInitEvent;
|
||||
HANDLE hGuiTermEvent;
|
||||
|
||||
// HANDLE InputThreadHandle;
|
||||
ULONG_PTR InputThreadId;
|
||||
HWINSTA WinSta;
|
||||
HDESK Desktop;
|
||||
|
||||
BOOLEAN IsWindowVisible;
|
||||
|
||||
POINT OldCursor;
|
||||
|
|
|
@ -23,8 +23,8 @@
|
|||
#define CONGUI_UPDATE_TIME 0
|
||||
#define CONGUI_UPDATE_TIMER 1
|
||||
|
||||
#define PM_CREATE_CONSOLE (WM_APP + 1)
|
||||
#define PM_DESTROY_CONSOLE (WM_APP + 2)
|
||||
#define PM_CREATE_CONSOLE (WM_APP + 1)
|
||||
#define PM_DESTROY_CONSOLE (WM_APP + 2)
|
||||
|
||||
|
||||
/* GLOBALS ********************************************************************/
|
||||
|
@ -33,13 +33,15 @@ typedef struct _GUI_INIT_INFO
|
|||
{
|
||||
PCONSOLE_INFO ConsoleInfo;
|
||||
PCONSOLE_START_INFO ConsoleStartInfo;
|
||||
ULONG ProcessId;
|
||||
ULONG_PTR ProcessId;
|
||||
HANDLE GuiThreadStartupEvent;
|
||||
ULONG_PTR InputThreadId;
|
||||
HWINSTA WinSta;
|
||||
HDESK Desktop;
|
||||
BOOLEAN IsWindowVisible;
|
||||
} GUI_INIT_INFO, *PGUI_INIT_INFO;
|
||||
|
||||
static BOOL ConsInitialized = FALSE;
|
||||
static HANDLE hInputThread = NULL;
|
||||
static DWORD dwInputThreadId = 0;
|
||||
static BOOL ConsInitialized = FALSE;
|
||||
|
||||
extern HICON ghDefaultIcon;
|
||||
extern HICON ghDefaultIconSm;
|
||||
|
@ -137,20 +139,42 @@ SwitchFullScreen(PGUI_CONSOLE_DATA GuiData, BOOL FullScreen);
|
|||
VOID
|
||||
CreateSysMenu(HWND hWnd);
|
||||
|
||||
static DWORD NTAPI
|
||||
static ULONG NTAPI
|
||||
GuiConsoleInputThread(PVOID Param)
|
||||
{
|
||||
PHANDLE GraphicsStartupEvent = (PHANDLE)Param;
|
||||
NTSTATUS Status;
|
||||
PCSR_THREAD pcsrt = NULL;
|
||||
PGUI_INIT_INFO GuiInitInfo = (PGUI_INIT_INFO)Param;
|
||||
DESKTOP_CONSOLE_THREAD DesktopConsoleThreadInfo;
|
||||
ULONG_PTR InputThreadId = HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread);
|
||||
|
||||
LONG WindowCount = 0;
|
||||
MSG msg;
|
||||
|
||||
/*
|
||||
* This thread dispatches all the console notifications to the
|
||||
* notification window. It is common for all the console windows.
|
||||
* notification window. It is common for all the console windows
|
||||
* in a given desktop in a window station.
|
||||
*/
|
||||
|
||||
/* Assign this console input thread to this desktop */
|
||||
DesktopConsoleThreadInfo.DesktopHandle = GuiInitInfo->Desktop; // Duplicated desktop handle
|
||||
DesktopConsoleThreadInfo.ThreadId = InputThreadId;
|
||||
Status = NtUserConsoleControl(ConsoleCtrlDesktopConsoleThread,
|
||||
&DesktopConsoleThreadInfo,
|
||||
sizeof(DesktopConsoleThreadInfo));
|
||||
if (!NT_SUCCESS(Status)) goto Quit;
|
||||
|
||||
/* Connect this CSR thread to the USER subsystem */
|
||||
pcsrt = CsrConnectToUser();
|
||||
if (pcsrt == NULL) goto Quit;
|
||||
|
||||
/* Assign the desktop to this thread */
|
||||
if (!SetThreadDesktop(DesktopConsoleThreadInfo.DesktopHandle)) goto Quit;
|
||||
|
||||
/* The thread has been initialized, set the event */
|
||||
NtSetEvent(*GraphicsStartupEvent, NULL);
|
||||
NtSetEvent(GuiInitInfo->GuiThreadStartupEvent, NULL);
|
||||
Status = STATUS_SUCCESS;
|
||||
|
||||
while (GetMessageW(&msg, NULL, 0, 0))
|
||||
{
|
||||
|
@ -257,7 +281,7 @@ GuiConsoleInputThread(PVOID Param)
|
|||
|
||||
if (InterlockedDecrement(&WindowCount) == 0)
|
||||
{
|
||||
DPRINT("CONSRV: Going to quit the Input Thread!!\n");
|
||||
DPRINT("CONSRV: Going to quit the Input Thread 0x%p\n", InputThreadId);
|
||||
goto Quit;
|
||||
}
|
||||
|
||||
|
@ -270,19 +294,41 @@ GuiConsoleInputThread(PVOID Param)
|
|||
}
|
||||
|
||||
Quit:
|
||||
DPRINT("CONSRV: Quit the Input Thread!!\n");
|
||||
DPRINT("CONSRV: Quit the Input Thread 0x%p, Status = 0x%08lx\n", InputThreadId, Status);
|
||||
|
||||
hInputThread = NULL;
|
||||
dwInputThreadId = 0;
|
||||
/* Remove this console input thread from this desktop */
|
||||
// DesktopConsoleThreadInfo.DesktopHandle;
|
||||
DesktopConsoleThreadInfo.ThreadId = 0;
|
||||
NtUserConsoleControl(ConsoleCtrlDesktopConsoleThread,
|
||||
&DesktopConsoleThreadInfo,
|
||||
sizeof(DesktopConsoleThreadInfo));
|
||||
|
||||
return 1;
|
||||
/* Close the duplicated desktop handle */
|
||||
CloseDesktop(DesktopConsoleThreadInfo.DesktopHandle); // NtUserCloseDesktop
|
||||
|
||||
/* Cleanup CSR thread */
|
||||
if (pcsrt) CsrDereferenceThread(pcsrt);
|
||||
|
||||
/* Exit the thread */
|
||||
RtlExitUserThread(Status);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// FIXME: Maybe return a NTSTATUS
|
||||
static BOOL
|
||||
GuiInit(VOID)
|
||||
GuiInit(IN PCONSOLE_INIT_INFO ConsoleInitInfo,
|
||||
IN PCSR_PROCESS ConsoleLeaderProcess,
|
||||
IN OUT PGUI_INIT_INFO GuiInitInfo)
|
||||
{
|
||||
/* Exit if we were already initialized */
|
||||
// if (ConsInitialized) return TRUE;
|
||||
BOOL Success = TRUE;
|
||||
UNICODE_STRING DesktopPath;
|
||||
DESKTOP_CONSOLE_THREAD DesktopConsoleThreadInfo;
|
||||
HWINSTA hWinSta;
|
||||
HDESK hDesk;
|
||||
|
||||
NTSTATUS Status;
|
||||
HANDLE hInputThread;
|
||||
CLIENT_ID ClientId;
|
||||
|
||||
/*
|
||||
* Initialize and register the console window class, if needed.
|
||||
|
@ -294,39 +340,164 @@ GuiInit(VOID)
|
|||
}
|
||||
|
||||
/*
|
||||
* Set-up the console input thread
|
||||
* Set-up the console input thread. We have
|
||||
* one console input thread per desktop.
|
||||
*/
|
||||
if (hInputThread == NULL)
|
||||
|
||||
if (!CsrImpersonateClient(NULL))
|
||||
// return STATUS_BAD_IMPERSONATION_LEVEL;
|
||||
return FALSE;
|
||||
|
||||
if (ConsoleInitInfo->DesktopLength)
|
||||
{
|
||||
HANDLE GraphicsStartupEvent;
|
||||
NTSTATUS Status;
|
||||
|
||||
Status = NtCreateEvent(&GraphicsStartupEvent, EVENT_ALL_ACCESS,
|
||||
NULL, SynchronizationEvent, FALSE);
|
||||
if (!NT_SUCCESS(Status)) return FALSE;
|
||||
|
||||
hInputThread = CreateThread(NULL,
|
||||
0,
|
||||
GuiConsoleInputThread,
|
||||
(PVOID)&GraphicsStartupEvent,
|
||||
0,
|
||||
&dwInputThreadId);
|
||||
if (hInputThread == NULL)
|
||||
{
|
||||
NtClose(GraphicsStartupEvent);
|
||||
DPRINT1("CONSRV: Failed to create graphics console thread.\n");
|
||||
return FALSE;
|
||||
}
|
||||
SetThreadPriority(hInputThread, THREAD_PRIORITY_HIGHEST);
|
||||
CloseHandle(hInputThread);
|
||||
|
||||
WaitForSingleObject(GraphicsStartupEvent, INFINITE);
|
||||
NtClose(GraphicsStartupEvent);
|
||||
DesktopPath.MaximumLength = ConsoleInitInfo->DesktopLength;
|
||||
DesktopPath.Length = DesktopPath.MaximumLength - sizeof(UNICODE_NULL);
|
||||
DesktopPath.Buffer = ConsoleInitInfo->Desktop;
|
||||
}
|
||||
else
|
||||
{
|
||||
RtlInitUnicodeString(&DesktopPath, L"Default");
|
||||
}
|
||||
|
||||
// ConsInitialized = TRUE;
|
||||
hDesk = NtUserResolveDesktop(ConsoleLeaderProcess->ProcessHandle,
|
||||
&DesktopPath,
|
||||
0,
|
||||
&hWinSta);
|
||||
DPRINT("NtUserResolveDesktop(DesktopPath = '%wZ') returned hDesk = 0x%p; hWinSta = 0x%p\n",
|
||||
&DesktopPath, hDesk, hWinSta);
|
||||
|
||||
return TRUE;
|
||||
CsrRevertToSelf();
|
||||
|
||||
if (hDesk == NULL) return FALSE;
|
||||
|
||||
/*
|
||||
* We need to see whether we need to create a
|
||||
* new console input thread for this desktop.
|
||||
*/
|
||||
DesktopConsoleThreadInfo.DesktopHandle = hDesk;
|
||||
DesktopConsoleThreadInfo.ThreadId = (ULONG_PTR)INVALID_HANDLE_VALUE; // Special value to say we just want to retrieve the thread ID.
|
||||
NtUserConsoleControl(ConsoleCtrlDesktopConsoleThread,
|
||||
&DesktopConsoleThreadInfo,
|
||||
sizeof(DesktopConsoleThreadInfo));
|
||||
DPRINT("NtUserConsoleControl returned ThreadId = 0x%p\n", DesktopConsoleThreadInfo.ThreadId);
|
||||
|
||||
/*
|
||||
* Save the opened window station and desktop handles in the initialization
|
||||
* structure. They will be used later on, and released, by the GUI frontend.
|
||||
*/
|
||||
GuiInitInfo->WinSta = hWinSta;
|
||||
GuiInitInfo->Desktop = hDesk;
|
||||
|
||||
/* Here GuiInitInfo contains original handles */
|
||||
|
||||
/* If we already have a console input thread on this desktop... */
|
||||
if (DesktopConsoleThreadInfo.ThreadId != 0)
|
||||
{
|
||||
/* ... just use it... */
|
||||
DPRINT("Using input thread InputThreadId = 0x%p\n", DesktopConsoleThreadInfo.ThreadId);
|
||||
GuiInitInfo->InputThreadId = DesktopConsoleThreadInfo.ThreadId;
|
||||
goto Quit;
|
||||
}
|
||||
|
||||
/* ... otherwise create a new one. */
|
||||
|
||||
/* Initialize a startup event for the thread to signal it */
|
||||
Status = NtCreateEvent(&GuiInitInfo->GuiThreadStartupEvent, EVENT_ALL_ACCESS,
|
||||
NULL, SynchronizationEvent, FALSE);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
Success = FALSE;
|
||||
goto Quit;
|
||||
}
|
||||
|
||||
/*
|
||||
* Duplicate the desktop handle for the console input thread internal needs.
|
||||
* If it happens to need also a window station handle in the future, then
|
||||
* it is there that you also need to duplicate the window station handle!
|
||||
*
|
||||
* Note also that we are going to temporarily overwrite the stored handles
|
||||
* in GuiInitInfo because it happens that we use also this structure to give
|
||||
* the duplicated handles to the input thread that is going to initialize.
|
||||
* After the input thread finishes its initialization, we restore the handles
|
||||
* in GuiInitInfo to their old values.
|
||||
*/
|
||||
Status = NtDuplicateObject(NtCurrentProcess(),
|
||||
hDesk,
|
||||
NtCurrentProcess(),
|
||||
(PHANDLE)&GuiInitInfo->Desktop,
|
||||
0, 0, DUPLICATE_SAME_ACCESS);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
Success = FALSE;
|
||||
goto Quit;
|
||||
}
|
||||
|
||||
/* Here GuiInitInfo contains duplicated handles */
|
||||
|
||||
Status = RtlCreateUserThread(NtCurrentProcess(),
|
||||
NULL,
|
||||
TRUE, // Start the thread in suspended state
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
(PVOID)GuiConsoleInputThread,
|
||||
(PVOID)GuiInitInfo,
|
||||
&hInputThread,
|
||||
&ClientId);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
/* Add it as a static server thread and resume it */
|
||||
CsrAddStaticServerThread(hInputThread, &ClientId, 0);
|
||||
Status = NtResumeThread(hInputThread, NULL);
|
||||
}
|
||||
DPRINT("Thread creation hInputThread = 0x%p, InputThreadId = 0x%p, Status = 0x%08lx\n",
|
||||
hInputThread, ClientId.UniqueThread, Status);
|
||||
|
||||
if (!NT_SUCCESS(Status) || hInputThread == NULL)
|
||||
{
|
||||
/* Close the thread's handle */
|
||||
if (hInputThread) NtClose(hInputThread);
|
||||
|
||||
/* We need to close here the duplicated desktop handle */
|
||||
CloseDesktop(GuiInitInfo->Desktop); // NtUserCloseDesktop
|
||||
|
||||
/* Close the startup event and bail out */
|
||||
NtClose(GuiInitInfo->GuiThreadStartupEvent);
|
||||
|
||||
DPRINT1("CONSRV: Failed to create graphics console thread.\n");
|
||||
Success = FALSE;
|
||||
goto Quit;
|
||||
}
|
||||
|
||||
/* No need to close hInputThread, this is done by CSR automatically */
|
||||
|
||||
/* Wait for the thread to finish its initialization, and close the startup event */
|
||||
NtWaitForSingleObject(GuiInitInfo->GuiThreadStartupEvent, FALSE, NULL);
|
||||
NtClose(GuiInitInfo->GuiThreadStartupEvent);
|
||||
|
||||
/*
|
||||
* Save the input thread ID for later use, and restore the original handles.
|
||||
* The copies are held by the console input thread.
|
||||
*/
|
||||
GuiInitInfo->InputThreadId = (ULONG_PTR)ClientId.UniqueThread;
|
||||
GuiInitInfo->WinSta = hWinSta;
|
||||
GuiInitInfo->Desktop = hDesk;
|
||||
|
||||
/* Here GuiInitInfo contains again original handles */
|
||||
|
||||
Quit:
|
||||
if (!Success)
|
||||
{
|
||||
/*
|
||||
* Close the original handles. Do not use the copies in GuiInitInfo
|
||||
* because we may have failed in the middle of the duplicate operation
|
||||
* and the handles stored in GuiInitInfo may have changed.
|
||||
*/
|
||||
CloseDesktop(hDesk); // NtUserCloseDesktop
|
||||
CloseWindowStation(hWinSta); // NtUserCloseWindowStation
|
||||
}
|
||||
|
||||
return Success;
|
||||
}
|
||||
|
||||
|
||||
|
@ -362,7 +533,7 @@ GuiInitFrontEnd(IN OUT PFRONTEND This,
|
|||
ConsoleStartInfo = GuiInitInfo->ConsoleStartInfo;
|
||||
|
||||
/* Terminal data allocation */
|
||||
GuiData = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(GUI_CONSOLE_DATA));
|
||||
GuiData = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(*GuiData));
|
||||
if (!GuiData)
|
||||
{
|
||||
DPRINT1("CONSRV: Failed to create GUI_CONSOLE_DATA\n");
|
||||
|
@ -471,9 +642,13 @@ GuiInitFrontEnd(IN OUT PFRONTEND This,
|
|||
GuiData->LineSelection = FALSE; // Default to block selection
|
||||
// TODO: Retrieve the selection mode via the registry.
|
||||
|
||||
GuiData->InputThreadId = GuiInitInfo->InputThreadId;
|
||||
GuiData->WinSta = GuiInitInfo->WinSta;
|
||||
GuiData->Desktop = GuiInitInfo->Desktop;
|
||||
|
||||
/* Finally, finish to initialize the frontend structure */
|
||||
This->Context = GuiData;
|
||||
if (This->Context2) ConsoleFreeHeap(This->Context2);
|
||||
ConsoleFreeHeap(This->Context2);
|
||||
This->Context2 = NULL;
|
||||
|
||||
/*
|
||||
|
@ -490,10 +665,10 @@ GuiInitFrontEnd(IN OUT PFRONTEND This,
|
|||
DPRINT("GUI - Checkpoint\n");
|
||||
|
||||
/* Create the terminal window */
|
||||
PostThreadMessageW(dwInputThreadId, PM_CREATE_CONSOLE, 0, (LPARAM)GuiData);
|
||||
PostThreadMessageW(GuiData->InputThreadId, PM_CREATE_CONSOLE, 0, (LPARAM)GuiData);
|
||||
|
||||
/* Wait until initialization has finished */
|
||||
WaitForSingleObject(GuiData->hGuiInitEvent, INFINITE);
|
||||
NtWaitForSingleObject(GuiData->hGuiInitEvent, FALSE, NULL);
|
||||
DPRINT("OK we created the console window\n");
|
||||
NtClose(GuiData->hGuiInitEvent);
|
||||
GuiData->hGuiInitEvent = NULL;
|
||||
|
@ -515,12 +690,15 @@ GuiDeinitFrontEnd(IN OUT PFRONTEND This)
|
|||
PGUI_CONSOLE_DATA GuiData = This->Context;
|
||||
|
||||
DPRINT("Send PM_DESTROY_CONSOLE message and wait on hGuiTermEvent...\n");
|
||||
PostThreadMessageW(dwInputThreadId, PM_DESTROY_CONSOLE, 0, (LPARAM)GuiData);
|
||||
WaitForSingleObject(GuiData->hGuiTermEvent, INFINITE);
|
||||
PostThreadMessageW(GuiData->InputThreadId, PM_DESTROY_CONSOLE, 0, (LPARAM)GuiData);
|
||||
NtWaitForSingleObject(GuiData->hGuiTermEvent, FALSE, NULL);
|
||||
DPRINT("hGuiTermEvent set\n");
|
||||
NtClose(GuiData->hGuiTermEvent);
|
||||
GuiData->hGuiTermEvent = NULL;
|
||||
|
||||
CloseDesktop(GuiData->Desktop); // NtUserCloseDesktop
|
||||
CloseWindowStation(GuiData->WinSta); // NtUserCloseWindowStation
|
||||
|
||||
DPRINT("Destroying icons !! - GuiData->hIcon = 0x%p ; ghDefaultIcon = 0x%p ; GuiData->hIconSm = 0x%p ; ghDefaultIconSm = 0x%p\n",
|
||||
GuiData->hIcon, ghDefaultIcon, GuiData->hIconSm, ghDefaultIconSm);
|
||||
if (GuiData->hIcon != NULL && GuiData->hIcon != ghDefaultIcon)
|
||||
|
@ -897,9 +1075,9 @@ GuiGetSelectionInfo(IN OUT PFRONTEND This,
|
|||
|
||||
if (pSelectionInfo == NULL) return FALSE;
|
||||
|
||||
ZeroMemory(pSelectionInfo, sizeof(CONSOLE_SELECTION_INFO));
|
||||
ZeroMemory(pSelectionInfo, sizeof(*pSelectionInfo));
|
||||
if (GuiData->Selection.dwFlags != CONSOLE_NO_SELECTION)
|
||||
RtlCopyMemory(pSelectionInfo, &GuiData->Selection, sizeof(CONSOLE_SELECTION_INFO));
|
||||
RtlCopyMemory(pSelectionInfo, &GuiData->Selection, sizeof(*pSelectionInfo));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -1074,7 +1252,7 @@ NTSTATUS NTAPI
|
|||
GuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd,
|
||||
IN OUT PCONSOLE_INFO ConsoleInfo,
|
||||
IN OUT PVOID ExtraConsoleInfo,
|
||||
IN ULONG ProcessId)
|
||||
IN PCSR_PROCESS ConsoleLeaderProcess)
|
||||
{
|
||||
PCONSOLE_INIT_INFO ConsoleInitInfo = ExtraConsoleInfo;
|
||||
PGUI_INIT_INFO GuiInitInfo;
|
||||
|
@ -1082,21 +1260,25 @@ GuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd,
|
|||
if (FrontEnd == NULL || ConsoleInfo == NULL || ConsoleInitInfo == NULL)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
/* Initialize GUI terminal emulator common functionalities */
|
||||
if (!GuiInit()) return STATUS_UNSUCCESSFUL;
|
||||
|
||||
/*
|
||||
* Initialize a private initialization info structure for later use.
|
||||
* It must be freed by a call to GuiUnloadFrontEnd or GuiInitFrontEnd.
|
||||
*/
|
||||
GuiInitInfo = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(GUI_INIT_INFO));
|
||||
GuiInitInfo = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(*GuiInitInfo));
|
||||
if (GuiInitInfo == NULL) return STATUS_NO_MEMORY;
|
||||
|
||||
/* Initialize GUI terminal emulator common functionalities */
|
||||
if (!GuiInit(ConsoleInitInfo, ConsoleLeaderProcess, GuiInitInfo))
|
||||
{
|
||||
ConsoleFreeHeap(GuiInitInfo);
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
// HACK: We suppose that the pointers will be valid in GuiInitFrontEnd...
|
||||
// If not, then copy exactly what we need in GuiInitInfo.
|
||||
GuiInitInfo->ConsoleInfo = ConsoleInfo;
|
||||
GuiInitInfo->ConsoleStartInfo = ConsoleInitInfo->ConsoleStartInfo;
|
||||
GuiInitInfo->ProcessId = ProcessId;
|
||||
GuiInitInfo->ProcessId = HandleToUlong(ConsoleLeaderProcess->ClientId.UniqueProcess);
|
||||
GuiInitInfo->IsWindowVisible = ConsoleInitInfo->IsWindowVisible;
|
||||
|
||||
/* Finally, initialize the frontend structure */
|
||||
|
|
|
@ -96,7 +96,7 @@ NTSTATUS NTAPI
|
|||
TuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd,
|
||||
IN OUT PCONSOLE_INFO ConsoleInfo,
|
||||
IN OUT PVOID ExtraConsoleInfo,
|
||||
IN ULONG ProcessId);
|
||||
IN PCSR_PROCESS ConsoleLeaderProcess);
|
||||
NTSTATUS NTAPI
|
||||
TuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd);
|
||||
#endif
|
||||
|
@ -105,7 +105,7 @@ NTSTATUS NTAPI
|
|||
GuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd,
|
||||
IN OUT PCONSOLE_INFO ConsoleInfo,
|
||||
IN OUT PVOID ExtraConsoleInfo,
|
||||
IN ULONG ProcessId);
|
||||
IN PCSR_PROCESS ConsoleLeaderProcess);
|
||||
NTSTATUS NTAPI
|
||||
GuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd);
|
||||
/***************/
|
||||
|
@ -114,7 +114,7 @@ typedef
|
|||
NTSTATUS (NTAPI *FRONTEND_LOAD)(IN OUT PFRONTEND FrontEnd,
|
||||
IN OUT PCONSOLE_INFO ConsoleInfo,
|
||||
IN OUT PVOID ExtraConsoleInfo,
|
||||
IN ULONG ProcessId);
|
||||
IN PCSR_PROCESS ConsoleLeaderProcess);
|
||||
|
||||
typedef
|
||||
NTSTATUS (NTAPI *FRONTEND_UNLOAD)(IN OUT PFRONTEND FrontEnd);
|
||||
|
@ -156,7 +156,7 @@ static NTSTATUS
|
|||
ConSrvLoadFrontEnd(IN OUT PFRONTEND FrontEnd,
|
||||
IN OUT PCONSOLE_INFO ConsoleInfo,
|
||||
IN OUT PVOID ExtraConsoleInfo,
|
||||
IN ULONG ProcessId)
|
||||
IN PCSR_PROCESS ConsoleLeaderProcess)
|
||||
{
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
ULONG i;
|
||||
|
@ -171,7 +171,7 @@ ConSrvLoadFrontEnd(IN OUT PFRONTEND FrontEnd,
|
|||
Status = FrontEndLoadingMethods[i].FrontEndLoad(FrontEnd,
|
||||
ConsoleInfo,
|
||||
ExtraConsoleInfo,
|
||||
ProcessId);
|
||||
ConsoleLeaderProcess);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
/* Save the unload callback */
|
||||
|
@ -206,7 +206,7 @@ NTSTATUS NTAPI
|
|||
ConSrvInitTerminal(IN OUT PTERMINAL Terminal,
|
||||
IN OUT PCONSOLE_INFO ConsoleInfo,
|
||||
IN OUT PVOID ExtraConsoleInfo,
|
||||
IN ULONG ProcessId)
|
||||
IN PCSR_PROCESS ConsoleLeaderProcess)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
PFRONTEND FrontEnd;
|
||||
|
@ -218,7 +218,7 @@ ConSrvInitTerminal(IN OUT PTERMINAL Terminal,
|
|||
Status = ConSrvLoadFrontEnd(FrontEnd,
|
||||
ConsoleInfo,
|
||||
ExtraConsoleInfo,
|
||||
ProcessId);
|
||||
ConsoleLeaderProcess);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("CONSRV: Failed to initialize a frontend, Status = 0x%08lx\n", Status);
|
||||
|
|
|
@ -942,7 +942,7 @@ NTSTATUS NTAPI
|
|||
TuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd,
|
||||
IN OUT PCONSOLE_INFO ConsoleInfo,
|
||||
IN OUT PVOID ExtraConsoleInfo,
|
||||
IN ULONG ProcessId)
|
||||
IN PCSR_PROCESS ConsoleLeaderProcess)
|
||||
{
|
||||
if (FrontEnd == NULL || ConsoleInfo == NULL)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
|
|
@ -494,10 +494,14 @@ ConSrvAllocateConsole(PCONSOLE_PROCESS_DATA ProcessData,
|
|||
ConSrvFreeHandlesTable(ProcessData);
|
||||
|
||||
/* Initialize a new Console owned by this process */
|
||||
DPRINT("Initialization of console '%S' for process '%S' on desktop '%S'\n",
|
||||
ConsoleInitInfo->ConsoleTitle ? ConsoleInitInfo->ConsoleTitle : L"n/a",
|
||||
ConsoleInitInfo->AppName ? ConsoleInitInfo->AppName : L"n/a",
|
||||
ConsoleInitInfo->Desktop ? ConsoleInitInfo->Desktop : L"n/a");
|
||||
Status = ConSrvInitConsole(&ConsoleHandle,
|
||||
&Console,
|
||||
ConsoleInitInfo,
|
||||
HandleToUlong(ProcessData->Process->ClientId.UniqueProcess));
|
||||
ProcessData->Process);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Console initialization failed\n");
|
||||
|
|
|
@ -414,7 +414,6 @@ ConSrvConnect(IN PCSR_PROCESS CsrProcess,
|
|||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
PCONSRV_API_CONNECTINFO ConnectInfo = (PCONSRV_API_CONNECTINFO)ConnectionInfo;
|
||||
PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrProcess);
|
||||
CONSOLE_INIT_INFO ConsoleInitInfo;
|
||||
|
||||
if ( ConnectionInfo == NULL ||
|
||||
ConnectionInfoLength == NULL ||
|
||||
|
@ -433,23 +432,51 @@ ConSrvConnect(IN PCSR_PROCESS CsrProcess,
|
|||
DPRINT("ConnectInfo->IsConsoleApp = %s\n", ConnectInfo->IsConsoleApp ? "True" : "False");
|
||||
if (!ConnectInfo->IsConsoleApp) return STATUS_SUCCESS;
|
||||
|
||||
/* Initialize the console initialization info structure */
|
||||
ConsoleInitInfo.ConsoleStartInfo = &ConnectInfo->ConsoleStartInfo;
|
||||
ConsoleInitInfo.IsWindowVisible = ConnectInfo->IsWindowVisible;
|
||||
ConsoleInitInfo.TitleLength = ConnectInfo->TitleLength;
|
||||
ConsoleInitInfo.ConsoleTitle = ConnectInfo->ConsoleTitle;
|
||||
ConsoleInitInfo.DesktopLength = ConnectInfo->DesktopLength;
|
||||
ConsoleInitInfo.Desktop = ConnectInfo->Desktop;
|
||||
ConsoleInitInfo.AppNameLength = ConnectInfo->AppNameLength;
|
||||
ConsoleInitInfo.AppName = ConnectInfo->AppName;
|
||||
ConsoleInitInfo.CurDirLength = ConnectInfo->CurDirLength;
|
||||
ConsoleInitInfo.CurDir = ConnectInfo->CurDir;
|
||||
|
||||
/* If we don't inherit from an existing console, then create a new one... */
|
||||
if (ConnectInfo->ConsoleStartInfo.ConsoleHandle == NULL)
|
||||
{
|
||||
CONSOLE_INIT_INFO ConsoleInitInfo;
|
||||
|
||||
DPRINT("ConSrvConnect - Allocate a new console\n");
|
||||
|
||||
/* Initialize the console initialization info structure */
|
||||
ConsoleInitInfo.ConsoleStartInfo = &ConnectInfo->ConsoleStartInfo;
|
||||
ConsoleInitInfo.IsWindowVisible = ConnectInfo->IsWindowVisible;
|
||||
ConsoleInitInfo.TitleLength = ConnectInfo->TitleLength;
|
||||
ConsoleInitInfo.ConsoleTitle = ConnectInfo->ConsoleTitle;
|
||||
ConsoleInitInfo.DesktopLength = 0;
|
||||
ConsoleInitInfo.Desktop = NULL;
|
||||
ConsoleInitInfo.AppNameLength = ConnectInfo->AppNameLength;
|
||||
ConsoleInitInfo.AppName = ConnectInfo->AppName;
|
||||
ConsoleInitInfo.CurDirLength = ConnectInfo->CurDirLength;
|
||||
ConsoleInitInfo.CurDir = ConnectInfo->CurDir;
|
||||
|
||||
/*
|
||||
* Contrary to the case of SrvAllocConsole, the desktop string is
|
||||
* allocated in the process' heap, so we need to retrieve it by
|
||||
* using NtReadVirtualMemory.
|
||||
*/
|
||||
if (ConnectInfo->DesktopLength)
|
||||
{
|
||||
ConsoleInitInfo.DesktopLength = ConnectInfo->DesktopLength;
|
||||
|
||||
ConsoleInitInfo.Desktop = ConsoleAllocHeap(HEAP_ZERO_MEMORY,
|
||||
ConsoleInitInfo.DesktopLength);
|
||||
if (ConsoleInitInfo.Desktop == NULL)
|
||||
return STATUS_NO_MEMORY;
|
||||
|
||||
Status = NtReadVirtualMemory(ProcessData->Process->ProcessHandle,
|
||||
ConnectInfo->Desktop,
|
||||
ConsoleInitInfo.Desktop,
|
||||
ConsoleInitInfo.DesktopLength,
|
||||
NULL);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
ConsoleFreeHeap(ConsoleInitInfo.Desktop);
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We are about to create a new console. However when ConSrvNewProcess
|
||||
* was called, we didn't know that we wanted to create a new console and
|
||||
|
@ -467,6 +494,12 @@ ConSrvConnect(IN PCSR_PROCESS CsrProcess,
|
|||
&ConnectInfo->ConsoleStartInfo.OutputHandle,
|
||||
&ConnectInfo->ConsoleStartInfo.ErrorHandle,
|
||||
&ConsoleInitInfo);
|
||||
|
||||
/* Free our local desktop string if any */
|
||||
if (ConsoleInitInfo.DesktopLength)
|
||||
ConsoleFreeHeap(ConsoleInitInfo.Desktop);
|
||||
|
||||
/* Check for success */
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Console allocation failed\n");
|
||||
|
|
Loading…
Reference in a new issue