Как выполнить печать в окне вывода отладки в приложении Win32?


98

У меня есть проект win32, который я загрузил в Visual Studio 2005. Я хотел бы иметь возможность печатать что-либо в окне вывода Visual Studio, но я не могу понять, как это сделать. Я пытался «Printf» и «<<» COUT но мои сообщения остаются упорно без надписей.

Есть ли какой-то особый способ печати в окне вывода Visual Studio?


11
Обратите внимание, что окно вывода Visual Studio не является консолью. Оба они представляют собой «окна с текстом», но за кадром они разные.
MSalters

Если окно вывода VS по умолчанию показывает полный путь к исходному cpp перед каждым сообщением, рассмотрите обходной путь для __ FILE __.
Лори Стерн,

Ответы:


137

Вы можете использовать OutputDebugString. OutputDebugString- это макрос, который в зависимости от ваших параметров сборки сопоставляется с OutputDebugStringA(char const*)или OutputDebugStringW(wchar_t const*). В последнем случае вам нужно будет передать функции строку широких символов. Чтобы создать литерал с широким символом, вы можете использовать Lпрефикс:

OutputDebugStringW(L"My output string.");

Обычно вы будете использовать версию макроса вместе с таким _Tмакросом:

OutputDebugString(_T("My output string."));

Если ваш проект настроен на сборку для UNICODE, он расширится до:

OutputDebugStringW(L"My output string.");

Если вы не строите для UNICODE, он расширится до:

OutputDebugStringA("My output string.");

2
Отлично! Спасибо. Однако для полноты картины мне пришлось сделать следующее: OutputDebugString (TEXT ("Hello console world")); .. предположительно из-за какой-то опции сборки, связанной с юникодом.
izb

1
обратите внимание, что вам будет полезно получить отладочную информацию из sysinternals. Это позволяет вам видеть вывод ODS, даже если Visual Studio не запущена (или даже не установлена) на приставке
pm100,

4
@CDT: Это зависит от типа myStr. Является ли это char*, wchar_t*или LPTSTR? Предполагая, что это char*вы просто звоните OutputDebugStringA(myStr)или используете OutputDebugStringWwith wchar_t*и OutputDebugStringwith, LPTSTRкак описано в моем ответе.
Martin Liversage

1
@CDT: Что может быть проще, чем вызов функции с единственным параметром, который является сообщением, которое вы хотите вывести? Это сложность ANSI / UNICODE? Просто используйте OutputDebugStringи либо определите соответствующие символы препроцессора, соответствующие ширине символов, которые вы используете, либо используйте гибкие типы «T», которые позволяют компилировать как 8-, так и 16-битные символы.
Martin Liversage

1
@MonaJalal: Из вашего комментария неясно, какой экран , поэтому немного сложно дать вам конкретный совет. Если вы отлаживаете свой процесс, отладчик сможет отображать результаты отладки. Если вы используете Visual Studio в качестве отладчика, результат отображается в окне вывода . Чтобы увидеть результат, вам нужно выбрать « Отладка» в раскрывающемся списке « Показать вывод из» . Если вы по какой-то причине запускаете свой процесс вне отладчика, вы можете использовать DebugView, чтобы увидеть вывод отладки всех процессов.
Martin Liversage 02

29

Если проект представляет собой проект с графическим интерфейсом, консоль не появится. Для того, чтобы превратить проект в консольный, вам нужно зайти в панель свойств проекта и установить:

  • В « компоновщик-> Система-> Подсистема » значение « Консоль (/ SUBSYSTEM: CONSOLE) »
  • В " C / C ++ -> Preprocessor-> Preprocessor Definitions " добавьте определение " _CONSOLE "

Это решение работает, только если у вас есть классическая точка входа « int main () ».

Но если вы похожи на мой случай (проект openGL), вам не нужно редактировать свойства, так как это работает лучше:

AllocConsole();
freopen("CONIN$", "r",stdin);
freopen("CONOUT$", "w",stdout);
freopen("CONOUT$", "w",stderr);

printf и cout будут работать как обычно.

Если вы вызовете AllocConsole перед созданием окна, консоль появится за окном, если вы вызовете ее после, она появится впереди.

Обновить

freopenустарела и может быть небезопасной. freopen_sВместо этого используйте :

FILE* fp;

AllocConsole();
freopen_s(&fp, "CONIN$", "r", stdin);
freopen_s(&fp, "CONOUT$", "w", stdout);
freopen_s(&fp, "CONOUT$", "w", stderr);

EDITBINможно установить подсистему, CONSOLEдаже если вы используете WinMainвместо int main().
Бен Фойгт

1
@Zac. Спасибо! Четыре строки, начинающиеся с AllocConsole (), отлично работали. Плюс 1 за это. Больше ничего не работало, хотя у меня раньше появлялись консоли в проектах Win32 перед использованием макросов / SUBSYSTEM: CONSOLE и / или _CONSOLE. Не знаю, почему сегодня вечером макросы не сработали. Может ли это иметь какое-либо отношение к использованию Common Language Runtime Support (/ clr) ?
riderBill

12

Чтобы печатать в realконсоли, вам нужно сделать его видимым с помощью флага компоновщика /SUBSYSTEM:CONSOLE. Дополнительное окно консоли раздражает, но для целей отладки очень ценно.

OutputDebugString выводит на вывод отладчика при работе внутри отладчика.


6
Вы также можете выделить свою собственную консоль с помощью AllocConsole ()
Билли Онил,

5

Рассмотрите возможность использования макросов времени выполнения VC ++ для создания отчетов _RPT N () и _RPTF N ()

Вы можете использовать макросы _RPTn и _RPTFn, определенные в CRTDBG.H, чтобы заменить использование операторов printf для отладки. Эти макросы автоматически исчезают в вашей сборке выпуска, если _DEBUG не определен, поэтому нет необходимости заключать их в #ifdefs.

Пример...

if (someVar > MAX_SOMEVAR) {
    _RPTF2(_CRT_WARN, "In NameOfThisFunc( )," 
         " someVar= %d, otherVar= %d\n", someVar, otherVar );
}

Или вы можете напрямую использовать функции времени выполнения VC ++ _CrtDbgReport, _CrtDbgReportW .

_CrtDbgReport и _CrtDbgReportW могут отправлять отчет об отладке в три разных места назначения: файл отчета отладки, монитор отладки (отладчик Visual Studio) или окно сообщения отладки.

_CrtDbgReport и _CrtDbgReportW создают пользовательское сообщение для отчета об отладке, подставляя аргумент [n] arguments в строку формата, используя те же правила, которые определены функциями printf или wprintf. Затем эти функции создают отчет об отладке и определяют место назначения или места назначения на основе текущих режимов отчета и файла, определенного для reportType. Когда отчет отправляется в окно сообщения отладки, имя файла, lineNumber и moduleName включаются в информацию, отображаемую в окне.


Стоит добавить к ответу или отметить, что _RPTF0можно использовать там, где не ожидается, что переменные будут переданы после строки формата. _RPTFNМакро, с другой стороны, требует , по меньшей мере , один аргумента следующей строки формата.
amn

5

Если вы хотите распечатать десятичные переменные:

wchar_t text_buffer[20] = { 0 }; //temporary buffer
swprintf(text_buffer, _countof(text_buffer), L"%d", your.variable); // convert
OutputDebugString(text_buffer); // print

%uдля беззнакового, %fдля плавающего по ссылке .
Лори Стерн,

4

Если вам нужен вывод существующей программы, которая широко использовала printf без изменения кода (или с минимальными изменениями), вы можете переопределить printf следующим образом и добавить его в общий заголовок (stdafx.h).

int print_log(const char* format, ...)
{
    static char s_printf_buf[1024];
    va_list args;
    va_start(args, format);
    _vsnprintf(s_printf_buf, sizeof(s_printf_buf), format, args);
    va_end(args);
    OutputDebugStringA(s_printf_buf);
    return 0;
}

#define printf(format, ...) \
        print_log(format, __VA_ARGS__)

1
будьте осторожны из-за статического буфера, эта функция не является реентерабельной и не может использоваться из разных потоков.
Nikazo 07

2

Ваш проект Win32, скорее всего, представляет собой проект графического интерфейса, а не консольный проект. Это вызывает разницу в исполняемом заголовке. В результате ваш проект графического интерфейса будет отвечать за открытие собственного окна. Хотя это может быть консольное окно. Вызовите AllocConsole()его, чтобы создать его, и используйте функции консоли Win32 для записи в него.


2

Я сам искал способ сделать это и нашел простое решение.

Я предполагаю, что вы запустили проект Win32 по умолчанию (приложение Windows) в Visual Studio, который предоставляет функцию «WinMain». По умолчанию Visual Studio устанавливает точку входа в «SUBSYSTEM: WINDOWS». Вам необходимо сначала изменить это, перейдя по ссылке:

Проект -> Свойства -> Компоновщик -> Система -> Подсистема

И выберите «Консоль (/ SUBSYSTEM: CONSOLE)» из раскрывающегося списка.

Теперь программа не запустится, так как вместо функции «WinMain» нужна функция «main».

Итак, теперь вы можете добавить «основную» функцию, как обычно в C ++. После этого, чтобы запустить программу GUI, вы можете вызвать функцию «WinMain» изнутри функции «main».

Начальная часть вашей программы должна теперь выглядеть примерно так:

#include <iostream>

using namespace std;

// Main function for the console
int main(){

    // Calling the wWinMain function to start the GUI program
    // Parameters:
    // GetModuleHandle(NULL) - To get a handle to the current instance
    // NULL - Previous instance is not needed
    // NULL - Command line parameters are not needed
    // 1 - To show the window normally
    wWinMain(GetModuleHandle(NULL), NULL,NULL, 1); 

    system("pause");
    return 0;
}

// Function for entry into GUI program
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    // This will display "Hello World" in the console as soon as the GUI begins.
    cout << "Hello World" << endl;
.
.
.

Результат моей реализации

Теперь вы можете использовать функции для вывода на консоль в любой части программы с графическим интерфейсом пользователя для отладки или других целей.


2

Вы также можете использовать метод WriteConsole для печати на консоли.

AllocConsole();
LPSTR lpBuff = "Hello Win32 API";
DWORD dwSize = 0;
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), lpBuff, lstrlen(lpBuff), &dwSize, NULL);
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.