vc控制臺程序關閉事件時的處理方式及註意點詳解

百度可以找到很多關於這個問題解決的方法

關鍵控制臺API函數:SetConsoleCtrlHandler

在支持C++ 11以上的編譯器中,你可以這麼做。

SetConsoleCtrlHandler([](DWORD fdwctrltype)->BOOL {
    if (fdwctrltype == CTRL_CLOSE_EVENT) {
        // 你的善後代碼...
        return TRUE;
    }
    return FALSE;
}, TRUE);

最初這麼做是很舒服的,但之後發現瞭問題:

Windows控制臺在標記狀態下,printf之類的輸出函數,會阻塞在標記選擇時(點控制臺左上角-編輯-標記)。

這就導致瞭,我們的善後代碼中,可能會死鎖,例如你要優雅的結束一個線程,這個線程在最後的時候printf瞭。

線程裡printf等待標記狀態,SetConsoleCtrlHandler回調函數裡等待線程結束,總之就是死鎖。

我本來想著,去找到能夠獲取這種標記狀態的控制臺API,但找瞭很久都沒有結果。

最後,我就考慮,有沒有方法讓printf不與標記狀態發生死鎖,答案是: 輸出流重定向。

所以,代碼變成這樣:

SetConsoleCtrlHandler([](DWORD fdwctrltype)->BOOL {
    if (fdwctrltype == CTRL_CLOSE_EVENT) {
        char szbuf[0x1000];
        setvbuf(stdout, szbuf, _IOFBF, 0x1000);
        // 你的善後代碼...
        return TRUE;
    }
    return FALSE;
}, TRUE);

這麼做之後,世界果然更美好瞭,如果最後這些日志信息對你來說是重要的,那麼你可能需要寫更多代碼去實現。

知識點擴展:

實例:

BOOL WINAPI ConsoleHandler(DWORD CEvent)
{
DWORD e = 0;
switch (CEvent)
{
case CTRL_C_EVENT:
e = CTRL_C_EVENT;
break;
case CTRL_BREAK_EVENT:
e = CTRL_BREAK_EVENT;
break;
case CTRL_CLOSE_EVENT:
e = CTRL_CLOSE_EVENT;
break;
case CTRL_LOGOFF_EVENT:
break;
case CTRL_SHUTDOWN_EVENT:
break;
}
return true;
}
int main(int argc, char* argv[])
{
if (SetConsoleCtrlHandler((PHANDLER_ROUTINE)ConsoleHandler, TRUE) == FALSE)
{
//安裝失敗
return -1;
}
GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); //手工產生一事件
}

到此這篇關於vc控制臺程序關閉事件時的處理方式及註意點詳解的文章就介紹到這瞭,更多相關vc控制臺程序關閉事件時的正確處理方式內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: