I. Création d'une application Windows▲
I-A. Hello, world !▲
Ce programme affiche une boîte de dialogue qui affiche « Hello, world ! ».
#include <windows.h>
int
WINAPI WinMain
(
HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int
nCmdShow)
{
MessageBox
(
NULL
, "
Hello, world !
"
, "
Hello
"
, MB_OK);
return
0
;
}
La fonction MessageBox sert généralement à afficher un petit message à l'utilisateur comme pour l'informer du succès ou de l'échec d'une opération par exemple ou pour demander une action à effectuer lorsque le programme ne peut prendre de décision tout seul.
int
MessageBox
(
HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType);
Paramètres :
- hWnd : handle d'une fenêtre à laquelle la boîte de dialogue se rapporte ou tout
simplement NULL si on ne veut lui associer aucune fenêtre (nous verrons un peu plus
loin ce que c'est qu'un handle)
- lpText : le texte à afficher
- lpCaption : titre de la boîte de dialogue
- uType : type de la boîte de dialogue. Ce type peut être une combinaison valide des
constantes suivantes :
Boutons | Icônes | Boutons par défaut |
---|---|---|
MB_OK | MB_ICONASTERISK | MB_DEFBUTTON1 |
MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2 |
MB_YESNOCANCEL | MB_ICONEXCLAMATION | MB_DEFBUTTON3 |
MB_ABORTRETRYIGNORE | MB_ICONSTOP |
Par exemple : MB_ABORTRETRYIGNORE | MB_ICONSTOP | MB_DEFBUTTON1 |
Valeur de retour :
- Retourne un entier indiquant la décision prise par l'utilisateur. Peut être IDOK,
IDCANCEL, IDYES, IDNO, IDABORT, IDRETRY, IDIGNORE
Nous reviendrons plus tard sur la fonction WinMain.
I-B. Création et compilation du projet▲
Sous Visual C++ 6▲
- Lancez Visual C++.
- Créez un nouveau projet Win32 que vous allez nommer helloworld en choisissant
File > New > Project > Win32 Application. Un dossier nommé helloworld
est alors créé. Ce sera votre répertoire par défaut. Deux fichiers, entre autres, sont
également créés : helloworld.prj (votre projet) et helloworld.dsw (votre espace
de travail).
- Choisissez An empty project pour qu'aucun fichier ne soit automatiquement ajouté
à notre projet.
- Ajoutez au projet un nouveau fichier que vous allez nommer hello.c avec la
commande Project > Add to Project > New > C++ source file. Nommez-le
bien hello.c car si vous omettez l'extension, VC6 va automatiquement ajouter
l'extension .cpp et vous aurez donc un fichier source C++ (hello.cpp) au lieu d'un
fichier source C, à moins bien sûr que c'est justement ce que vous cherchiez ...
- Dans l'explorateur de projet (normalement c'est sur votre gauche), cliquez sur File
View pour afficher une vue des fichiers qui constituent votre projet. Ouvrez ensuite le
dossier Source Files puis double cliquez sur hello.c pour l'ouvrir dans l'éditeur.
- Saisissez maintenant le code puis compilez avec la commande Build > Build
helloworld.exe (F7). Le fichier helloworld\Debug\helloworld.exe est alors
créé.
- Pour tester votre programme sans quitter VC, choisissez Build > Execute helloworld.exe (Ctrl + F5).
Sous Visual Studio .NET▲
La procédure est presque les même que sous VC6. Créez un nouveau projet d'application
Windows (Win32 Project) puis dans l'étape Applications Settings de l'assistant, choissez
Windows Application puis Empty Project.
Sous Visual Studio 2005 et plus récents, allez ensuite dans Project > Properties > Configuration Properties > General
puis positionnez la valeur de Character Set à Not Set. La raison de ce réglage supplémentaire sera expliquée un peu plus bas.
Compilez puis testez.
Sous Code::Blocks 1.0▲
- Lancez Code::Blocks.
- Créez un nouveau projet d'application Windows (Projet Win32) que vous aller
nommer helloworld en choisissant File > New Project > Win32 GUI
Application. Enregistrez-le dans un répertoire de votre choix qui sera alors votre
répertoire par défaut. Avant de valider, cochez l'option Do not create any files
afin qu'aucun fichier ne soit automatiquement ajouté à notre projet. Une fois que vous
avez validé, un fichier helloworld.cbp (votre projet) sera créé dans le répertoire de
votre projet.
- Créez un nouveau fichier que vous allez nommer hello.c avec la commande File
> New File. Acceptez que ce fichier soit ajouté au projet.
- Saisissez maintenant le code puis compilez avec la commande Build > Build
(Ctrl + F9). Le fichier helloworld.exe est alors créé.
- Pour tester votre programme sans quitter Code::Blocks, choisissez Build > Run
(Ctrl + F10).
I-C. La fonction WinMain▲
Le point d'entrée d'une application Windows est la fonction WinMain.
int
WINAPI WinMain
(
HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int
nCmdShow);
Paramètres :
- hInstance : handle de l'instance de l'application. Un handle est un numéro qui
identifie de manière unique un objet quelconque. Ici, hInstance identifie donc de
manière unique notre application.
- hPrevInstance : handle de l'instance précédente. Vaut toujours NULL. Ce paramètre
fut utilisé dans les premières versions de Windows et est uniquement gardé pour des
raisons de compatibilité.
- lpCmdLine : pointeur les arguments de la ligne de commande de l'application. Pour
obtenir la ligne de commande dans son intégralité, utilisez la fonction
GetCommandLine. Cette fonction ne nécessite aucun argument et retourne un pointeur
sur la ligne de commande toute entière.
- nCmdShow : indique comment l'utilisateur désire t-il que la fenêtre principale soit
affichée : avec sa taille normale, agrandie ou réduite ? Rien n'oblige cependant le
programme à considérer ce choix.
Valeur de retour :
- La fonction doit retourner un entier appelé code d'erreur de l'application.
WINAPI est une macro qui représente la convention d'appel utilisée par les fonctions de l'API Windows. Quant à windows.h, c'est bien sûr le fichier d'en-tête principal pour la programmation d'applications pour Windows. En fait, windows.h inclut lui-même d'autres fichiers dont windef.h (définitions des types de base), winnt.h (définitions des types et constantes spécifiques à Windows NT), winbase.h (APIs de base), winuser.h (tout ce qui touche l'interface utilisateur) et wingdi.h (tout ce qui touche la GDI, qui sera étudiée dans les chapitres suivants).
I-D. La notation hongroise▲
La notation hongroise est la pratique de préfixer chaque identificateur pour coder des informations qui sont bons à savoir à son sujet. Cette pratique est très utilisée par les programmeurs Windows. Par exemple le préfixe p ou lp sert à indiquer qu'il s'agit d'un pointeur, le préfixe h qu'il s'agit d'un handle, etc. Les préfixes couramment utilisés sont :
Préfixe | Type de la variable |
---|---|
h | handle |
p, lp | pointeur |
sz, lpsz | chaîne terminée par 0 |
i, n | int |
u | UINT (unsigned int) |
ul | ULONG (unsigned long) |
dw | DWORD (unsigned long) |
c | effectif (count) |
cb | taille en octets (count of bytes) |
b | BOOL (int) |
I-E. Unicode▲
Unicode est un jeu de caractères dérivé de l'ASCII utilisant 16 bits pour représenter chaque
caractère. Il est utilisé en interne par Windows mais les applications peuvent également utiliser des caractères ou chaînes de caractères ANSI (caractères codés sur 8 bits)
pour communiquer avec le système grâce à un jeu de conversions totalement transparent pour l'utilisateur.
Par contre lorsqu'on développe des programmes qui doivent dialoguer directement avec le noyau du système
(comme les pilotes de périphériques par exemple), on est obligé d'utiliser des chaînes en Unicode uniquement.
En langage C, sous Windows, le type wchar_t (wide character) est utilisé pour représenter des caractères Unicode. Ces caractères sont appelés caractères
larges. char et wchar_t étant des types différents, un caractère "large" (un caractère de type wchar_t) ne s'écrit pas de la même façon qu'un simple caractère. Les caractères larges doivent toujours être précédés d'un L. Par exemple L'A',
L'*' et L'1' sont des caractères larges. C'est valable également pour les chaînes de caractères larges, par exemple : L"Bonjour" au lieu de "Bonjour". De même, les fonctions de manipulation des caractères et/ou chaînes de caractères larges ne
sont pas les mêmes que celles qui sont dédiées aux caractères et/ou chaînes de caractères simples bien que l'on puisse noter une certaine similitude au niveau des noms et des paramètres requis. Par exemple, pour les caractères et chaînes de caractères
larges, on utilise wprintf à la place de printf, wcscpy à la place de strcpy, iswalpha à la place de isalpha, etc. Selon les fonctions que vous utilisez, vous devez inclure wchar.h et/ou wctype.h.
Le programme suivant montre un exemple d'utilisation des caractères larges.
#include <stdio.h>
#include <wchar.h>
int
main
(
)
{
wchar_t s[256
];
wcscpy
(
s, L"
Hello
"
);
wcscat
(
s, L"
, world !
"
);
wprintf
(
L"
%s
\n
"
, s);
return
0
;
}
Pour ne pas rendre les programmes dépendants du jeu de caractères utilisé (ANSI ou Unicode), les développeurs de Microsoft ont décidé d'ajouter
à la bibliothèque standard du C des macros et types qui permettent de compiler n'importe quel programme avec n'importe quel jeu de caractères sans
aucune modification du code source. Ces macros et types sont définis dans le fichier d'en-tête tchar.h (qui est actuellement un fichier d'en-tête "standard" sous Windows).
A la compilation, si la macro _UNICODE n'est pas définie, _TCHAR est remplacé par char, les "fonctions" par leur version ANSI (_tcscpy -> strcpy, _tprintf -> printf, etc.)
et _TEXT("...") par "...". Sinon _TCHAR est remplacé par wchar_t, les "fonctions" par leur version Unicode (_tcscpy -> wcscpy, _tprintf -> wprintf, etc.) et _TEXT("...") par L"...".
Voici un exemple de programme utilisant les _TCHAR :
#include <stdio.h>
#include <tchar.h>
int
main
(
)
{
_TCHAR s[256
];
_tcscpy
(
s, _TEXT
(
"
Hello
"
));
_tcscat
(
s, _TEXT
(
"
, world !
"
));
_tprintf
(
_TEXT
(
"
%s
\n
"
), s);
return
0
;
}
Le SDK (le kit de développement de logiciels pour Windows) utilise également cette technique. En effet, MessageBox par exemple en réalité n'est pas le nom d'une fonction mais celui d'une
macro qui sera remplacée par MessageBoxA (MessageBox ANSI Characters) si la macro UNICODE (à ne pas confondre avec _UNICODE) n'est pas définie et par MessageBoxW (MessageBox Wide Characters)
si elle l'est.
A la compilation, si la macro UNICODE n'est pas définie, TCHAR est remplacé par char, les "fonctions" par leur version ANSI (par exemple : MessageBox -> MessageBoxA)
et TEXT("...") par "...". Sinon _TCHAR est remplacé par wchar_t, les "fonctions" par leur version Unicode (par exemple : MessageBox -> MessageBoxW) et TEXT("...") par L"...".
Comme vos applications utiliseront généralement à la fois des fonctions de la bibliothèque du C et des fonctions de l'API Windows, n'oubliez donc pas de définir _UNICODE si vous définissez UNICODE
et de ne pas définir la permière si vous ne définissez pas la seconde. Sous Visual Studio .NET, la définition de ces macros peut être contrôlée via les paramètres du projet : Project > Properties > Configuration Properties > General > Character Set.
Chosissez Not Set pour utiliser le jeu de caractères ANSI et Unicode pour utiliser le jeu de caractères Unicode. A noter que depuis Visual Studio 2005, c'est Unicode qui est utilisé par défaut.
Voici un programme qui utilise la macro TEXT afin de pouvoir compiler quel que le soit le jeu de caractères utilisé, contrairement à notre premier
programme qui ne fonctionnait que pour le jeu de caractères ANSI.
#include <windows.h>
int
WINAPI WinMain
(
HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int
nCmdShow)
{
MessageBox
(
NULL
, TEXT
(
"
Hello, world !
"
), TEXT
(
"
Hello
"
), MB_OK);
return
0
;
}
Il est également temps d'expliquer ce que sont que les types LPSTR et LPCTSTR. Et bien, ce sont tout simplement des pointeurs de caractère. En effet on a :
typedef
char
CHAR;
typedef
wchar_t WCHAR;
#ifndef UNICODE
typedef
CHAR TCHAR;
#else
typedef
WCHAR TCHAR;
#endif
#define CONST const
typedef
CHAR *
LPSTR;
typedef
CONST CHAR *
LPCSTR;
typedef
WCHAR *
LPWSTR;
typedef
CONST WCHAR *
LPCWSTR;
typedef
TCHAR *
LPTSTR;
typedef
CONST TCHAR *
LPCTSTR;
Dans la suite, nous allons toujours utiliser le jeu de caractères ANSI afin de rendre nos programmes plus simple à lire mais dans des projets plus sérieux, il est recommandé d'écrire du code "portable", c'est-à-dire utilisant les TCHAR.