begin process at 2012 02 12 19:15:38
  Trouver un code source :
 
dans
 
Accueil > 

Tutoriels

 > 

API

 > BASE DE LA CRÉATION D'UNE FENETRE EN API WINDOWS [C]

BASE DE LA CRÉATION D'UNE FENETRE EN API WINDOWS [C]


 Information sur le tutoriel

Note :
8,9 / 10 - par 20 personnes
8,90 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10


 Description

Pour toutes les personnes sur le forum qui demandent encore et toujours des exemples de code pour débuter en API et une documentation en français. Je n'ai pas la prétention de dire que c'est une documentation, mais pour un point de départ, pourquoi pas.
J'espere que ce tutorial pouura vous etre utile.

Tutorial

Avantde commencer, il faut savoir que pour obtenir plus d'informations sur lesdifférentes fonctions utilisées, il faut utiliser MSDN. Toutes les donnéesconcernant chaque fonctionnel sont référencées et expliquées.

Danstout ce fichier nous allons très régulièrement parlé de handle, nous allonsdonc dès maintenant définir ce que c'est. Il s'agit d'un pointeur sur unestructure contenant un identifiant32 bits unique pour chaque objet (fenêtre,bitmap, pinceau, police…) dont une table est maintenue par Windows

La base de tout: La création d'une fenêtre

Nousseront amenés dans cette partie à créer 2 fonctions:

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCEhPrevInstance, LPSTR lpCmdLine,  int nCmdShow);

Cettefonction est le point d'entrée dans le programme (comme la fonction main dansles programmes consoles)

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam,LPARAM lParam);

Tandisque celle-ci  sera la fonction de traitement des messages

Méthode hard (sans ressource)

Pourcela, 4 variables s'imposent:

  • un handle sur la fenêtre (une sorte d'adresse sur la fenêtre qui sert à la retrouver parmi les autres) de type: HWND
  • une classe permettant de connaître les informations relatives à la fenêtre comme les actions demandant un redessinement de la fenêtre, le nom de la fonction de traitement des messages, le titre qui s'affichera dans le gestionnaire des taches… de type: WNDCLASSEX
  • une variable contenant les données du message devant être transmises à la fenêtre de type: MSG
  • une variable  (appelées instance) qui permet d'identifier par groupe des fenêtres. Ainsi toutes les fenêtres d'un même projet auront la possibilité d'avoir la même instance et seront plus facilement accessible de type: HINSTANCE

Lacréation de la fenêtre se fait au travers de la fonction CreateWindow oude la fonction CreateWindowEx.
Une fois la fenêtre créée, rien ne se passe!!! Pourquoi?
Contrairement à la programmation en mode console, cette programmation estappelée évènementielle. On doit donc envoyer des évènements (sous forme demessage) à notre fenêtre.

Ci-dessous,la boucle type d'envoie des messages à la fenêtre (nous verrons plus tardcomment l'améliorer, mais celle-ci fonctionne dans la majorité des cas):

                while(GetMessage(&msg, NULL, 0, 0))                      //msg est défini comme suit: MSG msg;

                {

                       TranslateMessage(&msg);

                       DispatchMessage(&msg);

                }

Cetteboucle transmet à la fenêtre les messages, ces messages seront traités ensuitedans la fonction de traitement des messages dont le nom est spécifié dans lastructure WNDCLASSEX.
Dans la fonction de traitement des messages, il faudra donc pouvoir déterminerle type du message, et ses paramètres.
La fonction de traitement des messages s'articule en général de la façon suivante:

                switch(message)

                {

               case WM_CREATE:

                       //Votre code

                       return TRUE;
               case WM_COMMAND:     //Message si action sur un élément (bouton, combo…)

                       //Votre code

                       return TRUE;
               case WM_CLOSE:

                       DestroyWindow(hwnd);

                       return TRUE;
               case WM_DESTROY:

                       PostQuitMessage(0);

                       return TRUE;
               default:

                       return DefWindowProc(hwnd, message, wParam, lParam);

                }

                return FALSE;

Pourafficher une fenêtre, il faut donc traiter le message WM_CREATE qui est envoyéà la fenêtre lors de sa création.
Ici deux fonctions sont importantes:

  • ShowWindow(HWND, BOOL) qui permet de rendre visible (SW_SHOW) ou invisible une fenêtre (SW_HIDE).
  • SetForegroundWindow(HWND) qui place au premier plan la fenêtre.

D'autrefonction peuvent également être utilisée pour placer la fenêtre.
Voila, après ça, vous venez de créer votre première fenêtre, vide certes, maisvotre première fenêtre quand même.

Méthode avec ressource

Pourcela, créer dans l'éditeur de ressource de votre IDE une nouvelle fenêtre. Dansnotre exemple nous dirons que l'identifiant de cette fenêtre est IDD_DIALOG1.Cette identifiant est un entier associé à chaque élément de la ressource pourpouvoir facilement naviguer dans la ressource.
Avec cette méthode, la création de la fenêtre se résume en une seule ligne:

         DialogBox(hInst,MAKEINTRESOURCE(IDD_DIALOG1), hwnd_parent, WndProc)

Ontrouve dans cette fonction 4 paramètres qu'il convient de bien identifier.

  • hInst est l'instance de votre application (il est conseillé d'utiliser ce paramètre en variable globale car il est utilisé par toutes les fenêtres de votre programme.
  • MAKEINTRESOURCE(IDD_DIALOG1) spécifie la ressource à charger et à utiliser
  • hwnd_parent est le handle de la fenêtre demandant la création de cette nouvelle fenêtre. Si il s'agit de la première fenêtre que vous créez ou d'une fenêtre qui n'a pas de fenêtre parente, mettez ce paramètre à NULL.
  • WndProc est le nom de votre fonction de traitement des messages pour votre fenêtre.

Ilest à noter qu'il est également possible d'utiliser d'autres fonctions pourcharger des ressources comme la fonction CreateDialog, mais après cesfonctions il faut réutiliser les boucles de message vues dans la partieprécédente. Cette fonction est cependant nécessaire si l'on veut pouvoirmodifier la boucle de traitement des messages.

Conclusion

Nousvenons de voir 2 méthodes différentes pour la création d'une fenêtre. Maislaquelle de ces 2 méthodes choisir? Vous vous doutez bien que chacune de ces 2méthodes a ses avantages et ses inconvénients.

  • La méthode hard permet de créer une fenêtre "modulable". Par exemple dans notre application nous créons une fenêtre avec des formes particulières, mais on pourrait aussi avoir des fenêtres dont le contenu change. Par exemple en fonction d'une variable, on doit afficher plus ou moins de composants… Cependant cette méthode est longue à programmer, et il faut sans cesse se ramener à MSDN pour savoir quels types donnés à la fenêtre.
  • La méthode utilisant les ressources est quand à elle moins modulable, mais beaucoup plus rapide. Dans l'éditeur de ressource il est aisé de créer une fenêtre, de placer des composants sur celle-ci, de paramétrer les options de la fenêtre…

Modifier et tester le comportement d'une fenêtre

Dansce deuxième chapitre, nous allons voir quelques fonctions permettant demodifier le comportement de la fenêtre, son apparence…

Cettepartie ne se veut pas une liste exhaustive de toutes les fonctions permettantun accès aux données de la fenêtre, mais liste quand même un certains nombresde fonctions et peut paraître assez rébarbative.

Passage Handle à Identifiant

Ilest très important de comprendre cette notion, car les fonctions utilisent"indifféremment"dans leur paramètre soit un identifiant soit unhandle pour désigner la fenêtre ou le composant sur lequel on souhaitetravailler.

  • Récupération du code à partir de l'identifiant:

Grâceà l'utilisation de la fonction GetDlgItem(hwnd, identifiant) on récupèrele code de la fenêtre ou du composant. Nous allons voir à quoi correspondentles deux paramètres de cette fonction. hwnd est le code de la fenêtre parent,et identifiant est l'identifiant (que l'on peut voir dans l'éditeur deressource par exemple) du composant ou de la fenêtre.
Attention, cette méthode ne peut pas prendre en premier paramètre la valeurNULL. Vous me direz alors"Comment récupérer le code de notre premièrefenêtre?" La réponse est toute simple! Le code de la fenêtre est lepremier paramètre de la fonction de traitement des messages, il suffit donc dele lire. Cette fonction est donc utile pour récupérer le code d'un composantd'une fenêtre, ou celui d'une fenêtre enfant par rapport à la fenêtre danslaquelle on travaille.

  • Récupération de l'identifiant à partir du code:

Cettefois-ci, nous utilisons une fonction beaucoup plus paramétrable, il s'agit dela fonction GetWindowLong(hwnd, index). Je dis que cette fonction estplus paramétrable, car selon la valeur d'index qu'on lui passe, elle nousrenvoie une information différente. Dans notre cas, hwnd est le code de lafenêtre ou du composant dont on veut récupérer l'identifiant, et index doitprendre la valeur GWL_ID.

La visibilité de la fenêtre

Commevu au premier chapitre, pour modifier la visibilité de la fenêtre, il faututiliser la fonction ShowWindow(hwnd, index). hwnd représente le code dela fenêtre et index permet de saisir l'action à effectuer. Nous nous limiteronsdans ce tutorial à l'utilisation de 2 valeurs d'index: SW_SHOW(affichage de la fenêtre) et SW_HIDE (masquer la fenêtre), mais il estaussi possible de maximiser/minimiser/iconifier/restaurer/… la fenêtre avecd'autres valeur d'index. Pour les connaître, se référer à MSDN.

Ilest aussi possible de faire appel à la fonction SetWindowPos(…)

La position de la fenêtre

Commeévoquer au chapitre 1, cette modification est réalisable avec la fonction SetWindowPos(hwnd,hwndafter, x, y, w, h, flag). Cette fonction parait au premier abord un peuplus compliquée. Loin s'en faut! Selon la valeur de flag (possibilité desassocier avec l'opérateur |), tous les champs ne sont pas nécessaires!
Etudions quelques valeurs de flag. En regardant dans MSDN, on se rend compteque flag n'indique les actions à effectuer, mais les actions à ne paseffectuer! Ainsi pour ne pas déplacer la fenêtre et donc ne pas avoir à tenircompte des paramètres x et y, flag doit avoir la valeur SWP_NOMOVE; pourne pas modifier la taille de la fenêtre et donc ignorer w et h, flag doit avoirla valeur SWP_NOSIZE.
Vous aurez compris que pour déplacer la fenêtre ou la redimensionner, il nefaut pas utiliser ces paramètres.
Cette fonction est aussi très utile pour régler l'ordre des fenêtres. Essayerde vous imaginer votre écran en profondeur. Comment dire à une fenêtre son"altitude"? En utilisant cette fonction! Le second paramètre (hwndafter)permet de le spécifier. Quelques valeurs de hwndafter sont prédéfinies (voirMSDN) et permettent de placer la fenêtre à la plus haute ou la plus basse des"altitudes" par exemple.
Dans le cas d'un déplacement au sens propre sur la fenêtre (changementd'origine), on peut utiliser la fonction MoveWindow(…). Je vous laissealler voir dans MSDN ses paramètres tant ils sont simples à comprendre
La fonction AdjustWindowRect(…) permet de modifier la taille de lafenêtre, et la fonction GetWindowRect(…) permet de la récupérer.

Activer une fenêtre

Unefenêtre peut être active ou inactive. Si une fenêtre est inactive,l'utilisateur ne peut pas interagir avec elle. On met souvent une fenêtreinactive quand on a ouvert une nouvelle fenêtre de paramétrage d'option parexemple.
Pour cela, la fonction EnableWindow(hwnd, BOOL) est à votre disposition.Si BOOL est à TRUE, la fenêtre sera activée, sinon, elle sera désactivée.Simple, non?

Modifier le style

Cettefois ci, il faut utiliser la fonction SetWindowLong(hwnd, flag,value).flag permet de spécifier quels types de modification apporter à la fenêtre.
Si flag prend la valeur GWL_STYLE, on peut modifier le style de lafenêtre. Pour rajouter un style à la fenêtre, ne pas oublier de rajouter lesanciens styles que l'on obtient avec GetWindowLong(hwnd,GWL_STYLE).

Sil'on veut retirer un style de la fenêtre, faire alors:

                SetWindowLong(hwnd, GWL_STYLE, GetWindLong(hwnd,GWL_STYLE) & !styletodel);

Sil'on veut ajouter un style à la fenêtre faire:

                SetWindowLong(hwnd,GWL_STYLE, GetWindLong(hwnd, GWL_STYLE) | styletoadd);

Pourmodifier les styles étendus(que l'on a pu créer uniquement avec la fonction CreateWindowEx)utilisé le flag GWL_EXSTYLE.

Modifier la fonction de traitement des messages

Ilpeut arriver dans certain casque vous ayez besoin de changer la fonction detraitement des messages de la fenêtre, ceci s'appelle du sous classement. Nousreviendrons plus tard dans ce tutorial sur cette méthode et surtout sur sonutilité. Sachez cependant que pour changer de fonction de traitement desmessages, nous utilisons la fonction SetWindowLong() avec le paramètreflag à GWL_WNDPROC (pour une fenêtre)ou DWL_WNDPROC (pour unedialogbox).
Pour ne pas modifier la fonction de traitement des messages, mais en appelerune autre connue juste dans un cas précis, utilisé la fonction CallWindowProc(…).Pasde panique si vous ne comprenez pas à quoi cela peut bien servir, nousreviendrons dessus plus tard et fournirons des exemples. Nous citons ici cettefonction pour montrer son existence.

Modifier l'instance

Pourmodifier l'instance d'une fenêtre on utilise encore la même fonctionSetWindowLong() avec son paramètre flag à la valeur GWL_HINSTANCE.

Modifier/récupérer le titre

Pourmodifier le titre d'une application, nous allons voir la une nouvelle fonction.Il s'agit de la fonction SetWindowText(hwnd, titre).titre est une chaînede caractères contenant le titre à donner à la fenêtre ou au composant. Il fautremarquer que par exemple le titre d'un bouton est le texte qui apparaît sur lebouton. SetWindowText ne se restreint donc pas seulement aux fenêtres,elle travaille aussi sur les composants.
Pour récupérer le titre, utiliser la fonction GetWndowText(…)

Modifier le curseur/l'icône/le menu/…

Bienque la fonction permettant de le faire soit très simple d'emploi, si on veutcomprendre ce qui se passe,on se mélange facilement les pinceaux entre code,instance et classe. Aussi nous n'entrerons pas dans les détails.
Ici, une ou deux possibilités s'offrent à nous. A la création de la fenêtre, sion a utilisé la méthode hard pour la créer, on peut sélectionner lecurseur/icône/menu/… à utiliser dans les différents champs de la structure WNDCLASSEX.
Je ne compte pas cette méthode comme vrai puisque le but de ce chapitre est demodifier un curseur/icône/menu/…,pas d'en mettre un dès le début du programme.
Pour cela, il faut utiliser la fonction SetClassLong(hwnd, flag, value).Al'image de la fonction SetWindowLong(…)cette fonction offre denombreuses possibilités, à vous d'aller les voir dans MSDN.
A savoir qu'il existe son homologue, la fonction GetClassLong(…)qui aulieu de modifier une donnée permet de la récupérer.

Récupérer/modifier le code de la fenêtre parent

Pourrécupérer le code de la fenêtre parent, utilisé la fonction GetParent(hwnd).
Pour la modifier, utiliser la fonction SetParent(hwnd, hwndparent).

Tester la visibilité de la fenêtre

Dansce cas ci, utiliser la fonction IsWindowVisible(hwnd) qui renvoie TRUEsi la fenêtre est visible, FALSE autrement.

Tester si une fenêtre est active

Dela même façon que précédemment, utilisé la fonction IsWindowEnable(hwnd)

Tester si un code représente une fenêtre

Commeprécédemment, cela se fait en utilisant la fonction IsWindow(hwnd)

Tester si une fenêtre est une fenêtre enfant d'uneautre

Toujoursà l'identique des tests précédents, cela se fait avec la fonction IsChild(hwndparent,hwnd)

Création et communication avec des composants

Ici,nous allons étudier une des parties les plus importantes (tant en taille qu'enintérêt). Nous allons essayer de voir comment fonctionne réellementl'évènementiel, et nous verrons comment faire communiquer plusieurs élémentsentre eux.

Création des composants – Méthode hard

Commepour créer une fenêtre, on peut créer un composant en les programmant. Pourcela on utilise encore une fois les fonctions CreateWindow ou CreateWindowEx.
Il faut rentrer le type de composant à créer dans le champ lpClassName d'unedes 2 fonctions citées ci-dessus.
Listons les composants qu'il est possible de créer et la chaîne de caractères àentrer pour le faire:

Bouton:           "BUTTON"

Combo:          "COMBOBOX"

Edit:               "EDIT"

ListBox:          "LISTBOX"

ScrollBar:        "SCROLLBAR"

Static:            "STATIC"

ListView:        WC_LISTVIEW

Progress:         PROGRESS_CLASS

Cesont les principaux composants existants.
A savoir que pour les checkbox et les radiobox sont des boutons, et que pourles créés il faut mettre dans le champ dwStyledes fonctions CreateWindow(Ex)respectivement les valeurs BS_AUTOCHECKBOX et  BS_RADIOBUTTON.
On peut aussi créer une sorte de délimiteur dans une fenêtre avec le style BS_GROUPBOXassocié à la création d'un bouton.
Pour plus de styles possibles pour chacun de ces composants, se référer àl'aide disponible dans MSDN pour les fonctions CreateWindow(Ex).
Juste un dernier petit mot sur les listviews et les progressbars. Ce sont descomposants que l'on appelle complexes. Ils nécessitent l'importation d'unelibrairie: comctl32.lib, et celle d'un nouveau header: commctrl.h.
Pour importer la librairie dans le projet, deux solutions, soit l'importer àpartir de la rubrique settings du menu project, soit indiquer au précompilateur d'importer cette librairie. Cela se fait par l'intermédiaire d'unedirective appelée pragma: #pragma comment(lib,"comctl32.lib")
Ce n'est pas tout, ces composants nécessitent l'initialisation d'une dllexterne (installée par windows et donc forcément présente).

Nousverrons comment cela se fait au travers d'un exemple (exemple2).

Exemple1: Création d'un composant "simple": le bouton

CreateWindow("BUTTON", chaine, WS_CHILD |  BS_PUSHBUTTON | BOUTONVISIBLE | WS_TABSTOP,

               xpos, ypos, width, heigth,  windowlocation, NULL, 0, NULL);

Avec ce code, on vient de créer un bouton classique sur lequel est marqué le texte contenue dans la chaîne de caractère chaîne. Ce bouton est à la position indiquée par les entiers xpos et ypos et mesure width de largeur et heigth de hauteur. Les types donnés permettent à ce bouton d'apparaître visible, de pouvoir être sélectionné lors d'un appui sur la touche TAB. Ce bouton fait parti de la fenêtre code windowlocation.

Exemple2: Création d'un composant "complexe": la progressbar

INITCOMMONCONTROLSEX InitCtrlEx;

HWND progress;
InitCtrlEx.dwSize = sizeof(INITCOMMONCONTROLSEX);

InitCtrlEx.dwICC  =  ICC_PROGRESS_CLASS;           // ICC_LISTVIEW_CLASSES  pour les listviews

if (!InitCommonControlsEx(&InitCtrlEx))

                exit(1);

progress = CreateWindowEx(CS_DBLCLKS, PROGRESS_CLASS, NULL,  WS_CHILD | WS_VISIBLE | PBS_SMOOTH,

                               xpos, ypos, width,  heigth, windowlocation, NULL, 0, NULL);

Dans un premier temps, on doit initialiser la dll de gestion des composants complexes. Si cela ne marche pas, on n'a plus qu'à quitter le programme. Ensuite on crée la progressbar de la même façon que pour un bouton. On a utilisé ici la fonction CreateWindowEx car on a voulu indiquer que la progressbar réagirait aux doubles clics. PBS_SMOOTH est un style propre des progressbars qui indique que son contenu sera continu, et pas hachurer.

Création de composants – Méthode"ressource"

Lorsde la création d'une fenêtre dans une ressource, on peut à ce moment ladessiner les composants constituants cette fenêtre, et leur donner des styles.Ces composants sont alors connus par un identifiant dans la ressource.Souvenez-vous que nous avons au chapitre précédent comment passer d'unidentifiant à un code
Si vous utilisez cette méthode,vous remarquerez la présence de composants dontje ne vous ai pas parlé plus haut. En effet, ce sont des composants moinsutilisés (mais utilisé quand même)et si un jour vous en avez besoin, et bienvous chercherez dans MSDN comment les utiliser.

Communication avec les composants

Nousallons voir là la fonction autour de laquelle s'organise la programmationévénementielle, il s'agit de la fonction SendMessage(…).

Voicile prototype de cette fonction:

                SendMessage(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);

Etudionsmaintenant chacun de ces paramètres un par un:

  • hwnd: Il s'agit du code de la fenêtre ou du composant à qui le message est destiné.
  • message: Identifiant du message que l'on envoie (WM_QUIT, WM_COMMAND, WM_USER…), c'est autour de ce paramètre que doit se faire le switch principal des fonctions de traitement des messages (voir chapitre 1 pour un exemple)
  • wParam: Un paramètre du message, on peut lui donner n'importe quel type, à condition de le caster avant.
  • lParam: Un paramètre du message, on peut lui donner n'importe quel type, à condition de le caster avant.

Commeles messages envoyés à la fenêtre ou au composant sont très nombreux, il seraittrès pénible de devoir tous les traiter, particulièrement pour les fenêtres"simples".

L'APIwindows fournit la fonction DefWindowProc(…) qui propose un traitementpar défaut de tous les messages envoyés à la fenêtre. Cette fonction s'avèretrès pratique pour la plupart des messages, mais il faut bien en gérerquelques-uns pour que votre programme fasse quelque chose. Ainsi par exemplelors de l'appui par l'utilisateur sur un bouton vous devrez spécifier auprogramme ce qu'il doit faire. Mais lorsque l'utilisateur déplace la sourisdans votre fenêtre, peut-être n'avez rien à faire suite à ce message, et il estpénible de devoir traiter tous les messages de ce style, sachant que DefWindowProcpeut le faire à votre place. Voir l'exemple donné au chapitre 1 pourl'utilisation de cette fonction dans une boucle de traitement des messages.

Ci-dessous,une liste non exhaustive des principaux messages:

  • WM_CREATE: Message envoyé à une fenêtre lors de sa création
  • WM_INITDIALOG: Envoyé lors de la création d'une fenêtre à partir
  • WM_PAINT: Message envoyé à une fenêtre lorsqu'une partie de sa zone client doit être redessinée
  • WM_ERASEBKGND: Demande d'effacement d'une partie de la zone client
  • WM_SYSCOMMAND: Envoyé pour le traitement de différents événements pouvant survenir (fenêtre minimisée, restaurée…)
  • WM_ACTIVATE: Envoyé à la fenêtre lorsqu'elle est activée / désactivée
  • WM_MOVE: Envoyé lorsque la fenêtre est déplacée
  • WM_SIZE: Envoyé lorsque la taille de la fenêtre à été modifiée
  • WM_CLOSE: Envoyé lorsque l'utilisateur demande la fermeture de la fenêtre (croix ou raccourci ALT+F4)
  • WM_DESTROY: Destruction de la fenêtre
  • WM_QUIT: Met fin à l'application (on peut l'appeler avec la fonction PostQuitMessage(valuesortie) )
  • WM_COMMAND: Message envoyé par un contrôle, un menu… lorsqu'une action est effectué sur lui
  • WM_KEYDOWN/UP:Message envoyé lorsqu'une touche du clavier est enfoncée/relevée
  • WM_CHAR: Indique le caractère ASCII correspondant à la touche pressée
  • WM_SYSKEYUP/DOWN/CHAR: Utilisé pour identifier les événements dus aux touches systèmes
  • WM_MOUSEMOVE: Envoyé à chaque déplacement de souris
  • WM_LBUTTONDOWN/UP:Envoyé lorsque le bouton gauche de la souris est pressé ou relevé
  • WM_RBUTTONDOWN/UP:Envoyé lorsque le bouton droit de la souris est pressé ou relevé
  • WM_MBUTTONDOWN/UP:Envoyé lorsque le bouton central de la souris est pressé ou relevé
  • WM_L/R/MBUTTONDBLCLK: Envoyé lorsqu'un double clic a été détecté. Pour que ce message soit envoyé, il faut que la fenêtre/composant soit le style CS_DBLCLKS
  • WM_TIMER: Envoyé lorsqu'un timer envoie un message

Nousnous arrêterons là pour les messages, mais un bref coup d'oeil dans MSDN vousmontrera la quantité de message qu'il existe.
Rajoutons à ces messages que l'on peut qualifier de système, les messages quechaque composant peut envoyer, et nous arrivons à une quantité non négligeable.Alors on peut dire merci à la fonction DefWindowProc qui nous évite detous les traiter.
On pourra noter en allant voir dans MSDN les différents messages envoyés parles composants que la deuxième lettre du message est soit un M, soit un N. Le Msignifie MODIFY, et le N signifie NOTIFY. En général, les messages avec un Nsont envoyés par le composant à la fenêtre parent pour indiquer unemodification.
Je pense qu'après toute cette théorie, un petit exemple s'impose!
Imaginons que nous avons créé une ressource  d'identifiant IDD_DIALOG1quia à l'intérieur un bouton d'identifiant IDCANCEL. Nous souhaitons afficherla fenêtre et lorsqu'un clic sur le bouton intervient, nous voulons la fermer.Comment allons-nous procéder? Et bien regardez ci-dessous!

#include <windows.h> 

#include "resource.h"
 LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam,LPARAM lParam)

{

                switch(message)

                {

                case WM_INITDIALOG:

                               ShowWindow(hwnd,SW_SHOW);

                               SetForegroundWindow(hwnd);

                               return TRUE;
                Case WM_COMMAND:

                               switch(LOWORD(wParam))

                               {

                               case IDCANCEL:

                                               SendMessage(hwnd,WM_DESTROY, 0, 0);

                                               return TRUE;
                               default:

                                               return DefWindowProc(hwnd, message, wParam, lParam);

                               }
                case WM_CLOSE:

                               DestroyWindow(hwnd);

                               return TRUE;
                caseWM_DESTROY:

                               PostQuitMessage(0);

                               return TRUE;
                default:

                               return 0; //et pas DefWindowProc (car sinon la fenêtre ne se déplace plus, si certains savent, je suis intéressé)

                }

}
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCEhPrevInstance, LPSTR lpCmdLine, int nCmdShow)

{

                return DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, (DLGPROC) WndProc);

}

Sous classement: pourquoi et comment

Dansun premier temps, répondons à la question pourquoi! Pour ceci, nous allonsutiliser un exemple.
Nous voulons créer une fenêtre contenant des progressbars. Par un double clicsur une progressbar, nous souhaitons ouvrir un MessageBox contenant en titrel'identifiant de la progressbar et en message, le code de la progressbar.
Avec ce que nous avons vu précédemment, normalement pas de problèmes.
Et bien si! Les progressbars renvoient bien des messages de notification surcertaines actions, mais pas siil s'agit d'un double clic!
Il faut alors spécifier à la progressbar notre propre fonction de traitementdes messages! Allons-nous devoir traiter tous les messages qu'une progressbarpeut recevoir et envoyer?Heureusement que non! Nous allons juste traiter lemessage WM_LBUTTONDBLCLK, et laisseront le reste à traiter par la fonction pardéfaut de traitement des messages d'une progressbar. C'est ce que l'on appelledu sous traitement! Une fonction de gestion des messages en appelle une autre!
Voyons maintenant au travers du code suivant comment mettre en place cettefonction.
Nous allons créer une fenêtre de façon hard, puis une progressbar de façon hardégalement. Cet exemple utilise des notions non encore abordées, comme lestimers, que nous verrons plus loin dans ce cours. Il s'agit en gros d'undécompteur dont on fixe une valeur initiale, et chaque fois qu'il arrive à 0,un message WM_TIMER intervient.

