1. 程式人生 > >【轉載】讓 Win32 視窗程式擁有控制檯視窗

【轉載】讓 Win32 視窗程式擁有控制檯視窗

讓 Win32 視窗程式擁有控制檯視窗

  首先,為什麼我們有了普通視窗後還要控制檯視窗呢?因為我們可以用它方便的輸出除錯資訊,而且普通玩家看到了也會覺得很高階。如果他會輸幾條命令,可能他會以為自己就是黑客了。

示例效果:

  WinMain 作為入口函式後,手動建立了控制檯視窗,然後建立了普通視窗,輸出了一些資訊到控制檯視窗。
示例圖片

具體實現:

  為什麼我不用 main 作為入口函式,再建立普通視窗呢?因為使用者不可以選擇關閉控制檯視窗。如果強行實現就是先找到視窗控制代碼然後再呼叫 ShowWindow 隱藏掉視窗。但實際還是會閃一下,其實大家可以發現有一些比較 low 的病毒雙擊後就會閃一下。
  要建立一個控制檯視窗,首先呼叫 AllocConsole 建立一個。但此時呼叫 cout 或者 printf 都不能正常輸出文字到視窗(包括輸入流 cin 和 scanf)。所以需要如下重定向輸入輸出流:

AllocConsole();
FILE* stream;
freopen_s(&stream, "CON", "r", stdin);//重定向輸入流
freopen_s(&stream, "CON", "w", stdout);//重定向輸入流

  如果我們需要用到控制檯視窗控制代碼,可以呼叫 FindWindow 取得:

HWND _consoleHwnd;
SetConsoleTitle(DEFAULT_CONSOLE_TITLE);//設定視窗名
for (int i = 0; i < 100; i++)
{
        _consoleHwnd = FindWindow(NULL
, DEFAULT_CONSOLE_TITLE); if (_consoleHwnd) break; Sleep(100); }

  然後還需要輸出流控制代碼:

HANDLE _handleOutput;
_handleOutput = GetStdHandle(STD_OUTPUT_HANDLE);

  在不需要的時候請呼叫 FreeConsole 釋放控制檯視窗:

FreeConsole();

  完成以上工作後,就能夠建立一個控制檯視窗,並能夠使用 cout 標準輸出流輸出文字到其上。這裡我們用 wcout 為例,並給文字新增上顏色:

void DebuggerConsole::Write(const String& str, int level)
{
        switch(level)
        {
        case DebugLevel::BLANK://空白
                SetConsoleTextAttribute(_handleOutput,
                                FOREGROUND_INTENSITY |
                                BACKGROUND_INTENSITY);
                break;
        case DebugLevel::TIME://時間(白色)
                SetConsoleTextAttribute(_handleOutput,
                                BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE |
                                BACKGROUND_INTENSITY);
                break;
        case DebugLevel::INFO://資訊(白色藍底)
                SetConsoleTextAttribute(_handleOutput,
                        FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE |
                        BACKGROUND_BLUE |
                        FOREGROUND_INTENSITY);
                break;
        case DebugLevel::NOTICE://提示(綠色)
                SetConsoleTextAttribute(_handleOutput,
                        FOREGROUND_GREEN |
                        BACKGROUND_GREEN |
                        FOREGROUND_INTENSITY);
                break;
        case DebugLevel::WARN://警告(黃色)
                SetConsoleTextAttribute(_handleOutput,
                        FOREGROUND_GREEN | FOREGROUND_RED |
                        BACKGROUND_GREEN | BACKGROUND_RED |
                        FOREGROUND_INTENSITY);
                break;
        case DebugLevel::ERR://錯誤(紅色)
                SetConsoleTextAttribute(_handleOutput,
                        FOREGROUND_RED |
                        BACKGROUND_RED |
                        FOREGROUND_INTENSITY);
                break;
        }
        std::wcout << str.GetWcs();//獲取字串WCHAR陣列版本
}

  其中 SetConsoleTextAttribute 設定了輸出文字的顏色,第一個引數是前面取得的輸出控制代碼,第二個引數是巨集的值組合。FOREGROUND 字首代表前景色,BACKGROUND 代表背景色。RED、GREEN、BLUE 是三原色分量,INTENSITY 代表顏色加強(變得更亮)。
  最後再提一句,wcout 不能直接輸出中文,需要提前呼叫一句(至於為什麼我也不知道^_^):

locale::global((locale("")));