【问题标题】:How to programmatic disable C# Console Application's Quick Edit mode?如何以编程方式禁用 C# 控制台应用程序的快速编辑模式?
【发布时间】:2012-11-19 08:38:42
【问题描述】:

我已经尝试了几种解决方案,比如一个 ->

http://www.pcreview.co.uk/forums/console-writeline-hangs-if-user-click-into-console-window-t1412701.html

但是,我观察到 GetConsoleMode(IntPtr hConsoleHandle, out int mode) 中的模式对于不同的控制台应用程序会有所不同。它不是一成不变的。

我能否在控制台应用程序上禁用鼠标单击(右/左按钮)以实现相同的场景。我发现它可以使用 IMessageFilter 完成,但仅适用于 Window Form Application 而不是控制台应用程序。

请指导。

【问题讨论】:

  • 据我所知默认情况下它是关闭的,如果用户想要启用它,那么你是谁告诉他们不同的?
  • 实际上,昨天发生了同样的情况,当我们的一个基于控制台的 C# 应用程序作为服务器上线时。实施团队中的一些人可能错误地打开了快速编辑模式,而不是无意中点击了窗口。这会冻结 UI 线程。在真正发现问题不是技术问题之前,花了 2 个小时的忙碌。 :)

标签: c# console-application


【解决方案1】:

对于那些使用 vb.net 的人

Const ENABLE_QUICK_EDIT As UInteger = &H40
Const STD_INPUT_HANDLE As Integer = -10


   <DllImport("kernel32.dll", SetLastError:=True)>
Public Function GetStdHandle(ByVal nStdHandle As Integer) As IntPtr
End Function

<DllImport("kernel32.dll")>
Private Function GetConsoleMode(ByVal hConsoleHandle As IntPtr, <Out> ByRef lpMode As UInteger) As Boolean
End Function

<DllImport("kernel32.dll")>
Private Function SetConsoleMode(ByVal hConsoleHandle As IntPtr, ByVal dwMode As UInteger) As Boolean
End Function 

    Friend Function Go() As Boolean
    Dim consoleHandle As IntPtr = GetStdHandle(STD_INPUT_HANDLE)
    Dim consoleMode As UInteger

    If Not GetConsoleMode(consoleHandle, consoleMode) Then
        Return False
    End If

    consoleMode = consoleMode And Not ENABLE_QUICK_EDIT

    If Not SetConsoleMode(consoleHandle, consoleMode) Then
        Return False
    End If

    Return True
End Function

sub main()
go()
end sub

【讨论】:

  • 但问题是关于 C#。
  • 但是这个答案是为那些使用 vb.net 的人准备的
【解决方案2】:

我碰巧在我的控制台应用程序中启用了快速编辑模式时偶然发现了同样的问题,该应用程序是用 C 编写的,并且已经在 windows 7 32 位下工作了很长时间。在将其移植(不是真正的移植,而是调整了一些代码行)到 Windows 10 64 位(仍然是 32 位应用程序)之后,我观察到了相同的行为。 所以我寻找了一个解决方案。

但由于我不知道的原因,代码的工作方式相反,即在 mode 参数中设置位 ENABLE_QUICK_EDIT_MODE 实际上会禁用快速编辑模式。并且重置位启用快速编辑模式...???

这是我的代码:

    /// <summary>
/// This flag enables the user to use the mouse to select and edit text. To enable
/// this option, you must also set the ExtendedFlags flag.
/// </summary>
const int QuickEditMode = 64;

// ExtendedFlags must be combined with
// InsertMode and QuickEditMode when setting
/// <summary>
/// ExtendedFlags must be enabled in order to enable InsertMode or QuickEditMode.
/// </summary>
const int ExtendedFlags = 128;

BOOLEAN EnableQuickEdit()
{
    HWND conHandle = GetStdHandle(STD_INPUT_HANDLE);
    int mode;
    DWORD dwLastError = GetLastError();
    if (!GetConsoleMode(conHandle, &mode))
    {
        // error getting the console mode. Exit.
        dwLastError = GetLastError();
        return (dwLastError == 0);
    }
    else 
        dwLastError = 0;
    mode = mode & ~QuickEditMode;

    if (!SetConsoleMode(conHandle, mode | ExtendedFlags))
    {
        // error setting console mode.
        dwLastError = GetLastError();
    }
    else
        dwLastError = 0;
    return (dwLastError == 0);
}

