Graphical Templates - Big

Transcription

Graphical Templates - Big
Développement graphique de programme
Template de Keygen
V 1.0
Neitsa [FRET]
Introduction ................................................................................................................................ 3
Finalité.................................................................................................................................... 3
Convention d’écriture............................................................................................................. 4
I Préparation ............................................................................................................................... 6
1.1 Outils et applications requis ............................................................................................. 7
1.1.1 Programmes utilisés .................................................................................................. 7
1.1.2 Outils & bibliothèques & add-ons............................................................................. 8
1.2 Organisation ..................................................................................................................... 9
1.2.1 Création du projet...................................................................................................... 9
1.2.2 Structure des répertoires.......................................................................................... 12
1.3 Convention de nom ........................................................................................................ 14
1.3.1 Noms des ressources ............................................................................................... 15
1.3.2 Etats des boutons..................................................................................................... 16
II Moteur minimal de notre template ....................................................................................... 17
2.1 Organisation des fichiers ................................................................................................ 18
2.2 Ressources minimales .................................................................................................... 19
2.3 Code minimal ................................................................................................................. 23
2.3.1 Le fichier main.cpp ................................................................................................. 23
2.3.2 Le fichier main.h ..................................................................................................... 28
III Région et compilation conditionnelle ................................................................................. 30
3.1 Région ............................................................................................................................ 31
3.2 Compilation conditionnelle ............................................................................................ 34
IV Implémentation des boutons ............................................................................................... 37
4.1 Boutons et évènements................................................................................................... 38
4.2 Implémentation des boutons........................................................................................... 39
4.2.1 Commutateurs pour les boutons.............................................................................. 39
4.2.2 Le code pour les boutons........................................................................................ 42
V Edit Boxes et Commandes ................................................................................................... 48
5.1 Edit Boxes ...................................................................................................................... 49
5.2 Commandes des boutons................................................................................................ 52
VI Musique Maestro ! .............................................................................................................. 54
6.1 Bibliothèque musicale..................................................................................................... 55
5.2 Implémentation de la musique ....................................................................................... 56
Notes d'optimisation & remerciements .................................................................................... 60
Introduction
Ce tutorial vous propose un guide pour écrire des applications graphiques, plus exactement
des templates de keygens. L’idée de ce tutorial vient du fait de ma quasi non connaissance
dans l’implémentation d’applications graphiques et aussi du fait que beaucoup de demandes
m’ont été faites à ce sujet.
Cet essai a été pensé dans une logique séquentielle (pas à pas) pour aider les débutants de
façon à leur éviter de tomber dans les pièges que j’ai pu rencontrer lors de précédents
essais.
Le tutorial est basé sur le C++ (procédural) sous Windows, mais si vous programmez en
assembleur la conversion devrait être relativement simple. Un strict minimum de
connaissance du langage C++ et de l’API Windows est demandé, le but de ce tutorial n’étant
pas l’acquisition du langage ni de l’interface de programmation d’application (API) . L’IDE
utilisé ici est celui de Visual studio .NET, néanmoins cela n’est pas une obligation quant à la
compréhension du tutorial.
Rien n’est parfait mais le code présenté dans ce tutorial a été vérifié plusieurs fois pour
s’assurer qu’aucune erreur n’y avait été introduite, la même chose ayant été faites à propos
du texte de cet essai. Si toutefois vous aviez des commentaires ou suggestions n’hésitez pas
à m’en faire part.
Finalité
Le but de ce tutorial est de vous montrer en détail comment coder un template de
programme graphique. Le programme affichera une fenêtre préalablement dessinée sous un
éditeur graphique. Chaque bouton possédera plusieurs états, par exemple si un bouton est
appuyé ou si la souris passe au dessus, la couleur de ce bouton sera différente.
Le programme pourra jouer une musique de notre choix et cette dernière sera contrôlable
(jouer, arrêter, pause, stop, avant, arrière).
Enfin le programme offrira quelques effets graphiques (apparition progressive à l’écran, text
scrolling, starfield, etc.)
Convention d’écriture
Vous pourrez voir d’un coup d’œil les différents concepts grâce au style d’écriture et à sa
mise en forme.
Concepts importants :
Les concepts importants sont mis en gras à l’intérieur d’une phrase.
Tips / aide :
Les tips ou l’aide sont placés dans un chapitre séparé, le chapitre étant accolé à une icône
aisément reconnaissable. Le tout est encadré en bleu foncé, par exemple :
La taille de la boite de dialogue peut être mise à zéro en éditant
manuellement le fichier de ressources « rsrc.rc », néanmoins cela n’est pas
une obligation. Assurez vous tout de même que celle-ci ne soit pas plus
grande que votre fichier graphique *.png.
Attention :
Dans le cas ou un concept est très important et peux prêter à un mauvais fonctionnement
du programme s’il n’est pas respecté, l’explication adéquate est fournie accolée à l’icône d’un
warning. Notez que le cadre est rouge.
Attention : veillez bien à inclure votre fichier graphique *.png en tant que
ressource RCDATA sans quoi cela peut poser des problèmes au
programme pour retrouver le fichier dans les ressources.
Code :
Le code du programme est formaté avec la police « Lucida ». Les commentaires du code
sont en vert et les mots clé du C++ en bleu, le tout étant encadré en vert foncé. En voici un
exemple :
case WM_CLOSE:
case WM_DESTROY:
//minimise la fenêtre
ShowWindow (hWin, SW_MINIMIZE);
//destruction de la boite de dialogue
EndDialog (hWin,0);
break;
Exemple tiré de la MSDN :
Ci-dessous un exemple présentant les différents paramètres d’une fonction, tirée de la
MSDN. La police utilisée est « Verdana » et le fond est grisé, sans cadre.
int MessageBox(
HWND hWnd,
LPCTSTR lpText,
LPCTSTR lpCaption,
UINT uType
);
I Préparation
Ce chapitre introduit les différentes choses à savoir ou posséder avant de commencer à
coder nos applications. Il est important de bien lire ce chapitre afin de savoir quels outils
sont utilisés ici et quelles sont les conventions utilisées. Ces dernières sont importantes
pour la compréhension de la suite du tutorial.
Notez toutefois que vous n’êtes absolument pas dans l’obligation d’utiliser ou de posséder
les différents outils dont il est fait état ici !
La programmation des templates graphiques requière au minimum un compilateur C++
pour Windows ainsi que le SDK., le reste vous est fourni dans l’archive.
1.1 Outils et applications requis
Comme expliqué ci avant la programmation de nos templates graphiques se fera en C++.
Vous pouvez utiliser n’importe quel compilateur C++ pour Windows. De plus j’utiliserais ici
l’IDE de Visual Studio .NET, mais n’importe quel IDE pourra faire l’affaire (si vous utilisez
VC++ 6.0 cela ne devrait poser aucun problème).
Nous utiliserons le format graphique PNG (Portable Network graphic), ce choix ayant été
fait car le PNG est libre de droit et assure la transparence sur les couleurs.
Nous aurons besoin d’un générateur de région pour la transparence sur certaines parties du
graphique.
Finalement un module permettant de jouer des fichiers XM sera utiliser. Notez que nous
verrons aussi comment jouer des MP3 ou d’autres formats, mais ces formats sont lourds et
finalement peu recommandés.
La plupart des outils présentés ici sont gratuits et/ou libres de droits sauf mention contraire.
1.1.1 Programmes utilisés

C++, Compilateur & IDE
- Visual Studio C++ (payant)
- Alternatives gratuites: voir http://c.developpez.com/compilateurs/
- A notez que le compilateur et le SDK peuvent être obtenu gratuitement ! [Lien]

Graphisme
- The Gimp : http://www.gimp.org/
- IrfanView (convertisseur) : http://www.irfanview.com/
1.1.2 Outils & bibliothèques & add-ons

Générateur de région
L’excellent outil de Richard de Oude, RgnCreator :
http://www.codeproject.com/gdi/rgncreator.asp
RgnCreator : This program is provided courtesy of Data Dynamics.

PNG Lib
Bibliothèque pour le format PNG (originellement en asm) par Thomas Bleeker
[MadWizard]
http://www.madwizard.org/view.php?page=downloads
PNGLib : © 2003 by Thomas Bleeker [MadWizard].

Bibliothèque pour fichiers musicaux : miniFMOD
Cette bibliothèque nous permettra de jouer des fichiers musicaux notamment ceux au
format XM. La version utilisée est une version modifiée de MiniFmod (d’origine, cette
bibliothèque ne supporte pas la mise en pause d’un morceau de musique…).
MiniFmod [original] : http://www.fmod.org/files/minifmod170.zip
MiniFmod : Firelight Technologies Pty, Ltd. All rights reserved.

Packer
UPX peut être utilisé pour réduire la taille de l’exécutable, non comme une protection
en soi.
http://upx.sourceforge.net/
UPX : Copyright (C) Markus F.X.J. Oberhumer & László Molnár

Musique
Différent morceaux de musique au format XM (eXtended Module). Le format XM à
l’avantage d’être très petit puisque la musique est recrée par un synthétiseur.
http://www.modarchive.com/
1.2 Organisation
L’organisation d’un tel programme, si en apparence ne revêt pas trop de difficulté, est
néanmoins importante tant le développement peut nécessiter de multiples fichiers qu’il est
important de classer correctement.
La structure proposée ici n’est qu’un point de départ, aussi n’oubliez pas que vous êtes seul
juge de la manière la plus appropriée pour classer avec efficacité vos fichiers.
1.2.1 Création du projet
Point de programme sans code source, nous allons donc créer notre projet. Si vous ne
possédez pas VS (Visual Studio) vous pouvez néanmoins lire ce chapitre qui vous indiquera
les fichiers à créer.
Démarrer VS, choisissez de créer une nouvelle solution, soit avec la page de démarrage, soit
avec le menu File > Create a new solution.
Choisissez de créer un projet Win32 C++, et donnez lui un nom adéquat.
Vous pouvez choisir de créer un répertoire pour la solution au cas où vous feriez plusieurs
template (avec un code différent, pas différente graphiquement) en cochant la case « Create
directory for solution », mais cela n’est pas réellement nécessaire.
Une fois votre solution nommée, cliquez sur OK.
Dans la fenêtre suivante, vérifiez bien qu’il s’agit d’un programme pour Windows (Windows
application) et surtout n’oubliez pas de cliquer sur la boite « empty project ».
Il est important de choisir « empty project » car nous allons coder un
template à base de DialogBox, or VS ne propose pas nativement de solution
par défaut sur cette base.
Cliquez ensuite sur « Finish ». Une fois ceci terminé l’écran vous montre l’IDE pour coder
directement.
Nous allons d’abord ajouter les fichiers de base nécessaires pour notre code.
Dans la fenêtre de l’explorer de solution (en haut à droite) faites un click droit sur le dossier
« source files », vous devriez voir apparaître ces fenêtres :
Choisissez Add > Add New Item. Dans la nouvelle fenêtre qui s’ouvre :
Choisissez C++ file (.cpp) et donnez lui un nom (vous n’avez pas besoin d’ajouter
l’extension). Par convention, nous l’appellerons « main ». Cliquez ensuite sur « Open ». Le
fichier (vide) doit alors s’ouvrir dans l’IDE.
Faites la même chose pour ajouter un fichier header (.h) au projet. Clique droit sur le
répertoire « header files » dans l’explorateur de solution. Nommez votre fichier header
« main ». Le reste de la marche à suivre est le même que pour le fichier CPP.
Recommencez le même processus pour ajouter cette fois ci un fichier « resource » (.rc) au
projet. Vous devrez faire un click droit sur le dossier « ressource files » de l’explorateur de
solution pour ajouter ce fichier. Nommez celui « rsrc ».
Vous devriez finalement avoir ceci dans l’explorateur de solution :
Notez qu’à l’ajout du fichier de ressources, VS ajoute automatiquement un fichier
« resource.h », vous ne devriez pas, en temps normal, éditer ce fichier manuellement.
Le fichier « resource.h » contient la définition
et les caractéristiques des
objets du fichier .rc. Notez qu’il faudra bien sur ne pas oublier d’inclure le
fichier « resource.h » à notre projet, sans quoi aucune ressource n’est
compilée dans notre exécutable.
1.2.2 Structure des répertoires
A présent que nos fichiers de base sont créés nous allons générer mettre en place une
structure de répertoire appropriée afin d’y placer tout les fichiers supplémentaires.
Ouvrez le répertoire contenant votre solution. Pour l’instant seul les fichiers de projet, de
solution et les fichiers que nous avons créés auparavant sont présents. J’appellerais
désormais [RACINE] le dossier contenant votre solution.
Vous créerez les dossiers suivant sous la racine de votre projet :

[RACINE]\Effets\
Répertoire contenant le code des effets graphiques que nous pourrons ajouter au
programme. Chaque effet prendra place dans un répertoire distinct.

[RACINE]\Libs\
Répertoire contenant les bibliothèques supplémentaires pour le programme. Nous
utiliserons principalement PngLib et MiniFmod. Chaque bibliothèque prendra place dans un
répertoire
distinct.
Vous
devriez
donc
avoir
[RACINE]\libs\pnglib
et
[RACINE]\libs\minifmod.

[RACINE]\Musique\
Répertoire qui contiendra les musiques que nous utiliserons.

[RACINE]\Skins\
Répertoire contenant les « skins » (autres templates graphiques). Les skins ne sont pas
utilisés, ce répertoire sert donc d’entrepôt. Chaque « skin » ira dans un répertoire séparé.
Par exemple [RACINE]\Skins\FlowerPower\ pour votre belle template psychédélique ou
[RACINE]\Skins\DarkAges\ pour une template sombre à souhait ;-)

[RACINE]\Template
Répertoire contenant la template graphique actuelle utilisée par le programme en cours. Ce
répertoire contient toutes les parties de la template nécessaire à son bon fonctionnement.
Le dossier template contient donc un skin sortie du même dossier.

[RACINE]\Template\Main\
La fenêtre graphique principale du programme est située ici. On y mettra aussi l’icône du
programme.

[RACINE]\Template\Boutons\général\
Contient les fichiers .png les boutons généraux, tel que maximiser, minimiser, fermer mais
aussi « generate » ou « about » par exemple.

[RACINE]\Template\Boutons\Musique\
Contient les boutons nécessaires à la musique, comme « play », « stop », etc.

[RACINE]\Template\Misc\
Tout autre graphisme n’entrant pas dans les catégories ci-dessus.
A présent votre dossier [RACINE] devrait ressembler à ceci :
Si vous êtes sous un autre environnement que VS .NET il est tout à fait possible que certains
fichiers soient différents ou non présents.
1.3 Convention de nom
Maintenant que tout est en place, nous allons voir la convention (toute personnelle) pour
nommer les différents « objets » compris dans notre template. En premier nous verrons les
conventions pour nommer les ressources et deuxièmement les qualificatifs qui s’y appliquent
le cas échéant.
1.3.1 Noms des ressources

IDD_ xxx
Notre boite de dialogue principale.

IDR_PNG_xxx
Toutes les ressources graphiques PNG commencent ainsi (IDR pour Ressource). Par
exemple, IDR_PNG_BG (ressource PNG principale qui donne son apparence à la
fenêtre).

IDI_xxx
L’icône du programme se nomme ainsi.

IDC_Bxxx
Les boutons généraux commencent par cet identifiant, par exemple IDC_BMAXIMIZE.
Voici une liste des boutons généraux (5 lettres pour la fonction):

o IDC_BCLOSE
fermer
o IDC_BMINIM
minimiser
o IDC_BMAXIM
maximiser
o IDC_BGENER
générer
o IDC_BABOUT
about
IDC_Mxxx
Les boutons pour la musique ont cet identifiant, par exemple IDC_MPLAY. Voici une liste
des boutons (en 4 lettres pour la fonction).
o IDC_MPLAY
jouer
o IDC_MSTOP
arrêter
o IDC_MPAUS
pause
o IDC_MREWI
en arrière
o IDC_MFORW
en avant
1.3.2 Etats des boutons
Chaque bouton aura 3 états possibles, état qui changera son apparence graphique. A coté du
qualificatif (4 lettres) vous trouverez l’état du bouton utilisé. Ces qualificatifs s’ajoutent aux
noms des boutons.

_NORM
Normal

_PRESS
Appuyer

_OVER
Au dessus
Ainsi le bouton « fermer » dans son état normal s’appellera : IDC_BCLOSE_NORM
A présent tout est prêt pour coder une template minimale de notre application.
II Moteur minimal de notre template
A présent qu’une bonne partie des définitions est mise en place nous allons coder le moteur
minimal du programme de façon à afficher un « background » graphique au format PNG.
Nous n’utiliserons aucun bouton, ni aucune musique pour l’instant. Nous continuerons
d’ajouter du code sur cette base par la suite.
Avant cela nous verrons comment se présentent les fichiers du projet et ce qu’ils
contiennent mais aussi comment ajouter des ressources à notre programme.
2.1 Organisation des fichiers
Nous allons voir comment s’organisent les fichiers de notre projet de template graphique.

Le fichier main.cpp contient uniquement le code de base de l’application.

Le fichier main.h contient les directives pour inclure les fichiers d’en-têtes (.h)
nécessaires à la compilation, ainsi que les bibliothèques (.lib). On y placera également
les variables globales et les déclarations de fonctions (prototypes).

