CYFROWY BARON • PROGRAMOWANIE • Zobacz wątek - Zapis w pliku exe
Strona 1 z 1

Zapis w pliku exe

Nowy postNapisane: czwartek, 10 września 2009, 21:19
przez Bishamoth
Witam
Czy jest mozliwosc zapisania informacji tekstowych w pliku exe? Dajmy na to, ze mam komponeny TEdit1 oraz TButton1, wpisuje cos do TEdit1, klikam na TButton1 (zapisuje zawartosc TEdit1), wylaczam program, wlaczam go z powrotem i w TEdit1 znajduje sie to co napisalem wczesniej. Nie chce zadnego zapisywania do pliku tekstowego, czy jakiego kolwiek innego.

Pozdrawiam Bish

Re: Zapis w pliku exe

Nowy postNapisane: czwartek, 10 września 2009, 21:33
przez banita
poczytaj o zasobach programu, chocby w portalu CB

Re: Zapis w pliku exe

Nowy postNapisane: czwartek, 10 września 2009, 23:47
przez Bishamoth
Tworzenie tablicy łańcuchów znaków i umieszczenie jej w zasobach programu.

Jezeli chodzilo Ci o ta porade, to wychodzi na to, ze nie ma mozliwosci zapisania czegokolwiek w binarce podczas dzialania programu... Te pliki *.rh *.rc -sa tworzone przed kompilacja i sa pozniej "wbudowane" w program, wiec nie ma jak ich edytowac :roll: Przynajmniej tak to wyglada po przeczytaniu/
Jest inny sposob na zapisanie tekstu?

Re: Zapis w pliku exe

Nowy postNapisane: piątek, 11 września 2009, 00:03
przez banita
http://cyfbar.republika.pl/api5.html#api2

niestety uruchomiony proces nie moze zmieniac swoich zasobow.

Re: Zapis w pliku exe

Nowy postNapisane: piątek, 11 września 2009, 08:35
przez izdrink
Witam!
dobrym sposobem na to co chcesz zrobić-jest obsługa plików ini :)
super opisana na cyfbar!!!
zapamietuje to co wpiszesz do edita i przy kolejnym uruchomieniu programu tez tam sie bedzie znajdowac!
i wcale nie musisz uzywac buttona!
wystarcza dwie funkcej(np read i write-read odzczytuje przy tworzeniu form,write zapisuje przy zamykaniu).
a plik ini stworz najlepiej
Kod: Zaznacz cały
void TForm1::Read()
{
   TIniFile *ini = new TIniFile(ChangeFileExt(Application->ExeName,".ini"));
   
   Edit1->Text = ini->ReadString("Sekcja","Wartosc","");

   delete ini;
}


Kod: Zaznacz cały
TIniFile *ini = new TIniFile(ChangeFileExt(Application->ExeName,".ini"));

   ini->WriteString("Sekcja","Wartosc",Edit1->Text);

   delete ini;

Re: Zapis w pliku exe

Nowy postNapisane: piątek, 11 września 2009, 14:40
przez Bishamoth
banita napisał(a):niestety uruchomiony proces nie moze zmieniac swoich zasobow.

O tym juz sie przekonalem ;) A mozliwym by bylo stworzenie dwoch programow. Jeden glowny i drugi poboczny. Glowny program odpala poboczny, a ten czeka az glowny program zakonczy swoje dzialanie, gdy juz sie tak stanie, to poboczny zmieni zasoby glownego, tak by bylo to co sie wpisalo w komponencie TEdit1. Po tym program poboczny konczy swoja prace... Coz, troche na okolo, jednak moze zadzialac. Teraz tylko musze sie dowiedziec, jak dokonac takiego czynu ;P

izdrink napisał(a):Witam!
dobrym sposobem na to co chcesz zrobić-jest obsługa plików ini :)

Bishamoth napisał(a):Nie chce zadnego zapisywania do pliku tekstowego, czy jakiego kolwiek innego.

Przeciez pisalem, ze nie chce zadnej obslugi plikow tekstowych ani tym podobnych. Chce to zrobic w binarce.

Re: Zapis w pliku exe

Nowy postNapisane: piątek, 11 września 2009, 16:25
przez Cyfrowy Baron
Potrzebujesz chyba porady: ► patrz serwis: Cyfrowy Baron dział porady -> API -> Uruchomienie aplikacji i oczekiwanie na jej zamknięcie.

Co do zapisywanie ustawień w pliku aplikacji to takiej metody chyba nikt nie stosuje. Jest to niebezpieczne, gdyż edycja takich zasobów może uszkodzić plik aplikacji.
Lepszym rozwiązaniem byłoby już stworzenie pliku rozszerzenia aplikacji (*.DLL). Program nie musiałby wcale korzystać z tego pliku, mógłby jednak bez problemu modyfikować zasoby tegoż programu.

Jeżeli sądzisz, że zapisując jakieś dane w pliku *.EXE lub *.DLL chronisz je przed użytkownikiem, to jesteś w błędzie. Takie zasoby można bez problemu podejrzeć pisząc program do edycji zasobów aplikacji, korzystajać chociażby z porady w serwisie Cyfrowy Baron, lub prościej - wykorzystując np. program Resource Hacker.

Jest ogólnie przyjęte, że dane konfiguracyjne aplikacji zapisuje się w rejestrze a opcje programu (opcje użytkownika) w plikach *.INI.

W celu zablokowania modyfikacji danych przez użytkownika należy je zapisywać w postaci binarnej. Można do tego celu wykorzystać struktury.
Innym sposobem jest zapisywanie i odczytywanie danych z/do pliku będącego chronionym hasłem archiwum ZIP (polecam komponent ZIPForge). Takie archiwa można obsługiwać bez wypakowywania plików, zapisując i odczytując dane strumieniowo bezpośrednio z/do pamięci.

Re: Zapis w pliku exe

Nowy postNapisane: środa, 16 września 2009, 22:46
przez Bishamoth
Witam ponownie ;)
Cyfrowy Baron napisał(a):Innym sposobem jest zapisywanie i odczytywanie danych z/do pliku będącego chronionym hasłem archiwum ZIP (polecam komponent ZIPForge). Takie archiwa można obsługiwać bez wypakowywania plików, zapisując i odczytując dane strumieniowo bezpośrednio z/do pamięci.

To mnie bardzo zaciekawilo. Czy mozna sie czegos wiecej dowiedziec o tym komponencie? Mam go juz zainstalowanego, lecz help do niego, jak dla mnie jest troche... za malo. W szczegolnosci interesuja mnie strumienie :)

Re: Zapis w pliku exe

Nowy postNapisane: czwartek, 17 września 2009, 20:09
przez Cyfrowy Baron
Plik pomocy jest bardzo dobrze opracowany, ale podam gotowe rozwiązania strumieniowego zapisu i odczytu danych za pomocą ZIPForge. Komponent będzie tworzony dynamicznie, a to oznacza, ze nie trzeba go umieszczać na formularzu.

w pliku nagłówkowym w sekcji Include dodajemy wpis: #include "ZipForge.hpp"

KOD cpp:     UKRYJ  
#include <Classes.hpp>
#include <StdCtrls.hpp>
// [...]
#include "ZipForge.hpp"

private:
          void SaveOptions(void);
          void LoadOptions(void);
 
Zapis do pliku:

KOD cpp:     UKRYJ  
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
#include <memory>
//---------------------------------------------------------------------------

#pragma package(smart_init)
#pragma link "ZipForge"

//---------------------------------------------------------------------------
void TForm1::SaveOptions(void)
{
 TZipForge *SaveArchiver = new TZipForge(NULL);

 TMemoryStream *mStream = new TMemoryStream();
 mStream->Position = 0;

 /* tutaj tworzona jest lista typu TStringList i w niej zapisywane są opcje */
 std::auto_ptr<TStrings> optionList(new TStringList());
 optionList->Add("coś tam sobie zapisujesz");

 optionList->SaveToStream(mStream); // przepisanie listy do strumienia pamięci

 String optionFile = "nazwa pliku.zip"; /* nazwa pliku archiwum rozszerzenie może być dowolne, niekoniecznie ZIP */
 SaveArchiver->FileName  = optionFile;

 if(FileExists(optionFile))
 {
  /* jeżeli plik istnieje nastęuje otwarcie archiwum do odczytu i zapisu */
  SaveArchiver->OpenArchive(fmOpenReadWrite);
  SaveArchiver->Active = true;
 }
 else
 {
  /* jeżeli plik nie istnieje archiwum jest otwierane tylko do zapisu */
  SaveArchiver->OpenArchive(fmCreate);
 }

 SaveArchiver->Password = "hasło"; // podaj hasło - rozróżnia wielkość liter
 SaveArchiver->CompressionMode = 9; // stopień kompresji 0-9
 SaveArchiver->CompressionLevel = Zipforge::clMax; // poziom kompresji
 SaveArchiver->EncryptionMethod = caAES_256; /* metoda szyfrowania podawana tylko przy zapisie do archiwum */

 String optionTxt = "option.txt"; // nazwa pliku w archiwum, nazwa dowolna

 SaveArchiver->AddFromStream(optionTxt, mStream, true, 0, 0, 0, Now()); /* przepisanie zawartości strumienia pamięci do pliku w archiwum */
 SaveArchiver->CloseArchive(); /* zamknięcie archiwum, WAŻNE! trzeba zamknać w przeciwnym razie plik będzie niedostępny do dalszych operacji */

 mStream->Position = 0;

 delete mStream;
 delete SaveArchiver;
}


czytaj więcej o metodzie szyfrowania

Odczyt z pliku:
KOD cpp:     UKRYJ  
 /* tutaj tworzona jest lista typu TStringList i w niej umieszczone zostaną pobrane opcje, do przechowywania opcji programu powinna to być lista globalna, czyli należy ja zadeklarować w pliku nagłówkowym w sekcji private lub public i zdefiniować najlepiej w konstruktorze klasy formularza */

TStrings *optionList;
optionList = new TStringList();

//---------------------------------------------------------------------------
void TForm1::LoadOptions(void)
{
 if(!FileExists(optionFile)) return; /* jeżeli plik nie istnieje funkcja przerywa działanie */

 TZipForge *LoadArchiver = new TZipForge(NULL);
 TMemoryStream *mStream = new TMemoryStream();

 String optionFile = "nazwa pliku.zip"; /* nazwa pliku archiwum w którym zapisano opcje */

 LoadArchiver->FileName  = optionFile;
 LoadArchiver->OpenArchive(fmOpenRead); // otwarcie w trybie do odczytu
 LoadArchiver->Password = "hasło"; // podaj hasło archiwum


 String optionTxt = "option.txt"; /* nazwa pliku w archiwum, ten sam plik, który był wykorzystany do zapisu */

 TZFArchiveItem ArchiveItem;
 std::auto_ptr<TStrings> findList(new TStringList());

/* wyliczanie plików w archiwum, celem sprawdzenia, czy archiwum zawiera potrzebny plik tutaj option.txt reprezentowany przez zmienną optionTxt, mozna wyszukiwać grupy plików z rozszerzeniem podając jako argument zamiast pełnej nazwy pliku tylko rozszerzenie np. "*.txt", można też wyszukiwać wszystkie pliki w archiwum "*.*" */

 if(LoadArchiver->FindFirst("*.txt", ArchiveItem, faAnyFile - faDirectory))
  do
  {
    findList->Add(ArchiveItem.FileName);
  }
  while (LoadArchiver->FindNext(ArchiveItem));

 if(findList->IndexOf(optionTxt) < 0)
 {
  /* jeżeli w archiwum nie znaleziono żadnego pliku, obiekt LoadArchiver kończy działanie i przerywa dalsze wykonywanie funkcji */
  LoadArchiver->CloseArchive();
  delete mStream;
  return;
 }

 LoadArchiver->ExtractToStream(optionTxt, mStream); /* wypakowanie zawartości pliku z archiwum do pamięci */
 mStream->Position = 0;

 optionList->LoadFromStream(mStream); /* przepisanie zawartośći strumienia pamięci do listy optionList */
 LoadArchiver->CloseArchive();  /* zamknięcie archiwum, WAŻNE! trzeba zamknać w przeciwnym razie plik będzie niedostępny do dalszych operacji */

 delete mStream;
delete LoadArchiver;
}

Re: Zapis w pliku exe

Nowy postNapisane: czwartek, 17 września 2009, 21:52
przez Bishamoth
Oki, nie wiem czy to bylo pisane z glowy i nie sprawdzone, czy tez nie, ale:
Kod: Zaznacz cały
[C++ Error] Unit1.cpp(34): E2316 'Items' is not a member of 'TStrings'
[C++ Error] Unit1.cpp(57): E2451 Undefined symbol 'Strings'
[C++ Error] Unit1.cpp(57): E2379 Statement missing ;
[C++ Error] Unit1.cpp(59): E2451 Undefined symbol 'optionTxt'
[C++ Error] Unit1.cpp(71): E2451 Undefined symbol 'optionFile'
[C++ Error] Unit1.cpp(76): E2238 Multiple declaration for 'optionFile'
[C++ Error] Unit1.cpp(83): E2451 Undefined symbol 'Strings'
[C++ Error] Unit1.cpp(83): E2379 Statement missing ;
[C++ Error] Unit1.cpp(90): E2451 Undefined symbol 'optionTxt'
[C++ Error] Unit1.cpp(90): E2285 Could not find a match for 'TZFBaseArchiver::FindFirst(undefined,TZFArchiveItem,int)'

:roll:

Re: Zapis w pliku exe

Nowy postNapisane: piątek, 18 września 2009, 10:27
przez Cyfrowy Baron
Kod jest sprawdzony pochodzi z jednego z moich programów.

Ten komunikat:


[C++ Error] Unit1.cpp(34): E2316 'Items' is not a member of 'TStrings'




dotyczy tego fragmentu kodu:

jest:
Kod: Zaznacz cały
optionList->Items->Add("coś tam sobie zapisujesz");

powinno być:
Kod: Zaznacz cały
optionList->Add("coś tam sobie zapisujesz");




Co do tych komunikatów:


[C++ Error] Unit1.cpp(57): E2451 Undefined symbol 'Strings'
[C++ Error] Unit1.cpp(57): E2379 Statement missing ;
[C++ Error] Unit1.cpp(59): E2451 Undefined symbol 'optionTxt'
[C++ Error] Unit1.cpp(71): E2451 Undefined symbol 'optionFile'
[C++ Error] Unit1.cpp(83): E2451 Undefined symbol 'Strings'
[C++ Error] Unit1.cpp(83): E2379 Statement missing ;
[C++ Error] Unit1.cpp(90): E2451 Undefined symbol 'optionTxt'




to błędy wynikające z błędnej deklaracji zmiennych, gdyż deklarując zmienne typu String pisałem Strings.

Pojawiają się tam drobne literówki, które nieopatrznie wprowadziłem podczas przepisywania kodu. Tam gdzie jest Strings powinno być oczywiście String, gdyż chodzi o zmienne String. Błąd pojawia się dwa razy:

w funkcji SaveOptions:

jest:
Kod: Zaznacz cały
Strings optionTxt = "option.txt"; // nazwa pliku w archiwum, nazwa dowolna

powinno być:
Kod: Zaznacz cały
String optionTxt = "option.txt"; // nazwa pliku w archiwum, nazwa dowolna


oraz w funkcji LoadOptions:

jest:
Kod: Zaznacz cały
  Strings optionTxt = "option.txt"; /* nazwa pliku w archiwum, ten sam plik, który był wykorzystany do zapisu */

powinno być:
Kod: Zaznacz cały
  Strings optionTxt = "option.txt"; /* nazwa pliku w archiwum, ten sam plik, który był wykorzystany do zapisu */




Co do tego komunikatu:

[C++ Error] Unit1.cpp(76): E2238 Multiple declaration for 'optionFile'




Oznacza, on że zmienna o nazwie optionFile została dwukrotnie zadeklarowana, ale ten błąd nie występuje w moim kodzie, wiec to pewnie efekt twoich modyfikacji.



Funkcje zdefiniowane w pliku źródłowym wymagają deklaracji w pliku nagłówkowy, o czym nie pisałem, gdyż sądziłęm, że to oczywiste.

plik nagłówkowy np. Unit1.h:
Kod: Zaznacz cały
private:
          void LoadOptions(void);
          void SaveOptions(void);




Kolejny błąd jaki popełniłem modyfikując funkcję do Twoich potrzeb występuje w funkcji SaveOptions:

jest:
Kod: Zaznacz cały
/* tutaj tworzona jest lista typu TStringList i w niej zapisywane są opcje */
std::auto_ptr<TStrings> optionListt(new TStringList());
optionLista->Items->Add("coś tam sobie zapisujesz");


powinno być:
Kod: Zaznacz cały
/* tutaj tworzona jest lista typu TStringList i w niej zapisywane są opcje */
std::auto_ptr<TStrings> optionList(new TStringList());
optionList->Add("coś tam sobie zapisujesz");




Co do tego komunikatu:


[C++ Error] Unit1.cpp(90): E2285 Could not find a match for 'TZFBaseArchiver::FindFirst(undefined,TZFArchiveItem,int)'




to błąd wywołuje ten fragment kodu:

Kod: Zaznacz cały
if(LoadArchiver->FindFirst(optionTxt, ArchiveItem, faAnyFile - faDirectory))


bierze się stąd, że zmodyfikowałem go do Twoich potrzeb, ale w pomocy jest napisane, że pierwszy argument to wartość typu WideString (mój błąd po podałem wartość typu String). Nie mam też pewności, czy można tutaj podać pełną nazwę pliku, więc możesz to zrobić na dwa sposoby:

pierwszy (niepewny)
Kod: Zaznacz cały
if(LoadArchiver->FindFirst(optionTxt.c_bstr(), ArchiveItem, faAnyFile - faDirectory))

.c_bstr() - konwersja zmiennej typy String do WideString

drugi (musi zadziałać:
Kod: Zaznacz cały
if(LoadArchiver->FindFirst("*.txt", ArchiveItem, faAnyFile - faDirectory))





Poprawiłem kod w moim poprzednim poście, ale kopiując go musisz dostosować go do swojego programu.