Autor Beitrag
Murdock1
Hält's aus hier
Beiträge: 9



BeitragVerfasst: Di 05.11.02 09:33 
Eigene Ressourcen in Delphi-Programmen nutzen

Ich gehe mal davon aus, das als Delphi-Benutzer der Borland-RessourceWorkshop benutzt wird, der ist zwar nicht schön, aber auf der Delphi-CD enthalten. Sollte ein anderes Tool verwendet werden, dann gilt das hier entsprechend gesagte sinngemaess.

Also gut, legen wir mal los...

Als erstes stellen wir mal sicher, das im Ressource Workshop unter den Voreinstellungen das 32bit-Format eingestellt ist, da der Delphi Linker Ressourcen im 32bit Format erwartet.

Der Einfachheit halber wollen wir mal zwei Datenbanken mitgeben, die dann beim Start des Programmes, so nicht vorhanden, aus der Ressource neu erstellt wird (geht natürlich auch mit Grafik-, Sound-, Binaer- oder was auch immer- Dateien).

Als erstes starten wir mal unseren Ressource Workshop und legen ein neues Projekt an und wählen als Projektformat das RES-Format. Anschliessend ueber "FILE- ADD TO PROJEKT" und mit dem Typ "USER DATA RESSOURCE" unsere erste Datenbankdatei hinzufuegen. Anschliessend will der Ressource Workshop noch wissen, was denn unsere Datei denn fuer einen Typ hat, wir legen uns dazu ueber "NEW TYP" einen neuen Typ namens "DATABASE" an, unter dem wir diese Datei dann hinzufuegen. Analog verfahren wir auch mit unserer zweiten Datenbank-Datei, wobei wir aber diesmal nicht noch einen neuen Typ kreieren, sondern unseren schon vorher erzeugten Typ "DATABASE" auswählen koennen.
Anschliessend können wir noch in der Liste der Ressourcen mit Rechtsklick - RENAME auf der Datenbankdatei, die bis dahin database_1 bzw. database_2 heissen, einen aussagekräftigen Namen verpassen (lasse ich hier mal der Übersichtlichkeit halber weg).
Wenn alles O.K. ist, dann speichern wir das Projekt unter einem sinnvollem Namen (z.B. MyDB.RES) zweckmaessigerweise im Verzeichnis mit unserem Delphi-Projekt.

hier nun der Delphi-Teil des Ganzen:

Unter dem Eintrag {$R *.dfm} in unserem Quellcode fuegen wir als naechste Zeile {$R MyDB.RES} ein (ich geh mal davon aus, das die RES-Datei bereits im Verzeichnis mit unserem Projekt liegt).
Als naechstes basteln wir uns eine Funktion, die eine Ressource in eine Datei schreibt:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
procedure TForm1.WriteResToFile(sFrom, sTo:String);
begin
  sRSStream:=TResourceStream.Create(hInstance, sFrom, 'DATABASE');
  // hInstance ist das Handle unserer Exe-Datei
  // sFrom ist der Name, den wir der DB-Datei in der Res-Datei verpasst haben
  // und sTo schliesslich ist der Name der zu schreibenden Datei 
  try
    sRSStream.SaveToFile(sTo);
  finally
    sRSStream.Free;
  end;
end;


Und aufgerufen wird das ganze dann folgendermassen( kann auch im Form.Create oder aehnlichem stehen):

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
procedure TForm1.Button1Click(Sender: TObject);
begin
  if not FileExists('Test1.db')
    WriteResToFile('DATABASE_1','Test1.db');
  if not FileExists('Test2.db')
    WriteResToFile('DATABASE_2','Test2.db');

end;


Zum Schluss noch ein paar Hinweise, wie man das alles statt mit der exe-Datei mit einer dll realisiert:
Eigentlich ist das Vorgehen analog, als erstes ein neues DLL-Projekt erstellen und irgendeine unit in mit uses einbinden (sonst wird die dll gar nicht erst erstellt. Anschliessend wie gehabt die Ressourcen erstellen und mit {R ....} einbinden.
In der Anwendung muessen wir dann nur unsere Funktion WriteResToFile anpassen, da wird dann nicht mit hInstance auf das Handle der Anwedung zugegriffen sondern wir besorgen uns das Handle ueber einen LoadLibrary-Aufruf, etwa so:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
procedure TForm1.WriteResToFile(sFrom, sTo:String);
var
  hRs:Handle;
begin
  hRes:=LoadLibrary('blah.dll');
  if hRs<>0 then
  begin
    sRSStream:=TResourceStream.Create(hRs, sFrom, 'DATABASE');
    // hRs ist jetzt das Handle unserer DLL
    try
      sRSStream.SaveToFile(sTo);
    finally
      sRSStream.Free;
    end;
end;


So, war doch gar nicht so schwer...
Man koennte das alles dann noch mit Gimmicks wie Fehlerbehandluung bei nicht vorhandener Ressource, Abfrage nach Platz auf Ziellaufwerk usw. verzieren, für die Funktion ist das aber unerheblich.

Bei Fragen Mail an mich:
huebnerp@gmx.net

ciao....
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Di 05.11.02 13:28 
Und wer das ganze mit Verzicht auf die Klasse TResourceStream machen will, kann folgende Routine von Assarbad benutzen:

ausblenden volle Höhe Delphi-Quelltext
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:
{ following code is copied directly from Assarbad }
function PutBinResTo(binresname: string; path: string): boolean;
var ResSize, HG, HI, SizeWritten, hFileWrite: Cardinal;
begin
  result := false;
  //find resource
  HI := FindResource(hInstance, @binresname[1], 'BINRES');
  //if legal handle, go on
  if HI <> 0 then
  begin
    //load resource and check the handle
    HG := LoadResource(hInstance, HI);
    if HG <> 0 then
    begin
      //check resource size (needed to copy a block of data)
      ResSize := SizeOfResource(hInstance, HI);
      //create the file
      hFileWrite := CreateFile(@path[1], GENERIC_READ or GENERIC_WRITE,
        FILE_SHARE_READ or FILE_SHARE_WRITE, nil, CREATE_ALWAYS,
        FILE_ATTRIBUTE_ARCHIVE, 0);
      //if succeeded ...
      if hFileWrite <> INVALID_HANDLE_VALUE then
      try
        //write to it
        result := (WriteFile(hFileWrite, LockResource(HG)^, ResSize,
          SizeWritten, niland (SizeWritten = ResSize));
      finally
        //close file
        CloseHandle(hFileWrite);
      end;
    end;
  end;
end;


Und Aufruf mit:
ausblenden Delphi-Quelltext
1:
PutBinResTo('MPEGDLL', ExtractFilePath(ParamStr(0))+'mpegdll.dll');					


Gefällt mir irgendwie besser, ist schöner, weil es einen Hauch von Genialität hat. :mrgreen: