/************************************************************************* * * command.c * * WinStation command channel handler * * Copyright (c) 1985 - 1999, Microsoft Corporation * * $Author: *************************************************************************/ /* * Includes */ #include "precomp.h" #pragma hdrstop #include "ntuser.h" #include #include #include 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; }