Jump to content
direktor05

x32->x64

Recommended Posts

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

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
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

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

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

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
11 minutes ago, Jirka52 said:

VerInfo: TVerInfo; //class from unit UVerInfoClass.pas

From where is this unit UVerInfoClass?

Share this post


Link to post
{
  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

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×