direktor05 2 Posted October 16 I'm getting a ton of issues converting from x32 to x64. First one: var Size: Cardinal; Handle: Cardinal; FileName: String; begin if ModuleName = '' then FileName := OAExeName else FileName := ModuleName; Size := GetFileVersionInfoSize(PWideChar(FileName), Handle); Size returned is 0 and the error is: VerQueryValue (Language in Project Settings/Version Info has to be set to English (United Kingdom)) var SubBlock: String; ValuePointer: Pointer; ValueLen: Cardinal; begin SubBlock := '\StringFileInfo\080904E4\' + ValueName; TestGetLastError(VerQueryValue(@FBuffer[0], PWideChar(SubBlock), ValuePointer, ValueLen), 'VerQueryValue (Language in Project Settings/Version Info has to be set to English (United Kingdom))'); Result := PChar(ValuePointer); So what is wrong? I assume it's the variable (un)signed-ness again. GetFileVersionInfoSize(PWideChar(FileName), Handle) - Handle must be Cardinal according to API definition. How can I fix this? Another one is array of Byte variable is causing AV error. Share this post Link to post
FPiette 385 Posted October 16 Try using THandle data type for all handles. Share this post Link to post
direktor05 2 Posted October 16 The error I get is 1813 - resource not found Share this post Link to post
Uwe Raabe 2063 Posted October 16 Make sure you have version info enabled for the x64 platform. There may be different settings for each platform. Share this post Link to post
Virgo 18 Posted October 16 3 minutes ago, FPiette said: Try using THandle data type for all handles. Except Windows documentation defines this lpdwHandle as LPDWORD, So THandle would be wrong. Share this post Link to post
Cristian Peța 107 Posted October 16 Is this working? I have something like this in my code and is working for both x32 and x64. var Size: DWORD; Handle: DWORD; FileName: String; begin if ModuleName = '' then FileName := OAExeName else FileName := ModuleName; UniqueString(FileName); Size := GetFileVersionInfoSize(PChar(FileName), Handle); Share this post Link to post
Cristian Peța 107 Posted October 16 Actually this is what I have and is working x32 and x64. procedure GetFileVersion(const AFileName: string; var V1, V2, V3, V4: Integer); var FileName: string; InfoSize, Wnd: DWORD; VerBuf: Pointer; FI: PVSFixedFileInfo; VerSize: DWORD; begin V1 := 0; V2 := 0; V3 := 0; V4 := 0; // GetFileVersionInfo modifies the filename parameter data while parsing. // Copy the string const into a local variable to create a writeable copy. FileName := AFileName; UniqueString(FileName); InfoSize := GetFileVersionInfoSize(PChar(FileName), Wnd); if InfoSize <> 0 then begin GetMem(VerBuf, InfoSize); try if GetFileVersionInfo(PChar(FileName), Wnd, InfoSize, VerBuf) then if VerQueryValue(VerBuf, PathDelim, Pointer(FI), VerSize) then begin V1 := FI.dwFileVersionMS shr 16; V2 := FI.dwFileVersionMS and $FFFF; V3 := FI.dwFileVersionLS shr 16; V4 := FI.dwFileVersionLS and $FFFF; end; finally FreeMem(VerBuf); end; end; end; Share this post Link to post
Davide Angeli 44 Posted October 16 To get that kind of info from a file I use the JCL class TJvVersionInfo (https://github.com/project-jedi/jvcl/blob/master/jvcl/run/JvVersionInfo.pas) that is a wrapper of that kind API. For me it works both 32 and 64 bit. Share this post Link to post
Jirka52 2 Posted October 17 Try this function GetVersionInformation(): {$WARNINGS OFF} function LinkerTimeStamp(const AFileName: string): TDateTime; var LI: TLoadedImage; m: TMarshaller; timeStamp: Int64; utcTime: TDateTime; begin Win32Check(MapAndLoad(PAnsiChar(m.AsAnsi(ParamStr(0)).ToPointer), nil, @LI, False, True)); timeStamp := LI.FileHeader.FileHeader.TimeDateStamp; UnMapAndLoad(@LI); utcTime := System.DateUtils.UnixToDateTime(timeStamp); Result := TTimeZone.local.ToLocalTime(utcTime); end; {$WARNINGS ON} function GetVersionInformation(): string; const lastCompileStr: string = 'Last Compile'; cnPackLastCompileStr: string = 'LastCompiledTime'; bitStr: string = '; %d bit'; verInfoStr: string = '%d.%d.%d.%d'; var VerInfo: TVerInfo; //class from unit UVerInfoClass.pas myFileName: string; myResultStr: string; verBitStr: string; FFI: WinApi.Windows.TVSFixedFileInfo; myCompiledTime: TDateTime; Fmt: TFormatSettings; begin Result := ''; myFileName := Application.ExeName; VerInfo := TVerInfo.Create(myFileName); try if VerInfo.HasVerInfo then begin myResultStr := ' ver.'; {get version info} FFI := VerInfo.FixedFileInfo; myResultStr := myResultStr + Format(verInfoStr, [HiWord(FFI.dwFileVersionMS), LoWord(FFI.dwFileVersionMS), HiWord(FFI.dwFileVersionLS), LoWord(FFI.dwFileVersionLS)]); //add bit version {$IFDEF WIN32} verBitStr := Format(bitStr, [32]); {$ENDIF} {$IFDEF WIN64} verBitStr := Format(bitStr, [64]); {$ENDIF} myResultStr := myResultStr + verBitStr; //get date of last compilation if (VerInfo.TranslationCount > 0) then begin myCompiledTime := LinkerTimeStamp(myFileName); if (myCompiledTime <= Now) then begin Fmt.ShortDateFormat := 'dd.mm.yyyy'; Fmt.DateSeparator := '.'; Fmt.LongTimeFormat := 'hh:nn'; Fmt.TimeSeparator := ':'; myResultStr := myResultStr + compiledStr + DateTimeToStr(myCompiledTime, Fmt); end; Result := myResultStr; end; end; finally VerInfo.Free; end; {try} end; Share this post Link to post
Cristian Peța 107 Posted October 17 11 minutes ago, Jirka52 said: VerInfo: TVerInfo; //class from unit UVerInfoClass.pas From where is this unit UVerInfoClass? Share this post Link to post
Jirka52 2 Posted October 18 { Demo program for article # 20 "How to extract version information using the Windows API" from http://www.delphidabbler.com/articles.php?id=20. Unit implements class that encapsulates version from an executable file. Copyright (c) 2005, P.D.Johnson (DelphiDabbler) } unit UVerInfoClass; interface uses Windows; const // List of all standard string name cStrNames: array[0..13] of string = ( 'Comments','CompanyName','FileDescription','FileVersion','InternalName', 'LegalCopyright','LegalTrademarks','OriginalFilename','PrivateBuild', 'ProductName','ProductVersion','SpecialBuild', 'Last Compile', 'LastCompiledTime' ); type TTransRec = packed record Lang, // language code CharSet: Word; // character set (code page) end; { PTransRec: Pointer to translation record. } PTransRec = ^TTransRec; { TTransRecArray: Dynamic array of translation records: the translation table. } TTransRecArray = array of TTransRec; { TVerInfo: Class that encapsulates version information stored in an executable file. } TVerInfo = class(TObject) private fFixedFileInfo: TVSFixedFileInfo; // fixed file info record fTransTable: TTransRecArray; // translation table fHasVerInfo: Boolean; // whether file contains ver info fVerInfo: Pointer; // buffer storing ver info function GetString(const Trans, Name: string): string; function GetTranslation(Idx: Integer): string; function GetTranslationCount: Integer; protected function GetVerInfoSize(const FileName: string): Integer; procedure GetVerInfo(const FileName: string; const Size: Integer; const Buffer: Pointer); function GetFFI(const Buffer: Pointer): TVSFixedFileInfo; function GetTransTable(const Buffer: Pointer): TTransRecArray; function GetVerInfoStr(const Buffer: Pointer; const Trans, StrName: string): string; public constructor Create(const FileName: string); destructor Destroy; override; property HasVerInfo: Boolean read fHasVerInfo; property FixedFileInfo: TVSFixedFileInfo read fFixedFileInfo; property Translations[Idx: Integer]: string read GetTranslation; property TranslationCount: Integer read GetTranslationCount; property Strings[const Trans, Name: string]: string read GetString; end; implementation uses SysUtils; { TVerInfo } constructor TVerInfo.Create(const FileName: string); var BufSize: Integer; // size of ver info buffer begin inherited Create; // Get size of buffer: no ver info if size = 0 BufSize := GetVerInfoSize(FileName); fHasVerInfo := BufSize > 0; if fHasVerInfo then begin // Read ver info into buffer GetMem(fVerInfo, BufSize); GetVerInfo(FileName, BufSize, fVerInfo); // Read fixed file info and translation table fFixedFileInfo := GetFFI(fVerInfo); fTransTable := GetTransTable(fVerInfo); end; end; destructor TVerInfo.Destroy; begin // Free ver info buffer FreeMem(fVerInfo); inherited; end; function TVerInfo.GetString(const Trans, Name: string): string; begin Assert(fHasVerInfo); Result := GetVerInfoStr(fVerInfo, Trans, Name); end; function TVerInfo.GetTranslation(Idx: Integer): string; begin Assert(fHasVerInfo); Assert((Idx >= 0) and (Idx < TranslationCount)); // Return string representation of translation at given index Result := Format( '%4.4x%4.4x', [fTransTable[Idx].Lang, fTransTable[Idx].CharSet] ); end; function TVerInfo.GetTranslationCount: Integer; begin Result := Length(fTransTable); end; function TVerInfo.GetVerInfoSize(const FileName: string): Integer; var Dummy: DWORD; // Dummy handle parameter begin Result := GetFileVersionInfoSize(PChar(FileName), Dummy); end; procedure TVerInfo.GetVerInfo(const FileName: string; const Size: Integer; const Buffer: Pointer); begin if not GetFileVersionInfo(PChar(FileName), 0, Size, Buffer) then begin raise Exception.Create('Can''t load version information'); end; end; function TVerInfo.GetFFI(const Buffer: Pointer): TVSFixedFileInfo; var Size: DWORD; // Size of fixed file info read Ptr: Pointer; // Pointer to FFI data begin // Read the fixed file info if not VerQueryValue(Buffer, '\', Ptr, Size) then begin raise Exception.Create('Can''t read fixed file information'); end; // Check that data read is correct size if Size <> SizeOf(TVSFixedFileInfo) then begin raise Exception.Create('Fixed file information record wrong size'); end; Result := PVSFixedFileInfo(Ptr)^; end; function TVerInfo.GetTransTable(const Buffer: Pointer): TTransRecArray; var TransRec: PTransRec; // pointer to a translation record Size: DWORD; // size of data read RecCount: Integer; // number of translation records Idx: Integer; // loops thru translation records begin // Read translation data VerQueryValue(Buffer, '\VarFileInfo\Translation', Pointer(TransRec), Size); // Get record count and set length of array RecCount := Size div SizeOf(TTransRec); SetLength(Result, RecCount); // Loop thru table storing records in array for Idx := 0 to Pred(RecCount) do begin Result[Idx] := TransRec^; Inc(TransRec); end; end; function TVerInfo.GetVerInfoStr(const Buffer: Pointer; const Trans, StrName: string): string; var Value: PChar; // the string value data Dummy: DWORD; // size of value data (unused) Path: string; // "path" to string value begin // Build path from translation and string name Path := '\StringFileInfo\' + Trans + '\' + StrName; // Read the string: return '' if string doesn't exist if VerQueryValue(Buffer, PChar(Path), Pointer(Value), Dummy) then Result := Value else Result := ''; end; end. Share this post Link to post