How to get the version of the executable executable?

How can I get the version of my running application?


I used GetFileVersionInfo(ParamStr(0), ...) :

 filename := PChar(ExtractShortPathName(ParamStr(0))); //Get the number of bytes he have to allocate for the file information structure dwInfoLength := GetFileVersionInfoSize(lptstrFilename, {var}dwHandle); //Get version info GetMem(pInfoData, dwInfoLength); GetFileVersionInfo(lptstrFilename, dwHandle, dwInfoLength, pInfoData); //Set what information we want to extract from pInfoData lpSubBlock := PChar(Chr(92)+Chr(0)); //Extract the desired data from pInfoData into the FileInformation structure VerQueryValue(pInfoData, lpSubBlock, PFileInformation, LengthOfReturned); 

The problem with this method is that the Windows bootloader requires the Windows bootloader to load the image . I create my applications with IMAGE_FILE_NET_RUN_FROM_SWAP image flag ( to avoid exceptions on the page in an inconvenient network ).

This forces the Windows bootloader to download the entire image over the network again, rather than just watching "me . " Since I check and save my own version at startup, the launch for 6 seconds starts at the 10 second launch of the application.

How can I read the version of me, my running application?


I would suggest that Windows does not have an API to read the version of the running process, only from the file that I downloaded (and if the file no longer exists, then it cannot read version information).

But I also suggest that it would be possible to read version resources from my own processes (without being a member of the Administrators or Debuggers group).

Can I read the version of my process?


Related Bonus Question . How can I upload PE Image resources from me, and not through the network?

+4
source share
3 answers

Found this right here on Stackoverflow:

How to determine the version of a Delphi application

I already knew how to determine the version of the application, but @StijnSanders suggested the "best" way, precisely for the reasons why I hit:

I highly recommend not using GetFileVersion if you want to know the version of the executable that is currently running! I have two good reasons for this:

  • The executable file may be unavailable (mapped drive / share) or modified (.exe renamed to .bak and replaced with a new .exe without stopping the running process).
  • The version information that you are trying to read is already loaded into memory and available to you when you load this resource, which is always better than performing additional (relatively slow) disk operations.

Which I adapted in:

 function GetModuleVersion(Instance: THandle; out iMajor, iMinor, iRelease, iBuild: Integer): Boolean; var fileInformation: PVSFIXEDFILEINFO; verlen: Cardinal; rs: TResourceStream; m: TMemoryStream; resource: HRSRC; begin //You said zero, but you mean "us" if Instance = 0 then Instance := HInstance; //UPDATE: Workaround bug in Delphi if resource doesn't exist resource := FindResource(Instance, 1, RT_VERSION); if resource = 0 then begin iMajor := 0; iMinor := 0; iRelease := 0; iBuild := 0; Result := False; Exit; end; m := TMemoryStream.Create; try rs := TResourceStream.CreateFromID(Instance, 1, RT_VERSION); try m.CopyFrom(rs, rs.Size); finally rs.Free; end; m.Position:=0; if not VerQueryValue(m.Memory, '\', (*var*)Pointer(fileInformation), (*var*)verlen) then begin iMajor := 0; iMinor := 0; iRelease := 0; iBuild := 0; Exit; end; iMajor := fileInformation.dwFileVersionMS shr 16; iMinor := fileInformation.dwFileVersionMS and $FFFF; iRelease := fileInformation.dwFileVersionLS shr 16; iBuild := fileInformation.dwFileVersionLS and $FFFF; finally m.Free; end; Result := True; end; 

Warning : the above code sometimes fails due to an error in Delphi:

 rs := TResourceStream.CreateFromID(Instance, 1, RT_VERSION); 

If version information is missing, Delphi tries to throw an exception:

 procedure TResourceStream.Initialize(Instance: THandle; Name, ResType: PChar); procedure Error; begin raise EResNotFound.CreateFmt(SResNotFound, [Name]); end; begin HResInfo := FindResource(Instance, Name, ResType); if HResInfo = 0 then Error; ... end; 

The error, of course, is that PChar not always a pointer to an ANSI character. With unnamed resources, they are integer constants cast to PChar . In this case:

 Name: PChar = PChar(1); 

When Delphi tries to create an exception string and dereferences the 0x00000001 pointer, this also causes an access violation.

The fix is ​​to FindResource(Instance, 1, RT_VERSION) manually call FindResource(Instance, 1, RT_VERSION) :

 var ... resource: HRSRC; begin ... resource := FindResource(Instance, 1, RT_VERSION); if (resource = 0) begin iMajor := 0; iMinor := 0; iRelease := 0; iBuild := 0; Result := False; Exit; end; m := TMemoryStream.Create; ... 

Note Any code is published in the public domain. Attribution is not required.

+8
source

You might want to try the FindResource / LockResource API to access the VERSIONINFO resource of your working module. The MSDN article provides an example in the Examples section, as well as a community comment with C ++ example code that does just that. This starts with the module already loaded, and not from the file name (which is supposed to be loaded separately with a flag indicating only “download resources” and, possibly, ignoring the fact that the image is already displayed in the process).

Please note that - for the provided code snippet - you can find the resource of your module, and then reuse the standard VerQueryValue API to continue analyzing the resources.

+8
source

I suggest you read the JclFileUtils.pas code from JCL. The "TJclFileVersionInfo" class has some overloaded constructors that allow you to work with the file and using the module descriptor to obtain version information.

You can use the JCL class, or at least read it to test how it works in detail.

+2
source

Source: https://habr.com/ru/post/1415631/


All Articles