- Offizieller Beitrag
Hi,
mit FileInstall oder Speichern des Binärcodes von Ressourcen direkt im Skript kann ich nur eine vorher festgelegte Quantität und Qualität dieser Ressourcen verwenden. D.h., wenn ich z.B. ein Bild aktualisieren möchte, muß das Skript dann auch neu kompiliert werden.
Kann man natürlich umgehen, wenn man die Ressourcen auslagert. Dabei ist es jedoch nicht sehr schick, wenn eine Handvoll Dateien im Verzeichnis "rumlungern". Mit nur einer ist das doch viel eleganter.
Und um es so einfach, wie möglich handhaben zu können, sollte es auch nicht unbedingt in einer Dll landen.
Deshalb habe ich zwei Tools erstellt, einmal zum Einfügen/Austauschen von Ressourcen in einem Ressourcencontainer und einmal um gezielt Ressourcen aus diesem Container in eine Zieldatei zu installieren.
Das Erstellen des Containers kann per Kommandozeile oder GUI erfolgen. Bei der GUI-Variante ist sowohl Drag&Drop als auch Auswahl per FileOpenDialog (beides mit Mehrfachauswahl) möglich.
Soll eine Komponente aktualisiert werden: Container aufrufen mit der Komponente und ein Überschreibflag setzen.
Dateiname.Suffix der eingefügten Komponenten sind auch die Identifier um die jeweilige Komponente wieder abzurufen.
Es wird bei jedem Erstellen/Hinzufügen von Komponenten auf eventuell bereits vorhandene Doppel dieser Komponenten geprüft. Ist das Überschreibflag nicht gesetzt, bleiben die vorhandenen Versionen erhalten.
Wenn ihr mal vergessen habt, was eigentlich im Container enthalten ist: Mit "SourceFromContainer.exe <Ressourcendatei> LIST" werden die Identifier der Komponenten ausgelesen und in die Zwischenablage übergeben.
Für den Container verwende ich das Suffix *.rbn ( ressourcen binär ). Eine Ressourcencontainer ist folgendermaßen aufgebaut:
Das heißt also auch: NIEMALS eine Containerdatei mit SciTE öffnen! Bei kleineren Dateien mag das noch gehen, aber schon unter 100 kB ist der Binärstring deutlich länger als das, was SciTE verkraften kann. Es schmiert dann einfach ab.
Es spielt keine Rolle, was ihr in den Container packt. Bilder, Texte für Controls, Sounddateien - alles kann rein. Nur sollte man das nicht als Bibliothek oder Mediathek betrachten. Dazu ist es nicht gedacht. Das kleine Gerümpel, das sonst im Programmverzeichnis dümpelt, soll einen Ruheplatz finden.
Erstellen eines Ressourcen Containers per Kommandozeile:
Spoiler anzeigen
$sPathRessource = "C:\Users\Standard\Code_AutoIt\TEST\Ressourcencontainer\RessContainer1.rbn"
$sPathDigi = 'C:\Pict\digicam_blau_200x150.jpg'
$sPathNPP = 'C:\Pict\Ico\npp_64x64.ico'
$sPathVideo = 'C:\Pict\Ico\videocam_87x96.ico'
RunWait("C:\Tools\SourceToContainer.exe " & $sPathRessource & " " & $sPathDigi & " " & $sPathNPP & " " & $sPathVideo)
[/autoit]SourceToContainer(0.1) Kommandozeile und GUI
#Region - TimeStamp
; 2011-11-17 00:10:37 v 0.1
#EndRegion - TimeStamp
#include-once
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#cs
MUSTER AUFRUF:
"..\SourceToContainer.exe <Ressourcendatei> <Quelldatei_1> <Quelldatei_2..n> [ optional: Überschreibflag = 1 ]
"..\SourceToContainer.exe C:\bla\Ressource.rbn C:\Pict\picture1.jpg C:\Pict\picture2.jpg C:\Pict\picture3.jpg"
mit Überschreib-Flag
"..\SourceToContainer.exe C:\bla\Ressource.rbn C:\Pict\picture2.jpg 1"
#ce
;===============================================================================
; Script Name......: SourceToContainer.au3
; Description......: Quelldatei(en) als Binärstring in eine Ressourcendatei schreiben (neu erstellen od. hinzufügen/überschreiben), Dateityp (*.rbn) (RessourceBiNär)
; Dateiname.Suffix als Identifier
; Existiert eine Ressource bereits, wird diese bei gesetztem Überschreib-Flag überschrieben. Ohne Flag bleibt die vorhandene Version erhalten.
; Mit SourceFromContainer.au3 wird aus der Ressourcendatei dann die gewünschte Quelldatei wieder ausgelesen und installiert.
; AutoIt version...: 3.3.6.1
; Author(s)........: BugFix ( [email='bugfix@autoit.de'][/email] )
;===============================================================================
Global $sPathRess, $aFiles[1], $fOverwrite = False
[/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]; == Kommandozeilen-Variante
If $CMDLINE[0] Then ; == [1]=Pfad_Ressourcendatei; [2..[0]-1]=Pfade_Quelldateien; [[0]-1]=optional_Flag_Overwrite(1) - Default nicht gesetzt
$sPathRess = $CMDLINE[1]
ReDim $aFiles[$CMDLINE[0] -1]
For $i = 2 To $CMDLINE[0]
$aFiles[$i-2] = $CMDLINE[$i]
If $CMDLINE[$i] = 1 Then
$fOverwrite = True
ReDim $aFiles[$CMDLINE[0] -2]
ExitLoop
EndIf
Next
__AddOrCreateBin($sPathRess, $aFiles, $fOverwrite)
Exit
EndIf
; == GUI-Variante
$hMain = GUICreate(' Ressourcencontainer Erstellen oder Dateien Hinzufügen', 600, 190, -1, -1, -1, $WS_EX_ACCEPTFILES)
GUICtrlCreateGroup(' Quelldatei(en) Pfad(e) ', 10, 10, 580, 60)
$inSource = GUICtrlCreateInput('', 20, 35, 525, 20)
GUICtrlSetState(-1, $GUI_DROPACCEPTED)
$btSource = GUICtrlCreateButton('...', 555, 35, 25, 20)
GUICtrlCreateGroup('', -99, -99, 1, 1)
GUICtrlCreateGroup(' Ressourcencontainer [ Zieldatei (*.rbn) ] ', 10, 80, 580, 60)
$inDest = GUICtrlCreateInput('', 20, 105, 525, 20)
GUICtrlSetState(-1, $GUI_DROPACCEPTED)
$btDest = GUICtrlCreateButton('...', 555, 105, 25, 20)
GUICtrlCreateGroup('', -99, -99, 1, 1)
$btRun = GUICtrlCreateButton('Start', 500, 155, 80, 20)
$cbOverwrite = GUICtrlCreateCheckbox(' Ressourcen, wenn bereits vorhanden, überschreiben', 20, 158, 300, 17)
GUISetState()
WinSetOnTop($hMain, '', 1)
While 1
Switch GUIGetMsg()
Case -3
Exit
Case $btSource
WinSetOnTop($hMain, '', 0)
$sRead = FileOpenDialog('Quelldatei(en)', @CommonFilesDir, 'Alle (*.*)', 7)
If $sRead <> '' Then
$aTmp = StringSplit($sRead, '|')
If $aTmp[0] = 1 Then
GUICtrlSetData($inSource, $sRead)
Else
$sRead = ''
For $i = 2 To $aTmp[0]
$sRead &= $aTmp[1] & '\' & $aTmp[$i] & '|'
Next
GUICtrlSetData($inSource, StringTrimRight($sRead, 1))
EndIf
EndIf
WinSetOnTop($hMain, '', 1)
Case $btDest
WinSetOnTop($hMain, '', 0)
$sRead = FileOpenDialog('Ressourcendatei', @CommonFilesDir, 'Ressource Binär (*.rbn)', 10)
If $sRead <> '' Then
If StringRight($sRead, 4) <> '.rbn' Then $sRead &= '.rbn'
GUICtrlSetData($inDest, $sRead)
EndIf
WinSetOnTop($hMain, '', 1)
Case $btRun
If GUICtrlRead($inSource) <> '' Then
$aFiles = StringSplit(GUICtrlRead($inSource), '|', 2)
If GUICtrlRead($inDest) <> '' Then
$sPathRess = GUICtrlRead($inDest)
If BitAND(GUICtrlRead($cbOverwrite), $GUI_CHECKED) Then $fOverwrite = True
__AddOrCreateBin($sPathRess, $aFiles, $fOverwrite)
Else
GUICtrlSetData($inDest, 'D E S T I N A T I O N !!!')
Sleep(600)
GUICtrlSetData($inDest, '')
EndIf
Else
GUICtrlSetData($inSource, 'S O U R C E !!!')
Sleep(600)
GUICtrlSetData($inSource, '')
EndIf
EndSwitch
WEnd
Func __AddOrCreateBin($sPathRess, ByRef $aFiles, $fOverwrite=False)
Local $hFile, $bRead, $sToWrite = '', $sFileName, $sFileErr = '', $sMsg = "erstellt."
Local $n = UBound($aFiles), $nErr = 0, $aContent, $aExisting[1][2] = [[0]], $ret, $x
If StringRight($sPathRess, 4) <> '.rbn' Then $sPathRess &= '.rbn'
If FileExists($sPathRess) Then
$sToWrite = FileRead($sPathRess)
$sMsg = "erweitert."
; == Check ob Dateien bereits vorhanden
$aContent = StringSplit($sToWrite, @CRLF, 1)
For $i = 0 To UBound($aFiles) -1
$ret = __RessourceGetLine($aContent, __GetFileName($aFiles[$i]))
If $ret > 0 Then
$aExisting[0][0] += 1
ReDim $aExisting[$aExisting[0][0] +1][2]
$aExisting[$aExisting[0][0]][0] = $i
$aExisting[$aExisting[0][0]][1] = $ret
EndIf
Next
; == wenn Überschreibmodus und Doppel vorhanden ==> Doppel löschen durch Kopieren bleibender Inhalte in $sToWrite
If $fOverwrite And $aExisting[0][0] > 0 Then
Local $sTmpWrite = ''
For $i = 1 To $aContent[0] -3 Step 3
$x = 0
For $j = 1 To $aExisting[0][0]
If $aExisting[$j][1] = $i Then
$x = 1
ExitLoop
EndIf
Next
If $x = 0 Then
$sTmpWrite &= $aContent[$i] & @CRLF & $aContent[$i+1] & @CRLF & $aContent[$i+2] & @CRLF
EndIf
Next
$sToWrite = $sTmpWrite
EndIf
EndIf
For $i = 0 To UBound($aFiles) -1
If Not FileExists($aFiles[$i]) Then
$sFileErr &= $aFiles[$i] & @CRLF
$nErr += 1
ContinueLoop
EndIf
If $aExisting[0][0] > 0 Then
$x = 0
For $j = 1 To $aExisting[0][0]
If $aExisting[$j][0] = $i Then
$x = 1
ExitLoop
EndIf
Next
If ($x = 1) And (Not $fOverwrite) Then ; == Doppel u. kein $fOverwrite ==> nicht hinzufügen
$n -= 1 ; == Dateizähler für Msg
ContinueLoop
EndIf
EndIf
$hFile = FileOpen($aFiles[$i], 16) ; == es existieren Doppel, wenn $fOverwrite, wurden diese gelöscht ==> müssen neu hinzugefügt werden
$bRead = FileRead($hFile)
FileClose($hFile)
$sFileName = __GetFileName($aFiles[$i])
$sToWrite &= '<' & $sFileName & '>' & @CRLF & _ ; == <Name.Suffix>
$bRead & @CRLF & _ ; == Binärstring
'</' & $sFileName & '>' & @CRLF ; == </Name.Suffix>
Next
If $sToWrite <> '' Then
$hFile = FileOpen($sPathRess, 2)
FileWrite($hFile, $sToWrite)
FileClose($hFile)
EndIf
If Not $nErr Then
MsgBox(262208,"Ressourcen Container","Die Ressourcendatei " & @CRLF & $sPathRess & @CRLF & "wurde mit " & $n & " Datei(en) " & $sMsg)
Else
$sMsg = "Von " & $n & " Datei(en) waren " & $nErr & " Datei(en) unter dem angegebenen Pfad nicht vorhanden:" & @CRLF & $sFileErr & @CRLF & "Die Ressourcen Datei wurde "
Select
Case ($sToWrite = '') And ($n = $nErr)
$sMsg &= 'nicht erstellt!'
Case $sToWrite = ''
$sMsg &= 'ohne die angeführte(n) Datei(en) erstellt!'
Case ($sToWrite <> '') And ($n = $nErr)
$sMsg &= 'nicht erweitert!'
Case $sToWrite <> ''
$sMsg &= 'ohne die angeführte(n) Datei(en) erweitert!'
EndSelect
MsgBox(262192,"Ressourcen Datei - Fehler", $sMsg)
EndIf
EndFunc
Func __GetFileName($sFullPath)
Return StringTrimLeft($sFullPath, StringInStr($sFullPath, '\', 1, -1))
EndFunc
Func __RessourceGetLine(ByRef $aContent, $sSearch)
Local $iLine = 0
For $i = 1 To $aContent[0] Step 3
If $aContent[$i] = '<' & $sSearch & '>' Then
$iLine = $i
ExitLoop
EndIf
Next
Return $iLine
EndFunc
Dateien aus dem Ressourcen Container in das TempDir installieren:
Spoiler anzeigen
$sPathRessource = "C:\Users\Standard\Code_AutoIt\TEST\Ressourcencontainer\RessContainer1.rbn"
$sFileDigi = 'digicam_blau_200x150.jpg'
$sFileNPP = 'npp_64x64.ico'
$sFileVideo = 'videocam_87x96.ico'
RunWait("C:\Tools\SourceFromContainer.exe " & $sPathRessource & " " & $sFileDigi & " " & @TempDir & "\" & $sFileDigi)
RunWait("C:\Tools\SourceFromContainer.exe " & $sPathRessource & " " & $sFileNPP & " " & @TempDir & "\" & $sFileNPP)
RunWait("C:\Tools\SourceFromContainer.exe " & $sPathRessource & " " & $sFileVideo & " " & @TempDir & "\" & $sFileVideo)
SourceFromContainer(0.1) Kommandozeile
#Region - TimeStamp
; 2011-11-17 00:09:59 v 0.1
#EndRegion - TimeStamp
#cs
MUSTER AUFRUF:
"..\SourceFromContainer.exe <Ressourcendatei> <Identifier-Ressource> <Installationspfad>"
"..\SourceFromContainer.exe C:\bla\Ressource.rbn picture1.jpg " & @TempDir & "\picture1.jpg"
[/autoit] [autoit][/autoit] [autoit]AUFLISTUNG der Ressourcen eines Containers:
"..\SourceFromContainer.exe <Ressourcendatei> LIST"
"..\SourceFromContainer.exe C:\bla\Ressource.rbn LIST"
schreibt Ressourcen-Identifier in die Zwischenablage:
Pict1.jpg
Message1.txt
Program1.ico
#ce
;===============================================================================
; Script Name......: SourceFromContainer.au3
; Description......: Binärstring (Dateiname.Suffix als Identifier) aus Ressourcendatei lesen und damit Zieldatei erstellen (neu erstellen od. hinzufügen/überschreiben)
; Ressourcencontainer [Dateityp (*.rbn)] muß mit SourceToContainer.au3 erstellt worden sein
; Ressourcen Identifier eines Containers lassen sich mit LIST in die Zwischenablage ausgeben
; AutoIt version...: 3.3.6.1
; Author(s)........: BugFix ( [email='bugfix@autoit.de'][/email] )
;===============================================================================
If $CMDLINE[0] Then ; == [1]=Pfad_Ressourcendatei; [2]=zu_verwendende_Datei_aus_dem_Container; [3]=Installationspfad
Local $sPathRess, $sFileName, $sPathInstall, $aContent, $hFileOut, $sRessourcen = ''
$sPathRess = $CMDLINE[1]
If Not FileExists($sPathRess) Then Exit MsgBox(262192, 'Fehler', 'Quelldatei nicht vorhanden!')
$sFileName = $CMDLINE[2]
If $sFileName <> 'LIST' Then $sPathInstall = $CMDLINE[3]
$aContent = StringSplit(FileRead($sPathRess) , @CRLF, 1)
For $i = 1 To $aContent[0] -3 Step 3
If $sFileName = 'LIST' Then
$sRessourcen &= StringTrimLeft(StringTrimRight($aContent[$i], 1) , 1) & @CRLF
ContinueLoop
EndIf
If $aContent[$i] = '<' & $sFileName & '>' Then
$hFileOut = FileOpen($sPathInstall, 2+8+16)
FileWrite($hFileOut, Binary($aContent[$i+1]))
FileClose($hFileOut)
Exit
EndIf
Next
If $sFileName = 'LIST' Then Exit ClipPut($sRessourcen)
Exit MsgBox(262192, 'Fehler', '"' & $sFileName '" nicht im Ressourcencontainer enthalten!')
EndIf
Edit 17.11.2011:
Hier mal noch ein Muster, wie man ein Skript gestalten kann, um die Ressourcen mit einem einfachen Kommandozeilenaufruf upzudaten oder zu erweitern.
Spoiler anzeigen
; == die Tools per FileInstall im Skript verfügbar machen
FileInstall("C:\Tools\SourceToContainer.exe", @TempDir & "\SourceToContainer.exe")
FileInstall("C:\Tools\SourceFromContainer.exe", @TempDir & "\SourceFromContainer.exe")
Local $STCexe = @TempDir & "\SourceToContainer.exe" ; == für Updates und Hinzufügen von Ressourcen
Local $SFCexe = @TempDir & "\SourceFromContainer.exe" ; == zum Laden der Ressourcen
; == Pfad Ressourcencontainer
Local $sPathRessource = @ScriptDir & "\RessContainer1.rbn"
; == UPDATEN von Ressourcen, Kommandozeilenaufruf: "Skript.exe UPDATE <Pfad_zur_neuen_Version_von_Datei_1> <Pfad_zur_neuen_Version_von_Datei_2...n>"
; == HINZUFÜGEN von neuen Ressourcen, analog: "Skript.exe ADD <Pfad_zur_Datei_X> <Pfad_zur_Datei_Y...n>"
If $CMDLINE[0] Then
If StringInStr('UPDATE ADD', $CMDLINE[1]) Then
Local $sCmd = $STCexe & " " & $sPathRessource
For $i = 2 To $CMDLINE[0]
$sCmd &= " " & $CMDLINE[$i]
Next
If $CMDLINE[1] = 'UPDATE' Then $sCmd &= " 1"
RunWait($sCmd)
EndIf
EndIf
; == alle Identifier des Containers in Zwischenablage laden und als Array speichern
RunWait($SFCexe & " " & $sPathRessource & " LIST")
Local $aIdentifier = StringSplit(ClipGet(), @CRLF, 1)
; == alle Ressourcen des Containers im TempDir installieren
For $i = 1 To $aIdentifier[0]
RunWait($SFCexe & " " & $sPathRessource & " " & $aIdentifier[$i] & " " & @TempDir & "\" & $aIdentifier[$i])
Next
#region - Skript
; ....
; ....
; ....
#endregion
; == bei Beenden Skript sollte man die Dateien wieder löschen
For $i = 1 To $aIdentifier[0]
FileDelete(@TempDir & "\" & $aIdentifier[$i])
Next
FileDelete($STCexe)
FileDelete($SFCexe)