465 lines
20 KiB
C
465 lines
20 KiB
C
// RSSRV interactive-session policy. Session 0 owns display routing, activation, focus, pointer capture, and DWM authority.
|
|
|
|
#include "rssrv_internal.h"
|
|
#include <ntlite/internal/session_control.h>
|
|
#include <ntlite/port.h>
|
|
#include <string.h>
|
|
|
|
#define RSSRV_SESSION_ZERO_PATH "/Sessions/0"
|
|
#define RSSRV_SESSION_ZERO_CONSOLE_PATH "/Sessions/0/Console"
|
|
#define RSSRV_CURRENT_CONSOLE_PATH "/Console"
|
|
#define RSSRV_DWM_LISTENER_BACKLOG 1u
|
|
|
|
// Acquires the session-state mutex.
|
|
static KSTATUS RssrvSessionLock(RSSRV_SESSION_STATE* session) {
|
|
if (!session || session->Mutex == SYS_HANDLE_INVALID) return NTLSTATUS_INVALID_PARAMETER;
|
|
return SysWait(session->Mutex, SYS_WAIT_FLAG_NONE);
|
|
}
|
|
|
|
// Releases the session-state mutex.
|
|
static void RssrvSessionUnlock(RSSRV_SESSION_STATE* session) {
|
|
if (session && session->Mutex != SYS_HANDLE_INVALID) (void)SysReleaseMutex(session->Mutex);
|
|
}
|
|
|
|
// Advances the session generation while preserving zero as an uninitialized value.
|
|
static void RssrvSessionChangedLocked(RSSRV_SESSION_STATE* session) {
|
|
session->Generation++;
|
|
if (session->Generation == 0) session->Generation = 1;
|
|
}
|
|
|
|
// Sends one best-effort DWM input notification while holding the session mutex.
|
|
static void RssrvSessionSendDwmEventLocked(RSSRV_SESSION_STATE* session,
|
|
uint32_t type,
|
|
const INPUT_KEY_RECORD* key,
|
|
const INPUT_MOUSE_EVENT* mouse,
|
|
int32_t x,
|
|
int32_t y) {
|
|
if (!session || session->DwmEndpoint == SYS_HANDLE_INVALID) return;
|
|
|
|
NTL_SESSION_DWM_EVENT event;
|
|
memset(&event, 0, sizeof(event));
|
|
event.Size = sizeof(event);
|
|
event.Version = NTL_SESSION_DWM_PROTOCOL_VERSION;
|
|
event.Type = type;
|
|
event.Flags = NTL_SESSION_DWM_FLAG_NONE;
|
|
event.PointerX = x;
|
|
event.PointerY = y;
|
|
if (key) event.Key = *key;
|
|
if (mouse) event.Mouse = *mouse;
|
|
|
|
SYS_SEND_PORT_REQUEST send;
|
|
memset(&send, 0, sizeof(send));
|
|
send.Size = sizeof(send);
|
|
send.EndpointHandle = session->DwmEndpoint;
|
|
send.Flags = SYS_PORT_FLAG_NONE;
|
|
send.Payload = &event;
|
|
send.PayloadLength = sizeof(event);
|
|
send.TimeoutMilliseconds = 0;
|
|
(void)SysSendPort(&send);
|
|
}
|
|
|
|
// Routes one focused keyboard record into the connected DWM desktop target.
|
|
static void RssrvSessionDwmRouteKey(void* context, const INPUT_KEY_RECORD* record) {
|
|
RSSRV_SESSION_STATE* session = (RSSRV_SESSION_STATE*)context;
|
|
if (!session || !record) return;
|
|
if (!KSUCCESS(RssrvSessionLock(session))) return;
|
|
RssrvSessionSendDwmEventLocked(session, NTL_SESSION_DWM_EVENT_DELIVER_KEY, record, 0, 0, 0);
|
|
RssrvSessionUnlock(session);
|
|
}
|
|
|
|
// Routes one focused/captured mouse record into the connected DWM desktop target.
|
|
static void RssrvSessionDwmRouteMouse(void* context,
|
|
const INPUT_MOUSE_EVENT* event,
|
|
int32_t x,
|
|
int32_t y) {
|
|
RSSRV_SESSION_STATE* session = (RSSRV_SESSION_STATE*)context;
|
|
if (!session || !event) return;
|
|
if (!KSUCCESS(RssrvSessionLock(session))) return;
|
|
RssrvSessionSendDwmEventLocked(session, NTL_SESSION_DWM_EVENT_DELIVER_MOUSE, 0, event, x, y);
|
|
RssrvSessionUnlock(session);
|
|
}
|
|
|
|
// Replies to one private DWM session-control request.
|
|
static void RssrvSessionReplyDwm(SYS_HANDLE endpoint,
|
|
uint32_t messageId,
|
|
uint32_t operation,
|
|
KSTATUS status) {
|
|
NTL_SESSION_DWM_REPLY reply;
|
|
memset(&reply, 0, sizeof(reply));
|
|
reply.Size = sizeof(reply);
|
|
reply.Version = NTL_SESSION_DWM_PROTOCOL_VERSION;
|
|
reply.Operation = operation;
|
|
reply.Flags = NTL_SESSION_DWM_FLAG_NONE;
|
|
reply.Status = status;
|
|
|
|
SYS_REPLY_PORT_REQUEST send;
|
|
memset(&send, 0, sizeof(send));
|
|
send.Size = sizeof(send);
|
|
send.EndpointHandle = endpoint;
|
|
send.MessageId = messageId;
|
|
send.Flags = SYS_PORT_FLAG_NONE;
|
|
send.Payload = &reply;
|
|
send.PayloadLength = sizeof(reply);
|
|
(void)SysReplyPort(&send);
|
|
}
|
|
|
|
// Applies one DWM focus/capture request while preserving RSSRV as the session authority owner.
|
|
static KSTATUS RssrvSessionApplyDwmRequest(RSSRV_SESSION_STATE* session,
|
|
const NTL_SESSION_DWM_REQUEST* request) {
|
|
if (!session || !request || request->Enabled > 1u) return NTLSTATUS_INVALID_PARAMETER;
|
|
KSTATUS status = RssrvSessionLock(session);
|
|
if (!KSUCCESS(status)) return status;
|
|
|
|
RSSRV_INPUT_TARGET* desktop = &session->DesktopTarget;
|
|
RSSRV_INPUT_TARGET* fallback = session->ActiveTarget == desktop ? (RSSRV_INPUT_TARGET*)0 : session->ActiveTarget;
|
|
switch (request->Operation) {
|
|
case NTL_SESSION_DWM_OP_SET_KEYBOARD_FOCUS:
|
|
if (request->Enabled) {
|
|
if (session->KeyboardFocus != desktop) {
|
|
session->KeyboardFocus = desktop;
|
|
RssrvSessionChangedLocked(session);
|
|
}
|
|
} else if (session->KeyboardFocus == desktop) {
|
|
session->KeyboardFocus = fallback;
|
|
RssrvSessionChangedLocked(session);
|
|
}
|
|
break;
|
|
case NTL_SESSION_DWM_OP_SET_POINTER_FOCUS:
|
|
if (request->Enabled) {
|
|
if (session->PointerFocus != desktop) {
|
|
session->PointerFocus = desktop;
|
|
RssrvSessionChangedLocked(session);
|
|
}
|
|
} else if (session->PointerFocus == desktop) {
|
|
session->PointerFocus = fallback;
|
|
RssrvSessionChangedLocked(session);
|
|
}
|
|
break;
|
|
case NTL_SESSION_DWM_OP_SET_POINTER_CAPTURE:
|
|
if (request->Enabled) {
|
|
if (session->PointerCapture != desktop) {
|
|
session->PointerCapture = desktop;
|
|
RssrvSessionChangedLocked(session);
|
|
}
|
|
} else if (session->PointerCapture == desktop) {
|
|
session->PointerCapture = (RSSRV_INPUT_TARGET*)0;
|
|
RssrvSessionChangedLocked(session);
|
|
}
|
|
break;
|
|
default:
|
|
status = NTLSTATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
RssrvSessionUnlock(session);
|
|
return status;
|
|
}
|
|
|
|
// Restores non-DWM routing after one DWM control connection disappears.
|
|
static void RssrvSessionDisconnectDwm(RSSRV_SESSION_STATE* session, SYS_HANDLE endpoint) {
|
|
if (!session) return;
|
|
if (!KSUCCESS(RssrvSessionLock(session))) return;
|
|
if (session->DwmEndpoint == endpoint) {
|
|
RSSRV_INPUT_TARGET* desktop = &session->DesktopTarget;
|
|
RSSRV_INPUT_TARGET* fallback = session->ActiveTarget == desktop ? (RSSRV_INPUT_TARGET*)0 : session->ActiveTarget;
|
|
if (session->KeyboardFocus == desktop) session->KeyboardFocus = fallback;
|
|
if (session->PointerFocus == desktop) session->PointerFocus = fallback;
|
|
if (session->PointerCapture == desktop) session->PointerCapture = (RSSRV_INPUT_TARGET*)0;
|
|
session->DwmEndpoint = SYS_HANDLE_INVALID;
|
|
RssrvSessionChangedLocked(session);
|
|
}
|
|
RssrvSessionUnlock(session);
|
|
}
|
|
|
|
// Accepts replaceable DWM connections and serves the private Session 0 authority protocol.
|
|
static void RssrvSessionDwmListenerThread(uintptr_t argument) {
|
|
RSSRV_SESSION_STATE* session = (RSSRV_SESSION_STATE*)argument;
|
|
RssrvSetCurrentThreadName("rssrv.session.dwm");
|
|
if (!session) SysExitThread(1);
|
|
|
|
for (;;) {
|
|
SYS_HANDLE endpoint = SYS_HANDLE_INVALID;
|
|
SYS_ACCEPT_PORT_REQUEST accept;
|
|
memset(&accept, 0, sizeof(accept));
|
|
accept.Size = sizeof(accept);
|
|
accept.ListenerHandle = session->DwmListener;
|
|
accept.Flags = SYS_PORT_ACCEPT_FLAG_NONE;
|
|
accept.TimeoutMilliseconds = SYS_PORT_TIMEOUT_INFINITE;
|
|
accept.EndpointHandleOut = &endpoint;
|
|
KSTATUS status = SysAcceptPort(&accept);
|
|
if (!KSUCCESS(status)) RssrvExit(16);
|
|
|
|
status = RssrvSessionLock(session);
|
|
if (!KSUCCESS(status)) {
|
|
(void)SysCloseHandle(endpoint);
|
|
continue;
|
|
}
|
|
if (session->DwmEndpoint != SYS_HANDLE_INVALID) {
|
|
RssrvSessionUnlock(session);
|
|
(void)SysDisconnectPort(endpoint);
|
|
(void)SysCloseHandle(endpoint);
|
|
continue;
|
|
}
|
|
session->DwmEndpoint = endpoint;
|
|
RssrvSessionChangedLocked(session);
|
|
RssrvSessionUnlock(session);
|
|
|
|
for (;;) {
|
|
NTL_SESSION_DWM_REQUEST request;
|
|
SYS_PORT_MESSAGE_INFO info;
|
|
memset(&request, 0, sizeof(request));
|
|
memset(&info, 0, sizeof(info));
|
|
info.Size = sizeof(info);
|
|
SYS_RECEIVE_PORT_REQUEST receive;
|
|
memset(&receive, 0, sizeof(receive));
|
|
receive.Size = sizeof(receive);
|
|
receive.EndpointHandle = endpoint;
|
|
receive.Flags = SYS_PORT_FLAG_NONE;
|
|
receive.Payload = &request;
|
|
receive.PayloadCapacity = sizeof(request);
|
|
receive.InfoOut = &info;
|
|
receive.TimeoutMilliseconds = SYS_PORT_TIMEOUT_INFINITE;
|
|
status = SysReceivePort(&receive);
|
|
if (status == NTLSTATUS_PORT_DISCONNECTED || !KSUCCESS(status)) break;
|
|
|
|
if (info.Type != SYS_PORT_MESSAGE_REQUEST || info.HandleCount != 0 ||
|
|
info.PayloadLength != sizeof(request) || request.Size != sizeof(request) ||
|
|
request.Version != NTL_SESSION_DWM_PROTOCOL_VERSION ||
|
|
request.Flags != NTL_SESSION_DWM_FLAG_NONE || request.Reserved[0] != 0 ||
|
|
request.Reserved[1] != 0 || request.Reserved[2] != 0) {
|
|
RssrvSessionReplyDwm(endpoint, info.MessageId, request.Operation, NTLSTATUS_INVALID_PARAMETER);
|
|
continue;
|
|
}
|
|
|
|
status = RssrvSessionApplyDwmRequest(session, &request);
|
|
RssrvSessionReplyDwm(endpoint, info.MessageId, request.Operation, status);
|
|
}
|
|
|
|
RssrvSessionDisconnectDwm(session, endpoint);
|
|
(void)SysDisconnectPort(endpoint);
|
|
(void)SysCloseHandle(endpoint);
|
|
}
|
|
}
|
|
|
|
// Initializes Session 0 and creates the private listener that init may delegate only to DWM.
|
|
KSTATUS RssrvSessionInitialize(RSSRV_SESSION_STATE* session,
|
|
RSSRV_NAMESPACE* namespaceState,
|
|
RSSRV_DISPLAY_STATE* display) {
|
|
if (!session || !namespaceState || !display) return NTLSTATUS_INVALID_PARAMETER;
|
|
memset(session, 0, sizeof(*session));
|
|
session->Mutex = SYS_HANDLE_INVALID;
|
|
session->DwmListener = SYS_HANDLE_INVALID;
|
|
session->DwmEndpoint = SYS_HANDLE_INVALID;
|
|
session->Namespace = namespaceState;
|
|
session->Display = display;
|
|
session->Id = 0;
|
|
session->Generation = 1;
|
|
session->NextTargetId = 1;
|
|
|
|
SYS_DISPLAY_INFO info;
|
|
memset(&info, 0, sizeof(info));
|
|
KSTATUS status = RssrvDisplayQueryInfo(display, &info);
|
|
if (!KSUCCESS(status)) return status;
|
|
session->DisplayWidth = info.Mode.Width ? (int32_t)info.Mode.Width : 1;
|
|
session->DisplayHeight = info.Mode.Height ? (int32_t)info.Mode.Height : 1;
|
|
|
|
status = SysCreateMutex(&session->Mutex);
|
|
if (!KSUCCESS(status)) return status;
|
|
status = RssrvNamespaceCreateDirectory(namespaceState,
|
|
RSSRV_SESSION_ZERO_PATH,
|
|
sizeof(RSSRV_SESSION_ZERO_PATH) - 1u);
|
|
if (!KSUCCESS(status)) return status;
|
|
|
|
SYS_CREATE_PORT_REQUEST create;
|
|
memset(&create, 0, sizeof(create));
|
|
create.Size = sizeof(create);
|
|
create.Flags = SYS_PORT_FLAG_NONE;
|
|
create.Backlog = RSSRV_DWM_LISTENER_BACKLOG;
|
|
create.HandleOut = &session->DwmListener;
|
|
return SysCreatePort(&create);
|
|
}
|
|
|
|
// Registers one stable in-process input target with Session 0.
|
|
KSTATUS RssrvSessionRegisterInputTarget(RSSRV_SESSION_STATE* session,
|
|
RSSRV_INPUT_TARGET* target,
|
|
uint32_t kind,
|
|
void* context,
|
|
RSSRV_INPUT_TARGET_KEY_ROUTINE keyRoutine,
|
|
RSSRV_INPUT_TARGET_MOUSE_ROUTINE mouseRoutine) {
|
|
if (!session || !target || kind == RSSRV_INPUT_TARGET_KIND_NONE || !context)
|
|
return NTLSTATUS_INVALID_PARAMETER;
|
|
KSTATUS status = RssrvSessionLock(session);
|
|
if (!KSUCCESS(status)) return status;
|
|
if (target->Id != 0) {
|
|
RssrvSessionUnlock(session);
|
|
return NTLSTATUS_OBJECT_NAME_COLLISION;
|
|
}
|
|
memset(target, 0, sizeof(*target));
|
|
target->Id = session->NextTargetId++;
|
|
if (target->Id == 0) target->Id = session->NextTargetId++;
|
|
target->Kind = kind;
|
|
target->Session = session;
|
|
target->Context = context;
|
|
target->KeyRoutine = keyRoutine;
|
|
target->MouseRoutine = mouseRoutine;
|
|
RssrvSessionChangedLocked(session);
|
|
RssrvSessionUnlock(session);
|
|
return NTLSTATUS_SUCCESS;
|
|
}
|
|
|
|
// Activates one registered target and gives it ordinary keyboard and pointer focus.
|
|
KSTATUS RssrvSessionActivateInputTarget(RSSRV_SESSION_STATE* session, RSSRV_INPUT_TARGET* target) {
|
|
if (!session || !target || target->Id == 0 || target->Session != session) return NTLSTATUS_INVALID_PARAMETER;
|
|
KSTATUS status = RssrvSessionLock(session);
|
|
if (!KSUCCESS(status)) return status;
|
|
session->ActiveTarget = target;
|
|
session->KeyboardFocus = target;
|
|
session->PointerFocus = target;
|
|
RssrvSessionChangedLocked(session);
|
|
RssrvSessionUnlock(session);
|
|
return NTLSTATUS_SUCCESS;
|
|
}
|
|
|
|
// Sets keyboard focus without changing activation or pointer routing.
|
|
KSTATUS RssrvSessionSetKeyboardFocus(RSSRV_SESSION_STATE* session, RSSRV_INPUT_TARGET* target) {
|
|
if (!session || (target && (target->Id == 0 || target->Session != session))) return NTLSTATUS_INVALID_PARAMETER;
|
|
KSTATUS status = RssrvSessionLock(session);
|
|
if (!KSUCCESS(status)) return status;
|
|
if (session->KeyboardFocus != target) {
|
|
session->KeyboardFocus = target;
|
|
RssrvSessionChangedLocked(session);
|
|
}
|
|
RssrvSessionUnlock(session);
|
|
return NTLSTATUS_SUCCESS;
|
|
}
|
|
|
|
// Sets ordinary pointer focus without disturbing an active pointer capture.
|
|
KSTATUS RssrvSessionSetPointerFocus(RSSRV_SESSION_STATE* session, RSSRV_INPUT_TARGET* target) {
|
|
if (!session || (target && (target->Id == 0 || target->Session != session))) return NTLSTATUS_INVALID_PARAMETER;
|
|
KSTATUS status = RssrvSessionLock(session);
|
|
if (!KSUCCESS(status)) return status;
|
|
if (session->PointerFocus != target) {
|
|
session->PointerFocus = target;
|
|
RssrvSessionChangedLocked(session);
|
|
}
|
|
RssrvSessionUnlock(session);
|
|
return NTLSTATUS_SUCCESS;
|
|
}
|
|
|
|
// Sets or releases pointer capture independently of ordinary pointer focus.
|
|
KSTATUS RssrvSessionSetPointerCapture(RSSRV_SESSION_STATE* session, RSSRV_INPUT_TARGET* target) {
|
|
if (!session || (target && (target->Id == 0 || target->Session != session))) return NTLSTATUS_INVALID_PARAMETER;
|
|
KSTATUS status = RssrvSessionLock(session);
|
|
if (!KSUCCESS(status)) return status;
|
|
if (session->PointerCapture != target) {
|
|
session->PointerCapture = target;
|
|
RssrvSessionChangedLocked(session);
|
|
}
|
|
RssrvSessionUnlock(session);
|
|
return NTLSTATUS_SUCCESS;
|
|
}
|
|
|
|
// Returns the active session display bounds used to clamp the logical pointer.
|
|
KSTATUS RssrvSessionQueryDisplayBounds(RSSRV_SESSION_STATE* session, int32_t* widthOut, int32_t* heightOut) {
|
|
if (!session || !widthOut || !heightOut) return NTLSTATUS_INVALID_PARAMETER;
|
|
KSTATUS status = RssrvSessionLock(session);
|
|
if (!KSUCCESS(status)) return status;
|
|
*widthOut = session->DisplayWidth;
|
|
*heightOut = session->DisplayHeight;
|
|
RssrvSessionUnlock(session);
|
|
return NTLSTATUS_SUCCESS;
|
|
}
|
|
|
|
// Gives DWM a non-consuming observation of one logical key before authoritative session routing occurs.
|
|
void RssrvSessionObserveKey(RSSRV_SESSION_STATE* session, const INPUT_KEY_RECORD* record) {
|
|
if (!session || !record) return;
|
|
if (!KSUCCESS(RssrvSessionLock(session))) return;
|
|
RssrvSessionSendDwmEventLocked(session, NTL_SESSION_DWM_EVENT_OBSERVE_KEY, record, 0, 0, 0);
|
|
RssrvSessionUnlock(session);
|
|
}
|
|
|
|
// Gives DWM a non-consuming observation of one logical mouse event for hit testing and cursor policy.
|
|
void RssrvSessionObserveMouse(RSSRV_SESSION_STATE* session,
|
|
const INPUT_MOUSE_EVENT* event,
|
|
int32_t x,
|
|
int32_t y) {
|
|
if (!session || !event) return;
|
|
if (!KSUCCESS(RssrvSessionLock(session))) return;
|
|
RssrvSessionSendDwmEventLocked(session, NTL_SESSION_DWM_EVENT_OBSERVE_MOUSE, 0, event, x, y);
|
|
RssrvSessionUnlock(session);
|
|
}
|
|
|
|
// Routes one logical keyboard record to the current keyboard-focus target.
|
|
void RssrvSessionRouteKey(RSSRV_SESSION_STATE* session, const INPUT_KEY_RECORD* record) {
|
|
if (!session || !record) return;
|
|
RSSRV_INPUT_TARGET* target = (RSSRV_INPUT_TARGET*)0;
|
|
if (KSUCCESS(RssrvSessionLock(session))) {
|
|
target = session->KeyboardFocus;
|
|
RssrvSessionUnlock(session);
|
|
}
|
|
if (target && target->KeyRoutine) target->KeyRoutine(target->Context, record);
|
|
}
|
|
|
|
// Routes one logical mouse event through capture or pointer focus; DWM owns visible cursor policy.
|
|
void RssrvSessionRouteMouse(RSSRV_SESSION_STATE* session,
|
|
const INPUT_MOUSE_EVENT* event,
|
|
int32_t x,
|
|
int32_t y) {
|
|
if (!session || !event) return;
|
|
RSSRV_INPUT_TARGET* target = (RSSRV_INPUT_TARGET*)0;
|
|
if (KSUCCESS(RssrvSessionLock(session))) {
|
|
target = session->PointerCapture ? session->PointerCapture : session->PointerFocus;
|
|
RssrvSessionUnlock(session);
|
|
}
|
|
if (target && target->MouseRoutine) target->MouseRoutine(target->Context, event, x, y);
|
|
}
|
|
|
|
// Publishes Session 0's console alias and starts the private DWM authority listener.
|
|
KSTATUS RssrvSessionStart(RSSRV_SESSION_STATE* session, RSSRV_CONSOLE_STATE* console) {
|
|
if (!session || !console || console->Listener == SYS_HANDLE_INVALID || !session->ActiveTarget ||
|
|
session->DwmListener == SYS_HANDLE_INVALID)
|
|
return NTLSTATUS_INVALID_PARAMETER;
|
|
|
|
KSTATUS status = RssrvSessionRegisterInputTarget(session, &session->DesktopTarget,
|
|
RSSRV_INPUT_TARGET_KIND_DESKTOP, session,
|
|
RssrvSessionDwmRouteKey, RssrvSessionDwmRouteMouse);
|
|
if (!KSUCCESS(status)) return status;
|
|
|
|
SYS_HANDLE sessionConsole = SYS_HANDLE_INVALID;
|
|
SYS_DERIVE_HANDLE_REQUEST derive;
|
|
memset(&derive, 0, sizeof(derive));
|
|
derive.Size = sizeof(derive);
|
|
derive.SourceHandle = console->Listener;
|
|
derive.DesiredRights = SYS_RIGHT_TRANSFER | SYS_RIGHT_QUERY | SYS_PORT_RIGHT_CONNECT;
|
|
derive.DerivedHandleOut = &sessionConsole;
|
|
status = SysDeriveHandle(&derive);
|
|
if (!KSUCCESS(status)) return status;
|
|
|
|
status = RssrvNamespaceBindOwned(session->Namespace,
|
|
RSSRV_SESSION_ZERO_CONSOLE_PATH,
|
|
sizeof(RSSRV_SESSION_ZERO_CONSOLE_PATH) - 1u,
|
|
NTL_RESOURCE_KIND_CAPABILITY,
|
|
sessionConsole,
|
|
SYS_RIGHT_QUERY | SYS_PORT_RIGHT_CONNECT);
|
|
if (!KSUCCESS(status)) {
|
|
(void)SysCloseHandle(sessionConsole);
|
|
return status;
|
|
}
|
|
|
|
status = RssrvNamespaceCreateSymbolicLink(session->Namespace,
|
|
RSSRV_CURRENT_CONSOLE_PATH,
|
|
sizeof(RSSRV_CURRENT_CONSOLE_PATH) - 1u,
|
|
RSSRV_SESSION_ZERO_CONSOLE_PATH,
|
|
sizeof(RSSRV_SESSION_ZERO_CONSOLE_PATH) - 1u);
|
|
if (!KSUCCESS(status)) return status;
|
|
|
|
SYS_CREATE_THREAD_REQUEST create;
|
|
memset(&create, 0, sizeof(create));
|
|
create.Size = sizeof(create);
|
|
create.Entry = (uintptr_t)RssrvSessionDwmListenerThread;
|
|
create.Argument = (uintptr_t)session;
|
|
create.Priority = 1u;
|
|
create.Flags = SYS_CREATE_THREAD_FLAG_NONE;
|
|
return SysCreateThread(&create);
|
|
}
|