samedi 29 décembre 2001

Environnement de développement intégré


ENVIRONNEMENT DE DÉVELOPPEMENT INTÉGRÉ

L'edi (environnement de développement intégré) de delphi est divisé en 3 parties.
  • Fenêtre principale
  • Inspecteur d'objet
  • Espace de travail

Fenêtre principale



on y retrouve les barres d'outils et la palette de composants. C'est à partir de cette fenêtre qu'on choisit et dépose les composants sur notre fiche dans l'espace de travail.

L'inspecteur d'objet



L'inspecteur d'objet permet de:
  • visualiser
  • modifier
les propriétés et événements des composants en mode création.
Les propriétés et évènements varient d'un composant à l'autre.
Les propriétés correspondent aux caractéristiques, aspects, comportements d'un objet.
Explorez-les afin de les connaître d?avantage. Dans cette fenêtre, on remarque que Form1 sera affiché dans la barre de menu de l'application.
On peut aisément changer cela en modifiant la propriété caption.

Espace de travail

L'espace de travail sert à déposer les composants qui constituent notre programme.
C'est dans cette fenêtre qu'on crée la partie graphique, l'esthétique de notre programme

Éditeur de code

On écrit tout notre code dans cet éditeur. C'est la fenêtre à laquelle le programmeur passera le plus clair de son temps.


Delphi génère automatiquement le nom des composants en leur ajoutant un chiffre. Comme vous avez pu le remarquer, dans l'espace de travail la forme s'appelait form1. S'il y en avait eu une deuxième, delphi l'aurait appelé form2. Ceci s'applique pour tous les composants: bouton, liste..... On peut à tout moment changer le nom du composant enfin de lui donner un nom plus significatif.

L'edi peut s'avérer complexe au novice, mais il deviendra rapidement indispensable. Il regroupe tout ce qu'un programmeur a besoin. Il n'est plus nécessaire de disposer de plusieurs programmes séparés pour faire ce dont on a besoin.
C'est un outil très pratique, vous le découvrirez rapidement.

dimanche 23 décembre 2001

Interface


INTERFACE

Dans le chapitre précédent, nous avons vu que nous pouvons déclarer des méthodes abstraites dans une classe mère. Les méthodes peuvent ensuite être définies dans les classes enfants.

Nous pouvons créer une interface au lieu d'avoir une classe avec de nombreuses méthodes abstraites. Une interface peut ressembler à une classe mais c'en est pas une. Une interface permet de déclarer plusieurs méthodes sans les définir. Elles sont très utilisées pour les objets com.



En delphi comparativement au langage C++ on peut seulement hériter d'une seule classe. Il est impossible de faire de l'héritage multiple (image ci-dessus) avec delphi tout comme java. C'est là que les interfaces deviennent intéressantes.
La structure d'une interface ressemble à

type nomInterface = interface (interfaceAncêtre)
  ['{GUID}']
  listeMembres
end;

La longue série de lettres et de chiffres dans l'interface est un identifiant numérique.
L'interfaceAncêtre et le GUID sont facultatifs.
Il est nécessaire d'en avoir un pour pouvoir faire des «QueryInterface» et des cast dynamiques
en utilisant cette interface, il n'est pas nécessaire pour le reste.

Il faut appuyer sur «Ctrl+Shift+G» dans le l'éditeur de code pour générer un GUID.
Un exemple d'une interface

type
  IEncrypt = Interface
  ['{F26B6D20-F718-11D5-8E23-BCD4F752513A}'] //GUID
  function Encrypt(S: String; Key: Word): String;
  function Decrypt(S: String; Key: Word): String;
end;

Il est impossible de déclarer des méthodes virtual, dynamic, abstract ou override étant
donné que les interfaces n'implantent pas les méthodes. Seulement des propriétés et des
méthodes peuvent être utilisés dans les interfaces.
Code source disponible ici

lundi 17 décembre 2001

Programmation orienté objet


PROGRAMMATION ORIENTÉ OBJET

La programmation orienté objet ou plus communément appelé poo est devenu essentiel. Les gains de temps et d'argent obtenues par une telle approche ont contribué à son ascension. La poo tente de modéliser des objets de la vie courante en des objets logiciels. C'est une manière complètement différente de penser. Même si au début, c'est un peu plus complexe que la programmation procédurale, la maîtriser est à la porter de tous.

But

La poo tente de résoudre quelques lacunes de la programmation procédurale. Différents facteurs font qu'une solution orienté objet est plus adapté qu'une solution à l'ancienne. C'est évident que chaque facteur ne peut atteindre un seuil d'utilisation parfait dans une application. Il faut savoir doser chaque facteur en fonction de nos besoins présents et à venir.

Avantage de la poo

Réutilisabilité

Il arrive souvent en programmation qu'il y ait du code qui revient sans cesse de projet à projet. Habituellement, on copierait le code nécessaire dans notre projet en cours. Avec la poo, on ne copie pas le code nécessaire, on crée une classe (un genre de structure avec des fonctions et des procédures) qu'on instanciera avant de l'utiliser. Par la suite, on pourra utiliser cette classe dans tous nos autres projets et même y rajouter des fonctionnalités si on le souhaite. Plus nos classes seront réutilisables moins qu'on codera dans le futur.

Compatiblité

Il est facile de constater l'incompatibilité qu'il existe dans le domaine de l'informatique. Des logiciels conçus pour mac sont inutilisables sous PC... Palier à une telle lacune peut selon un certain seuil d'efficacité être envisageable avec la poo. Ce qu'on crée doit pouvoir fonctionner avec un maximum de classe.

Facilité d'utilisation

Étant donné que la réutilisabilité est primée en poo, on doit s'attendre que d'autre programmeur puisse un jour utilisé nos classes. Pour ne pas décourager les autres et rendre les mises à jour plus aisés, c'est important de garder nos classes simples. Une bonne documentation est des commentaires ne sont jamais de trop.

Classe

Les classes sont des types de données que le programmeur créera. Ces types de données contiennent des fonctions et des procédures qu'on désigne par des méthodes. Vous avez certainement déjà utilisé des classes sans vous en rendre compte. En créant votre interface graphique sous Delphi, cette dernière utilise de nombreuses autres classes. Plaçons une TListbox sur un formulaire. Ce code est automatiquement créé.
ListBox1: TListBox;
Dans cet exemple, TListBoxest une classe.

Objet

Un objet est tout simplement une instance, variable d'une classe. Dans l'exemple précédent, l'objet serait ListBox1

Méthode, propriété

Écrivez quelque part dans le code ListBox1 ensuite appuyé sur le . Vous verrez comme sous les illustrations ci-dessous toutes les méthodes et propriétés de la classe.

Méthodes


Propriété



Les propriétés sont les caractéristiques de la classe. Pour la classe TListBox, on a la propriété MultiSelect. Cette caractéristique permet de spécifier si on veut permettre la multi-sélection dans la liste.En assignant true à cette propriété, la liste permettra de sélection plusieurs éléments. En ajoutant items.add, on accède à une méthode qui permet d'ajouter un élément de type string dans la liste.
Un autre exemple serait une voiture. Une voiture peut avoir plusieurs caractéristiques comme : transmission, turbo, vitre électrique,vitesse. Pour les méthodes, on pourrait avoir : démarrer,rouler,arrêt.

Opération sur les classes

Utilisation

Les objets demandent des opérations additionnelles pour qu'il puisse fonctionner correctement. Lorsqu'on utilise des composés comme TListBox, TLabel... et qu'on les dépose sur notre fiche, Delphi s'occupe de certaines opérations pour nous. Ces opérations qui sont la construction et la destruction d'objet doivent être faites par le programmeur lorsque nous instancions n'importe quel objet tel que TListBox, TLabel... à l'exécution.

Construction

Lorsqu'on désire construire un objet, on doit utiliser la méthode create. Il peut arriver que cette méthode nécessite des paramètres. Cette méthode initialise les données de l'objet lors de sa création. Il est possible de surcharger un constructeur. Delphi met nos données automatiquement à zéro, si on veut que nos données soient initialisées à d'autres valeurs, on crée un constructeur.
Un modèle de constructeur pourrait ressembler à ceci
>objet := classe.constructeur[(paramètres)];

Destruction

Un destructeur sert à détruire un objet. Cet objet ne pourra plus être utilisé par la suite. Le destructeur a une syntaxe semblable à un destructeur.

objet := objet.destructeur[(parametres)];

Il est rare que l'on doive créer un destructeur car on peut le détruire en appelant la 
méthode Free. Avant d'appeler cette méthode, on devrait toujours mettre l'objet à nil puisque
que l'objet ne connaît pas les variables qui peuvent le référencer.
A partir de Delphi 5, on peut faire appel à la méthode FreeAndNil(objet). En mettant l'objet
à nil, il n'y aura pas d'erreur si on tente de détruire l'objet plusieurs fois.

Contrôle d'accès

En programmation procédurale, n'importe qui peut modifier à peu près n'importe quoi. Il n'est pas rare de chercher pourquoi une variable à une certaine valeur et de se rendre compte que dans le code que son contenu est modifié. Beaucoup d'erreurs peuvent facilement intervenir. En poo, on a vu restreindre ce type d'erreur en permettant d'avoir un certain contrôle sur le contenu d'une classe. Les données ne peuvent être modifiées que par des méthodes. L'accès aux données est ainsi indirect, leur sécurité est accrue. Delphi permet quatre types d'accès aux données.
  • Private
  • Public
  • Protected
  • Published
Nous discuterons seulement des 3 premiers dans ce chapitre. Le dernier étant réservé principalement pour les composants. Les données private et protected sont accessible à n'importe quelles méthodes qui sont dans la même unité. Nous devrions donc mettre une classe par unité, sinon l'accès aux données n'est pas vraiment sécuritaire.
Ceux qui utiliseront nos classes verront seulement ce que nous voudrons. Rien ne sert de donner accès à tout ce qui est dans la classe si seulement quelques données doivent être modifiées. Un exemple très simple pourrait être le cas d'un ordinateur. On n'a pas besoin de savoir comment il fonctionne ni comment les données s'affichent à l'écran. On a accès à une souris, clavier et on peut faire tout le travail que l'on désire. Le contrôle d'accès des données est aussi appelé encapsulation.Grâce à l'encapsulation, on cache le fonctionnement interne (implantation) de la classe.

private

Les données et les méthodes qui sont privés ne sont pas accessibles à l'extérieur d'une unité. On n'a pas besoin de savoir comment les données se transigent par le bus... pour utiliser l'ordinateur. Savoir cette information n'est pas pertinente pour utiliser l'ordinateur.

public

Le clavier, les haut-parleurs, la souris et l'écran seraient publics. Grâce à eux, on peut exécuter de nombreuses tâches. N'importe qui peut utiliser les objets ou méthodes déclarés public. Il faut bien choisir ce qu'on mettra dans cette section.

protected

Lorsqu'on overclock un ordinateur, seul quelques informations techniques sont nécessaires. Nul besoin de savoir comment l'information circule dans le processeur. Il faut ouvrir le boîtier et faire quelques modifications. Les données et méthodes protected sont seulement accessibles à la classe et ses sous-classes.
Voici un exemple pour mieux comprendre le fonctionnement des classes et de l'encapsulation des données.
 
unit unitAgenda;

interface

uses
  SysUtils;

type
  TAgenda = class
  private
    Annee:string;
  public
    procedure SetAnnee(const a:string);
    constructor  create;
end;

implementation

constructor TAgenda.create;
begin
  Annee:= DateToStr(Date);
end;

procedure TAgenda.SetAnnee(const a:string);
begin
  Annee:=a;
end;
end.

Après avoir créé notre classe, on peut l'utiliser dans un programme.

var  agenda:TAgenda;
begin
  agenda := TAgenda.Create;
  agenda.annee := 2005; //[Erreur] Unit1.pas(29): Identificateur non déclaré : 'annee'
  FreeAndNil(agenda);
end;

Dans l'exemple ci-dessus, on tente d'assigner une valeur au champ annee. Cette propriété
est privée, on ne peut directement accéder par elle. Delphi nous envoie un message d'erreur.
La bonne façon est d'employer la méthode SetAnnee.

var
  agenda:TAgenda;
begin
  agenda := TAgenda.Create;
  agenda.SetAnnee('2005');
  FreeAndNil(agenda);
end;

Héritage

Nous avons vu au début de ce chapitre, que la réutilisation est très importante. Souvent, on ne modifie que quelques lignes dans une fonction ou procédure pour qu'elle puisse fonctionner dans un nouveau programme. On doit alors tout copier et faire les modifications nécessaires. En poo de tel changement s'effectue grâce à l'héritage. Rien ne sert d'inventer la roue à chaque fois. Lorsqu'on fait du copier-coller, on oublie souvent des morceaux. L'héritage empêche de faire de telles erreurs. On peut ajouter de nouvelles fonctionnalités, fonctions, procédures à une classe existante en créant une nouvelle classe qui se basera sur la première. Je vais utiliser l'exemple classique utilisé pour expliquer l'héritage en poo. J'ai eu cet exemple en langage C++ et java.


La classe ancêtre, de base sur l'image ci-dessus est Forme. Les classes oval, rectangle et ligne sont dérivées de forme, on les surnomme classes dérivées ou classes enfants. La classes oval est l'ancêtre de cercle. Une telle approche permet de regrouper des points en commun dans une classe. Cette classe servira par la suite en a crér d'autres plus spécialisés. On peut continuer le schéma en ajoutant une classe carré. Un carré est en fait un rectangle avec 4 côtés identiques.



En programmation procédurale, on aurait eu probablement beaucoup de structure et elles auraient de nombreuses variables. Beaucoup de code aurait été redondant. L'héritage permet d'éviter la redondance et d'utiliser ce qui a déjà été créé. On peut sans cesse rendre les objets de plus en plus spécialisés.

Nous allons utiliser un exemple plus simple ensuite nous continuerons avec les formes pour des concepts plus avancés.


Le premier gameboy fonctionnait en noir et blanc. On pouvait l'ouvrir, l'éteindre et il y avait du son.



Lorsque la deuxième version sortit, les couleurs avaient apparu dans les jeux. On pouvait toujours l'ouvrir, l'éteindre et le son était encore de la partie. Rien ne sert de réécrire ce qui n'a pas changé. Faut seulement ajouter les nouvelles fonctionnalités.
Il suffit de rajouter le nom de la classe qu'on veut hériter en parenthèse à côté du mot réservé class.

[nom de class] = class(nom de class ancêtre)
La classe gameboy ressemblerait à
TGameBoy = class
 protected
   Alumer:boolean;
   Son:boolean;
 public
   procedure Ouvrir;
   procedure Fermer;
end;
Celle du gameboy color à
TGameBoyColor = class(TGameBoy)
 private
   Couleur:Integer;
 public
   procedure SetCouleur(Coul:Integer);
   function  GetCouleur:Integer;
end;

Les variables et méthodes de TGameBoy sont accessibles à la classe TGameBoyColor. Il
suffit d'instancier TGameBoyColor ensuite de taper le «.» et on verra les propriétés et
méthodes accessibles.

Si nous avions voulu ajouter, modifier des fonctionnalités aux méthodes existantes de TGameBoy, il aurait fallu les déclarer virtual.

TGameBoy = class
 protected
   Alumer:boolean;
   Son:boolean;
 public
   procedure Ouvrir;virual;
   procedure Fermer;virtual;
end;

Dans la classe TGameBoyColor, il faut ajouter le mot override; après les méthodes pour pouvoir les surcharger.

TGameBoyColor = class(TGameBoy)
 private
   Couleur:Integer;
 public
   procedure Ouvrir;virual;override;
   procedure Fermer;virtual;override;
   procedure SetCouleur(Coul:Integer);
   function  GetCouleur:Integer;
end;

Après les avoir surchargés, on a 2 possibilités, ajouter du code à celui existant ou réécrire complètement la 
méthode. Si on ajoute du code, il faut mettre le mot inherited. Dans le cas contraire, on inscrit le code qu'on désire.

procedure Open;
begin
  inherited;
  GetCouleur;
end;

Tout le code de la méthode open de la classe TGameBoy est exécuté plus le nouveau bout
de code. Nul besoin de tout recopier le code, ajouter un seul mot suffit.

Polymorphisme

Le polymorphisme permet d'appeler une méthode commune à un groupe d'objet (héritage). Nul de besoin de se soucier de la classe à appeler, le programme détermine dynamiquement quelle méthode appelée selon la méthode.

Méthode abstraite

Les méthodes abstraites sont très importantes pour profiter pleinement du polymorphisme. Le mot abstract est utilisé en Delphi pour une classe déclarée mais non défini dans une classe ancêtre. Seulement ses sous-classes la définiront. Dans l'exemple antérieur sur les formes, TForme pourrait avoir une méthode dessiner mais elle ne serait pas définie. Rectangle, Oval, ligne... auraient aussi cette méthode pleinement définie. Alors si nous créons un tableau de TForme et que nous y insérons des rectangles, carrés, cercles... En appelant la méthode dessine de TForme, on pourrait dessiner toutes les formes sans connaître d'avance si c'est un rectangle, cercle carré.

Un programme est disponible ici

Nous pouvons remarquer dans ce programme que la méthode dessine est déclarée abstract. Comme je l'ai dit, une méthode abstract doit seulement être déclarée. Les autres héritent de TForme. Elles doivent mettre le mot override à leurs méthodes dessiner, on peut ensuite les définir. Regardez ce code assez simple (j'ai tout mis dans la même unité) et essayé de le comprendre.

jeudi 11 octobre 2001

Comment fermer une application par son nom?

Comment fermer une application par son nom?
function KillApp(const sCapt: PChar) : boolean;
 var AppHandle:THandle;
begin
 AppHandle:=FindWindow(Nil, sCapt);
 Result:=PostMessage(AppHandle, WM_QUIT, 0, 0);
end;

lundi 13 août 2001

Mastering Delphi 6


Excellent livre pour s'améliorer sous Delphi.
Ce livre est très intéressant aussi pour Kylix. Il y a des explications sur la vcl et clx.

Beaucoup d'informations concernant le développement sur des bases de donnée. Le côté internet n'a pas été oublié: xml, soap, websnap.

La programmation orienté objet est aussi de la partie. La création de composent fait aussi parti du livre. Le parfait livre pour du développement sérieux sous delphi et kylix. Beaucoup d'exemples sont intégrés dans ce livre.

Excellente référence.

samedi 30 juin 2001

Création d'un composant

CRÉATION D'UN COMPOSANT

Beaucoup de composants visuel et non visuel existent pour Delphi. Il peut arriver que ces composants ne nous conviennent pas pour diverses raisons. On peut alors utiliser le composant existant et lui ajouter des fonctionnalités. Nous allons créer un composant qui défilera du texte à l'écran, un peu à la manière d'un générique au cinéma. Le composant fonctionnera sous Windows et Linux grâce à la CLX.

