вторник, 3 ноября 2015 г.

Открытие и закрытие консольного окна для GUI-приложения

Работая с 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);
}





3 комментария:

Unknown комментирует...

Я новичок в теме программирования в Autocad.
Подскажите, пожалуйста, как выполнить данный код?

Андрей Бушман комментирует...

Обозначенные фрагменты исходного кода предназначены для использования в ObjectARX проектах. Т.о. необходимо иметь навыки написания кода на C++ в IDE MS Visual Studio (версия используемой IDE зависит от версии AutoCAD). Информацию о создании и конфигурировании ObjectARX проектов можно найти в книге Н.Н. Полещука: http://adn-cis.org/forum/index.php?topic=1097.0

Дмитрий Макаревич комментирует...

Спасибо за ссылку, с удовольствием почитаю!