Le fichier rsrc.rc contient, comme nous l’avons vu, les différentes définitions des
ressources.
Pour afficher correctement notre PNG nous devrons inclure dans notre programme la
bibliothèque PNG (png.lib) ainsi que le fichier d’en-tête « pnglib.h ». La DLL « png.dll » devra
se trouver absolument dans le même répertoire que le programme lorsque celui-ci sera
lancé.
Pour ajouter un fichier, ici le fichier header existant dans [RACINE]\libs\Pnglib\ : Faites un
click droit sur le dossier voulu dans l’explorateur de solution et choisissez les options
comme montrées ci-dessous.
Choisissez alors le fichier « pnglib.h » dans le dossier adéquat.
2.2 Ressources minimales
Nous allons commencer par créer notre boite de dialogue, qui ne sera jamais affichée en
tant que telle mais qui est toutefois nécessaire. Ce sera une « fausse » boite de dialogue où
seul notre graphique en PNG sera visible.
Double cliquez sur le fichier « rsrc.rc » dans l’explorateur de solution ou cliquez simplement
sur l’explorateur de ressources (« resource view »).
Faites un click droit sur le dossier « rsrc.rc » (cf. photo ci-dessus) et choisissez « add
resource ». Dans la nouvelle fenêtre qui apparaît, choisissez « Dialog » puis cliquez sur
« New ».
Une nouvelle page dans l’IDE apparaît alors, vous permettant d’éditer le fichier de dialogue.
Dans un premier temps, supprimez tous les boutons qui s’y trouvent (sélectionnez les et
faites « suppr. »).
Dans la fenêtre des propriétés de la boite de dialogue, repérez les styles suivant et mettez
les à la bonne valeur :
o BORDER : NONE
o SYSMENU : FALSE
Vous devriez obtenir une fenêtre totalement vide et gris uniforme.
Si toutefois vous n’aviez pas d’IDE ou que les manipulations était différentes, vous devriez
obtenir ceci dans le fichier « rsrc.rc » (éditez le avec un éditeur de texte).
//
// Dialog
//
IDD_DIALOG1 DIALOGEX 0, 0, 186, 95
STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
END
Si votre PNG principal devait être plus petit que notre boite de dialogue par défaut, assurez
vous de retoucher la taille de celle-ci de façon à ce qu’elle soit plus petite que votre
graphique. Typiquement vous pouvez retoucher cette ligne si vous ne disposez pas d’IDE :
IDD_DIALOG1 DIALOGEX 0, 0, 0, 0
Attention : Si vous disposez d’un IDE la retouche manuelle du fichier
« rsrc.rc » peut causer certains problèmes. A ne faire donc que si vous
savez ce que vous faites.
Vous aurez bien sur notez que notre boit de dialogue s’appelle IDD_DIALOG1, nous ne
changerons pas son nom.
A présent nous allons insérer notre template graphique pour la fenêtre principale.
Faites un click droit sur le dossier « rsrc.rc » dans l’explorateur de ressources. Choisissez
ensuite « Add Resources » et dans la nouvelle boite de dialogue qui apparaît, choisissez
« Import » :
Dans la fenêtre qui s’ouvre allez dans le dossier [RACINE]\Template\Main\ pour y
rechercher le background principal de l’application. Etant donné que le fichier est au format
PNG, l’explorateur ne le montrera pas. Choisissez bien de montrer tous les types de
fichiers :
Ensuite tapez dans le champs disponible : RCDATA
Faites alors OK. Le fichier est alors intégré
en tant que fichier binaire (RCDATA : Raw
Content) à l’application dans la section des
ressources.
Renommé l’identifiant en IDR_PNG_BG. Pour cela, dans la fenêtre « ressource view »,
cliquez sur le fichier et allez dans sa fenêtre propriétés où vous pourrez le renommer :
Nous pouvons à présent importer l’icône dans les ressources. Faites un
click droit sur le dossier rsrc.rc et choisissez cette fois ci d’importer une
icône en cliquant à droite sur le type approprié puis en choisissant à
nouveau « import ». L’icône doit se trouver dans le dossier
[RACINE]\Template\Main\ et n’oubliez pas, dans l’explorateur de fichier,
de choisir le type *.ico pour voir le fichier. Nous laisserons à l’icône
l’identifiant IDI_ICON1.
Le fichier « rsrc.rc » devrait contenir ceci, si vous l’éditer manuellement :
///////////////////////////////////////////////////////////////////////////
//
//
// RCDATA
//
IDR_PNG_BG
RCDATA
"Template\\Main\\bg.png"
///////////////////////////////////////////////////////////////////////////
//
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_ICON1
ICON
"Template\\Main\\main.ico"
A présent nos ressources contiennent le minimum pour notre application. Nous allons
pouvoir coder notre programme.
2.3 Code minimal
Nous allons maintenant étudier le code minimal requis pour faire fonctionner notre
application, aussi bien le code « en lui-même » mais aussi les déclarations des fichiers d’entêtes.
2.3.1 Le fichier main.cpp
Voyons à présent le fichier « main.cpp ». Rappelez vous que ce fichier ne contient que du
code et que les données globales (visibles pour toute l’application) se situent dans le fichier
« main.h ». Il suffira donc d’inclure ce dernier avec la directive #include au tout début du
code pour que les fichiers soient visibles depuis notre fichier .cpp.
Dans un premier temps nous allons seulement voir le squelette de base sur lequel nous
broderons peu à peu par la suite.
Le code du programme commence bien sur par la fonction principale, la fonction WinMain,
point d’entrée de l’application :
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR
lpCmdLine,
int
nCmdShow)
{
hInst = hInstance;
InitCommonControls ();
//obtient les dimensions de l'écran
ScreenWidth = GetSystemMetrics (SM_CXSCREEN);
ScreenHeigth = GetSystemMetrics (SM_CYSCREEN);
//appel la boite de dialogue et sa procédure
DialogBoxParam(hInstance,(LPCTSTR)IDD_DIALOG1,NULL,(DLGPROC)MainProc,
NULL);
ExitProcess (NULL);
return 0;
}
On obtient d’abord les dimensions de l’écran en largeur (ScreenWidth) et hauteur
(ScreenHeigth). Ces dimensions serviront plus tard à placer le programme a centre de
l’écran.
L’application est réellement lancée par DialogBoxParam qui permet d’appeler la
procédure de dialogue MainProc.
Voici un code schématique des différent cas utilisé dans notre template de base. Les
commentaires vous indiqueront ce que font ces différents cas à l’intérieur de la procédure.
LRESULT CALLBACK MainProc(HWND hWin,UINT message,WPARAM wParam,LPARAM
lParam)
{
//variable locales
switch(message)
{
case WM_INITDIALOG:
{
//initialisation du programme
break;
}
case WM_PAINT:
{
//peinture de la fenêtre
break;
}
case WM_COMMAND:
Select=LOWORD(wParam);
switch(Select)
{
// rien pour l'instant (code pour l’appui des boutons)
break;
}
break;
case WM_LBUTTONDOWN:
{
//code pour déplacement de la fenêtre avec la souris
break;
}
case WM_CLOSE:
case WM_DESTROY:
// Destruction ou fermeture de la fenêtre
break;
default:
return FALSE;
}
return TRUE;
}
Commençons par voir, toujours dans la procédure MainProc, le cas WM_INITDIALOG,
premier cas à être appelé puisqu’il s’agit de l’initialisation.
case WM_INITDIALOG:
{
//charge l'icone et l'affiche
HICON hIcon = LoadIcon (hInst, (LPCSTR)IDI_ICON1);
SendMessage (hWin, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
// affiche le titre de l'application dans la taskbar
SendMessage (hWin, WM_SETTEXT, NULL, (LPARAM) lpszDialogCaption );
Ici le code procède au chargement de l’icône et à l’affichage du titre de l’application dans la
barre des tâches (TaskBar). L’icône est visible dans la TaskBar mais aussi en faisant
ALT+TAB grâce au paramètre ICON_BIG.
Vient ensuite la fonction qui charge le PNG et le transforme en interne en bitmap :
//charge le PNG
hBmpMain = PNG_GetResource (IDR_PNG_BG, hInst, hWin, &StructPngDim);
La fonction est déclarée dans « pnglib.h » comme ceci :
HBITMAP CALLBACK PNG_GetResource (
int ResourceId,
HINSTANCE hInst,
HWND hWin,
LPPNGDIMENSION pStruct);
On lui passe donc en premier lieu l’ID de la ressource à extraire, ici le graphique au format
PNG de notre fenêtre principale. Ensuite le hInstance de notre application (obtenu dans la
fonction WinMain), puis le hWin qui est le handle de notre fenêtre principale.
LPPNGDIMENSION est une structure qui renferme seulement deux paramètres, la largeur
et la hauteur du PNG, vous devrez donc passer un pointeur vers une structure de ce type.
La définition de la structure se trouve dans le même fichier :
typedef struct
{
int pngHeight;
int pngWidht;
}PNGDimension, * LPPNGDIMENSION;
En sortie de fonction nous obtenons un handle de bitmap (HBITMAP) et la structure
(StructPngDim de type PNGDIMENSION dans notre cas) passée en argument est
remplie avec les dimension du PNG.
La suite du code servira uniquement à centrer la fenêtre, grâce aux informations obtenues
sur la taille de l’écran et les dimensions du PNG.
//centre la dialog box à l'écran
StartPosX = ((ScreenWidth - StructPngDim.pngWidht) >> 1);
StartPosY = ((ScreenHeigth - StructPngDim.pngHeight) >> 1);
SetWindowPos (hWin, HWND_TOPMOST, StartPosX, StartPosY,
StructPngDim.pngWidht,
StructPngDim.pngHeight,
SWP_HIDEWINDOW
);
//petit effet d'apparition
ShowWindow (hWin, SW_MINIMIZE);
ShowWindow (hWin, SW_SHOWNORMAL);
break;
Notez l’opérateur ‘>>’ avec l’opérande 1 (un) qui correspond dans notre cas à une division
par 2. Le reste du code est assez parlant de lui-même.
Le petit effet d’apparition correspond au fait que le programme semble venir de la barre des
tâches quand il démarre…Rien de transcendant mais toujours agréable.
Si vous ne comprenez pas un traître mot de ce qui vient d’être dit ici, fermez ce tutorial,
reprenez quelque cours sur l’API win32 et rouvrez à nouveau cet essai…
En cas de doute sur une API n’hésitez pas à compulser la MSDN si le code vous parait
familier mais vous ne comprenez pas la fonction d’une API ou un de ses paramètres. En effet
il eut été difficile d’expliquer par le détail chacune d’elle…
Vient ensuite le cas WM_PAINT appelé juste après le cas d’initialisation :
case WM_PAINT:
{
// yo soy picasso :p
// préparation au fonction GDI
hDC = BeginPaint (hWin, &ps);
//création du DC (device context)
hBitmapDc = CreateCompatibleDC (hDC);
//sélectionne le graphique principal dans le DC
hOldBitmap = SelectObject (hBitmapDc , hBmpMain);
//transfère des couleurs du hBitmap au hDC
BitBlt (hDC, 0, 0, StructPngDim.pngWidht,
StructPngDim.pngHeight,
hBitmapDc, 0, 0, SRCCOPY);
// selectionne le nouvel objet
SelectObject (hBitmapDc, hOldBitmap);
//effacement du DC
DeleteDC (hBitmapDc);
// fin des fonctions de paint
EndPaint (hWin, &ps);
break;
}
Encore une fois le code est relativement parlant, même s’il peut paraître confus à ceux qui
ne pratiquent pas les fonctions GDI (graphisme primaire sous Windows).
Le code prépare tout d’abord l’application à l’utilisation de fonctions GDI par le biais de
BeginPaint. Ensuite vient la création d’un DC (device context) qui servira à l’affichage de
notre graphique principal pour la fenêtre.
SelectObject sélectionne le handle retourné par la fonction de la DLL (Png_GetResource)
dans le DC.
BitBlt copie directement le graphique de la fenêtre dans le DC principal.
Le dernier SelectObject sélectionne le DC principal, puis DeleteDC ferme le DC relative au
graphique mémoire (le graphique de notre application est déjà dans le DC principal puisqu’il
y a été copié par BitBlt). Enfin EndPaint termine les opérations.
Nous n’étudierons pas le cas WM_COMMAND qui traite les interactions avec les contrôle
de l’utilisateur (bouton ou boite d’édition, etc.) étant donné que nous n’en mettrons pas
pour l’instant. Ceci sera vu dans une prochaine partie.
Le cas WM_LBUTTONDOWN est traité lorsque l’utilisateur appui sur le bouton gauche de
la souris et que la fenêtre principale à le focus (sur la fenêtre principale si vous préférez).
case WM_LBUTTONDOWN:
{
ReleaseCapture ();
SendMessage (hWin, WM_NCLBUTTONDOWN, HTCAPTION, NULL);
break;
}
Sans ce code nous ne pourrions pas déplacer notre fenêtre car celle-ci ne dispose pas de
barre de titre. Comment cela se fait-il? Un petit passage de la MSDN nous éclaire sur ce
point :
The WM_LBUTTONDOWN message is posted when the user presses the left mouse
button while the cursor is in the client area of a window. If the mouse is not captured,
the message is posted to the window beneath the cursor. Otherwise, the message is
posted to the window that has captured the mouse.
En
outre
il
est
important
de
comprendre
la
fonction
du
message
WM_NCLBUTTONDOWN :
The WM_NCLBUTTONDOWN message is posted when the user presses the left mouse
button while the cursor is within the nonclient area of a window. This message is posted
to the window that contains the cursor. If a window has captured the mouse, this
message is not posted.
Ce message permet simplement de simuler l’appui comme si nous faisions un click gauche de
souris sur la barre de titre.
Viennent ensuite les deux cas de fermeture de l’application :
case WM_CLOSE:
case WM_DESTROY:
//minimise la fenêtre
ShowWindow (hWin, SW_MINIMIZE);
// destruction de la boite de dialogue
EndDialog (hWin,0);
break;
On minimise la fenêtre (simple effet de fermeture) puis on appelle Endialog qui finira le
traitement dans la procédure de dialogue (MainProc) et mettra fin à la fonction
DialogBoxParam et appellera ainsi la fonction ExitProcess.
2.3.2 Le fichier main.h
Le fichier.h, décrit plus haut, est relativement simple. Schématiquement, il se présente ainsi :

Indication des bibliothèques supplémentaires
#pragma comment (lib, "comctl32.lib") // requis pour initcommoncontrols
#pragma comment (lib, "libs/pnglib/png.lib") // requis pour le format Png
Cette notation permet d’éviter d’utiliser la ligne de commande du
préprocesseur ainsi que de l’éditeur de lien. Il suffit simplement de spécifier
les mots clés en bleu et le nom ainsi que l’emplacement de la bibliothèque
entre guillemets.

Inclusion des fichiers d’entête généraux et spécifiques
On trouve ici, dans l’ordre, les fichiers nécessaires pour le développement Windows, les
fichiers d’inclusion du C++ standard et finalement les fichiers propres à notre programme.

Les variables globales et les déclarations de fonctions
Finalement on déclare les variables visibles à travers tout le programme (à la différence des
variables locales) ainsi que les déclarations de fonctions (le prototypage de fonctions).
Voilà qui clos notre première partie générale, relativement longue certes mais nous n’y
reviendrons pas. Assurez vous de bien comprendre chaque point abordé ici, car il ne sera
plus fait référence aux points qui y ont été vus.
Le code source de cette partie se trouve dans le dossier "Template1" et est bien sur présent
dans l’archive.
N.B : le code compile parfaitement mais vous obtiendrez un Warning de compilation dû au
fait que le cas WM_COMMAND ne comporte pas de « switch » pour l’instant. Ceci est sans
importance, le programme fonctionne très bien comme cela.
III Région et compilation conditionnelle
Nous allons voir dans ce chapitre la création de région qui permettra de rendre la bordure
de notre graphique invisible. Nous verrons aussi les bases de la compilation conditionnelle
qui nous permettra de ne compiler que les parties de code et les fichiers que nous désirons
voir effectivement mis dans l’exécutable.
3.1 Région
Comme vous l’aurez sûrement remarqué la template1 affiche une bordure rose peut
agréable à l’œil. En fait c’est la couleur choisie par ++Meat (l’excellent graphiste de FRET qui
a fait cette template) pour la transparence.
Pour enlever cette bordure il faut utiliser une API spécifique :
HRGN ExtCreateRegion(
CONST XFORM *lpXform,
// transformation data
DWORD nCount,
// size of region data
CONST RGNDATA *lpRgnData // region data buffer
);
Nous ne pouvons pas utiliser l’API CreateRegion car notre région n’a pas une forme
standard définie (telle qu’un carré, un cercle ou une ellipse par exemple) nous utilisons donc
la forme étendue de cette API.
Voici les paramètres de l’API que nous utiliserons :
lpXform
[in] Pointer to an XFORM structure that defines the transformation to be performed on the
region. If this pointer is NULL, the identity transformation is used.
nCount
[in] Specifies the number of bytes pointed to by lpRgnData.
lpRgnData
[in] Pointer to a RGNDATA structure that contains the region data in logical units.
Le paramètre lpXform ne nous est d’aucune utilité, il sert au cas ou nous voudrions agrandir,
mettre en miroir, couper, ou faire une rotation sur notre région.
Le paramètre lpRgnData qui est un pointeur vers une structure de type RGNDATA est par
contre très important. Cette structure renferme tout ce qu’il nous faut pour produire notre
région.
Je n’entrerais pas plus avant dans les détails de création d’une région de forme complexe par
le biais de la programmation (cela fera peut être l’objet d’un tutorial séparé) car cela
demande une bonne connaissance des en-têtes de fichiers images, de certaines structures et
de diverses manipulations mathématiques.
Pour faire plus simple nous allons utiliser un outil qui fera ce travail pour nous. Celui-ci est
situé dans le dossier « tools » de l’archive, il s’agit de RegionGenerator (« RGNerator.exe »)
par Richard de Oude.
Démarrez
ce
programme,
et
ouvrez
l’image
bg.png
située
dans
le
dossier
[RACINE]\Template\Main en cliquant sur « Browse ». Choisissez ensuite « Pick », vous
voyez alors l’image apparaître dans une fenêtre. Pour choisir la couleur qui sera désormais
transparente faites un click droit sur cette couleur (ici le rose, tout en haut de la template).
Faites OK, puis sur la fenêtre principale, cliquez sur le bouton « Create » à gauche. Vous
pouvez alors sauver le fichier de région (*.rgn), dans le même dossier «Main », que nous
appellerons dorénavant « template.rgn ».
Insérez le fichier de région généré à l’instant (template.rgn) dans
les ressources de notre programme et ce dans le même dossier
que le PNG principal (donc en tant que Raw content c'est à dire
RCDATA) et nommez le : IDR_PNG_REG
A présent voyons le code nécessaire à la création de notre région (placé dans
WM_INITDIALOG):
//transparence
HRSRC hRsrc = FindResource (hInst, (LPCSTR)IDR_PNG_REG, RT_RCDATA);
HGLOBAL hGlob= LoadResource (hInst, hRsrc);
DWORD RegionSize = SizeofResource (hInst, hRsrc);
LPVOID lpRegion = LockResource (hGlob);
HRGN hRegion = ExtCreateRegion (NULL, RegionSize, (RGNDATA *)lpRegion);
SetWindowRgn (hWin, hRegion, TRUE);
Les APIs FindResource et LoadResource permettent d’avoir un pointeur interne sur notre
ressource. SizeOfResource nous retourne sa taille (nécessaire pour le paramètre nCount de
ExtCreateRegion) et LockResource nous retourne un pointeur sur la ressource avec lequel
nous pouvons travailler (contrairement au pointeur interne). ExtCreateRegion créé la région
à partir de notre fichier ressource (template.rgn) et enfin SetWindowRgn rend la région
effective sur notre graphique.
A présent la bordure rose n’existe plus et ce qui la remplace est tout simplement
transparent.
N’oubliez pas, lorsque vous créez vous-même vos graphiques de définir une couleur pour la
transparence qui n’est utilisée nulle part ailleurs sur votre dessin (à moins que vous désiriez
la
rendre
explicitement
transparente) !
Sinon
cette
couleur
sera
effectivement
transparente… Notez que la couleur rose pure (de part son codage hexadécimal aisément
repérable 0xFF00FF) est souvent utilisée pour ce faire. [En tout cas ça n'est pas un effet de
mode :p]
Vous pouvez à présent compiler cette deuxième template pour voir de quoi il retourne
exactement. Comme stipulé auparavant la bordure rose n’existe plus. Nous allons à présent
voir un aspect important des templates, la compilation conditionnelle.
3.2 Compilation conditionnelle
La compilation conditionnelle est un aspect important des templates. Imaginons que votre
graphique principal n’ait pas besoin de région (tout simplement parce qu’il serait carré par
exemple) le code nécessaire à la mise en place d’une région, que nous venons de voir
précédemment, serait inutile. Même chose si par exemple votre template ne dispose pas de
musique, quel serait alors l’intérêt d’avoir du code pour gérer la musique ou d’inclure les
fichiers de musique…
C’est là qu’entre en jeux la compilation conditionnelle. Nous allons donc coder une template
comprenant tout le code nécessaire (même s’il n’est pas utilisé) et nous utiliserons ensuite
des « commutateurs » permettant au compilateur de savoir ce qu’il doit ou non compiler.
La compilation sous condition s’effectue au moyen des mots clés #ifdef ou #ifndef et #endif.
Par exemple :
#ifdef blabla
//compile cette partie si « blabla » est défini
#endif
Ou encore :
#ifndef blabla
//compile cette partie seulement si « blabla » n’est PAS défini
#endif
Définissons pour l’exemple un commutateur (« switch » en anglais) pour l’utilisation des
régions. Nous nommerons celui-ci USEREGION.
#ifdef USEREGION
// Code pour la transparence en utilisant une région
#endif
Le code situé entre les mots clés ci-dessus n’est compilé que si USEREGION est défini.
Comment définir ce mot clé ?
Nous allons le définir dans les symboles de ressources.
Dans l’explorateur de ressources, faites un click droit sur le dossier « rsrc.rc » et cliquez sur
« Resource Symbols ».
Dans la nouvelle fenêtre qui s’ouvre choisissez « NEW » mettez comme nom USEREGION
et comme ID 1000 (l’ID importe peu, choisissez en un qui n’est pas déjà utilisé). Vous
pouvez alors voir votre symbole pris en compte dans les ressources.
Maintenant nous allons nous intéressez à la compilation conditionnelles des fichiers. Pour
notre exemple, si nous n’utilisons pas de régions, le fichier « template.rgn » ne sert à rien.
Pour le compiler sous condition, faites un click gauche sur ce fichier dans l’explorateur de
ressources et choisissez l’onglet « Properties ».
Spécifiez ensuite « USEREGION » en face de condition.
Vous pourrez alors voir que le nom de votre de ressources se retrouve accolé avec la
condition de sa compilation sous l’éditeur de ressources.
Si vous désirez ne pas compiler le code dépendant de USEREGION vous devrez éditez le
« switch » voulu, en changeant simplement son nom (en rajoutant un underscore avant ou
après ou en spécifiant un nom facilement reconnaissable pour savoir si le switch est utilisé
ou non), par exemple :
USEREGION_NON
Pour changer le nom du symbole refaites la même opération que ci-dessus, mais choisissez
« Change » au lieu de « New ».
Vous pouvez laisser USEREGION tel quel et compiler la template n°2, vous devriez voir sans
problème la région qui est maintenant transparente. Au contraire si vous mettez autre chose
que USEREGION la région n’est plus prise en compte et la bordure rose est visible.
Le code de ce chapitre est disponible dans le dossier « template2 ».
IV Implémentation des boutons
Notre template commence à ressembler à quelque chose, toutefois il est nécessaire
d’améliorer l’interface avec l’utilisateur. Par exemple, pour quitter l’application, faire ALT+F4
n’est définitivement pas le moyen le plus aisé. C’est pour cette raison que nous allons
implémenter les boutons sous formes graphiques, mais d’une manière spécifique.
En effet comme nous avons déjà vu les régions dans un chapitre précédent, nous allons
continuer avec ces dernières en les utilisant encore une fois pour nos boutons, mais cette
fois-ci avec des événements…
Notez que pour l’exemple, seul le bouton « Generate » sera explicité, les autres boutons
relevant des mêmes manipulations il aurait été superflu de les traiter.
Remarquez enfin que les boutons sont au format bitmap (.bmp) et non au format .png. Il eut
été relativement simple d’implémenter ceux-ci au format PNG, toutefois leur petite taille et
la compression avec UPX rend le format PNG peut performant dans ce cas là. Toutefois cela
reste à l’appréciation du programmeur qui devra faire la part entre la taille de l’exécutable et
les performances (le format BMP est natif sous Windows alors que le format PNG nécessite
du code supplémentaire pour être chargé).
4.1 Boutons et évènements
Rappelez vous, pour faire une jolie template graphique nous utilisons une fenêtre avec un
dessin sous la forme d’un PNG. Chaque bouton se voit doter de plusieurs états, soit il est au
repos, ou alors il réagit à la souris, c'est-à-dire au survol et à l’appui. Ainsi plusieurs
évènements sont possibles :
o Le curseur est en dehors de l’aire du bouton  Etat Repos
o Le curseur entre dans l’aire du bouton  Etat survol
o Le bouton gauche de la souris est appuyé dans l’aire du bouton  Etat appuyé
o Le bouton gauche est relâché dans l’aire du bouton  Exécute action + Etat survol
o Le curseur quitte l’aire du bouton  Etat Repos
Peut être vous demandez-vous pourquoi l’action n’est exécutée que lorsque le bouton est
relâché et non lorsqu’il est appuyé ! En fait c’est très simple, et Windows fonctionne ainsi lui
aussi. Pour preuve, avec votre souris appuyez sur la croix de fermeture d’un programme (en
haut à droite) et tout en gardant le bouton de la souris appuyé, sortez de l’aire du bouton
représentant cette croix : résultat, le programme ne se ferme pas, c’est donc l’action
« bouton de la souris relâché dans l’aire du bouton croix » qui exécute l’action de
fermeture.
Au niveau IHM (Interfaçage Homme Machine) ce type d’interaction est souhaitable car l’être
humain n’étant pas exempt d’erreur, il peut toujours vouloir changer d’avis après avoir
appuyer sur le bouton de fermeture…
4.2 Implémentation des boutons
Notre fenêtre principale étant déjà faite nous pouvons penser à l’implémentation des
boutons. Chaque bouton sera implémenté comme une fenêtre enfant (child window), ainsi
notre template sera un peu comme une fenêtre principale disposant de plusieurs fenêtres
enfants. Chacune de ces fenêtres enfants sera créer dynamiquement avec l’API
CreateWindowEx.
Ainsi toutes les commandes arrivent via notre fenêtre principale, nous devrons devront donc
séparer les traitements et commandes relatifs aux boutons de ceux relatifs à la fenêtre
principale. De ce fait nous aurons donc une procédure dédiée spécifiquement aux boutons.
Notez enfin qu’au démarrage de notre programme tous les boutons auront le style
« Repos ».
Nous allons utiliser la technique de la compilation conditionnelle vue précédemment pour
faire fonctionner les boutons.
4.2.1 Commutateurs pour les boutons
Nous allons créer un fichier d’entête (.h) qui contiendra toutes les directives nécessaires à la
compilation conditionnelles, que ce soit pour les boutons ou d’autre paramètres. J’ai choisi
d’appeler ce fichier « switch.h ».
Nous définirons dans ce fichier les aires (surface exprimées avec la structure RECT)
correspondantes à chaque bouton, chacune de ces surface étant soumises à une directive
conditionnelle de compilation.
Par exemple pour le bouton « generate » :
//commutateurs pour les boutons
#ifdef USE_GENERATE_BUTTON
RECT BTN_GENERATE_RECT = {78, 404,78+132, 404+57};
#endif
Notez que les coordonnées sont bien sûr propres à chaque templates… Il faudra que vous
notiez clairement où ce situe les points de chacun des boutons ou que votre graphiste vous
les donnes…
Si vous ne saisissez pas vraiment à quoi correspondent ces chiffres, en voilà une illustration :
Notez simplement que la structure RECT ne
nécessite que deux points, chaque point ayant
deux coordonnées :
Le premier point en haut à gauche se définit par
l’axe des X et l’axe des Y (ici X = 78 et Y =
404).
Le second point, en bas à droite se définit de
même manière, soit 78 + 132 (largeur du
bouton) et 404 + 57 (Hauteur du bouton).
La notation avec addition n’est absolument pas
indispensable et 78+132 aurait pu être remplacé
par 210.
Voici la structure RECT telle que définie dans la
MSDN :
typedef struct _RECT {
LONG left;
LONG top;
LONG right;
LONG bottom;
} RECT, *PRECT;
Il ne nous reste plus qu’à définir les symboles de ressources. Pour ce faire dans l’explorateur
de ressources, faites un click droit sur le dossier « rsrc.rc » et cliquez sur « Resource
Symbols » (cf. chapitre 3.2, inclusion de symboles, voir ici). On ajoutera le symbole
USE_GENERATE_BUTTON et un symbole pour la fenêtre enfant nommé simplement
IDC_BGENER (voir chapitre 1.3 pour les conventions de nom adoptée). Cet ID « général »
sera utilisé lors de la création de la fenêtre.
Les trois symboles pour les fichiers bitmaps seront ajoutés comme suit :
Incluez les trois fichiers bitmaps (situés dans \Template\boutons\general) représentant le
bouton « generate » dans ces trois états (voir ici, mais choisissez bien « IMPORT » puis
« BITMAP »). Les trois états sont : normal, survolé et pressé. Vous pouvez les inclure un par
un ou les trois à la fois (ce qui demandera de regarder lequel correspond à quoi).
Dans le cas où vous les incluriez un par un : choisissez le bouton nommé « gen_n.bmp »
(generate normal), un fois inclus le fichier s’ouvre dans l’IDE et VC++ à la fâcheuse manie de
le nommer à sa convenance (IDB_BITMAP1) et de lui assigner un ID par défaut…
Pour changer cela, cliquer sur le fichier bitmap dans l’explorateur de ressource :
Ensuite regardez ses propriétés et changez son ID en IDC_BGENER_NORM.
Si vous souhaitez changer aussi le numéro (par exemple ici j’ai choisi le numéro d’ID 1102,
vous pouvez ajouter « =XXX » où XXX est un entier) :
N’oubliez pas non plus de spécifier la condition de compilation dans le champ adéquat
(Condition).
Dans l’explorateur de ressources, le fichier bitmap à désormais le bon ID (et le cas échéant
le bon numéro). Vous pouvez réitérer l’opération pour les deux autres fichiers BITMAP.
Une fois tout cela fait pour le bouton « generate » vous pouvez recommencer l’opération
pour chacun des boutons dont vous disposez.
Rappelez vous que cette opération, bien que fastidieuse, ne sera nécessaire qu’une seule fois,
pour votre premier template, ensuite vous n’aurez que quelques paramètres à changer !
En résumé :
-
Chaque bouton est une fenêtre enfant qui sera créée avec CreateWindowEx.
-
Chaque boutons dispose de trois images : Repos, Survolé, Appuyé.
-
Chaque bouton est compilé conditionnellement suivant l’utilisation d’un « switch »
[exemple : USE_GENERATE_BOUTON]
-
Chaque bouton dispose d’une surface, que nous donnons avec la structure RECT.
-
Chaque bouton dispose d’un ID général [exemple : IDC_BGENER]
-
Nous mettons en ressource trois bitmaps représentant le bouton dans ses trois
états, chaque état se voit doter d’un ID, composé de l’ID général et de l’état
[exemple : IDC_BGENER_OVER].
4.2.2 Le code pour les boutons
Nous allons voir dans ce sous chapitre le code nécessaire à l’implémentation des boutons.
Dans un premier temps nous définirons les variables nécessaires au code. Ensuite il faudra
charger les bitmaps des boutons, créer les fenêtres supportant les boutons et finalement
« sous classer » (SubClassing) les procédures des boutons.
A présent que tout est en place concernant nos boutons nous devons définir les handles de
notre fenêtre « generate » qui comme nous l’avons dit précédemment est une fenêtre
enfant de la fenêtre principale. Nous aurons besoin pour ceci de quatre handles (un handle
de fenêtre et trois handles de bitmap) que nous définirons encore une fois dans le fichier
d’en tête dévolu à la compilation conditionnelle (switch.h) :
//commutateurs pour les boutons
#ifdef USE_GENERATE_BUTTON
RECT BTN_GENERATE_RECT = {78, 404, 78+132, 404+57};
HWND hWin_Generate;
HBITMAP hBmp_GENER_NORM;
HBITMAP hBmp_GENER_OVER;
HBITMAP hBmp_GENER_PRESS;
#endif
Les HBITMAP sont obtenus par le chargement des bitmaps en ressource avec l’API
LoadBitmap et le HWND est obtenu avec la création de fenêtre par l’API CreateWindowEx.
Avant d’aller plus loin, nous allons créer un nouveau fichier CPP pour le code des boutons
(chargement des BMP, création des fenêtres, SubClassing). Nommez ce fichier comme bon
vous semble, pour ma part je l’ai appelé « Buttons Handling.cpp » (gestion des boutons).
L’en tête du fichier inclura le fichier d’en tête principal (« main.h ») et le fichier d’en-tête de
compilation conditionnelle (« switch.h »).
//
// Fichier de gestion des boutons
//
#include "main.h"
#include "switch.h"
4.2.2.1 Chargement des Bitmaps
L’opération de chargements de états des bitmaps est relativement simple et ne nécessite pas
de grandes explications, voyez par vous-même :
//Chargement des bitmaps des boutons
void LoadButtons (HINSTANCE hInstance)
{
#ifdef USE_GENERATE_BUTTON
hBmp_GENER_NORM = LoadBitmap (hInstance, (LPCSTR)IDC_BGENER_NORM);
hBmp_GENER_OVER = LoadBitmap (hInstance, (LPCSTR)IDC_BGENER_OVER);
hBmp_GENER_PRESS = LoadBitmap (hInstance, (LPCSTR)IDC_BGENER_PRESS);
#endif
}
Il ne faut pas oublier, encore une fois la compilation conditionnelle ! On charge simplement
les trois bitmaps représentant les trois états du bouton « generate » dans l’exemple cidessus. Les handles de bitmaps (HBITMAP) ont été déclarés précédemment dans le fichier
« switch.h ».
Reste à savoir où nous devrons appeler cette procédure… En tout état de cause, avant la
création de la fenêtre principale (et des fenêtres enfants). On peut donc soit le faire dans
WinMain (avant DialogBoxParam bien sûr !), soit au début de WM_INITDIALOG. Pour ma
part, j’ai choisi de la faire au début de WinMain (fichier main.cpp) :
InitCommonControls ();
//chargement des images des boutons
LoadButtons (hInst);
//obtient les dimensions de l'écran
ScreenWidth = GetSystemMetrics (SM_CXSCREEN);
4.2.2.2 Création des fenêtres
Avant tout, voici le code de la procédure de création de nos fenêtres (encore une fois, seul
le bouton « generate » est explicité).
//créations des fenêtres de boutons
void CreateButtons (HWND hWin)
{
#ifdef USE_GENERATE_BUTTON
hWin_Generate = CreateWindowEx (0,
"STATIC", // fenêtre (control) de type Static
0,
WS_CHILD | WS_VISIBLE | SS_BITMAP | SS_NOTIFY,
BTN_GENERATE_RECT.left, // position de départ (X)
BTN_GENERATE_RECT.top, // position de départ (Y)
0, // largeur donnée par le bitmap lui-même
0, // même chose pour la hauteur
hWin, // Handle de la fenêtre principale
(HMENU)IDC_BGENER, // ID de la fenêtre (ou control)
hInst,
0);
//on associe l'image au control (image de type "repos" ou position
"normale")
SendDlgItemMessage (hWin, IDC_BGENER, STM_SETIMAGE, IMAGE_BITMAP,
(LPARAM)hBmp_GENER_NORM);
//on indique que l'on subclass notre control
OldButtonProc = (WNDPROC)SetWindowLong (hWin_Generate, GWL_WNDPROC,
(LONG)ButtonProc);
#endif
}
Le code est assez parlant de lui-même encore une fois. Remarquez simplement que l’on
utilise un contrôle de type « STATIC ». La position du bouton est donnée par notre
structure RECT (cf. fichier « switch.h »). On donne finalement le handle de la fenêtre
principale et l’ID de notre fenêtre bouton (ici IDC_BGENER).
Ensuite on associe l’image de type « bouton au repos » ou « bouton position normale » à
notre contrôle en passant le HBITMAP (obtenu avec notre procédure « LoadButtons ») par
l’intermédiaire de l’API SendDlgITemMessage.
Finalement on indique que l’on va « subclasser » notre contrôle par l’intermédiaire de
SetWindowLong. Notez que l’on passe en paramètre une procédure (ici ButtonProc) qui
sera notre procédure de « subclassing ». L’API SetWindowLong retourne l’adresse de
l’ancienne procédure de gestion de la fenêtre, adresse qu’il faudra sauvegarder. Dans notre
exemple nous la sauvegardons dans « OldButtonProc ». Cette variable est définie en variable
globale dans le fichier « ButtonsHandling.cpp ».
4.2.2.3 SubClassing des fenêtres
// Subclass procedure
LRESULT APIENTRY ButtonProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
#ifdef USE_GENERATE_BUTTON
if (hWnd == hWin_Generate)
{
if (uMsg==WM_MOUSEMOVE && wParam!= MK_LBUTTON)
//affiche image "bouton survolé" si souris bouge et
//bouton gauche souris n'est pas enfoncé
SendMessage (hWin_Generate, STM_SETIMAGE, IMAGE_BITMAP,
(LPARAM)hBmp_GENER_OVER);
else if (uMsg==WM_LBUTTONDOWN)
//affiche image "bouton appuyé" si bouton gauche enfoncé
SendMessage (hWin_Generate, STM_SETIMAGE, IMAGE_BITMAP,
(LPARAM)hBmp_GENER_PRESS);
else if (uMsg==WM_LBUTTONUP)
{
//affiche bouton "normal" si bouton relâché
SendMessage (hWin_Generate, STM_SETIMAGE, IMAGE_BITMAP,
(LPARAM)hBmp_GENER_NORM);
//envoi un "bouton gauche appuyé" à l'ancienne procédure
return CallWindowProc (OldButtonProc, hWnd, WM_LBUTTONDOWN,
wParam, lParam);
}
else
//si aucun cas traité, appel l'ancienne procédure normalement
return CallWindowProc (OldButtonProc, hWnd, uMsg, wParam,
lParam);
}
#endif
}
Après cette vue du code, peut être vous posez vous la question concernant l’utilité du
SubClassing…
Le SubClassing permet en effet de gérer les messages pour un contrôle (une fenêtre enfant)
en particulier. Sans entrer dans les détails, il est important de savoir que, par exemple, le
message WM_MOUSEMOVE (dans la procédure de fenêtre principale) n’est utile que pour
cette même fenêtre principale, en aucun cas il n’est utile pour les fenêtre enfants. Ainsi, dès
lors que l’on cherche à gérer les messages d’un ou plusieurs contrôles en particulier, il est
important de les subclasser.
D’une manière générale, cela peut se résumer ainsi :
Dés lors que le curseur est dans la surface (cf. structure RECT) d’un bouton, c’est la
procédure de SubClassing qui gère les messages suivant les critères suivant.
-
Identifie le handle du bouton.
-
Quel est l’évènement ?  Accorde le bitmap suivant l’évènement.
-
Si le bouton gauche est relâché (WM_LBUTTONUP) dans la surface du bouton,
envoi un message (WM_LBUTTONDOWN) à la procédure de la fenêtre principale
 Mise en place de l’action.
Une fois le WM_LBUTTONDOWN envoyé à notre procédure de fenêtre principale, celuici est reçu via WM_COMMAND où il pourra être traité ! (Nous verrons plus tard le
traitement de ce message).
Tout dernier point, il nous reste à implémenter un message WM_MOUSEMOVE dans la
procédure de la fenêtre principale, sans quoi, lorsque le curseur quitte la surface du bouton,
celui reste en position « survolée » et non en position repos. Il est en effet impossible de
traiter, dans la procédure de « SubClassing » le cas où le curseur quitte la zone du bouton,
c’est pourquoi il est nécessaire de le traiter dans la procédure principale (fichier
« main.cpp ») :
case WM_MOUSEMOVE:
#ifdef USE_GENERATE_BUTTON
SendMessage (hWin_Generate, STM_SETIMAGE, IMAGE_BITMAP,
(LPARAM)hBmp_GENER_NORM);
#endif
Dernier point à régler, concernant les variables déclares dans le fichier « switch .h» mais
utilisée dans le fichier « main.cpp ».
Attention : Dans notre cas, pour utiliser correctement ces variables vous
devrez les déclarer avec le mot clé « extern » !
A Présent nous disposons d’un programme avec des boutons possédant plusieurs états
suivant l’action qui est faites à la souris. Je vous invite vivement à regarder le code de plus
près, le code de ce chapitre étant présent dans le dossier « template3 ». N’hésitez surtout
pas à expérimenter avec les différents paramètres !
Dans le prochain chapitre nous allons nous concentrer sur les commandes des boutons ainsi
que sur les deux edit boxes.
V Edit Boxes et Commandes
Bien que les champs des deux edit boxes soient visibles sur notre template, il faudra tout de
même créer dynamiquement les contrôles nécessaires. De plus un peu de fantaisie et de
couleur ne faisant pas de mal, nous verrons comment créer notre propre fonte (police)
pour les champs et comment appliquer un peu de couleur au texte.
Une fois ceci fait nous pourrons nous pencher sur l’implémentation des divers messages de
commandes relatifs à l’application. En effet nos boutons ne sont toujours pas effectifs et bien
que l’on puisse appuyer dessus il ne se passe rien !
5.1 Edit Boxes
Le graphique de notre programme contient deux edit boxes mais celles-ci ne sont que
graphiques :
Nous allons dans un premier temps créer les deux edit boxes dynamiquement. Pour ce faire
créez un fichier « EditBoxes.cpp », incluez le fichier d’en tête « main.h » et créer un fichier
« EditBoxes.h » que vous inclurez dans ce nouveau fichier C++.
//fichier EditBoxes.cpp
//création des EditBoxes
#include "main.h"
#include "EditBoxes.h"
extern HINSTANCE
hInst;
void CreateEditBoxes (HWND hWin)
{...}
Dans un premier temps nous commençons par créer dynamiquement une fonte (police)
pour nos EditBoxes :
//créé la fonte pour les deux edit boxes
HFONT hEditFont =
CreateFont(16,0,0,0,FW_BOLD,TRUE,0,0,DEFAULT_CHARSET,0,0,0,0,0);
Ici nous créons une fonte grasse (BOLD), italique et ayant les attribut du jeu de caractère
par défaut. Le système choisira lui-même la fonte se rapprochant le plus de ces spécifications
étant donné que le dernier paramètre ne spécifie aucune police prédéfinie. Je vous invite à
regarder les paramètres de cette API avec plus de détails dans la MSDN.
Ensuite nous créons une couleur pour l’arrière plan des EditBoxes :
//créé une couleur pour le background
hEditBrush = CreateSolidBrush (EDIT_BACKGROUND);
Le paramètre EDIT_BACKGROUND aura été défini par nos soins dans le fichier « main.h »
(en effet ce paramètre sera réutilisé dans le fichier de code « main.cpp ») :
//define globales (fichier main.h)
#define EDIT_BACKGROUND RGB(255, 255, 255)
#define EDIT_TEXTCOLOR RGB(233, 181, 170)
Notez l’utilisation de la macro “RGB” permettant d’utiliser le codage de couleur de 0 à 255
sur chaque composante lumineuse [Rouge, Vert, Bleu]. Ici les trois valeurs à 255
correspondent à un blanc pur.
Ensuite on crée dynamiquement nos deux EditBoxes (seul le code de la première est
exposé) et on associe à chacune la fonte créée précédemment:
//création de l'edit box "NAME"
hEditName = CreateWindowEx (0,
"EDIT",
0,
WS_CHILD | WS_VISIBLE ,
EDIT_NAME_RECT.left,
EDIT_NAME_RECT.top,
EDIT_WIDTH,
EDIT_HEIGTH,
hWin,
(HMENU)IDC_EDIT_NAME,
hInst,0);
//on associe la fonte à l'EditBox
SendMessage ( hEditName, WM_SETFONT, (WPARAM)hEditFont, 0);
Le fichier d’en-tête “EditBoxes.h” ne comprend que le strict minimum pour la création de
nos deux EditBoxes :
//fichier d'en-tête pour les EditBoxes
#define EDIT_WIDTH 123 // largeur d'une EditBox
#define EDIT_HEIGTH 19 // Hauteur d'une EditBox
//cordonnées des EditBoxes
RECT EDIT_NAME_RECT = {28, 354, 28 + EDIT_WIDTH, 354 + EDIT_HEIGTH};
RECT EDIT_SERIAL_RECT = {36, 380, 36 + EDIT_WIDTH, 380 + EDIT_HEIGTH};
//handle des EditBoxes
HWND hEditName;
HWND hEditSerial;
//HBRUSH (couleur de fond) pour les deux EditBoxes
HBRUSH hEditBrush;
Les différentes coordonnées (structure RECT) ainsi que la largeur et la hauteur de nos
EditBoxes auront été calculées en fonction du graphique principal.
Notez aussi que les IDs des deux EditBoxes ont été mis dans le fichier de ressource,
toutefois que leur inclusion dans le fichier « EditBoxes.h » n’aurait posé aucun problème :
#define IDC_EDIT_NAME
#define IDC_EDIT_SERIAL
3000
4000
Finalement il nous reste un peu de code à mettre en place dans le fichier « main.cpp », dans
notre
procédure
de
dialogue
principale,
plus
spécifiquement
dans
le
cas
WM_CTLCOLOREDIT qui prend en charge la couleur des EditBoxes :
case WM_CTLCOLOREDIT:
//applique la couleur de fond pour les EditBoxes
SetBkColor ((HDC)wParam, EDIT_BACKGROUND);
//applique la couleur du texte pour les EditBoxes
SetTextColor ((HDC)wParam, EDIT_TEXTCOLOR);
//retourne OBLIGATOIREMENT la HBRUSH des EditBoxes
return (LRESULT)hEditBrush;
Notez que hEditBrush est déclaré en “extern” dans le fichier « main.cpp ».
A présent nos EditBoxes fonctionnent mais les appuis sur les boutons ne produisent rien.
Nous allons y remédier dans le chapitre suivant.
5.2 Commandes des boutons
Dans ce chapitre nous allons voir comment implémenter les appuis sur les différents
boutons.
Lorsqu’un bouton est pressé, il envoi un message (en l’occurrence WM_COMMAND) à la
procédure de dialogue de sa fenêtre principale. L’identificateur (ID) du bouton est reçu dans
mot de poids faible (Low Word) de la variable wParam.
Voici un exemple avec le bouton de fermeture qui envoie un WM_CLOSE :
case WM_COMMAND:
Select=LOWORD(wParam);
switch(Select)
{
case IDC_BCLOSE:
SendMessage(hWin, WM_CLOSE, 0, 0);
break;
default:
break;
}
break;
Toutefois nous ne devons pas oublier, encore une fois, la compilation conditionnelle que
nous avons appliquée à nos boutons. Nous devons donc enclore chaque bouton dans des
commutateurs conditionnels.
Le même exemple avec le bouton de fermeture, mais cette fois ci avec un commutateur de
compilation conditionnel :
case WM_COMMAND:
Select=LOWORD(wParam);
switch(Select)
{
#ifdef USE_CLOSE_BUTTON
case IDC_BCLOSE:
SendMessage(hWin, WM_CLOSE, 0, 0);
break;
#endif
default:
break;
}
break;
Voici au final à quoi ressemble notre implémentation des boutons de fermeture (« close »),
« minimiser » et « generate » pour l’instant :
case WM_COMMAND:
Select=LOWORD(wParam);
switch(Select)
{
#ifdef USE_CLOSE_BUTTON
case IDC_BCLOSE:
SendMessage(hWin, WM_CLOSE, 0, 0);
break;
#endif
#ifdef USE_MINIMIZE_BUTTON
case IDC_BMINIM:
ShowWindow (hWin, SW_MINIMIZE);
break;
#endif
#ifdef USE_GENERATE_BUTTON
case IDC_BGENER:
GenerateRoutine (hWin);
break;
#endif
default:
break;
}
break;
La routine « GenerateRoutine » qui consiste simplement à inverser le nom entré a été
implémentée dans un fichier à part (« KeyRoutine.cpp ») dans un simple but de
démonstration.
Les boutons pour la musique vont être mis en oeuvre dans la grande partie suivante, dédiée
spécifiquement à la musique, toutefois leur fonctionnement général reste le même.
Le code final de ce chapitre est présent dans le dossier « template4 ». Nous disposons à
présent d’un programme fonctionnel mais qui n’a toujours pas de musique…
VI Musique Maestro !
Notre programme fonctionne plutôt bien, mais les boutons dédiés à la musique sont bien sûr
inopérants. Nous allons voir dans ce chapitre comment jouer des fichiers musicaux et
comment gérer efficacement les appuis sur les différents boutons en charge de la musique.
Pour jouer des fichiers XM j’ai choisi la bibliothèque MiniFmod qui à la particularité d’être
une bibliothèque statique (c'est-à-dire qui est incluse dans le programme et ne nécessite
donc pas de DLL). Malheureusement cette bibliothèque ne disposait pas de fonction de
pause, qu’il a fallut ajouter mais comme elle n’était pas implémentée pour cela, un temps de
latence (de l’ordre de la demi seconde) est nécessaire pour mettre un fichier en pause.
6.1 Bibliothèque musicale
Comme il a été dit auparavant, la bibliothèque utilisée est une version de MiniFmod
modifiée. L'interfaçage de cette bibliothèque se fait grâce aux fonctions présentent dans le
fichier "FmodHandling.cpp". Voici les différents prototypes de fonctions :
o bool Music_Init (void);
o bool Music_Load (int RessourceID);
o bool Music_Play (void);
o bool Music_Unload (void);
o bool Music_Pause (void);
o bool Music_Stop (void);
Vous n'avez pas à vous souciez de l'implémentation de ces fonctions n'y à
celle des fonctions de rappels (memtell, memopen, etc.) présentes dans ce
fichier. Seul leur utilisation vous sera nécessaire !
La bibliothèque (minifmod.lib) et son fichier d'en tête (minifmod.h) se trouvent dans le
répertoire [RACINE]\libs\minifmod.
Pour utiliser la bibliothèque nous devrons donc inclure ces quelques lignes dans le fichier
"main.h" :
// headers spécifiques au programme:
#include "libs/minifmod/minifmod.h" // header pour minifmod (jouer des
fichiers musicaux)
// libs supplémentaires à inclure
#pragma comment (lib, "winmm.lib") // Requis pour MiniFmod
#pragma comment (lib, "libs/minifmod/minifmod.lib") // requis pour
MiniFmod (XM player)
Il ne faudra pas oublier non plus d'exposer les prototypes de fonctions présentes dans
"FmodHandling.cpp" dans le fichier "main.h".
//fichier fmodhandling.cpp
bool Music_Init (void);
bool Music_Load(int RessourceID);
bool Music_Play (void);
bool Music_Unload (void);
bool Music_Pause (void);
bool Music_Stop (void);
Je ne vous ferais pas l'affront de vous expliquer le rôle des fonctions, les noms de celles-ci
sont assez équivoques !
A présent que notre bibliothèque et toutes ces dépendances sont installées, il ne nous reste
plus qu'à implémenter les fonctions dans le code de notre programme.
5.2 Implémentation de la musique
Après avoir mis en place ce qui était nécessaire pour utiliser la bibliothèque, il faut dans un
premier temps importer notre fichier XM dans les ressources. Encore une fois il s'agit
simplement de placer le fichier en temps que ressource de type RCDATA (voir ce chapitre).
Ici j'ai choisi l'identifiant (ID) IDR_XM pour ce même fichier XM. Le fichier (dans notre
exemple "weather.xm") ce trouve dans le dossier [RACINE]\Musique.
Il a été choisi, de manière simple, de jouer le fichier dès le lancement de l'application, aussi
nous mettrons le code permettant l'initialisation, le chargement et la lecture du fichier dans
WM_INITDIALOG :
//MUSIC !
//initialisation du système de musique
Music_Init();
// charge le fichier musical
Music_Load(IDR_XM);
//joue le fichier !
Music_Play();
Les paramètres des fonctions sont on ne peut plus simples et d'ailleurs seul le chargement du
fichier requiert un paramètre, qui n'est autre que l'ID du fichier XM. Notez que l'ordre des
fonctions est bien sûr très important (initialisation puis chargement puis lecture !).
Il ne nous reste plus qu'à implémenter les différentes fonctions pour les boutons. On se
doute qu'un appui sur le bouton "stop" arrêtera la musique en appelant la fonction
Music_Stop, qu'un appui sur le bouton "pause" appellera la fonction Music_Pause, etc.
Toutefois, il est important de savoir si la musique est en train de jouer ou pas ! Pour cela
nous utiliserons deux drapeaux (flags) qui nous indiquerons si la musique joue ou est en
pause. C'est deux drapeau sont déclarés dans le fichier "main.cpp" comme suit :
unsigned char MusicPlay = TRUE;
unsigned char MusicPause = FALSE;
Voici une représentation schématique du fonctionnement général :
L'implémentation en elle-même, au niveau du code C++ est relativement simple et se
déroule au niveau de WM_COMMAND.
En voici un exemple pour la mise en pause :
#ifdef USE_MUSIC_PAUSE
case IDC_MPAUSE:
// le fichier joue
if (MusicPlay == TRUE && MusicPause == FALSE)
{
Music_Pause();
MusicPause = TRUE;
MusicPlay = FALSE;
}
break;
#endif
La seule chose non triviale qu'il faille retenir est la suivante :
Attention : Si la musique est en pause (grâce à la fonction Music_Pause),
pour reprendre la lecture vous devez rappeler Music_Pause ! En effet la
fonction établi un drapeau interne à MiniFmod, et l'inversion de ce drapeau
n'est possible qu'en rappelant la fonction. Vous n'aurez pas besoin de
rappeler Music_Play.
Voici l'exemple avec la gestion du bouton Play :
#ifdef USE_MUSIC_PLAY
case IDC_MPLAY:
//le fichier est en pause
if (MusicPlay == FALSE && MusicPause == TRUE)
{
Music_Pause();// inverse le flag interne de pause
(cela reprend la lecture)
MusicPlay = TRUE;
MusicPause = FALSE;
}
// le fichier est stoppé
else if (MusicPlay == FALSE && MusicPause == FALSE)
{
Music_Play();
MusicPlay = TRUE;
MusicPause = FALSE;
}
break;
#endif
Ensuite à la fermeture du programme (WM_CLOSE), pour être sûr de faire une sortie
propre, on arrêtera la musique et on déchargera le fichier de la mémoire comme ceci :
case WM_CLOSE:
Music_Stop();
Music_Unload();
Vous trouverez le code de ce chapitre dans le dossier "template 5"… Vous avez à présent
une application pleinement fonctionnelle !
Notes d'optimisation & remerciements
Le but de ce tutorial étant la programmation basique d'une application graphique, il n'a pas
été question d'y adjoindre de commentaires sur l'optimisation. Sachez toutefois qu'il est
possible de faire "maigrir" le programme de plusieurs centaines de kilo-octets sans trop
d'effort tout en ayant un programme performant en terme de vitesse.
La première chose dont il est nécessaire de parler est cette DLL qu'il faut adjoindre au
programme (png.dll). Généralement on aime les applications seules et sans dépendances, car
si une DLL vient à manquer, le programme ne démarre tout simplement pas.
Pour remédier à ce "problème", le moyen le plus simple est d'inclure la DLL en ressource, et
de l'extraire au démarrage du programme. Vous n'aurez besoin, pour ce faire, que de ces
APIs (dans l'ordre) :
o FindResource
o LoadResource
o LockResource
o SizeOfResource
o CreateFile
o WriteFile
Ensuite le comportement du programme reste le même !
Pour la question de taille, mieux vaut "packer" l'application (avec UPX par exemple). Mais
vous pouvez bien sûr choisir tout autre packer, voir un packer doublé d'un protector si vous
avez des choses à cacher :p
Certains packers (tel UPX) permettent de garder l'icône du programme tout en
compressant la section des ressources ce qui est réellement un plus au niveau de la taille
finale de l'exécutable. Regarder bien si votre packer permet de compresser la section
ressource tout en préservant la visibilité de l'icône sous l'explorateur de Windows.
N'oubliez pas que les compilateurs modernes disposent d'options non négligeables qui
peuvent influencer la vitesse d'exécution ou la taille de l'exécutable finale voir les deux dans
certains cas. Les toutes dernières générations de compilateurs réalisent réellement des
merveilles dans ce domaine avec de multiples options possibles.
D'un point de vue générale, essayez d'utiliser les instructions FPU ou SSE (attention le SSE2
et à plus forte raison le SSE3 ne sont pas toujours pris en charge par les CPUs !) grâce aux
options de votre compilateur. Essayez de favoriser la taille et la vitesse d'exécution du code
et pensez aux diverses autres optimisations (VC 8 dispose d'une option d'optimisation
"cross-obj" performante).
Remerciements :
Ce tutorial m'aura pris au final un temps considérable et sa rédaction s'est "propagée" sur
des mois, avec de nombreuses retouches… Au départ il contenait seulement quelques notes
et a fini par devenir un tutorial complet… J'en suis finalement arrivé à bout :D
-
Je tiens tout particulièrement à remercier ++Meat pour ses fabuleux GFX et ses
encouragements !
-
L'équipe de la FRET et les habitants du forum pour leurs encouragements et l'amitié
qu'ils me portent.
-
L'équipe des Modos de FC.
-
Les personnes que j'apprécie dans le monde du RE. [Kikooo !!!]
-
Ceux qui font du RE pour apprendre et surtout, surtout, surtout … pour s'amuser !!!
Tutorial livré avec fautes d'orthographes ! [Cadeau !]
L'auteur n'est aucunement responsable de l'utilisation qui est faite de ce
tutorial ainsi que des codes sources et des binaires présentés. Tous les
fichiers compris dans l'archive sont livrés SANS AUCUNE GARANTIE !

Documents pareils