IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)


API Windows en C

Sous classement de fenêtres.

Par CGi

Le 11 juillet 2005




Introduction :

Dans une application, vous traitez les messages des fenêtres ordinaires ou des boîtes de dialogue. Les contrôles leur envoient des messages de notification pour signaler un événement propre à eux mêmes. Malheureusement, tous les événements de ces contrôles n'ont pas de messages de notification qui leurs sont associés. Si vous voulez tout de même traiter un de ces événements, une seule solution, accéder à la procédure de fenêtre du contrôle.
Pour cet exemple, nous reprendrons l'exemple du chapitre 2 "Contrôles et Messages". Nous mettrons le contrôle d'édition en lecture seule, mais pas en lui donnant le style "lecture seule" qui lui donnerait un fond gris. Ce que ne nous ne désirons pas (pour l'exemple).


Préparation de l'exemple:

Après avoir créé le contrôle d'édition nous changerons son curseur par celui en forme de flèche. Ceci juste pour montrer visuellement que l'on ne peut pas l'éditer.

    static HWND hEdit;

    switch (uMsg)
    {
        case WM_CREATE:
            hEdit =CreateWindow("edit", "Texte non modifiable.\r\nVous ne pouvez \
que le lire.\r\nMais il garde la couleur du fond d'un contrôle d'édition actif.",
              WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL,
                                           0, 0, 0, 0, hwnd, NULL, hinst, NULL);
            SetClassLong(hEdit, GCL_HCURSOR, (LONG)LoadCursor(NULL, IDC_ARROW));

Cette action étant réalisée en le changeant dans la classe de fenêtre du contrôle. Ceci sera réalisé à l'aide de la fonction SetClassLong. Elle permet de modifier des éléments d'une classe de fenêtre déjà créée.

Mise en oeuvre:

Accéder à la procédure de fenêtre du contrôle ne sera pas suffisant. On ne pourra en obtenir que seulement un pointeur. Il ne pourra donc servir qu'à l'appeler. Nous devons donc en créer une nouvelle.

LRESULT APIENTRY EditProc(HWND, UINT, WPARAM, LPARAM);

Ensuite, on affectera la nouvelle procédure de fenêtre au contrôle d'édition avec la fonction SetWindowLong, qui de plus nous retourne l'adresse de l'ancienne procédure de fenêtre.

#ifdef STRICT
  WNDPROC wpOrigEditProc ;
#else
  FARPROC wpOrigEditProc ;
#endif
/*...
             ... */
            wpOrigEditProc = (PVOID)SetWindowLong(hEdit,
                                                   GWL_WNDPROC, (LONG)EditProc);

SetWindowLong permet de modifier les propriétés d'une fenêtre comme son style par exemple.
Le pointeur sur l'ancienne procédure de fenêtre nous est nécessaire pour traiter les messages par défaut du contrôle. Les traitements que l'on veux implémenter se font bien sûr dans la nouvelle procédure de fenêtre du contrôle :

LRESULT APIENTRY EditProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
   if (uMsg == WM_SETFOCUS || uMsg == WM_CONTEXTMENU || uMsg == WM_CHAR ||
                                                             uMsg == WM_KEYDOWN)
                                                                       return 0;
   return CallWindowProc(wpOrigEditProc, hwnd, uMsg, wParam, lParam);
}

Dans cette nouvelle procédure, on doit comme déjà dit, appeler l'ancienne procédure afin d'effectuer les actions par défaut du contrôle, ne serait-ce que de se dessiner par exemple. C'est le rôle de la fonction CallWindowProc qui reçoit bien sûr le pointeur sur l'ancienne procédure de fenêtre et les paramètres du message.
Dans notre exemple on bloquera les messages, WM_SETFOCUS (pour qu'il ne puisse pas prendre le focus), WM_CONTEXTMENU (pour ne pas ouvrir son menu contextuel), WM_KEYDOWN et WM_CHAR (pour qu'il ne puisse pas recevoir des commandes ou des caractères depuis le clavier). Ces messages ne seront donc pas envoyés à la procédure de fenêtre d'origine. Ceci afin d'en faire un contrôle d'édition en lecture seule qui n'est pas gris.

Code complet :

#include <windows.h>

#ifdef STRICT
  WNDPROC wpOrigEditProc ;
#else
  FARPROC wpOrigEditProc ;
#endif

LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);

LRESULT APIENTRY EditProc(HWND, UINT, WPARAM, LPARAM);