Nous allons utiliser l'expert Delphi pour créer le squelette du composant. Il faut cliquer dans le menu «component», ensuite cliquez sur «New component...». L'expert Delphi apparait, on doit sélectionner l'ancêtre de notre composant, c'est à dire son parent. Notre composant héritera de ses fonction et méthode. L'ancêtre de notre composant est le TCustomPanel et le nom de la classe choisie est TUnitTextSequence.


Squelette du composant

Lorsqu'on valide, Delphi nous génère le code.



La procédure Register permettra à notre composant d'être inséré dans la liste des composants disponible sous delphi. Le composant se trouvera dans l'onglet Sample. Vous pouvez modifier cette valeur pour le mettre dans un autre onglet.

Champs

Afin de rendre le composant un peu plus intéressant, quelques champs sont ajoutés au composant. Une image de fond, la vitesse de défilement du texte ainsi que le texte sont des éléments de la classe. Ces champs sont privés afin de ne pas être utilisé directement par une autre classe externe à l'unité.

private
     FAlignment:TAlignment;           //alignement du texte
     FFond:TPicture;                  //image de fond pour le composant
     FTexte:TStringList;              //ligne pour l'animation
     FSpeedMove:Integer;              //Vitesse que le texte bougera
     FTimer:TTimer;                   //Le timer pour l'animation
     FMinMove:Integer;                //Point le plus haut où l'animation peut aller
     FMaxMove:Integer;                //Point le plus bas où l'animation peut se rendre
     FMove:Integer;                   //Le déroulement courant au millième de pixel près

Procédure

Ces champs doivent pouvoir être modifié. Leur valeur doit être changée. Nous allons créer quelques procédures qui permettront de modifier la valeur de certains champs.

protected
    { Déclarations protégées }
     procedure FondItemChange(ASender:TObject); {Quant FFond ou FItems sont modifiés}
     procedure SetAlignment(AAlignment:TAlignment);
     procedure SetFond(AFond:TPicture); virtual; {Losrqu'une affectation à Fond est fait: réf. property Fond}
     procedure SetTexte(ATexte:TStringList); virtual; {Lorsqu'une affecation à Items est effectuée: réf. property Items}
     procedure SetSpeedMove(ASpeedMove:integer); {Losrque l'utilisateur effectue un changement de vitesse de déroulement}
     procedure TimerTimer(Sender:TObject);virtual; {Quant FTimer a un événement selon l'intervalle de temps}

Propriété

Une propriété définie un attribut d'un objet. Elle permet d'associer une action à la lecture et modification de ses données Ces propriétés sont affichées dans l'inspecteur d'objet, car elles sont déclarées «published».

published
    { Déclarations publiées }
     property Alignment:TAlignment read FAlignment write SetAlignment;
     property Color;
     property Font;
     property Fond:TPicture read FFond write SetFond;
     property Texte:TStringList read FTexte write SetTexte;
     property SpeedMove:integer read FSpeedMove write SetSpeedMove;

Initiation du composant

Tel que vue dans le tutoriel sur la programmation orientée objet, un objet doit être initialisé avant d'être utilisé. Un constructeur doit être créé.

public
    { Déclarations publiques }
     constructor Create(AOwner:TComponent); override;
     destructor Destroy;override;
     procedure Paint; override; {la méthode responsable du redessinement}
     procedure SetBounds(ALeft,ATop,AWidth,AHeight:Integer); override; {Pour réactualiser la zone virtuelle de 
     déroulement sur un redimensionnement du composant}
     procedure SetRect1(var R: TRect; xLeft, yTop, xRight, yBottom: integer);

Dans la partie implémentation
constructor TTextSequence.Create(AOwner:TComponent);
begin
  inherited Create(AOwner); {Appele de méthode de son parent}
  FAlignment:=taCenter;
  Height:=150;
  Width:=100;
  FFond:=TPicture.Create;
  FTexte:=TStringList.Create;
  FTimer:=TTimer.Create(self);
  FFond.OnChange:=FondItemChange;  {Quand l'image de fond change, alors appelle de notre méthode FondItemChange}
  FTexte.OnChange:=FondItemChange; {Même chose pour les lignes d'animation}
  FMove:=0; {point de départ de l'animation au début}
  FTimer.OnTimer:=TimerTimer; {notre méthode TimerTimer sera appelée par FTimer}
  FTimer.Interval:=75; {1 = 1 ms environ}
  SpeedMove:=500; {vitesse de départ par défaut: peut-être autre chose si tu veux}
end;

Destuction du composant

Les éléments que nous avons créés dynamiquement doivent être libéré. Nous en avons créé 3 dans le constructeur.

destructor TTextSequence.Destroy;
begin
  FFond.Free;
  FTexte.Free;
  FTimer.Free;
  inherited Destroy;  {Appele le destructeur hérité}
end; 

Méthode

Le composant possède quelques méthodes, nous allons-nous attarder sur la méthode de dessinèrent. Cette méthode permet de rafraîchir le composant. Puisque le texte défile, le composant doit être constamment rafraichi.

procedure TTextSequence.Paint;
var
  DrawLine:integer;
  i:integer;
  Bitmap:TBitmap;
  Rectangle:TRect;
begin
  Bitmap:=TBitmap.Create;
  Bitmap.Width:=Width;     {largeur du bitmap}
  Bitmap.Height:=Height;   {Hauteur du bitmap}
  Bitmap.Canvas.Brush.Style:=bsSolid;
  Bitmap.Canvas.Brush.Color:=Color;
  SetRect1(Rectangle,0,0,ClientWidth,ClientHeight);
  Bitmap.Canvas.FillRect(Rectangle);
  if Assigned(FFond.Graphic) then
    if not FFond.Graphic.Empty then
      Bitmap.Canvas.StretchDraw(Rectangle,FFond.Graphic);
  Bitmap.Canvas.Brush.Style:=bsClear;
  Bitmap.Canvas.Font.Assign(Font);
  if FTexte.Count>0 then begin {si on a des lignes en animation}
    DrawLine:=FMove div 1000; {Nous conservons le déplacement au millième près}
    for i:=0 to Pred(FTexte.Count) do
    begin
      {calculs de l'affichage de la prochaine ligne d'animation}
      DrawLine:=DrawLine+Bitmap.Canvas.TextHeight(FTexte[i]);
      {si l'affichage est visible} 
      if (DrawLine>-Bitmap.Canvas.TextHeight(FTexte[i])) and (DrawLine<Height)  then
         case Alignment of
              TALeftJustify: Bitmap.Canvas.TextRect(Rectangle,Rectangle.Left+2,DrawLine,FTexte[i]);
              TARightJustify:Bitmap.Canvas.TextRect(Rectangle,
                Rectangle.Right-Bitmap.Canvas.TextWidth(FTexte[i])-2,DrawLine,FTexte[i]);
              TACenter:Bitmap.Canvas.TextRect(Rectangle,(Width div 2)-
                (Bitmap.Canvas.TextWidth(FTexte[i]) div 2),DrawLine,FTexte[i]);
         end;
    end;
  end;
  Canvas.Draw(0,0,Bitmap);{Dessine le bitmap en mémoire sur le canvas}
  Bitmap.Free;           {Libère l'objet de la mémoire}
end;

La méthode commence par créer un Bitmap, il servira à afficher le 
texte. On créer une zone de la dimension
du contrôle. On vérifie s'il a mouvement, on calcule la prochaine ligne 
et on ajuste l'alignement. Il est
possible d'augmenter la fluidité en diminuant la valeur du déplacement. 
Par défaut c'est 1000, une valeur plus faible
peut être mise. De plus, il est possible d'augmenter la valeur de 
l'intervalle du timer. Le composant se redessinera moins souvent
avec une valeur plus élevée.

Vous pouvez remarquer dans le code, que la méthode invalidate est utilisée. Cette méthode permet de redessiner le contrôle. La méthode paint à été définie comme override. Le composant n'appellera donc pas la méthode pain du parent du composant, mais cette qu'on a redéfini.

Au fur à mesure qu'on code un programme, on y décèle des problèmes. Afin de diminuer d'éventuel problème avec les composants existants, vous pouvez utiliser le composant tel qu'un objet. Il suffit de créer un programme, d'y ajouter l'unité de votre composant et de l'utiliser. Dans l'exemple ci-dessous, nous utilisons un trackbar pour diminuer ou augmenter la vitesse. La vitesse courante est affiché dans un label.



Lorsque vous pensez que votre composant être excent de problème, vous pouvez l'installer dans l'edi de Delphi. Il suffit de cliquer dans le menu Component ensuite sur Install component. Vous spécifiez le nom de l'unité. Le composant trouve alors dans l'onglet spécifié par la méthode register. Une fois que le composant est installé, vous n'avez qu'à le glisser sur la fiche pour l'utiliser.



Il est sage d'étudier les composants existants, les modifier afin dans créer de nouveau. Nous avons vue comment créer un composant visuel. D'autres fonctionnalités pourraient être ajoutées. Pratiquez-vous!

Un programme utilisant le composant est disponible ici

Je remercie Daniel Drouin de m'avoir initié à la programmation sous Delphi et de m'avoir initié à la programmation de composant à l'aide de cet exemple.

lundi 28 mai 2001

Comment rendre certaine touches inactive

Comment rendre certaine touches inactive
L'exemple ci-dessus désactive les touches ALT+TAB, CTRL+ESC, CTRL.
procedure SystemKeys(Disable: Boolean);
 var OldVal : LongInt;
begin
 SystemParametersInfo(SPI_SCREENSAVERRUNNING,
                      Word(Disable), @OldVal, 0);
end;

mercredi 2 mai 2001

Comment changer le clavier de la console?


Comment changer le clavier de la console?

Sous suse: regarder dans: /usr/share/kbd/keymaps/ (chercher où se trouve keymaps pour les autres distributions) si le clavier désiré est là sinon tenter de le trouver ensuite allez dans:

/etc/sysconfig/keyboard et mettez le nom du claiver désiré par exemple :
KEYTABLE="cf.map.gz"

Le numlock, capslock... peut être mis à on par défaut lors du démarrage à partir de ce fichier.

lundi 26 février 2001

Recherche


LES RECHERCHES

Nous utilisons différents types de recherche pour trouver des données spécifiques. Nous verrons qu'il y a divers types de recherche qui peuvent être faites.

Type de recherche

La recherche séquentielle

La recherche séquentielle consiste à vérifier du début  du tableau, liste... jusqu'à ce qu'on trouve ce qu'on désire ou parcoure totalement le tableau liste... C'est évidemment pas la recherche la plus efficace. Ce type de recherche est doit être utilisé si le tableau n'est pas trié.
//on définit les variables utilisées
Const
  Max=15;
  type
    tabType = array [1..Max] of integer;
function SequentialSearch(tab:tabType; item:integer):integer;
var
  i : integer;
  found : boolean;
begin
  SequentialSearch := 0;
  i := low(tab);
  found := false;
  while( i <= high(tab)) and (not found) do
  begin
    if tab[i] = item then
    begin
      SequentialSearch := i;
      found := true;
    end;
    inc(i);
  end;
end;

La recherche binaire

La recherche séquentielle consiste à comparer la valeur recherché par le milieu du vecteur.Si cet élément est plus grand que l'élément recherché, ce dernier est à gauche sinon à droite. On répète l'opération sur les sous-vecteurs. Le tableau doit évidemment être trié pour tirer parti de ce type de recherche

function BinarySearch(tab:tabType; item:integer):integer;
var
  Milieu:integer;
  Found:boolean;
  bas:integer;
  haut:integer;
begin
  bas := low(tab);
  haut := high(tab);
  Found := False;
  BinarySearch := 1;
  while(bas <= haut) and (not Found) do
  begin
    Milieu := (bas + haut) div 2;
    if tab[Milieu] = item then
    begin
      Found := True;
      BinarySearch := Milieu;
    end
    else
      if tab[Milieu] < item then
        bas := Milieu + 1
      else
        haut := Milieu - 1;
  end;
end;

jeudi 22 février 2001

Matrice

MATRICE

Une matrice est un genre de tableau
2 44 69
15 71 8
562 3 9
128 67 564
L'exemple précédent est une matrice 4 * 3 (4 lignes, 3 colonnes). Il est bien sûr possible de mettre des chiffres à virgule flottante dans une matrice. Diverses opérations peuvent être effectuées sur les matrices, c'est ce qu'on verra.

Opérations sur les matrices

Produit

Pour effectuer cette opération, il faut que le nombre de colonnes de la matrice A soit supérieur ou étal au nombre de ligne de la matrice B.

Matrice A

1 2 3
4 5 6

Matrice B

1 2
3 4
5 6
La multiplication de A et B donnera

Matrice A*B

1 2
22 28
49 64

Pour parvenir à ce résultat, il faut faire faire multiplier la ligne de la matrice A * la colonne de la matrice B.
Donc on a (1*1) + (2*3) + (3*5) , (1*2)+(2*4)+(3*6) , (4*1)+(5*3)+(6*5),(4*2)+(5*4)+(6*6).

Type
  matrice1=array[1..2,1..3]of integer;
  matrice2=array[1..3,1..2]of integer;
  matrice=array[1..high(matrice1),1..high(matrice2)]of integer;

function Produit(Mat1:matrice1;Mat2:Matrice2):matrice;
var
  i,j,k:integer;
  Mat3:matrice;
begin
for i:=1 to high(Mat1) do
  for j:=1 to high(Mat1) do
    begin
    Mat3[i,j]:=0;
    for k:=1 to high(Mat2) do
      Mat3[i,j] := Mat3[i,j]+Mat1[i,k]*Mat2[k,j];
    end;
    result := Mat3;
end;

Addition de matrice

L'addition de matrice est simple, il suffit d'additionner les valeurs des deux matrices qui sont situées au même endroit. Les matrices doivent être de même dimensions

Matrice A

1 2
3 4

Matrice B

5 6
7 8
On addition 1 avec 5, 2 avec 6 , 3 avec 7 et 4 avec 8 pour obtenir
6 8
10 12
Voici le code de la fonction
type
  matrice=array[1..2,1..2]of integer;

function Addition(Mat1:,Mat2:matrice):matrice;
var
  i,j:integer;
  Mat3:matrice;
begin
  for i:=1 to high(Mat1) do
    for j:=1 to high(Mat1) do
      Mat3[i,j] := Mat1[i,j]+ Mat2[i,j];
    result:=matc;
end;
Le principe de la soustraction est le même. Il suffit de remplacer le + par un - dans l'algo ci-dessus.

Produit boolean

Cette opération ressemble au calcul de matrice.Pour effectuer cette opération, il faut que le nombre de colonnes de la matrice A soit supérieur ou étal au nombre de ligne de la matrice B. Puisque c'est boolean, les éléments des matrices que peuvent avoir que des 0 ou des 1 comme valeur.

Matrice A

1 0 1
1 0 0
0 0 0

Matrice B

1 0 0
0 1 0
1 0 0

Le principe ressemble à la multiplication de deux matrices. On remplace les plus par des ou logiques. L'utilisation des ou logique implique qu'aussitôt qu'on retrouve 1*1, ça donnera 1.

Donc on a (1*1 ou 0*0 ou 1*1) ça donne 1. Puisqu'on a 1*1 et que c'est ou, on aurait pu arrêter à 1*1. Le résultat final donnera

1 0 0
1 0 0
0 0 0

Voici le code de la fonction pour calculer le produit boolean

type
  matrice=array [1..3,1..3] of integer;

function ProduitBoolean(matrice1,matrice2:matrice):matrice;
var
  i,j,k:integer;
  ok:boolean;
  matrice_result:matrice;
begin
  ok := false;
  for i:=1 to high(matrice1) do begin
    for j:=1 to high (matrice1) do
    begin
      for k:=1 to high(matrice1) do
        if (matrice1[i][k] = 1 ) and (matrice2[k][j]=1) and not(ok)then
          ok := true;
      if ok then
        matrice_result[i][j]:=1
      else
        matrice_result[i][j]:=0;
      ok := false;
    end;
  end;
  result := matrice_result;
end;

lundi 29 janvier 2001

Chaine de caractère

CHAÎNE DE CARACTÈRE

Type de chaîne

Chaîne courte

Les chaînes courtes ont une longueur fixe, elles ne peuvent dépasser plus de 255 caractères. Étant donné que les chaînes courtes ont une valeur fixe, leurs vitesses d'exécution sont très rapides. On peut les déclarer de deux façons, mais une seule est vraiment utile.

var
   Nom:shortstring;
   Prenom:string[30];

Lorsqu'on utilise shortstring, la longueur de la variable est automatiquement de 255 caractères. A moins d'avoir absolument besoin de 255 caractères, il n'est pas vraiment intéressant d'utiliser le type shortstring. Il est intéressant d'utiliser les chaînes courtes lorsqu'on sait que la longueur de la variable sera fixe ou que l'on sait le nombre de caractère maximum qu'il peut y avoir.

Le gain de vitesse sera appréciable si l'on fait beaucoup de manipulation sur les chaînes. Le premier élément d'une chaîne courte représente la longueur de la chaîne, ce qui peut s'avérer intéressant dans certaines situations.

Chaîne longue

Les chaînes longues sont allouées dynamiquement. Leur longueur est limitée à la taille de votre mémoire disponible. Tout le traitement pour allonger et réduire la taille de la chaîne est fait en coulisse, mais on perd un peu de vitesse.

var
  Nom:string;
  Prenom:string;

Les chaînes longues n'ont pas d'élément zéro.

Chaîne à zéro terminal

Ce type de chaîne est très utilisé lorsqu'on doit utiliser les fonctions de Windows. Les fonctions de Windows utilisent des tableaux de caractères (langage c) et utilisent donc un 0 à la fin de la chaîne afin de marquer la fin de la chaîne. On doit utiliser le type PChar lorsqu'on manipule les fonctions de windows ou bien faire de la conversion.

var
  libelle : string;
begin
  libelle := 'Bonjour'; messagebox (0, PCHAR(libelle), 'Message', mb_ok);
end;

Ce code utilise un api (très simple) afin d'afficher une boîte de message

Routine de gestion de chaîne

Voici quelques fonctions et procédures disponibles, il en existe de nombreuses autres.

Routines de traitement de chaîne AZT


Fonction Description
StrAlloc Alloue une zone tampon d'une taille donnée sur le tas.
StrBufSize Renvoie la taille d'une zone tampon de caractère alloué en utilisant StrAlloc ou StrNew.
StrCat Concatène deux chaînes.
StrComp Compare deux chaînes.
StrCopy Copie une chaîne.
StrDispose Dispose une zone tampon de caractère allouée en utilisant StrAlloc ou StrNew.
StrECopy Copie une chaîne et renvoie un pointeur à la fin de la chaîne.
StrEnd Renvoie un pointeur à la fin d'une chaîne.
StrFmt Formate une ou plusieurs valeurs dans une chaîne.
StrIComp Compare deux chaînes sans tenir compte des majuscules/minuscules.
StrLCat Concatène deux chaînes avec une longueur maximum donnée de la chaîne résultante.
StrLComp Compare deux chaînes pour une longueur maximum donnée.
StrLCopy Copie une chaîne jusqu'à une longueur maximum donnée.
StrLen Renvoie la longueur d'une chaîne.
StrLFmt Formate une ou plusieurs valeurs dans une chaîne avec une longueur maximum donnée.
StrLIComp Compare deux chaînes pour une longueur maximum donnée sans tenir compte des majuscules/minuscules.
StrLower Convertit une chaîne en minuscules.
StrMove Déplace un bloc de caractères d'une chaîne sur l'autre.
StrNew Alloue une chaîne sur le tas.
StrPCopy Copie une chaîne Pascal vers une chaîne à zéro terminal.
StrPLCopy Copie une chaîne Pascal vers une chaîne AZT avec une longueur maximum donnée.
StrPos Renvoie un pointeur sur la première occurrence d'une sous-chaîne donnée dans une chaîne.
StrRScan Renvoie un pointeur sur la dernière occurrence d'un caractère donné dans une chaîne.
StrScan Renvoie un pointeur sur la première occurrence d'un caractère donné dans une chaîne.
StrUpper Convertit une chaîne en majuscules.

Routines de traitement de chaînes shortstring (chaîne Pascal)


Fonction Description
AdjustLineBreaks Transforme les ruptures de lignes dans une chaîne en séquences CR/LF.
AnsiCompareStr Comparaison, en tenant compte des majuscules/minuscules, de deux chaînes.
AnsiCompareText Comparaison, sans tenir compte des majuscules/minuscules, de deux chaînes.
AnsiLowerCase Convertit des caractères en minuscules.
AnsiUpperCase Convertit des caractères en majuscules.
CompareStr Comparaison, en tenant compte des majuscules/minuscules, de deux chaînes.
CompareText Comparaison, sans tenir compte des majuscules/minuscules, de deux chaînes.
Concat Concatène une suite de chaînes.
Copy Renvoie une sous-chaîne d'une chaîne.
Delete Efface une sous-chaîne d'une chaîne.
DisposeStr Libère une chaîne du tas.
FmtLoadStr Charge une chaîne dans la ressource table de chaînes d'un programme.
Insert Insère une sous-chaîne dans une chaîne.
IntToHex Convertit un entier en hexadécimal.
IntToStr Convertit un entier en chaîne.
IsValidIdent Renvoie True si la chaîne spécifiée est un identificateur valide.
Length Renvoie la longueur dynamique de la chaîne.
LoadStr Charge la ressource chaîne depuis le fichier exécutable de l'application.
LowerCase Met en minuscule la chaîne spécifiée.
NewStr Alloue une nouvelle chaîne dans le tas.
Pos Recherche une sous-chaîne dans une chaîne.
Str Convertit une valeur numérique en chaîne.
StrToInt Convertit une chaîne en entier.
StrToIntDef Convertit une chaîne en entier ou à une valeur par défaut.
Trim Supprime les espaces de début et de fin et les caractères de contrôle d'une chaîne donnée.
TrimLeft Supprime les espaces de début et les caractères de contrôle d'une chaîne donnée
TrimRight Supprime les espaces de fin et les caractères de contrôle d'une chaîne donnée.
UpperCase Met en majuscule la chaîne spécifiée.
Val Convertit une valeur chaîne en sa représentation numérique.

StringList

Les stringlist permettent de gérer un tableau de phrase. Chaque ligne du tableau peut être accédées grâce à son index.

De nombreuses opérations peuvent être effectuées sur les stringlist: insertion, effacement, comparaison...

La création d'une stringlist est très aisée.

lstNom : TStrings; 
// Déclaration de TStrings au lieu de TStringList 
//pour des d'utilisations de paramatètres de la vcl.
//Création d'une instance de TStringList
lstNom := TStringList.Create;
//Ajout de chaîne dans la liste
lstNom.Add('Paul Smith');
lstNom.Add('Renée');
lstNom.Add('Nicolas');
Nom:=lstNom[2];
//insertion de plage dans la variable nom
insert('plage',Nom,3);
lstNom[2]:=Nom;

Les routines de traitement peuvent être facilement effectuées sur les stringslist.

Comment chercher et remplacer des caractères?

Comment chercher et remplacer des caractères?
function SearchAndReplace
  (sSrc, sLookFor, sReplaceWith : string) : string;
var
  nPos, nLenLookFor : integer;
begin
  nPos        := Pos(sLookFor, sSrc);
  nLenLookFor := Length(sLookFor);
  while (nPos > 0) do begin
    Delete(sSrc, nPos, nLenLookFor);
    Insert(sReplaceWith, sSrc, nPos);
    nPos := Pos(sLookFor, sSrc);
  end;
  Result := sSrc;
end;

dimanche 14 janvier 2001

Comment vérifier si un fichier est utilisé?

Comment vérifier si un fichier est utilisé?
function IsFileInUse(fName : string) : boolean;
var
   HFileRes : HFILE;
begin
   Result := false;
   if not FileExists(fName) then exit;
   HFileRes :=
     CreateFile(pchar(fName),
                GENERIC_READ or GENERIC_WRITE,
                0, nil, OPEN_EXISTING,
                FILE_ATTRIBUTE_NORMAL,
                0);
   Result := (HFileRes = INVALID_HANDLE_VALUE);
   if not Result then
   CloseHandle(HFileRes);
end;

vendredi 5 janvier 2001

Learn Pascal

Delphi est basé sur pascal, alors autant le connaître. Bien connaître le pascal, facilitera le développement sous delphi. 

Les routines de bas niveau du pascal nous serons présentées afin d'optimiser au mieux notre code delphi. La qualité de ce livre est phénoménale, on lit et on comprend aussitôt tellement que les exemples sont compréhensifs. De nombreux aspects que les autres livres oublient trop souvent d'expliquer sont précisés dans cet ouvrage: pointeur, tri de donnée, recherche de données... 

Ces aspects sont très bien détaillés, ce qui m'a vraiment surprit, car ce sont des concepts complexes à apprendre. 

C'est un livre en anglais, qui est aisé à lire et qui s'adresse à celui qui veut approfondir ses connaissances afin d'améliorer son code. Après la lecture de ce livre, les côtés sombres de Delphi vous sembleront plus claire. Le livre inclut une version complète de Delphi 4 standard.

mardi 2 janvier 2001

Dll

DLL

Les dll (dynamic link library) sont très répandues dans la programmation Windows. Une dll est en fait une portion de code exécutable d'un fichier ayant une extension dll. N'importe quel programme peut faire appel à une dll.

Avantage d'une dll

  • Réutilisation du code
  • Partage du code entre plusieurs applications
  • Fractionnement du code
  • Meilleure gestion des ressources de Windows

Création d'une dll

Allez dans le menu File, cliquer sur New..., choisisez Dll



Syntaxe d'une dll


library Calculer;
uses
  SysUtils,
  Classes;
var //déclaration des variables
  TPS: double;
  TVQ: double;
  
//déclaration de la fonction
function CalculerTotal(Somme:double):double;register;
begin
  Somme := Somme * TPS + Somme;
  Somme := Somme * TVQ + Somme;
  Result := Somme;
end;

//exportation de la fonction afin de pourvoir l'utiliser dans les programmes
exports
  CalculerTotal;
  
//initialisation des variables
//peu pratique étant donné que la valeur des taxes peuvent changer
begin
  TPS:=0.07;
  TVQ:=0.065;
end.
Pour créer la dll, allez dans le menu project et cliquez sur build «nom du projet»

Portée d'une fonction ou procédure

Les fonctions et les procédures peuvent être locaux ou exportées à une dll.

Locale

Les fonctions et procédures locaux ne peuvent être utilisées qu'à l'intérieur de la dll. Il est imppossible d'y faire référence à l'extérieur de celle-ci donc aucun programme ne peut l'appeler.

Exporté

Les fonctions et procédures exportées peuvent être utilisées à l'extérieur de la dll. Les programmes peuvent appeler une telle fonction ou procédure.
Le code source ci-dessus utilisait une fonction exportée
Le mot Exports ainsi que le nom de la fonction doivent être inscrits
exports CalculerTotal;

Les deux types de fonction et procédure peuvent être utilisées simultanément dans une dll.

Chargement d'une dll

En delphi, il existe deux types de chargement pour une dll
  • Chargement statique
  • Chargement dynamique

Chargement statique

Lorsque l'application démarre la dll est automatiquement exécuté. Elle reste en mémoire tout au long de l'exécution du programme. Elle est simple d'utilisation. Il suffit d'ajouter le mot external à la procédure ou fonction afin de l'utiliser.

function CalculerTotal(Somme:double):double;register; external 'Calculer.dll';
Si la dll n'est pas trouvée, le programme ne pourra s'exécuter.

Code source disponible ici

Chargement dynamique

La dll est chargé en mémoire selon vos besoins. Sa mise en oeuvre est beaucoup plus complexe car vous devez charger et décharger la dll de la mémoire. La mémoire est utilisée plus adéquatement et l'application fonctionne plus rapidement. Il y a quelques règles que le programmeur doit suivre afin que tout fonctionne correctement.
  • Déclarer un type qui décrit la fonction ou la procédure
  • Charger la fonction ou procédure
  • Récupérer l'adresse de la fonction ou procédure
  • Appeler la fonction ou procédure
  • Décharger la fonction ou procédure

Déclarer un type qui décrit la fonction

TypeTCalculerTotal = function(Somme:double):double;

Charger la fonction ou procédure

dllInstance := loadlibrary('Calculer.dll');

Récurpérer l'adresse de la fonction

@CalculerTotal :=getprocaddress(dllInstance,'Calculerotal');

Appeler la fonction

Somme:=CalculerTotal(Somme);

Décharger la fonction

freelibrary(dllInstance);

L'allocation dynamique exige plus de travail, mais les ressources mémoires sont mieux gérées. 
Si on doit faire usage de la dll tout au long du programme, l'allocation statique est préférable. 

N'oubliez pas d'utiliser les block try except et try finally pour éviter les erreurs
Code source disponible ici

Méthode d'appel de fonction et procédure
Il existe quelques conventions pour appeler une fonction ou procédure. Comme vous avez pu remarquer dans la section chargement statique, j'ai utilisé le mot register pour appeler la fonction.

Sommaire des conventions d'appels


Directive Ordre de paramètre Utilité
register Gauche - Droite La plus efficace, évite des accès sur la pile
pascal Gauche - Droite Comptabilité antérieure
cdecl Droite - Gauche Utilisé pour les appels de dll écrite en c, c++
stdcall Droite - Gauche Appel pour les api Windows
safecall Droite - Gauche Appel pour les api Windows

Exportation de chaîne de caractère

Les dll créer à l'aide de Delphi peuvent être utilisé dans d'autre langage. Pour cette raison, on ne peut utiliser n'importe qu'elle type de donnée. Les types qui existe en Delphi n'existe pas nécessaire sous d'autre langage. Il est préférable d'utiliser des types de données natif de Linux ou Window. La dll pourra ainsi être utilisé par d'autre programmeur qui utilise d'autre langage que celui que nous utilisons.

Il est possible d'utiliser les strings et les dynamic array de Delphi dans une dll. Il faut inclure l'unité ShareMem dans la dll et le programme qui l'utilise. De plus cette unité devra être la première dans chaque fichier du projet. Il faut être certain que la dll sera utilisé que dans delphi sinon des problèmes surviendront.

Les strings telle que nous les connaissons n'existe pas en C, C++... nous utiliserons alors les PChar.

PChar

Les PChar ont leur premier caractère à l'indice zéro contrairement au string qui commmence à 1. Un PChar est une chaîne de tableau de caractère qui se termine par Nul (#0). Qui a dit C? Aussitôt que le caractère nul est trouvé c'est la fin de la chaîne.
Nous allons créer un exemple afin de montrer l'utilisation de string dans une dll. Le programme envoirera une string à la dll. Cette dll mélangera les caractères et retournera la string au programme.

Voici le code de la dll
library mixstr;

uses
  SysUtils,
  Classes;

{$R *.res}

Function MixToStr(StrText:PChar):Pchar;stdcall;
var
  i, j : Integer;
  c1   : Char;
Begin
  For i:=Length(StrText)-1 downto 0 Do
  Begin
    j:=Random(i)+1;
    c1:=StrText[i];
    StrText[i]:=StrText[j];
    StrText[j]:=c1;
  End;
  result := StrText;
End;

exports
  MixToStr;

begin
end.
Voici le code du programme
var
  Form1: TForm1;
  function MixToStr(str:PChar):PChar;stdcall; external 'mixstr.dll';

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
   edtRecu.Text := MixToStr(pchar(edtEnvoyer.Text));
end;
 

Code source disponible ici