VB.NET For Everyone! : INNO, Installer, VB.NET, Setuphttp://zerosandtheone.com/blogs/vb/archive/tags/INNO/Installer/VB.NET/Setup/default.aspxTags: INNO, Installer, VB.NET, SetupenCommunityServer 2008 (Build: 30417.1769).NET : Install your app and the .NET framework using INNO Setuphttp://zerosandtheone.com/blogs/vb/archive/2008/06/23/vb-net-install-your-app-and-the-net-framework-using-inno-setup.aspxMon, 23 Jun 2008 19:53:00 GMT25aead6d-839f-4a6e-811a-c90be434890b:167Matthew Kleinwaks12http://zerosandtheone.com/blogs/vb/rsscomments.aspx?PostID=167http://zerosandtheone.com/blogs/vb/archive/2008/06/23/vb-net-install-your-app-and-the-net-framework-using-inno-setup.aspx#comments<p>Today we are going to look at an alternative to using ClickOnce or
Windows Installer MSI to install an application written in .NET.</p>
<p>This article is written for installing an application written in Microsoft .NET 2.0 (does not have to be VB specifically) and including the .NET Framework as part of your installation.&nbsp; The concepts here can be applied to do the same for a .NET 1.1 or .NET 3.x installation, however some specific values will change, and some logic will change (like the fact that .NET 3.x will not run on any Windows below XP SP2, and .NET 2.0 does).</p>
<p><b>Some History<br /></b>One of the biggest problems with using an MSI
based installer, or ClickOnce to deploy your .NET application, is the
need to have multiple installation files. At the least, you generally
need 2, a setup.exe bootstrapper to kick things off, and the MSI file
which contains the actual files to install. This can be fine when
dealing with a CD based installation, but how about internet downloads?
Some make use of self extracting zip type files to extract the setup
files and launch the bootstrapper, others simply zip the files up and
expect you to unzip them and run the setup.exe. There are also 3rd
party apps like InstallShield and Wise, however I was looking for a
&quot;free&quot; approach to his.</p>
<p>Depending on your target audience, you may want to have a nice, easy
to use, single setup.exe that people can download and run without any
extra hoops to jump through. </p>
<p>INNO Setup is a free open source installer program written and
maintained by Jordan Russell. It has the ability to package everything
into a single setup.exe for easy deployment.</p>
<p>Here are some links of importance:</p>
<ul>
<li><a target="_blank" title="Jordan Russell Homepage" href="http://www.jrsoftware.org/">JR Software Homepage</a></li>
<li><a target="_blank" title="INNO Setup 5.1.9" href="http://files.jrsoftware.org/ispack/ispack-5.1.9.exe">INNO Version used in this article</a></li>
<li><a target="_blank" title="Newest Inno Setup Download" href="http://www.jrsoftware.org/isdl.php#qsp">Newest INNO Version Page</a></li>
<li><a target="_blank" title=".NET 2.0 Redist Download" href="http://www.microsoft.com/downloads/details.aspx?FamilyID=0856EACB-4362-4B0D-8EDD-AAB15C5E04F5&amp;displaylang=en">.NET 2.0 Redist File Download</a></li>
<li><a target="_blank" title=".NET 2.0 (SP1) Redist Download" href="http://www.microsoft.com/downloads/details.aspx?familyid=79BC3B77-E02C-4AD3-AACF-A7633F706BA5&amp;displaylang=en">.NET 2.0 (sp1) Redist File Download</a> (<i>Note: This is a full version of .NET Framework, you don&#39;t need the above link if you use this one.</i>)</li>
</ul>
<p>Make sure you always download and install the QuickStart pack
installation of Inno versus just the standard one, as it includes a
preprocessor <br />(similar to conditional compiler statements in VB with the # sign). More on this later.</p>
<p>One thing to keep in mind as you start to use INNO Setup, is that it
is NOT a .NET installer. It is a generic installer for installing
anything from a full blown app, to possibly just a directory of
pictures. It is very flexible, albeit with a slight learning curve if
you are used to VB programming. I use VB for 95% of my programming, and
I found INNO&#39;s Pascal Scripting to be pretty easy to pickup, and not
required in all cases of use.</p>
<p>Inno setup files have .iss (Inno Setup Script) extensions, and they
are nothing more than plain text files. You can write them in notepad
if you wish, however using the INNO program gives you syntax
highlighting (plus it is free, and we need it to compile the script
when we are done).</p>
<p>This article does not require you have existing knowledge of INNO Setup, however if you do, you will likely understand much of this article a bit better than those who do not. For those of you who are new to INNO Setup, this is not going to teach you everything you will want to know about it, so I suggest you visit the INNO website and look over some of the docs, tutorials, and newsgroups there. That being said, you can take this script and mostly change around values of the fields to fit your own application and have a working installer.</p>
<p>This article is also not a tutorial on how to use INNO Setup. It is an article on how to use INNO Setup to install the .NET Framework. Yes there is a difference, and that difference is I am not going to go into great detail about what each property and method of the setup does. That would take a book, not a blog posting. <img src="http://zerosandtheone.com/emoticons/emotion-5.gif" alt="Wink" /></p>
<p>&nbsp;</p>
<p><b>Time to get down to business</b></p>
<p>Ok, so now that we have gotten those facts out of the way, and you
have downloaded and installed either the specific version I used for
this example (5.1.9), or the newest version.<br /><i>(Important note as of this article, the newest version of INNO 5.2.3 works fine with this script)</i></p>
<p>So we are going to go through the entire setup file, section by section, and talk about what is going on.</p>
<ol></ol>
<p>So open up INNO setup, and select &quot;Create a new empty script file&quot;,
or just click cancel on the welcome dialog. You will be at the script
editor window, which looks similar to a standard text editor like
notepad.</p>
<p>Lets add some comments to the top of the script:</p>
<p>
<span style="font-family:&#39;Courier New&#39;;color:#339966;">;Example
.NET Setup Script<br />;written
in Inno Setup 5.1.9 (ISPP 5.1.8.0)<br />;2008
Matthew Kleinwaks<br /></span><span style="font-family:&#39;Courier New&#39;;color:#339966;">;www.ZerosAndTheOne.com<br />;change these comments as needed for your own app<br /></span></p>
<p class="MsoNormal">Now we will define some preprocessor variables</p>
<p class="MsoNormal"><span style="font-family:&#39;Courier New&#39;;color:red;">#define
SourceFileDir &quot;c:\work\myapp&quot;<br />#define
IncludeFramework true<br />#define IsExternal &quot;&quot;</span></p>
<p class="MsoNormal"><span style="font-family:&#39;Courier New&#39;;color:red;"></span>Basically, these preprocessor variables are generated BEFORE the script is compiled. This is useful to do things like set options. Perhaps you want to have a demo version as well as the full version of your product. You could use a preprocessor directive to indicate if its the demo or not, which can allow for boolean logic (if statements) to include one file or another based on if its a demo or not. That is just one example, but you get the idea.</p>
<ul>
<li><b>SourceFileDir </b>is a directory on my machine where the release version
files of my actual application are. This would be the exe, dll files,
any support files that are part of the application itself, like
pictures, data files, eula, readme, etc.<br /></li>
<li><b>IncludeFramework </b>is simply a boolean to indicate if you want the framework packaged and installed. Sometimes it can be convenient to NOT include it.<br /></li>
<li><b>IsExternal</b> is also a directive that we will use to determine if in fact we want to package the app files with the setup.exe, or keep them separate. Obviously for a download we want them all to be part of one setup.exe file, however sometimes for distribution on CD, it is better to package the files loosely instead of all packed into one file. If you do want the files external, you should replace the &quot;&quot; in this line with &quot;external&quot; (including the quotes). More on why it works like that further down in the <b>[files]</b> section.<br /></li>
</ul>
<p><i></i></p>
<p>So now lets write out the sections of the setup file. After that, we will create the code section to do all of our custom .NET installer coding.</p>
<p>The first section is <b>[Setup]</b>. It defines many of the properties that make up the installer&#39;s look, feel, and many textual attributes.</p>
<p>
<b><span style="font-family:&#39;Courier New&#39;;">[setup]<br /></span></b><span style="font-family:&#39;Courier New&#39;;color:#339966;">;name
of your application</span><span style="font-family:&#39;Courier New&#39;;color:blue;"> <br />
AppName</span><span style="font-family:&#39;Courier New&#39;;">=MyApp<br /></span><span style="font-family:&#39;Courier New&#39;;color:#339966;">;repeat
name of application. (otherwise you get <br />
;multiple entries in add/remove programs)</span><span style="font-family:&#39;Courier New&#39;;color:blue;"><br />AppVerName</span><span style="font-family:&#39;Courier New&#39;;">=MyApp<br />
<span style="color:#339966;">;app publisher name</span></span><span style="font-family:&#39;Courier New&#39;;color:blue;"><br />AppPublisher</span><span style="font-family:&#39;Courier New&#39;;">=zerosandtheone.com<br />
<span style="color:#339966;">;app publisher website URL</span></span><span style="font-family:&#39;Courier New&#39;;color:blue;"><br />AppPublisherURL</span><span style="font-family:&#39;Courier New&#39;;">=http://www.zerosandtheone.com<br />
<span style="color:#339966;">;app publisher support URL</span></span><span style="font-family:&#39;Courier New&#39;;color:blue;"><br />AppSupportURL</span><span style="font-family:&#39;Courier New&#39;;">=http://www.zerosandtheone.com/support</span><span style="font-family:&#39;Courier New&#39;;color:#339966;"><br />;app
publisher updates URL</span><span style="font-family:&#39;Courier New&#39;;"></span><span style="font-family:&#39;Courier New&#39;;color:blue;"><br />AppUpdatesURL</span><span style="font-family:&#39;Courier New&#39;;">=http://www.zerosandtheone.com</span><span style="font-family:&#39;Courier New&#39;;color:#339966;"><br />;default
directory {pf} is a constant for<br />;program
files. See INNO help for all constants</span><span style="font-family:&#39;Courier New&#39;;"></span><span style="font-family:&#39;Courier New&#39;;color:blue;"><br />DefaultDirName</span><span style="font-family:&#39;Courier New&#39;;">={pf}\zerosandtheone\MyApp</span><span style="font-family:&#39;Courier New&#39;;color:#339966;"><br />;default
group name in the programs <br />; section
of the start menu</span><span style="font-family:&#39;Courier New&#39;;"></span><span style="font-family:&#39;Courier New&#39;;color:blue;"><br />DefaultGroupName</span><span style="font-family:&#39;Courier New&#39;;">=MyApp</span><span style="font-family:&#39;Courier New&#39;;color:#339966;"><br />;Boolean
to disable allowing user to customize <br />;start
menu entry during installation</span><span style="font-family:&#39;Courier New&#39;;color:red;"></span><span style="font-family:&#39;Courier New&#39;;color:blue;"><br />DisableProgramGroupPage</span><span style="font-family:&#39;Courier New&#39;;">=yes</span><span style="font-family:&#39;Courier New&#39;;color:#339966;"><br />;Boolean
to warn if directory user picks<br />;already
exists</span><span style="font-family:&#39;Courier New&#39;;color:red;"></span><span style="font-family:&#39;Courier New&#39;;color:blue;"><br />DirExistsWarning</span><span style="font-family:&#39;Courier New&#39;;">=no</span><span style="font-family:&#39;Courier New&#39;;color:#339966;"><br />;directory
where uninstaller exe will be</span><span style="font-family:&#39;Courier New&#39;;color:#339966;"><br />;this will
be where our app is<br />;the
constant we use is {app}</span><span style="font-family:&#39;Courier New&#39;;"></span><span style="font-family:&#39;Courier New&#39;;color:blue;"><br />UninstallFilesDir</span><span style="font-family:&#39;Courier New&#39;;">={app}</span><span style="font-family:&#39;Courier New&#39;;color:#339966;"><br />;Location
of the license file</span><span style="font-family:&#39;Courier New&#39;;color:red;"></span><span style="font-family:&#39;Courier New&#39;;color:blue;"><br />LicenseFile</span><span style="font-family:&#39;Courier New&#39;;">={#SourceFileDir}\eula.rtf</span><span style="font-family:&#39;Courier New&#39;;color:#339966;"><br />;file
to show before install (I show sys requirements)</span><span style="font-family:&#39;Courier New&#39;;color:red;"></span><span style="font-family:&#39;Courier New&#39;;color:blue;"><br />InfoBeforeFile</span><span style="font-family:&#39;Courier New&#39;;">={#</span><span style="font-family:&#39;Courier New&#39;;">SourceFileDir</span><span style="font-family:&#39;Courier New&#39;;">}\sysreq.rtf</span><span style="font-family:&#39;Courier New&#39;;color:#339966;"><br />;file
to show after install (I show readme)</span><span style="font-family:&#39;Courier New&#39;;color:red;"></span><span style="font-family:&#39;Courier New&#39;;color:blue;"><br />InfoAfterFile</span><span style="font-family:&#39;Courier New&#39;;">={#</span><span style="font-family:&#39;Courier New&#39;;">SourceFileDir</span><span style="font-family:&#39;Courier New&#39;;">}
eadme.txt<span style="color:red;"></span></span><span style="font-family:&#39;Courier New&#39;;color:#339966;"><br />;Custom
image to show on left side of installer</span><span style="font-family:&#39;Courier New&#39;;color:blue;"><br />WizardImageFile</span><span style="font-family:&#39;Courier New&#39;;">={#</span><span style="font-family:&#39;Courier New&#39;;">SourceFileDir</span><span style="font-family:&#39;Courier New&#39;;">}installlogo.bmp<br /></span><span style="font-family:&#39;Courier New&#39;;color:#339966;">;Icon
for uninstall in add/remove programs<br />;I use
whatever my apps icon is</span><span style="font-family:&#39;Courier New&#39;;color:red;"></span><span style="font-family:&#39;Courier New&#39;;color:blue;"><br />UninstallDisplayIcon</span><span style="font-family:&#39;Courier New&#39;;">={app}\MyApp.exe</span><span style="font-family:&#39;Courier New&#39;;color:#339966;"><br />;Version
number of your installer (not your app)</span><span style="font-family:&#39;Courier New&#39;;color:red;"></span><span style="font-family:&#39;Courier New&#39;;color:blue;"><br />VersionInfoVersion</span><span style="font-family:&#39;Courier New&#39;;">=1.0.0.0</span><span style="font-family:&#39;Courier New&#39;;color:#339966;"><br />;If
IncludeFramework, append _FW to end of compiled setup</span><span style="font-family:&#39;Courier New&#39;;color:#339966;">;<br />I do
this to make it easy to compile a version with and<br />;without
the framework included</span><span style="font-family:&#39;Courier New&#39;;"></span><span style="font-family:&#39;Courier New&#39;;color:red;"><br />#if
IncludeFramework</span><span style="font-family:&#39;Courier New&#39;;color:blue;"><br />&nbsp; OutputBaseFilename</span><span style="font-family:&#39;Courier New&#39;;">=setup_FW</span><span style="font-family:&#39;Courier New&#39;;color:red;"><br />#else</span><span style="font-family:&#39;Courier New&#39;;color:blue;"><br />&nbsp; OutputBaseFilename</span><span style="font-family:&#39;Courier New&#39;;">=Setup</span><span style="font-family:&#39;Courier New&#39;;color:red;"><br />#endif</span><span style="font-family:&#39;Courier New&#39;;color:#339966;"><br />;Directory
where setup.exe will be compiled to</span><span style="font-family:&#39;Courier New&#39;;color:red;"></span><span style="font-family:&#39;Courier New&#39;;color:blue;"><br />OutputDir</span><span style="font-family:&#39;Courier New&#39;;">={#</span><span style="font-family:&#39;Courier New&#39;;">SourceFileDir</span><span style="font-family:&#39;Courier New&#39;;">}\setup<span style="color:red;"></span></span></p>
<p>So there you have it. The comments should explain what is going on for you. Some of these fields are optional and can be removed if not needed. Likewise there are some others that I do not use. See the INNO help file for a full list of what is available to the <b>[setup]</b> section.</p>
<p>The next section is the <b>[files]</b> section. This section defines what files should be compiled into the setup.exe file. Our example will simply consist of an exe, a readme.txt and the .NET framework redistributable file.</p>
<p class="MsoNormal"><b><span style="font-family:&#39;Courier New&#39;;">[files]<br /></span></b><span style="font-family:&#39;Courier New&#39;;color:blue;">Source</span><span style="font-family:&#39;Courier New&#39;;">: {#SourceFileDir}\MyApp.exe; &nbsp; &nbsp; &nbsp;<span></span><span style="color:blue;">DestDir</span>:
{app};<span> </span><span style="color:blue;">Flags</span>:
ignoreversion {#IsExternal}<br /></span><span style="font-family:&#39;Courier New&#39;;color:blue;">source</span><span style="font-family:&#39;Courier New&#39;;">: {#</span><span style="font-family:&#39;Courier New&#39;;">SourceFileDir</span><span style="font-family:&#39;Courier New&#39;;">}readme.txt; &nbsp;&nbsp; <span></span><span style="color:blue;">&nbsp; DestDir</span>:
{app};<span>&nbsp;</span><span></span><span style="color:blue;">Flags</span>:
ignoreversion </span><span style="font-family:&#39;Courier New&#39;;">{#IsExternal}</span><span style="font-family:&#39;Courier New&#39;;color:red;"><br />#if
IncludeFramework</span><span style="font-family:&#39;Courier New&#39;;color:blue;"><br />&nbsp; Source</span><span style="font-family:&#39;Courier New&#39;;">: {#SourceFileDir}\dotnetfx.exe;<span> </span><span style="color:blue;">DestDir</span>:
{tmp};<span> </span><span style="color:blue;">Flags</span>:
ignoreversion </span><span style="font-family:&#39;Courier New&#39;;">{#IsExternal}</span>
<span style="font-family:&#39;Courier New&#39;;">; <span style="color:#3366ff;">Check</span>: NeedsFramework</span>
<br /><span style="font-family:&#39;Courier New&#39;;color:red;">#endif</span></p>
<p class="MsoNormal">So what we have here are 3 lines indicating our source files, where they will go on the target machine, and any flags we need to associate. Again see INNO help for all possible flags and properties here. (I will mention to refer to INNO Help a lot because it is too robust to cover every aspect in one article, however you will end up with a fully working script by the end of this one). Notice that while we install myapp.exe and readme.txt to the {app} directory, we unpack the dotnetfx.exe (framework redist file) to a temp directory. The constant {app} actually translates at install time to whatever directory the user selects for installation. While we always like to assume they will install to c:\program files\ that will never be the case 100% of the time. IgnoreVersion just means we are going to copy the file no matter what, you can put restrictions here to only copy the file if its a newer version, etc. Also notice our {#IsExternal} directive here. I mentioned earlier that its value should be either &quot;&quot; or &quot;external&quot;. That is because these preprocessor directives are compiled into literal strings for use when the setup is compiled. What that means is, when the value of #IsExternal is &quot;&quot; the line looks like this once compiled:</p>
<p class="MsoNormal">&nbsp; <span style="font-family:&#39;Courier New&#39;;color:blue;">Source</span><span style="font-family:&#39;Courier New&#39;;">: {#SourceFileDir}\MyApp.exe; &nbsp; &nbsp; &nbsp;<span></span><span style="color:blue;">DestDir</span>:
{app};<span> </span><span style="color:blue;">Flags</span>:
ignoreversion </span></p>
<p class="MsoNormal">however if the value is &quot;external&quot; then the line compiles like this:</p>
<p class="MsoNormal">&nbsp; <span style="font-family:&#39;Courier New&#39;;color:blue;">Source</span><span style="font-family:&#39;Courier New&#39;;">: {#SourceFileDir}\MyApp.exe; &nbsp; &nbsp; &nbsp;<span></span><span style="color:blue;">DestDir</span>:
{app};<span> </span><span style="color:blue;">Flags</span>:
ignoreversion external</span></p>
<p class="MsoNormal">Which adds the external flag to this file. The external flag tells the setup that the file to install is actually not packed into the installer, but a loose file included along with it. This makes preprocessor directives very powerful to customize your installer when used in this way. The <b>Check: NeedsFramework</b> line for the .NET redist file will call up a custom function to check and see if the machine even needs the .NET framework or not. We will define that function when we get to the code section of the script.</p>
<p>Now lets specify the shortcuts we want made.</p>
<p class="MsoNormal"><b><span style="font-family:&#39;Courier New&#39;;">[icons]<br /></span></b><span style="font-family:&#39;Courier New&#39;;color:#3366ff;">Name</span><span style="font-family:&#39;Courier New&#39;;">: {group}\MyApp;<span style="color:red;"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="color:#3366ff;">Filename</span>:
{app}\MyApp.exe;<span style="color:red;"><span> </span></span><span style="color:#3366ff;">WorkingDir</span>: {app}<br /></span><span style="font-family:&#39;Courier New&#39;;color:#3366ff;">Name</span><span style="font-family:&#39;Courier New&#39;;">: {group}\</span><span style="font-family:&#39;Courier New&#39;;">Remove </span><span style="font-family:&#39;Courier New&#39;;">MyApp;<span style="color:red;"><span> </span></span><span style="color:#3366ff;">Filename</span>: </span><span style="font-family:&#39;Courier New&#39;;">{uninstallexe};<span style="color:red;"><span>&nbsp; </span></span><span style="color:#3366ff;">WorkingDir</span>: {app}<br /></span><span style="font-family:&#39;Courier New&#39;;color:#3366ff;"></span><span style="font-family:&#39;Courier New&#39;;"></span><span style="font-family:&#39;Courier New&#39;;color:#3366ff;">Name</span><span style="font-family:&#39;Courier New&#39;;">: {userdesktop}\MyApp;<span style="color:red;"><span>&nbsp; </span></span><span style="color:#3366ff;">Filename</span>: </span><span style="font-family:&#39;Courier New&#39;;">{app}\MyApp.exe</span><span style="font-family:&#39;Courier New&#39;;">;<span style="color:red;"><span> </span></span><span style="color:#3366ff;">WorkingDir</span>: {app}</span></p>
<p class="MsoNormal">So we are putting a shortcut in the programs section of the start menu, as well as the desktop. We also put an uninstall shortcut in the start menu folder. Everything that is in curly braces { } is a constant that INNO translates at install time into a real string value. Where can you find all these constants? Yup, you guessed it, in the INNO Help file.</p>
<p>On to the <b>[Run]</b> section. This section defines what processed should be run as part of the installation. </p>
<p class="MsoNormal"><b><span style="font-family:&#39;Courier New&#39;;">[Run]</span></b></p>
<p class="MsoNormal"><span style="font-family:&#39;Courier New&#39;;color:red;">#if
IncludeFramework</span><span style="font-family:&#39;Courier New&#39;;color:#3366ff;"><br />&nbsp; Filename</span><span style="font-family:&#39;Courier New&#39;;">: {tmp}\dotnetfx.exe;<span> </span><span style="color:#3366ff;">Parameters</span>: &quot;/q:a /c:&quot;&quot;install /l
/q&quot;&quot;&quot;;<span> </span><span style="color:#3366ff;">WorkingDir</span>: {tmp};<span> </span><span style="color:#3366ff;">Flags</span>:
skipifdoesntexist; <span style="color:#3366ff;">StatusMsg</span>:
&quot;Installing .NET Framework if needed&quot;</span><span style="font-family:&#39;Courier New&#39;;color:red;"><br />#endif</span><span style="font-family:&#39;Courier New&#39;;color:#3366ff;"></span></p>
<p class="MsoNormal"><span style="font-family:&#39;Courier New&#39;;color:#3366ff;">Filename</span><span style="font-family:&#39;Courier New&#39;;">:
{win}\Microsoft.NET\Framework\v2.0.50727\CasPol.exe; <span style="color:#3366ff;">Parameters</span>:
&quot;-q -machine -remgroup &quot;&quot;MyApp&quot;&quot;&quot;;<span> </span><span style="color:#3366ff;">WorkingDir</span>: {tmp}; <span style="color:#3366ff;">Flags</span>:
skipifdoesntexist runhidden; <span style="color:#3366ff;">StatusMsg</span>:
&quot;Setting Program Access Permissions...&quot;</span></p>
<p class="MsoNormal"><span style="font-family:&#39;Courier New&#39;;color:#3366ff;">Filename</span><span style="font-family:&#39;Courier New&#39;;">:
{win}\Microsoft.NET\Framework\v2.0.50727\CasPol.exe; <span style="color:#3366ff;">Parameters</span>:
&quot;-q -machine -addgroup 1.2 -url &quot;&quot;file://{app}/*&quot;&quot;
FullTrust -name &quot;&quot;MyApp&quot;&quot;&quot;; <span></span><span style="color:#3366ff;">WorkingDir</span>:
{tmp}; <span style="color:#3366ff;">Flags</span>:
skipifdoesntexist runhidden; <span style="color:#3366ff;">StatusMsg</span>:
&quot;Setting Program Access Permissions...&quot;</span></p>
<p>Lets go over each of these 3 lines here. The first one installs the .NET framework. The Parameters we pass along with this file are simply those to make the installation silent (show no UI while installing). You may or may not want this, it is up to you. For full details on the exact meaning of the command line switch used for the framework installation, visit this <a target="_blank" title="MSDN: .NET Framework Redist Command Line Switches">MSDN Page</a> on the subject. The StatusMsg field lets you specify a message that INNO displays while this process is running. I left it off for space saving here, but I often also put &quot;this will take several minutes...&quot; because lets face it, installing the .NET framework on an average computer does take a few minutes. The skipifdcoesntexist flag is important because remember that we only extracted the framework to the temp directory if the system didn&#39;t have the framework installed, so if it doesn&#39;t exist, then chances are the user already had the framework (or is out of disk space!).</p>
<p>The other 2 lines simply run caspol.exe to set permissions using a little &quot;url&quot; trick. If you are not familiar with CasPol, it is the Code Access Security Policy utility. .NET code has an extra layer of code security hooked into the runtime, and by default your local drives run with full trust, and your network drives run with partial trust. Long story short, if your customer installs your program to a network mapped drive, there is a good chance they will start getting weird security exceptions because you did not design your app to run at partial trust (or your app simply NEEDS full trust to do whatever it is your app does). So we have INNO set permissions to give full trust to wherever the user installed the app. If its the local drive, they already had the permissions, and if its a network drive, this will give them the permissions to the installation folder. Its a win/win scenario. You may wonder why there are 2 entries though, and that is because we first try to remove an existing entry if it is there, to avoid duplicate entries in caspol. If there was no entry to begin with, the method simply completes without doing anything.</p>
<p>The skipifdoesntexist flag just tells INNO that if the file we are working with doesn&#39;t exist for some reason, don&#39;t try to launch it. The only time it won&#39;t exist is in weird scenarios of framework installation failure, etc.</p>
<p>Like the <b>[run]</b> section, there is also an <b>[uninstallrun]</b> section. This section defines what will run when the program is uninstalled. The only thing I put here, is to remove the caspol entry, just like we did in the run section. It is better to do it here, the entry in the run section is just a backup.</p>
<p class="MsoNormal"><b><span style="font-family:&#39;Courier New&#39;;">[UninstallRun]</span></b></p>
<p class="MsoNormal"><span style="font-family:&#39;Courier New&#39;;color:#3366ff;">Filename</span><span style="font-family:&#39;Courier New&#39;;">:
{win}\Microsoft.NET\Framework\v2.0.50727\CasPol.exe; <span style="color:#3366ff;">Parameters</span>:
&quot;-q -machine -remgroup &quot;&quot;</span><span style="font-family:&#39;Courier New&#39;;">MyApp</span><span style="font-family:&#39;Courier New&#39;;">&quot;&quot;&quot;; <span style="color:#3366ff;">Flags</span>: skipifdoesntexist runhidden;</span></p>
<p>So up to this point, we have finished our entire INNO script file, with the exception of the code section. INNO implemented a pascal scripting code section at some point in its life to allow you to extend and customize the installation experience. There is little you can not do, but this flexibility comes at the cost of knowing how to write the code. The Inno Setup IDE is not nearly as advanced as the Visual Studio IDE, so writing code can be a bit difficult at times, however I am going to take you through my standard setup code, and explain what it does.</p>
<p>The code section starts with, yes you guessed it, a <b>[code]</b> heading.</p>
<p>First we are going to define some functions that we will use to aid our setup process.</p>
<p>I am not going to go over every single line here in detail. The functions are pretty short, and do specifically only what they say. Most of them are just checking the state of the system for a given value, like if the framework exists, if a service pack is installed, etc. Most of them query a registry key, check a file version, or something similar to see what is already on the system.</p>
<p class="MsoNormal"><b><span style="font-family:&#39;Courier New&#39;;">[code]</span></b></p>
<p class="MsoNormal"><span style="font-family:&#39;Courier New&#39;;color:#339966;">//
Indicates whether .NET Framework 2.0 is installed.</span><span style="font-family:&#39;Courier New&#39;;color:#3366ff;"><br />function</span><span style="font-family:&#39;Courier New&#39;;"> IsDotNET20Detected(): boolean;</span><span style="font-family:&#39;Courier New&#39;;color:#3366ff;"><br />var<br /></span><span style="font-family:&#39;Courier New&#39;;"><span>&nbsp;&nbsp;&nbsp; </span>success: boolean;<br /><span>&nbsp;&nbsp;&nbsp; </span>install: cardinal;<br /></span><span style="font-family:&#39;Courier New&#39;;color:#3366ff;">begin<br /></span><span style="font-family:&#39;Courier New&#39;;"><span>&nbsp;&nbsp;&nbsp; </span>success := RegQueryDWordValue(HKLM,
&#39;SOFTWARE\Microsoft\NET Framework Setup\NDP\v2.0.50727&#39;, &#39;Install&#39;, install);<br /><span>&nbsp;&nbsp;&nbsp; </span>Result := success <span style="color:#3366ff;">and</span>
(install = 1);<br /></span><span style="font-family:&#39;Courier New&#39;;color:#3366ff;">end</span><span style="font-family:&#39;Courier New&#39;;">;</span></p>
<p class="MsoNormal"><span style="font-family:&#39;Courier New&#39;;color:#339966;">//RETURNS
OPPOSITE OF IsDotNet20Detected FUNCTION<br />//Remember
this method from the Files section above</span><span style="font-family:&#39;Courier New&#39;;color:#3366ff;"><br />function</span><span style="font-family:&#39;Courier New&#39;;"> NeedsFramework(): Boolean;</span><span style="font-family:&#39;Courier New&#39;;color:#3366ff;"><br />begin</span><span style="font-family:&#39;Courier New&#39;;"><span><br />&nbsp; </span>Result := (IsDotNET20Detected = false);</span><span style="font-family:&#39;Courier New&#39;;color:#3366ff;"><br />end</span><span style="font-family:&#39;Courier New&#39;;">;</span></p>
<p class="MsoNormal"><span style="font-family:&#39;Courier New&#39;;color:#339966;">//CHECKS
TO SEE IF CLIENT MACHINE IS WINDOWS 95</span><span style="font-family:&#39;Courier New&#39;;color:#3366ff;"><br />function</span><span style="font-family:&#39;Courier New&#39;;"> IsWin95 : boolean;</span><span style="font-family:&#39;Courier New&#39;;color:#3366ff;"><br />begin</span><span style="font-family:&#39;Courier New&#39;;"><span><br />&nbsp; </span>Result := (InstallOnThisVersion(&#39;4.0,0&#39;,
&#39;4.1.1998,0&#39;) = irInstall);</span><span style="font-family:&#39;Courier New&#39;;color:#3366ff;"><br />end</span><span style="font-family:&#39;Courier New&#39;;">;</span></p>
<p class="MsoNormal"><span style="font-family:&#39;Courier New&#39;;"></span><span style="font-family:&#39;Courier New&#39;;color:#339966;">//CHECKS
TO SEE IF CLIENT MACHINE IS WINDOWS NT4</span><span style="font-family:&#39;Courier New&#39;;color:#3366ff;"><br />function</span><span style="font-family:&#39;Courier New&#39;;"> IsWinNT : boolean;</span><span style="font-family:&#39;Courier New&#39;;color:#3366ff;"><br />begin</span><span style="font-family:&#39;Courier New&#39;;"><span><br />&nbsp; </span>Result := (InstallOnThisVersion(&#39;0,4.0.1381&#39;,
&#39;0,4.0.1381&#39;) = irInstall);</span><span style="font-family:&#39;Courier New&#39;;color:#3366ff;"><br />end</span><span style="font-family:&#39;Courier New&#39;;">;</span></p>
<p class="MsoNormal"><span style="font-family:&#39;Courier New&#39;;"></span><span style="font-family:&#39;Courier New&#39;;color:#339966;">//GETS
VERSION OF IE INSTALLED ON CLIENT MACHINE</span><span style="font-family:&#39;Courier New&#39;;color:#3366ff;"><br />function</span><span style="font-family:&#39;Courier New&#39;;"> GetIEVersion : <span style="color:#3366ff;">String</span>;<br /></span><span style="font-family:&#39;Courier New&#39;;color:#3366ff;">var<br /></span><span style="font-family:&#39;Courier New&#39;;"><span>&nbsp; </span>IE_VER: <span style="color:#3366ff;">String</span>;</span><span style="font-family:&#39;Courier New&#39;;color:#3366ff;"><br />begin</span><span style="font-family:&#39;Courier New&#39;;"><span><br />&nbsp; </span></span><span style="font-family:&#39;Courier New&#39;;"><span style="color:#339966;">{First check if Internet
Explorer is installed}</span><span><br /></span><span style="color:#3366ff;">&nbsp; if</span>
RegQueryStringValue(HKLM,&#39;SOFTWARE\Microsoft\Internet
Explorer&#39;,&#39;Version&#39;,IE_VER) <span style="color:#3366ff;">then</span><span><br />&nbsp;&nbsp; &nbsp;&nbsp; </span>Result := IE_VER<span><br /></span><span style="color:#3366ff;">else<br /></span><span>&nbsp;&nbsp;&nbsp; </span><span style="color:#339966;">{No Internet
Explorer at all}<br /></span><span>&nbsp;&nbsp;&nbsp; </span>result := &#39;&#39;;<br /></span><span style="font-family:&#39;Courier New&#39;;color:#3366ff;">end</span><span style="font-family:&#39;Courier New&#39;;">;</span></p>
<p class="MsoNormal"><span style="font-family:&#39;Courier New&#39;;color:#339966;">//GETS
THE VERSION OF WINDOWS INSTALLER DLL</span><span style="font-family:&#39;Courier New&#39;;color:#3366ff;"><br />function</span><span style="font-family:&#39;Courier New&#39;;"> GetMSIVersion(): <span style="color:#3366ff;">String</span>;</span><span style="font-family:&#39;Courier New&#39;;color:#3366ff;"><br />begin</span><span style="font-family:&#39;Courier New&#39;;"><span><br />&nbsp;&nbsp;&nbsp;
</span>GetVersionNumbersString(GetSystemDir+&#39;\msi.dll&#39;, Result);</span><span style="font-family:&#39;Courier New&#39;;color:#3366ff;"><br />end</span><span style="font-family:&#39;Courier New&#39;;">;</span></p>
<p class="MsoNormal"><span style="font-family:&#39;Courier New&#39;;color:#339966;">//LAUNCH
DEFAULT BROWSER TO WINDOWS UPDATE WEBSITE</span><span style="font-family:&#39;Courier New&#39;;color:#3366ff;"><br />procedure</span><span style="font-family:&#39;Courier New&#39;;"> GoToWindowsUpdate;<br /></span><span style="font-family:&#39;Courier New&#39;;color:#3366ff;">var</span><span style="font-family:&#39;Courier New&#39;;"><span><br />&nbsp; </span>ErrorCode: Integer;</span><span style="font-family:&#39;Courier New&#39;;color:#3366ff;"><br />begin</span><span style="font-family:&#39;Courier New&#39;;"><span><br />&nbsp; </span><span style="color:#3366ff;">if</span>
(MsgBox(&#39;Would you like to go to the Windows Update site now?&#39; + chr(13) +
chr(13) + &#39;(Requires Internet Connection)&#39;<span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>, mbConfirmation, MB_YESNO) =
IDYES) <span style="color:#3366ff;">then</span><span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>ShellExec(&#39;open&#39;,
&#39;http://windowsupdate.microsoft.com&#39;,&#39;&#39;, &#39;&#39;, SW_SHOW, ewNoWait, ErrorCode);</span><span style="font-family:&#39;Courier New&#39;;color:#3366ff;"><br />end</span><span style="font-family:&#39;Courier New&#39;;">;</span></p>
<p>Those are all of our helper functions. Now lets define a few functions that are built into INNO setup. When I say built in, I mean these are functions that INNO already knows the name of, and will run at a certain point if you define them.</p>
<p>There are many, but the ones we are going to use are</p>
<ul>
<li>InitializeSetup()</li>
<li>GetCustomSetupExitCode()<br /></li>
</ul>
<p>InitializeSetup() is the first thing that runs when the installer starts up, so we will add in our custom logic to this routine to make the installer do the checks we want to perform.</p>
<p>GetCustomSetupExitCode() is something that runs when setup is complete. We use this method to check for the .NET Framework (because at this point it should be installed) and give an error message if we don&#39;t find it. There are any number of reasons why the installation could fail, so all we really do here is check and alert the user if it did fail.</p>
<p>I will define GetCustomSetupExitCode() first because it is shorter and self explanatory.</p>
<p class="MsoNormal"><span style="font-family:&#39;Courier New&#39;;color:#339966;">//IF
SETUP FINISHES WITH EXIT CODE OF 0, MEANING ALL WENT WELL</span><span style="font-family:&#39;Courier New&#39;;color:#339966;"><br />//THEN
CHECK FOR THE PRESENCE OF THE REGISTRY FLAG TO INDICATE THE<br />//.NET
FRAMEWORK WAS INSTALLED CORRECTLY<br />//IT
CAN FAIL WHEN CUST DOESN&#39;T HAVE CORRECT WINDOWS INSTALLER VERSION</span><span style="font-family:&#39;Courier New&#39;;color:#3366ff;"><br />function</span><span style="font-family:&#39;Courier New&#39;;"> <b>GetCustomSetupExitCode</b>():
Integer;</span><span style="font-family:&#39;Courier New&#39;;color:#3366ff;"><br />begin</span><span style="font-family:&#39;Courier New&#39;;"><span><br />&nbsp; </span><span style="color:#3366ff;">if</span>
(IsDotNET20Detected = false) <span style="color:#3366ff;">then</span><span><br />&nbsp;&nbsp;&nbsp; </span><span style="color:#3366ff;">begin</span><span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>MsgBox(&#39;.NET Framework was NOT installed successfully!&#39;,mbError, MB_OK);<span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>result := -1<span><br />&nbsp;&nbsp;&nbsp; </span><span style="color:#3366ff;">end</span></span><span style="font-family:&#39;Courier New&#39;;color:#3366ff;"><br />end</span><span style="font-family:&#39;Courier New&#39;;">;</span></p>
<p>Now on to the InitializeSetup. This routine is pretty long, because it contains all the checks we want to do before allowing the user to install. Returning False from this routine aborts the setup.</p>
<p>We perform the following checks</p>
<ul>
<li>If Windows 2000, require at least SP3</li>
<li>If WIndows XP, require at least SP2</li>
<li>If Windows 95 or NT, don&#39;t install at all</li>
<li>If NT based (2000, XP, 2003, Vista), require MSI Installer 3 or higher</li>
<li>If 9x based (98, ME), require MSI Installer 2 or higher</li>
<li>If IE version is less than version 5.01, don&#39;t install</li>
<li>If admin is not logged on, don&#39;t install (.NET Framework install requires admin rights)</li>
</ul>
<p>So lets get to the code shall we:</p>
<p class="MsoNormal"><span style="font-family:&#39;Courier New&#39;;"></span><span style="font-family:&#39;Courier New&#39;;color:#3366ff;">function</span><span style="font-family:&#39;Courier New&#39;;"> <b>InitializeSetup</b>:
Boolean;</span><span style="font-family:&#39;Courier New&#39;;color:#3366ff;"><br />var</span><span style="font-family:&#39;Courier New&#39;;"><span><br />&nbsp; </span>Version: TWindowsVersion;<span><br />&nbsp; </span>IE_VER: <span style="color:#3366ff;">String</span>;<span><br />&nbsp; </span>MSI_VER: <span style="color:#3366ff;">String</span>;<span><br />&nbsp; </span>NL: Char;<span><br />&nbsp; </span>NL2: <span style="color:#3366ff;">String</span>;</span><span style="font-family:&#39;Courier New&#39;;color:#3366ff;"><br />begin</span></p>
<p class="MsoNormal"><span style="font-family:&#39;Courier New&#39;;"><span>&nbsp; </span>NL := Chr(13);<span><br />&nbsp; </span>NL2 := NL + NL;<br /><span><br />&nbsp; </span><span style="color:#339966;">// Get Version of
Windows from API Call</span><span><br />&nbsp; </span>GetWindowsVersionEx(Version); </span></p>
<p class="MsoNormal"><span style="font-family:&#39;Courier New&#39;;"><span>&nbsp; </span><span style="color:#339966;">// On Windows
2000, check for SP3</span></span></p>
<p class="MsoNormal"><span style="font-family:&#39;Courier New&#39;;"><span>&nbsp; </span><span style="color:#3366ff;">if</span>
Version.NTPlatform <span style="color:#3366ff;">and</span><span><br />&nbsp;&nbsp;&nbsp;&nbsp; </span>(Version.Major = 5) <span style="color:#3366ff;">and</span><span><br />&nbsp;&nbsp;&nbsp;&nbsp; </span>(Version.Minor = 0) <span style="color:#3366ff;">and</span><span><br />&nbsp;&nbsp;&nbsp;&nbsp; </span>(Version.ServicePackMajor &lt; 3) <span style="color:#3366ff;">then</span><span><br />&nbsp; </span><span style="color:#3366ff;">begin</span><span><br />&nbsp;&nbsp;&nbsp; </span>SuppressibleMsgBox(&#39;When running on Windows
2000, Service Pack 3 is required.&#39; + NL +<span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&#39;Visit&#39; + NL2 +<span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&#39; ***
http://windowsupdate.microsoft.com ***&#39; + NL2 +<span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&#39;to get the needed Windows
Updates,&#39; + NL +<span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&#39;and then reinstall this
program&#39;,<span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>mbCriticalError, MB_OK,
MB_OK);<span><br />&nbsp;&nbsp;&nbsp; </span>GoToWindowsUpdate;<span><br />&nbsp;&nbsp;&nbsp; </span>Result := False;<span><br />&nbsp;&nbsp;&nbsp; </span>Exit;<span><br />&nbsp; </span><span style="color:#3366ff;">end</span>;</span></p>
<p class="MsoNormal"><span style="font-family:&#39;Courier New&#39;;"><span>&nbsp; </span><span style="color:#339966;">// On Windows XP,
check for SP2</span><span><br />&nbsp; </span><span style="color:#3366ff;">if</span>
Version.NTPlatform <span style="color:#3366ff;">and</span><span><br />&nbsp;&nbsp;&nbsp;&nbsp; </span>(Version.Major = 5) <span style="color:#3366ff;">and</span><span><br />&nbsp;&nbsp;&nbsp;&nbsp; </span>(Version.Minor = 1) <span style="color:#3366ff;">and</span><span><br />&nbsp;&nbsp;&nbsp;&nbsp; </span>(Version.ServicePackMajor &lt; 2) <span style="color:#3366ff;">then</span><span><br />&nbsp; </span><span style="color:#3366ff;">begin</span><span><br />&nbsp;&nbsp;&nbsp; </span>SuppressibleMsgBox(&#39;When running on Windows
XP, Service Pack 2 is required.&#39; + NL +<span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&#39;Visit&#39; + NL2 + &#39; ***
http://windowsupdate.microsoft.com ***&#39; + NL2 +<span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&#39;to get the needed
Windows Updates,&#39; + NL +<span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&#39;and then reinstall this
program&#39;,<span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>mbCriticalError, MB_OK,
MB_OK);<span><br />&nbsp;&nbsp;&nbsp; </span>GoToWindowsUpdate;<span><br />&nbsp;&nbsp;&nbsp; </span>Result := False;<span><br />&nbsp;&nbsp;&nbsp; </span>Exit;<span><br />&nbsp; </span><span style="color:#3366ff;">end</span>;</span></p>
<p class="MsoNormal"><span style="font-family:&#39;Courier New&#39;;"><span>&nbsp; </span><span style="color:#339966;">//IF WINDOWS 95
OR NT DON&#39;T INSTALL</span><span><br />&nbsp; </span><span style="color:#3366ff;">if</span>
(IsWin95) <span style="color:#3366ff;">or</span> (IsWinNT) <span style="color:#3366ff;">then</span><span><br />&nbsp; </span><span style="color:#3366ff;">begin</span><span><br />&nbsp;&nbsp;&nbsp; </span>SuppressibleMsgBox(&#39;This program can not
run on Windows 95 or Windows NT.&#39;,<span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>mbCriticalError, MB_OK, MB_OK);<span><br />&nbsp;&nbsp;&nbsp; </span>Result := False;<span><br />&nbsp;&nbsp;&nbsp; </span>Exit;<span><br />&nbsp; </span><span style="color:#3366ff;">end</span>;<span>&nbsp; </span></span></p>
<p class="MsoNormal"><span style="font-family:&#39;Courier New&#39;;"><span>&nbsp; </span><span style="color:#339966;">//CHECK MSI VER,
NEEDS TO BE 3.0 ON ALL SUPPORTED SYSTEM EXCEPT 95/ME, WHICH NEEDS 2.0)</span><span><br />&nbsp; </span>MSI_VER := GetMSIVersion<span><br />&nbsp; </span><span style="color:#3366ff;">if</span>
((Version.NTPlatform) <span style="color:#3366ff;">and</span> (MSI_VER &lt;
&#39;3&#39;)) <span style="color:#3366ff;">or</span> ((<span style="color:#3366ff;">Not</span>
Version.NTPlatform) <span style="color:#3366ff;">and</span> (MSI_VER &lt; &#39;2&#39;)) <span style="color:#3366ff;">then</span><span><br />&nbsp;&nbsp;&nbsp; </span>begin<span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>SuppressibleMsgBox(&#39;You do not have all
the required Windows Updates to install this program.&#39; + NL +<span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&#39;Visit ***
http://windowsupdate.microsoft.com *** to get the needed Windows Updates,&#39; + NL
+<span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&#39;and then reinstall
this program&#39;,<span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>mbCriticalError,
MB_OK, MB_OK);<span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>GoToWindowsUpdate;<span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Result := False;<span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Exit;<span><br />&nbsp; </span><span style="color:#3366ff;">end</span>;<span>&nbsp; </span></span></p>
<p class="MsoNormal"><span style="font-family:&#39;Courier New&#39;;"><span>&nbsp; </span><span style="color:#339966;">//CHECK THE IE
VERSION (NEEDS TO BE 5.01+)</span><span><br />&nbsp; </span>IE_VER := GetIEVersion;<span><br />&nbsp; </span><span style="color:#3366ff;">if</span> IE_VER
&lt; &#39;5.01&#39; <span style="color:#3366ff;">then</span><span><br />&nbsp;&nbsp;&nbsp; </span><span style="color:#3366ff;">begin</span><span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:#3366ff;">if</span>
IE_VER = &#39;&#39; <span style="color:#3366ff;">then</span><span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:#3366ff;">begin</span><span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>MsgBox(&#39;Microsoft Internet Explorer
5.01 or higher is required to run this program.&#39; + NL2 +<span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&#39;You do not currently have
Microsoft Internet Explorer installed, or it is not working correctly.&#39; + NL +<span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&#39;Obtain a newer version at
www.microsoft.com and then run setup again.&#39;, mbInformation, MB_OK);<span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:#3366ff;">end</span><span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:#3366ff;">else</span><span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:#3366ff;">begin</span><span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>MsgBox(&#39;Microsoft Internet Explorer
5.01 or higher is required to run this program.&#39; + NL2 +<span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&#39;You are using version &#39; +
IE_VER + &#39;.&#39; + NL2 +<span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&#39;Obtain a newer version at
www.microsoft.com and then run setup again.&#39;, mbInformation, MB_OK);<span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:#3366ff;">end</span><span><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>GoToWindowsUpdate;<span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>result := false;<span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>exit;<span><br />&nbsp; </span><span style="color:#3366ff;">end</span>;<span>&nbsp; </span></span></p>
<p class="MsoNormal"><span style="font-family:&#39;Courier New&#39;;"><span>&nbsp; </span><span style="color:#339966;">//MAKE SURE USER
HAS ADMIN RIGHTS BEFORE INSTALLING<br /></span><span>&nbsp; </span><span style="color:#3366ff;">if</span>
IsAdminLoggedOn <span style="color:#3366ff;">then</span><span><br />&nbsp;&nbsp;&nbsp; </span><span style="color:#3366ff;">begin</span><span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>result := true<span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>exit;<span><br />&nbsp;&nbsp;&nbsp; </span><span style="color:#3366ff;">end</span><span><br />&nbsp; </span><span style="color:#3366ff;">else</span><span><br />&nbsp;&nbsp;&nbsp; </span><span style="color:#3366ff;">begin</span><span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>MsgBox(&#39;You must have admin rights to
perform this installation.&#39; + NL +<span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&#39;Please log on with an account
that has administrative rights,&#39; + NL +<span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&#39;and run this installation again.&#39;,
mbInformation, MB_OK);<span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>result := false;<span><br />&nbsp;&nbsp;&nbsp; </span><span style="color:#3366ff;">end</span><span><br />&nbsp; </span><span style="color:#3366ff;">end</span>;</span><span style="font-family:&#39;Courier New&#39;;color:#3366ff;"><br />end</span><span style="font-family:&#39;Courier New&#39;;">.</span></p>
<p class="MsoNormal">So there you have it. The completed code section of the script. You now have a fully functional INNO setup script that will package the .NET 2.0 framework with your program into a single setup.exe, extract it at install time if needed, and install it silently. The script also checks to make sure the user has admin rights, has the needed service pack levels for certain operating systems, has the needed versions of things like MSI installer and Internet Explorer. There may be other checks you want to do (or even some you want to omit) so I hope my script is a good jumping off point for you to get into customizing your own. My code also offers in several failure spots due to system requirements to launch the windows update page so users can get the updates they need. You would be surprised how many people are not even running SP2 on Windows XP even though it has been out a long time now and we are already up to SP3.</p>
<p class="MsoNormal">Next time, I plan to show you how to associate a file type with your program at install time. For example, maybe your app is a text editor, and you want to associate *.txt files with your program when it is installed. There are a few registry keys involved, and we will go over them in detail. I will also show you how to install a font file, as well as adding some custom functionality to the UI of the installer, to perform even more custom actions. Then I will go into detail about detecting if the user has the .NET Framework installed from an ASP, PHP, or ASP.NET Page and Internet Explorer (Sorry FireFox users, it doesn&#39;t work for you). This can be useful when you want to offer your user a download with or without the framework (to save the 20+MB) based on if they need it or not.</p>
<p>You can download the complete script file as it appears in this article from the <a title=".NET INNO Example File" href="http://zerosandtheone.com/media/p/180.aspx">media download page</a>.</p>
<p>&nbsp;</p><div style="clear:both;"></div><img src="http://zerosandtheone.com/aggbug.aspx?PostID=167" width="1" height="1">VB.NETInstallerINNOSetup.NET