FAQ C++ BuilderConsultez toutes les FAQ
Nombre d'auteurs : 60, nombre de questions : 670, dernière mise à jour : 21 novembre 2010 Ajouter une question
Cette F.A.Q. a été réalisée à partir des questions fréquemment posées sur le forum C++ Builder de developpez.com et de l'expérience personnelle des auteurs.
Nous tenons à souligner que cette F.A.Q. ne garantit en aucun cas que les informations qu'elle propose soient correctes. Les auteurs font le maximum, mais l'erreur est humaine. Cette F.A.Q. ne prétend pas non plus être complète. Si vous trouvez une erreur, ou que vous souhaitez devenir rédacteur, contactez pottiez
Nous espérons que cette F.A.Q. saura répondre à un maximum de vos questions. Nous vous souhaitons une bonne lecture.
L'équipe C++ Builder de Developpez.
Commentez cette FAQ : Commentez
Les fichiers exécutables contiennent tous un fichier ressource, visible avec un explorateur de ressources (type RESEXPLORER). Ce fichier contient les données utiles à l'exécutable, comme par exemple son icône.
Il est possible d'ajouter ou de modifier cette ressource pour inclure des fichiers que l'on ne souhaite pas "voir traîner", par exemple contenant des mots de passe.
Dans un premier temps, l'exécutable étant en cours, nous n'avons pas les droits d'accès. Il est nécessaire de les obtenir pour mettre à jour l'application. Pour cela, nous allons effectuer une copie de l'exécutable au même endroit que celui en cours (donc transparent pour l'utilisateur). L'original en exécution sera au préalable déplacé dans le dossier temporaire, puis supprimé.
Code c++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | AnsiString TempPath; AnsiString NewPath; AnsiString OriginalPath; //move running application GetTempPath(200,TempPath.c_str()); GetTempFileName(TempPath.c_str(), _T("TMP"),0,NewPath.c_str()); OriginalPath = Application->ExeName; if(MoveFileEx(OriginalPath.c_str(),NewPath.c_str(),MOVEFILE_REPLACE_EXISTING) == FALSE) ShowMessage("Moving file error"); if(CopyFile(NewPath.c_str(),OriginalPath.c_str(),FALSE) == FALSE) ShowMessage("Copying file error"); if(MoveFileEx(NewPath.c_str(),NULL,MOVEFILE_DELAY_UNTIL_REBOOT) == FALSE) ShowMessage("Moving file error"); |
Une fois les droits acquis, il n'y a plus qu'à charger le fichier à mettre en ressource puis de mettre à jour.
Code c++ : | Sélectionner tout |
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | DWORD dwFileSize, dwBytesRead,dwBytesWritten; LPBYTE lpBuffer; //récupération du fichier à ajouter en ressource HANDLE hFile = CreateFile(Chemin_Fichier_Text.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(INVALID_HANDLE_VALUE != hFile) { //chargement du fichier dans un buffer pour le transmettre dwFileSize = GetFileSize(hFile, NULL); lpBuffer = new BYTE[dwFileSize]; if(ReadFile(hFile, lpBuffer, dwFileSize, &dwBytesRead, NULL) != FALSE) { //récupération du Handle de la ressource HANDLE hResource = BeginUpdateResource(OriginalPath.c_str(), FALSE); if(NULL != hResource) { //mise à jour if(UpdateResource(hResource, RT_RCDATA, "RESOURCEADDED", MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL), (LPVOID) lpBuffer, dwFileSize) != FALSE) { if(EndUpdateResource(hResource, FALSE) != FALSE) ShowMessage("Update succed! Please restart application"); else ShowMessage("Error "+IntToStr(GetLastError())); } } } delete [] lpBuffer; CloseHandle(hFile); } |
Il suffit d'utiliser les classes TResourceStreamet TStringList comme suit :
Code c++ : | Sélectionner tout |
1 2 3 4 5 6 | AnsiString Chemin_Fichier_Text=ExtractFilePath(Application->ExeName)+"\\file.txt"; TResourceStream *MRes=new TResourceStream((int)HInstance, "RESOURCE", RT_RCDATA); MRes->SaveToFile(Chemin_Fichier_Text); TStringList *File= new TStringList; File->LoadFromFile(Chemin_Fichier_Text); DeleteFile(Chemin_Fichier_Text); |
L'idée développée est d'enregistrer un fichier (bmp, gif, csv ...) en ressource, quel que soit son type.
Il se peut que durant une application, on souhaite sauver des fichiers, des configurations ou tout autres fichiers qui ne puissent pas être pré-chargés durant la création de l'application.
Dans l'exemple suivant, on sauvegarde le fichier en ressource, l'important est de passer par le type TStream, pour le sauver en RC_DATA.
Pour l'enregistrer:
Code c++ : | Sélectionner tout |
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 32 33 | TMemoryStream *image = new TMemoryStream(); Image1->Picture->Graphic->SaveToStream(image); image->Position = 0; //procédure de sauvegarde AnsiString TempPath,NewPath,OriginalPath; GetTempPath(200,TempPath.c_str()); GetTempFileName(TempPath.c_str(), "TMP",0,NewPath.c_str()); OriginalPath = Application->ExeName; if(MoveFileEx(OriginalPath.c_str(),NewPath.c_str(),MOVEFILE_REPLACE_EXISTING) == FALSE) Application->MessageBox("Impossible de déplacer l'exe","Erreur",MB_OK+MB_ICONWARNING); if(CopyFile(NewPath.c_str(),OriginalPath.c_str(),FALSE) == FALSE) Application->MessageBox("Impossible de copier l'exe","Erreur",MB_OK+MB_ICONWARNING); if(MoveFileEx(NewPath.c_str(),NULL,MOVEFILE_DELAY_UNTIL_REBOOT) == FALSE) Application->MessageBox("Impossiblede déplacer la copie","Erreur",MB_OK+MB_ICONWARNING); DWORD dwFileSize, dwBytesRead,dwBytesWritten; LPBYTE lpBuffer; HANDLE hResource = BeginUpdateResource(OriginalPath.c_str(), FALSE); if(NULL != hResource) { if(UpdateResource(hResource,RT_RCDATA,"IMAGEBMP",MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),(LPVOID)image->Memory, (DWORD)image->Size) != FALSE) { if(EndUpdateResource(hResource, FALSE) == FALSE) ShowMessage("Error "+IntToStr(GetLastError())); } else ShowMessage("Error "+IntToStr(GetLastError())); } delete image; |
Pour le recharger, il suffit de lire le fichier en tant que TRessourceStream, de le convertir en TSream pour obtenir le format de sauvegarde, puis de sauver le fichier en tant que son propre type (".txt" pour les fichier texte, ".csv" pour les csv ...)
Pour le recharger :
Code c++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | hnd = FindResource( NULL, "IMAGEBMP", RT_RCDATA); if(hnd != NULL) { //chargement de la ressource TResourceStream *Res=new TResourceStream((int)HInstance,"IMAGEBMP",RT_RCDATA); TMemoryStream *image = new TMemoryStream(); //conversion de la ressource en TMemoryStream pour retrouver le même format enregistré Res->SaveToStream(image); image->Position = 0; //sauvegarde de l'image dans un fichier pour la recharger plus facilement image->SaveToFile("image1.bmp"); //supression de l'image et des variables Image1->Picture->Bitmap->LoadFromFile("image1.bmp"); DeleteFile("image1.bmp"); delete Res; delete image; } |
Par exemple dans une application multilangue, on peut sauver dans un fichier ini, txt ou autre les configurations (choix de la langue, fichiers chargés, modifications apportées par l'utilisateur...) puis le sauver en Ressource pour que l'exe soit portable.
L'avantage de cette manipulation est que TOUT est dans UN fichier : l'application elle-même.
L'inconvénient est que le code est un peu lourd à placer, et qu'il faut que l'application soit modifiable (non en lecture seule) pour être modifiée.
Proposer une nouvelle réponse sur la FAQ
Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour çaLes 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 © 2024 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.