BOOLEAN DisableQuickEdit()
{
    HWND conHandle = GetStdHandle(STD_INPUT_HANDLE);
    int mode;
    DWORD dwLastError = GetLastError();

    if (!GetConsoleMode(conHandle, &mode))
    {
        // error getting the console mode. Exit.
        dwLastError = GetLastError();
        return (dwLastError == 0);
    }
    else
        dwLastError = 0;

    mode = mode | QuickEditMode;

    if (!SetConsoleMode(conHandle, mode))
    {
        // error getting the console mode. Exit.
        dwLastError = GetLastError();
    }
    else
        dwLastError = 0;
    return (dwLastError == 0);
}

问候沃尔夫冈

【讨论】:

  • 问题是关于C#的
【解决方案3】:

阅读以上答案后,GetConsoleWindow() 无法使用。而是必须使用 GetStdHandle()。

所以这里有一个用于启用/禁用 QuickEditMode 的复制和粘贴类。调用 ConsoleWindow.QuickEditMode(false); 以禁用控制台窗口的快速编辑模式。

using System;
using System.Runtime.InteropServices;

public static class ConsoleWindow
{
    private static class NativeFunctions
    {
        public enum StdHandle : int
        {
            STD_INPUT_HANDLE = -10,
            STD_OUTPUT_HANDLE = -11,
            STD_ERROR_HANDLE = -12,
        }

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern IntPtr GetStdHandle(int nStdHandle); //returns Handle

        public enum ConsoleMode : uint
        {
            ENABLE_ECHO_INPUT = 0x0004,
            ENABLE_EXTENDED_FLAGS = 0x0080,
            ENABLE_INSERT_MODE = 0x0020,
            ENABLE_LINE_INPUT = 0x0002,
            ENABLE_MOUSE_INPUT = 0x0010,
            ENABLE_PROCESSED_INPUT = 0x0001,
            ENABLE_QUICK_EDIT_MODE = 0x0040,
            ENABLE_WINDOW_INPUT = 0x0008,
            ENABLE_VIRTUAL_TERMINAL_INPUT = 0x0200,

            //screen buffer handle
            ENABLE_PROCESSED_OUTPUT = 0x0001,
            ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002,
            ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004,
            DISABLE_NEWLINE_AUTO_RETURN = 0x0008,
            ENABLE_LVB_GRID_WORLDWIDE = 0x0010
        }

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern bool GetConsoleMode(IntPtr hConsoleHandle, out uint lpMode);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint dwMode);
    }

    public static void QuickEditMode(bool Enable)
    {
        //QuickEdit lets the user select text in the console window with the mouse, to copy to the windows clipboard.
        //But selecting text stops the console process (e.g. unzipping). This may not be always wanted.
        IntPtr consoleHandle = NativeFunctions.GetStdHandle((int)NativeFunctions.StdHandle.STD_INPUT_HANDLE);
        UInt32 consoleMode;

        NativeFunctions.GetConsoleMode(consoleHandle, out consoleMode);
        if (Enable)
            consoleMode |= ((uint)NativeFunctions.ConsoleMode.ENABLE_QUICK_EDIT_MODE);
        else
            consoleMode &= ~((uint)NativeFunctions.ConsoleMode.ENABLE_QUICK_EDIT_MODE);

        consoleMode |= ((uint)NativeFunctions.ConsoleMode.ENABLE_EXTENDED_FLAGS);

        NativeFunctions.SetConsoleMode(consoleHandle, consoleMode);
    }
}

