Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

dotNetInstaller - Setup Bootstrapper for .NET Application

0.00/5 (No votes)
4 Jan 2004 74  
With this tool the developer can define the application prerequisites and install the correct version of these components in the correct order based on the user operating system type and language, allow the user to download these components from the web or install these components directly.

Sample Image - maximum width is 600 pixels

Introduction

This application doesn't replace tool like InstallShield, Wise or Visual Studio Setup and Deployment Project; my goal is to create an application to help the users to installing the correct prerequisites components. Today applications often need to install several components to work properly: Windows Service Pack, Internet Explorer, MDAC, .NET Framework etc. With this tool the developer can define the application prerequisites and install the correct version of these components in the correct order based on the user operating system type and language, allow the user to download these components from the web or install these components directly from his media (usually a CDROM).

This project is composed with these components:

  • dotNetInstaller.exe + Source Code: Main bootstrapper application, written with Visual Studio 2003 C++ and MFC.
  • InstallerEditor.exe + Source Code: Application for editing configurations files and edit dotNetInstaller.exe resources, written with Visual Studio 2003 C#
  • Configuration samples and SupportFiles template.

This project is based on Microsoft bootstrapper and Kevin Moore bootstrapper 'Enhanced .NET Bootstrap Setup' (http://www.codeproject.com/managedcpp/dotnetsetup.asp).

All the settings are stored in a XML file parsed with a little XML parser by Cho, Kyung-min (XMLite: simple xml parser. http://www.codeproject.com/useritems/xmlite.asp

A special thanks to Kevin Moore and Cho, Kyung-min for theirs works.

I build this project with Windows XP, Visual Studio 2003 (C++ and C#) and Microsoft .NET Framework 1.1 . Check for the latest version at: http://dotnetinstaller.codeplex.com/.

The editor: InstallerEditor.exe

You can create two type of configuration file with the editor:

  • Standalone Configuration: A configuration that runs the components setups from a specified path, usually a relative path of the dotNetInstaller.exe file. Select this configuration if you want to distribute your application with a CDROM.
  • Web Configuration: A configuration that download and execute the required components from a specified web site. Select this configuration if you want to distribute the configuration over the web.

With the editor you can create these configurations files and then include these files in the dotNetInstaller resources. With this solution you can only distribute one exe file.

Another solution is to distribute in the same path of the dotNetInstaller.exe the configuration file using the name 'configuration.xml' and if you want you can also distribute a bitmap with the name 'banner.bmp'. dotNetInstaller first checks for this configuration file, if the file doesn't exist the application use the configuration embedded into the exe.

In the XML configuration file you can use some path variables in all command or path settings. Is recommended to use " symbol in all the command attributes that contains one or more space, in msi component the " symbol is not supported and if needed the application add this symbol automatically. Is recommended to use #APPPATH variable in all the attributes with path value (like command, dialog_bitmap, package), this constant allows to write relative path string from the dotNetInstaller.exe folder otherwise all the path are relative to the system current directory.

If you configure the application to download the components, I recommend to download the components using the #TEMPPATH variable and the run the components from the same path.

For example if you want to launch a file ('My App.exe') in the same folder of dotNetInstaller.exe you can write in the command string: "#APPPATH\My App.exe"

In this release you cannot change the order of the components from the editor, if you need this feature you must change the XML manually.

Tutorials

How to create a Standalone Setup to install .NET Framework and your msi setup:

We create a CDROM with your MSI package, SupportFiles (like .NET Framework), configuration file configuration.xml) and a bitmap (banner.bmp). All these components are installed directly from the CDROM.

  1. Create a folder that represents your final distribution CDROM, for example 'c:\MyRelease\' .
  2. Copy under 'c:\MyRelease\' the directory 'SupportFiles' that you can find in the project .zip .
  3. In the SupportFiles replace all the readme.txt files with the real components files that your installation need; for example replace the 'SupportFiles\dotNet\v1.1\English\dotnetfx.exe.readme.txt' with the real dotnetfx.exe file that you can download from microsoft web site.
  4. Copy your msi package (that you can create with Visual Studio .NET, InstallShield or others installation tool) under the 'c:\MyRelease\'.
  5. Copy dotNetInstaller.exe under 'c:\MyRelease\'.
  6. Create a bitmap (banner.bmp 110x208 pixels) with the name 'c:\MyRelease\banner.bmp' with the logo of your application.
  7. Execute the InstallerEditor.exe file.
  8. Select the menu 'File'->'New...' and create a new file with the name 'c:\MyRelease\configuration.xml' .
  9. Select from the menu 'Tools'->'Language for New Item' the user interface language that you want. (for now there are only English and Italian, but you can write your custom messages editing manually the properties.)
  10. Right click on the 'Config File' node and select 'Add'->'Setup Configuration'
  11. Select the just created 'install:' node and customize the properties 'dialog_caption', 'dialog_message' and 'installation_completed' with the name of your application.
  12. Right click on the 'install:' node and select 'Add'->'Component Wizard...'
  13. Select 'Microsoft .NET Framework 1.1', 'Distributed with dotNetInstaller' and click the OK button.
  14. Right click on the 'install:' node and select 'Add'->'Msi Component'
  15. Select the just created node and customize the properties 'description', 'installmessage' and 'package' with the name of your setup and msi package name. In the package path I use #APPPATH variable that represents the dotNetInstaller.exe path.
  16. Select the menu 'File'->'Save'.
  17. Write all the contents of the 'c:\MyRelease\' directory on your CDROM. If you want you can also create a 'autorun.inf' file that execute dotNetInstaller.exe.

For others informations in the .zip you can find an example of a configuration.xml file configured to install these components for Windows 98, 98 SE, Millennium, NT4, 2000, XP, 2003:

  • Windows Service Pack required to install .NET Framework, MDAC and Internet Explorer (Windows 2000 Sp4, Windows NT 4 Sp6a, Year 2000 Updates for Windows 98)
  • Internet Explorer 6 Sp1
  • .NET Framework 1.1
  • Microsoft Data Access Component 2.7 (MDAC 2.7)
  • Microsoft JET 4.0 Service Pack 6
  • Sample application

I included a SupportFiles directory with the required structure and some readme.txt files where you can find a link to download the required components (usually from microsoft web site).

How to create a Web Setup to install .NET Framework and your msi setup:

Create the support files directory

We create a web site with your MSI package and all the support files (like .NET Framework).

  1. Create a folder that represents your final distribution web site, for example 'http://www.mysite.com/MyRelease/' .
  2. Copy under 'http://www.mysite.com/MyRelease/' the directory 'SupportFiles' that you can find in the project .zip .
  3. In the SupportFiles replace all the readme.txt files with the real components files that your installation need; for example replace the 'SupportFiles\dotNet\v1.1\English\dotnetfx.exe.readme.txt' with the real dotnetfx.exe file that you can download from microsoft web site.
  4. Copy your msi package (that you can create with Visual Studio .NET, InstallShield or others installation tool) under the 'http://www.mysite.com/MyRelease/'.

Create the main configuration file

We create a configuration file that download and install the components from a web site (for .NET Framework and one MSI package).

  1. Execute the InstallerEditor.exe file.
  2. Select the menu 'File'->'New...' and create a new file with the name 'configuration.xml' .
  3. Select from the menu 'Tools'->'Language for New Item' the user interface language that you want. (for now there are only English and Italian, but you can write your custom messages editing manually the properties.)
  4. Right click on the 'Config File' node and select 'Add'->'Setup Configuration'
  5. Select the just created 'install:' node and customize the properties 'dialog_caption', 'dialog_message' and 'installation_completed' with the name of your application.
  6. Right click on the 'install:' node and select 'Add'->'Component Wizard...'
  7. Select 'Microsoft .NET Framework 1.1', 'Downloaded from Internet', and replace 'http://www.myWebSite.com/MyApp/SupportFiles' with your web site for example 'http://www.mysite.com/MyRelease/SupportFiles' and click the OK button.
  8. Right click on the 'install:' node and select 'Add'->'Msi Component'
  9. Select the just created node and customize the properties 'description', 'installmessage' and 'package' with the name of your setup and msi package name. Replace the #APPPATH\mysetup.msi with #TEMPPATH\MyApplicationName\mysetup.msi, this is download destination of the package.
  10. Right click on the msi component and select 'Add'->'Download Dialog'
  11. Select the just created node 'Download Dialog' and customize the properties 'dialog_caption' and 'dialog_message' with the name of your application.
  12. Right click on the 'Download Dialog' node and select 'Add'->'Download File'
  13. Select the just created node under 'Download Dialog' and customize the properties 'componentname', 'destinationpath' (write for example '#TEMPPATH\MyApplicationName\', must be the same path of the 'package' property) and 'sourceurl' (write 'http://www.mysite.com/MyRelease/mysetup.msi') .
  14. Select the menu 'File'->'Save', and copy this configuration.xml file under 'http://www.mysite.com/MyRelease/'.

Create the bootstrapper

We create an executable that download and execute the main configuration file from a web site, changing the dotNetInstaller resources with our custom xml and bitmap.

  1. Create a bitmap (banner.bmp 110x208 pixels) with the logo of your application.
  2. Execute the InstallerEditor.exe file.
  3. Select the menu 'File'->'New...' and create a new file with the name 'reference.xml' .
  4. Select from the menu 'Tools'->'Language for New Item' the user interface language that you want. (for now there are only English and Italian, but you can write your custom messages editing manually the properties.)
  5. Right click on the 'Config File' node and select 'Add'->'Web Configuration'
  6. Select the just created node 'reference:' and customize the properties 'referencefile' for example write '#TEMPPATH\MyApplicationName\configuration.xml'.
  7. Select the node 'Download Dialog' under 'reference:' and customize the properties 'dialog_caption' and 'dialog_message'.
  8. Right click on the 'Download Dialog' node and select 'Add'->'Download File'
  9. Select the just created node under 'Download Dialog' and customize the properties 'componentname', 'destinationpath' (write for example '#TEMPPATH\MyApplicationName\', must be the same path of the 'referencefile' property) and 'sourceurl' (write 'http://www.mysite.com/MyRelease/configuration.xml', must be the URL where you can download the previously created configuration file) .
  10. Select the menu 'File'->'Save'.
  11. Select the menu 'File'->'Create Exe'; in the 'Template dotNetInstaller.exe file' select the path of your 'dotNetInstaller.exe', in the 'Banner Bitmap' select the bitmap created previously. Click Make button and select a file name of the new dotNetInstaller, for example 'MyWebSetup.exe'.
  12. Copy 'MyWebSetup.exe' under your 'http://www.mysite.com/MyRelease/'.

Now the user must only download the 'MyWebSetup.exe' (310 Kb) and this application automatically download and install the required components, in this example .NET Framework and one MSI package.

Path variables

These are the variables that can be used in all the attribute that contains a path (dialog_bitmap,command, ...):
  • #APPPATH - This string is replaced with the directory of dotNetInstaller.exe program.
  • #SYSTEMPATH - This string is replaced with the windows system directory (using GetSystemDirectory() API, usually c:\WINNT\System32 ).
  • #WINDOWSPATH - This string is replaced with the windows directory (using GetWindowsDirectory() API, usually c:\WINNT ).
  • #TEMPPATH - This string is replaced with the temp directory (using GetTempPath() API, usually C:\Documents and Settings\[User]\Local Settings\Temp ).

Check if the component is already installed

You can use the installedcheck element to check if a component is already installed, for example you can check if the .NET Framework 1.1 is installed by reading this registry key SOFTWARE\Microsoft\NET Framework Setup\NDP\v1.1.4322\Install = 1.

For now there are two type of install check:

  • 'check_registry_value' - Check for a specific registry value.
  • 'check_file' - Check for a specific file with a specific version.
There are two type of comparison when check for a registry value or file version: 'match' (check if the exact value is present) or 'version' (check if the version is greater or equal).

You can look at the example to see the check used with the most common components: .NET Framework, Internet Explorer, MDAC, JET and more.

Check the operating system version

This is the operating system table used to install a component only in a specific operating system version.

Operating System Name Enum Numeric Identifier
Not Valid winNotValid 0
Windows 95 win95 5
Windows 95 OSR2 win95osr2 10
Windows 98 win98 15
Windows 98 Second Edition win98se 20
Windows Millennium winME 25
Windows NT4 winNT4 30
Windows NT4 Service Pack 6 winNT4sp6 35
Windows NT4 Service Pack 6a winNT4sp6a 40
Windows 2000 win2000 45
Windows 2000 Service Pack 1 win2000sp1 50
Windows 2000 Service Pack 2 win2000sp2 55
Windows 2000 Service Pack 3 win2000sp3 60
Windows 2000 Service Pack 4 win2000sp4 65
Windows XP winXP 75
Windows XP Service Pack 1 winXPsp1 80
Windows Server 2003 winServer2003 90
Next .... winLater 100

Same examples:

  • Install a component only in Windows XP (with no service pack check) : os_filter_greater='74', os_filter_smaller='90' .
  • Install a component only in Windows 2000 or later : os_filter_greater='44', os_filter_smaller='' .
  • Install a component only in Windows 98 (not in Windows 98 SE): os_filter_greater='14', os_filter_smaller='16' .
  • Install a component always: os_filter_greater='', os_filter_smaller='' .

Usually is best to use an install check to see if the component is already installed, but for some components is necessary to check the operating system version (especially for service pack or windows update).

XML Elements help:

Warning: the XML parser is not fully compatible with the standard xml specification; it supports only the basic features. Do not include XML comments and use a normal XML sintax like the examples provided in the .zip. Is recommended to use the editor InstallerEditor to create or modify your configuration files or I suggest to use a normal text editor. If you want to insert the " char in the XML manually you must write " .

configurations
Root element
ATTRIBUTES:
CHILDREN:
configuration

configuration (type='install')
A configuration used to install a collection of components.
ATTRIBUTES:
type 'install' - Type of the configuration. Can be 'install' or 'reference'.
lcid A filter to install this configuration only on all operating system language equals or not equals than the LCID specified (see Help->LCID Table). Separate multiple LCID with comma (',') and use not symbol ('!') for NOT logic ('1044,1033,!1038' ). You can also filter a specified component.
dialog_caption Main dialog title.
dialog_message Main message of the main dialog.
dialog_bitmap Bitmap file used in the left panel of the main dialog. If this file doesn't exist or this attribute is empty the application load the bitmap from the .exe resource. Can contain path constant (see Help->Path Constant).
install_caption Caption of the Install button.
cancel_caption Caption of the Cancel button.
reinstallflag_caption Caption for the 'Reinstall all check box'.
status_installed The string used for indicating an installed component.
status_notinstalled The string used for indicating a not installed component.
failed_exec_command_continue The message used when a component cannot be installed and ask if the application can continue with others components (Yes/No message). Must contain one '%s' string where the application put the description of the component.
installation_completed Installation completed message.
dialog_install_next Caption for the next button.
dialog_install_skip Caption for the skip button.
installing_component_wait The message used when installing a component. Must contain one '%s' string where the application put the description of the component.
reboot_required The message used when the application need to restart and ask if restart now (with a Yes/No message).
CHILDREN:
components

configuration (type='reference')
A configuration used to download a configuration file from a specific URL.
ATTRIBUTES:
type 'reference' - Type of the configuration. Can be 'install' or 'reference'.
lcid A filter to install this configuration only on all operating system language equals or not equals than the LCID specified (see Help->LCID Table). Separate multiple LCID with comma (',') and use not symbol ('!') for NOT logic ('1044,1033,!1038' ). You can also filter a specified component. If empty no filter is applied.
CHILDREN:
downloaddialog
configfile

configfile
The path to the configuration file downloaded.
ATTRIBUTES:
filename The configuration file where the application can find the configuration. Usually this is the destination directory of the downloaded component. Can contain path constant (see Help->Path Constant).
CHILDREN:

components
A collection of elements of type 'component'.
ATTRIBUTES:
CHILDREN:
component

component (see also specific help based on the 'type' attribute)
A component to be installed.
ATTRIBUTES:
type The type of the component; can be 'cmd' for executing generic command line installation or 'msi' for installing Windows Installer MSI package or 'openfile' to open a file. Each type has his own attributes.
os_filter_greater A filter to install this component only on all operating system id greater than the id specified (see Help->Operating System Table). For example to install a component only in Windows 2000 or later write '44'.
os_filter_smaller A filter to install this component only on all operating system id smaller than the id specified (see operating system table). For example to install a component preceding Windows 2000 write '45'.
os_filter_lcid A filter to install this component only on all operating system language equals or not equals than the LCID specified (see Help->LCID table). Separate multiple LCID with comma (',') and use not symbol ('!') for NOT logic ('1044,1033,!1038' ). You can also filter all the configuration element.
installcompletemessage The message used when a component is successfully installed. To disable this message leave this property empty.
mustreboot Indicates if ask to reboot after this component is installed successfully (True/False). Normally if the system must be restarted is automatically the component that tells this setup (with special return code) to stop and restart the system, but in special circumstances (for example in Windows 98) we must force a reboot to install correctly some components (for example the .NET Framework).
description Description of this component. This value is used also in some message to replace the %s string.
installmessage The message used to confirm the installation of this component.
note Note, not used by the setup.
CHILDREN:
installedcheck
downloaddialog

component (type='cmd')
A component that can be used to execute an .exe file like a setup application.
ATTRIBUTES:
see also 'component' element
type 'cmd'
command Specifies the command to execute when installing this component. Must be a valid command for the 'CreateProcess' API. Can contain " char and path constant (see Help->Path Constant).
CHILDREN:

component (type='msi')
A component that can be used to install an msi package.
ATTRIBUTES:
see also 'component' element
type 'msi'
package Specifies the path to the msi package to execute when installing this component. Can contain path constant (see Help->Path Constant).
cmdparameters Specifies the command line parameters for the msiexec program. Can contain " char and path constant (see Help->Path Constant). See MSDN for the command line you can use with Windows Installer.
CHILDREN:

component (type='openfile')
A component that can be used to open a web page, a readme file or execute any file during the installation process.
ATTRIBUTES:
see also 'component' element
type 'openfile'
file Specifies the file to open when installing this component. Must be a valid command for the 'ShellExecute' API. Can contain " char and path constant (see Help->Path Constant). Can be for example a internet link.
CHILDREN:

downloaddialog
Represents a list of files to download and the configurations of the download dialog.
ATTRIBUTES:
dialog_caption The caption of the download dialog.
dialog_message The initial message that appears in the download dialog before the user press the 'Start' button.
autostartdownload True to start the download without user interaction, False to let the user press the 'Start' button.
dialog_message_downloading The message that appears in the download dialog when the download process start.
buttonstart_caption Caption of the 'Start' button.
buttoncancel_caption Caption of the 'Cancel' button.
CHILDREN:
downloads

downloads
A collection of elements of type 'download'.
ATTRIBUTES:
CHILDREN:
download

download
Represent a single file to download.
ATTRIBUTES:
componentname The description of the file to download.
sourceurl The complete source path of the file to download. For example 'http://www.yourwebsite.com/ SetupX/Setup.exe' . Must be URL with http:// or ftp:// protocol
destinationpath The complete destination path where the application copy the sourceurl file. Is recommended to use the TEMP path for destination like this: '#TEMPPATH\\APPLICATION_NAME' . Can contain path constant (see Help->Path Constant).
destinationfilename New name of the downloaded file. Leave this value empty to use the same filename of the original filename.
CHILDREN:

installedcheck (type='check_file')
The application check if a component is installed looking for the specified registry information or file.
ATTRIBUTES:
type 'check_file' - Type of the check, can be 'check_registry_value' to check for a specific value in the registry or 'check_file' to check for a specific file.
filename Specifies the file to search, if the application cannot find the specified file then the component must be installed. This attribute can contain path constant (see Help->Path Constant).
fileversion The version of the file, can be used to perform version check based on comparison attribute. If empty the application check only for the presence of the file.
comparison Comparison mode, can be 'match' to check if the exact version of the file is present or 'version' to compare if a version equal or greater is present.
CHILDREN:

installedcheck (type='check_registry_value')
The application check if a component is installed looking for the specified registry information or file.
ATTRIBUTES:
type 'check_registry_value' - Type of the check, can be 'check_registry_value' to check for a specific value in the registry or 'check_file' to check for a specific file.
path Specifies the registry path to search for the registry value specified, must be a path under HKEY_LOCAL_MACHINE like 'SOFTWARE\\MyCompany'.
fieldname The registry field name in the specified path, for example 'Installed'.
fieldvalue The registry value used to check if the component is installed, this value is converted based on the value type specified.
fieldtype Specifies the type of the registry field, can be 'REG_DWORD' (for numeric value) or 'REG_SZ' (for string value).
comparison Comparison mode; can be 'match' to check if the exact value is present in the registry or 'version' to compare the registry version with the specified version and return true if the registry version is equal or greater then the version specified.
CHILDREN:

Notes

  • If a component needs to restart the system the application automatically add a key in the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run to reload the application at the next startup.
  • You must run this application with Administrator privilege.
  • I have tested this setup with Windows 98, 98 SE, Millennium, 2000, XP. (not yet tested with Windows NT 4 and with Terminal Server).
  • Is useful that also your setup write a little registry value where you can put some information about the installed version, this allows this application to check if your setup is already installed using a 'installedcheck' element.
  • The setup of .NET Framework 1.1 (dotNetFx.exe) automatically installs Windows Installer 2.0 .
  • In order to install MDAC 2.7 in Windows 98 you must first install the updates for year 2000 compatibility. In my sample configuration files I added a component for this files, you can download these updates from Windows Update Catalog web site.
  • In Windows 98 after installing .NET Framework I must force a reboot of the computer (with the 'mustreboot' attribute) otherwise some .NET Framework or Windows Installer components or not installed correctly.
  • The only way that I found to check if JET 4.0 is already installed is to search for Msjet40.dll file in the system directory with the version 4.0.7328.0 (JET 4.0 Sp7).
  • You can use this project also to launch multiple MSI or others setup at the same time, and can be used also for not .NET project (like Visual Basic, VC++, ...).
  • In Windows Millennium I had some strange problems if I rename the dotNetInstaller.exe to Setup.exe . If I launch Setup.exe I cannot detect anymore the right operating system version ( return Windows 98 version instead of Windows Millennium ). Anyway all you have to do is to leave the executable name dotNetInstaller.exe or use a name different from Setup.exe.
  • In my configuration file I also added components for installing Service Pack and others system components, but warning installing this kind of components is always an unsafe operation.
  • To find the operating system installed LCID I use the information provided in this article: Microsoft Knowledge Base Article - 181604. HOWTO: Determine Default Language ID of Windows 95 or WinNT
  • To download the components I use URLDownloadToFile API.
  • For now I don't delete the downloaded components, for this reason I recommended to use the TEMP path as a destination folder.
  • To change the resources of the exe file I use BeginUpdateResourceW, UpdateResourceW and EndUpdateResourceW API. These API are available only on Windows NT, 2000 and XP for this reason the editor cannot be used on Windows 98 (the bootstrapper is supported also on Windows 98 ).

Summary of future works

  • Silent mode and command line support.

History

1.1.0.2 (02 January 2004)

  • Added ability to download required components from the web.
  • Added #TEMPPATH path variable.
  • Editor to create and modify XML configuration file.
  • Many changes to the XML structure, old files are not compatible.
  • Fixed a bug on the function that read the operating system LCID and others small bugs fixing.

1.0.8.0 (05 November 2003)

  • Added #WINDOWSPATH path constant.

1.0.7.0 (28 September 2003)

  • Bug fixed on MDAC and JET components configuration file (registry check to REG_SZ and language support for JET).

1.0.7.0 (27 September 2003)

  • First public release.

License

dotNetInstaller - C++ Setup bootstrapper for .NET

Copyright (c) 2003, Davide Icardi

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  • Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  • Neither the name of the ORGANIZATION nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here