Service: C/C++ Tipps: Debug-Ausgaben auf Konsolenfenster umleiten


Im Artikel Adding Console I/O to a Win32 GUI App von Andrew Tucker (Windows Developer Journal, Ausgabe Dezember 1997) ist beschrieben, wie man aus einer grafischen Bedieneroberfläche heraus ein Konsolenfenster (DOS-Fenster) startet und stdin, stdout und errout auf dieses Konsolenfenster umleitet.

Diese Technik kann bei manchen Arten von Anwendungsfehlern die Fehlersuche vereinfachen - besonders für 'des Programmierers liebste Art von Fehlern': Fehler, die nicht auf dem Entwicklungssystem sondern nur bei Anwendern auftreten. Allerdings gilt das mit der Einschränkung, dass man Zugriff auf den Rechner des Anwenders haben muss.

So geht's

Man kann sich in Andrew Tucker's Artikel festbeißen, um zu versuchen genau zu verstehen, was es 'im Hintergrund' mit der Umleitung auf sich hat. Man kann es sich ein wenig einfacher machen: Den Artikel überfliegen, um einen ungefähren Eindruck von der Technik zu bekommen und den Quellcode aus dem Artikel übernehmen. Oder noch einfacher: Das Hintergrundwissen bis auf Weiteres ignorieren und nur den Quellcode übernehmen.

Wie auch immer! Im Endeffekt geht es tatsächlich nur darum:

  • Listing 1 und Listing 2 aus dem Artikel in je eine CPP- und H-Datei kopieren.
  • Die H-Datei in die geeignete CPP-Datei einbinden: Z.B.: #include "guicon.h"
  • An passender Stelle der CPP-Datei RedirectIOToConsole(); aufrufen
  • Alle bzw. die gewünschten Debug-Ausgaben umleiten. Z.B. so:
// Redirect CrtDbg output
    _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
    _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR );
    _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
    _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDERR);
    _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
    _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR);

Das Ganze sollte in den passenden DEBUG Schalter gefasst sein. Z.B. so:

#ifdef _DEBUG
#include "guicon.h"
#endif
Anmerkungen zur Anwendung in der Praxis

Die oben sogenannte 'geeignete Stelle' ist im Normalfall der Startpunkt der Anwendung.

Sobald die Debug-Version der Anwendung gestartet wird, wird zusätzlich zum Hauptfenster der Anwendung das Konsolenfenster geladen, in dem dann die TRACE-Ausgaben erscheinen.

Wie oben gesagt, ist die Technik im allgemeinen nur hilfreich, wenn man sich vor den Problem-Rechner setzen kann, um das Konsolenfenster zu beobachten.

In vielen Fällen wird man mit den TRACE-Anweisungen mehr oder weniger experimentieren müssen, bevor man im Konsolenfenster die Ausgaben sieht, die für die Fehlerbeseitigung geeignet sind.

In einigen Situationen können die TRACE-Ausgaben sehr schnell durch das Konsolenfenster 'rasen', so dass Sie kaum in der Lage sind, Erkenntnisse bezüglich der Fehlerursache zu gewinnen. Versuchen Sie folgendes:

  • Verringern Sie die Anzahl der TRACE-Aufrufe im Code. Versuchen Sie, die relevanten Stellen zu ermitteln. Fügen Sie dort Ihre TRACE-Aufrufe ein und deaktivieren Sie alle anderen.
  • Versuchen, Sie die Ausführung des betreffenden Codes 'künstlich' zu verlangsamen.

Bedenken Sie Folgendes: Der Debug-Code kann den eigentlichen Code unter Umständen massiv beeinflussen. Insbesondere zeitkritische Anwendungen können in ihrem Verhalten massiv beeinflusst werden (erst recht, wenn Sie den Code 'künstlich' verlangsamen).

Wenn die TRACE-Ausgaben 'durch das Konsolenfenster rasen', kommt man leicht auf die Idee, die Ausgaben statt dessen in eine Datei umzuleiten (dann könnte man die Ausgaben später in aller Ruhe analysieren). Allerdings - wie bereits gesagt: Debug-Code kann den eigentlichen Code massiv beeinflussen. Das gilt erst recht, wenn der Debug-Code selbst relativ viel Leistung beansprucht. Dies ist bei den notwendigen Festplattenzugriffen für ein 'TRACE in Datei' weit eher der Fall. TRACE-Ausgaben in eine Datei können eine Alternative sein - in manchen Fällen können sie aber einen so grossen Einfluss auf den Code haben, dass das Ergebnis nicht mehr sinnvoll zu verwerten ist.

Der Nutzen von TRACE-Ausgaben ist unter Umständen weit höher, wenn ein zeitlicher Zusammenhang hergestellt werden kann. Deswegen sollte jeder TRACE-Ausgabe ein Zeitstempel hinzugefügt werden. Dabei sollte das 'besorgen' des Zeitstempels so wenig Leistung wie möglich beanspruchen (und damit möglichst wenig Einfluss auf den eigentliche Code der Anwendung haben). Eine Möglichkeit dazu: timeGetTime() aus Mmsystem.h (Windows.h). Ein entsprechender TRACE-Aufruf würde wie folgt aussehen:

    ATLTRACE(_T("%d: IToolDeviceImpl::OnTimer() entered\n"), timeGetTime());

Seitenanfang

Kontaktaufnahme- und Terminvereinbarung:

Bei Fragen und für Terminvereinbarungen erreichen Sie uns unter:

0 63 49 99 07 38

0 151 51 95 34 00

Oder nutzen Sie das Kontaktformular




Ihr Ansprechpartner:


Hier sollte das Fahnungsfoto zu sehen sein.

Ralf Kunsmann

Spezialist für VBA-Programmierung
(alle Office-Anwendungen)
Entwickler der
VBA-Extension-Tools