我有一个控制台应用程序,无需用户交互即可执行我的代码。如果用户有意或无意地在控制台窗口内单击,则所有执行都将停止。
这与从控制台窗口复制文本有关。应用程序再次开始执行的唯一方法是,如果用户选择文本,然后右键单击控制台窗口,将其复制到剪贴板。
要查看此操作,请创建一个控制台应用程序并添加以下代码。
class Program
{
static void Main(string[] args)
{
var task = Task.Run(async () =>
{
int i = 0;
while (true)
{
Console.WriteLine(i++);
await Task.Delay(1000);
}
});
Console.ReadLine();
}
}
单击控制台窗口时,任务线程停止执行。这根本不是理想的行为,我想在我的控制台应用程序中防止这种情况发生。
我该怎样防止这种情况?据我所知,控制台窗口上的所有属性/事件都与控制此行为无关。
答案 0 :(得分:10)
如果在控制台窗口中启用了“快速编辑模式”,则会发生这种情况。如果右键单击标题栏并选择“属性”,然后选择“选项”选项卡,则可以检查是否启用了“快速编辑模式”。如果禁用“快速编辑模式”,则单击窗口时滚动不会停止。
滚动停止的原因是因为在窗口中单击鼠标用于选择文本。
您可以在程序中禁用控制台上的“快速编辑模式”,但这样做需要调用GetConsoleMode和SetConsoleMode API函数。以下是您的表现方式:
[DllImport("kernel32.dll", SetLastError=true)]
public static extern IntPtr GetConsoleWindow();
[DllImport("kernel32.dll", SetLastError=true)]
public static extern bool GetConsoleMode(
IntPtr hConsoleHandle,
out int lpMode);
[DllImport("kernel32.dll", SetLastError=true)]
public static extern bool SetConsoleMode(
IntPtr hConsoleHandle,
int ioMode);
/// <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;
void DisableQuickEdit()
{
IntPtr conHandle = GetConsoleWindow();
int mode;
if (!GetConsoleMode(conHandle, out mode))
{
// error getting the console mode. Exit.
return;
}
mode = mode & ~(QuickEditMode | ExtendedFlags);
if (!SetConsoleMode(conHandle, mode))
{
// error setting console mode.
}
}
void EnableQuickEdit()
{
IntPtr conHandle = GetConsoleWindow();
int mode;
if (!GetConsoleMode(conHandle, out mode))
{
// error getting the console mode. Exit.
return;
}
mode = mode | (QuickEditMode | ExtendedFlags);
if (!SetConsoleMode(conHandle, mode))
{
// error setting console mode.
}
}
如果沿着这条路走下去,在程序启动时保存原始控制台模式设置可能是个好主意,并在程序退出时恢复它。所以在启动时:
GetConsoleMode(GetConsoleWindow(), ref saveConsoleMode);
当你的程序终止时:
SetConsoleMode(GetConsoleWindow(), saveConsoleMode);
当然,有适当的错误处理。如果对GetConsoleMode
的调用失败,您将无法恢复控制台模式。
答案 1 :(得分:6)
我刚刚看到OP问题评论中的这个answer包含了我自己发现的内容。我会保留我的答案,因为人们可能看不到它,就像我一样,这样可以节省很多时间。
Jim的回答对我不起作用,我无法弄清楚原因。 我挖了一遍,找到了一个有效的解决方案,所以我会分享我的发现,希望能帮助处于相同情况的人。
问题在于我从GetConsoleWindow()
获得的句柄,它给出了Win32错误(0x6),当我尝试使用它时句柄无效。对SetConsoleMode()
的调用没有做任何事情。
为了获得工作句柄,我使用GetStdHandle()
来获取控制台的输入句柄。将此添加到Jim的代码中:
public const int STD_INPUT_HANDLE = -10;
[DllImport("Kernel32.dll", SetLastError = true)]
public static extern IntPtr GetStdHandle(int nStdHandle);
然后在GetConsoleWindow()
中的GetStdHandle(STD_INPUT_HANDLE)
和Jim代码中的DisableQuickEdit()
替换EnableQuickEdit()
。
调用DisableQuickEdit()
后,控制台中的选择将被禁用。
谢谢吉姆!