Comment imprimer dans la fenêtre de sortie de débogage dans une application Win32?

97

J'ai un projet win32 que j'ai chargé dans Visual Studio 2005. J'aimerais pouvoir imprimer des éléments dans la fenêtre de sortie de Visual Studio, mais je ne peux pas pour la vie de moi savoir comment. J'ai essayé 'printf' et 'cout <<' mais mes messages restent obstinément non imprimés.

Existe-t-il une manière spéciale d'imprimer dans la fenêtre de sortie de Visual Studio?

izb
la source
11
Notez que la fenêtre de sortie de Visual Studio n'est pas la console. Ce sont toutes les deux des "fenêtres contenant du texte", mais elles sont différentes dans les coulisses.
MSalters

Réponses:

136

Vous pouvez utiliser OutputDebugString. OutputDebugStringest une macro qui, en fonction de vos options de construction, correspond à OutputDebugStringA(char const*)ou OutputDebugStringW(wchar_t const*). Dans ce dernier cas, vous devrez fournir une large chaîne de caractères à la fonction. Pour créer un littéral de caractère large, vous pouvez utiliser le Lpréfixe:

OutputDebugStringW(L"My output string.");

Normalement, vous utiliserez la version macro avec la _Tmacro comme ceci:

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

Si votre projet est configuré pour construire pour UNICODE, il se développera en:

OutputDebugStringW(L"My output string.");

Si vous ne construisez pas pour UNICODE, il se développera en:

OutputDebugStringA("My output string.");
Martin Liversage
la source
2
Parfait! Merci. Pour être complet cependant, il s'est avéré que je devais faire ceci: OutputDebugString (TEXT ("Hello console world")); .. probablement en raison d'une sorte d'option de construction liée à Unicode.
izb
1
notez que vous trouverez utile d'avoir le debugview de sysinternals. Cela vous permet de voir la sortie ODS même si Visual Studio n'est pas en cours d'exécution (ou même installé) sur la boîte
pm100
4
@CDT: Cela dépend du type de myStr. Vraiment char*, wchar_t*ou LPTSTR? En supposant que ce soit char*vous appelez simplement OutputDebugStringA(myStr)ou utilisez OutputDebugStringWavec wchar_t*et OutputDebugStringavec LPTSTRcomme expliqué dans ma réponse.
Martin Liversage
1
@CDT: Qu'y a-t-il de plus simple que d'appeler une fonction ayant un seul paramètre qui est le message que vous voulez sortir? Est-ce la complexité ANSI / UNICODE? Il suffit d'utiliser OutputDebugStringet de définir les symboles de préprocesseur appropriés pour correspondre à la largeur des caractères que vous utilisez ou d'utiliser les types flexibles "T" qui vous permettent de compiler à la fois des caractères 8 et 16 bits.
Martin Liversage
1
@MonaJalal: Il n'est pas clair dans votre commentaire quel écran est donc il est un peu difficile de vous donner des conseils spécifiques. Si vous déboguez votre processus, le débogueur aura un moyen d'afficher la sortie de débogage. Si vous utilisez Visual Studio comme débogueur, la sortie s'affiche dans la fenêtre Sortie . Pour voir réellement la sortie, vous devez sélectionner Déboguer dans la liste déroulante Afficher la sortie . Si, pour une raison quelconque, vous exécutez votre processus en dehors d'un débogueur, vous pouvez utiliser DebugView pour voir la sortie de débogage de tous les processus.
Martin Liversage
29

Si le projet est un projet GUI, aucune console n'apparaîtra. Pour changer le projet en une console, vous devez aller dans le panneau des propriétés du projet et définir:

  • Dans " linker-> System-> SubSystem ", la valeur " Console (/ SUBSYSTEM: CONSOLE) "
  • Dans " C / C ++ -> Preprocessor-> Preprocessor Definitions ", ajoutez la définition " _CONSOLE "

Cette solution ne fonctionne que si vous aviez le point d'entrée classique " int main () ".

Mais si vous êtes comme dans mon cas (un projet openGL), vous n'avez pas besoin de modifier les propriétés, car cela fonctionne mieux:

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

printf et cout fonctionneront comme d'habitude.

Si vous appelez AllocConsole avant la création d'une fenêtre, la console apparaîtra derrière la fenêtre, si vous l'appelez après, elle apparaîtra en avant.

Mettre à jour

freopenest obsolète et peut être dangereux. Utilisez à la freopen_splace:

FILE* fp;

