Installer / Updater
This project is based on my Cabinet Library CabLib which is also published with source code on The Code Project.
The original purpose was to create an Installer or Setup which installs an ASPX server consisting of 3000 files. But obviously you can use this Installer to install any software package.
The installation files consist of only a tiny EXE file (the installer) and a CAB file which contains all files of the software package.
The CAB file can be:
- on the local disk (CAB file in the same folder as the EXE file)
- in the local network (LNK file which points to a fileserver)
- on the Internet (URL file which points to an HTTP(S) or FTP server).
You can do two things with the installer:
- Complete Setup (the whole software package is installed)
- Update of an existing installation (only the files that need an update are replaced).
If an update is done via Internet, a partial download of the CAB file is possible:
Only the parts of the CAB file will be downloaded which contain the files that require an update.
Obviously you can extend the existing code to your needs: for example add some Registry entries or run a script when the installation is done.
Multi-Language
If you don't need an installer, you can still use the versatile multi-language class from this project and use it in your own .NET projects. (See below.)
Features
- The installation process is 100% transparent: The log file shows exactly which files have been replaced. (depending on their MD5)
- Before installing new files, the user can make a backup of the current software installation into a CAB file.
- If there should be any problems with the new version of your software, it is very easy to restore the backup.
- The data in the CAB files can be encrypted.
- The GUI and the Log file entries are multi-language.
You can easily add a new language by simply adding entries to a XML translation file without modifying one line of code.
Limitations
- The total size of files which are to be packed into the CAB file must not exceed 2 GB.
- The resulting CAB file must not exceed 2 GB.
Source Code
You will find a very clean C# (Visual Studio 2003) source code with tidy error handling and plenty of comments written by a very experienced programmer.
The code is reusable, as for example the translation class, the MultiHashtable or the Logfile output.
The Installation Process
Instead of writing long explanations, I recommend to download the project and play around with it. Try this:
- Set the checkbox "Create a backup" and specify any folder on your harddisk. For example: C:\Program Files\Microsoft Office.
- Do NOT set the checkbox "The file to be installed".
- Click "Start".
- Now the installer will pack all files (which have the file extensions which are specified in the code) into a CAB file like Backup_2008.05.27_13.04.cab.
- If you open this CAB file, you also find a file _FileList.txt which stores a list of all packed files and their MD5.
- Now you can uncheck "Create a Backup" and check "The file to be installed" and specify the CAB file you created recently.
- If you click "Start" again, the installer will not install anything because all files are up to date.
- Now delete some files from your folder C:\Program Files\Microsoft Office.
- If you run the same setup again, the installer will show you a list of all the files you have deleted and ask you if want to install them (if "... confirm the installation" is checked).
- At the end, open the log file and you see exactly what has happened.
Installation from a File Server
If you want to put the CAB file on a file server in your company for internal setups, put a link (*.LNK) in the same folder as the Installer.exe.
The link will also be listed in the combo box of the files to be installed.
Installation via Internet
You can also put the CAB file on a HTTP(S) or FTP server and specify the address in a *.URL file in the same folder as the Installer.exe.
If your FTP server supports resuming broken downloads or your HTTP(S) server runs a tiny script (see CabLib article) you can make updates with partial downloads.
This means that only the parts of the CAB file are downloaded which are required to extract the outdated files.
Example: Your software package consists of 500 files, of which only 15 files have changed in the latest version. The CAB archive on the server contains the latest version of your entire software package and no matter which version is currently installed on your client's computer: the installer will only download the files which are out of date.
The data transferred will be compressed data and optionally encrypted data. (Read about CAB encryption.)
The Installer automatically takes the decision if it is more intelligent to download the entire CAB file or to download it partially.
If more than 50% of the files need an update, an entire download will be faster than multiple partial downloads.
IMPORTANT
If your server does NOT support partial downloads, you must modify the blocksize in the file Defaults.cs:
In this case, always the entire CAB file will be downloaded.
public static int GetDownloadBlocksize(bool b_Calculate)
{
return 0;
}
For a detailed description of this important parameter, read the CabLib article!
The Log File
The logfile contains all information which is required to analyze any problem that might arise after installing a new version of a software package.
The Log files can be stored on a server as a history of all installations.
The CAB file stores all files in UTC time. This has the advantage that the file times are independent of the local timezone.
File Extensions
You must adapt the file Defaults.cs to your needs.
There you can specify which file extensions to include into a backup (whitelist) and which file extensions to ignore (blacklist).
If while scanning a folder, a file extension isn't found neither in the whitelist nor in the blacklist, a warning is written to the debugfile to inform you that you have to update your file extension lists.
CabLib.dll
All the compression and extraction functionality is contained in CabLib.dll.
This file is compiled as an embedded resource into the EXE file.
So the only files you have to deliver are the EXE and the CAB file.
The Multi-Language Translation Class
How Not To Do It
If you ever tried to build a multilanguage application with Visual Studio .NET, you already know that this is a real nightmare.
The only chance you have is creating one RESX file for each language and each GUI form.
If your GUI has 50 Windows and you want to support 10 languages you need 500 resource files!!
To add a new language, you have to beg the translator to translate 50 cryptic RESX files!
For every tiny change in a GUI form (e.g. adding a button) you have to modify 10 resource files.
Ugly, ugly, ugly, ugly, ugly!!
Conclusion: Visual Studio .NET does not offer any multilanguage support which is worth thinking about it.
You will only waste your time with Microsoft's approach!
Simplicity
Instead of using the translation class of this installer in your own projects, you will be able to build multilanguage applications without effort.
- You can add an additional language by simply editing ONE XML file. You can pass this XML file to the translators which can edit it with WordPad.
- There is no need to recompile your project - neither for correcting translation errors nor for adding languages.
There are two ways you can deliver the XML file:
- You compile the XML file into the EXE as an embedded resource. In this way it is "fixed".
- You can put the XML file into the same folder as the EXE and load it when the program starts.
In this case, the user can edit it and if he likes, he can correct translation errors himself or add new languages.
You can ask your users to email you the XML file when they have added a new language, so with time, your program will support more and more languages and you don't even have to do anything for that!
GUI Design
The XML file contains a section for each form.
In the form designer, you put a keyword into braces {...} and in the code, you simply add one line:
public panelSettings()
{
InitializeComponent();
Lng.TranslateForm(this);
}
It cannot be easier anymore!
ATTENTION
It is your responsibility when designing GUI forms to let enough space for texts which may be longer in other languages.
It is the responsibility of the translator to check that his translation fits into the GUI and, if it should not, to abbreviate his prose.
The XML File
Additionally to the forms, the XML file contains a section for error messages and for logfile entries.
Obviously you can add your own sections as you need.
The section "Common" will automatically be searched if an entry is not found in the specified section.
So you can put texts like "Next", which are used in multiple locations, into the section "Common" instead of repeating them multiple times.
Enum eXml
The translation class contains an enum eXml for all translations which are not part of a GUI (e.g. error messages).
If you add an error message to the XML file, you must also add an entry into this enum.
This enum is essential to automatically check for missing translations (see below).
Each nesting level in the XML file is represented by an underscore in the enum eXml:
Messages
To translate a string like "Scanning files", you simple write:
string s_Scanning = Lng.TranslateString(Lng.eXml.Logfile_ScanFiles);
To translate a formatted string like "Backed up {0} files successfully.", you write:
string s_Success = Lng.TranslateFormat
(Lng.eXml.Logfile_BackupSuccess, s32_FileCount, 0, 0);
To display a messagebox with an error icon and the text "File not found: 'D:\Data\Setup.cab'", you write:
Lng.ErrorBoxFormat(Lng.eXml.Messages_FileNotFound, s_File, 0, 0);
Word Lists
To get a list of words (for example, to fill a combo box or for a table heading), you write in the XML file...
<FileList>
<english>File|Size|Date|MD5</english>
<german>Datei|Größe|Datum|MD5</german>
<spanish>Archivo|Tamaño|Fecha|MD5</spanish>
</FileList>
... and in the code...
string[] s_ColumnHeadings =
Lng.TranslateString(Lng.eXml.Logfile_FileList).Split('|');
... which returns only the values for the current language or...
Hashtable i_Hash = Lng.GetMultiString(Lng.eXml.Logfile_FileList);
... which returns a Hashtable with an English key and a value translated to the current language (e.g. German, Spanish, English):
| Key |
Value |
| File |
Datei |
| Size |
Größe |
| Date |
Datum |
| MD5 |
MD5 |
Auto Error Checking
The translation class contains code which automatically checks for missing translations.
Into a menu of your program, you can put an item "Check Translations" and the user gets an error for missing strings.
The following code checks all translations:
Lng.XmlErrorCheck(new Type[]
{ typeof(frmMain), typeof(panelSettings), .... } );
You must pass the types of all your GUI forms and panels.
Therefore all your forms and panels must support a default (parameterless) constructor!
Then the checking routine will create an instance of each form and panel and check the XML file for missing translations.
Additionally it will check if there are translations missing for one of the entries in the enum eXml.
If translations are missing, it shows a messagebox with a detailed error message.
P.S.: If you want to merge changes on an XML file made by another person into your version, I recommend using merge tools like Araxis Merge.
History
- 31st May, 2008: Initial post
| You must Sign In to use this message board. |
|
|
 |
