Recent

Author Topic: Exception in TFileVersionInfo.ReadFileInfo  (Read 3843 times)

Thaddy

  • Hero Member
  • *****
  • Posts: 7178
Re: Exception in TFileVersionInfo.ReadFileInfo
« Reply #15 on: November 12, 2018, 04:36:01 pm »
Indeed, a filesize of 0 is a legal filesize and will not immediately set an Os Error. This is actually a bit undefined I guess.
inline variables like in D10.3 are a bit like Brexit: if you are given the wrong information it sounds like a good idea. Every kid loves candy, but it makes you fat and your teeth will disappear.

lucamar

  • Sr. Member
  • ****
  • Posts: 463
Re: Exception in TFileVersionInfo.ReadFileInfo
« Reply #16 on: November 12, 2018, 04:57:57 pm »
According to Microsoft's doc:

Quote
If the function fails, the return value is zero. To get extended error information, call GetLastError.

The most probable cause for the function to fail is that the executable has no version info but there are others: You should check the error info and act in consequence.
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 1.8.4/FPC 3.0.4 on:
(K)Ubuntu 11..16, Windows XP SP3 (Home/Prof.) and various DOS incarnations.

Thaddy

  • Hero Member
  • *****
  • Posts: 7178
Re: Exception in TFileVersionInfo.ReadFileInfo
« Reply #17 on: November 12, 2018, 05:05:21 pm »
The most probable cause for the function to fail is that the executable has no version info but there are others: You should check the error info and act in consequence.
Which it doesn't properly. Right? It should only raise if there is actually an error.
inline variables like in D10.3 are a bit like Brexit: if you are given the wrong information it sounds like a good idea. Every kid loves candy, but it makes you fat and your teeth will disappear.

OLLI_S

  • Jr. Member
  • **
  • Posts: 69
Re: Exception in TFileVersionInfo.ReadFileInfo
« Reply #18 on: November 17, 2018, 05:30:45 pm »
Hello,

According to Microsoft's doc:

Quote
If the function fails, the return value is zero. To get extended error information, call GetLastError.

The most probable cause for the function to fail is that the executable has no version info but there are others: You should check the error info and act in consequence.

I am not a good programmer, what must be changed in ReadVersionInfo?

Best regards

OLLI

ASerge

  • Hero Member
  • *****
  • Posts: 997
Re: Exception in TFileVersionInfo.ReadFileInfo
« Reply #19 on: November 17, 2018, 05:57:06 pm »
I am not a good programmer, what must be changed in ReadVersionInfo?
Nothing.
There may be several reasons why version information is not available. Simply does not exist, or no access, etc. So that generation of errors and transfer to a higher code - the right thing. If you do not want to show this to the user - catch, output to the log, and show the user that there is no data.

OLLI_S

  • Jr. Member
  • **
  • Posts: 69
Re: Exception in TFileVersionInfo.ReadFileInfo
« Reply #20 on: November 17, 2018, 06:30:48 pm »
Hello Aserge,

I added a try ... except block:

Code: Pascal  [Select]
  1.     try
  2.       // Create the Version Information
  3.       VerInfo := TVersionInfo.Create(AppFileName);
  4.     except
  5.       // will only be executed in case of an exception
  6.       on E: Exception do begin
  7.         ShowMessage( 'Error: '+ E.ClassName + #13#10 + E.Message );
  8.         VerInfo.Free;
  9.         exit;
  10.       end;
  11.     end;  

When I select an application that causes problems I see the error message (as expected).
But I also get an Access-Violation message.

So maybe I have to add the try block in TVersionInfo.ReadVersionInfo ?
Or should I modify TVersionInfo.ReadVersionInfo so when the size is zero, that I don't call RaiseLastOSError but show a message and exit?

OLLI
« Last Edit: November 17, 2018, 06:43:07 pm by OLLI_S »

lucamar

  • Sr. Member
  • ****
  • Posts: 463
Re: Exception in TFileVersionInfo.ReadFileInfo
« Reply #21 on: November 17, 2018, 07:29:35 pm »
When I select an application that causes problems I see the error message (as expected).
But I also get an Access-Violation message.

So maybe I have to add the try block in TVersionInfo.ReadVersionInfo ?
Or should I modify TVersionInfo.ReadVersionInfo so when the size is zero, that I don't call RaiseLastOSError but show a message and exit?

The access violation probably comes from the fact that since, indirectly, ReadVersionInfo is called from the constructor, an exception will prevent the constructor from finalizing, so your call to VerInfo.Free catchs the object at an ... "incovenient" moment :)

To avoid it, you have some options but the best, IMHO, is to modify how TVersionInfo works. The needed changes are rather few and small:

  • Change TVersionInfo.Create() to also set FBuffer to Nil.
  • Delete the call to ReadVersionInfo from TVersionInfo.SetFileName.
  • At the beginning of methods that use FBuffer (GetFixedFileInfo and GetVerValue) add this guard:
    if FBuffer = Nil then ReadVersionInfo;

The basic effect of the changes is to defer doing anything until it is actually needed, instead of proactively doing it as soon as possible; which incidentally prevents raising exceptions until we are actually ready to catch them. Just a question of tastes ;D

ETA Incidentally, if I were you I wouldn't call that class TVersionInfo but TAltVersionInfo or something like that, since there is already a class TVersionInfo in the Fileinfo unit.
« Last Edit: November 17, 2018, 07:33:33 pm by lucamar »
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 1.8.4/FPC 3.0.4 on:
(K)Ubuntu 11..16, Windows XP SP3 (Home/Prof.) and various DOS incarnations.

ASerge

  • Hero Member
  • *****
  • Posts: 997
Re: Exception in TFileVersionInfo.ReadFileInfo
« Reply #22 on: November 17, 2018, 08:39:16 pm »
I added a try ... except block:
Code: Pascal  [Select]
  1.     try
  2.       // Create the Version Information
  3.       VerInfo := TVersionInfo.Create(AppFileName);
  4.     except
  5.       // will only be executed in case of an exception
  6.       on E: Exception do begin
  7.         ShowMessage( 'Error: '+ E.ClassName + #13#10 + E.Message );
  8.         VerInfo.Free;
  9.         exit;
  10.       end;
  11.     end;  

When I select an application that causes problems I see the error message (as expected).
But I also get an Access-Violation message.
Bad code: release object not in finally, but in the except block. When an exception occurs, the constructor calls the destructor and then you use Free again.
Use right construction:
Code: Pascal  [Select]
  1. try
  2.   VerInfo := TVersionInfo.Create(AppFileName);
  3.   try
  4.     // Do something with version
  5.   finally
  6.     VerInfo.Free;
  7.   end;
  8. except
  9.   on E: Exception do
  10.     ShowMessage( 'Error: '+ E.Message);
  11. end;