Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I get the version number of the current project using ToolsAPI in Delphi 10.2

In Delphi 2007 I can easily get the version information of the current project using the following ToolsAPI calls:

procedure Test;
var
  ProjectOptions: IOTAProjectOptions;
  Project: IOTAProject;
  Major: Variant;
  Minor: Variant;
  Release: Variant;
  Build: Variant;
begin
  // GxOtaGetCurrentProject is a function in GExpert's GX_OTAUtils unit that returns the current IOTAProject
  Project := GxOtaGetCurrentProject;
  if Assigned(Project) then begin
    ProjectOptions := Project.ProjectOptions;
    if Assigned(ProjectOptions) then begin
      Major := ProjectOptions.Values['MajorVersion'];
      Minor := ProjectOptions.Values['MinorVersion'];
      Release := ProjectOptions.Values['Release'];
      Build := ProjectOptions.Values['Build'];
    end;
  end;
end;

In Delphi 10.2.3 this will always return the version 1.0.0.0 regardless of the actual version number. This is the "simple" case: A VCL application.

I also tried the "Keys" value which returns a TStrings pointer. There I also get the FileVersion string, but it is always "1.0.0.0".

I guess this has something to do with the support for various platforms and configurations, but I could not find any documentation, on how it should work now. I also searched the ToolsAPI.pas for "version" and "release", but nothing suspicious showed up.

Any hints on how I can get the version information in Delphi 10.2?

like image 860
dummzeuch Avatar asked Jul 04 '18 19:07

dummzeuch


2 Answers

The effective values for version info are stored in separate configurations for build configuration and platform. To get access to the configurations, first get an interface to IOTAProjectOptionsConfigurations:

cfgOpt := project.ProjectOptions as IOTAProjectOptionsConfigurations;

Then iterate over each IOTABuildConfiguration:

  for I := 0 to cfgOpt.ConfigurationCount - 1 do
  begin
    cfg := cfgOpt.Configurations[I];
    DoWhatEverWith(cfg);
  end;

Be aware that each IOTABuildConfiguration can have several platforms and children:

  for S in cfg.Platforms do
  begin
    DoWhatEverWith(cfg.PlatformConfiguration[S]);
  end;

  for I := 0 to cfg.ChildCount - 1 do
  begin
    DoWhatEverWith(cfg.Children[I]);
  end;

Depending on which platform and build configuration is currently selected, different values for version info may be used. The current platform and configuration can be retrieved from the IOTAProject properties CurrentPlatform and CurrentConfiguration.

like image 51
Uwe Raabe Avatar answered Oct 18 '22 00:10

Uwe Raabe


To answer my own question after reading Uwe Raabe's very helpful answer:

The simplest code for getting the version information of the currently active configuration and platform is this:

procedure Test;
var
  ProjectOptions: IOTAProjectOptionsConfigurations;
  Project: IOTAProject;
  Major: Variant;
  Minor: Variant;
  Release: Variant;
  Build: Variant;
  cfg: IOTABuildConfiguration;
begin
  // GxOtaGetCurrentProject is a function in GExpert's GX_OTAUtils unit that returns the current IOTAProject
  Project := GxOtaGetCurrentProject;
  if Assigned(Project) then begin
    // as per Uwe's answer
    ProjectOptions := Project.ProjectOptions as IOTAProjectOptionsConfigurations;
    if Assigned(ProjectOptions) then begin
      // this is the currently active configuration
      cfg := ProjectOptions.ActiveConfiguration;
      if Assigned(cfg) then begin
        // Note that the names of the version properties are different!
        Major := cfg.GetValue('VerInfo_MajorVer', True);
        Minor := cfg.GetValue('VerInfo_MinorVer', True);
        Release := cfg.GetValue('VerInfo_Release', True);
        Build := cfg.GetValue('VerInfo_Build', True);
      end;
    end;
  end;
end;

So it is quite easy as long as you only want the values from the current configuration (which in my case is exactly what I need).

  1. Get the current project
  2. Get the IOTAProjectOptionsConfigurations interface
  3. Get the currently active configuration
  4. Read the values using GetValue. Note the new names for the version info properties. Also note, that you must pass True for the IncludeInheritedValues parameter.

Some notes:

  • You can enumerate the available properties with GetPropertyCount() and GetPropertyName().
  • Instead of calling GetValue('name', True) as above, you can also use the property Value['name']. It automatically retrieves the resulting value recursing to ancestor configurations as necessary.
  • There is also the option to get type casted values via the AsInteger property. Again this also takes ancestor configurations into account. Note that this might raise exceptions if the type conversion fails.
  • If the "Include Version Info" option is not checked for the current configuration or any of the ancestors, the GetValue calls return version 1.0.0.0 for whatever reason. There seems to be no way to check for that option, but I may be wrong here.
  • Embarcadero could have easily provided backwards compatibility by rerouting the ProjectOptions.Values['MajorVersion'] and related calls to the values of the current configuration. They didn't, OK, their choice, but in that case I would have expected some documentation.
  • The change goes back to Delphi XE.
like image 3
dummzeuch Avatar answered Oct 17 '22 22:10

dummzeuch