Créer un programme avec une fenêtre graphique et une sortie console


Lorsqu'on écrit un programme windows en mode graphique à l'aide du langage C (ou C++), en utilisant l'API Win32, il est parfois difficile d'identifer la cause de certaines erreurs pouvant survenir lors de l'exécution. Il est alors nécessaire de vérifier les valeurs prises par certaines variables pendant l'exécution. Cette vérification peut se faire relativement simplement, en affichant ces valeurs dans une fenêtre console à l'aide d'instructions printf() insérées dans le programme.

On trouve ci-après:
1) Un programme windows minimal doté à la fois d'une fenêtre et d'une sortie console;
2) Quelques remarques

1) Créer un programme Windows doté d'une fenetre graphique et d'une sortie console

Le programme suivant, de type fenêtre win32, a été créé avec CodeBlocks 16.01 sous Windows XP.

#include <windows.h>
#include <stdio.h>
#include<io.h>
#include <iostream>
using namespace std;
HDC hdc ; int gx=0; char texte[256];
//============ PARTIE A MODIFIER =========
void affiche_gui()
{
int x, y;
HPEN pinceau= CreatePen(PS_SOLID,2, RGB(255,255,0)); SelectObject(hdc, pinceau);
HBRUSH brosse= CreateSolidBrush( RGB( 0,0,255 ) ); SelectObject( hdc, brosse );
SetTextColor(hdc, RGB( 200,200,200 )); SetBkColor( hdc, RGB(0, 0, 0));
Ellipse(hdc, 120,120, 250, 200);
for (x=100; x<300; x++) { SetPixel( hdc, x, 100, RGB(255, 0, 0 ));}
for (y=100; y<200; y++) { SetPixel( hdc, 100, y, RGB(0, 255, 0)); }
printf("x = %d\n", x); printf("y = %d\n", y);
gx=gx+1;
sprintf(texte, " "); TextOut(hdc,0,15,texte, strlen(texte));
sprintf(texte, "1) gx= %d\n", gx); TextOut(hdc,0,5,texte, strlen(texte));
sprintf(texte, "2) Je fais gx=gx+1 si je masque cette fenetre\n"); TextOut( hdc,0,20, texte, strlen(texte));
sprintf(texte, " avec une autre fenêtre en la bougeant\n"); TextOut( hdc,0,35, texte, strlen(texte));
printf("3) gx = %d\n", gx);
}
void init_console()
{
AllocConsole();
SetConsoleTitle( "Ma fenetre console" ); fclose(stdout);
int fdout = _open_osfhandle( (long) GetStdHandle( STD_OUTPUT_HANDLE ), 0);
FILE* fout = _fdopen(fdout, "w");
*stdout = *fout;
}
//=============== ==============
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps; RECT rect;
switch (message){
case WM_DESTROY:PostQuitMessage (0); break;
case WM_PAINT:
hdc=BeginPaint(hwnd,&ps); GetClientRect(hwnd,&rect);
affiche_gui();
EndPaint(hwnd,&ps); break;
default: return DefWindowProc (hwnd, message, wParam, lParam);
}return 0;
}
int WINAPI WinMain (HINSTANCE hinst, HINSTANCE hprev, LPSTR arg, int cmd)
{
HWND hwnd; MSG messages; WNDCLASSEX wincl; char classe[]="test";
wincl.hInstance = hinst;
wincl.lpszClassName = classe;
wincl.lpfnWndProc = WindowProcedure;
wincl.style = CS_DBLCLKS;
wincl.cbSize = sizeof (WNDCLASSEX);
wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = NULL;
wincl.cbClsExtra = 0;
wincl.cbWndExtra = 0;
wincl.hbrBackground = ( HBRUSH) GetStockObject( BLACK_BRUSH ); // WHITE_BRUSH or GRAY_BRUSH or BLACK_BRUSH
if (!RegisterClassEx (&wincl)) return 0;
hwnd=CreateWindow( classe,"Ma fenetre GUI", WS_OVERLAPPEDWINDOW, 400,0, 400, 300, NULL, NULL, hinst, NULL);
ShowWindow (hwnd, cmd);
init_console();

while (GetMessage ( &messages, NULL, 0, 0))
{ TranslateMessage( &messages ); DispatchMessage( & messages); }
return messages.wParam;
}

Le résultat obtenu est le suivant. Les valeurs des variables x, y et gx utilisées dans la fenêtre GUI sont affichées dans la fenêtre console.

01

Code source du projet codeblocks 16.01 associé à cet exemple : test-1.7z

Masquer la fenêtre GUI avec la fenêtre console (ou avec une autre fenêtre) en la bougeant et vérifier que l'incrémentation de gx (effectuée entre case WM_PAINT: et break;) est bien affichée.

02

2) Remarques

AllocConsole(); BOOL AllocConsole(void); Alloue une console au processus appelant

SetConsoleTitle("Ma fenetre console"); Spécifie le titre affiché en haut de la fenêtre console allouée

fclose(stdout); Ferme le flux de données standard

int fdout = _open_osfhandle( (long) GetStdHandle( STD_OUTPUT_HANDLE ), 0); HANDLE GetStdHandle( DWORD nStdHandle); Retrouve l'identificateur (handle) du dispositif standard spécifié (STD_OUTPUT_HANDLE) int _open_osfhandle (intptr_t osfhandle, int flags ; Associe un identificateur de fichier de sortie à l'identificateur du dispositif standard

FILE* fout = _fdopen(fdout, "w"); FILE *_fdopen(int fd, const char *mode); Associe un flux de sortie à un identificateur de fichier

FILE * stdout; Flux de sortie standard

Il est utile de fixer la taille et la position à l'écran (0,0 dans cet exemple) de la fenêtre console. Pour cela, lors de la première exécution du programme, cliquer avec le bouton droit de la souris sur la fenêtre console et choisir "Propriétés". Dans la boîtede dialogue qui s'ouvre, fixer les valeurs souhaitées puis cliquer OK.

03