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 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
| unit FileVersionInfo;
interface
uses Windows, Types, SysUtils;
function GetFileVersionInfoList(const aFileName :TFileName) :TStringDynArray;
implementation
// - Ces structures ne sont que des prototypes, leurs tailles sont variables et dépendent des Children
// (TVersionInfo, TStringFileInfo, TStringTable) ou de la longueur des chaînes (TString).
// - Les Children et Value sont toujours alignés sur 32 bits. Les "Padding" serviraient à assurer cet
// alignement si la somme des tailles des données précédentes n'étaient pas multiple de 4 octets.
// Il n'y a ici aucune structure le demandant mais Padding est laissé en commentaire pour info.
// - Les Children sont déclarés en "array[0..0] of" uniquement pour rappeler qu'il s'agit de tableaux mais
// il est impossible d'atteindre un élément par son indice puisque les Children sont de taille variable.
// On récupère la position du Child suivant en ajoutant au pointeur la taille du Child courant (plus le
// complément pour un alignement sur 32 bits).
type
//https://msdn.microsoft.com/en-us/library/windows/desktop/ms646987(v=vs.85).aspx
PString = ^TString;
TString = record
wLength :word;
wValueLength :word;
wType :word;
szKey :array[0..0] of widechar; //La clé, chaîne de longeur variable à #0 terminal.
//Padding :array[0..0] of word;
//Value :array[0..0] of widechar; //szKey étant de taille variable, déclarer Value est parfaitement inutile.
//On trouve sa position (offset) en soustrayant sa taille (wValueLength) à
//la taille de la structure (wLength).
//La valeur est une chaîne à #0 terminal.
function Key: string;
function Value: string;
end;
//https://msdn.microsoft.com/en-us/library/windows/desktop/ms646992(v=vs.85).aspx
PStringTable = ^TStringTable;
TStringTable = record
wLength :word;
wValueLength :word;
wType :word;
szKey :array[0..8] of widechar; //Chaîne à #0 terminal représentant la langue et le codepage au format héxa.
//Padding :array[0..0] of word;
Children :array[0..0] of TString; //Liste des paires clé=valeur
function First(var P: PString): boolean;
function Next(var P: PString): boolean;
end;
//https://msdn.microsoft.com/en-us/library/windows/desktop/ms646989(v=vs.85).aspx
PStringFileInfo = ^TStringFileInfo;
TStringFileInfo = record
wLength :word;
wValueLength :word;
wType :word;
szKey :array[0..Length('StringFileInfo')] of widechar; //Vaut toujours 'StringFileInfo'#0
//Padding :array[0..0] of word;
Children :array[0..0] of TStringTable; //Liste des tables par langue/codepage
function First(var P: PStringTable): boolean;
function Next(var P: PStringTable): boolean;
end;
//https://msdn.microsoft.com/en-us/library/windows/desktop/ms647001(v=vs.85).aspx
PVersionInfo = ^TVersionInfo;
TVersionInfo = record
wLength :word;
wValueLength :word;
wType :word;
szKey :array[0..Length('VS_VERSION_INFO')] of widechar; //Vaut toujours 'VS_VERSION_INFO'#0
//Padding1 :array[0..0] of word;
Value :TVSFixedFileInfo; //Information de version non localisée
//Padding2 :array[0..0] of word;
Children :array[0..0] of TStringFileInfo; //StringFileInfo et/ou VarFileInfo
function Get(var P: PStringFileInfo): boolean;
end;
{ TVersionInfo }
function TVersionInfo.Get(var P: PStringFileInfo): boolean;
begin
P := @Children;
Result := SameText(P.szKey, 'StringFileInfo');
end;
{ TStringFileInfo }
function TStringFileInfo.First(var P: PStringTable): boolean;
begin
P := @Children;
Result := integer(P) < integer(@Self) +wLength;
end;
function TStringFileInfo.Next(var P: PStringTable): boolean;
begin
//Les données sont alignées sur 32 bits
inc(PByte(P), P.wLength +P.wLength mod SizeOf(dword));
Result := integer(P) < integer(@Self) +wLength;
end;
{ TStringTable }
function TStringTable.First(var P: PString): boolean;
begin
P := @Children;
Result := integer(P) < integer(@Self) +wLength;
end;
function TStringTable.Next(var P: PString): boolean;
begin
//Les données sont alignées sur 32 bits
inc(PByte(P), P.wLength +P.wLength mod SizeOf(dword));
Result := integer(P) < integer(@Self) +wLength;
end;
{ TString }
function TString.Key: string;
begin
Result := PChar(@szKey);
end;
function TString.Value: string;
var
P :PByte;
begin
//szKey étant de longueur variable, il faut
//localiser Value depuis la fin de la structure.
P := @Self;
inc(P, wLength -wValueLength *SizeOf(word));
Result := PChar(P);
end;
//=============================================================================
function GetFileVersionInfoList(const aFileName :TFileName) :TStringDynArray;
var
Block :PVersionInfo;
Size :cardinal;
Dummy :cardinal;
StringFileInfo :PStringFileInfo;
StringTable :PStringTable;
S :PString;
//---------------------------------------------
procedure Add(aIdent :integer; aText :string);
begin
SetLength(Result, Length(Result) +1);
Result[High(Result)] := StringOfChar(#9, aIdent) +aText;
end;
//---------------------------------------------
begin
SetLength(Result, 0);
Size := GetFileVersionInfoSize(PChar(aFileName), Dummy);
if Size > 0 then
begin
GetMem(Block, Size);
if GetFileVersionInfo(PChar(aFileName), 0, Size, Block) then
begin
if Block.Get(StringFileInfo) then
begin
Add(0, 'StringFileInfo');
if StringFileInfo.First(StringTable) then
repeat
Add(1, StringTable.szKey);
if StringTable.First(S) then
repeat
Add(2, S.Key +'=' + S.Value);
until not StringTable.Next(S);
until not StringFileInfo.Next(StringTable);
end;
end;
end;
end;
end. |
Partager