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

Technique : les Patch Files sous C++ Builder

Ce tutoriel démontre une des techniques utilisées pour mettre à jour des fichiers exécutables à l'aide des File Mapping avec un exemple d'application.

Sources du Programme disponible ici. ♪

Article lu   fois.

L'auteur

Profil ProSite personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Programme d'exemple

pour démontrer une des techniques des PatchFiles, je vous propose une application basique permettant de patcher un fichier exécutable ou une Dll.

I-A. Limitation

Ce programme est écrit en C++ à l'aide de C++ Builder 6.

Dans ce programme sont utilisées certaines fonctionnalités VCL qui rendent la partie GUI non portable sur un autre compilateur, l'adaptation du code est par contre possible.

II. Définition du GUI

Image non disponible

II-A. définition de la forme principale

Pour commencer, nous allons définir la forme principale.

Déposer les composants suivants sur une Form

Composant

Nom

1 TPanel

Align = alClient

1 TGroupBox

GroupBox1

1 TMainMenu

MainMenu1

1 TOpenDialog

OpenDialog1

1 TActionManager

ActionManager1

1 TStatusBar

StatusBar1

Déposer les Composants suivants sur le GroupBox

1 TLabeledEdit

edOldFile

1 TLabeledEdit

edNewFile

1 TBitBtn

BitBtn1

1 TBitBtn

BitBtn2

II-B. ImageList

Nous allons charger les images dans le composant ImageList1, sélectionner quatre images dans le répertoire fichiers communs de Borland comme dans la copie d'écran ci-dessous :

Image non disponible

II-C. ActionsList

Création des actions

Ouvrir le composant ActionManager1.

Touche droite de souris sur le composant, cliquer sur Personnaliser.

créer les actions suivantes

nom de l'action

Caption

Image index

OnExecute

OpenOlDfile

Open File

0

OpenOlDfileExecute

OpenPatchName

Open Patch File

0

OpenPatchNameExecute

Make

Make

3

MakeExecute

About

About

1

AboutExecute

CloseApp

Close

2

CloseApp

le résultat devrait être le suivant :

Image non disponible

II-D. ActionToolBar

Nous allons créer maintenant une action ToolsBar.

Dans le composant ActionManager, activer l'onglet Barre d'outils.

Presser le bouton Nouvelle.

Le résultat devrait être le suivant :

Image non disponible

Dans la vue arborescente des objets, placer le curseur de la souris sur ActionBars, clic touche droite de la souris sur ajouter un élément dans l'ActionToolbar nouvellement créé, placer le curseur de la souris sur l'élément Items puis créer cinq nouveaux éléments les noms donnés aux éléments sont les suivants

nom de l'élément

Action

TActionClients[0]

OpenOlDfile

TActionClients[1]

OpenPatchName

TActionClients[2]

Make

TActionClients[3]

About

TActionClients[4]

Close

II-E. Menu Principal

Création d'un menu selon l'image suivante :

Image non disponible

Donner aux Items Actions les valeurs suivantes :

Item

Action

OpenFile1

OpenOlDfile

OpenPatchFile1

OpenPatchName

Make1

Make

Close1

Close

About1

About

II-F. Boutons divers

Donner aux actions de boutons les valeurs suivantes :

Item

Action

BitBtn1

Make

BitBtn2

Close

Le design de l'application est maintenant terminé.

III. Classe TMMF

la Classe TMMF a été expliquée dans mon tutoriel utilisation des files Mappping https://djmsoftware.developpez.com/FileMapping.

III-A. Modification de la classe TMMF

j'ai modifié l'implémentation de la classe TMMF pour lui ajouter de nouvelles fonctionnalités.

Liste des éléments modifiés ainsi que leur signification :

Type

Nom

partie

détail

Champ

FMapFileSizeLow

private

indique la taille basse de la zone mappée

Champ

FMapFileSizeHigh

private

indique la taille haute de la zone mappée

champ

FMapFileOffset

private

contient la différence de taille par rapport au fichier d'origine

Champ

FBigger

private

indique si la taille du Patch est plus grande que la taille d'origine

Constructeur

TMMF(AnsiString FileName, long size, bool Bigger)

public

initalize FMapFileOffset et FBigger

III-B. Modification de la classe TMMF

la méthode Execute est modifiée comme suit

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
bool __fastcall TMMF::Execute()
{
   try 
   {
      GetFile();
      GetSizeofFile();
      if (FMapFileOffset==0)
      FMapFileOffset=FFileSize;
      if (FBigger)
      FMapFileSizeLow=FFileSize+FMapFileOffset;
      else 
      FMapFileSizeLow=FMapFileOffset;
      FMapFileSizeHigh=FFileSizeHigh;
      GetMapping();
      GetPtrAdresse();
      }
   catch (EOSError &E)
   {
      FErrorMsg=E.Message;
      return false;
      }
   return true;
   }

On va initialiser le champ FFileSize avec l'appel à GetSizeofFile.

On teste le contenu de FmapFileOffset, s'il est égal à 0, alors on initialise MapFileOffset à la valeur de FfileSize. Si la variable FBuffer est vraie alors FMapFileSizeLow devient égale à FFileSize+ FmapFileOffset, sinon FMapFileSizeLow est égale à FfileSize.

La méthode GetMapping est modifiée comme suit :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
void __fastcall TMMF::GetMapping()
{
   FFileMap=CreateFileMapping(
      FFileHandle, // handle to file to map
      NULL, // optional security attributes
      PAGE_READWRITE, // protection for mapping object
      FMapFileSizeHigh, // high-order 32 bits of object size
      FMapFileSizeLow, // low-order 32 bits of object size
      NULL);
   if (!FFileMap)
   RaiseLastOSError();
   
}

IV. Classe Tform

Déclaration de la classe les champs suivants sont déclarés :

Type

Nom

partie

détail

Champ

FStreamSize

private

contient la taille du fichier Patch Mappé en mémoire

Champ

FSizeOldFile

private

contient la taille du fichier à Patcher

champ

FSizePatchFile

private

contient le taille du fichier Patch

Champ

FDiff

private

Contient la différence de taille entre les deux fichiers

Champ

FPatchIsBigger

private

Flag indiquant si le Patch est plus grand que le fichier d'origine

Champ

FoldFileName

private

Contient le nom du fichier à patcher

Champ

FPatchFileName

private

Contient le nom du fichier Patch

Les méthodes suivantes sont déclarées :

Type

Nom

partie

Méthode

bool __fastcall GetFileSize(AnsiString FileName,long* Size)

private

Méthode

void __fastcall AdjustFileSize();

private

Méthode

bool __fastcall PatchFile();

private

Méthode

void __fastcall DisplayErrorMessage(AnsiString msgE);

private

Méthode

void __fastcall ClearFields();

private

Méthode

bool __fastcall IsBigger(long* size);

private

V. Explications sur les méthodes privées

V-A. Méthode GetFileSize(AnsiString FileName,long* Size)

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
bool __fastcall TForm1::GetFileSize(AnsiString FileName,long * Size)
{
long FileSize;
int FHandle=FileOpen(FileName,fmOpenRead);
if (FHandle!=-1)
{
   FileSize=FileSeek(FHandle,0,2);
   FileClose(FHandle);
   *Size= FileSize;
   return true;
   }
else return false;
}

Cette méthode retourne true si le fichier existe le paramètre Size passé par référence retourne la taille du fichier.

V-B. Méthode AdjustFileSize()

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
void __fastcall TForm1::AdjustFileSize()
{
HANDLE FFileHandle;
FFileHandle=CreateFile(
   FoldFileName.c_str(), // pointer to name of the file
   GENERIC_READ|GENERIC_WRITE, // access (read-write) mode
   FILE_SHARE_READ|FILE_SHARE_WRITE,// share mode
   NULL, // pointer to security attributes
   OPEN_EXISTING, // how to create
   FILE_ATTRIBUTE_NORMAL, // file attributes
   NULL);

SetFilePointer(
   FFileHandle,
   FStreamSize,
   NULL,
   FILE_BEGIN);

SetEndOfFile(FFileHandle);
CloseHandle(FFileHandle);
}

Cette méthode est utilisée pour ajuster la taille du fichier patché, en effet sans cette méthode si le fichier patch et plus petit que le fichier à patcher, la taille finale du fichier patché serait trop grande.

Pour ce faire, on ouvre le fichier, avec le Handle ainsi obtenu. On appelle l'API Win32 SetFilePointer en lui indiquant où placer le pointeur de fin de fichier(EOF). On appelle ensuiteSetEndOfFile qui va ajuster le fichier à sa nouvelle taille.

V-C. Méthode PatchFile()

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
bool __fastcall TForm1::PatchFile()
{
TMMF *oldMMF,*PatchMMF;
PatchMMF= new TMMF(FPatchFileName);
if (PatchMMF->Execute())
{
   FStreamSize=PatchMMF->FileSize;
   oldMMF= new TMMF(FoldFileName,FDiff,FPatchIsBigger);
   if (oldMMF->Execute())
   {
      memcpy(oldMMF->PtrMapping,PatchMMF->PtrMapping,FStreamSize);
      delete oldMMF;
      if (!FPatchIsBigger)AdjustFileSize();
      }
   else 
   {
      MessageDlg(oldMMF->ErrorMessage, mtError, TMsgDlgButtons() << mbOK, 0);
      StatusBar1->Panels->Items[0]->Text ="Erreur lors de la copie ...";
      delete oldMMF;
      return false;
      }
   delete PatchMMF;
   }
else 
{
   MessageDlg(PatchMMF->ErrorMessage, mtError, TMsgDlgButtons() << mbOK, 0);
   StatusBar1->Panels->Items[0]->Text ="Erreur lors du traitement ...";
   return false;
   }
return true;
}

Cette méthode est la principale de l'application.

On crée tout d'abord un objet PatchMMF de Type TMMF avec en paramètre le nom du fichier Patch. Si la méthode execute de PatchMMF se termine avec succès, on initialise le champ FStreamSize avec la taille du fichier Mapping.

On créée ensuite un object oldMMF avec comme paramètre le nom du fichier, la taille,et la variable Boolean. Si la méthode execute de oldMMF se termine avec succès, il reste maintenant à copier le pointeur PatchMMF->PtrMapping dans le pointeur oldMMF->PtrMapping.

La zone mappée par OldMMF devient égale alors à PatchMMF le fichier est donc copié, il nous reste alors à libérer la mémoire.

V-D. Méthode DisplayErrorMessage(AnsiString msgE)

 
Sélectionnez
1.
2.
3.
4.
5.
void __fastcall TForm1::DisplayErrorMessage(AnsiString msgE)
{
MessageDlg(msgE, mtError, TMsgDlgButtons() << mbOK, 0);
StatusBar1->Panels->Items[0]->Text =msgE;
}

Cette méthode est utilisée pour afficher dans un message dialog ainsi que dans la barre de status le message d'erreur.

V-E. Méthode ClearFields()

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
void __fastcall TForm1::ClearFields()
{
FPatchFileName="";
FoldFileName="";
edNewFile->Text="";
edOldFile->Text="";
}

La méthode ClearFields réinitialise les variables.

V-F. Méthode IsBigger

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
bool __fastcall TForm1::IsBigger(long * size)
{
if (FSizePatchFile>FSizeOldFile)
{
   *size= FSizePatchFile-FSizeOldFile;
   return true;
   }
else 
{
   *size=FSizePatchFile;
   return false;
   }
}

Cette méthode teste si le fichier patch est plus grand que le fichier à patcher. Le paramètre Size est initialisé avec la différence de taille entre les fichiers, si la taille du patch est plus petite que le fichier à patcher Size contient alors la taille du fichier Patch.

VI. Méthodes publiées (published)

Les méthodes suivantes sont générées automatiquement par l'IDE en fonction des actions générées par le composant ActionManager.

VI-A. Méthode OpenOlDfileExecute

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
void __fastcall TForm1::OpenOlDfileExecute(TObject *Sender)
{
OpenDialog1->Title="Sélectionner le fichier à patcher";
if (OpenDialog1->Execute())
{
   edOldFile->Text=OpenDialog1->FileName;
   FoldFileName=OpenDialog1->FileName;
   StatusBar1->Panels->Items[0]->Text ="Sélectionner le Patch";
   }
}

Ouverture de la boite de dialogue de sélection de fichiers, initialisation des membres FoldFileName, et du TLabeledEdit edOldFile.

VI-B. Méthode OpenPatchNameExecute

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
void __fastcall TForm1::OpenPatchNameExecute(TObject *Sender)
{
OpenDialog1->Title="Sélectionner le Patch";
if (OpenDialog1->Execute())
{
   edNewFile->Text=OpenDialog1->FileName;
   FPatchFileName=OpenDialog1->FileName;
   StatusBar1->Panels->Items[0]->Text ="Presser la touche Make...";
   }
}

Ouverture de la boite de dialogue de sélection de fichiers, initialisation des membres FPatchFileName et du TLabeledEdit edNewFile.

VI-C. Méthode AboutExecute

 
Sélectionnez
1.
2.
3.
4.
void __fastcall TForm1::AboutExecute(TObject *Sender)
{
   AboutBox->ShowModal();
   }

Ouverture de la boite de dialogue « À propos de ».

VI-D. Méthode CloseAppExecute

 
Sélectionnez
1.
2.
3.
4.
void __fastcall TForm1::CloseAppExecute(TObject *Sender)
{
   Close();
   }

Fermeture de l'application.

VI-E. Méthode MakeExecute

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
void __fastcall TForm1::MakeExecute(TObject *Sender)
{
FPatchIsBigger=false;
if (!GetFileSize(FoldFileName,&FSizeOldFile))
{
   DisplayErrorMessage("Veuillez choisir un fichier valide");
   FPatchFileName="";
   FoldFileName="";
   return ;
   }
if (!GetFileSize(FPatchFileName,&FSizePatchFile))
{
   DisplayErrorMessage("Veuillez choisir un fichier valide");
   FPatchFileName="";
   FoldFileName="";
   return ;
   }
FPatchIsBigger=IsBigger(&FDiff);
if (PatchFile())
{
   AnsiString msg="Le fichier \r\n";
   msg+=FoldFileName;
   msg+="\r\na été mis a jour avec succès avec le patch suivant\r\n";
   msg+=FPatchFileName;
   MessageDlg(msg, mtInformation, TMsgDlgButtons() << mbOK, 0);
   StatusBar1->Panels->Items[0]->Text ="Opération terminée avec succès...";
   ClearFields();
   }
}

Cette méthode teste tout d'abord la validité des fichiers, appelle en cas de succès la méthode PatchFile, en retour positif de cette méthode une messageBox est affichée indiquant le résultat de l'opération.

VII. Conclusion

l'application proposée est basique. Il est aisé de l'améliorer en lui rajoutant de nouvelles fonctionnalités par exemple :

  • exécution par lignes de commande ;
  • lecture d'une liste de fichiers à traiter dans un fichier Ini ;
  • etc.

Voir également mes autres articles :

  • Utilisation des Files Mapping sous C++Builder C++ Builder ;
  • La technique des PatchFiles C++ Builder ;
  • Maîtrisez les files d'impression sous Windows C++ Builder ;
  • Travailler avec les Interfaces en C++Builder Partie 1 C++ Builder ;
  • Composant de gestion des ports d'imprimantes C++ Builder ;
  • Programme de Test Version ActiveX du composant TDLIoport Delphi.

Sans oublier :

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2013 DjmSoftware. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.