¿Cómo imprimo en la ventana de salida de depuración en una aplicación Win32?

97

Tengo un proyecto win32 que cargué en Visual Studio 2005. Me gustaría poder imprimir cosas en la ventana de salida de Visual Studio, pero no puedo por mi vida averiguar cómo. Probé 'printf' y 'cout <<' pero mis mensajes permanecen obstinadamente sin imprimir.

¿Existe alguna forma especial de imprimir en la ventana de salida de Visual Studio?

izb
fuente
11
Tenga en cuenta que la ventana de salida de Visual Studio no es la consola. Ambas son "ventanas con texto", pero son diferentes detrás de escena.
MSalters

Respuestas:

136

Puede utilizar OutputDebugString. OutputDebugStringes una macro que, según sus opciones de compilación, se asigna a OutputDebugStringA(char const*)o OutputDebugStringW(wchar_t const*). En el último caso, deberá proporcionar una cadena de caracteres amplia a la función. Para crear un literal de carácter amplio, puede usar el Lprefijo:

OutputDebugStringW(L"My output string.");

Normalmente, usará la versión macro junto con la _Tmacro de esta manera:

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

Si su proyecto está configurado para compilar para UNICODE, se expandirá a:

OutputDebugStringW(L"My output string.");

Si no está construyendo para UNICODE, se expandirá a:

OutputDebugStringA("My output string.");
Martin Liversage
fuente
2
¡Perfecto! Gracias. Sin embargo, para completarlo, resultó que tenía que hacer esto: OutputDebugString (TEXT ("Hola mundo de la consola")); .. presumiblemente debido a algún tipo de opción de compilación relacionada con Unicode.
izb
1
tenga en cuenta que le resultará útil tener debugview desde sysinternals. Esto le permite ver la salida de ODS incluso si Visual Studio no se está ejecutando (o incluso no está instalado) en la caja
pm100
4
@CDT: Depende del tipo de myStr. ¿Es char*, wchar_t*o LPTSTR? Suponiendo que char*simplemente llame OutputDebugStringA(myStr)o use OutputDebugStringWcon wchar_t*y OutputDebugStringcon LPTSTRcomo se explica en mi respuesta.
Martin Liversage
1
@CDT: ¿Qué es más simple que llamar a una función que tiene un solo parámetro que es el mensaje que desea enviar? ¿Es la complejidad ANSI / UNICODE? Simplemente use OutputDebugStringy defina los símbolos de preprocesador apropiados para que coincidan con el ancho de los caracteres que usa o elija los tipos flexibles de "T" que le permiten compilar caracteres de 8 y 16 bits.
Martin Liversage
1
@MonaJalal: Tu comentario no deja claro qué pantalla es, por lo que es un poco difícil darte un consejo específico. Si depura su proceso, el depurador tendrá una forma de mostrar la salida de depuración. Si está utilizando Visual Studio como depurador, la salida se muestra en la ventana Salida . Para ver realmente la salida, debe seleccionar Depurar en el menú desplegable Mostrar salida . Si por alguna razón está ejecutando su proceso fuera de un depurador, puede usar DebugView para ver la salida de depuración de todos los procesos.
Martin Liversage
29

Si el proyecto es un proyecto de GUI, no aparecerá ninguna consola. Para cambiar el proyecto a uno de consola, debe ir al panel de propiedades del proyecto y configurar:

  • En " enlazador-> Sistema-> SubSistema " el valor " Consola (/ SUBSYSTEM: CONSOLE) "
  • En " C / C ++ -> Preprocesador-> Definiciones del preprocesador " agregue la definición " _CONSOLE "

Esta solución solo funciona si tenía el punto de entrada clásico " int main () ".

Pero si eres como en mi caso (un proyecto openGL), no necesitas editar las propiedades, ya que esto funciona mejor:

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

printf y cout funcionarán como de costumbre.

Si llama a AllocConsole antes de la creación de una ventana, la consola aparecerá detrás de la ventana, si la llama después, aparecerá adelante.

Actualizar

freopenestá en desuso y puede no ser seguro. Utilice en su freopen_slugar:

FILE* fp;

AllocConsole();
freopen_s(&fp, "CONIN$", "r", stdin);
freopen_s(&fp, "CONOUT$", "w", stdout);
freopen_s(&fp, "CONOUT$", "w", stderr);
Zac
fuente
EDITBINpuede configurar el subsistema CONSOLEincluso si está utilizando en WinMainlugar de int main().
Ben Voigt
1
@Zac. ¡Gracias! Las 4 líneas que comienzan con AllocConsole () funcionaron muy bien. Más 1 por eso. Nada más funcionaba, aunque he conseguido que las consolas aparezcan antes en proyectos Win32 antes de usar las macros / SUBSYSTEM: CONSOLE y / o _CONSOLE antes. No sé por qué las macros no funcionaron esta noche. ¿Podría tener algo que ver con el uso de Common Language Runtime Support (/ clr) ?
riderBill
12

Para imprimir en la realconsola, debe hacerla visible mediante el indicador del vinculador /SUBSYSTEM:CONSOLE. La ventana adicional de la consola es molesta, pero para fines de depuración es muy valiosa.

OutputDebugString se imprime en la salida del depurador cuando se ejecuta dentro del depurador.

Ringding
fuente
6
También puede asignar su propia consola usando AllocConsole ()
Billy ONeal
4

Considere usar las macros de tiempo de ejecución de VC ++ para informar _RPT N () y _RPTF N ()

Puede usar las macros _RPTn y _RPTFn, definidas en CRTDBG.H, para reemplazar el uso de declaraciones printf para la depuración. Estas macros desaparecen automáticamente en su versión de lanzamiento cuando _DEBUG no está definido, por lo que no es necesario incluirlas en #ifdefs.

Ejemplo...

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

O puede usar las funciones de tiempo de ejecución de VC ++ _CrtDbgReport, _CrtDbgReportW directamente.

_CrtDbgReport y _CrtDbgReportW pueden enviar el informe de depuración a tres destinos diferentes: un archivo de informe de depuración, un monitor de depuración (el depurador de Visual Studio) o una ventana de mensaje de depuración.

_CrtDbgReport y _CrtDbgReportW crean el mensaje de usuario para el informe de depuración sustituyendo el argumento [n] argumentos en la cadena de formato, utilizando las mismas reglas definidas por las funciones printf o wprintf. Estas funciones luego generan el informe de depuración y determinan el destino o los destinos, según los modos de informe actuales y el archivo definido para reportType. Cuando el informe se envía a una ventana de mensaje de depuración, el nombre de archivo, el número de línea y el nombre del módulo se incluyen en la información que se muestra en la ventana.

Autodidacta
fuente
Vale la pena agregar a la respuesta o señalar que _RPTF0se puede usar donde no se espera que se pasen variables después de la cadena de formato. La _RPTFNmacro, por otro lado, requiere al menos un argumento después de la cadena de formato.
amn
4

Si desea imprimir variables decimales:

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

Si necesita ver la salida de un programa existente que usó ampliamente printf sin cambiar el código (o con cambios mínimos), puede redefinir printf de la siguiente manera y agregarlo al encabezado común (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__)
vlad
fuente
1
tenga cuidado debido al búfer estático, esta función no es reentrante y no se puede usar desde diferentes subprocesos.
Nikazo
2

Es probable que su proyecto Win32 sea un proyecto de GUI, no un proyecto de consola. Esto provoca una diferencia en el encabezado ejecutable. Como resultado, su proyecto de GUI será responsable de abrir su propia ventana. Sin embargo, esa puede ser una ventana de consola. Llame AllocConsole()para crearlo y utilice las funciones de la consola Win32 para escribir en él.

MSalters
fuente
2

Estaba buscando una forma de hacerlo yo mismo y descubrí una solución simple.

Supongo que inició un proyecto Win32 predeterminado (aplicación de Windows) en Visual Studio, que proporciona una función "WinMain". De forma predeterminada, Visual Studio establece el punto de entrada en "SUBSYSTEM: WINDOWS". Primero debe cambiar esto yendo a:

Proyecto -> Propiedades -> Vinculador -> Sistema -> Subsistema

Y seleccione "Consola (/ SUBSYSTEM: CONSOLE)" de la lista desplegable.

Ahora, el programa no se ejecutará, ya que se necesita una función "principal" en lugar de la función "WinMain".

Así que ahora puede agregar una función "principal" como lo haría normalmente en C ++. Después de esto, para iniciar el programa GUI, puede llamar a la función "WinMain" desde dentro de la función "principal".

La parte inicial de su programa ahora debería verse así:

#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;
.
.
.

Resultado de mi implementación

Ahora puede usar funciones para enviar a la consola en cualquier parte de su programa GUI para depuración u otros propósitos.

estallidos
fuente
2

También puede utilizar el método WriteConsole para imprimir en la consola.

AllocConsole();
LPSTR lpBuff = "Hello Win32 API";
DWORD dwSize = 0;
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), lpBuff, lstrlen(lpBuff), &dwSize, NULL);
HaseeB Mir
fuente