LCC-Win32


Introduction - Installation
Utilisation avec Wedit - Exemple de programme Console
Utilisation avec Wedit - Exemple de programme GUI

Utilitaires personnels pour LCC-Win32
[Retour au sommaire]


Création pas à pas d'un programme GUI à partir de Wedit


La création d'un programme possédant une interface graphique sous Windows, est à la fois un peu différente d'un programme en 'console' et très éloignée d'un programme graphique sous DOS.
Windows, comme tout "serveur graphique", propose un certain nombre d'élements pour la création d'une interface utilisateur.

Un programme ayant une interface graphique, va se décomposer en 2 parties :

  • La création de l'interface graphique
  • La gestion de cette interface, c'est à dire réagir aux intéractions de l'utilisateur (clic sur les boutons, frappe au clavier, etc)

La création d'un projet en GUI, quel qu'il soit, ressemble beaucoup à un projet en mode console. La différence se situe uniquement (dans la configuration du projet) au niveau du 'type' de projet. Pour une application 'graphique', on choisira 'Windows executable'.


Configuration de base du projet

 

Wedit va indiquer qu'aucune ressource n'est définie. Au début, cela n'importera pas. Dans tous les cas, ces paramètres peuvent toujours être modifiés par la suite dans project - configuration.

La création de l'interface graphique fait intervenir un certain nombre de notions de fenêtres, contrôles, etc. Il est tout de même possible de réaliser quelques exemples simples.

Hello World en GUI

Ici, rien de spectaculaire, on va se contenter d'afficher une fenêtre pré-définie dans Windows.

<code>#include &lt;windows.h&gt;</code>

/********************************************************************************************/
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow){
/********************************************************************************************/
MessageBox(NULL,"Hello","World",MB_OK);
return 0;
}

Résultat de l'exécution

On peut remarquer qu'on se contente d'inclure windows.h qui contient un très grand nombre de définitions de fonctions et de constantes. Le point d'entrée n'est plus void main(); mais int WINAPI WinMain(...); Il s'agit d'une caractéristique d'un programme GUI.
La fonction MessageBox va afficher une boîte de message, avec un titre (Hello), un message (World), tout ça en ayant le style MB_OK.

Une autre caractéristique apparaît ici ... la nécessité d'avoir un minimum de documentation pour pouvoir programmer en Win32.
LCC-Win32 propose (téléchargement séparé) le fichier Win32.hlp qui correspond à l'aide de base de Microsoft permettant de programmer en Win32. Cette aide est indispensable. Ici aussi on en apréciera (notemment au début) la concision par rapport à la MSDN par exemple ...

La recherche s'effectue par 'index' lorsque l'on connait le nom de la fonction que l'on cherche. Si on ne connait pas le nom, le problème devient plus difficile. Soit on peut rechercher en texte brut, soit on peut essayer de le deviner ...

Ici, on peut trouver de l'aide sur WinMain (explication du rôle, des paramètres, etc) et sur MessageBox (les différents paramètres, les différentes valeurs possibles).

Un exemple d'utilisation de ressources

L'exemple précédent reste très limité. Pour pouvoir définir une boîte bien plus complète, on va utiliser une ressource. C'est à dire que l'on va décrire la boîte dans un fichier de ressource (.RC). Il sera ensuite possible d'afficher cette boîte au moment voulu.

Les fichiers de ressource sont des fichiers texte. Il est possible de les écrire à la main ou d'utiliser un éditeur de ressources pour les créer. C'est exactement ce qu'on va utiliser ici.

L'éditeur de ressources peut soit être démarré depuis Wedit, soit à l'extérieur. Bien qu'il soit plus facile de le démarrer depuis Wedit, il est préférable de le démarrer depuis l'extérieur, car un plantage de l'éditeur de ressources n'entraînera pas la fermeture de Wedit.

Cet éditeur de ressources s'appelle WeditRes. Il se trouve dans le répertoire 'bin' de LCC-Win32 et est nommé WeditRes.exe. Son lancement donne la fenêtre suivante :

WeditRes

On crée une nouvelle ressource par File - New. La boîte suivante apparaît :

Nouveau Projet

On y indique le nom du répertoire du projet et le nom (sans extension) du fichier de ressources (ici : RES).

Il est directement proposé de créer une nouvelle boîte de dialogue :

Créatiuon d'une boîte de dialogue

Le nombre de possibilités ne doit pas effrayer ...
Dans un premier temps, on pourra changer le titre de la boîte (Title) et remplacer dans identity DLG_100 par IDD_MAIN
Le bouton Ok va permettre de créer la boîte.

On obtient une boite vide :

Boîte nouvellement crée

Il est possible de la remplir à loisir grâce à la palette d'outil disponible à côté. Pour l'essai se contenter des éléments présentés dans l'exemple en dessous :

Palette d'outil

Boîte remplie ...

Une fois cette boîte crée, on peut sauvegarder le fichier de ressources. Un petit détour par File - Files sera nécessaire pour indiquer la liste des fichiers à générer :

Fichiers à générer

On choisira ici, uniquement 'Définitions and prototypes (.h)' et 'RC ASCII Resource File (.rc)'. Après sauvegarde, il faudra inclure le fichier RES.RC dans la liste des fichiers du projet par Projet - Add/Delete Files dans Wedit.

