Wie drucke ich in einer Win32-App im Debug-Ausgabefenster?

97

Ich habe ein Win32-Projekt, das ich in Visual Studio 2005 geladen habe. Ich möchte in der Lage sein, Dinge im Visual Studio-Ausgabefenster zu drucken, kann aber für mein ganzes Leben nicht herausfinden, wie. Ich habe 'printf' und 'cout <<' ausprobiert, aber meine Nachrichten bleiben hartnäckig unbedruckt.

Gibt es eine spezielle Möglichkeit, im Visual Studio-Ausgabefenster zu drucken?

izb
quelle
11
Beachten Sie, dass das Visual Studio-Ausgabefenster nicht die Konsole ist. Sie sind beide "Fenster mit Text", aber hinter den Kulissen unterschiedlich.
MSalters

Antworten:

136

Sie können verwenden OutputDebugString. OutputDebugStringist ein Makro, das abhängig von Ihren Build-Optionen entweder OutputDebugStringA(char const*)oder zugeordnet ist OutputDebugStringW(wchar_t const*). Im späteren Fall müssen Sie der Funktion eine breite Zeichenfolge eingeben. Um ein breites Zeichenliteral zu erstellen, können Sie das LPräfix verwenden:

OutputDebugStringW(L"My output string.");

Normalerweise verwenden Sie die Makroversion zusammen mit dem _TMakro wie folgt :

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

Wenn Ihr Projekt für die Erstellung für UNICODE konfiguriert ist, wird es erweitert in:

OutputDebugStringW(L"My output string.");

Wenn Sie nicht für UNICODE bauen, wird es erweitert in:

OutputDebugStringA("My output string.");
Martin Liversage
quelle
2
Perfekt! Vielen Dank. Der Vollständigkeit halber stellte sich heraus, dass ich Folgendes tun musste: OutputDebugString (TEXT ("Hallo Konsolenwelt")); .. vermutlich aufgrund einer Unicode-bezogenen Build-Option.
izb
1
Beachten Sie, dass Sie es nützlich finden, Debugview von Sysinternals zu haben. Auf diese Weise können Sie die ODS-Ausgabe auch dann
anzeigen,
4
@CDT: Das hängt vom Typ ab myStr. Ist es char*, wchar_t*oder LPTSTR? Angenommen, char*Sie rufen einfach an OutputDebugStringA(myStr)oder verwenden OutputDebugStringWmit wchar_t*und OutputDebugStringmit, LPTSTRwie in meiner Antwort erläutert.
Martin Liversage
1
@CDT: Was ist einfacher als das Aufrufen einer Funktion mit einem einzelnen Parameter, der die Nachricht ist, die Sie ausgeben möchten? Ist es die ANSI / UNICODE-Komplexität? Verwenden Sie einfach OutputDebugStringdie entsprechenden Präprozessorsymbole und definieren Sie sie entweder so, dass sie der Breite der von Ihnen verwendeten Zeichen entsprechen, oder wählen Sie die flexiblen "T" -Typen, mit denen Sie sowohl 8- als auch 16-Bit-Zeichen kompilieren können.
Martin Liversage
1
@MonaJalal: Aus Ihrem Kommentar geht nicht hervor, welcher Bildschirm angezeigt wird. Daher ist es etwas schwierig, Ihnen spezifische Ratschläge zu geben. Wenn Sie Ihren Prozess debuggen, kann der Debugger die Debug-Ausgabe anzeigen. Wenn Sie Visual Studio als Debugger verwenden , ist der Ausgang in dem gezeigten Ausgabefenster. Um die Ausgabe tatsächlich anzuzeigen, müssen Sie in der Dropdown-Liste Ausgabe von anzeigen die Option Debug auswählen. Wenn Sie Ihren Prozess aus irgendeinem Grund außerhalb eines Debuggers ausführen , können Sie DebugView verwenden , um die Debug-Ausgabe aller Prozesse anzuzeigen .
Martin Liversage
29

Wenn es sich bei dem Projekt um ein GUI-Projekt handelt, wird keine Konsole angezeigt. Um das Projekt in eine Konsole umzuwandeln, müssen Sie im Projekteigenschaftenfenster Folgendes festlegen:

  • In " Linker-> System-> SubSystem " den Wert " Console (/ SUBSYSTEM: CONSOLE) "
  • In " C / C ++ -> Preprocessor-> Preprocessor Definitionen " add die " _CONSOLE " definieren

Diese Lösung funktioniert nur, wenn Sie den klassischen Einstiegspunkt " int main () " hatten.

Aber wenn Sie wie in meinem Fall (ein openGL-Projekt) sind, müssen Sie die Eigenschaften nicht bearbeiten, da dies besser funktioniert:

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

printf und cout funktionieren wie gewohnt.

Wenn Sie AllocConsole vor dem Erstellen eines Fensters aufrufen, wird die Konsole hinter dem Fenster angezeigt. Wenn Sie sie danach aufrufen, wird sie vor dem Fenster angezeigt.

Aktualisieren

freopenist veraltet und kann unsicher sein. Verwenden Sie freopen_sstattdessen:

FILE* fp;

AllocConsole();
freopen_s(&fp, "CONIN$", "r", stdin);
freopen_s(&fp, "CONOUT$", "w", stdout);
freopen_s(&fp, "CONOUT$", "w", stderr);
Zac
quelle
EDITBINkann das Subsystem auf einstellen, CONSOLEauch wenn Sie WinMainanstatt verwenden int main().
Ben Voigt
1
@ Zac. Vielen Dank! Die 4 Zeilen, die mit AllocConsole () beginnen, haben großartig funktioniert. Plus 1 dafür. Nichts anderes funktionierte, obwohl ich zuvor Konsolen in Win32-Projekten angezeigt habe, bevor ich die Makros / SUBSYSTEM: CONSOLE und / oder _CONSOLE verwendet habe. Ich weiß nicht, warum die Makros heute Abend nicht funktioniert haben. Könnte es etwas mit der Verwendung von Common Language Runtime Support (/ clr) zu tun haben ?
FahrerBill
12

Um auf der realKonsole zu drucken , müssen Sie sie mithilfe des Linker-Flags sichtbar machen /SUBSYSTEM:CONSOLE. Das zusätzliche Konsolenfenster ist ärgerlich, aber für Debugging-Zwecke sehr wertvoll.

OutputDebugString Druckt auf die Debugger-Ausgabe, wenn sie im Debugger ausgeführt wird.

Klingeln
quelle
6
Sie können auch Ihre eigene Konsole mit AllocConsole ()
Billy ONeal
4

Erwägen Sie die Verwendung der VC ++ - Laufzeitmakros für die Berichterstellung _RPT N () und _RPTF N ()

Sie können die in CRTDBG.H definierten Makros _RPTn und _RPTFn verwenden, um die Verwendung von printf-Anweisungen zum Debuggen zu ersetzen. Diese Makros verschwinden automatisch in Ihrem Release-Build, wenn _DEBUG nicht definiert ist, sodass Sie sie nicht in #ifdefs einschließen müssen.

Beispiel...

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

Oder Sie können die VC ++ - Laufzeitfunktionen _CrtDbgReport, _CrtDbgReportW direkt verwenden.

_CrtDbgReport und _CrtDbgReportW können den Debug-Bericht an drei verschiedene Ziele senden: eine Debug-Berichtsdatei, einen Debug-Monitor (den Visual Studio-Debugger) oder ein Debug-Meldungsfenster.

_CrtDbgReport und _CrtDbgReportW erstellen die Benutzernachricht für den Debug-Bericht, indem sie die Argumente argument [n] in die Formatzeichenfolge einsetzen, wobei dieselben Regeln verwendet werden, die von den Funktionen printf oder wprintf definiert wurden. Diese Funktionen generieren dann den Debug-Bericht und bestimmen das Ziel oder die Ziele basierend auf den aktuellen Berichtsmodi und der für reportType definierten Datei. Wenn der Bericht an ein Debug-Meldungsfenster gesendet wird, sind Dateiname, Zeilennummer und Modulname in den im Fenster angezeigten Informationen enthalten.

Autodidakt
quelle
Es lohnt sich, die Antwort zu ergänzen oder zu beachten, dass _RPTF0sie verwendet werden kann, wenn nach der Formatzeichenfolge keine Variablen übergeben werden sollen. Das _RPTFNMakro benötigt dagegen mindestens ein Argument nach der Formatzeichenfolge.
Amn
4

Wenn Sie Dezimalvariablen drucken möchten:

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

Wenn Sie die Ausgabe eines vorhandenen Programms sehen möchten, das printf ausgiebig verwendet hat, ohne den Code zu ändern (oder mit minimalen Änderungen), können Sie printf wie folgt neu definieren und zum allgemeinen Header (stdafx.h) hinzufügen.

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
quelle
1
Seien Sie wegen des statischen Puffers vorsichtig, diese Funktion ist nicht wiedereintrittsfähig und kann nicht von verschiedenen Threads verwendet werden.
Nikazo
2

Ihr Win32-Projekt ist wahrscheinlich ein GUI-Projekt, kein Konsolenprojekt. Dies führt zu einem Unterschied im ausführbaren Header. Infolgedessen ist Ihr GUI-Projekt dafür verantwortlich, ein eigenes Fenster zu öffnen. Das kann jedoch ein Konsolenfenster sein. Rufen Sie AllocConsole()auf, um es zu erstellen, und verwenden Sie die Win32-Konsolenfunktionen, um darauf zu schreiben.

MSalters
quelle
2

Ich suchte nach einer Möglichkeit, dies selbst zu tun, und fand eine einfache Lösung.

Ich gehe davon aus, dass Sie in Visual Studio ein Standard-Win32-Projekt (Windows-Anwendung) gestartet haben, das eine "WinMain" -Funktion bietet. Standardmäßig setzt Visual Studio den Einstiegspunkt auf "SUBSYSTEM: WINDOWS". Sie müssen dies zuerst ändern, indem Sie zu:

Projekt -> Eigenschaften -> Linker -> System -> Subsystem

Und wählen Sie "Konsole (/ SUBSYSTEM: CONSOLE)" aus der Dropdown-Liste.

Das Programm wird jetzt nicht ausgeführt, da anstelle der Funktion "WinMain" eine "Haupt" -Funktion benötigt wird.

Jetzt können Sie eine "Haupt" -Funktion hinzufügen, wie Sie es normalerweise in C ++ tun würden. Um das GUI-Programm zu starten, können Sie anschließend die Funktion "WinMain" innerhalb der Funktion "main" aufrufen.

Der Startteil Ihres Programms sollte nun ungefähr so ​​aussehen:

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

Ergebnis meiner Implementierung

Jetzt können Sie Funktionen verwenden, um sie in einem beliebigen Teil Ihres GUI-Programms zum Debuggen oder für andere Zwecke an die Konsole auszugeben.

Pops
quelle
2

Sie können auch die WriteConsole- Methode verwenden, um auf der Konsole zu drucken.

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