【讨论】:

    【解决方案4】:

    对于像我这样喜欢不费吹灰之力复制/粘贴代码的人,以下是受接受答案启发的代码:

    using System;
    using System.Runtime.InteropServices;
    
    static class DisableConsoleQuickEdit {
    
       const uint ENABLE_QUICK_EDIT = 0x0040;
    
       // STD_INPUT_HANDLE (DWORD): -10 is the standard input device.
       const int STD_INPUT_HANDLE = -10;
    
       [DllImport("kernel32.dll", SetLastError = true)]
       static extern IntPtr GetStdHandle(int nStdHandle);
    
       [DllImport("kernel32.dll")]
       static extern bool GetConsoleMode(IntPtr hConsoleHandle, out uint lpMode);
    
       [DllImport("kernel32.dll")]
       static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint dwMode);
    
       internal static bool Go() {
    
          IntPtr consoleHandle = GetStdHandle(STD_INPUT_HANDLE);
    
          // get current console mode
          uint consoleMode;
          if (!GetConsoleMode(consoleHandle, out consoleMode)) {
             // ERROR: Unable to get console mode.
             return false;
          }
    
          // Clear the quick edit bit in the mode flags
          consoleMode &= ~ENABLE_QUICK_EDIT;
    
          // set the new mode
          if (!SetConsoleMode(consoleHandle, consoleMode)) {
             // ERROR: Unable to set console mode
             return false;
          }
    
          return true;
       }
    }
    

    【讨论】:

    • 这太完美了!
    • 绝对完美!
    • 这正是我一直在寻找的。谢谢。
    • 也可以在 .Net Core 中使用
    【解决方案5】:

    通过使用下面的代码组合,我可以启用或禁用快速编辑模式。

    const int ENABLE_QUICK_EDIT = 0x0040;
    
    // STD_INPUT_HANDLE (DWORD): -10 is the standard input device.
    const int STD_INPUT_HANDLE = -10;
    
    [DllImport("kernel32.dll", SetLastError = true)]
    static extern IntPtr GetStdHandle(int nStdHandle);
    
    [DllImport("kernel32.dll")]
    static extern bool GetConsoleMode(IntPtr hConsoleHandle, out int lpMode);
    
    [DllImport("kernel32.dll")]
    static extern bool SetConsoleMode(IntPtr hConsoleHandle, int dwMode);
    

    要启用,只需currentConsoleMode &amp;= ENABLE_QUICK_EDIT;

    要禁用,请执行 currentConsoleMode &amp;= ~ENABLE_QUICK_EDIT

    然后调用SetConsoleMode

    【讨论】:

      【解决方案6】:

      如果你想禁用快速编辑模式,你需要调用GetConsoleMode来获取当前模式。然后清除启用快速编辑的位,并调用SetConsoleMode。假设你有非托管函数的托管原型,你会写:

      const int ENABLE_QUICK_EDIT = 0x0040;
      
      IntPtr consoleHandle = GetConsoleWindow();
      UInt32 consoleMode;
      
      // get current console mode
      if (!GetConsoleMode(consoleHandle, out consoleMode))
      {
          // Error: Unable to get console mode.
          return;
      }
      
      // Clear the quick edit bit in the mode flags
      mode &= ~ENABLE_QUICK_EDIT;
      
      // set the new mode
      if (!SetConsoleMode(consoleHandle, consoleMode))
      {
          // ERROR: Unable to set console mode
      }
      

      如果你想禁用鼠标输入,你想清除鼠标输入位。

      const int ENABLE_MOUSE_INPUT = 0x0010;
      
      mode &= ~ENABLE_MOUSE_INPUT;
      

      【讨论】:

      • 谢谢你,这正是我想要的。
      • @M.Babcock:是的,这就是链接代码尝试要做的事情。但是链接的代码正在获取标准输入句柄而不是控制台窗口句柄(可能不同)。它还硬编码了一个控制台模式,可以改变许多不同的设置。此代码仅更改一个设置。
      • @Jim Mischel - 使用 IntPtr consoleHandle = GetConsoleWindow() 导致处于 if 条件下,然后返回。所以我使用了 public const int STD_INPUT_HANDLE = -10; IntPtr 句柄 = GetStdHandle(STD_INPUT_HANDLE); GetConsoleMode(handle, out consoleMode) 获取模式。有什么我想念的吗?
      • 这有点早了,但有一些额外的提示:Source 有重要信息:对于禁用快速编辑模式,必须在 SetConsole 上设置扩展标志。如果您在没有 QUICK 和没有 EXTENDED 的情况下调用 SetConsole:标志更改,但仍启用 quickedit。禁用:模式 &= ~ENABLE_QUICK_EDIT;模式 |= ENABLE_EXTENDED_FLAGS;
      • 投反对票的人:通常会提供投反对票的理由。这个答案有问题吗?
      猜你喜欢
      • 2020-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-26
      • 1970-01-01
      • 2021-06-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多