type
TFileInfo = packed record
CommpanyName: string;
FileDescription: string;
FileVersion: string;
InternalName: string;
LegalCopyright: string;
LegalTrademarks: string;
OriginalFileName: string;
ProductName: string;
ProductVersion: string;
Comments: string;
VsFixedFileInfo:VS_FIXEDFILEINFO;
UserDefineValue:string;
end;
///UserDefine就是用户自定义的了,返回值保存在Info.UserDefineValue中
function GetFileVersionInfomation(const FileName: string; var info: TFileInfo;UserDefine:string=''):
boolean;
const
SFInfo= '\StringFileInfo\';
var
VersionInfo: Pointer;
InfoSize: DWORD;
InfoPointer: Pointer;
Translation: Pointer;
VersionValue: string;
unused: DWORD;
begin
unused := 0;
Result := False;
InfoSize := GetFileVersionInfoSize(pchar(FileName), unused);
if InfoSize > 0 then
begin
GetMem(VersionInfo, InfoSize);
Result := GetFileVersionInfo(pchar(FileName), 0, InfoSize, VersionInfo);
if Result then
begin
VerQueryValue(VersionInfo, '\VarFileInfo\Translation', Translation, InfoSize);
VersionValue := SFInfo + IntToHex(LoWord(Longint(Translation^)), 4) +
IntToHex(HiWord(Longint(Translation^)), 4) + '\';
VerQueryValue(VersionInfo, pchar(VersionValue + 'CompanyName'), InfoPointer, InfoSize);
info.CommpanyName := string(pchar(InfoPointer));
VerQueryValue(VersionInfo, pchar(VersionValue + 'FileDescription'), InfoPointer, InfoSize);
info.FileDescription := string(pchar(InfoPointer));
VerQueryValue(VersionInfo, pchar(VersionValue + 'FileVersion'), InfoPointer, InfoSize);
info.FileVersion := string(pchar(InfoPointer));
VerQueryValue(VersionInfo, pchar(VersionValue + 'InternalName'), InfoPointer, InfoSize);
info.InternalName := string(pchar(InfoPointer));
VerQueryValue(VersionInfo, pchar(VersionValue + 'LegalCopyright'), InfoPointer, InfoSize);
info.LegalCopyright := string(pchar(InfoPointer));
VerQueryValue(VersionInfo, pchar(VersionValue + 'LegalTrademarks'), InfoPointer, InfoSize);
info.LegalTrademarks := string(pchar(InfoPointer));
VerQueryValue(VersionInfo, pchar(VersionValue + 'OriginalFileName'), InfoPointer, InfoSize);
info.OriginalFileName := string(pchar(InfoPointer));
VerQueryValue(VersionInfo, pchar(VersionValue + 'ProductName'), InfoPointer, InfoSize);
info.ProductName := string(pchar(InfoPointer));
VerQueryValue(VersionInfo, pchar(VersionValue + 'ProductVersion'), InfoPointer, InfoSize);
info.ProductVersion := string(pchar(InfoPointer));
VerQueryValue(VersionInfo, pchar(VersionValue + 'Comments'), InfoPointer, InfoSize);
info.Comments := string(pchar(InfoPointer));
if VerQueryValue(VersionInfo, '\', InfoPointer, InfoSize) then
info.VsFixedFileInfo := TVSFixedFileInfo(InfoPointer^);
if UserDefine<>'' then
begin
if VerQueryValue(VersionInfo,pchar(VersionValue+UserDefine),InfoPointer,InfoSize) then
info.UserDefineValue:=string(pchar(InfoPointer));
end;
end;
FreeMem(VersionInfo);
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
info: TFileInfo;
begin
if OpenDialog1.Execute then
begin
if GetFileVersionInfomation(opendialog1.FileName, info,'WOW Version') then
////我必须知道'WOW Version'才能知道有这么一个自定义的串。如果用户定义的是'abc'我就没有办法取得了。
////而资源管理器的版本信息中
///就不一定需要知道。它可以找出所有的版本信息。
begin
Listbox1.Items.Add(OpenDialog1.FileName);
ListBox1.Items.Add('Comments:' + info.Comments);
ListBox1.Items.Add('CommpanyName:' + info.CommpanyName);
ListBox1.Items.Add('FileDescription:' + info.FileDescription);
ListBox1.Items.Add('FileVersion:' + info.FileVersion);
ListBox1.Items.Add('InternalName:' + info.InternalName);
ListBox1.Items.Add('LegalCopyright:' + info.LegalCopyright);
ListBox1.Items.Add('LegalTrademarks:' + info.LegalTrademarks);
ListBox1.Items.Add('OriginalFileName:' + info.OriginalFileName);
ListBox1.Items.Add('ProductName:' + info.ProductName);
ListBox1.Items.Add('ProductVersion:' + info.ProductVersion);
ListBox1.Items.Add('UserDefineValue:' + info.UserDefineValue);
if boolean(info.VsFixedFileInfo.dwFileFlags and vs_FF_Debug) then
listbox1.Items.Add('Debug:True')
else
ListBox1.Items.Add('Debug:False');
ListBox1.Items.Add('');
end;
end;
end;
type
TFileInfo = packed record
CommpanyName: string;
FileDescription: string;
FileVersion: string;
InternalName: string;
LegalCopyright: string;
LegalTrademarks: string;
OriginalFileName: string;
ProductName: string;
ProductVersion: string;
Comments: string;
VsFixedFileInfo: VS_FIXEDFILEINFO;
UserDefineValue: string;
end;
PAString = ^TAString;
TAString = packed record
wLength: WORD;
wValueLength: WORD;
wType: WORD;
szKey: PWCHAR;
Padding: PWCHAR;
Value: PWCHAR;
end;
PStringTable = ^TStringTable;
TStringTable = packed record
wLength: WORD;
wValueLength: WORD;
wType: WORD;
szKey: PWCHAR;
Padding: PWCHAR;
Children: array of PAString;
end;
PStringFileInfo = ^TStringFileInfo;
TStringFileInfo = packed record
wLength: WORD;
wValueLength: WORD;
wType: WORD;
szKey: PWCHAR;
Padding: PWCHAR;
Children: array of PStringTable;
end;
PAVar = ^TAVar;
TAVar = packed record
wLength: WORD;
wValueLength: WORD;
wType: WORD;
szKey: PWCHAR;
Padding: PWCHAR;
Value: PWCHAR;
end;
PVarFileInfo = ^TVarFileInfo;
TVarFileInfo = packed record
wLength: WORD;
wValueLength: WORD;
wType: WORD;
szKey: PWCHAR;
Padding: PWCHAR;
Children: array of PAVar;
end;
PVSVersionInfo = ^TVSVersionInfo;
TVSVersionInfo = packed record
wLength: WORD;
wValueLength: WORD;
wType: WORD;
szKey: PWCHAR;
Padding1: PWCHAR;
Value: TVSFixedFileInfo;
Padding2: PWCHAR;
StringFileInfo: PStringFileInfo;
VarFileInfo: PVarFileInfo;
end;
function LoadVersionInfo(const FileName: string): PVSVersionInfo;
var
Stream: TMemoryStream;
function ReadWideString: PWideChar;
var
iCount, iSize: Integer;
Buffer: PWideChar;
wcTerminal: WideChar;
begin
Result := nil;
Buffer := Pointer(Integer(Stream.Memory) + Stream.Position);
wcTerminal := #0;
for iCount := 0 to ((Stream.Size - Stream.Position) div 2) - 1 do
if Buffer[iCount] = wcTerminal then
begin
iSize := Succ(iCount) * SizeOf(WideChar);
Result := AllocMem(iSize);
Stream.Read(Result^, iSize);
Exit;
end;
end;
function AlignToDWord: PWideChar;
var
iCount: Integer;
begin
iCount := Stream.Position mod 4;
if iCount = 0 then
Result := nil
else
begin
Result := AllocMem(((iCount + 1) div 2) * SizeOf(WideChar));
Stream.Read(Result^, iCount);
end;
end;
function ReadString: PAString;
begin
New(Result);
Stream.Read(Result.wLength, SizeOf(WORD));
Stream.Read(Result.wValueLength, SizeOf(WORD));
Stream.Read(Result.wType, SizeOf(WORD));
Result.szKey := ReadWideString;
Result.Padding := AlignToDWord;
Result.Value := ReadWideString;
AlignToDWord;
end;
function ReadStringTable: PStringTable;
var
TerminalPos: Integer;
begin
TerminalPos := Stream.Position;
New(Result);
Stream.Read(Result.wLength, SizeOf(WORD));
Stream.Read(Result.wValueLength, SizeOf(WORD));
Stream.Read(Result.wType, SizeOf(WORD));
Result.szKey := ReadWideString;
Result.Padding := AlignToDWord;
Inc(TerminalPos, Result.wLength);
while Stream.Position < TerminalPos - 1 do
begin
SetLength(Result.Children, Length(Result.Children) + 1);
Result.Children[High(Result.Children)] := ReadString;
end;
end;
function ReadStringFileInfo: PStringFileInfo;
var
TerminalPos: Integer;
begin
TerminalPos := Stream.Position;
New(Result);
Stream.Read(Result.wLength, SizeOf(WORD));
Stream.Read(Result.wValueLength, SizeOf(WORD));
Stream.Read(Result.wType, SizeOf(WORD));
Result.szKey := ReadWideString;
Result.Padding := AlignToDWord;
Inc(TerminalPos, Result.wLength);
while Stream.Position < TerminalPos - 1 do
begin
SetLength(Result.Children, Length(Result.Children) + 1);
Result.Children[High(Result.Children)] := ReadStringTable;
end;
end;
function ReadAVar: PAVar;
begin
New(Result);
Stream.Read(Result.wLength, SizeOf(WORD));
Stream.Read(Result.wValueLength, SizeOf(WORD));
Stream.Read(Result.wType, SizeOf(WORD));
Result.szKey := ReadWideString;
Result.Padding := AlignToDWord;
Result.Value := ReadWideString;
AlignToDWord;
end;
function ReadVarFileInfo: PVarFileInfo;
var
TerminalPos: Integer;
begin
TerminalPos := Stream.Position;
New(Result);
Stream.Read(Result.wLength, SizeOf(WORD));
Stream.Read(Result.wValueLength, SizeOf(WORD));
Stream.Read(Result.wType, SizeOf(WORD));
Result.szKey := ReadWideString;
Result.Padding := AlignToDWord;
Inc(TerminalPos, Result.wLength);
while Stream.Position < TerminalPos - 1 do
begin
SetLength(Result.Children, Length(Result.Children) + 1);
Result.Children[High(Result.Children)] := ReadAVar;
end;
end;
begin
New(Result);
Stream := TMemoryStream.Create;
Stream.LoadFromFile(FileName);
Stream.Read(Result.wLength, SizeOf(Result.wLength));
Stream.Read(Result.wValueLength, SizeOf(Result.wValueLength));
Stream.Read(Result.wType, SizeOf(Result.wType));
Result.szKey := ReadWideString;
Result.Padding1 := AlignToDWord;
Stream.Read(Result.Value, SizeOf(Result.Value));
Result.StringFileInfo := ReadStringFileInfo;
Result.VarFileInfo := ReadVarFileInfo;
Stream.Free;
end;