Работая с GUI приложением иногда бывает удобно в режиме реального времени посмотреть, что оно отправляет себе на консоль (т.е. в потоки stdout и stderr), а порой может возникнуть и желание что-то отправить в поток stdin с клавиатуры. Можно, конечно же, выполнять перенаправление в файлы, но этот вариант не всегда удобен. В данной заметке, на примере AutoCAD, показано, как для GUI-приложения открыть консольное окно, выполнить перенаправление потоков и, после того как консольное окно не будет нужно, закрыть его.


Пример C++ кода, выполняющего открытие консольного окна и перенаправляющие потоки ввода-вывода:


// I open console window for AutoCAD GUI application
BOOL result = AllocConsole();

if (0 == result){
    DWORD errCode = GetLastError();
    LPTSTR msg = NULL;
    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
        | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errCode, 0, (LPTSTR)&msg, 0, NULL);

    acutPrintf(_T(«\nAllocConsole Error: %s»), msg);
    HeapFree(GetProcessHeap(), 0, msg);
}
else{
    acutPrintf(_T(«\nAllocConsole: OK.»));
    SetConsoleTitle(L»AutoCAD console window»);

    // Disable the close button of the Console window
    HWND hwnd = GetConsoleWindow();
    HMENU hmenu = GetSystemMenu(hwnd, FALSE);
    EnableMenuItem(hmenu, SC_CLOSE, MF_GRAYED);

    // redirecting of the streams
    freopen(«CONOUT$», «w», stdout);
    freopen(«CONOUT$», «w», stderr);
    freopen(«CONIN$», «r», stdin);

    // You will see this messages in the console window
    wcout << L»wcout ping…» << endl;
    wcerr << L»wcerr ping…» << endl;
    cout << «cout ping…» << endl;
    cerr << «cerr ping…» << endl;

    // check wcin accessibility
    wcout << L»Press any char: «;
    wchar_t c;
    wcin >> c;
    wcout << L»You pressed the ‘» << c << «‘ char.» << endl;
}


Результат выглядит следующим образом:

После того, как консольное окно станет ненужным, его можно закрыть. Однако его нельзя закрывать обычным кликом мышки по кнопке «X» в верхнем правом углу, иначе это приведёт к аварийному завершению работы GUI-приложения (в нашем примере — AutoCAD). Для того, чтобы пользователь случайно не нажал этой кнопки, в обозначенном выше коде мы делаем её недоступной.

Закрытие консольного окна выполняем так же программно:


BOOL result = FreeConsole();

if (0 == result){
    DWORD errCode = GetLastError();
    LPTSTR msg = NULL;
    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
        | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errCode, 0, (LPTSTR)&msg, 0, NULL);

    acutPrintf(_T(«\nFreeConsole Error: %s»), msg);
    HeapFree(GetProcessHeap(), 0, msg);
}
else{
    // redirecting of the streams
    freopen(«CONOUT$», «w», stdout);
    freopen(«CONOUT$», «w», stderr);
    freopen(«CONIN$», «r», stdin);
}