Les bases de la programmation sous Windows


précédentsommairesuivant

I. Création d'une application Windows

I-A. Hello, world !

Ce programme affiche une boîte de dialogue qui affiche « Hello, world ! ».

hello.c
Sélectionnez
#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.

 
Sélectionnez
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

  1. Lancez Visual C++.

  2. 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).

  3. Choisissez An empty project pour qu'aucun fichier ne soit automatiquement ajouté à notre projet.

  4. 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 ...

  5. 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.

  6. Saisissez maintenant le code puis compilez avec la commande Build > Build helloworld.exe (F7). Le fichier helloworld\Debug\helloworld.exe est alors créé.

  7. 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

  1. Lancez Code::Blocks.

  2. 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.

  3. 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.

  4. Saisissez maintenant le code puis compilez avec la commande Build > Build (Ctrl + F9). Le fichier helloworld.exe est alors créé.

  5. 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.

 
Sélectionnez
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.

 
Sélectionnez
#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 :

 
Sélectionnez
#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.

 
Sélectionnez
#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 :

 
Sélectionnez
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.


précédentsommairesuivant

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2008 Melem. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Droits de diffusion permanents accordés à Developpez LLC.