Delphi 2007 Handbook




Essential Pascal




social web book








May 29, 2007

Auto Updating Delphi Programs

I have the need to deploy a program that can update itself. Do you know of a better approach?

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 

Marco,

You can check the TJFCAppUpdate component posted at:
http://perso.orange.fr/cycocrew/delphi/components.html

Any feedback, let me know.

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

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.

Andrew
Comment 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.htm
Comment 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/

Regards

Comment 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.