#pragma comment(lib, "comctl32.lib")        //Inclusion de la librairie pour la progressbar

 
#include <windows.h>

#include <commctrl.h>    //Pour les progress bars

#include <resource.h>



#define  WM_GETDEFAULTID                      WM_USER
LONG ProgressProc(HWND hwnd, UINT message, WPARAM wParam, LPARAMlParam)

{

                static WNDPROC DefProgressProc;

                switch(message)

                {

                case WM_LBUTTONDBLCLK:

                               {

                                               char titre[20], msg[20];

                                               sprintf(titre,"ID:%i", GetWindowLong(hwnd, GWL_ID));

                                               sprintf(msg, "Handle:0x%x", hwnd);

                                               MessageBox(NULL,msg, titre, MB_OK);

                                               return TRUE;

                               }
                Case WM_GETDEFAULTID:

                               DefProgressProc= (WNDPROC) wParam;

                               return TRUE;
                default:

                               return CallWindowProc(DefProgressProc, hwnd, message, wParam, lParam);

                }

}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam,LPARAM lParam)

{

                static HWND hProgress;
                switch(message)

                {

                case WM_CREATE:

                               {

                                               INITCOMMONCONTROLSEX InitCtrlEx;

                                               WNDPROC DefProgressProc;

                                               InitCtrlEx.dwSize= sizeof(INITCOMMONCONTROLSEX);

                                               InitCtrlEx.dwICC  = ICC_PROGRESS_CLASS;

                                               if(!InitCommonControlsEx(&InitCtrlEx))

                                                               PostQuitMessage(1);

                                               hProgress= CreateWindow(PROGRESS_CLASS, NULL, WS_CHILD | WS_VISIBLE

                                                                                  | PBS_SMOOTH , 10, 10, 100, 100, hwnd, NULL, 0, NULL);

                                               SetClassLong(hProgress,GCL_STYLE, GetClassLong(hProgress, GCL_STYLE) | CS_DBLCLKS);

                                               DefProgressProc= (WNDPROC) SetWindowLong(hProgress, GWL_WNDPROC,(LONG) ProgressProc);

                                               SendMessage(hProgress,WM_GETDEFAULTID, (WPARAM) DefProgressProc, 0);

                                               SendMessage(hProgress,PBM_SETRANGE, 0, MAKELPARAM(0, 100));

                                               SendMessage(hProgress,PBM_SETSTEP, (LPARAM) 1, 0);

                                               SetTimer(hwnd,0x10, 100, NULL);

                                               ShowWindow(hwnd,SW_SHOW);

                                               SetForegroundWindow(hwnd);

                                               returnTRUE;

                               }
                case WM_TIMER:

                               {

                                               int pos;

                                               pos= SendMessage(hProgress, PBM_GETPOS, 0, 0);

                                               if(pos >= 100)  pos= 0;

                                               SendMessage(hProgress,PBM_SETPOS, ++pos, 0);

                                               return TRUE;

                               }
                case WM_CLOSE:

                               DestroyWindow(hwnd);

                               return TRUE;
                case WM_DESTROY:

                               KillTimer(hwnd,0x10);

                               PostQuitMessage(0);

                               return TRUE;
                default:

                               return DefWindowProc(hwnd, message, wParam, lParam);

                }

}
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
                MSG msg;

                HWND Dlg;

                WNDCLASSEXconfig;
                config.cbSize= sizeof(WNDCLASSEX);

                config.style= CS_HREDRAW | CS_VREDRAW;

                config.lpfnWndProc= WndProc;

                config.cbClsExtra= 0;

                config.cbWndExtra= 0;

                config.hInstance= hInstance;

                config.hIcon= NULL;

                config.hCursor= LoadCursor(NULL, IDC_ARROW);

                config.hbrBackground= (HBRUSH) COLOR_APPWORKSPACE + 1;

                config.lpszClassName= "My Test Window";

                config.lpszMenuName= NULL;

                config.hIconSm= NULL;
                if (!RegisterClassEx(&config))

                               exit(-1);
                Dlg =CreateWindow (config.lpszClassName, "Test", WS_OVERLAPPEDWINDOW, 0,0, 200, 200, NULL, NULL, hInstance, NULL);

                if (!Dlg)

                               exit(-1);

                while(GetMessage(&msg, NULL, 0, 0))

                {

                        TranslateMessage(&msg);

                        DispatchMessage(&msg);

                }

                return msg.wParam;

}

Reprenonscalmement cet exemple!Pas d'affolement, ce n'est pas si compliqué que ça!
Tout d'abord la fonction WinMain. Rien de bien dur, on crée une fenêtrede façon classique. La fonction RegisterClassEx(…)permet justed'enregistrer la classe de fenêtre que l'on vient de créer. En cas d'échec, onquitte le programme.
Dans la fonction CreateWindow, le style WS_OVERLAPPEDWINDOWpermet de créer une fenêtre des plus classiques (titre, menu système,bordure…).
Si on n'a pas réussi à créer la fenêtre on quitte le programme.

Ensuite,voyons la fonction WndProc. Là, ça se complique un peu.
Etudions pour commencer le traitement du message WM_CREATE. A la création de lafenêtre, nous commençons par créer une progressbar (n'oublions que c'est uncomposant complexe, et qu'il faut donc initialiser la dll). Ensuite, nousmettons le style étendu CS_DBLCLKS  à cette progressbar à l'aide dela fonction SetClassLong. C'est ensuite que l'on fait le sousclassement.
A ce moment la, la progressbar à encore sa fonction de traitement des messagespar défaut.
Avec la fonction SetWindowLong et en lui donnant le paramètre GWL_WNDPROC,on change cette fonction de traitement des messages. Il faut savoir (en allantdans MSDN)que dans ces conditions, SetWindowLongrenvoie l'anciennevaleur de la fonction de traitement des messages. Donc on vient de récupérerdans DefProgressProc la valeur de la fonction de traitement des messagespar défaut d'une progressbar. On s'empresse de l'envoyer à la fonction detraitement des messages des progressbars que l'on acréée pour la sauvegarder.
Nous reviendrons là-dessus par la suite.

Dansle reste du message WM_CREATE, on initialise la progressbar(intervalle,pas d'incrément) et le timer (100ms entre chaque message WM_TIMER), eton affiche notre fenêtre.
Dans le message WM_TIMER, on ne fait qu'augmenter la position de laprogressbar, et quand on est rendu à la fin de la progressbar,on repart de 0.
Avant de continuer avec la fonction ProgressProc, une petite explication sur le

               #define WM_GETDEFAULTID                        WM_USER

Avecl'API, on a la possibilité de créer nos propres messages. Leur identifiantparte de la valeur WM_USER(0x0400) jusqu'à la valeur 0x7fff. Ces messagesrespectent la même casse que les messages systèmes, c'est-à-dire un identifiantet deux paramètres.
Dans notre cas, nous nous servons de ce message pour envoyer à la fonctionProgressProc la valeur de la fonction de traitement des messages desprogressbars par défaut, et nous mettons cette donnée dans le paramètre wParam.
Maintenant la fonction la plus intéressante, notre fonction de traitement desmessages, la fonction ProgressProc.
En fait rien de bien particulier!Lorsqu'elle détecte un double clic de sourissur la progressbar elle affiche un MessageBox, sinon elle appelle la fonctionde traitement par défaut. Ainsi quand la progressbar reçoit le message PBM_SETPOS,elle regarde s'il s'agit du message WM_LBUTTONDBLCLK et commence n'estpas le cas, elle transfert le message à la fonction par défaut.
Si vous n'avez pas compris, le jour ou vous en aurez besoin, vous comprendrez!Il faut rencontrer le problème pour se rendre compte de l'intérêt.

Le dessin sur une fenêtre

Dansce chapitre, pas de long discours théorique, mais du code, encore du codetoujours du code!
Rien ne sert de déblatérez sur le sujet, tant de livres en parle, alors nousallons faire des exemples!

Le Device Context

Uncontexte d'affichage (DC) identifie une zone dans laquelle l'application peutafficher tous types de données. Pour récupérer un DC, on peut utiliser lafonction GetDC(hwnd). Si le paramètre fournit est NULL, GetDCrenvoie un DC sur la totalité de l'écran. Lorsque l'on modifie une propriété duDC, on dit que l'on sélectionne un objet dans le DC, cela se fait parl'intermédiaire de la fonction SelectObject(…). Différents typesd'objets peuvent être saisis dans un DC (police, image, pinceaux de dessin…)Les DC sont représentés par des HDC (Handle to Device Context)
Ainsi, pour dessiner sur une fenêtre, vous devez récupérer un HDC sur lafenêtre avec la fonction GetDC, puis dessiner dessus à l'aide desfonctions GDI (Graphic Device Interface) comme BitBlt pour coller desbitmaps, TextOutpour dessiner du texte ou encore LineTo pourtracer des lignes.

Anoter qu'il vaut mieux utiliser BeginPaint dans le cas d'un WM_PAINT que GetDCpour récupérer le DC.

Les bitmaps

  • Chargement d'un bitmap: LoadImage
HBITMAP BITMAPLoad(HINSTANCE hInst, LPCTSTR bitmap, BOOLINRESOURCE, BOOL TRANSP)

{

                unsigned int type = LR_CREATEDIBSECTION | LR_LOADMAP3DCOLORS;

 
                if(!INRESOURCE)

                               type|= LR_LOADFROMFILE;

                if (TRANSP)

                               type|= LR_LOADTRANSPARENT;

                return (HBITMAP) LoadImage(hInst, bitmap, IMAGE_BITMAP, 0, 0, type);

}

UnHBITMAP est un code sur un bitmap, en résumé, c'est un pointeur sur une zonemémoire qui contient les données du bitmap.
La fonction donnée permet donc de charger un bitmap soit à partir d'uneressource, soit à partir d'un fichier*.bmp se situant sur votre disque.

Appel 1:         hBmp = BITMAPLoad(hInst, MAKEINTRESOURCE(IDB_BITMAP1), TRUE, TRUE);
Appel 2:          hBmp =BITMAPLoad(hInst, "monbitmap.bmp", FALSE, TRUE);


  • Affichage d'un bitmap sur un HDC: BitBlt; BeginPaint; SelectObject…
BOOL BITMAPDraw(HWND hWindow, HINSTANCE hInst, LPCTSTR imagename,int xdest, int ydest, int xsrc,

                                    int ysrc,int width, int heigth, BOOL INRESOURCE, BOOL TRANSPARENCE)

{

                HDC hDC,MemDCExercising;

                PAINTSTRUCT Ps;

                HBITMAP bmpExercising;

                BOOL ret;



                hDC =BeginPaint(hWindow, &Ps);

                // Chargement du bitmap

                if (NULL ==(bmpExercising = BITMAPLoad(hInst, imagename, INRESOURCE, TRANSPARENCE)))

                               return FALSE;

                // Création d'un DC compatible avec le précédent

                if (NULL ==(MemDCExercising = CreateCompatibleDC(hDC)))

                               return FALSE;

                 // Sélection du bitmap

                 SelectObject(MemDCExercising, bmpExercising);

                //Copie les bits du DC en mémoire vers le DC courant

                ret =BitBlt(hDC, xdest, ydest, width, heigth, MemDCExercising, xsrc, ysrc, SRCCOPY);

                // Suppressiondes données temporaires

                DeleteDC(MemDCExercising);

                DeleteObject(bmpExercising);

                EndPaint(hWindow,&Ps);

                DeleteDC(hDC);

                return ret;

}

Commentcela se fait-il? Nous créons une surface sur laquelle on peut dessiner surtoute la surface de notre application à l'aide de la fonction BeginPaint.Ensuite on charge le bitmap avec la fonction vue précédemment,et on le met surune surface temporaire avec la fonction SelectObject. Pourquoi fait-onça? La réponse est simple, on ne veut pas forcément charger tout le bitmap, ouon veut le mettre à un endroit précis sur le HDC, or la fonction SelectObjectlemet en (0, 0). Aussi, avec la fonction BitBlt, nous sélectionnons lapartie du HDC temporaire que nous voulons garder et nous la collons à l'endroitoù nous le souhaitons sur le HDC de notre fenêtre.
Avant de boucler cette partie, une petite explication sur la structure PAINTSTRUCTetla fonction BeginPaint. PAINTSTRUCT est une structure qui contientdes informations à propos de la fenêtre qui va être repeinte. BeginPaintpermet de sélectionner la totalité de la fenêtre sur laquelle on veut dessiner.La fonction EndPaint maque la fin du dessin, son appel est OBLIGATOIREaprès un appel à BeginPaint.

Ily a possibilité d'agrandir ou de rétrécir le bitmap en utilisant la fonction StretchBltà la place de BitBlt.

  • Affichage d'un bitmap dans un staticbox:
void BITMAPSetInStatic(HWND hstatic, HBITMAP bitmap)

{

                SendMessage(hstatic,STM_SETIMAGE, IMAGE_BITMAP, (LPARAM) bitmap);

}

Poureffectuer cette opération, on utilise un des messages spécifiques desstaticbox. Avec cette méthode, on peut se passer des HDC pour afficher desimages dans une fenêtre. On ne peut pas travailler sur le bitmap, mais onarrive à l'afficher où on veut tant que l'on met le staticbox là où il fautafficher le bitmap.

  • Affichage d'un bitmap sur un bouton:
BOOL BOUTONSetBitmape(HWND button, HBITMAP hBitmap)

{

                if (hBitmap== NULL)

                               returnFALSE;

                SendMessage(button,BM_SETIMAGE, TYPE, (LPARAM)(HANDLE) hBitmap);

                return TRUE;

}

Commedans l'exemple précédent, utilisation des messages spécifiques au bouton pourafficher une image sur le bouton.

Les polices

  • Création d'une police: CreateFont

Lafonction CreateFont() crée une police selon les caractéristiquesspécifiées en arguments. Cette police doit ensuite être sélectionnée par SelectObject()pour devenir la fontecourante du contexte d'affichage.

HFONT MaPolice; 
MaPolice = CreateFont(20, 10, 0, 0, 800 ,FALSE, FALSE, FALSE, 0, OUT_DEFAULT_PRECIS,

                                       CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH |

                                       FF_DONTCARE,"Arial");
  • Ecriture sur DC avec la police: TextOut; SetTextAlign
BOOL DCWriteString(HDC hDc, HFONT police, char *string, int xpos,in typos)

{

        SelectObject(hDc, police);

        SetTextAlign(hDc, TA_BASELINE | TA_LEFT);

        return TextOut(hDc, xpos, ypos , string, lstrlen(string));

}

Dansun premier temps, on associe la police au contexte d'affichage, puis on définitl'alignement du texte et on écrit le texte. Avec TextOut on spécifie unpoint d'ancrage du texte, avec SetTextAlign,on dit à quoi correspond lepoint d'ancrage (ici c'est le coin en haut à gauche du texte)

Les pinceaux et les crayons

  • Création d'un pinceau et d'un crayon: Create(Hatch)Brush; CreatePen
HBRUSH hBrush1 = CreateHatchBrush(HS_DIAGCROSS, 0x00FF5050);

HBRUSH hBush2 = CreateSolidBrush(0x00FFBB00);

HPEN hPen= CreatePen(PS_SOLID, 1, 0x00FF0000);

Cestrois fonctions permettent de créer respectivement:

*Un pinceau qui dessine de façon hachurée, avec la possibilité de définir lahachure et la couleur
* Un pinceau plein pour lequel on peut définir une couleur.
*Un crayon dont on peut régler le type de trait (plein, pointillé…), l'épaisseuret la couleur

Pourdéfinir la couleur, il y a deux possibilités. On peut utiliser la notation d'unCOLORREF qui est: 0x00RRGGBB, ou une macro qui convertira en COLORREFpar la suite: RGB(RR,BB,GG)

  • Colorier une surface avec un pinceau: FillRect; FillRgn; Ellipse; Polygon…
FillRect(hDc,&Rect,hBrush);

FillRgn(hDc,&Rgn,hBrush);

Cesdeux fonctions remplissent respectivement un rectangle ou une région avec lepinceau que l'on a sélectionné. Pour ces deux instructions, pas besoin deSelectObject.

Parcontre, il est également possible de créer des surfaces plus "libres"à l'aide des fonctions Ellipse et Polygon. Pour remplir cessurfaces, il faut avant tout sélectionner les pinceaux et les crayons àutiliser avec SelectObject. Le pinceau servira à remplir l'intérieur dela surface ainsi créée, et le crayon en fera le tour. On peut créer plusieurssurfaces sur un HDC en utilisant plusieurs fois ces fonctions.

  • Tracer des traits: MoveTo; LineTo; PolyBezier; ArcTo; PolylineTo…

Avecla fonction MoveTo, on sélectionne un point de départ pour notre trait, puisselon la fonction utiliser, on peut tracer des lignes droites, courbes, desarcs de cercle…
Avant de tracer le trait, il faut sélectionner le crayon à utiliser avec SelectObject.(Je sais je me répète, mais ça ne fait pas de mal!)

Les Timers

Alors,là, juste un petit chapitre pour expliquer le fonctionnement d'un composantfort sympathique si l'on veut créer des actions qui se répètent à intervalle detemps régulier.

Création d'un timer

SetTimer(hwnd, ID, time, callbackfunc);

Unepetite ligne de code et ça y est, on a notre timer, n'est-ce pas magique toutça?

Bon,je vous dois quand même quelques explications. Tout d'abord, il faut se rendrecompte que lorsque l'on crée un timer, il faut que celui ne communique qu'avecnotre application, pas avec les autres, d'où la nécessité de lui donner enparamètre le code de notre fenêtre (car rappelez-vous, ce code est unique!).Ensuite, il y a la possibilité de créer plusieurs timers pour une seule et mêmeapplication, donc il faut pouvoir les identifier (ceci est fait parl'intermédiaire d'un identifiant). Et comment spécifions-nous le tempsd'attente du timer? Et bien en le donnant en paramètre. Attention, il est ànoter que time s'exprime en millisecondes.
Reste le dernier paramètre. Ilest possible de définir notre propre fonction detraitements des messages pour les messages émanant d'un timer. Si ce paramètreest à NULL, le timer enverra le message WM_TIMER à la fonction de traitementdes messages de la fenêtre. Ne vous inquiétez pas, nous verrons un exemple plusloin dans ce chapitre.

Destruction d'un timer

Toutcela est bien beau, mais moi j'ai besoin de créer un timer que je peux arrêterpar un clic sur un bouton, ou que sais-je encore comme action.
La fonction suivante fera alors votre bonheur. De toute façon, lorsque vousquittez votre programme, il faut détruire le timer, donc vous devrez utilisercette instruction dans le WM_DESTROY ou WM_QUIT de votre appli.

KillTimer(hwnd, ID);

Riende bien sorcier, juste préciser le code de votre fenêtre et l'identifiant devotre timer.
Attention cependant, cette fonction ne supprime pas les messages WM_TIMER enattente dans la liste des messages à traiter.

Un petit exemple

Ci-dessous,un peu de code. Dan sune ressource, nous créons 3 boutons (IDOK, IDCANCEL etIDSTOP), un combobox(IDC_COMBOTIME) et une progressbar (IDC_PROGRESS).
On souhaite remplir la progressbar par intervalle de temps régulier(utilisation de timer). Cet intervalle de temps sera choisi à partir d'uncombobox. Lorsque l'on changera la valeur de la progressbar, on en changeraaussi la couleur.
Cet exemple montrera donc l'utilisation des timers, des boutons, des combos etdes progressbar, aussi essayez de bien le comprendre.

 #pragma comment(lib,"comctl32.lib")

 
#include <windows.h>

#include <commctrl.h>

#include <time.h>

#include "resource.h"



#define IDTIMER                               0x10

#define MIN_PROGRESS                 0

#define MAX_PROGRESS                1000
//Ajout d'une chaine de caractère dans un combobox

BOOL COMBOSetValue(HWND hCombo, char *value)

{

                unsignedlong error;



                //Envoi du message d'ajout d'une chaine au combo

                error =SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR) value);

                if (error ==CB_ERR || error == CB_ERRSPACE)

                {

                               MessageBox(NULL,"Impossible d'ajouter du texte au combobox", "Erreur",MB_OK |MB_ICONERROR);

                               return FALSE;

                }

                return TRUE;

}
//Récupération de l'index d'une chaine (CB_ERR si la chaine n'est pas trouvée)

unsigned long COMBOGetStringIndex(HWND hCombo, char *chaine)

{

                return SendMessage(hCombo, CB_FINDSTRINGEXACT, -1, (LPARAM)(LPCTSTR) chaine);

}



//Pour sélectionner une valeur dans le combo

int COMBOSetInitialValue(BOOL ISVALUEANINDEX, HWND hCombo,unsigned long index, char *nom)

{

                if(!ISVALUEANINDEX)

                               index= COMBOGetStringIndex(hCombo, nom);

                return SendMessage(hCombo, CB_SETCURSEL, index, 0);

}
//Récupère l'index de l'item sélectionné dans un combobox

unsigned long COMBOGetIndexSelectedItem(HWND hCombo)

{

                return SendMessage(hCombo, CB_GETCURSEL, 0, 0);

}
//Récupère la taille de l'item sélectionné

unsigned long COMBOGetLenIndex(HWND hCombo, unsigned long index)

{

                return SendMessage(hCombo, CB_GETLBTEXTLEN, index, 0);

}
//Récupère le texte de l'item sélectionné
char* COMBOGetStringFromIndex(HWND hCombo, unsigned long index)
{

                char* buffer;



                buffer =(char*) malloc((1 + COMBOGetLenIndex(hCombo, index)) * sizeof(char));

                SendMessage(hCombo,CB_GETLBTEXT, index, (LPARAM)(LPCTSTR) buffer);

                return strdup(buffer);

}
//Définit l'intervalle d'une progressbar

int PROGRESSSetRange(HWND hProgress, int minimum, int maximum)

{

                return SendMessage(hProgress, PBM_SETRANGE, 0, MAKELPARAM(minimum, maximum));

}



//Définit la position dans la progressbar

int PROGRESSSetPos(HWND hProgress, int pos)

{

                return SendMessage(hProgress, PBM_SETPOS, pos, 0);

}



//Récupère la position dans une progressbar

int PROGRESSGetPos(HWND hProgress)

{

                return SendMessage(hProgress, PBM_GETPOS, 0, 0);

}
//Met la progressbar de la couleur donnée

int PROGRESSSetColor(HWND hProgress, COLORREF color)

{

                return SendMessage(hProgress, PBM_SETBARCOLOR, 0, (LPARAM) (COLORREF) color);

}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam,LPARAM lParam)

