Окно администратора DOS/CMD в Windows 2012 R2 не принимает ключ ESC, ожидаемый в консольном приложении C#
Вот фрагмент кода C# из консольного приложения, которое работает в моей локальной среде Windows 8 и VS .NET 2015. Это также работает, когда я запускаю консольное приложение в окне DOS/CMD администратора на моем локальном компьютере с Windows 8.
Консольное приложение (окно DOS/CMD, открытое от имени администратора) не принимает ключ ESC при использовании удаленного рабочего стола Windows для подключения к серверу Windows 2012 R2.
do
{
while (!Console.KeyAvailable)
{
// Do nothing while waiting for input
}
} while (Console.ReadKey(true).Key != ConsoleKey.Escape);
Я знаю, что в Windows 2012 R2 есть специальные ключи для специальных команд при использовании удаленного рабочего стола, однако это ключ ESC, который не работает с удаленным рабочим столом для Windows 2012 R2 в окне DOS/CMD.
Я знаю, что могу использовать другой ключ (или другие комбинации), но я хочу знать, почему ключ ESC не "принимается" окном DOS/Console в этом сценарии.
[РЕДАКТИРОВАТЬ]: Хорошо, я должен быть более конкретным здесь.
Я действительно пытаюсь запустить EXE как консольное приложение. Код, который я разместил, работал в Windows 2008, но подождите, это еще не все! Прежде чем выводить результаты в приглашение CMD/DOS, я должен сначала присоединиться к существующему окну Parent CMD. Я использую код, найденный по следующему URL, либо для новой AllocConsole(), либо для AttachConsole (). http://www.jankowskimichal.pl/en/2011/12/wpf-hybrid-application-with-parameters/
Как на Windows Server 2008, так и на Windows Server 2012 он записывает все, что я кодировал с Console.Write.... все время.
Однако в Windows Server 2012 этот код больше не принимает мои данные, используя ReadKey() или код, опубликованный выше.
Code Snippet (bool "show" = true делает присоединение к консоли; ложное отключение). Опять же, работает для вывода во всех случаях, но не принимает мой ввод в Console.ReadKey().
//Declarations area
[DllImport("kernel32.dll",
EntryPoint = "AllocConsole",
SetLastError = true,
CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
private static extern bool AllocConsole();
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool FreeConsole();
[DllImport("kernel32", SetLastError = true)]
private static extern bool AttachConsole(int dwProcessId);
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", SetLastError = true)]
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
private enum ConsoleCtrlEvent
{
CTRL_C = 0,
CTRL_BREAK = 1,
CTRL_CLOSE = 2,
CTRL_LOGOFF = 5,
CTRL_SHUTDOWN = 6
}
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool GenerateConsoleCtrlEvent(ConsoleCtrlEvent sigevent, int dwProcessGroupId);
[DllImport("User32.Dll", EntryPoint = "PostMessageA")]
private static extern bool PostMessage(IntPtr hWnd, uint msg, int wParam, int lParam);
[СНиП]
//Caller:
//Attach or create a console window to display information to the user
DoConsoleWindow(true);
//Determine if user has administrator privileges
if (UserHasAdminPrivileges(args))
{
//Write information to the console
HandleCommandArgs(args);
}
DoConsoleWindow(false);
[СНиП]
private static void DoConsoleWindow(bool show)
{
if (show == true)
{
ptr = GetForegroundWindow();
int u;
GetWindowThreadProcessId(ptr, out u);
process = Process.GetProcessById(u);
if (process.ProcessName == "cmd") //Is the uppermost window a cmd process?
{
AttachConsole(process.Id);
attachedExisting = true;
}
else
{
//no console AND we're in console mode ... create a new console.
AllocConsole();
}
}
else
{
try
{
//Must pause for 2 seconds to allow display of data to catch up?
Thread.Sleep(2000);
//Send the {ENTER} Key to the console.
PostMessage(ptr, WM_KEYDOWN, VK_RETURN, 0);
FreeConsole();
if (process != null)
{
if (attachedExisting != true)
{
process.Close();
}
}
}
catch (Exception ex)
{
Logger.Log(TraceEventType.Error,
string.Format("{0} failed handling console close", serviceName),
string.Format("{0} failed handling console close: {1}",
serviceName, ex.ToString()),
serviceLogContext);
}
}
}
1 ответ
Давайте посмотрим на ваш код
do
{
while (!Console.KeyAvailable)
{
// Do nothing while waiting for input
}
} while (Console.ReadKey(true).Key != ConsoleKey.Escape);
Часть
while (!Console.KeyAvailable)
это горячая петля. Одно ядро процессора будет работать почти на 100% при опросе KeyAvailable. На моем 8-ядерном компьютере код по-прежнему отзывчив и завершается при нажатии ConsoleKey.Escape. Однако это излишне неэффективно, и если у вас только одно или ограниченное количество ядер ЦП, это может привести к пропуску события нажатия клавиши.
Переписать на более эффективный
do
{
} while (Console.ReadKey(true).Key != ConsoleKey.Escape);
и посмотрим, исчезнет ли проблема.
Я запустил и ваш исходный код, и мой на сервере Windows 2012 R2, доступ к которому осуществляется через удаленный рабочий стол. Оба варианта работали. У меня есть несколько процессорных ядер, доступных на этом сервере, и одно из них полностью соответствует вашему коду.