AllocConsole();
freopen_s(&fp, "CONIN$", "r", stdin);
freopen_s(&fp, "CONOUT$", "w", stdout);
freopen_s(&fp, "CONOUT$", "w", stderr);
Zac
la source
EDITBINpeut définir le sous-système sur CONSOLEmême si vous utilisez WinMainplutôt que int main().
Ben Voigt
1
@Zac. Merci! Les 4 lignes commençant par AllocConsole () ont très bien fonctionné. Plus 1 pour ça. Rien d'autre ne fonctionnait, même si j'ai déjà fait apparaître des consoles dans des projets Win32 avant d'utiliser les macros / SUBSYSTEM: CONSOLE et / ou _CONSOLE auparavant. Je ne sais pas pourquoi les macros n'ont pas fonctionné ce soir. Cela pourrait-il avoir quelque chose à voir avec l'utilisation du support Common Language Runtime (/ clr) ?
riderBill
12

Pour imprimer sur la realconsole, vous devez le rendre visible à l'aide de l'indicateur de l'éditeur de liens /SUBSYSTEM:CONSOLE. La fenêtre de console supplémentaire est ennuyeuse, mais à des fins de débogage, elle est très précieuse.

OutputDebugString imprime sur la sortie du débogueur lors de l'exécution à l'intérieur du débogueur.

Sonnerie
la source
6
Vous pouvez également allouer votre propre console en utilisant AllocConsole ()
Billy ONeal
4

Envisagez d'utiliser les macros d'exécution VC ++ pour Reporting _RPT N () et _RPTF N ()

Vous pouvez utiliser les macros _RPTn et _RPTFn, définies dans CRTDBG.H, pour remplacer l'utilisation d'instructions printf pour le débogage. Ces macros disparaissent automatiquement dans votre version de version lorsque _DEBUG n'est pas défini, il n'est donc pas nécessaire de les enfermer dans #ifdefs.

Exemple...

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

Ou vous pouvez utiliser les fonctions d'exécution VC ++ _CrtDbgReport, _CrtDbgReportW directement.

_CrtDbgReport et _CrtDbgReportW peuvent envoyer le rapport de débogage vers trois destinations différentes: un fichier de rapport de débogage, un moniteur de débogage (le débogueur Visual Studio) ou une fenêtre de message de débogage.

_CrtDbgReport et _CrtDbgReportW créent le message utilisateur pour le rapport de débogage en substituant l'argument [n] arguments dans la chaîne de format, en utilisant les mêmes règles définies par les fonctions printf ou wprintf. Ces fonctions génèrent ensuite le rapport de débogage et déterminent la ou les destinations, en fonction des modes de rapport actuels et du fichier défini pour reportType. Lorsque le rapport est envoyé à une fenêtre de message de débogage, le nom de fichier, lineNumber et moduleName sont inclus dans les informations affichées dans la fenêtre.

Autocrate
la source
Cela vaut la peine d'ajouter à la réponse ou de noter que cela _RPTF0peut être utilisé là où aucune variable ne devrait être transmise après la chaîne de format. La _RPTFNmacro, en revanche, nécessite au moins un argument après la chaîne de format.
amn
4

Si vous souhaitez imprimer des variables décimales:

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

Si vous avez besoin de voir la sortie d'un programme existant qui a largement utilisé printf sans changer le code (ou avec des changements minimes), vous pouvez redéfinir printf comme suit et l'ajouter à l'en-tête commun (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
la source
1
attention à cause du tampon statique, cette fonction n'est pas réentrante et ne peut pas être utilisée à partir de différents threads.
Nikazo
2

Votre projet Win32 est probablement un projet GUI, pas un projet de console. Cela provoque une différence dans l'en-tête de l'exécutable. En conséquence, votre projet GUI sera responsable de l'ouverture de sa propre fenêtre. Cela peut être une fenêtre de console, cependant. Appelez AllocConsole()pour le créer et utilisez les fonctions de la console Win32 pour y écrire.

MSalters
la source
2

Je cherchais un moyen de le faire moi-même et j'ai trouvé une solution simple.

Je suppose que vous avez démarré un projet Win32 par défaut (application Windows) dans Visual Studio, qui fournit une fonction "WinMain". Par défaut, Visual Studio définit le point d'entrée sur «SUBSYSTEM: WINDOWS». Vous devez d'abord changer cela en accédant à:

Projet -> Propriétés -> Linker -> Système -> Sous-système

Et sélectionnez "Console (/ SUBSYSTEM: CONSOLE)" dans la liste déroulante.

Désormais, le programme ne fonctionnera pas, car une fonction "main" est nécessaire à la place de la fonction "WinMain".

Vous pouvez maintenant ajouter une fonction "main" comme vous le feriez normalement en C ++. Ensuite, pour démarrer le programme GUI, vous pouvez appeler la fonction "WinMain" depuis la fonction "main".

La partie de départ de votre programme devrait maintenant ressembler à ceci:

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

Résultat de ma mise en œuvre

Vous pouvez maintenant utiliser des fonctions pour générer une sortie vers la console dans n'importe quelle partie de votre programme GUI à des fins de débogage ou à d'autres fins.

pop
la source
2

Vous pouvez également utiliser la méthode WriteConsole pour imprimer sur la console.

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