HINSTANCE hinst;

int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hPrevInstance,
                                                  LPSTR lpCmdLine, int nCmdShow)
{
    HWND hwnd;
    MSG msg;
    WNDCLASS wc;

    hinst = hinstance;

    wc.style = 0 ;
    wc.lpfnWndProc = MainWndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hinstance;
    wc.hIcon = NULL;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = NULL;
    wc.lpszMenuName =  NULL;
    wc.lpszClassName = "MaWinClass";

    if(!RegisterClass(&wc)) return FALSE;

    hwnd = CreateWindow("MaWinClass", "Titre", WS_OVERLAPPEDWINDOW,
                                   CW_USEDEFAULT, CW_USEDEFAULT, 400, 300,
                                                   NULL, NULL, hinstance, NULL);
    if (!hwnd)  return FALSE;

    ShowWindow(hwnd, nCmdShow);

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

/******************************************************************************/

LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    static HWND hEdit;

    switch (uMsg)
    {
        case WM_CREATE:
            hEdit =CreateWindow("edit", "Texte non modifiable.\r\nVous ne pouvez \
que le lire.\r\nMais il garde la couleur du fond d'un contrôle d'édition actif.",
              WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL,
                                           0, 0, 0, 0, hwnd, NULL, hinst, NULL);
            SetClassLong(hEdit, GCL_HCURSOR, (LONG)LoadCursor(NULL, IDC_ARROW));
            wpOrigEditProc = (PVOID)SetWindowLong(hEdit,
                                                   GWL_WNDPROC, (LONG)EditProc);
            return 0;

        case WM_SIZE:
            MoveWindow(hEdit, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
            return 0;

        case WM_DESTROY:
            SetWindowLong(hEdit, GWL_WNDPROC, (LONG)wpOrigEditProc);
            PostQuitMessage(0);
            return 0;

        default:
            return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
}

/******************************************************************************/

LRESULT APIENTRY EditProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
   if (uMsg == WM_SETFOCUS || uMsg == WM_CONTEXTMENU || uMsg == WM_CHAR ||
                                                             uMsg == WM_KEYDOWN)
                                                                       return 0;
   return CallWindowProc(wpOrigEditProc, hwnd, uMsg, wParam, lParam);
}

J'ai testé les compilations avec C++ Builder et DevC++.


A vos PC.

CGi

Avec la contribution de pharaonix pour la relecture.



Sommaire



C/C++
  Les pointeurs du C/C++.   Les listes chaînées.             Liste simple.             Liste triée.             Liste double.   Les arbres.   Les tas.   Le C orienté objets ?

  1 - La fenêtre principale.   2 - Contrôles et messages.   3 - Les commandes.   4 - Dialogue std.   5 - Contexte de périph.   6 - Dessiner.   7 - Les ressources.   8 - Dialogue perso.   9 - Dialogue comm.   10 - Les accélérateurs.

Assembleur
  Assembleur sous Visual C++.

C++ BUILDER
  Trucs et astuces.   Composant.   TRichEdit.   TDrawGrid.   Application MDI.   TThread.   wxWidgets.   Style Win XP.

  Première application.   Construire un menu.   Dessiner.   Sisers, Timers...   Dialogues standards.   Dialogues perso.

DotNet
  Composant C# Builder.   Contrôle WinForm.   Application MDI.

Java
  Applet java.





Copyright 2002-2020 CGi - Tous droits réservés CGi. Toutes reproduction, utilisation ou diffusion de ce document par quelque moyen que ce soit autre que pour un usage personnel doit faire l'objet d'une autorisation écrite de la part de l'auteur, propriétaire des droits intellectuels.
Les codes sources de ce document sont fournis en l'état. L'utilisateur les utilise à ses risques et périls, sans garantie d'aucune sorte de la part de l'auteur. L'auteur n'est responsable d'aucun dommage subi par l'utilisateur pouvant résulter de l'utilisation ou de la distribution des codes sources de ce document.
De la même façon, l'auteur n'est en aucun cas responsable d'une quelconque perte de revenus ou de profits, ou de données, ou de tous dommages directs ou indirects, susceptibles de survenir du fait de l'utilisation des codes sources de ce document, quand bien même l'auteur aurait été averti de la possibilité de tels dommages. L'utilisation des codes sources de ce document vaut acceptation par l'utilisateur des termes de la licence ci-dessus.