{

                switch(message)

                {

                //A la creation de la fenetre

                case WM_INITDIALOG:

                               {

                                               INITCOMMONCONTROLSEX InitCtrlEx;

                                               const char *datatime[] = {"10", "100", "1000","10000"};

                                               int i;

                                               time_t date;



                                               time(&date);

                                               srand(date);

                                               for(i = 0; i < 4;i++)

                                                               COMBOSetValue(GetDlgItem(hwnd,IDC_COMBOTIME), (char*) datatime[i]);

                                               COMBOSetInitialValue(TRUE,GetDlgItem(hwnd, IDC_COMBOTIME), 0, NULL);

                                               InitCtrlEx.dwSize= sizeof(INITCOMMONCONTROLSEX);

                                               InitCtrlEx.dwICC  = ICC_PROGRESS_CLASS;

                                               if(!InitCommonControlsEx(&InitCtrlEx))

                                                               PostQuitMessage(1);

                                               PROGRESSSetRange(GetDlgItem(hwnd,IDC_PROGRESS), MIN_PROGRESS, MAX_PROGRESS);

                                               PROGRESSSetPos(GetDlgItem(hwnd,IDC_PROGRESS), MIN_PROGRESS);

                                               ShowWindow(hwnd,SW_SHOW);

                                               SetForegroundWindow(hwnd);

                                               returnTRUE;

                               }
 
                case WM_COMMAND:

                               {

                                               switch(LOWORD(wParam)) //LOWORD(wParam)) contient l'ID du contrôle

                                               {

                                               case IDOK:

                                                               {

                                                                              char* buffer;

                                                                              unsigned int timer;



                                                                             //Récupération de la chaîne du combo

                                                                              buffer= COMBOGetStringFromIndex(GetDlgItem(hwnd,IDC_COMBOTIME),

                                                                                                                    COMBOGetIndexSelectedItem(GetDlgItem(hwnd,IDC_COMBOTIME)));

                                                                              timer= (unsigned int) atoi(buffer);

                                                                             //Suppression de l'ancien TIMER puis création du nouveau

                                                                              KillTimer(hwnd,IDTIMER);

                                                                              SetTimer(hwnd,IDTIMER, timer, NULL);

                                                                              free(buffer);

                                                                              return TRUE;

                                                               }
                                               case IDSTOP:

                                                               KillTimer(hwnd,IDTIMER);

                                                               return TRUE;
                                               case IDCANCEL:

                                                               SendMessage(hwnd,WM_DESTROY, 0, 0);

                                                               return TRUE;
                                               default:

                                                               return 0;

                                               }

                               }
                case WM_TIMER:

                               {

                                               unsigned long pos;
                                              //Récupération de la position dans la progressbar

                                               pos= PROGRESSGetPos(GetDlgItem(hwnd, IDC_PROGRESS));

                                               if(pos == MAX_PROGRESS)

                                                              pos =MIN_PROGRESS;

                                               PROGRESSSetColor(GetDlgItem(hwnd,IDC_PROGRESS), RGB(rand() % 0x100,rand() % 0x100, rand() % 0x100));

                                              //Nouvelle position = Ancienne position + 1

                                               PROGRESSSetPos(GetDlgItem(hwnd,IDC_PROGRESS), ++pos);

                                               return TRUE;

                               }
                Case WM_CLOSE:

                               DestroyWindow(hwnd);

                               return TRUE;
                Case WM_DESTROY:

                               KillTimer(hwnd,0x10); //Ne pas oublier de killer le timer en quittant

                               PostQuitMessage(0);

                               return TRUE;
                default:

                               return 0;

                }

}

 intAPIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevinstance, LPSTR lpCmdLine,int nCmdShow)
{
               return DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, WndProc);
}

Nousne regarderons pas les différentes fonctions pour gérer le combobox et laprogressbar, une recherche rapide dans MSDN sur le nom du message que l'onenvoie vous fournira toutes les explications nécessaires.
Non, nous nous allons regarder les actions effectuer par les boutonsd'identifiant IDOK et IDSTOP.
Le bouton IDOK permet de créer un timer à un intervalle de temps régulier. Nepas oublier de supprimer le précédent timer si on n'est pas passé par le boutonstop, sinon, nous ne verrons aucune différence i nous passons d'un timer rapideà un timer court,l'ancien timer continuant de s'exécuter.
Pour arrêter un timer lors de l'appui sur le bouton IDSTOP, il n'y a qu'à tuerce timer.
Le reste du code n'est que de la mise en forme pour vous montrer ce qu'il estpossible de réaliser.

Les menus

Ilexiste deux types de menus. Les menus que nous allons dire"classiques" qui se trouvent sous la barre de titre de l'applicationet les menus pop up qui sont affichables par exemple lors d'un clic droit avecla souris.
Dans ces menus, certains items peuvent être grisés, d'autre peuvent êtremarqués d'un petit "v" devant pour indiquer un état.
Mais comment cela fonctionne-t-il?

Les menus que nous utiliseront par la suite seront créés à partird'une ressource, mais il faut savoir qu'il y a moyen des programmer manuellement.

La création

