Come si stampa nella finestra di output del debug in un'app Win32?


97

Ho un progetto win32 che ho caricato in Visual Studio 2005. Mi piacerebbe essere in grado di stampare le cose nella finestra di output di Visual Studio, ma non riesco a capire come. Ho provato "printf" e "cout <<" ma i miei messaggi rimangono ostinatamente non stampati.

Esiste un modo speciale per stampare nella finestra di output di Visual Studio?


11
Si noti che la finestra di output di Visual Studio non è la console. Sono entrambe "finestre con del testo", ma sono diverse dietro le quinte.
MSalters

Risposte:


136

Puoi usare OutputDebugString. OutputDebugStringè una macro che, a seconda delle opzioni di compilazione, esegue il mapping a OutputDebugStringA(char const*)o OutputDebugStringW(wchar_t const*). Nell'ultimo caso si dovrà fornire una stringa di caratteri ampia alla funzione. Per creare un carattere letterale ampio puoi utilizzare il Lprefisso:

OutputDebugStringW(L"My output string.");

Normalmente utilizzerai la versione macro insieme alla _Tmacro in questo modo:

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

Se il progetto è configurato per compilare per UNICODE, si espanderà in:

OutputDebugStringW(L"My output string.");

Se non stai creando per UNICODE, si espanderà in:

OutputDebugStringA("My output string.");

2
Perfetto! Grazie. Per completezza, però, si è scoperto che dovevo fare questo: OutputDebugString (TEXT ("Hello console world")); .. presumibilmente a causa di una sorta di opzione di compilazione relativa a Unicode.
izb

1
nota che troverai utile avere debugview da sysinternals. Ciò consente di vedere l'output ODS anche se Visual Studio non è in esecuzione (o addirittura installato) sulla confezione
pm100

4
@CDT: dipende dal tipo di file myStr. E ' char*, wchar_t*o LPTSTR? Supponendo che si tratti char*semplicemente di chiamare OutputDebugStringA(myStr)o utilizzare OutputDebugStringWcon wchar_t*e OutputDebugStringcon LPTSTRcome spiegato nella mia risposta.
Martin Liversage

1
@CDT: Cosa c'è di più semplice che chiamare una funzione con un singolo parametro che è il messaggio che si desidera visualizzare? È la complessità ANSI / UNICODE? Basta usare OutputDebugStringe definire i simboli del preprocessore appropriati in modo che corrispondano alla larghezza dei caratteri che usi o scegli i tipi flessibili "T" che ti permettono di compilare sia caratteri a 8 che a 16 bit.
Martin Liversage

1
@MonaJalal: dal tuo commento non è chiaro quale sia lo schermo, quindi è un po 'difficile darti un consiglio specifico. Se si esegue il debug del processo, il debugger avrà un modo per visualizzare l'output di debug. Se utilizzi Visual Studio come debugger, l'output viene visualizzato nella finestra Output . Per vedere effettivamente l'output è necessario selezionare Debug dalla Mostra in uscita dal menu a discesa. Se per qualche motivo stai eseguendo il tuo processo al di fuori di un debugger, puoi usare DebugView per vedere l'output di debug di tutti i processi.
Martin Liversage

29

Se il progetto è un progetto GUI, non verrà visualizzata alcuna console. Per cambiare il progetto in uno console devi andare al pannello delle proprietà del progetto e impostare:

  • In " linker-> System-> SubSystem " il valore " Console (/ SUBSYSTEM: CONSOLE) "
  • In " C / C ++ -> Preprocessore-> Definizioni preprocessore " aggiungi la definizione " _CONSOLE "

Questa soluzione funziona solo se avevi il classico punto di ingresso " int main () ".

Ma se sei come nel mio caso (un progetto openGL), non è necessario modificare le proprietà, poiché funziona meglio:

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

printf e cout funzioneranno come al solito.

Se chiami AllocConsole prima della creazione di una finestra, la console apparirà dietro la finestra, se la chiami dopo, apparirà davanti.

Aggiornare

freopenè deprecato e potrebbe non essere sicuro. Usa freopen_sinvece:

FILE* fp;

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

EDITBINpuò impostare il sottosistema CONSOLEanche se stai usando WinMaininvece di int main().
Ben Voigt

1
@Zac. Grazie! Le 4 righe che iniziano con AllocConsole () hanno funzionato alla grande. Più 1 per quello. Nient'altro funzionava, anche se ho ottenuto console per apparire prima nei progetti Win32 prima di utilizzare le macro / SUBSYSTEM: CONSOLE e / o _CONSOLE prima. Non so perché le macro non hanno funzionato questa sera. Potrebbe avere qualcosa a che fare con l'utilizzo del supporto Common Language Runtime (/ clr) ?
rider Bill

12

Per stampare sulla realconsole, è necessario renderlo visibile utilizzando il flag del linker /SUBSYSTEM:CONSOLE. La finestra della console aggiuntiva è fastidiosa, ma per scopi di debug è molto preziosa.

OutputDebugString stampa sull'output del debugger durante l'esecuzione all'interno del debugger.


6
Puoi anche allocare la tua console utilizzando AllocConsole ()
Billy ONeal

4

Prendi in considerazione l'utilizzo delle macro di runtime VC ++ per i rapporti _RPT N () e _RPTF N ()

È possibile utilizzare le macro _RPTn e _RPTFn, definite in CRTDBG.H, per sostituire l'uso delle istruzioni printf per il debug. Queste macro scompaiono automaticamente nella build di rilascio quando _DEBUG non è definito, quindi non è necessario racchiuderle in #ifdefs.

Esempio...

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

Oppure puoi utilizzare le funzioni di runtime di VC ++ _CrtDbgReport, _CrtDbgReportW direttamente.

_CrtDbgReport e _CrtDbgReportW possono inviare il rapporto di debug a tre diverse destinazioni: un file di rapporto di debug, un monitor di debug (il debugger di Visual Studio) o una finestra di messaggio di debug.

_CrtDbgReport e _CrtDbgReportW creano il messaggio utente per il rapporto di debug sostituendo gli argomenti [n] argomenti nella stringa di formato, utilizzando le stesse regole definite dalle funzioni printf o wprintf. Queste funzioni generano quindi il rapporto di debug e determinano la destinazione o le destinazioni, in base alle modalità di rapporto correnti e al file definito per reportType. Quando il report viene inviato a una finestra di messaggio di debug, il nome del file, il numero di riga e il nome del modulo vengono inclusi nelle informazioni visualizzate nella finestra.


Vale la pena aggiungere alla risposta o notare che _RPTF0può essere utilizzata laddove non è previsto il passaggio di variabili dopo la stringa di formato. La _RPTFNmacro, invece, richiede almeno un argomento che segue la stringa di formato.
amn

4

Se vuoi stampare variabili decimali:

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

4

Se hai bisogno di vedere l'output di un programma esistente che ha ampiamente utilizzato printf senza modificare il codice (o con modifiche minime) puoi ridefinire printf come segue e aggiungerlo all'intestazione comune (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
attenzione a causa del buffer statico, questa funzione non è rientrante e non può essere utilizzata da thread diversi.
Nikazo

2

Il tuo progetto Win32 è probabilmente un progetto GUI, non un progetto console. Ciò causa una differenza nell'intestazione eseguibile. Di conseguenza, il tuo progetto GUI sarà responsabile dell'apertura della propria finestra. Potrebbe essere una finestra della console, però. Chiama AllocConsole()per crearlo e usa le funzioni della console Win32 per scriverci.


2

Stavo cercando un modo per farlo da solo e ho trovato una soluzione semplice.

Presumo che tu abbia avviato un progetto Win32 predefinito (applicazione Windows) in Visual Studio, che fornisce una funzione "WinMain". Per impostazione predefinita, Visual Studio imposta il punto di ingresso su "SUBSYSTEM: WINDOWS". Devi prima cambiarlo andando a:

Progetto -> Proprietà -> Linker -> Sistema -> Sottosistema

E seleziona "Console (/ SUBSYSTEM: CONSOLE)" dall'elenco a discesa.

Ora, il programma non verrà eseguito, poiché è necessaria una funzione "principale" invece della funzione "WinMain".

Quindi ora puoi aggiungere una funzione "principale" come faresti normalmente in C ++. Dopodiché, per avviare il programma GUI, è possibile richiamare la funzione "WinMain" dall'interno della funzione "main".

La parte iniziale del tuo programma dovrebbe ora assomigliare a questa:

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

Risultato della mia implementazione

Ora è possibile utilizzare le funzioni per eseguire l'output sulla console in qualsiasi parte del programma GUI per il debug o per altri scopi.


2

È inoltre possibile utilizzare il metodo WriteConsole per stampare su console.

AllocConsole();
LPSTR lpBuff = "Hello Win32 API";
DWORD dwSize = 0;
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), lpBuff, lstrlen(lpBuff), &dwSize, NULL);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.