|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionUpdating an application deployed with Windows Installer can be a time-consuming task if the application itself is distributed over many clients in a local network and if updates are frequent. I've written this simple function that automatically detects a new version of the application and installs it transparently, without user intervention. The only requirement is that the installation file (.msi) of the application has to be placed in a predetermined network folder where every client can access and check it. How it worksThe application's
The installation file is considered newer if its file date is at least two minutes greater than the executable's (.exe) file date (crude method, but effective). Because the application can't uninstall itself while it's running, it quits itself and calls a batch file to do the uninstall/install work. This batch file is generated directly by the program and put in a temporary folder. It looks like this: @echo off
ping localhost -n 2
C:\WINDOWS\system32\msiexec.exe /x {67BC5B51-1534-4C68-86C4-C74F4469C2BA} /qr
C:\WINDOWS\system32\msiexec.exe /i "Z:\setup\MyAppSetup.msi" /qr
cd "C:\Program Files\Myapp"
start "" "C:\Program Files\Myapp\MyApp.exe"
The ping command at line 2 is used to add a small delay before the uninstall, just to make sure that the calling application has terminated. ping is used because there is no standard Windows command for introducing a delay (e.g., a sleep command). At line 3, the old application in uninstalled using Windows Installer (/x switch). The /qr switch minimizes the user interface. At line 4, the new version of the application is installed. In lines 5 and 6, the application is launched again, providing the same working folder and the same command line parameters (if any). The start command is used to make the batch file continue its execution without waiting for the application to complete. Using the codeAll the work is done in a single function called static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
// add the following line to your main
if(CheckApplicationUpdate()) return; // update is needed, quit
Application.Run(new Form1());
}
The static bool CheckApplicationUpdate()
{
string InstallFile = "Z:\\setup_folder\\MyApp.msi";
string BatName = "c:\\windows\\temp\\update.bat";
string ProductCode = "{67BC5B51-1534-4C68-86C4-C74F4469C2BA}";
The whole function: static bool CheckApplicationUpdate()
{
// location of setup file
string InstallFile = "Z:\\setup_folder\\MyApplication.msi";
// name of the .bat file that does the uninstall/install
string BatName = "c:\\windows\\temp\\update.bat";
// product code of the application
string ProductCode = "{67BC5B51-1534-4C68-86C4-C74F4469C2BA}";
// if install file is not available skip the whole process
if(!File.Exists(InstallFile))
return false;
// calculates the time difference betwenn install package and executable
DateTime EXE_Stamp = Directory.GetLastWriteTime(Application.ExecutablePath);
DateTime MSI_Stamp = Directory.GetLastWriteTime(InstallFile);
TimeSpan diff = MSI_Stamp - EXE_Stamp;
// if installable is newer than 2 minutes, does the new install
if(diff.Minutes > 2)
{
string msg = "A new version of "+Application.ProductName+
" is available.\r\n\r\nClick OK to install it.";
MessageBox.Show(msg,"Updates available",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
// prepares the batch file
string BatFile = "";
string old_dir = Directory.GetCurrentDirectory();
BatFile += "@echo off\r\n";
BatFile += "ping localhost -n 2\r\n";
BatFile += "C:\\WINDOWS\\system32\\msiexec.exe /x "+
ProductCode+" /qr \r\n";
BatFile += "C:\\WINDOWS\\system32\\msiexec.exe /i \""+
InstallFile+"\" /qr\r\n";
BatFile += "cd \""+old_dir+"\"\r\n";
BatFile += "start \"\" "+
Environment.CommandLine+"\r\n";
StreamWriter sw = new StreamWriter(BatName);
sw.Write(BatFile);
sw.Close();
// executes the batch file
System.Diagnostics.ProcessStartInfo psi =
new System.Diagnostics.ProcessStartInfo();
psi.FileName = BatName;
psi.Arguments = "";
psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo = psi;
p.Start();
return true;
}
return false;
}
Points of interestThis workaround is far from being elegant, and it is rather raw. But, it proved to be effective because it saved me lot of time when updating client computers, because I do frequent updates. Now, all I do is put the install file in the folder and forget about updating. History
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||