Windows 2012 R2 中的管理员 DOS/CMD 窗口不接受 C# 控制台应用程序中预期的 ESC 密钥

本文关键字:应用程序 控制台 密钥 不接受 ESC CMD R2 2012 管理员 DOS Windows | 更新日期: 2023-09-27 18:31:07

这是控制台应用程序中的C#代码片段,适用于我的本地Windows 8和VS .NET 2015环境。 当我在本地Windows 8计算机上的管理员DOS/CMD窗口中运行控制台应用程序时,它也可以工作。

控制台应用程序(DOS/CMD 窗口以管理员身份打开)在使用 Windows 远程桌面连接到 Windows 2012 R2 服务器时不接受 ESC 密钥。

do
{
    while (!Console.KeyAvailable)
    {
         // Do nothing while waiting for input
    }
} while (Console.ReadKey(true).Key != ConsoleKey.Escape);
我知道Windows 2012 R2在使用

远程桌面时具有特殊命令的特殊键,但是,这是ESC键不适用于DOS/CMD窗口中的Windows 2012 R2远程桌面。

我知道我可以使用不同的键(或其他组合),但我想知道为什么在这种情况下 DOS/控制台窗口不"接受"ESC 键。

[编辑]:好的,我需要在这里更具体。

我真的在尝试将 EXE 作为控制台应用程序运行。 我发布的代码在 Windows 2008 中有效,但等等,还有更多! 在将结果输出到 CMD/DOS 提示符之前,我必须首先附加到现有的父 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() 或上面最初发布的代码接受我的输入。

代码片段(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);
            }
        }
    }

Windows 2012 R2 中的管理员 DOS/CMD 窗口不接受 C# 控制台应用程序中预期的 ESC 密钥

让我们看看你的代码

do
{
    while (!Console.KeyAvailable)
    {
         // Do nothing while waiting for input
    }
} while (Console.ReadKey(true).Key != ConsoleKey.Escape);

零件

while (!Console.KeyAvailable)

是一个热循环。一个 CPU 内核将在接近 100% 轮询 KeyAvailable 的情况下运行。 在我的 8 核机器上,代码仍然响应,并在按下 ConsoleKey.Escape 时终止。但是,它不必要地效率低下,如果您只有一个或有限的 CPU 内核,则可能会导致错过按键事件。

重写以更高效

do
{
} while (Console.ReadKey(true).Key != ConsoleKey.Escape);

看看问题是否消失了。

我在通过远程桌面访问的Windows 2012 R2服务器上运行了您的原始代码和我的原始代码。两种变体都奏效了。我确实在该服务器上有几个可用的 CPU 内核,其中一个确实与您的代码一起达到了 100%。