Recherche…


Créer une fenêtre

#define UNICODE
#define _UNICODE
#include <windows.h>
#include <tchar.h>
const TCHAR CLSNAME[] = TEXT("helloworldWClass");
LRESULT CALLBACK winproc(HWND hwnd, UINT wm, WPARAM wp, LPARAM lp);

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, PTSTR cmdline,
                   int cmdshow)
{
    WNDCLASSEX wc = { };
    MSG msg;
    HWND hwnd;

    wc.cbSize        = sizeof (wc);
    wc.style         = 0;
    wc.lpfnWndProc   = winproc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInst;
    wc.hIcon         = LoadIcon (NULL, IDI_APPLICATION);
    wc.hCursor       = LoadCursor (NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = CLSNAME;
    wc.hIconSm       = LoadIcon (NULL, IDI_APPLICATION);

    if (!RegisterClassEx(&wc)) {
        MessageBox(NULL, TEXT("Could not register window class"), 
                  NULL, MB_ICONERROR);
        return 0;
    }

    hwnd = CreateWindowEx(WS_EX_LEFT,
                          CLSNAME,
                          NULL,
                          WS_OVERLAPPEDWINDOW,
                          CW_USEDEFAULT,
                          CW_USEDEFAULT,
                          CW_USEDEFAULT,
                          CW_USEDEFAULT,
                          NULL,
                          NULL,
                          hInst,
                          NULL);
    if (!hwnd) {
        MessageBox(NULL, TEXT("Could not create window"), NULL, MB_ICONERROR);
        return 0;
    }

    ShowWindow(hwnd, cmdshow);
    UpdateWindow(hwnd);
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}
LRESULT CALLBACK winproc(HWND hwnd, UINT wm, WPARAM wp, LPARAM lp)
{
    return DefWindowProc(hwnd, wm, wp, lp);
}

La première chose que l'on voit sont les deux définitions de macro, UNICODE et _UNICODE . Ces macros font que notre programme comprend des chaînes de caractères larges ( wchar_t[n] ), pas des chaînes étroites ( char[n] ). Par conséquent, tous les littéraux de chaîne doivent être encapsulés dans une macro TEXT( type de caractère générique pour les chaînes Win32 est TCHAR , dont la définition dépend du fait que UNICODE soit défini ou non. Un nouvel en-tête est inclus: <tchar.h> contient le déclaration de TCHAR .

Une fenêtre se compose de ce qu'on appelle une classe de fenêtre . Cela décrit des informations sur une fenêtre à partager entre ses instances, comme l'icône, le curseur et d'autres. Une classe de fenêtre est identifiée par un nom de classe de fenêtre, qui est donné dans la variable globale CLSNAME dans cet exemple. Le premier acte de WinMain est de remplir la structure de classe de fenêtre WNDCLASSEX wc . Les membres sont:

  • cbSize: La taille, en octets, de la structure
  • style: les styles de classe de fenêtre. Ceci est 0 pour le moment.
  • lpfnWndProc: C'est l'un des champs les plus importants. Il stocke l'adresse de la procédure de fenêtre . La procédure de fenêtre est une fonction qui gère les événements pour toutes les fenêtres qui sont des instances de cette classe de fenêtre.
  • cbClsExtra: Le nombre d'octets supplémentaires à allouer pour la classe de fenêtre. Pour la plupart des situations, ce membre est 0.
  • cbWndExtra: Le nombre d'octets supplémentaires à allouer pour chaque fenêtre individuelle. Ne confondez pas cela avec cbClsExtra , qui est commun à toutes les instances. C'est souvent 0.
  • hInstance: Le handle d'instance. Attribuez simplement l'argument hInst dans WinMain à ce champ.
  • hIcon: Le descripteur d'icône pour la classe de fenêtre. LoadIcon(NULL, IDI_APPLICATION) charge l'icône de l'application par défaut.
  • hCursor: Le handle de curseur pour la classe de fenêtre. LoadCursor(NULL, IDC_ARROW) charge le curseur par défaut.
  • hbrBackground: Un handle pour le pinceau d'arrière-plan. GetStockObject (WHITE_BRUSH) donne un handle à un pinceau blanc. La valeur de retour doit être GetStockObject car GetStockObject renvoie un objet générique.
  • lpszMenuName: Le nom de ressource de la barre de menus à utiliser. Si aucune barre de menus n'est nécessaire, ce champ peut être NULL.
  • lpszClassName: Le nom de classe qui identifie cette structure de classe de fenêtre. Dans cet exemple, la variable globale CLSNAME stocke le nom de la classe de fenêtre.
  • hIconSm: Un handle pour l'icône de petite classe.

Une fois cette structure initialisée, la fonction RegisterClassEx est appelée. Cela provoque l'enregistrement de la classe de fenêtre avec Windows, ce qui la fait connaître à l'application. Il retourne 0 en cas d'échec.

Maintenant que la classe de fenêtre a été enregistrée, nous pouvons afficher la fenêtre en utilisant CreateWindowEx . Les arguments sont:

  • stylesex: les styles de fenêtres étendus. La valeur par défaut est WS_EX_LEFT.
  • clsname: le nom de la classe
  • cap: le titre de la fenêtre ou la légende. Dans ce cas, c'est la légende qui est affichée dans la barre de titre d'une fenêtre.
  • styles: les styles de fenêtre. Si vous souhaitez créer une fenêtre de niveau supérieur (parent) comme celle-ci, l'indicateur à transmettre est WS_OVERLAPPEDWINDOW.
  • x: Coordonnée x du coin supérieur gauche de la fenêtre.
  • y: coordonnée y du coin supérieur gauche de la fenêtre
  • cx: La largeur de la fenêtre
  • cy: La hauteur de la fenêtre
  • hwndParent: le handle de la fenêtre parente. Comme cette fenêtre est en soi une fenêtre parente, cet argument est NULL.
  • hMenuOrID: Si la fenêtre en cours de création est une fenêtre parente, cet argument est un handle vers le menu de la fenêtre. Ne confondez pas cela avec le menu de la classe, qui est WNDCLASSEX::lpszClassName . Le menu de classe est commun à toutes les instances de fenêtres portant le même nom de classe. Cet argument, cependant, est spécifique à cette instance uniquement. Si la fenêtre en cours de création est une fenêtre enfant, il s'agit de l'ID de la fenêtre enfant. Dans ce cas, nous créons une fenêtre parente sans menu, donc NULL est passé.
  • hInst: le handle de l'instance de l'application.
  • etc: les informations supplémentaires transmises à la fenêtre de la fenêtre. Si aucune information supplémentaire ne doit être transmise, transmettez NULL.

Si x ou y ou cx ou cy est CW_USEDEFAULT , alors la valeur de cet argument sera déterminée par Windows. C'est ce qui se fait dans cet exemple.

CreateWindowEx renvoie le descripteur à la fenêtre nouvellement créée. Si la création de la fenêtre échouait, il NULL .

Nous montrons ensuite la fenêtre en appelant ShowWindow . Le premier argument de cette fonction est le handle de la fenêtre. Le second argument est le style d'affichage, qui indique comment la fenêtre doit être affichée. La plupart des applications transmettent simplement l'argument cmdshow transmis dans WinMain . Une fois la fenêtre affichée, elle doit être mise à jour par un appel à UpdateWindow . Un message de mise à jour est envoyé à la fenêtre. Nous allons apprendre ce que cela signifie dans un autre tutoriel.

Vient maintenant le coeur de l'application: la pompe à messages. Il pompe les messages envoyés à cette application par le système d'exploitation et envoie les messages à la procédure de fenêtre. L'appel GetMessage renvoie une valeur différente de zéro jusqu'à ce que l'application reçoive des messages provoquant sa fermeture, auquel cas elle renvoie 0. Le seul argument qui nous concerne est le pointeur vers une structure MSG contenant des informations sur le message. Les autres arguments sont tous 0.

Dans la boucle de message, TranslateMessage traduit les messages de clé virtuelle en messages de caractère. La signification de ceci, encore une fois, est sans importance pour nous. Il faut un pointeur sur une structure MSG . L'appel qui le suit directement, DispatchMessage , distribue le message pointé par son argument à la procédure de fenêtre de la fenêtre. La dernière chose que WinMain doit faire est de renvoyer un code d'état. Le membre wParam de la structure MSG contient cette valeur de retour, il est donc retourné.

Mais c'est juste pour la fonction WinMain . L'autre fonction est winproc , la procédure de fenêtre. Il traitera les messages de la fenêtre qui lui sont envoyés par Windows. La signature de winproc est la suivante:

  • hwnd: descripteur de la fenêtre dont les messages sont en cours de traitement.
  • wm: l'identifiant du message de la fenêtre
  • wp: un des arguments d'information sur le message. Cela dépend de l'argument wm
  • lp: un des arguments d'information de message. Cela dépend de l'argument wm . Cet argument est généralement utilisé pour transmettre des pointeurs ou des poignées

Dans ce programme simple, nous ne traitons aucun message nous-mêmes. Mais cela ne signifie pas que Windows non plus. C'est pourquoi il faut appeler DefWindowProc , qui contient le code de gestion des fenêtres par défaut. Cette fonction doit être appelée à la fin de chaque procédure de fenêtre.

Qu'est-ce qu'une poignée?

Un handle est un type de données qui représente un objet unique. Ce sont des pointeurs, mais des structures de données secrètes gérées par le système d'exploitation. Les détails de ces structures ne doivent pas nous concerner. Tout ce que l'utilisateur doit faire, c'est simplement créer / récupérer un descripteur en utilisant un appel d'API, et le transmettre à d'autres appels d'API en utilisant ce type de descripteur. Le seul type de handle que nous avons utilisé était le HWND renvoyé par CreateWindowEx .

Les constantes

Dans cet exemple, nous rencontrons une poignée de constantes, qui sont en majuscules et commencent par un préfixe de 2 ou 3 lettres. (Les types Windows sont également en majuscules)

  • IDI_APPLICATION: Nom de la ressource contenant l'icône de l'application par défaut. Ceci est utilisé avec LoadIcon ou LoadImage (LoadIcon dans cet exemple).
  • IDC_ARROW: le nom de la ressource qui contient le curseur de l'application par défaut. Ceci est utilisé avec LoadIcon ou LoadImage (LoadIcon dans cet exemple).
  • WHITE_BRUSH: Le nom d'un objet stock. Cet objet de stock est le pinceau blanc.
  • MB_ICONERROR: Un indicateur utilisé avec MessageBox pour afficher une icône d'erreur.
  • WS_EX_LEFT: le style de fenêtre étendu par défaut. Cela entraîne la fenêtre à avoir des propriétés alignées à gauche.
  • WS_OVERLAPPEDWINDOW: style de fenêtre indiquant que la fenêtre doit être une fenêtre parente avec une barre de titre, une zone de taille et d'autres éléments typiques des fenêtres de niveau supérieur.
  • CW_USEDEFAULT: Utilisé avec les arguments x , y , cx ou cy CreateWindowEx . Windows choisit une valeur valide pour l'argument pour lequel CW_USEDEFAULT été transmis.

Types de Windows

Lors de la programmation pour Windows, vous devrez vous familiariser avec les types Win32, qui sont des alias pour les types intégrés. Ces types sont en majuscules. Les types d'alias utilisés dans ce programme sont:

  • TCHAR: Le type de caractère générique. Si UNICODE est défini, il s'agit d'un wchar_t . Otheriwse, c'est un char .
  • UINT: Un entier non signé. Utilisé pour représenter l'identificateur de message dans les procédures de fenêtre et à d'autres fins.
  • WPARAM: Dans Win16, il s'agissait d'un argument WORD (d'où le préfixe W ). Avec l'introduction de Win32, il s'agit maintenant d'un UINT_PTR . Cela illustre le point de ces alias Windows; ils sont là pour protéger les programmes du changement.
  • LPARAM: Ceci est un argument LONG ( LONG_PTR dans Win64).
  • PTSTR: Le P signifie un pointeur. Le T signifie un caractère générique et le STR signifie une chaîne. Il s’agit donc d’un pointeur sur une chaîne TCHAR . Les autres types de chaînes incluent:
    • LPTSTR: Identique à PTSTR
    • LPCTSTR: signifie const TCHAR *
    • PCTSTR: Identique à LPCTSTR
    • LPWSTR: Chaîne large ( wchar_t * )
    • LPCWSTR: signifie const wchar_t *
    • PWSTR: Identique à LPWSTR
    • Et beaucoup plus Comme vous pouvez le voir, les types Win32 peuvent être un problème à comprendre, en particulier avec autant de types synonymes, qui sont un artefact de Win16.
  • LRESULT: Ce type est utilisé pour représenter la valeur de retour des procédures de fenêtre. C'est généralement un long (d'où le L ).


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow