Seite 1 von 2

IncludeBinary mit allen Dateitypen : CatchFile()

Verfasst: 26.07.2006 18:49
von Olaf
IncludeBinary unterstützt bei PureBasic mit den "Catch..."-Befehlen bisher nur
das Einfügen von Grafiken und Sounds. Es ist jedoch möglich, alle Dateitypen
in ein Executable einzubinden und später wieder zu "catchen".
Das ist insbesondere dann nützlich, wenn man eine Standalone-Setup.exe für ein Programm
erstellen will, die sich selbst entpackt und alle DLLs, Bitmaps oder sonstige Dateien
aus sich heraus erstellen kann. Da mit Pointern gearbeitet wird und somit in der
CatchFile()-Prozedur keine Codespezifischen Variablen vorkommen, sollte der Code in
allen anderen Codes problemlos einzubinden sein. Zudem kann durch die Arbeit mit Pointern
die Prozedur beliebig oft für verschiedene Dateien verwendet werden.

Code: Alles auswählen

DataSection
  filestart:                                 ;StartLabel (Position)
  IncludeBinary "C:\WINDOWS\explorer.exe"    ;...oder irgendeine andere Datei (hab hier den
                                             ;Explorer gewählt, damit der Code, ohne umgeschrieben
                                             ;werden zu müssen, getestet werden kann)
  fileend:                                   ;EndLabel (Position) wichtig zum berechnen
                                             ;der Datenlänge (siehe unten)
EndDataSection

Procedure CatchFile(FileID,FileName$,Includesection,Length)
  ;FileID :         FileID ist die #FileID, die die Datei später erhalten wird.
  ;FileName :       Es wird die Datei mit dem Namen FileName$ erstellt
  ;IncludeSection : Als IncludeSection muss der Pointer auf das StartLabel
  ;                 des IncludeBinary angegeben werden (hier: ?filestart)
  ;Length :         Length als Datenlänge berechnet sich als Differenz von EndPointer
  ;                 und StartPointer des betroffenen IncludeBinarys.
  ;                 Handelt es sich um mehrere IncludeBinaries, kann als
  ;                 EndPointer auch das StartLabel des nächsten IncludeBinarys
  ;                 angegeben werden:
  ;
  ;                 DataSection
  ;                   file1:
  ;                   IncludeBinary "C:\WINDOWS\notepad.exe"
  ;                   file2:
  ;                   IncludeBinary "C:\WINDOWS\system32\logon.scr"
  ;                   endfiles:
  ;                 EndDataSection
  ;
  ;                 In diesem Fall wäre Length der ersten Datei gleich
  ;                 ?file2-?file1 und als IncludeSection müsste ?file1 angegeben werden.
  ;                 Die letzte Datei in einem solchen DataSection-Block muss natürlich
  ;                 ein eigenes EndLabel erhalten (hier: ?endfiles).
  If CreateFile(FileID,FileName$)
    WriteData(FileID,Includesection,Length)
    CloseFile(FileID)
  EndIf
EndProcedure

;Beispielaufruf:
CatchFile(0,GetHomeDirectory()+"\Desktop\explorer2.exe",?filestart,?fileend-?filestart)

Verfasst: 26.07.2006 19:01
von ts-soft

Code: Alles auswählen

CreateFile(FileID,FileName$)
Die Erstellung der Datei sollte aber überprüft werden, kann sonst böse
Abstürze geben.

Verfasst: 26.07.2006 19:08
von Olaf
@ts-soft
Das wollte ich eigentlich dem PB-User überlassen, dafür zu sorgen
(is nicht so, als hätte ich nicht dran gedacht).
Der kann dann ja seine eigenen ProcedureReturns einbauen.
Aber stimmt schon.

Verfasst: 26.07.2006 19:24
von ts-soft
Es geht nicht um ProcedureReturn, es geht darum, wenn das CreateFile
fehlschlägt, ein WriteData den PC zum Absturz bringen könnte.

Also immer so:

Code: Alles auswählen

If CreateFile(FileID,FileName$)
  WriteData(FileID,Includesection,Length)
  CloseFile(FileID)
EndIf 

Verfasst: 26.07.2006 19:28
von Olaf
@ts-soft
Ja, ich weiß, war ehrlich gesagt einfach zu faul, das reinzupacken, wird aber erledigt.

Verfasst: 26.07.2006 19:30
von Olaf
@ts-soft
besser so?

Verfasst: 26.07.2006 19:41
von ts-soft
Olaf hat geschrieben:@ts-soft
besser so?
Ja :wink:
Wir sind hier schließlich bei Code, Tipps und Tricks. Bei vielen Dingen kann
man diese Überprüfung mal vernachlässigen, aber so Dinge wie
Dateierstellung, Speicherreservierung usw. sollten immer gescheckt werden.

Verfasst: 27.07.2006 07:30
von Leonhard
Ich denke mal, das wenn man schon mit Catch arbeitet man sich den FileName$ ersparen möchte und die Datei auch geöffnet werden sollte.
Daher habe ich folgenen Code geschreieben (bin mir nur nicht einig, ob ich ReadFile(...) oder OpenFile(...) benutzen soll).

Code: Alles auswählen

;// Beschreibung:
;//   Lädt die angegebene Datei 'FileID' von der angegebenen
;//   Speicheradresse. Wenn #PB_Any als '#Image' Parameter
;//   verwendet wird, dann wird die Nummer des neuen Image
;//   als 'Ergebnis' zurückgegeben. Sonst wir der Handle der
;//   FileID zurückgegeben. Auch auslesbar mit FileID(...).
;//   Sie können in der Datei ausschließlich nur
;//   Lese-Operationen ausführen.
;//   
;//   Dieser Befehl ist nützlich in Verbindung mit dem
;//   'IncludeBinary' PureBasic Schlüsselwort. Damit können
;//   Dateien mit in das Executable gepackt werden. Nichts-
;//   destotrotz, benutzen Sie diese Option mit Bedacht,
;//   da hiermit mehr Speicher benötigt wird, als wenn die
;//   Datei in einer externen Datei gespeichert wird (die
;//   Datei befindet sich im Speicher des Executable und
;//   auch geladen im physikalischen Speicher).
;// Parameter:
;//   FileID
;//     Die FileID ist die ID der Datei.
;//     Wenn #PB_Any als 'FileID' Parameter verwendet wird,
;//     dann wird die neue Datei-Nummer als 'Ergebnis'
;//     zurückgegeben.
;//   *Memory
;//     Die Speicheradresse, wo sich die Datei befindet.
;//   Length
;//     Die Länge der Speicheradresse.
;// Rückgabewert:
;//   Der Rückgabewert ist der Handle der FileID (auch
;//   ermittelbar mit FileID(...)) oder wenn in den
;//   'FileID'-Parameter #PB_Any geschrieben wurde die
;//   FileID.
;// Beispiel:
;//   DataSection
;//     file1:
;//     IncludeBinary "C:\WINDOWS\notepad.exe"
;//     file2:
;//     IncludeBinary "C:\WINDOWS\system32\logon.scr"
;//     endfiles:
;//   EndDataSection
;//   
;//   In diesem fall werden die Dateien so eingelanden:
;//   Datei1: CatchFile(XXX, ?file1, ?file2-?file1)
;//   Datei2: CatchFile(XXX, ?file1, ?endfiles-?file1)
Procedure,l CatchFile(FileID, *Memory, Length)
  Protected FileID, ReturnFileID, FileName$
  FileName$=GetEnvironmentVariable("TMP")+"\"+MD5Fingerprint(*Memory, Length)+".tmp")
  ReturnFileID = CreateFile(FileID, FileName$)
  If FileID = #PB_Any
    FileID = ReturnFileID
  EndIf
  If FileID
    WriteData(FileID, *Memory, Length)
    CloseFile(FileID)
  Else
    ProcedureReturn 0
  EndIf
  ReturnFileID = ReadFile(FileID, FileName$)
  ProcedureReturn ReturnFileID
EndProcedure

Verfasst: 27.07.2006 11:17
von myself
Nur liegt der unterschied darin das Catch befehle von PB die datei nicht auf die festplatte schreiben. wenn ich dann den filebuffer von so einer CatchFile geöffneten datei einlest verbraucht das 2x so viel speicher wie die datei groß ist. Ich würde versuchen da mit FreeMemory was zu drehen, aber kA ob das funktioniert.

Verfasst: 27.07.2006 11:53
von pankgraf
@myself
Was du schreibst ist richtig.
Olaf hat geschrieben:IncludeBinary unterstützt bei PureBasic mit den "Catch..."-Befehlen bisher nur das Einfügen von Grafiken und Sounds. Es ist jedoch möglich, alle Dateitypen in ein Executable einzubinden und später wieder zu "catchen".
Das ist insbesondere dann nützlich, wenn man eine Standalone-Setup.exe für ein Programm erstellen will, die sich selbst entpackt und alle DLLs, Bitmaps oder sonstige Dateien aus sich heraus erstellen kann. Da mit Pointern gearbeitet wird und somit in der CatchFile()-Prozedur keine Codespezifischen Variablen vorkommen, sollte der Code in allen anderen Codes problemlos einzubinden sein. Zudem kann durch die Arbeit mit Pointern die Prozedur beliebig oft für verschiedene Dateien verwendet werden.
Doch die Vorteile, die sich durchs Olaf's Idee ergeben, sind so groß, daß man unbedingt dieses Projekt weiter verfolgen muß.
Leonhard scheint eine ähnliche Ansicht zu haben, sonst hätte er doch nicht eine verbesserte Prozedur geliefert.

@Leonhard
Es wäre sehr freundlich von dir, wenn du deine Prozedur durch einen Prozedur-Aufruf, wie Olaf es vorgemacht hat, erweiterst.
Hier lesen auch eine große Zahl von Anfängern mit, die nicht unbedingt wissen, woher du *memory und length nimmst. Allen Anderen erleichtert es das schnelle Testen.