Sunday, March 25, 2012

Inno Setup, Part 7. Integrating Inno Setup with SVN.

It is convenient when installer gets its version number automatically. There are different systems of software versioning. For our builds we are using the following system:

major version . minor version . revision . build

First three numbers are set manually since they are being changed not very often. Last number build is taken from version control system, in our case it is SVN.
Let’s discuss what we need to do for automatic versioning of Inno Setup installers.
First you need to create installer script for your program as usual, let’s call it OurProgram.iss. In its Setup section there is an additional line:
[Setup]
VersionInfoVersion = 1.0.0.$WCREV$
Also you are creating bat file containing the following line:

SubWCRev.exe . OurProgram.iss OurProgram_version.iss

When you need to make the installer, you are launching this bat file first. It will generate OurProgram_version.iss Inno Setup script. SubWCRev.exe program which is a part of SVN installation will substitute $WCREV$ with current build number. So in OurProgram_version.iss you will find the line like:
[Setup]
VersionInfoVersion = 1.0.0.105
Then you are building installer with the help of OurProgram_version.iss script. And the resulting file will have the version number you need.
The similar method for automatic versioning can be used for C++/C# exe files, we will talk about this in one of the next posts.

Saturday, March 10, 2012

Inno Setup, Part 6. Creating file associations during installation.

During installation you may need to create file association, i.e. make some file extension being connected with your program. In this case Windows will receive information that files with this extension should be always opened with your program. In Windows this is done with the help of registry records. Here is the code:
[Registry]
Root: HKCR; Subkey: ".ext"; ValueType: string; ValueName: ""; ValueData: "OurProgramFile"; Flags: uninsdeletevalue

Root: HKCR; Subkey: "OurProgramFile"; ValueType: string; ValueName: ""; ValueData: "Our Program File"; Flags: uninsdeletekey

Root: HKCR; Subkey: "OurProgramFile\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\OurProgram.exe,0"

Root: HKCR; Subkey: "OurProgramFile\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\OurProgram.exe"" ""%1"""
In the code above we associated files with file extension .ext with OurProgram.exe which was put into {app} folder by installer. Also we set description and default icon for all the files with given file extension.
If our program is uninstalled in future, this registry records will be automatically deleted by Inno Setup.

Sunday, March 4, 2012

Inno Setup, Part 5. Checking .NET Framework versions.

In installers for programs which are using .NET Framework it is necessary to perform a check before installation if .NET Framework is installed on the machine. Such checks are not difficult and, actually they are checks of some keys in registry. These registry keys depend on .NET Framework version.

If .NET Framework is not installed, you need to install it. We prefer opening browser with appropriate URL in order user can download and install .NET Framework. Another way is to include .NET Framework installer into the main installer of the program, it may be convenient but of course this increases size of installer significantly.

Now let’s turn to the code. Here is the check for .NET Framework 3.0:
[CustomMessages]
en.dotnetmissing=Our program needs Microsoft .NET Framework 3.0. Would you like to download and install it now?
[Code]
function InitializeSetup(): Boolean;
var
    ErrorCode: Integer;
    netFrameWorkInstalled : Boolean;
    isInstalled: Cardinal;
begin
    result := true;
    isInstalled := 0;
    netFrameworkInstalled := RegQueryDWordValue(HKLM, 'SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.0\Setup',
  'InstallSuccess', isInstalled);
    if ((netFrameworkInstalled)  and (isInstalled <> 1)) then netFrameworkInstalled := false;   
    if netFrameworkInstalled = false then
    begin
        if (MsgBox(ExpandConstant('{cm:dotnetmissing}'),
            mbConfirmation, MB_YESNO) = idYes) then
        begin
          ShellExec('open',
          'http://www.microsoft.com/downloads/details.aspx?familyid=10CC340B-F857-4A14-83F5-25634C3BF043&displaylang=en',
          '','',SW_SHOWNORMAL,ewNoWait,ErrorCode);
        end;
        result := false;
    end;
end;
Here is the same code for .NET Framework 4 Client Profile.
[CustomMessages]
dotnetmissing=Our program needs Microsoft .NET Framework 4.0 Client Profile. Would you like to download and install it now?
[Code]
function InitializeSetup(): Boolean;
var
    ErrorCode: Integer;
    netFrameWorkInstalled : Boolean;
    isInstalled: Cardinal;
begin
    result := true;

  isInstalled := 0;
    netFrameworkInstalled := RegQueryDWordValue(HKLM, 'SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\client',
  'Install', isInstalled);
    if ((netFrameworkInstalled)  and (isInstalled <> 1)) then netFrameworkInstalled := false;

    if netFrameworkInstalled = false then
    begin
        if (MsgBox(ExpandConstant('{cm:dotnetmissing}'),
            mbConfirmation, MB_YESNO) = idYes) then
        begin
          ShellExec('open',
          'http://download.microsoft.com/download/7/B/6/7B629E05-399A-4A92-B5BC-484C74B5124B/dotNetFx40_Client_setup.exe',
          '','',SW_SHOWNORMAL,ewNoWait,ErrorCode);
        end;
        result := false;
    end;
end; 
So comparing functions for two versions of .NET Framework we notice that they are differing only in messages, download URLs and registry keys. If necessary, you can simply make general function for several versions of .NET Framework.

Update: for example of general function which checks different versions of .NET Framework you can look at this Q & A at stackoverflow.com.