簡體   English   中英

當用戶單擊控制台窗口時,代碼停止執行

[英]Code stops executing when a user clicks on the console window

我有一個控制台應用程序,無需用戶交互即可執行我的代碼。 如果用戶有意或無意地在控制台窗口內單擊,則所有執行都將停止。

這與從控制台窗口復制文本有關。 應用程序再次開始執行的唯一方法是,如果用戶選擇文本,然后右鍵單擊控制台窗口,將其復制到剪貼板。

要查看此操作,請創建一個控制台應用程序並添加以下代碼。

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();
    }
}

單擊控制台窗口時,任務線程停止執行。 這根本不是理想的行為,我想在我的控制台應用程序中防止這種情況發生。

我怎么能阻止這個? 據我所知,控制台窗口上的所有屬性/事件都與控制此行為無關。

如你所見,當我在窗口內點擊時出現光標。 當我按任意鍵 - 光標消失,應用程序繼續工作 暫停的應用程序

如果在控制台窗口中啟用了“快速編輯模式”,則會發生這種情 如果右鍵單擊標題欄並選擇“屬性”,然后選擇“選項”選項卡,則可以檢查是否啟用了“快速編輯模式”。 如果禁用“快速編輯模式”,則單擊窗口時滾動不會停止。

滾動停止的原因是因為在窗口中單擊鼠標用於選擇文本。

您可以在程序中禁用控制台上的“快速編輯模式”,但這樣做需要調用GetConsoleModeSetConsoleMode 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的調用失敗,則不希望恢復控制台模式。

我剛剛看到OP的問題評論中的這個答案包含了我自己發現的內容。 我會保留我的答案,因為人們可能看不到它,就像我一樣,它會為他們節省很多時間。


吉姆的回答對我不起作用,我無法弄明白為什么。 我挖掘並找到了一個有效的解決方案,所以我將分享我的發現,希望能幫助處於相同情況的人。

問題是我從GetConsoleWindow()獲得的句柄,它給出了Win32錯誤(0x6),當我嘗試使用它時句柄無效。 SetConsoleMode()的調用什么也沒做。

為了得到一個工作句柄,我使用GetStdHandle()來獲取控制台的Input句柄。 將此添加到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)DisableQuickEdit()EnableQuickEdit()在吉姆的代碼。

調用DisableQuickEdit() ,在控制台中禁用選擇。

謝謝吉姆!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM