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