Créer un programme Windows minimal


L'interface de programmation d'applications API Win32 fournit aux programmeurs l'ensemble des fonctions nécessaires pour pouvoir écrire des applications fonctionnant en mode graphique sur les systèmes d'exploitation Windows 32 bits de Microsoft. Les systèmes d'exploitation Windows 64 bits de Microsoft sont dotés d'un émulateur automatique appelé wow64 (Windows 32-bit on Windows 64-bit) qui n'a pas besoin d'être activé explicitement. Cet émulateur permet aux applications 32 bits basées sur l'API Win32 de s'exécuter de façon transparente sur Windows 64 bits. Pour cela wow64l utilise trois librairies à liens dynamiques (DLLs) : wow64.dll, wow64win.dll et wow64cpu.dll.

Avant de créer un programme Windows, il est utile de se remémoriser quelques notions de base sur les caractères et sur les chaines de caractères en langage C++.
Les exemples suivants ont été réalisés sur un PC équipé de Windows XP et de l'IDE CodeBlocks 16.01. Les projets CodeBlocks ont ét créés en mode "Console application" pour les exemples relatifs aux caractères et aux chaines de caractères (1) et en mode "Win32 GUI Project" pour les exemples de programmes windows minimaux en mode graphique (2).

01

1) Caractères et chaines de caractère en C++

Type char

Le type char est un type de données fondamental en C++ car il permet de représenter les caractères ASCII. Les variables de type char sont associées à une valeur numérique de type entier (int) dans une plage donnée.
char : plage de valeur -128 à 127
signed char : plage de valeur -128 à 127
unsigned char : plage de valeur 0 à 255.

Ainsi les intructions suivantes conduissent au même résultat (affichage du caractère A), comme le montre le programme ci-après, de type application console, créé avec CodeBlocks

char a = 'A'; cout << a << endl;
char b = 65; cout << b << endl;

02

Type chaine de caractère

Une chaine de caractère est une succession de caractères placés entre guillement "ceci est une chaine de caractères".

Il n'existe pas de type chaine de caractère en C++. Pour définir une chaine de caractères, il faut définir un tableau de caractères 8 bits (codage ansi) de type char dont le dernier caractère est zéro ( noté '/0' ou 0 en valeur numérique) Ainsi, si on définit char machaine[255+1], ce tableau peut contenir un maximum de 255 caractères utilies numérotés de 0 à 254. Il doit se terminer par le caractère de fin de chaine '/0'

Ainsi, pour intitialiser une chaine de caractères, on peut écrire :
char texte[256];
texte[0]='H';texte[1]='e'; texte[2]='l'; texte[3]='l'; texte[4]='o'; texte[5]=0;
strcpy(texte, "bonjour");

03

Il est à noter que texte (sans les crochets) représente un pointeur (adresse) vers le premier élément du tableau texte[256].

Remarque : on peut déclarer et initialiser une chaine de caractère constante avec la syntaxe char * ptexte = "bonjour" où ptexte est un pointeur (adresse) ver le premier caractère de cette chaine mais, dans ce cas, la chaine ne doit pas être modifiée ensuite car cela risque d'entrainer une erreur d'exécution du programme.

04

Type LPCSTR

Le type LPCSTR est un pointeur vers une chaine de caractère constante qui peut être terminée par un zéro.
typedef char* LPSTR;

Si on utilise ce type de donnée, équivalent à char *, il faut inclure "windows.h" au début du programme console.

05

Transformation d'un entier en une chaine de caractère

La fonction sprintf qui fait partie de la librairie du langage C envoie une sortie formattée vers une chaine de caractères pointée par str. i Si on utilise cette fonction, il ne faut pas oublier d'inclure "stdio.h" au début du programme console.

int sprintf(char *str, const char *format, variable...)
str : pointeur vers un tableau de caractères dans lequel est rangée la chaine de caractère résultanteThis is the pointer to an array of char elements where the resulting C string is stored.
format : indication du type de donnée à convertir ( %d ou %i pour un entier, %f pour un flottant, %x pour un entier hexadécimal, %c pour un caractère, %s pour une chaine de caractères...)

06

2) Créer un programme Windows minimal

Programme Windows minimal avec boîte de massage

Le programme windows minimum suivant permet d'afficher des variables et des résultats de calculs dans une boîte de message.

#include <windows.h>
#include <stdio.h>
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
char texte[16]; int x,y,z; x=2; y=3; z=x*y;
sprintf(texte,"z = x*y = %d", z);
MessageBox (NULL, texte, "Boite de message", 0) ;
return 0 ;
}

07

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

On peut de la même façon afficher des variables flottantes et des calculs de variables flottantes.

#include <windows.h>
#include <stdio.h>
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
char texte[256]; float x,y,z; x=2.1; y=3.0; z=x*y;
sprintf(texte," x= %f et y= %f => z = x*y = %f", x, y, z);
MessageBox (NULL, texte, "Boite de message", 0) ;
return 0 ;
}

08

Programme Windows minimal avec fenêtre

Le programme windows suivant permet d'afficher des variables et des résultats de calculs entre variables dans une fenêtre.

#include <windows.h>
#include <stdio.h>
HDC hdc ;
//=============== PARTIE A MODIFIER ===================
void affiche()
{
char texte[256]; float x,y, z;
x=5.1; y=3.0; z=x*y; sprintf(texte, "x=%f et y=%f => z est égal à %f", x, y, z);
TextOut(hdc,0,0,texte, strlen(texte));
}
//========================= ================================
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(); 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,"Test",WS_OVERLAPPEDWINDOW,0,0,400,300,NULL,NULL,hinst,NULL);
ShowWindow (hwnd, cmd);
while (GetMessage (&messages,NULL,0,0))
{TranslateMessage(&messages);DispatchMessage(&messages);}
return messages.wParam;
}

09

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

Le programme windows suivant permet d'afficher des informations dans une fenêtre quand on clique un bouton.

#include <windows.h>
#include <stdio.h>
LRESULT CALLBACK wndproc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HWND hb ; static char texte[256] ; HDC hdc ;
switch (message){
case WM_CREATE :
hb = CreateWindow ("button", "Bouton", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 0, 0, 100, 20, hwnd, (HMENU) 1, NULL, NULL) ;
return 0 ;
case WM_COMMAND :
hdc = GetDC (hwnd) ; SelectObject (hdc, GetStockObject (SYSTEM_FIXED_FONT)) ;
sprintf(texte, "Bonjour"); TextOut(hdc,100,100,texte, strlen(texte));
ReleaseDC (hwnd, hdc) ;
break ;
case WM_DESTROY :
PostQuitMessage (0) ;
return 0 ;}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
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 = wndproc;
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,"Test",WS_OVERLAPPEDWINDOW,0,0,400,300,NULL,NULL,hinst,NULL);
ShowWindow (hwnd, cmd);
while (GetMessage (&messages,NULL,0,0))
{TranslateMessage(&messages);DispatchMessage(&messages);}
return messages.wParam;
}

10

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