Checking current application version

From ISXKB

Revision as of 06:53, 17 March 2014 by Uecasm (Talk | contribs)
(diff) ←Older revision | Current revision (diff) | Newer revision→ (diff)
Jump to: navigation, search

Assuming that you already know where a prior version of your application is installed (eg. Upgrades), you may want to compare the version you are about to install with the existing version. A common requirement is to warn or prevent accidental downgrades of the software (though note that the user will still be able to downgrade if they uninstall and reinstall an older full install).

Contents

Version of application being installed

By default, new scripts will typically have a definition like the following near the top of the script:

#define MyAppVersion "1.5"

It is fairly common to update this to automatically discover the version of a particular EXE/DLL file (usually the main application file) like so:

#define MyAppVersion GetFileVersion("MyApp.exe")

(You may need to specify the full path to the exe.)

This is sufficient for use in the various [Setup] directives (although you may wish to use GetFileVersionString for the *TextVersion values, if you have non-numeric versions). However for programmatically comparing versions it's not ideal. So we'll define the following as well:

#define VersionMajor
#define VersionMinor
#define VersionRevision
#define VersionBuild
#expr ParseVersion("MyApp.exe", VersionMajor, VersionMinor, VersionRevision, VersionBuild)
#define VersionMS ((VersionMajor << 16) + VersionMinor)
#define VersionLS ((VersionRevision << 16) + VersionBuild)

You'll see how these are used later.

Version of installed application

This can be fetched in a numeric form (VersionMS and VersionLS) using the GetVersionNumbers support function, provided that you already know where it will be located on the user's machine.

Putting it together

type
  VersionState = (vsNotInstalled, vsOlderInstalled, vsSameInstalled, vsNewerInstalled);

function GetVersionState(): VersionState;
var
  ExePath: String;
  VersionMS, VersionLS: Cardinal;
begin
  ExePath := ExpandConstant('{app}\MyApp.exe');
  if GetVersionNumbers(ExePath, VersionMS, VersionLS) then begin
    if (VersionMS < {#VersionMS}) or ((VersionMS = {#VersionMS}) and (VersionLS < {#VersionLS})) then begin
      Result := vsOlderInstalled;
    end else if (VersionMS > {#VersionMS}) or ((VersionMS = {#VersionMS}) and (VersionLS > {#VersionLS})) then begin
      Result := vsNewerInstalled;
    end else begin
      Result := vsSameInstalled;
    end;
  end else begin
    Result := vsNotInstalled;
  end;
end;

This function will check the version of the file on disk against the version compiled into the setup (as above) and will tell you whether the one that is already installed is older or newer than the one that you are trying to install.

Example Usage

One example of discouraging accidental downgrades:

function OnNextButtonClick(CurPageId: Integer): Boolean;
begin
  Result := True;
  if CurPageId = wpSelectDir then begin
    if GetVersionState() = vsNewerInstalled then begin
      Result := SuppressibleMsgBox('A newer version of the application is already installed.  Are you sure you want to '
         + 'downgrade to {#MyAppVersion}?', mbConfirmation, MB_YESNO, IDYES) = IDYES;
    end;
  end;
end;

Note that this will allow them to continue anyway, and will do so if /SUPPRESSMSGBOXES is in effect (eg. as part of a silent install), as it assumes that the user knows what they're doing in that case.

If you wish to prevent downgrades by default (including silent installs), then you can use this fragment instead:

mbConfirmation, MB_YESNO or MB_DEFBUTTON2, IDNO) = IDYES;

Completely disallowing downgrades is left as an exercise for the reader.

Why not compare string versions?

While this might work when you're comparing version "1.0" vs. version "1.2" etc, you'll get surprising results whenever the number of digits changes -- for example when comparing "10.3" vs. "9.2" or "2.9" vs. "2.11". And you'll get into even more trouble if you include additional information in the text version, such as release codenames or special build identifiers. Stick with comparing versions numerically instead.

Why not prevent installing the same version?

It's not unusual for a user to re-run the same version of the installer as they presently have in order to perform a "repair", if they suspect that something has corrupted the application's files. If you prevented same-version installs then it would force them to do an uninstall/reinstall cycle instead, which may be more annoying (particularly if reboots are required).

It's also possible that the versions are not actually the same -- perhaps they currently have version "5.6" installed and they're now trying to install "5.6 hotfix customerA". As we're only doing a numeric comparison (and things like customer-specific builds can't map into a numeric version) that detail will get lost, and they will be seen as vsSameVersion. This is usually not a problem unless you try to stop same-version installs (so don't do that).

See Also

Personal tools
Ads: