dimanche 13 juillet 2003

Fichier ini


FICHIER INI

Les fichiers ini sont utilisés pour sauvegarder toutes sortes d'information. Il était énormément populaire à l'époque de windows 3.1. Néanmoins, ils peuvent être fortement utiles de nos jours pour sauvegarder des paramètres de configuration pour un programme. Les fichiers ini sont une bonne alternative à la base de registre de windows. De plus, les fichiers ini peuvent être utilisés sous Linux et Windows.

Exemple de fichier ini

[marc]
host=166.130.84.164
port=21
user=test
password=test
passive=false

[agreyz]
host=12.333.33.130
port=1143
user=os
password=allo
passive=true

Dans l'exemple précédent, marc et agreyz sont considéré comme des «sections». host, port, user, password
et passive sont des clés. Il faut bien distinguer les deux. On pourrait faire un lien avec une base de donnée
Le nom de la table serait la «sections» tandis que les champs serait des clé.

Méthode pour les fichiers ini

Ils existent diverses méthodes afin de faciliter l'utilisation des fichiers ini.

ReadSections

Cette méthode permet de lires toutes les sections d'un fichier ini. Dans le fichier ini montré ci-dessus, cette méthodes retournerais: marc et agreyz.

ReadSection

Cette méthode permet de lires toutes les clés d'une section d'un fichier ini. Dans le fichier ini montré ci-dessus, cette méthodes retournerais la section marc: host, port, user, password, passive.

ReadString

Cette méthode permet de lire la valeur d'une clé dans une section. Dans le fichier ini montré ci-dessus, cette méthodes retournerais: os, si la section est agreyz et la cé est user.

WriteString

Cette méthode permet d'écrire une valeur pour une clé dans une section. Si la section et la clé n'existent pas, cette méthode va les créer.

EraseSection

Cette méthode permet d'effacer une section entière d'un fichier ini. Dans le fichier ini montré ci-dessus, si on appelerait cette méthode avec comme paramètre: marc, le fichier ini ressemblerait à :

[agreyz]
host=12.333.33.130
port=1143
user=os
password=allo
passive=true

Il existe d'autre méthodes pour lire et écrire d'autre type de donnée que des string.

Vous pouvez télécharger les sources du projet ici.

dimanche 29 juin 2003

Web service


WEB SERVICE

Un web service est une application serveur qui est disponible sur Internet. L'interface est disponible pour des applications clientes. On peut ainsi accéder aux fonctions que le serveur offre. Le client et le serveur utilisent le WSDL (web service description language) pour communiquer ensemble.



Une application serveur fonctionnant derrière un serveur Web offre une panoplie de fonctions. L'application client peut utiliser ces fonctions. Le protocole utilisé est bien sur le HTTP. Ce protocole est simple et fonctionne sur la majorité des plateformes existantes actuellement. La façon d'appeler des applications à distance a été appelée SOAP (simple object acces protocol).

SOAP transmet ses données via le langage XML. Le client et le serveur utilisent ce langage pour communiquer. Il est ainsi possible de rajouter une structure de donnée en fournissant un schéma XML (XSD). Comme vous pouvez le remarquer, le principe des Webservices est simple. Delphi le simplifie encore d'avantage. Il existait bien avant les Webservices, des technologies qui offraient ce genre de fonctionnalités (accès à distances de fonction). On n'a qu'à penser à Corba et DCOM. Il est possible de faire un serveur Web en langage C et le client en Java.

Un exemple fort simple d'un service Web serait d'avoir une méthode dictionnaire sur le serveur. Lorsque l'application client appellerait la méthode dictionnaire, un mot au hasard parviendrait à l'application client. Imaginez maintenant toutes les possibilités.

Delphi est les Web services

Dépendant de ce qu'on désire faire, il existe plusieurs façons d'utiliser des web services sous delphi. Nous verrons comment créer un webservice qui utilisera MyBase.

Création du serveur

Démarrez un nouveau projet, Sélectionner Web Service et cliquer sur Application Serveur Soap.


Sélectionnez ensuite le type d'application Serveur que vous désirez. J'utilise un serveur apache, j'ai pris l'exécutable autonome CGI.


Delphi vous demandera si vous désirez créer une interface, répondez non. Sauvegarder le TWebModule sous le nom SWebMod et le projet sous SoapServer.


Ajouté au projet, un serveur de données soap


Inscriver le nom SoapDataMod au serveur de donnée et sauvegardé sous le nom SDataMod.


Ajoutez un TClientDataSet et un TDataSetProvider sur le datamodule. Mettez la propriété Name du TClientDataSet à cdsAnimal et celle du TDataSetProvider à dspAnimal. Mettez la propriété Filename du TClientDataSet à animals.xml (Inclus dans le dossier partagé de Borlan). Mettez la propriété Active du TClientDataSet à True. Mettez la propriété DataSet du TDataSetProvider à cdsAniaml. Mettez la propriété ResolveToDataSet du TDataSetProvider à True.



Compilez le projet et mettre le fichier exécutable ainsi que les fichiers suivants:
  • animal.cds
  • animal.dbt
  • animal.xml
pour la base de donnée dans le répertoire cgi-bin du serveur Web.

Démarrez votre serveur Web et inscrivez dans votre navigateur web: http://ip/cgi-bin/SoapServer/wsdl. ip étant bien sur votre adresse ip. Si vous voyez une image comme ci-dessous, c'est que vous avez bien suivie les instructions.


Code source du serveur disponible ici.

Création du client

Créez un nouveau projet. Sauvegarder l'unité sous le nom ClientForm et le projet sous SoapClient.

Ajoutez un TSoapConnection sur la fiche à partir de l'onglet Web service. Mettez sa propriété UseSOAPAdapter à false.

Mettre la propriété URL du TSoapConnection à l'adresse où est votre serveur suivi du nom du serveur suivi de soap, suivi du nom de l'interface. On utilisera à des fins éducatives et pour faciliter l'adresse ip: 127.0.0.1. J'utilise apache et j'ai sélectionné cgi pour le serveur donc le programme serveur sera logé dans le répertoire: cgi-bin.

Ce qui donne: http://127.0.0.1//cgi-bin/SoapServer/soap/ISoapDataMod

Ajoutez ensuite un TClientDataSet et mettez sa propriété RemoteServer au composant TSoapConnection. Ensuite ouvrez la propriété ProviderName et sélectionné dspAnimal.

Mettez sa propriété active à true.

Ajoutez un TDataSource et lié le au ClientDataset grâce à sa propriété DataSet.

Ajoutez un TDBGrid et lié le au datasource grâce à sa propriété DataSet.

Ajoutez un TDBNavigator et lié le au datasource grâce à sa propriété DataSet.

Ajoutez un TDBImage et lié le au datasource grâce à sa propriété DataSource.Mettez ensuite sa propriété datafield à bmp.

Vous pouvez démarrer le programme, vous obtiendrez environ le résultat ci-dessous.



Code source du client disponible ici.

vendredi 11 avril 2003

Thread


THREAD

Le parallélisme fait partie de notre quotidien. Il n'est pas rare d'exécuter plusieurs actions en même temps : manger, écouter, écrire... Une telle approche peut-être utilisé en programmation. De plus en plus de logiciels utilisent cette technique. Cette méthode est employée par certains lecteurs vidéo et audio sur le Web. On peut ainsi écouter le fichier sans devoir attendre qu'il soit totalement téléchargé. Un thread exécute le fichier, un autre le télécharge.

Le système alloue un certain temps d'exécution à chaque tâche. Le temps alloué à chaque programme est si court qu'on a l'impression que tout fonctionne simultanément. Un tel système est dit multitâche de prémption.

Un thread est un sous-programme d'une application, c'est une unité d'exécution de celui-ci. Plusieurs threads peuvent fonctionner en même temps dans une application. L'utilisation des threads permet d'augmenter les performances.

Priorité

La priorité permet d'allouer un certain temps d'exécution aux threads. Les valeurs suivantes peuvent être affectés à la propriété «Priority» du thread.
  • tpIdle Le thread s'exécute seulement quand le système est en attente.
  • tpLowest La priorité du thread est deux points en dessous de la normale.
  • tpLower La priorité du thread est un point en dessous de la normale.
  • tpNormal La priorité du thread est normale.
  • tpHigher La priorité du thread est un point au-dessus de la normale
  • tpHighest La priorité du thread est deux points au-dessus de la normale.
  • tpTimeCritical Le thread a la priorité la plus élevée.
Il faut bien identifier les besoins qu'on a pour ne pas allouer trop de temps à un thread qui attend des donnés de l'extérieur, on réduisait ainsi les performances au lieu de les augmenter.

Synchronisation de base

Il a sa propre pile et les variables locales sont locales à chaque thread. Des données globabes peuvent être partagées entre les différents threads, il peut donc avoir des problèmes de synchronisation. S'il y a qu'un thread qui utilise une variable globale, il n'y a aucun problème.

Aperçu des méthodes

Création

Il faut créer un descendant de la classe TThread

Execute

Cette méthode est abstraite, elle contiendra le code à exécuter lorsque le thread débutera.

Terminated

Cette propriété et la méthode Terminate permettent d'arrêter un thread.

Suspended

En affectant true à cette propriété ou en appelant la méthode Suspend, le thread sera suspendu.

Resume

Cette méthode reprend l'exécution d'un thread interrompu.

Synchronize

Cette méthode sert à exécuter une méthode dans le thread principal de la vcl. On évite de nombreux conflits lors du multi-thread en l'employant. La synchronisation peut s'avérer nécessaire lorsqu'on utilise des objets de la vcl/clx.
L'unité classes doit être incluse dans la partie uses.

Ce thread servira à afficher le nombre de fois qu'il est passé dans une boucle.

type
  TLoop = class(TThread)
  private
    cptIteration : integer;
  protected
    constructor create();
    procedure Execute; override;
    procedure ReAfficher;
end;
Nous sommes obligés de définir la méthode execute.
procedure TLoop.Execute;
begin
  while (not Terminated) do begin
    inc(cptIteration);
     Synchronize(ReAfficher);
  end;
end;

Destruction de thread

Afin d'évider les problèmes lors de la destruction de threads, il faut quitter le threads convenablement, récupérer la mémoire allouée et obtenir les résultats du threads.
Si le threads ne doit pas communiquer de l'information à nouveau au thread principal de la vcl, on n'a pas besoin de se préoccuper réllement de sa libération de mémoire. On utilise FreeOnTerminate et le thread effectue lui-même sa propre désalocation de la mémoire.

Arrêt prématuré de thread

Il peut arriver qu'un thread doit en informer un autre qu'il va se terminer. Ceci se produit généralement si un thread exécute une opération prolongé et que l'utilisateur décide de quitter l'application ou que l'exécution doit être interrompue. TThread inclut la méthode Terminate et la propriété Terminated pour supporter de telles situations. Lorsque thread est démaré, sa propriété terminated est mise à false.C'est la responsabilité des threads de vérifier périodiquement s'ils ont été terminés.En somme cette propriété signifié terminait le thread le plus rapidement possible.

L'événement OnTerminate

Cet évènement survient lorsqu'un thread a fini d'être exécuté et non lorsque la méthode Terminate est appelée. C'est très utile car on l'exécute comme le thread principal de la vcl. C'est une façon très intéressante de ne pas avoir un thread vcl et de transférer ses donnés à un thread de vcl. OnTerminate fonctionne étrangement à synchronise.

Grâce à du code trouvé sur le Web, j'ai créé une petite application qui peut exécuter jusqu'à 3 threads en même temps. Ce programme vous permettra de mieux comprendre les notions apprises sur les threads jusqu'à maintenant.
Code source disponible ici

Blocage

Méthode de WaitFor

Il peut arriver qu'on est besoin que tous les autres thread soient terminés à un certain moment lorsqu'on fait exécuter le thread de la vcl. voici un petit exemple pour mieux comprendre ce que fait cette méthode.

Un thread A appelle la méthode WaitFor d'un thread B, le tread A est mis en attente jusqu'à ce que le thread B est fini son exécution. Lorsque le thread A reprend, il est certain que le résultat du thread B peut-être lu et que l'objet du thread représentant B peut être détruit.

Il faut faire attention lorsqu'on utilise cette méthode, car elle ne peut pas recevoir de message. Le formulaire ne pourra pas se redessiner, se redimensionner et communiquer avec l'extérieur. En appelant PostMessage le problème sera moins visible, mais si le traitement est vraiment long, il faudrait penser à ajouter un messager à l'usager. Il existe de nombreuses techniques pour résoudre ce problème dont les messages d'attente de win32.

Danger

Si on utilise synchronize et waitfor il est possible qu'il se produise un blocage de notre application. Un blocage survient si les threads s'attendent les uns les autres de façon cyclique. Un cercle vicieux en quelques sortes. Ce problème peut-être résout en levant des exceptions. En utilisant pas synchronise et waitfor dans la même application, on s'assure ainsi de ne pas rencontrer ce problème.

Thread: avancé

Inconvénient de synchronize

Synchronise a plusieurs inconvénients qui peuvent le rendre inacceptable pour des applications multi-thread complexe.
  • Utile lorsqu'on veut faire communiquer nos threads avec ceux de la vcl
  • Si on utilise beaucoup de synchronize, la vcl bloque notre application
  • Synchronize peut bloquer notre application si la vcl attend nos threads
Le thread principal de l'application devrait s'exécuter rapidement pour avoir un temps réponse optimal.

Il arrive très souvent que des threads communiquent avec la vcl dans le même sens. C'est à dire lire un flux de donnés, exécuter une requête... Des données sont ainsi partagées. Il faut alors s'assurer que seul un thread pourra modifier des donnés. La classe TCriticalSection est une bonne solution.

Section critique

La classe TCriticalSection permet de bloquer l'accès à une partie du code à plusieurs threads. Seul un thread pourra exécuter le code. La méthode Acquire empêche les autres threads d'exécuter une section et Release enlève cette protection. L'api de Windows a bien évidemment des fonctionnalités plus complètes.

samedi 29 mars 2003

Base de registre


BASE DE REGISTRE

La base de registre constitue le système nerveux de Windows. Une panoplie d'information y est entreposée. Il est possible d'intervenir sur le matériel, logiciel et sur le système d'exploitation grâce à la base de registre. Cette base de données peut aisément devenir énorme (des centaines de meg). Elle peut souvent rendre service, mais trop souvent elle est utilisée à tort. Il n'est pas rare de voir un programme qui y laisse sa trace même si le programme en question n'existe pu.

La structure du registre

La base de registre est divisée en 5 sections
  • HKEY_CLASSES_ROOT
  • HKEY_CURRENT_USER
  • HKEY_LOCAL_MACHINE
  • HKEY_USERS
  • HKEY_CURRENT_CONFIG

HKEY_CLASSES_ROOT

Cette section permet de lier un type de fichier à un programme

HKEY_CURRENT_USER

Cette section contient tous les paramètres utilisateurs de celui qui est connecté

HKEY_LOCAL_MACHINE

Cette section contient tous les paramètres du système relatif à tous les utilisateurs

HKEY_USERS

Cette section contient toutes les préférences de tous les profils utilisateurs

HKEY_CURRENT_CONFIG

Cette section les informations sur le matériel du système
Nous avons vu les différentes sections de la base de registre. Il est bien attendu possible de lire et d'écrire dans ces sections.

Méthode

Il existe différentes méthodes disponibles dans Delphi permettant d'effectuer divers traitements dans la base de registre. L'unité «Registry» doit être ajoutée dans la section «uses» afin de pouvoir utiliser les méthodes liées à la base de registre.

Exemple

Nous allons créer un petit programme qui créer une clé dans la base de registre qui dira au programme la couleur que la forme doit prendre.

Lecture

Var
  Registre : TRegistry;
  tmpCouleur:integer;
begin
   //Crée un objet TRegistry
  Registre:=TRegistry.Create;
  //Définit la clé principale
  Registre.RootKey:=HKEY_LOCAL_MACHINE;
  //Ouvre la clé et la crée si elle n'existe pas
  Registre.OpenKey('\Software\BorlandRulez\Test\',True);
  if Registre.ValueExists('Couleur') then
  begin
    tmpCouleur:=Registre.ReadInteger('Couleur');
    ColorBox1.ItemIndex := tmpCouleur;
    form1.Color := ColorBox1.Colors[ColorBox1.ItemIndex];
  end
  else
  begin
    showmessage('Veuillez écrire une valeur avant de pouvoir écrire');
    Button1.Enabled := False;
  end;
  //Ferme la clé
  Registre.CloseKey;
  //Détruit l'objet
  Registre.Free;
end;
 
Nous pouvons voir sur l'image ci-dessous l'effet qu'a la méthode «OpenKey» lorsque la clé n'existe pas. L'arborescence est crée. La clé Couleur fait partie de cette arborescence. Sa valeur est 23 (sa valeur en décimal est entre paranthèse)selon cette image.

Écriture

Var
  Registre : TRegistry;
begin
   //Crée un objet TRegistry
  Registre:=TRegistry.Create;
  //Définit la clé principale
  Registre.RootKey:=HKEY_LOCAL_MACHINE;
  //Ouvre la clé et la crée si elle n'existe pas
  Registre.OpenKey('\Software\BorlandRulez\Test\',True);

  if ColorBox1.ItemIndex = -1 then
    ColorBox1.ItemIndex := 0;
  //Écrit la valeur
  Registre.WriteInteger('Couleur',ColorBox1.ItemIndex);
  //Ferme la clé
  Registre.CloseKey;
  //Détruit l'objet
  Registre.Free;
end;

Suppression

Var
  Registre : TRegistry;
begin
   //Crée un objet TRegistry
  Registre:=TRegistry.Create;
  //Définit la clé principale
  Registre.RootKey:=HKEY_LOCAL_MACHINE;
  //Ouvre la clé et la crée si elle n'existe pas
  Registre.OpenKey('\Software\BorlandRulez\Test\',True);
  //Écrit la valeur
  Registre.WriteInteger('Couleur',2);
  //Efface la valeur
  Registre.DeleteValue('Couleur');
  Registre.CloseKey;
  //Détruit l'objet
  Registre.Free;
end;


En exécutant ce code, la valeur 'Couleur' est enlevée de la base de registre. Il serait possible d'enlever la clé test en utilisant la méthode DeleteKey.

 
if Registre.KeyExists('\Software\BorlandRulez\Test\') then
  Registre.DeleteKey('\Software\BorlandRulez\Test\');

La méthode KeyExists permet de savoir si la clé existe, une telle méthode existe aussi pour les valeurs: ValueExists

Nous avons pu voir que la base de registre permet d'obtenir beaucoup d'information sur le matériel, logiciel et sur Windows. Il est aussi possible de l'utiliser afin de créer une configuration par défaut de notre programme. Elle peut alors remplacer l'utilisation des fichiers ini.

Code source disponible ici