|
|
 |
|
 |
I'm getting this error when I try to update from a URL.
error 122: the data area passed to a system call is too small.
Any ideas?
Thanks
Rick
Rick Cole
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hello
You are one of these intelligent guys which are hopeless.
My car does not start, what do I have to do now ?
I dont know!
Elmü
|
| Sign In·View Thread·PermaLink | 1.00/5 |
|
|
|
 |
|
 |
That's an intellengent response, indeed!
You don't need to be so defensive simply because your code doesn't work.
Rather than wasting my time trying to find/fix the problem I moved on to another solution. But that was weeks ago.
R
Rick Cole
|
| Sign In·View Thread·PermaLink | 5.00/5 |
|
|
|
 |
|
 |
Hello
The code works perfectly.
If YOU have any problem with it it should be obviuos that asking a question here requires as much as possible details about YOUR problem which I never have seen!
How about a stack trace ? How about posting the URL you use ? Where does the error come from (from the server or from .NET) ?
People like you who are so incredible lazy that they dont give !ANY! information are realy hopeless!
Elmü
|
| Sign In·View Thread·PermaLink | 3.00/5 |
|
|
|
 |
|
|
 |
|
 |
Hello
There is a new version 4.0 of Installer available. It uses the new version 9.9 of CabLib.
This has some improvements as you can read in the documentation in the ZIP file. Additionally a bug has been fixed.
Download Mulitlanguage Installer 4.0
If you need 64 Bit support also download the CabLib 9.9 project!
Elmü
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
Clearly a lot of good work and very useful reusable components have gone into / come out of this project, however it seems as though you are re-inventing the wheel...
The Windows Installer engine in conjunstion with .msi's (installation database files) and .msp's (patch files) provides a raft of enterprise-grade features to ensure sound software installations; roll-back, component advertising, repair, product self-healing, patching, product upgrades, dll version management, multi-language support, to name but a few.
There are a number of tools out there to assist with the creation of .msi's, my personal favorite happens to be Wise's Package Studio, which is on an equal footing to Installshield (although I find that Installshield is easier to get to grips with for beginners, but Wise results in cleaner installation files & doesn't have any pre-reqs to run - compared to Installshield's scripting runtime, which in all fairness can be disabled by someone who knows what they're doning in Installshield).
Clearly Wise & Installshield are expensive products, but for someone like me who regularly packages software for distribution to a wide audience it is worth every penny. If you're not so keen to part with the cash, then there are a number of other (cheaper & probably freeware!) products available these days that perform a similar role (such as Visual Studio - although as an msi purist I cringe every time I come across a VS.NET generated .msi!!).
Sorry to harp on, I just thought it was important to point out that the windows installer engine is an extremeley powerful (free!) resource that is sitting on every windows user's desktop, just waiting to be used!
Matt
// Life is too short...
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hey
It seems you work for Microsoft or at least did a quick look at the project and give your opinion without reading the details.
This project can NOT be replaced with MSI nor Installshield. Read the details before posting here!
I worked once with the Installer integrated into Visual Studio: It is primitive ans really stupid. I had a lot of problems with it until I was sick of it.
Elmü
|
| Sign In·View Thread·PermaLink | 2.71/5 |
|
|
|
 |
|
 |
The Windows Installer Engine (with the right authoring toolset) provides the ability to satisfy your articles' objectives. I'm not being derogatory, just pointing out to others that with the relevant 'msi' know-how Windows Installer is ready and waiting to be used.
P.S. I work for a mid-sized financial investment company (not Microsoft! ) and frequently re-package applications and Websites (including ASP.Net) etc. for internal automated deployment.
P.P.S. I have to agree with you on the MSI support within Visual Studio; it's awful!!
Matt
// Life is too short...
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
looks like people reading this might have years of experience in deployment strategies
most of the project i created were for internal or my own dev tools so "click once" installers available in express editions and professional edition was all i needed.
recently however i needed to give an executable to a customer.
basically now i need to be concerned with presence, program placement in c:\program files, embedded resources, adding items to registery, uninstalling(cleaning up) ect.
so the options now are: 1) visual studio professional has setup deployment projects. (what use case should i use this?) 2) then theres installshield 2008 (what use case should i use this?) 3) and then there is this tool. (what use case should i use this?)
i'm trying to decide what tool i'm going to invest the time to learn. anyone with words of advice or words of caution?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hello
My opinion is that writing into the Registry in the installer is at the wrong place!
The installer should only copy the files and the application ITSELF should understand that it is running for the first time and do ALL the initialization that is required. Opening hundreds of windows in an installer and making a lot of initialization in an installer is at the wrong place.
My installer project has no UNinstall implemented as it was origionally designed to be used by administrators who install a server which is never uninstalled. But you can easily extend it because you have the source code.
> anyone with words of advice or words of caution?
My advice: When you can, you should always prefer projects for which you have the sourcecode! Later changes will be easily done. Even more complicated things can be implemented later easily. Neither for InstallShield nor for the Visual Studio installer (which is quite primitive) you have the source code.
And obviously neither of them offers you a comfortable internet update.
Another disadvantage of InstallShield becomes visible when you look into the folder: C:\Program Files\InstallShield Installation Information There a lot of disk space is wasted with useless files which are never used except you uninstall the application. ____________________
It is easy to implement Uninstall:
Your Application adds a Registry entry:
[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall\MyApplication] DisplayName = "My super program" UninstallString = "C:\ProgramFiles\MyApplication\Application.exe /Uninstall"
Thats all! Aftter adding this to the Registry your application will appear in Control Panel under "Add / Remove Programs".
When the user uninstalls your application via Control Panel the Application.exe will be called with the commandline parameter "/Uninstall". You detect this in your application and
1.) delete all files that need to be deleted. 2.) delete all Registry entries that need to be deleted. 3.) As the Application.exe is not able to finally delete itself (because it is running) you simply let Windows delete the EXE when the computer is booted the next time. You do this with
MoveFileEx("C:\ProgramFiles\MyApplication\Application.exe", NULL, MOVEFILE_DELAY_UNTIL_REBOOT) Thats it. As you see it is easy to implement Uninstall. You don't need any separate uninstaller for that. The advantage is, that ANY changes you do in the future at your program, will NEVER require ANY change on the installer! You always use the same installer without modifications. You simply put a new CAB file on your homepage and your are done.
Additionally this method of uninstallation is cleaner than all commercial Uninstallers. Because these only uninstall the files which they themself have installed before. But what about all the files that your application has created during its lifetime? (Data files, Config files, downloaded files, Log files, etc) If you look into your "Documents and Settings" folder you will find a lot of data of programs which you have uninstalled since a long time! Also in your "Program Files" folder you will find a lot of files which have not been removed by Uninstallers. Also the Registry is full of garbage which remains because of badly programmed Uninstallers.
A separate Uninstaller does not know which files he has to remove. ONLY your application knows that. So Uninstall must happen in your application itself!
Elmü
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
thanks for clearing up the uninstall issue. I like the command line approach you created.
>Neither for InstallShield nor for the Visual Studio installer (which is quite primitive) you have the source code.
I do perfer projects with source code.
Even though i don't have a product that requires licensing i think this is where installshield makes sense. tying down a product to hardware configuration, or using a licensing server aka flexlm.
how about handling .net framework versions?
are you planning to make a code plex project of an installer system? "An Intelligent .NET Multilanguage Installer"
at the end of the day this all needs to be roled into the configuration management system
of: build - CruiseControl.NET test - nunit version - subversion, document - sandcastle deploy [should be here and fully automated with pre/post conditions]
since my current product is simple it'll be a good start to practice with your project. It would be nice for it to be on codeplex so that its versioned and code base can be maintained/updated/features added... ect
thanks!
-lm
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hello
> product that requires licensing i think this is where installshield makes sense
I dont recommend this! If a cracker once cracked a common licensing system he has access to ALL products which use this system. It is much more secure writing your own individual licensing system, which nobody else uses but you! For so many software exist cracks or even Keygenerators because they are badly protected. For a good licensing system you will have to invest a lot of time and need a lot of knowledge about how the crackers work and attack your protection. A licensing system in the installer is at the wrong place! It has to be deeply embedded into your program. .NET and Java will never be secure against crackers because they can easily be decompiled!
> how about handling .net framework versions?
I dont see any problem. If you copy your program files to "C:\Program Files\My Application" and create a shortcut to the Application.exe in startmenu you dont have to care about .NET versions. The EXE will automatically load the correct DLLs which it needs.
The installer obviously could check if the correct framework is installed. But this becomes a problem if the installer itself is written in .NET and NO framework is installed at all. Microsoft was so INCREDIBLE stupid that in this case the user does not receive an intelligent error message like "Please install .NET Framework XYZ!". Instead a stupid error message "Coree.dll not found" is displayed which the user will not understand!
> are you planning to make a code plex project of an installer system?
No I prefer REAL open source projects like Codeproject or Sourceforge. It is a lie if Microsoft opens a "Open Source" community! Microsoft's goal is to take control over the world and fight against open source projects like Linux. They steal the ideas of Linux and Mac and put them into their own products to make money with them. I will never support such a lie!
> It would be nice for it to be on codeplex so that its versioned and code base can be maintained/updated/features added... ect
If a new version of this installer comes, I will beg Codeproject to update the download files. Here in the discussion area I will put an advice that a new version is available. There is no need to use Codeplex.
> version - subversion,
I have no idea what you are writing about? This installer does not have to care about any version numbers of files. It compares the MD5 and always replaces existing files with the version in the CAB file.
Elmü
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
hey i'm learning quite a bit here thanks for answering my questions.
Last 2 questions.....
so basically you installers goal is just to copy files/uncompress cabs in c:\program files [a pretty xcopy with language support] ?
everything else should be handled by the users application. 0) checking framework dependence. 1) adding application to start menu 2) initial registery values 3) licensing system 4) uninstallation
>> But this becomes a problem if the installer itself is written in .NET and NO framework is installed at all. ooops so what is a work around?
an Autorun.exe c/c++ project that calls if framework required is installed: 1) "Setup.exe /Install" // copy/uncompress add to start menu if check box to run after install is checked then have the Autorun.exe load: 2) "c:\Program File\MyApplication.exe
>> No I prefer REAL open source projects like Codeproject or Sourceforge. lol true... codeplex svnbridge blows also
>> version - subversion, >> I have no idea what you are writing about?
i'm talking about continuous integration http://martinfowler.com/articles/continuousIntegration.html
these steps should be fully automated: build - CruiseControl.NET test - nunit version - subversion, document - sandcastle deploy - your project.
I plan to add this project into our continuous integration step for deployment. Then the whole system is fully automated. As i release software I want all my installers to model my template...the same look and feel.
sorry for not making that clear in my last post.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hello
> ooops so what is a work around?
There is no workaround possible in .NET. If there is at least ANY framework installed the installer will run and can check for a specific framework version if this is required.
If no Framework is installed at all you have 2 choices:
- On your homepage, where the user downloads the installer, you put a fat red hint:
"To run this application you must install .NET framewok XYZ." I think this is enough. Java users have the same problem. And if the user is not too stupid he will read that.
- The more elegant but more complicated solution: You write a little starter EXE in C++ which does noting else than checking the framework and then executing the .NET Installer Exe which you can rename as for example "Installer.dat" in the same folder to avoid that the user executes it directly.
- In the future this will not be a topic anymore because Vista comes with a framework pre installed.
_____________
What you write about continuous integration etc.. exceeds my intentions. I wrote an installer for my needs and put the sourcecode on Codeproject. If you need more funtionality you are free to add it.
Whatever you will do with this project: You will safe thousands of hours of coding effort, which I invested for solely writing the complex CabLib.Dll - not even talking about the installer!
Elmü
|
| Sign In·View Thread·PermaLink | 1.00/5 |
|
|
|
 |
|
 |
This is great! Great job on the muli-lingual xml file.
I'm curious why you don't specify an encoding in the xml file itself? I would think a unicode encoding would be best, for languages such as chinese, arabic, russian, etc to be encoded properly.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hello
The XML file IS already Unicode. It already allows russian and chinese characters. Obviously you must edit the file in a Unicode editor (e.g. Wordpad) and save it as Unicode.
If you add the following before the first line in Translation.xml:
="1.0" ="UTF-16" the file will be saved in the correct format even after editing it with Visual Studio.
Elmü
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
If you look at another articles, you'll notice that 1's and 5's almost always outnumber other ratings. In this case, 1 means 'I can't understand what's this all about'. Don't worry about those
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Nice. Why in the world you've got a 4.22 rating with 6 votes in so far I've got no idea. Who is the feakin' idiot!? Did this scumbag actually have enough time to download and properly evaluate this to arrive at a low score? A 2? A freakin' 2? Even the 4 I can't understand, but a 2?!!! 
So, I did my part to help compensate. Sorry I couldn't vote a 6.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Yes, who the hell is tht freak to stick 2 to this gr8 1.
You have my 5!
Absolute 5..
Ruchit S. http://ruchitsurati.net
******************************************
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
Hello
I have absolutely no idea what you are talking about ??
The installer USES Multithreading! For example the extraction takes place in an extra thread.
If you already would have tried the program before posting this you would have noted that if you click "Cancel" in the GUI thread, the extraction thread will immediately stop. This is impossible without Multithreading!
> will be suitable for extra-large program
I have no idea what you are talking about. Extra large ??? If you talk about the restriction to 2 Gigabyte the reason is that that Microsoft's Cabinet DLL internally works with integer variables. There is no way to change this! I have never seen an installer which installes more than 2 Gigabyte. But obviously it would be no problem to realize this with multiple CAB files!
> i hope that improving will be continued.
There is nothing to improve. All the work is done. The only thing to improve is that you study the code before posting a comment here and giving a bad note to something you did not understand.
Elmü
|
| Sign In·View Thread·PermaLink | 3.71/5 |
|
|
|
 |
|
|