AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Win32/Win64 API (native code) Delphi StringFileInfo/VarFileInfo für Dateiversion schreiben

StringFileInfo/VarFileInfo für Dateiversion schreiben

Ein Thema von Mazel · begonnen am 24. Mai 2009 · letzter Beitrag vom 14. Jul 2009
Antwort Antwort
Benutzerbild von Mazel
Mazel

Registriert seit: 11. Nov 2005
Ort: Leipzig
831 Beiträge
 
#1

StringFileInfo/VarFileInfo für Dateiversion schreiben

  Alt 24. Mai 2009, 09:15
Guten Morgen,

nachdem es mir mit der Hilfe von Zacherl gelungen ist, die Versionsinformation mittels UpdateResource zu einer Datei hinzuzufügen, stehe ich nun vor dem Problem die StringFileInfo zu setzen bzw. zu schreiben. Auf den msdn Seiten sind die nötigen Strukturen (StringFileInfo, VS_VERSIONINFO) gut beschrieben, jedoch ist mir nicht klar, wie ich der einen Struktur - VS_VERSIONINFO - die Struktur der StringFileInfo übergebe, da es eigentlich ein Word Array sein müsste.
Genauso muss auch die VarFileInfo geschrieben werden.
Ohne diese beiden Informationen wird der Reiter unter Windows nicht richtig dargestellt. (siehe Anhang)

Hat jemand dies schonmal getan, wenn ja, mit welcher Technik. Ich habe bei meinen Recherchen einen Ansatz gefunden, der Streams verwendetet, leider ist mir die URL abhanden gekommen.

Würde mich auf Antworten freuen.

Gruß
Mazel
Miniaturansicht angehängter Grafiken
infoinhalt_ohne_stringfileinfo_und_varfileinfo_677.png   leere_versionsinfo_169.png  
Marcel Jänicke
www.mj-software.net
  Mit Zitat antworten Zitat
Benutzerbild von sx2008
sx2008

Registriert seit: 16. Feb 2008
Ort: Baden-Württemberg
2.332 Beiträge
 
Delphi 2007 Professional
 
#2

Re: StringFileInfo/VarFileInfo für Dateiversion schreiben

  Alt 25. Mai 2009, 06:00
Die Strukturen werden einfach hintereinander "geklebt".
Man kann keine normalen Pascal Records verwenden, sondern man braucht einen Speicherblock (mit GetMem) und baut dann dort die Strukturen auf.
Die Herausforderung ist dann, dass wLength von VS_VERSIONINFO auch alle weiteren StringFileInfo Blöcke berücksichtigen muss.
  Mit Zitat antworten Zitat
Benutzerbild von Mazel
Mazel

Registriert seit: 11. Nov 2005
Ort: Leipzig
831 Beiträge
 
#3

Re: StringFileInfo/VarFileInfo für Dateiversion schreiben

  Alt 25. Mai 2009, 19:16
Hallo und danke für deine Antwort.

Mit GetMem arbeiten, ok. Das heißt in dem Fall für jeden Block den ich hizufüge oder von vorn herein soviel reservieren, wie cih für alles benötige, was zur Folge habe muss, dass ich vorher die Größe brauch.

Hast du eventuell ein Beispiel?

Ich habe mir gestern eine Variante überlegt, die funktioniert aber nicht "das Wahre" ist. Ich habe aus ResHacker eine binäre Datei erstellt die eine vollständige VERSIONINFO Struktur mit allen unterstrukturen enthält. Diese lade über ein FileStream in mein Programm und übergebe diese dann per UpdateResource an die jeweilige Anwendung. Nachteil ist aber dabei, dass ich danach wieder die Werte ändern muss und so wieder vor dem Problem stehe. Hier mal der Code dazu, eventuell kann man mir daraus auch einen weiteren Tipp geben.
Delphi-Quellcode:
{--[AddResourceStruture]-------------------------------------------------------}

function AddResourceStruture(ExecutableFile: String): Boolean;
var
 FileStream : TFileStream;
 ResourceHandle : THandle;
 DataLength : Cardinal;
 Data : Pointer;
 Path : String;

begin
 Result := False;
 Path := ExtractFilePath(ParamStr(0));
 if not EndsWith(Path, '\') then Path := Path + '\';
 Path := Path + 'Resource\VSResource.bin';
 ResourceHandle := BeginUpdateResource(PChar(ExecutableFile), False);
 if (ResourceHandle <> 0) then
  begin
   FileStream := TFileStream.Create(Path, fmOpenRead);
   FileStream.Seek(0, soFromBeginning);
   DataLength := FileStream.Size;
   try
    GetMem(Data, DataLength);
    FileStream.Read(Data^, DataLength);
    FileStream.Free;
    Result := True;
    // for german language only - 1031
    if not UpdateResource(ResourceHandle, RT_VERSION, MakeIntResource(1), 1031, Data, DataLength) then Result := False;
    if not EndUpdateResource(ResourceHandle, False) then Result := False;
   finally
    FreeMem(Data);
   end;
   ShowMessage(SysErrorMessage(GetLastError));
  end;
end;
Gruß
Mazel
Marcel Jänicke
www.mj-software.net
  Mit Zitat antworten Zitat
Benutzerbild von sx2008
sx2008

Registriert seit: 16. Feb 2008
Ort: Baden-Württemberg
2.332 Beiträge
 
Delphi 2007 Professional
 
#4

Re: StringFileInfo/VarFileInfo für Dateiversion schreiben

  Alt 26. Mai 2009, 06:10
Zitat von Mazel:
Das heißt in dem Fall für jeden Block den ich hizufüge oder von vorn herein soviel reservieren, wie cih für alles benötige, was zur Folge habe muss, dass ich vorher die Größe brauch.
Genau das ist das Problem, was die Sache so knifflig macht.
Eine Möglichkeit wäre, mit den innersten String Structure zu beginnen und diese dann zu einer StringTable Structure zusammenzubauen, die dann wiederum zur StringFileInfo Structure aufgebaut wird.

Hier völlig ungetestet als Anregung:
Delphi-Quellcode:
function BuildStringStructure(Key, Value : Widestring):Ansistring;
var
  p : PInteger;
begin
   key := key + #0; // Terminierung mit 0x0000
   if odd(length(key)) then
      key := key + #0; // auf 32-bit boundary bringen

   SetLength(result, 2 + 2 + 2+ 2*Length(key) + 2 * Length(Value))
   p := PInteger(PChar(result));
   p^ := length(Result); // WORD wLength befüllen
   Inc(p);
   p^ := length(Value) * 2; // WORD wValueLength befüllen
   Inc(p);
   p^ := 1; // WORD wType
   Inc(p);
   // jetzt muss noch Key und Value in den Resultstring kopiert werden (mit Move())
   // ich spar mir das mal
end;
Damit kann man jetzt mehrere String Structures zusammen verketten:
data := BuildStringStructure('Comments', 'ein Test') + BuildStringStructure('CompanyName', 'DP') + .... Jetzt muss das zu einer StringTable Structure aufgebaut werden:
function BuildStringTableStructure(Key:WideString; const Children:Ansistring):AnsiString; Wenn man soweit ist, ist der Aufbau der StringFileInfo Structure relativ einfach:
Delphi-Quellcode:
function BuildStringFileInfoStructure(Key:WideString; const Children:Ansistring):AnsiString;
begin
   Result := BuildStringTableStructure('StringFileInfo', Children);
end;
  Mit Zitat antworten Zitat
Benutzerbild von Mazel
Mazel

Registriert seit: 11. Nov 2005
Ort: Leipzig
831 Beiträge
 
#5

Re: StringFileInfo/VarFileInfo für Dateiversion schreiben

  Alt 26. Mai 2009, 20:10
Guten Abend,

danke für diese schönen Tipps. Ich habe jetzt schonmal versucht etwas zu kreieren, bin aber bis jetzt noch zu keinem Erfolg gekommen und zum zeigen muss ich noch einiges zusammenfassen und weiter ausprobieren.
Es ist eben nicht einfach diese Struktur zusammen zubauen

Wenn ich dein Code als Grundlage nehme verarbeite ich am Ende den AnsiChar. Ich bräuchte ja aber den Pointer, damit ich diesen an Children weitergeben kann.

Btw.: ich hatte von Zacherl folgende Strukturen bekommen, die ich ein wenig aufgebessert habe, damit es funktioniert.
Delphi-Quellcode:
type
  TFIXEDFILEINFO = packed record
    dwSignature: DWord;
    dwStrucVersion: DWord;
    dwFileVersionMS: DWord;
    dwFileVersionLS: DWord;
    dwProductVersionMS: DWord;
    dwProductVersionLS: DWord;
    dwFileFlagsMask: DWord;
    dwFileFlags: DWord;
    dwFileOS: DWord;
    dwFileType: DWord;
    dwFileSubtype: DWord;
    dwFileDateMS: DWord;
    dwFileDateLS: DWord;
  end;

     TVERSIONSTRING = packed record
    wLength: Word;
    wValueLength: Word;
    wType: Word;
    {$IFDEF D12ORABOVE}
    szKey: String;
    {$ELSE}
    szKey: WideString;
    {$ENDIF}
    Padding: TWordArray;
    {$IFDEF D12ORABOVE}
    Value: String;
    {$ELSE}
    Value: WideString;
    {$ENDIF}
  end;

  TVERSIONSTRINGTABLE = packed record
    wLength: Word;
    wValueLength: Word;
    wType: Word;
    {$IFDEF D12ORABOVE}
    szKey: Array[0..8] of Char;
    {$ELSE}
    szKey: Array[0..8] of WideChar;
    {$ENDIF}
    Padding: TWordArray;
    Children: array of TVERSIONSTRING;
  end;
  TSTRINGFILEINFO = packed record
    wLength: Word;
    wValueLength: Word;
    wType: Word;
    {$IFDEF D12ORABOVE}
    szKey: Array[0..14] of Char;
    {$ELSE}
    szKey: Array[0..14] of WideChar;
    {$ENDIF}
    Padding: TWordArray;
    Children: Array of TVERSIONSTRINGTABLE;
  end;

  TVERSIONINFO = packed record
    wLength: Word;
    wValueLength: Word;
    wType: Word;
    szKey: Array[0..15] of WideChar;
    Padding1: Word;
    Value: TFIXEDFILEINFO;
    Padding2: Word;
    Children: Array of TSTRINGFILEINFO;
  end;
Anfangs gab es Probleme in der Reihenfolge, nachdem ich das geändert hatte konnte ich die VERSIONINFO schreiben, aber die children gehen bis heute noch nicht, da tu ich mich wohl etwas schwer.

Gruß
Mazel
Marcel Jänicke
www.mj-software.net
  Mit Zitat antworten Zitat
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.629 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#6

Re: StringFileInfo/VarFileInfo für Dateiversion schreiben

  Alt 27. Mai 2009, 08:30
Ich hatte es damals so gemacht, dass ich zuerst die Strukturen aufgebaut habe, wobei ich die Größe erst einmal komplett umberechnet gelassen habe.
In einem zweiten Durchgang habe ich dann für jeden Zweig jeweils von innen nach außen die Größe berechnet. Bei dieser Struktur ist dies ja gar nicht mal so schwer, da die Anzahl der Zweige statisch gestaltet ist.
  Mit Zitat antworten Zitat
Benutzerbild von sx2008
sx2008

Registriert seit: 16. Feb 2008
Ort: Baden-Württemberg
2.332 Beiträge
 
Delphi 2007 Professional
 
#7

Re: StringFileInfo/VarFileInfo für Dateiversion schreiben

  Alt 27. Mai 2009, 09:53
Zitat von Mazel:
Wenn ich dein Code als Grundlage nehme verarbeite ich am Ende den AnsiChar. Ich bräuchte ja aber den Pointer, damit ich diesen an Children weitergeben kann.
Nein, man kann doch AnsiStrings wunderbar mit dem pluszeichen miteinander verketten.
Dabei werden die beteiligten Stringstücke in einen neuen String kopiert.
Mit der Technik von Zacherl könnte man sich die kopierei sparen, aber so ist es viel eleganter.

alles ungetestet:
Delphi-Quellcode:
function BuildStringStructure(Key, Value : Widestring):Ansistring;
var
  p : PInteger;
begin
   key := key + #0; // Terminierung mit 0x0000
   if odd(length(key)) then
      key := key + #0; // auf 32-bit boundary bringen

   SetLength(result, 2 + 2 + 2+ 2*Length(key) + 2 * Length(Value))
   p := PInteger(PChar(result));
   p^ := length(Result); // WORD wLength befüllen
   Inc(p);
   p^ := length(Value) * 2; // WORD wValueLength befüllen
   Inc(p);
   p^ := 1; // WORD wType
   Inc(p);

   // Key und Value auf den Ergebnisstring kopieren
   Move(key[1], p^, length(key)*2);
   Inc(p, length(key)*2);
   Move(Value, p^, length(value)*2);
   // hoffentlich war die Längenberechnung von result richtig ;-)
end;

function BuildStringTableStructure(Key:WideString; const Children:Ansistring):AnsiString;
var
  p : PInteger;
begin
   key := key + #0; // Terminierung mit 0x0000
   if odd(length(key)) then
      key := key + #0; // auf 32-bit boundary bringen

   SetLength(result, 2 + 2 + 2+ 2*Length(key)); // wird später noch länger...
   p := PInteger(PChar(result));
   p^ := length(Result) + length(Children); // WORD wLength befüllen
   Inc(p);
   p^ := length(Children) * 2; // WORD wValueLength befüllen
   Inc(p);
   p^ := 1; // WORD wType
   Inc(p);
   Move(key[1], p^, length(key)*2);

   // einfach den übergebenen Children-Datenblock hinten anhängen
   Result := Result + Children;
end;

function BuildStringFileInfoStructure(const Children:Ansistring):AnsiString;
begin
   Result := BuildStringTableStructure('StringFileInfo', Children);
end;

function BuildVarSructure(Value : Widestring):Ansistring;
begin
  Result := BuildStringStructure('Translation', Value);
end;
und dann die Daten quasi von Innen nach Aussen aufbauen:
Delphi-Quellcode:
data := BuildStringStructure('Comments', 'ein Test') + BuildStringStructure('CompanyName', 'DP') + ....;
data := BuildStringTableStructure(LANG_CODE_8BYTES, data);
data := BuildStringFileInfoStructure(data);
Jetzt fehlt nur noch die VS_VERSIONINFO Structure:
function BuildVersionInfoStructure(const fixedinfo:TFIXEDFILEINFO;const Children:Ansistring):AnsiString;
  Mit Zitat antworten Zitat
rakekniven

Registriert seit: 4. Apr 2008
Ort: Franken
82 Beiträge
 
Delphi XE5 Professional
 
#8

Re: StringFileInfo/VarFileInfo für Dateiversion schreiben

  Alt 14. Jul 2009, 16:07
Hallo,

in dem Zusammhang habe ich eine Frage zur LCID.

In ganz vielen Beiträgen im Internet wird ja beschrieben wie man seine Versionsinformationen in einer Textdatei zu pflegen.

Wir haben sie "Version.RC" genannt und folgenden Block drin

BLOCK "VarFileInfo"
{
VALUE "Translation", 1031, 1252
}

Viele der genannten Seiten haben anstattt "1031" den Wert "1033" drin.
Warum?

Bei einigen Projekten hier war auch bei uns "1033" drin.
Windows schluckt das und zeigt im Windows-Explorer die Infos richtig an.

Heute haben wir eine Funktion gesucht zum Auslesen der Versionsinformationen und sind dabei über http://www.delphipraxis.net/internal...t.php?t=159069 gestolpert.

Der Code funktioniert mit "1031, 1252" sehr gut, mit "1033, 1252" liefert er Schrott zurück.
Ich vermute dass der Grund ist, dass die LCID nicht zur Codepage passt.

Weiss hier jemand mehr?

Gruß
Frag google
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 11:12 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz