14
ALLER PLUS LOIN AVEC DELPHI 6 Support de formation

97118059 Aller Plus Loin Avec Delphi 6

Embed Size (px)

Citation preview

Page 1: 97118059 Aller Plus Loin Avec Delphi 6

ALLER PLUS LOINAVEC DELPHI 6

Support de formation

Page 2: 97118059 Aller Plus Loin Avec Delphi 6

Aller plus loin avec Delphi 6

1. Les API (Application Program Interface) Windows

Pour aller plus loin dans la programmation fenêtrée, il faut s'intéresser au cœur même de Windows. Il existe des bibliothèques de procédures et de fonctions fournies à l'utilisateur sous forme de DLL afin de réaliser les tâches de programmation les plus pointues (par exemple l'attaque d'un modem sur un port série).

Les outils graphiques se trouvent au sein du GDI (Graphic Device Independance). Ce système est indépendant de l'écran ou de l'imprimante connectés.

Delphi met à notre disposition ces méthodes "bas niveau" en incluant les prototypes de celles-ci dans l'unité "Windows".

1.1 La notion de "handle"Nous avons bien compris que l'essentiel de notre travail se fait sur les classes qui

comportent l'ensemble des définitions des propriétés et des méthodes. Une classe peut générer des objets au cours d'une opération de création. Lorsque l'objet est créé, la méthode de création réserve la mémoire nécessaire pour "loger" l'objet. Pour manipuler l'objet, il faut connaître son adresse: c'est le rôle des "Handle" ou poignées (16384 max.) qui sont des pointeurs contenant l'adresse de celui-ci.

Ces pointeurs sont utiles pour manipuler tous types d'objets Windows:• visuels: fenêtres, barres d'outils et de menus, boutons, listes, …• graphiques (GDI): bitmaps, stylos, brosses, …• systèmes (kernel): processus et traitements, communications, fichiers, …

© Maurice GINDENSPERGER (V 6.0) page 2/14

Page 3: 97118059 Aller Plus Loin Avec Delphi 6

Aller plus loin avec Delphi 6

1.2 Exemple d'utilisation: tracé d'un carréprocedure TForm1.Button1Click(Sender: TObject);varPoignee: THandle;Contexte:HDC;begin

Poignee:=Form1.Handle;Contexte:=GetDC(Poignee);Rectangle(Contexte, 10, 10, 400, 400);ReleaseDC(Poignee,Contexte);

end;

Puisque nous utilisons les fonctions du GDI, il nous faut une poignée supplémentaire (de type HDC), appelée contexte de dispositif. En effet, ceci permet d'indiquer au système où nous allons dessiner (écran, imprimante, …).

© Maurice GINDENSPERGER (V 6.0) page 3/14

Page 4: 97118059 Aller Plus Loin Avec Delphi 6

Aller plus loin avec Delphi 6

2. MULTITRAITEMENT

2.1 Le problème du système multitâches

Windows est un système d'exploitation multitâches, c'est à dire que plusieurs programmes (tâches) peuvent être exécutées simultanément. Pourtant, ce système d'exploitation n'est pas préemptif , c'est à dire qu'une application peut mobiliser le processeur à temps complet. Il est donc indispensable d'ajouter des lignes de code dans nos applications pour éviter ce phénomène, particulièrement embarrassant dans l'exécution des boucles(ex: Application.ProcessMessages).

Chaque fois que nous exécutons une application standard, une tâche est crée. Windows réserve une zone de mémoire (4Go. virtuels) pour ses besoins. D'autre part la tâche va exécuter un traitement nommé "Thread": c'est le traitement principal de l'application.

Lors de l'exécution active du traitement, il est souvent difficile de lancer une autre action ou même de déplacer la fenêtre d'exécution.

Essayez le code suivant dans une fiche pourvue d'un "Edit" et d'un "Button":

procedure TForm1.Button1Click(Sender: TObject);var i:integer;beginfor i:=1 to 100000 do Edit1.Text:=IntToStr(i);end;

On ne voit même pas l'affichage défiler, puisque les messages envoyés au composant "Edit" ne sont pas traités pendant l'exécution de la boucle.

Le fait de rajouter une ligne de code améliore la situation, on peut même déplacer la fenêtre.

procedure TForm1.Button1Click(Sender: TObject);var i:integer;beginfor i:=1 to 10000 do begin Edit1.Text:=IntToStr(i); Application.ProcessMessages; end;end;

© Maurice GINDENSPERGER (V 6.0) page 4/14

Page 5: 97118059 Aller Plus Loin Avec Delphi 6

Aller plus loin avec Delphi 6

Je souhaite voir défiler 2 compteurs en même temps. Je rajoute donc un 2° "Edit" et un 2° "Button" auquel j'affecte une procédure semblable:

procedure TForm1.Button2Click(Sender: TObject);var j:integer;beginfor j:=1 to 10000 do begin Edit2.Text:=IntToStr(j); Application.ProcessMessages; end;end;

A l'exécution, je constate que le fait d'appuyer sur le premier bouton fait bien défiler le 1er compteur. Pendant ce temps, j'appuie sur le 2° bouton: le premier compteur est suspendu alors que le 2° fonctionne. Dès son arrêt, le 1er termine son travail.

Il est maintenant évident qu'un programme habituel n'accomplit qu'un seul traitement. Les différentes procédures sont empilées puis dépilées par le système, mais ne peuvent "tourner" simultanément.

L'alternative à cette problématique est la création de traitements (Threads) "à la volée", on va faire croire à l'utilisateur qu'il dispose de plusieurs processeurs (16 max).

© Maurice GINDENSPERGER (V 6.0) page 5/14

Page 6: 97118059 Aller Plus Loin Avec Delphi 6

Aller plus loin avec Delphi 6

2.2 Exemple d'application multi-traitements (multithread)Réaliser la fiche suivante:

A. On peut commencer à écrire la procédure à exécuter par le traitement:procedure MonTraitement;var i:integer; begin i:=0; while true do begin inc(i); Form1.Edit1.Text:=format('Le compteur : %d',[i]); end; end;

N'ayons pas peur ici d'une boucle infinie, puisque le traitement peut être interrompu par une commande particulière.

B. Déclarer les variables nécessaires au traitement (en global pour l'unité):var ThreadID, hThread: THandle;

Un traitement est caractérisé par 2 propriétés, son numéro et le pointeur servant à le manipuler. Rappel: un "handle" est un pointeur permettant de manipuler les objets de Windows dans le cas de l'utilisation des méthodes des APIs.

© Maurice GINDENSPERGER (V 6.0) page 6/14

Page 7: 97118059 Aller Plus Loin Avec Delphi 6

Aller plus loin avec Delphi 6

C. Ecrire la procédure pour le bouton "Marche1"procedure TForm1.BtM1Click(Sender: TObject); begin HThread:=CreateThread(nil,0,@MonTraitement,nil,0,ThreadID); end;

Nous faisons appel ici à la fonction "CreateThread" de l'API Windows (à vois dans l'aide en ligne).

D. Ecrire la procédure pour le bouton "Suspend 1"procedure TForm1.BtS1Click(Sender: TObject);beginSuspendThread(HThread);end;

Un traitement peut "s'endormir" !!!

E. Ecrire la procédure pour le bouton "Reprend 1"procedure TForm1.BtR1Click(Sender: TObject);beginResumeThread(HThread);end;

Un traitement peut "se réveiller" !!!

F. Ecrire la procédure pour le bouton "Arrêt 1"procedure TForm1.BtA1Click(Sender: TObject);beginTerminateThread(hThread,0);end;

Un traitement peut heureusement s'arrêter.

© Maurice GINDENSPERGER (V 6.0) page 7/14

Page 8: 97118059 Aller Plus Loin Avec Delphi 6

Aller plus loin avec Delphi 6

G. Vérifier le fonctionnement puis refaire de même pour le 2° traitement. Le code complet sera voisin du suivant:

unit Unit1;

interface

uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;

type TForm1 = class(TForm) BtM1: TButton; Edit1: TEdit; BtA1: TButton; Edit2: TEdit; BtM2: TButton; BtA2: TButton; BtS1: TButton; BtS2: TButton; BtR1: TButton; BtR2: TButton; procedure BtM1Click(Sender: TObject); procedure BtA1Click(Sender: TObject); procedure BtM2Click(Sender: TObject); procedure BtA2Click(Sender: TObject); procedure BtS1Click(Sender: TObject); procedure BtS2Click(Sender: TObject); procedure BtR1Click(Sender: TObject); procedure BtR2Click(Sender: TObject); private { Déclarations privées} public { Déclarations publiques} end;

var Form1: TForm1; ThreadID, hThread: THandle; ThreadID2, hThread2: THandle;implementation

{$R *.DFM}

procedure MonTraitement;var i:integer; begin i:=0; while true do

© Maurice GINDENSPERGER (V 6.0) page 8/14

Page 9: 97118059 Aller Plus Loin Avec Delphi 6

Aller plus loin avec Delphi 6

begin inc(i); Form1.Edit1.Text:=format('Le compteur : %d',[i]); end; end;

procedure MonTraitement2; //stdcall;var j:integer; begin j:=0; while true do begin inc(j); Form1.Edit2.Text:=format('Le compteur : %d',[j]); end; end;

procedure TForm1.BtM1Click(Sender: TObject); begin HThread:=CreateThread(nil,0,@MonTraitement,nil,0,ThreadID); end;

procedure TForm1.BtA1Click(Sender: TObject);beginTerminateThread(hThread,0);end;

procedure TForm1.BtM2Click(Sender: TObject);begin HThread2:=CreateThread(nil,0,@MonTraitement2,nil,0,ThreadID2);end;

procedure TForm1.BtA2Click(Sender: TObject);beginTerminateThread(hThread2,0); // ou mieux, utiliser la fonction ExitThreadend;

procedure TForm1.BtS1Click(Sender: TObject);beginSuspendThread(HThread);end;

procedure TForm1.BtS2Click(Sender: TObject);beginSuspendThread(HThread2);end;

procedure TForm1.BtR1Click(Sender: TObject);beginResumeThread(HThread);end;

© Maurice GINDENSPERGER (V 6.0) page 9/14

Page 10: 97118059 Aller Plus Loin Avec Delphi 6

Aller plus loin avec Delphi 6

procedure TForm1.BtR2Click(Sender: TObject);beginResumeThread(HThread2);end;

end.

Le fonctionnement des traitements n'empêche pas l'exécution d'autres tâches, ni le traitement des messages par l'application: on peut donc quitter celle-ci à tout moment. D'autre part, on remarque que le traitement principal du programme n'est pas sollicité et que les 2 traitements s'exécutent à une vitesse voisine. Il est possible de changer la priorité des traitements.

2.3 Priorité des traitementsIl est possible de changer la priorité des traitements par la fonction SetThreadPriority.

Exemple pour notre bouton "Marche 1":procedure TForm1.BtM1Click(Sender: TObject); begin HThread:=CreateThread(nil,0,@MonTraitement,nil,0,ThreadID); SetThreadPriority(HThread,THREAD_PRIORITY_HIGHEST);// end;

On constate maintenant que le premier compteur est plus rapide que le second.

Le système de priorité n'est pas simple, puisqu'il faut d'abord tenir compte de la classe de priorité de la tâche (application).

2.3.1 Priorités des applications

La fonction "GetPriorityClass" retourne la priorité de la tâche.

Priorité application Signification IndiceHIGH_PRIORITY_CLASS haute priorité: utilise presque toutes les

ressources du processeur13

IDLE_PRIORITY_CLASS basse priorité: s'exécute quand la charge du processeur est voisine de zéro

4

NORMAL_PRIORITY_CLASS priorité normale 7 à 9REALTIME_PRIORITY_CLASS priorité absolue: même sur les disques et

la souris24

© Maurice GINDENSPERGER (V 6.0) page 10/14

Page 11: 97118059 Aller Plus Loin Avec Delphi 6

Aller plus loin avec Delphi 6

2.3.2 Priorités des threads (traitements)

La fonction GetThreadPriority nous renseigne sur la priorité en cours.

Indicateur de priorité du traitement Indice de prioritéTHREAD_PRIORITY_ABOVE_NORMAL + 1 / tâcheTHREAD_PRIORITY_BELOW_NORMAL - 1 / tâcheTHREAD_PRIORITY_HIGHEST + 2 / tâcheTHREAD_PRIORITY_IDLE valeur de 1 pour toutes les tâches sauf

REALTIME_PRIORITY_CLASS (16).THREAD_PRIORITY_LOWEST - 2 / tâcheTHREAD_PRIORITY_NORMAL + 0 / tâcheTHREAD_PRIORITY_TIME_CRITICAL valeur de 15 pour toutes les tâches sauf

REALTIME_PRIORITY_CLASS (31).

2.4 Temps d'exécutionAttention, sous Windows, on ne sait jamais quel va être le temps d'exécution d'un

traitement. Il n'est évidemment plus question de chronométrer, puisque plusieurs traitements s'effectuent "en parallèle".

2.4.1 Suspendre l'exécution d'une durée connueEmployer la fonction Sleep(Millisecondes).

2.4.2 Attendre un événementUtiliser la fonction WaitMessageEnvoyer un message au traitement: PostThreadMessage

© Maurice GINDENSPERGER (V 6.0) page 11/14

Page 12: 97118059 Aller Plus Loin Avec Delphi 6

Aller plus loin avec Delphi 6

3. DELPHI pour le WEB

Il est simple de construire des fiches DELPHI et de les déployer sur le WEB.

3.1 Création d'une fiche ACTIVEChoisir "Fichier- Tout fermer" puis "Fichier - Nouveau - Autre" puis "Fiche active" dans

l'onglet "Active X".

Taper le nom:

© Maurice GINDENSPERGER (V 6.0) page 12/14

Page 13: 97118059 Aller Plus Loin Avec Delphi 6

Aller plus loin avec Delphi 6

Une nouvelle fiche apparaît. Il suffit d'y placer des composants.

Enregistrer dans un nouveau dossier bien identifié.

Choisir "Exécuter - recenser le serveur Active X":

Choisir "Projet - Options de déploiement pour le web"

© Maurice GINDENSPERGER (V 6.0) page 13/14

Page 14: 97118059 Aller Plus Loin Avec Delphi 6

Aller plus loin avec Delphi 6

Choisir "Projet -déployer pour le Web".

Si tout va bien, on doit obtenir une page WEB:

On constate le fonctionnement.

© Maurice GINDENSPERGER (V 6.0) page 14/14