Deuxfaçons de créer un menu existent.
La première façon consiste lors d'une création en hard à spécifier à la classede la fenêtre qu'elle a un menu, et de lui dire quel menu elle doit afficher enlui fournissant un identifiant.
Pour cela, il faut renseigner le champ lpszMenuName de la structure WNDCLASSEX.

                WNDCLASSEX    config;

               
                config.cbSize= sizeof(WNDCLASSEX);

                config.style= CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;

                config.lpfnWndProc= WndProc;

                config.cbClsExtra= 0;

                config.cbWndExtra= 0;

                config.hInstance= hInstance;

                config.hIcon= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));

                config.hCursor= LoadCursor(NULL, IDC_ARROW);

                config.hbrBackground= (HBRUSH) COLOR_APPWORKSPACE + 1;

                config.lpszClassName= TITREAPPLI;

                config.lpszMenuName= (LPCSTR) IDR_MENU1;

                config.hIconSm= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));

                if(!RegisterClassEx(&config))

                               exit(1);

Ladeuxième méthode revient à utiliser la fonction LoadMenu.
Nous allons donner ci-dessous un exemple permettant de charger un menu pop up àl'endroit où se situe la souris.

                POINT position_souris;

                HMENU hMenu,hMenuPopup;

                DWORD selection



                GetCursorPos(&position_souris);

                hMenu=LoadMenu((HINSTANCE),GetModuleHandle(NULL),MAKEINTRESOURCE(IDR_MENUSYSTRAY));

                //Récupération du code du menu à afficher (on doit afficher le sous-menu du menu principal

                hMenuPopup =GetSubMenu(hMenu, 0);

                if(hMenuPopup == NULL)

                               SendMessage(window,WM_DESTROY, 0, 0);

                //Permet d'éviter un bug windows : si on ne clique sur aucun choix du menu, il s'en va tout seul

                SetForegroundWindow(window);

                selection =TrackPopupMenu(hMenuPopup, TPM_NONOTIFY | TPM_LEFTALIGN |

                                                              TPM_LEFTBUTTON |TPM_RETURNCMD, position_souris.x, position_souris.y, 0, window, NULL);

AvecGetCursorPos, on récupère la position de la souris, puis avec LoadMenu etGetSubMenu, on récupère le menu pop up à afficher. La fonction TrackPopupMenupermet d'afficher le menu et de récupérer l'identifiant du menu cliquer. Par lasuite, dans un switch, il n'y a plus qu'à traiter les différentes valeurspossibles de la valeur retournée.
TrackPopupMenu ne marche que pour les menus pop up, pour un menu classique, onn'a pas besoin de l'appeler, il est déjà présent (si ce n'est pas le cas,utilisé SetMenu après avoir au préalable chargé le menu avec un LoadMenu).

Si on a crée un menu "classique", un clic sur le menu envoieun message WM_COMMAND à l'application, à ce moment la, LOWORD(wParam)contientl'identifiant du contrôle qui a envoyé le message, on peut donc trouver surquel menu on a cliquer par un switch(LOWORD(wParam)).

Activer/désactiver/valider…un élément du menu

Toutesles opérations de modification de l'état d'un menu se font à travers une seulefonction: SetMenuItemInfo. Mais pour pouvoir l'utiliser, il faut comprendre lefonctionnement de la structure MENUITEMINFO.
SetMenuItemInfo permet aussi de rajouter des éléments à un menu.
MENUITEMINFO est relativement simple à comprendre. Voici sa définition (merciMSDN)

typedef struct tagMENUITEMINFO {

    UINT    cbSize;

    UINT    fMask;

    UINT    fType;

    UINT    fState;

    UINT    wID;

    HMENU   hSubMenu;

    HBITMAPhbmpChecked;

    HBITMAPhbmpUnchecked;

    DWORD   dwItemData;

    LPTSTR  dwTypeData;

    UINT    cch;

} MENUITEMINFO, FAR *LPMENUITEMINFO;

Elles'articule principalement autour du champ fMask qui permet de définir leschamps à prendre en compte. Le champ wID permet de définir l'identifiant del'item à modifier.
Imaginons que nous voulions dans le menu précédemment chargé désactivé l'itemd'identifiant ID_ITEM1 si le booléen TEST est à TRUE.

MENUITEMINFO menu; 



menu.cbSize = sizeof(MENUITEMINFO);

menu.fMask = MIIM_STATE;

menu.fState =  TEST ?MFS_ENABLED : MFS_GRAYED;

SetMenuItemInfo(hMenuPopup, ID_DRAW, FALSE, &menu);

Vousvoyez, rien de bien compliqué!

Il est même possible d'accéder au menu système (vous savez, le menuqui apparaît quand vous cliquez droit sur la barre de titre de l'appli)avec lafonction GetSystemMenu et d'en modifier les données ensuite.

Destruction d'un menu

Etoui, comme pour tous les objets, une fois qu'ils sont utilisés, plus besoin deles garder en mémoire. La fonction DestroyMenu permet de les détruire.

Le systray

Cequ'il faut bien comprendre, c'est que le systray n'est qu'une zone danslaquelle on peut afficher des icônes. Ces icônes sont un peu particulières,dans le sens qu'elles peuvent envoyer des messages de notification à votreapplication comme "on m'a cliqué dessus".
Voyons comment cela fonctionne.

Affichage d'une icône dans le systray

Pource faire, il faut correctement initialiser la structure NOTIFYICONDATA, etdemander à l'icône de s'afficher.

#define WM_ICONSYSTRAY            WM_USER 



NOTIFYICONDATA icone; 



icone.cbSize = sizeof(icone);

icone.uID = IDI_ICON1;

icone.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE;

icone.uCallbackMessage = WM_ICONSYSTRAY;

icone.hIcon = LoadIcon(NULL, NULL);

icone.szTip = 'icône dans le systray"';

icone.hWnd = hwnd;

icone.hIcon = LoadIcon((HINSTANCE) GetModuleHandle (NULL),MAKEINTRESOURCE(IDI_ICON1));

Shell_NotifyIcon(NIM_ADD, &icone);

Commevu dans un chapitre précédent, on associe à l'icône un type de message. Quandune action sera effectuée, l'icône enverra à notre application le messageWM_ICONSYSTRAY.
On dit également à la structure quelle icône utiliser, et on la lui associe.
La fonction Shell_NotifyIcon est utilisée lors du dialogue application vers icônedu systray.
On peut donc ajouter une icône, modifier une icône, où supprimer une icône aveccette fonction.

Modification de l'icône du systray:

Celase fait de la même façon que pour la créer, à la seule différence près qu'aulieu de passer le paramètre NIM_ADD à la fonction Shell_IconNotify, on luidonne le paramètre NIM_MODIFY. On peut donc tout modifier (icône, tooltip,fonction de traitement…)

icone.hIcon = LoadIcon((HINSTANCE) GetModuleHandle (NULL),MAKEINTRESOURCE(IDI_ICON2));

Shell_NotifyIcon(NIM_MODIFY, &icone);

Suppression d'une icône du systray

Vousdevez vous en doutez maintenant, on procède encore de la même façon. Cettefois-ci, nous utiliserons le paramètre NIM_DELETE avec la fonctionShell_NotifyIcon. N'oubliez pas de supprimer votre icône lorsque vous quittezvotre application.

Les accélérateurs de clavier

Alorscomment faire ces raccourcis claviers?
La encore, nous ne nous baserons que sur des ressources, même si il estpossible de les programmer manuellement. Mais la encore, d'un point de vuepurement personnel, je dirais que c'est une perte de temps!

HACCEL hAccelTable;

hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDR_ACCELERATOR1);

Engros, on crée un nouvel objet de type accélérateur de table, et on le chargeavec LoadAccelerators.
A chaque raccourci clavier que vous créez, vous associer l'identifiant d'unmenu ou d'un bouton, donc lorsque vous utilisez le raccourci que vous venez decréer, vous recevrez le même message que si l'utilisateur avait cliqué survotre menu ou votre bouton.
Pour supprimer un accélérateur de table, utiliser la fonction DestroyAcceleratorTable.
Vous voyez, rien de bien extraordinaire, voir même plutôt trop simple! Ce n'estpas marrant de n'avoir rien à faire! J

Un peu de code

Danscette partie, pas d'explication, juste des fonctions qui peuvent vous êtreutiles!

Eteindre votre ordinateur

void StopComputer(void)

{

                HANDLE hToken;

                TOKEN_PRIVILEGES tkp;



                OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);

                LookupPrivilegeValue(NULL,SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid);

                tkp.PrivilegeCount= 1; 

                tkp.Privileges[0].Attributes= SE_PRIVILEGE_ENABLED;

                AdjustTokenPrivileges(hToken,FALSE, &tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0);

                ExitWindowsEx(EWX_POWEROFF| EWX_FORCE, 0);

}

Possibilitéde redémarrez l'ordinateur en mettant EWX_REBOOT dans ExitWindowEx ou de fermerune session en utilisant EWX_LOGOFF.

Ouvrir un fichier avec le programme par défaut

Quandje dis programme par défaut, j'entends le programme qui doit ouvrir ce type defichier.

ShellExecute(NULL, "open"L, "monfichier.doc",NULL, NULL, SW_SHOW);

Récupération de la hauteur de la barre des taches

long GetHeigthTray(BOOL VIEWERROR)

{

                RECT tray;

                HWND hWnd;



                if (NULL ==(hWnd = FindWindow("Shell_TrayWnd", NULL)))

                {

                               if(VIEWERROR)

                                               VoirErreur(GetLastError());

                               return -1;

                }

                if(!GetWindowRect(hWnd, &tray))

                {

                               if(VIEWERROR)

                                               VoirErreur(GetLastError());

                               return -1;

                }

                returntray.bottom - tray.top;

}

