May 29, 2007
Auto Updating Delphi Programs
I have the need to deploy a program that can update itself. I came up with a rather simple strategy. When the program starts it downloads a file from the web, which contains the version number of the latest edition (this file is maintained manually, I though about extracting the version number but the site is deployed on Linux and it needs to be very fast in case many users download the program). If the number there matches the internal version (extracted from the version information), that's OK. If not, I suggest the user to download the new version.
If the user agrees, I get the new version, save it as s different filename, run an "updater" application (as the program executable file is locked while the program is running) and terminate the current program (remember this is before the program created its main form):
if MessageDlg (
'A new version of YYY is available. '...
mtConfirmation, mbYesNo, 0) = idYes then
begin
// download new version
filestream := TFileStream.Create (Application.ExeName + '_update', fmCreate);
Http.Get('http://www.xmltypist.com/download/YYY.exe', filestream);
filestream.Free;
WinExec ('UpdateYYY.exe', 0);
Application.ShowMainForm := False;
Application.Terminate;
end;
The UpdateYYY program is a non visual program that waits a little time (for the main program to actually terminate), copies the current executable to a backup file, moves the _update version in place, and executes the new main program. There is a little extra code I'm adding for to comply with Vista protection, but more or less it works.
Now I know I have to update this strategy a little, as I might need to update other files like DLLs that are statically bound, so again they can be replaced only by stopping the program. I though about using the installer (InstallAware in particular) to manage the updates, but overall I'd rather use a manual approach as depicted above.
How to you mange automatic updates of Delphi programs? Any suggestions or ideas? Do you know of a better approach? I'm all ears... and will soon let you know about this "soon-to-be-free-for-all" program I resumed working on...
21 Comments
Auto Updating Delphi Programs
We went with the same strategy, although we don't dail out over the internet, but query a local server for updates (because our product suite runs in a contained environment). We has some trouble with Vista's UAC, but solved that by letting the updater execute itself with elevated rights, this way you keep the primary token, which helps somehow (I forgot what it meant actually).Comment by Patrick van Logchem [http://www.every-angle.com] on May 29, 09:14
Auto Updating Delphi Programs
We use a pre-loader program. Users start this program,
and as soon as it discovers that a new version is
available, it will update the main program before
executing it. This pre-loader also checks and updates
some dll's and templates in the users profile.
Also, a log is written of all users that have updated,
just so we can check. We have an option to force a
specific user to re-install an update in case the
program gets corrupted ('the program' being an Access
database in this case, the pre-loader is written in
Delphi).
Comment by Birger Jansen
[http://www.cnoc.nl]
on May 29, 09:32
Auto Updating Delphi Programs
How would you handle updating an exe in an environment such as a Terminal Server where there are multiple users all running the same exe? One user might say OK, but what about the other users who are still running the application? Cheers.Comment by Greg on May 29, 09:37
Auto Updating Delphi Programs
It would be better, imho, if you created a custom MSBuild action incrementing the version number appropriately and then FTPing the new file on the Linux server. This sounds like a better approach to me. AndrewComment by Andrea Raimondi [http://www.andrearaimondi.net] on May 29, 10:50
Auto Updating Delphi Programs
I was working on similar solution. For updating I use a zipped package that actually contains the little application to perform the update it self. So when new update is found it downloads it, unpacks it, and executes the updater placed in the package. This way I can perform more operations in the updater.Comment by Petr Matejka on May 29, 10:51
Auto Updating Delphi Programs
You dont need to execute an external program to update the current exe file. You can rename a running program, and that way "override" the exe file name. (The same with dll's) And if you have updated the exe file, you just restart the program. (Execfile on the exe file and terminate the current running program right after that)Comment by Kim Friis on May 29, 10:59
Auto Updating Delphi Programs
Hi Marco, Where can we find all that code you promised us in the past blogposts, is there a specialized website?Comment by Ilse on May 29, 11:04
Auto Updating Delphi Programs
If your need to limit the download you could think of using a patch system. xdelta(http://xdelta.org/) can create patches and patch them back. I was thinking of implementing a patch system using this for an online update system.Comment by Luc Neville on May 29, 11:20
Auto Updating Delphi Programs
You don't need to run an updater application. You can RENAME a running application to another name and then save the new version, like this: EXE:=ParamStr(0); BAK:=ChangeFileExt(EXE,'.BAK'); IF FileExists(BAK) THEN DeleteFile(BAK); <If Update Available and ready for download> RenameFile(EXE,BAK); <Save downloaded file as EXE> <Execute EXE> ExitProcess(0) <End> That's what I use in my self-updating programs. This way you only need ONE file (the .EXE file) and no need for installation programs or other such nonsense :-).Comment by Keld R. Hansen [http://www.heartware.dk] on May 29, 11:52
Auto Updating Delphi Programs
Hi Marco,
Here is my strategy, very similar to yours:
1. Main application download updates.
2. Optionally, updater program can be downloaded too,
so after update it can be wiped. This leaves me an
option to update the updater itself more easy. This of
course is option and can be used or not and didn't
change the main course of updating process.
3. When download is finished all main application do is:
ShellExecute(Handle, 'open', PChar(
[UpdaterFullFileName] ), nil, nil, SW_SHOWNORMAL);
MainForm.Close;
4. the first thing that updater do is to check is main
application is closed:
procedure CloseMainApp;
var
ProcessHandle:THandle;
WinHwnd:HWND;
ProcessID, ExitCode:Integer;
begin
ProcessID := 0;
ExitCode := 0;
WinHwnd := FindWindow(nil,
'[CaptionOfMainApplicationWindow]');
// Or use next line of code. I found so issues with
// it so I prefer the previous one
//WinHwnd :=
FindWindow('[MainApplicationClassName]', nil);
if not (IsWindow(WinHwnd)) then
Exit;
GetWindowThreadProcessID(WinHwnd, @ProcessID);
ProcessHandle := OpenProcess(PROCESS_CREATE_THREAD
or PROCESS_VM_OPERATION
or PROCESS_VM_WRITE or PROCESS_VM_READ or
PROCESS_TERMINATE, False, ProcessID);
if (ProcessHandle > 0) then
begin
GetExitCodeProcess(ProcessHandle, DWORD(ExitCode));
TerminateProcess(ProcessHandle, ExitCode);
CloseHandle(ProcessHandle);
end;
end;
5. Do the updates
6. ShellExecute(Handle, 'open',
PChar([MainApplicationFullFileName), nil, nil, SW_SHOW)
That's it.
procedure CloseMainApp makes sure that main
application is closed. This also works if application
is using some DLL(s) part of it. Windows will count
them as no longer in use, so all overwrites are working.
I'm using this procedure in application with 6
additional DLLs and it proves working over a year and
a half.
I hope this will help you and other people.
Comment by Georgi Hadzhigeorgiev on May 29, 12:24
Auto Updating Delphi Programs
I use Inno Setup (I highly recommend it!) with the restartreplace flag for copying the files. So if any files are in use (locked) they get replaced on restart.Comment by Ajasja Ljubetič on May 29, 13:36
Auto Updating Delphi Programs
We use a similar setup to deploy our application, except that the initial downloaded file is an xml file with all the metadata we need to decide to update the file. Also, all this download-and-compare logic before even showing the "New update available" dialog is done by the installer itself, in invisible mode. If a new version is available, it downloads all the necessary files and then warns the user that a new version is available and has been downloaded, requests permission to install (Firefox-style). However, this is complicated to maintain (the xml setup is done by hand) and we're thinking about moving to a big-fat-file with everything in it, with a single version number for the whole package. Yes, there is some bandwidth wastage, but our app needs wideband, anyway (video-chat).Comment by Gustavo Carvalho [http://messenger.sapo.pt] on May 29, 13:48
Auto Updating Delphi Programs
I don't work with Delphi anymore for a long time, but once I used the following a approach: 1. Have an "updater" application, just like that you described. 2. When the main application detects there are some updates it launches the updater, passes its process handle and the list of files to be updated and exits. 3. The updater waits on the process handle of the main application. When the wait completes it can replace all executables and dlls that were previously locked. You'll need to use the following Windows APIs: - WaitForSingleObject: using this the updater doesn't need to test for the main application in a loop. It'll know immediately when it terminates. - DuplicateHandle: the main application needs to duplicate its own process handle for SYNCHRONIZE access in order to allow another process to wait for it. - CreateProcess: the updater needs to be created with CreateProcess because the process handle of the newly created process is required by DuplicateHandle. The major issue is the need of interprocess synchronization to pass the duplicated handle. You can't pass the handle in the command line because it'll be available only after the process starts. A named pipe can make things easier, though. To pass the list of updates you may use the command line, a temporary file, interprocess synchronization etc.Comment by Romulo A. Ceccon [http://insanebits.blogspot.com/] on May 29, 15:39
Auto Updating Delphi Programs
DIY approaches are doomed to fail as soon as users understand that allowing everything to write into "Program files" is bad - as much as having executables file in "free for all" folders. Approaches that try to replace a file in folders on which user have no permission to write can't work in properly configured environments - unless the program or user privileges are elevated. We prefer to rely on Windows Installer and .msi/.msp files to deploy upgrades - they get "registered" within Add/Remove apps too. We used a service or another executable to detect upgrades, download them and then launch the installer, that took care of detecting running applications and locked shared files, now we're using our install tool update feature.Comment by Luigi D. Sandon on May 29, 16:01
Auto Updating Delphi Programs
I wrote an article for the UK Bug magazine several years ago that used a similar strategy. Using either HTTP or custom protocol it would contact server, request a new file and download it (supported multiple files). The difference with yours is that I replaced the executable file itself (simulated) without having a helper app as such. I'd get the new file with a _ (as you do) in front of it. Then I would terminate myself and launch the new process (the one with the _). On the new instance, I would check to see if the application name has _ in it. If it did, I would then copy it to the "real" one so that on next launch (when clicking on shortcuts), everything again would work. Have been using the same thing in many applications for many years. Works without a glitch.Comment by Hadi Hariri [http://www.hadihariri.com] on May 29, 17:14
Auto Updating Delphi Programs
Why don't use dynamic packages. You can divid functional modules into packages, and then upload those packages to backend server. The only thing that you need to deploy is a tiny application launcher, the size would be less then 500KB, the launcher takes the role to download the package loader and required runtime packages from the backend server, and then launch the package loader. Based on the user's authority, the package loader build the functional menu dynamically. When the user click a function menu, the loader will check and download the linked package to local machine, and then load the package. I just made a flash demo to show the application framework that I'm using, http://www.wiseone.hk/northwind.htmComment by YC Wong on May 29, 18:40
Auto Updating Delphi Programs
We have several big systems that run in public institutions (government offices, justice departments, congress, etc.), with many users (more than 300 in every institution). 4 years ago we made a custom software updating system to install and update all our systems from one or more web servers: 1. A service application on every WinNT (Win2K, WinXP) client (on Win95/Win98 we made a small application that runs twice a day) checks the local version of every registered software system (registered in our service) 2. The local service client connects to the web server via HTTP and checks if there is any update for all the registered applications on the client platform (the updates are labeled for every Windows version). If there is no update, then the process ends. 3. If there is any update, the server responds with the list of new/updated files. The client service backups every file on that list. 4. The client downloads the file packet and installs every new/updated file. If there is any file in use, the system tries the rename trick (it may fail on Win95/98) and installs the new one. 5. The client service updates the registry with the updated version information and removes the backup files. The system does a lot more (include auto executable files, update files only if they are present on the client seat, etc.) and even updates itself. It has worked like a charm on these 4 years. In fact it has been the only one system that didn't failed the first time we made demo of it.Comment by Arturo Martinez [http://www.sigob.org] on May 29, 19:20
Auto Updating Delphi Programs
Thanks for all the feedback. Some of the solutions are out of reach for this specific project, but hey sound interesting in general. I'll work on a better solution for my program and blog about the topic again, hopefully quite soon.Comment by Marco Cantù [http://www.marcocantu.com] on May 29, 23:52
Auto Updating Delphi Programs
You should have a look at MakeUpdate, it helped me to make an auto-update system quickly by adding an HTTP version check + download to it. http://sourceforge.net/projects/makeupdate/ RegardsComment by Denis A. [http://pascalmock.sf.net] on May 30, 00:57
Auto Updating Delphi Programs
Also, you can't remove EXE file of started program (without tricks), but you can rename it and on start check the presence of some predefined file and delete it. By this way you can not need in "updater" program, all what you doing is: at start: - check presence of the mutex with some name - if it here, delay sometime (f.e. 10 secs) - if mutex not free, kill the instance - if it not here, create mutex and lock it - check the some file presence, and if it's here delete it (f.e. *.EXE.OLD) at update step: - get new version - if loaded version is older: rename the EXE file of the program; exec instance of new version and stop this instance.Comment by Leonid Koninin on June 6, 23:33
Post Your Comment
Click here for posting your feedback to this blog.
There are currently 0 pending (unapproved) messages.



Auto Updating Delphi Programs
Comment by Jean-Fabien Connault [http://perso.orange.fr/cycocrew/delphi/] on May 29, 09:01