Le code associé est le suivant :

<code><font color="#009900">#include &lt;windows.h&gt;<br> #include &quot;res.h&quot;</font></code>

BOOL _stdcall DialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

/********************************************************************************************/
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow){
/********************************************************************************************/
DialogBox(hInstance,MAKEINTRESOURCE(IDD_MAIN),NULL,DialogProc);
return 0;
}

/******************************************************************************/
BOOL _stdcall DialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){
/******************************************************************************/
switch(msg) {
case WM_INITDIALOG:
break;
case WM_CLOSE:
EndDialog(hwnd,0);
break;
}
return 0;
}

On inclus le fichier res.h, généré par WeditRes. Ce fichier contient les constantes que l'on a défini dans la boîte (ici : IDD_MAIN).

La création de la boîte est lancée par DialogBox. On lui passe le nom de la ressource par MAKEINTRESOURCE(IDD_MAIN), on lui indique aussi le nom d'une fonction (ici DialogProc), qui sera appelée à chaque fois qu'un événement se produit dans la boîte. Ici cette fonction se contente de gérer la fermeture de la boîte lorsque l'on clique sur la croix (EndDialog).

Un exemple de création directe

Cet exemple pourrait être vu en opposition avec l'utilisation de ressources. En réalité, il est très rare de créer complètement les boîtes depuis le programme. L'utilisation de ressources apporte une aide précieuse, et la création directe est utilisée en complément pour réaliser ce qu'il n'est pas possible de réaliser à partir d'une ressource.

#include <windows.h>

/********************************************************************************************/
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow){
/********************************************************************************************/

CreateWindow("EDIT","HelloWorld",
WS_VISIBLE|WS_BORDER|WS_SIZEBOX,
0,0,200,60,NULL,NULL,hInstance,NULL);

MSG msg;

while (GetMessage(&msg,NULL,0,0)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}

Création Directe

Ici, on crée directement une boîte (un contrôle) de type 'EDIT'. Ce contrôle constitue à lui seul une fenêtre. Il n'y a plus de ressources.

En réalité, il n'est jamais utilisé tel quel mais toujours en tant qu'élément enfant (CHILD) dans une autre fenêtre.

Une fois ce contrôle créé, l'exécution continue contrairement à la boite de dialogue où Windows attend que la boîte soit fermée pour continuer. La boucle while sert à envoyer les messages qui arrivent (GetMessage) à la fonction qui gère les messages (DispatchMessage). La fonction qui gère les messages est propre à la boîte (ou au contrôle).
Ici, cette fonction est une fonction interne de Windows. C'est d'ailleurs pour cela qu'elle ne peut pas prévoir la 'sortie' du programme. Cet exemple ne peut donc pas être fermé directement. Il est nécessaire de tuer le processus (gestionnaire des tâches sous NT/2K/XP, ctrl+alt+suppr sous 95/98/Me)

Dans le cas de la boite de dialogue, la boucle de message formée ici par le while était cachée dans le DialogBox.

 

Un exemple de création directe personnalisée

Il est aussi possible de définir son propre contrôle ou sa propre boîte. L'exemple qui suit le montre :

#include <windows.h>

LRESULT CALLBACK MainWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam);

/********************************************************************************************/
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow){
/********************************************************************************************/
WNDCLASS wc;

memset(&wc,0,sizeof(WNDCLASS));
wc.style = CS_HREDRAW|CS_VREDRAW |CS_DBLCLKS ;
wc.lpfnWndProc = (WNDPROC)MainWndProc;
wc.hInstance = hInstance;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszClassName = "HelloWorldWndClass";
wc.lpszMenuName = NULL;
wc.hCursor = NULL;
wc.hIcon = NULL;
if (!RegisterClass(&wc)){
MessageBox(NULL,"Erreur à l'enregistrement de la classe","Erreur",MB_OK);
return 1;
}

CreateWindow("HelloWorldWndClass","HelloWorld",
WS_MINIMIZEBOX|WS_VISIBLE|WS_CAPTION|WS_BORDER|WS_SYSMENU|WS_SIZEBOX,
0,0,600,300,NULL,NULL,hInstance,NULL);

MSG msg;

while (GetMessage(&msg,NULL,0,0)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}

///////////////////////////////////////////////////////////////////////////////////
// MAIN CALLBACK
///////////////////////////////////////////////////////////////////////////////////
/*********************************************************************************/
LRESULT CALLBACK MainWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam){
/*********************************************************************************/
switch (msg) {
case WM_CREATE:
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd,msg,wParam,lParam);
}
return 0;
}

Création d'une boîte personnalisée

Le code devient plus compliqué.
On commence par enregistrer une 'classe'. Cette classe n'a rien à voir avec une classe du C++, mais est une classe de fenêtre. Elle définit l'ensemble des propriétés de cette fenêtre, ainsi que le nom de la fonction qui va se charger de prendre en compte les événements (en fait, quelque part, le même concept qu'une classe C++ ...)

En enregistrant cette classe, on crée un nouveau type de fenêtre (mais pas une fenêtre, juste un type).

On crée ensuite, comme au-dessus, une fenêtre (CreateWindow), mais cette fois du type que l'on vient de définir.

Utilitaires personnels pour LCC-Win32

Liens associés : LCC -Win32