You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
239 lines
8.1 KiB
239 lines
8.1 KiB
|
|
/*************************************************************************
|
|
*
|
|
* command.c
|
|
*
|
|
* WinStation command channel handler
|
|
*
|
|
* Copyright (c) 1985 - 1999, Microsoft Corporation
|
|
*
|
|
* $Author:
|
|
*************************************************************************/
|
|
|
|
/*
|
|
* Includes
|
|
*/
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#include "ntuser.h"
|
|
|
|
#include <winsta.h>
|
|
#include <wstmsg.h>
|
|
|
|
#include <icadd.h>
|
|
|
|
extern HANDLE WinStationIcaApiPort;
|
|
|
|
extern HANDLE G_DupIcaVideoChannel;
|
|
extern HANDLE G_DupIcaCommandChannel;
|
|
extern HANDLE G_DupConsoleShadowVideoChannel;
|
|
extern HANDLE G_DupConsoleShadowCommandChannel;
|
|
|
|
|
|
extern NTSTATUS BrokenConnection(BROKENCLASS, BROKENSOURCECLASS);
|
|
extern NTSTATUS ShadowHotkey(VOID);
|
|
|
|
NTSTATUS
|
|
Win32CommandChannelThread(
|
|
PVOID ThreadParameter)
|
|
{
|
|
ICA_CHANNEL_COMMAND Command;
|
|
ULONG ActualLength;
|
|
NTSTATUS Status;
|
|
ULONG Error;
|
|
OVERLAPPED Overlapped;
|
|
USERTHREAD_USEDESKTOPINFO utudi;
|
|
BOOL bRestoreDesktop = FALSE;
|
|
BOOL bShadowCommandChannel = (BOOL)PtrToUlong(ThreadParameter);
|
|
HANDLE hChannel = bShadowCommandChannel ? G_DupConsoleShadowCommandChannel : G_DupIcaCommandChannel;
|
|
HANDLE hChannelToClose = NULL;
|
|
|
|
for ( ; ; ) {
|
|
RtlZeroMemory(&Overlapped, sizeof(Overlapped));
|
|
|
|
if (!ReadFile(hChannel,
|
|
&Command,
|
|
sizeof(Command),
|
|
&ActualLength,
|
|
&Overlapped)) {
|
|
|
|
Error = GetLastError();
|
|
|
|
if (Error == ERROR_IO_PENDING) {
|
|
|
|
/*
|
|
* check on the results of the asynchronous read
|
|
*/
|
|
if (!GetOverlappedResult(hChannel, &Overlapped,
|
|
&ActualLength, TRUE)) {
|
|
// wait for result
|
|
|
|
RIPMSG1(RIP_WARNING, "Command Channel: Error 0x%x from GetOverlappedResult", GetLastError());
|
|
break;
|
|
}
|
|
} else {
|
|
RIPMSG1(RIP_WARNING, "Command Channel: Error 0x%x from ReadFile", Error);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ActualLength < sizeof(ICA_COMMAND_HEADER)) {
|
|
|
|
RIPMSG1(RIP_WARNING, "Command Channel Thread bad length 0x%x",
|
|
ActualLength);
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* This is a Csrss thread with no desktop. It needs to grab a temporary one
|
|
* before calling into win32k.
|
|
*/
|
|
|
|
|
|
Status = STATUS_SUCCESS;
|
|
bRestoreDesktop = FALSE;
|
|
if (Command.Header.Command != ICA_COMMAND_BROKEN_CONNECTION && Command.Header.Command != ICA_COMMAND_SHADOW_HOTKEY) {
|
|
if (Command.Header.Command != ICA_COMMAND_DISPLAY_IOCTL || Command.DisplayIOCtl.DisplayIOCtlFlags & DISPLAY_IOCTL_FLAG_REDRAW) {
|
|
utudi.hThread = NULL;
|
|
utudi.drdRestore.pdeskRestore = NULL;
|
|
bRestoreDesktop = TRUE;
|
|
Status = NtUserSetInformationThread(NtCurrentThread(),
|
|
UserThreadUseActiveDesktop,
|
|
&utudi, sizeof(utudi));
|
|
}
|
|
}
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
switch (Command.Header.Command) {
|
|
|
|
case ICA_COMMAND_BROKEN_CONNECTION:
|
|
/*
|
|
* broken procedure
|
|
*/
|
|
Status = BrokenConnection(
|
|
Command.BrokenConnection.Reason,
|
|
Command.BrokenConnection.Source);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
RIPMSG1(RIP_WARNING, "BrokenConnection failed with Status 0x%x", Status);
|
|
}
|
|
break;
|
|
|
|
case ICA_COMMAND_REDRAW_RECTANGLE:
|
|
/*
|
|
* setfocus ???
|
|
*/
|
|
if (ActualLength < sizeof(ICA_COMMAND_HEADER) + sizeof(ICA_REDRAW_RECTANGLE)) {
|
|
|
|
RIPMSG1(RIP_WARNING, "Command Channel: redraw rect bad length %d", ActualLength);
|
|
break;
|
|
}
|
|
Status = NtUserRemoteRedrawRectangle(
|
|
Command.RedrawRectangle.Rect.Left,
|
|
Command.RedrawRectangle.Rect.Top,
|
|
Command.RedrawRectangle.Rect.Right,
|
|
Command.RedrawRectangle.Rect.Bottom);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
RIPMSG1(RIP_WARNING, "NtUserRemoteRedrawRectangle failed with Status 0x%x", Status);
|
|
}
|
|
break;
|
|
|
|
case ICA_COMMAND_REDRAW_SCREEN: // setfocus
|
|
|
|
Status = NtUserRemoteRedrawScreen();
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
RIPMSG1(RIP_WARNING, "NtUserRemoteRedrawScreen failed with Status 0x%x", Status);
|
|
}
|
|
break;
|
|
|
|
case ICA_COMMAND_STOP_SCREEN_UPDATES: // killfocus
|
|
|
|
Status = NtUserRemoteStopScreenUpdates();
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
RIPMSG1(RIP_WARNING, "NtUserRemoteStopScreenUpdates failed with Status 0x%x", Status);
|
|
} else {
|
|
IO_STATUS_BLOCK IoStatus;
|
|
|
|
NtDeviceIoControlFile(
|
|
bShadowCommandChannel ? G_DupConsoleShadowVideoChannel
|
|
: G_DupIcaVideoChannel,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatus,
|
|
IOCTL_VIDEO_ICA_STOP_OK,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0);
|
|
}
|
|
break;
|
|
|
|
case ICA_COMMAND_SHADOW_HOTKEY: // shadow hotkey
|
|
|
|
Status = ShadowHotkey();
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
RIPMSG1(RIP_WARNING, "ShadowHotkey failed with Status 0x%x", Status);
|
|
}
|
|
break;
|
|
|
|
case ICA_COMMAND_DISPLAY_IOCTL:
|
|
|
|
Status = NtUserCtxDisplayIOCtl(
|
|
Command.DisplayIOCtl.DisplayIOCtlFlags,
|
|
&Command.DisplayIOCtl.DisplayIOCtlData[0],
|
|
Command.DisplayIOCtl.cbDisplayIOCtlData);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
RIPMSG1(RIP_WARNING, "NtUserCtxDisplayIOCtl failed with Status 0x%x", Status);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
RIPMSG1(RIP_WARNING, "Command Channel: Bad Command 0x%x", Command.Header.Command);
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Release the temporary desktop.
|
|
*/
|
|
if (bRestoreDesktop) {
|
|
NTSTATUS retStatus;
|
|
retStatus = NtUserSetInformationThread(NtCurrentThread(),
|
|
UserThreadUseDesktop,
|
|
&utudi,
|
|
sizeof(utudi));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!bShadowCommandChannel) {
|
|
/*
|
|
* Close command channel LPC port if there is one.
|
|
*/
|
|
if (WinStationIcaApiPort) {
|
|
NtClose(WinStationIcaApiPort);
|
|
WinStationIcaApiPort = NULL;
|
|
}
|
|
}
|
|
|
|
// We have to close the commandchannel handle here
|
|
if (hChannel != NULL) {
|
|
NtClose(hChannel);
|
|
}
|
|
|
|
// We have to close the relevant Video Channel here
|
|
hChannelToClose = ( bShadowCommandChannel ? G_DupConsoleShadowVideoChannel : G_DupIcaVideoChannel );
|
|
if (hChannelToClose != NULL) {
|
|
NtClose(hChannelToClose);
|
|
}
|
|
|
|
UserExitWorkerThread(STATUS_SUCCESS);
|
|
return STATUS_SUCCESS;
|
|
}
|