Zasoby programu

0

Witam Serdecznie, natrafiłem na pewien problem a mianowicie, potrzebuję umieścic szereg plików najprościej cały jeden katalog, i zastanawiam sie jak to zgrabnie spakowac do zasobów i wypakować, tzn wiem ze można pojedyńczo, a jak cały katalog jeśli plików jest sporo. po prostu zeby program przy starcie wypakował pliki z zasobów.

0

A zastanowiłeś się jaki w ogóle jest sens umieszczać pliki w zasobach programu i je za każdym razem wypakowywać na dysk? Jakoś nie potrafię sobie wyobrazić sensu takiego rozwiązania. Co stoi na przeszkodzie aby te pliki były cały czas w folderze? Co to mają być za pliki?

0

tzn chodzi o to, mamy aplikacje która potrzebuje inne pliki wykonywalne i nie tylko, chodzi o to by je raz wypakować i tyle, no to jak wiadomo prosty warunek, tylko jak umiescic cały katalog plikow w zasobach

0

Całego folderu się nie da każdy plik musi być umieszczony osobno, można np. zrobić jeszcze jakiś plik w formacie XML lub INI (albo jakimś innym swoim własnym) który umieścisz także w zasobach. W pliku tym będą dane na temat ID pozostałych do wypakowania zasobów oraz ścieżki i nazwy pliku gdzie dany plik ma być "wypakowany". Ten plik wypakowujesz jako plik tymczasowy (nawet nie wiem czy przypadkiem XML nie można czytać czasem z pamięci) i później czytasz z tego pliku i pętli wypakowujesz resztę. Innym sposobem spakować folder i taki spakowany umieścić w zasobach później taki spakowany "wyciągnąć" z zasobów i wypakować.

0

@luftturned - z racji tej, że całego katalogu do zaobów nie można dołączyć (a przynajmniej ja nie wiem jak to zrobić), najprostszym sposobem będzie dołączenie pojedynczych plików do zasobów aplikacji; Nie będę Ci tutaj tłumaczył jak posługiwać się zasobami, bo o tym możesz poczytać choćby w Rozdziale 9 Kompendium;

Dość prostym rozwiązaniem będzie zapisanie sobie w kodzie programu identyfikatorów danych plików w zasobach w postaci np. tablicy łańcuchów:

const
  RES_FILE_NAMES: array [0 .. 4] of String = ('RESFILE0',
                                              'RESFILE1',
                                              'RESFILE2',
                                              'RESFILE3',
                                              'RESFILE4');

gdzie RESFILEX to identyfikator zasobu; Następnie przygotowujesz sobie plik *.rc do kompilacji:

RESFILE0 RT_RCDATA "C:\RESFILE0.ext"
RESFILE1 RT_RCDATA "C:\RESFILE1.ext"
RESFILE2 RT_RCDATA "C:\RESFILE2.ext"
RESFILE3 RT_RCDATA "C:\RESFILE3.ext"
RESFILE4 RT_RCDATA "C:\RESFILE4.ext"

gdzie RESFILEX to identyfikator zasobu, a C:\RESFILEX.ext to pełna nazwa pliku, który ma być włączony do zasobów; Następnie plik *rc kompilujesz wykorzystując np. Borlandowski kompilator zasobów brcc32.exe, a skompilowany plik zasobów *.res dołączasz odpowiednią dyrektywą do programu w odpowiednim module:

{$R PlikZasobow.res}

Podczas wypakowywania plików z zasobów najpierw sprawdzasz czy katalog docelowy istnieje (np. funkcją DirectoryExists) i jeśli nie istnieje to tworzysz go wykorzystując np. funkcję CreateDir lub ForceDirectories; Jeśli już katalog docelowy jest przygotowany - w pętli wypakowujesz do niego pliki z zasobów; Do tego celu możesz wykorzystać klasę TResourceStream;

Przykładowa funkcja wypakowująca wyżej wymienione pliki z zasobów do danego katalogu:

function ExtractResourceFiles(APath: AnsiString): Boolean;
const
  { lista identyfikatorów zasobów }
  RES_FILE_NAMES: array [0 .. 4] of String = ('RESFILE0',
                                              'RESFILE1',
                                              'RESFILE2',
                                              'RESFILE3',
                                              'RESFILE4');
var
  rsFile: TResourceStream;
  I: Integer;
begin
  Result := False;
  { dodanie znaku \ do ścieżki }
  APath := IncludeTrailingPathDelimiter(APath);

  { sprawdzenie istnienia katalogu docelowego }
  if not DirectoryExists(APath) then
    { utworzenie katalogu docelowego }
    if not ForceDirectories(APath) then
      Exit;

  { wypakowywanie plików z zasobów }
  try
    for I := 0 to High(RES_FILE_NAMES) do
    begin
      { utworzenie strumienia zasobów }
      rsFile := TResourceStream.Create(hInstance, RES_FILE_NAMES[I], 'RT_RCDATA');

      try
        { zapis strumienia do pliku }
        rsFile.SaveToFile(APath + RES_FILE_NAMES[I]);
      finally
        rsFile.Free();
      end;
    end;

    { jeśli poprawnie wypakowano pliki - zwróć True }
    Result := True;
  except
    { w razie wystąpienia błędu - zwróć False }
    on Exception do
      Result := False;
  end;
end;

Możesz także dodać do zasobów tymczasowy plik zawierający identyfikatory plików dodanych do zasobów oraz np. ich nazwy docelowe, które wykorzystasz podczas zapisu strumienia do pliku; Cały proces wypakowywania plików z zasobów będzie wyglądał podobnie, jednak w przypadku wykorzystania dodatkowego pliku tymczasowego:

  1. najpierw wypakowujesz na dysk plik z informacjami o zasobach (wygodny będzie plik INI),
  2. otwierasz plik tymczasowy i w pętli:
  3. pobierasz identyfikator danego pliku w zasobach (np. RESFILE0)
  4. tworzysz strumień zasobów pobierając plik o pobranym identyfikatorze,
  5. pobierasz decelową nazwę pliku,
  6. zapisujesz na dysk strumień o nazwie pobranej z pliku tymczasowego i danej ścieżce,
  7. zamykasz i usuwasz plik tymczasowy;
    Przykładowa zawartość pliku tymczasowego:
[0]
ResName="RESFILE0"
DestFileName="Bin\AppName.exe"

[1]
ResName="RESFILE1"
DestFileName="Bin\Dump.exe"

[2]
ResName="RESFILE2"
DestFileName="Config\Preferences.ini"

[3]
ResName="RESFILE3"
DestFileName="Help\Help.exe"

[4]
ResName="RESFILE4"
DestFileName="Help\Content.dat"

w ten sposób podczas modyfikacji programu i zwiększeniu ilości plików dodanych do zasobów nie będziesz musiał modyfikować kodu, a jedynie zamienisz plik *res z listą informacji o plikach w zasobach oraz drugi plik *.res z plikami do wypakowania.

0

Ja tylko dodam od siebie, że jeżeli zależy Tobie tylko na przeprowadzeniu po swojemu instalacji. To najlepiej zrobić to pod pakietami, które do tego służą. Jeżeli koniecznie chcesz posługiwać się przy tym językiem Object Pascal to polecam Inno Setup. Chociaż jakoś nigdy go nie używałem, bo jako pierwszą swoją instalkę potrzebowałem zrobić setup z pluginem do WinAMP'a, a więc wybór padł na NSIS'a. Nie wiem jak InnoSetup, ale NSIS pozwala na korzystanie z dllek jako własnych pluginow do użycia ich jako funkcji, które coś robią. Także zawsze mozesz zaopatrzeć instalkę we własną dllke, pisaną w Delphi i ona może realizować dodatkowe zadania poza właściwą instalacją plików. Na google zarówno do Inno, jak i NSIS istnieje bogata dokumentacja i na pewno do NSIS mnóstwo przykładów.

1 użytkowników online, w tym zalogowanych: 0, gości: 1