Affichage du message d'erreur

void VoirErreur(unsigned long error)

{

                LPVOID lpMsgBuf;
                FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|

                                           FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error,

                                           MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL);

                MessageBox(NULL,(LPCTSTR )lpMsgBuf, "Erreur", MB_OK | MB_ICONERROR);

                LocalFree(lpMsgBuf);

}

Cettefonction est utile quand une fonction échoue, et que l'on peut récupérer lenuméro de l'erreur par un appel à GetLastError(). Si la fonction renvoie uncode d'erreur, c'est indiqué dans MSDN. Un appel classique de cette fonctionest:

VoirErreur(GetLastError());

Récupérer la taille de composant système

Utiliserla fonction GetSystemMetric.
On peut récupérer la taille de l'écran, le nombre de boutons de la souris, lalargeur des bordures de fenêtres, la taille des icônes, si la machine est enréseau…
Pour les différentes possibilités, vois dans MSDN, elles sont trop nombreusespour les expliquer.

 

 Historique

27 janvier 2006 02:58:38 :
Mise à jour de la présentation
27 janvier 2006 03:41:51 :
Suite à je ne sais quoi, la majorité des espaces étaient manquant. J'espere que cette fois ci ce sera mieux.

Commentaires

Commentaire de julienbj le 27/01/2006 03:43:43

Je suis désolé pour la mise en page.
Ca fait deux fois que j'essaie de mettre à jour, mais à chaque fois il manque plein d'espaces dans le texte.
Ce qui fait que de nombreux mots sont collés.
Il est un peu tard pour que je continue de chercher, je verrais ca demain.

Commentaire de wxccxw le 28/01/2006 21:51:21

Joli Joli L'ami !
19/20 !!!!!!!!!!!! Whaoo quel travaille !!
pourrait tu etre plus clair sur les Progresse bar ?
Ciao :) Jean

Commentaire de julienbj le 28/01/2006 23:56:17

Que veux-tu savoir sur les progressbars?
C'est sur leurs créations ou serait-ce au moment ou je parle du sous classement?

Commentaire de wxccxw le 29/01/2006 16:17:41

non enfaite j'ai trouver Merci Beacoup et encore tres tres bon cours complet !

Commentaire de badr07 le 10/08/2006 00:06:39

Pourquoi y a pas une explication sur GetDlgItemText() [Recuperer les valeur d'un ComBobox ou autres...]
C'est comême ça le plus important...
Pourquoi?
Si possible vous pouvez en mettre parce que la je câââle sur cette fonction...
Merci !!!

Commentaire de julienbj le 10/08/2006 12:02:30

Je n'utilise jamais ce genre de fonction. Je travaille toujours avec les différents messages que fournit l'API windows et la fonction SendMessage.
La fonction GetDlgItemText te permet de récupérer le texte associé à un composant ou à une fenetre.
Donc si tu veux récupérer le texte écrit sur un bouton, dans un edit box ou un static box, pas de souci, tu peux l'utiliser.
Mais pour récupérer le texte affiché dans un combobox, ca ne fonctionne pas. Il n'y a pas de texte associé à ce composant. Tu es obligé de passer par les fonctions de l'API windows et la fonction SendMessage (ou SendDlgItemMessage). Si tu veux un example, va voir le code dans la rubrique des timers, il y a des fonctions qui te permettent de récupérer la texte de l'item sélectionné dans un combobox.

Si tu as besoin de plus d'aide, précise ce qui ne marche pas, ou tu bloques...
++

Commentaire de badr07 le 17/08/2006 17:44:59

ok merciç

Commentaire de badr07 le 17/08/2006 17:45:43

Sinon Tres tres tres bon tutorial!
Franchement Bravo!

Commentaire de retaks666 le 18/01/2007 15:20:32

Et bien je mets la note maximale;) chapeau !

Commentaire de _Julien_ le 07/02/2007 23:52:46

Salut.
Est-il possible de faire la même chose dans un dll en C "pur"?
Merci.

Commentaire de julienbj le 08/02/2007 17:21:37

euh...
Tu veux bien expliqué un peu plus ce que tu veux?

Je n'ai mis ici que des morceaux d'exemples de code.
Alors bien sur il est possible de créer une dll pour créer des fenetres...
En C pur, evidemment, il n'y a que du C dans ce tuto.

Alors ben si tu voulais bien expliqué plus ce que tu voulais, je (on) pourrait peut etre plus t'aider.

Commentaire de _Julien_ le 08/02/2007 21:23:37

Bien voila,
je dois ecrire un dll tres simple qui sera lancé par un programme de dessin (type Autocad qui se debrouille d'appeler la fct principale
car elle a un nom spécifique).
Ce dll lance des fonctions contenues dans d'autres dll. Precisement une fct par dll. chaque fct etant une partie
du dessin. Seule la première fct contenue dans le 1er Dll doit afficher une fenêtre pour demander a l'utilisateur d'entrer deux valeurs.
Actuellement je lance un executable avec CreateProcess qui affiche la fenêtre mais je ne peux pas récupérer les valeurs saisies
par l'utilisateur (disons que je n'ai rien trouvé la dessus). De plus si je déplace la fenêtre les traces de la précédente reste.
Pour récupérer les info, j'écris dans un fichier puis je vais le lire a l'instruction suivante. Voila ca me semble
pas très propre comme méthode.
Donc je souhaite lancer dans mon dll principal, une fct d'un dll qui affiche une fenêtre et retourne les deux
valeurs saisies. J'arrive a lancer un MessageBox mais dès qu'il faut spécifier l'Instance je suis perdu! Je ne sais pas qu'elle
fct lancer, la fonction qui sert de point d'entrée? (qui serait l'équivalent de WinMain mais pour un dll?)

Voila Merci d'avance.

Commentaire de Altau le 03/03/2007 11:02:34

Bonjour et merci pour ce beau travail,

Je cherche un éditeur de ressources simple pour utiliser avec dev-cpp. Que me conseillez-vous ?

Commentaire de kiki67100 le 12/04/2007 21:27:05

Merci pour se tuto vraiment bien !!!!

9/10 rien nais parfait!

sincerement BRAVOO!!!

Kevin

Commentaire de biduletrucmachin le 14/05/2007 22:38:53

Salut moi j'ai un problème pour la création d'un bouton... alors j'ai les erreurs suivantes :

In function 'int winMain(HINSTANCE__*,HINSTANCE__*,CHAR*,int)':
'BOUTONVISIBLE' undeclared(first use this function)
(Each undeclared identifier is reported only once for each function it appears in.)

Les 2 librairies que j'ai inclues sont :
#include <windows.h>
#include <commctrl.h>

et donc je sais pas si le problème vient de là ou pas.
Est ce que quelqu'un aurait de l'aide ou des conseils à me donner ou est que quelqu'un pourrait me donner un code
déja tout fait et qui marche? Je pourrais ainsi le comparer avec mon code et essayer de comprendre pourequoi ça ne va pas chez moi
NB :  Je sais pas si ça joue un rôle je travaille sur Dev-C++

Merci d'avance

Commentaire de julienbj le 15/05/2007 11:51:05

Salut BiduleTrucMachin (original comme pseudo....)
Il y a dans ce tuto des références à des petites fonctions que j'ai développée et qui ne sont pas dispo sur ce site.
Récupère ce fichier zip, il contient l'intégralité du tuto:
http://baronju.free.fr/Documentation/Informatique/Windows/API/mon%20tuto%20sur%20l'api%20c.zip

Commentaire de GroDouDou le 16/01/2008 07:47:40

Bonjour Julien ...

Bel article pour qui veut se lancer dans les arcanes du C et consors ; merci pour ce travail ...

J'ai essayé de récupérer le Zip que tu évoques dans le message précédant mais je reçois un message d'erreur ; le fichier Zip est-il toujours dispo et où puis-je le télécharger ?

Cordialement

Commentaire de julienbj le 21/01/2008 11:19:12

Nouveau lien vers le fichier zip (susceptible de changer dans les mois à venir, je fais une refonte de mes dossiers)
http://baronju.free.fr/Misc/Documentation/Informatique/Windows/API/mon%20tuto%20sur%20l'api%20c.zip

Commentaire de kodioro le 12/03/2008 11:33:06

salut
je suis tres content de la maniere dont vous travaillez, en effet je suis un debutant dans
la programme et j'aimerai avoir des conseil pour m'orienter dans l'attitude à tenir.
je vx developper sur VB.net et le c .je sais pas pour où commener
aider moi!

Commentaire de FloWeRvIncube le 02/04/2008 09:34:10

Merci mec , sympa ce que tu as fais.

Commentaire de Idefix57 le 13/03/2009 22:18:01

Super beau travail , merci
Je ne suis qu'un débutant
mais je suis sur que ce cour me serviras

Merci beaucoup ;-)

 Ajouter un commentaire




Nos sponsors


Sondage...

Comparez les prix

CalendriCode

Février 2012
LMMJVSD
  12345
6789101112
13141516171819
20212223242526
272829    

Consulter la suite du CalendriCode

Photothèque

 
Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils.
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés

Google Coop CodeS-SourceS Google Coop CodeS-SourceS
Temps d'éxécution de la page : 0,250 sec (3)

Nous contacter | Annoncer sur CodeS-SourceS | Mentions légales