Accueil
Rechercher:
sur developpez.com sur les forums
Forums | Tutoriels | F.A.Q's | Participez | Hébergement | Contacts
Club Emploi Blogs   TV   Dév. Web PHP XML Python Autres 2D-3D-Jeux Sécurité Windows Linux PC Mac
Accueil Conception Java DotNET Visual Basic  C  C++ Delphi MS-Office SQL & SGBD Oracle  4D  Business Intelligence

Technique : les Patch Files sous C++ Builder

21/08/2003

Par DjmSoftware
 

niveau : moyen

durée : 30 minutes

ce tutorial démontre une des technique utilisée pour mettre à jour des Fichiers executables a l'aide des File Mapping avec un exemple d'application


Sources du Programme disponible ici.


Définition
1. Programme d'exemple
1.1. Limitation
2. Définition du GUI
2.1. définition de la forme principale
2.2. ImageList
2.3. ActionsList
2.4. ActionToolBar
2.5. Menu Principal
2.6. Boutons divers
3. Classe TMMF
3.1. Modification de la classe TMMF
3.2. Modification de la classe TMMF
4. Classe Tform
4. Explicatif sur les méthodes Privées
4.1. Méthode GetFileSize(AnsiString FileName,long* Size)
4.2. Méthode AdjustFileSize()
4.3. Méthode PatchFile()
4.4. Méthode DisplayErrorMessage(AnsiString msgE)
4.5. Méthode ClearFields()
4.6. Méthode IsBigger
5. Méthodes Publiées(published)
5.1. Méthode OpenOlDfileExecute
5.2. Méthode OpenPatchNameExecute
5.3. Méthode AboutExecute
5.4. Méthode CloseAppExecute
5.5. Méthode MakeExecute
6. Conclusion


Définition


les patchs sont généralement utilisés pour mettre à jour des applications en remplacant les exeécutables
livrés avec une nouvelle version corrigeant des erreurs ou apportant de nouvelles fonctionalités


1. 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.


1.1. Limitation


Ce programme est écrit en C++ à l'aide de C++ Builder 6
Dans ce programme est utilisé certaines fonctionnalités VCL qui rendent la parti GUI
non portable sur une autre compilateur, l'adaptation du code est par contre possible


2. Définition du GUI



2.1. 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

2.2. ImageList


Nous allons Charger les Images dans le composant ImageList1
sélectionner 4 images dans le répertoire fichiers communs de Borland
comme dans la copie écran ci dessous


2.3. ActionsList


Creation des actions
Ouvrir le composant ActionManager1
touche droite de souris sur le composant clicker sur personaliser
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


2.4. 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

dans la vue arborescente des objets placer le curseur de la souris sur
ActionBars, click touche droite de la souris sur ajouter un élément
dans l'ActionToolbar nouvellement crée placer le curseur de la souris sur
sur l'élément Items puis créer 4 nouveaux éléments
les noms données 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

2.5. Menu Principal


Création d'un menu selon Image Suivante

donnez aux Items Actions les valeurs suivantes

Item Action
OpenFile1 OpenOlDfile
OpenPatchFile1 OpenPatchName
Make1 Make
Close1 Close
About1 About

2.6. Boutons divers


Donnez aux aux Actions de Buttons les Valeurs Suivantes

Item Action
BitBtn1 Make
BitBtn2 Close
Le design de l'application est maintenant terminé


3. Classe TMMF


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


3.1. Modification de la classe TMMF


j'ai modifié l'implémentation de la classe TMMF pour lui ajouter de nouvelles fonctionalité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 taiille d'origine
Constructeur TMMF(AnsiString FileName, long size, bool Bigger) public initalize FMapFileOffset et FBigger

3.2. Modification de la classe TMMF


la méthode Execute est modifiée comme suit

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

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();
   
}


4. Classe Tform


Déclaration de la classe les champs suivantes 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 taile du fichier à Patcher
champ FSizePatchFile private contient le taille du fichier Patch
Champ FDiff private Contient la différence de taille entre les 2 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

4. Explicatif sur les méthodes Privées



4.1. Méthode GetFileSize(AnsiString FileName,long* Size)


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.


4.2. Méthode AdjustFileSize()


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 SetFilePointeren lui indiqant ou placer le pointeur de fin de fichier(EOF) on appelle ensuiteSetEndOfFilequi va ajuster le fichier à sa nouvelle taille


4.3. Méthode PatchFile()


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 creé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 a 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 a libérer la mémoire


4.4. Méthode DisplayErrorMessage(AnsiString msgE)


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 une message dialog ainsi que dans la barre de status le message d'erreur


4.5. Méthode ClearFields()


void __fastcall TForm1::ClearFields()
{
FPatchFileName="";
FoldFileName="";
edNewFile->Text="";
edOldFile->Text="";
}

la méthode ClearFields réinitialise les variables


4.6. Méthode IsBigger


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 a 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


5. Méthodes Publiées(published)


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


5.1. Méthode OpenOlDfileExecute


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 fichier,initialisation des membres FoldFileName, et du TLabeledEdit edOldFile


5.2. Méthode OpenPatchNameExecute


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 fichier,initialisation des membres FPatchFileName, et du TLabeledEdit edNewFile


5.3. Méthode AboutExecute


void __fastcall TForm1::AboutExecute(TObject *Sender)
{
    AboutBox->ShowModal();
    }

ouverture de la boite de dialogue A propos de


5.4. Méthode CloseAppExecute


void __fastcall TForm1::CloseAppExecute(TObject *Sender)
{
    Close();
    }

Fermeture de l'application


5.5. Méthode MakeExecute


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


6. Conclusion


l'application proposée est basique il est aisé de l'améliorer en lui rajoutant de nouvelles fonctionalités
par exemple

  • Execution par lignes de commandes
  • lecture d'une liste de fichiers a 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 :
la FAQ C++ Builder par Geronimo
la FAQ C
la FAQ C++

Ce document est issu de http://www.developpez.com et reste la propriété exclusive de son auteur.
La copie, modification et/ou distribution par quelque moyen que ce soit est soumise à l'obtention préalable de l'autorisation de l'auteur.

Responsables bénévoles de la rubrique Accueil : Nicolas Vallée (gorgonite) et Guillaume Rossolini (Yogui) - Contacter par EMail :
Vos questions techniques : forum d'entraide Accueil - Publiez vos articles, tutoriels et cours
et rejoignez-nous dans l'équipe de rédaction du club d'entraide des développeurs francophones
Nous contacter - Copyright © 2000-2008 www.developpez.com - Legal informations.