Fog Creek Software
Discussion Board




Replacing an EXE on the fly...

I'm curious as to Joel's technique for "how to replace an EXE on the fly" found in:

http://www.joelonsoftware.com/articles/fog0000000066.html

He says this in the context of executing an EXE, having it check a website for a newer version, downloading the latest version and replacing the EXE.

Is he talking about using a separate EXE to do this or using the actual EXE that will be replaced (updated)?

GuyIncognito
Thursday, June 10, 2004

I use a small launcher EXE file to check for latest and retrieve the new version of the main EXE before launching it.  It is pretty simple.

dover
Thursday, June 10, 2004

You can do it both ways. The trick is you have to stop the main exe to replace it. You are going to need somekind of separate app / script to do that.

DJ
Thursday, June 10, 2004

This is my (.NET) setup:

1) Stub executable checks for existence of patch program.  If it finds it, it runs it, using AppDomain.CreateDomain, and then calls AppDomain.UnloadDomain when it's done.

2) Patch program replaces all application files (except the stub exe) with newer versions that have been pre-downloaded and placed in an "Updates" subdirectory.

3) Stub executable deletes Updates directory if it exists (including patch program), then runs the main program executable (again with AppDomain.CreateDomain).

4) Main app runs and checks for updates on a background thread.  If it finds any, it downloads them to the Updates subdirectory (including the patch program), then prompts the user to restart the program at their convenience.

Since the stub is a standalone executable and isn't linked to any of the other program files, they can be safely replaced before the main app is launched.  The only file that can't be replaced, obviously, is the stub, so it should contain as little logic as possible.  Mine is about 55 lines of code including imports.

Many people may prefer using the Microsoft .NET Application Updater block, since it can handle a lot of the checking, downloading, and patching logic for you.  And that way you get a stub that is pre-built, so you know you'll never have to change it (which would require users to reinstall).

Joe
Thursday, June 10, 2004

OK,
Thanks.
I thought he maybe knew of some magical way to replace a running EXE.

GuyIncognito
Thursday, June 10, 2004

For updates I'm currently using login scripts for a set of users in a user group.  If they don't have the script in their profile or they aren't a member of the group then they don't get updated.

Otherwise it checks a directory on the server (could equally be a URL) and  copies the exe across.

The advantage of this is that you don't have to stop the exe, it gets updated before its started.  If you need someone to update in a hurry, then you have them logout and log back in, they don't need to know where to get it from.

There is one drawback to this, if the user running the app doesn't have rights to write to the application directory (in Program files say), then the whole thing falls down.  But it does in all the alternative methods as well.

Simon Lucy
Thursday, June 10, 2004

Good point on the access rights... my installer uses XCACLS to set the Program Files folder that my application resides in to Full Access for Everyone.  It works just fine for what we need.

dover
Thursday, June 10, 2004

Can you replace a running .exe ? I don't think you can, which is why you have to re-boot after downloading patches, etc.

If you *can* do it, I'd be interested to know how.

As an aside, in the old days, Joel would probably have jumped in on this thread and provided some insight. Still sulking I guess. Oh well, whatever. End of aside.

Steve Jones (UK)
Friday, June 11, 2004

http://support.microsoft.com/?kbid=228930

.
Friday, June 11, 2004

Silly programmers, Windows is for kids.

Without trying it, I'd expect that renaming the executable and creating a new executable of the same name might work in Win32, leaving the new executable to delete the old one when started.

On Linux you can just unlink (delete) your executable from the directory and create a new one, you're only forbidden from trying to write onto the actual running executable, which would be a nonsensical operation in most cases anyway. Everything is reference counted, so the current version will exist on disk until it finishes running, and then be gone forever.

[If the sysadmin needs to see what was in this executable, which is no longer visible in the disk filesystem, he can examine the running copy which is referenced in the process table and therefore reflected in the virtual proc filesystem]

Similarly Linux lets you delete an open file, the reference counting takes care of it. You can obtain temporary storage, counted against your disk quota but not accessible through the filesystem by opening and then deleting a file while keeping the handle. I don't think there's a portable way to do this unfortunately.

Nick Lamb
Friday, June 11, 2004

> you're only forbidden from trying to write onto the actual
> running executable, which would be a nonsensical
> operation in most cases anyway

That's the problem...people want to be able to update the application from within itself -- which would require replacing the exe while it's running.  Renaming the exe won't work either, since Windows locks files while they are in use.

The trick w/ the login scripts looks pretty good.  Much simpler than an in-app solution.  Too bad my users aren't part of my Windows domain :(

Joe
Friday, June 11, 2004

You can use the MoveFileEx API with the MOVEFILE_DELAY_UNTIL_REBOOT flag (which, as Steve says, requires a reboot).

Christopher Wells
Friday, June 11, 2004

Nick Lamb wrote [Similarly Linux lets you delete an open file, the reference counting takes care of it.]

It is not a Linux specific feature. As far as I know, FreeBSD and MacOS X behave similarly. I can even say that most UNIX systems have this feature since ages.

Linux is a good OS, but Linus hasn't invented all the cool things it has.

GinG
Saturday, June 12, 2004

"That's the problem...people want to be able to update the application from within itself -- which would require replacing the exe while it's running.  Renaming the exe won't work either, since Windows locks files while they are in use."

I see you didn't get it, and I suspect that the people who designed Windows this way (well before any of the smart people behind NT came along) didn't get it either.

In Unix a FILE is not synonymous with a FILENAME. It's forbidden for a program to overwrite itself by opening the relevant FILENAME, fopen(argv[0], "w") and scribbling away because the meaning of that would be to actually change the running code in memory, which should bring a shudder to any sane engineer.

However it is not only possible but routine for a program to unlink (delete) the FILENAME and create a new FILE with the SAME FILENAME which contains a newer version of that same program. The running program FILE is still there, on disk, but it no longer has a name, and so it will be deleted when there are no further references to it in memory.

It's also, as I hinted, quite possible for the running program to replace itself with freshly started copy of the new version, leaving any child processes (but not threads) that used the same program image running peacefully. In this way a server process can update itself several times with improved or bugfixed versions while users with an open session to the server continue to use the older version until they disconnect.

The poster who said that it was quite normal on any Unix to permit deleting open files is correct, I was thinking of directories where Linux behaviour does differ from the Unix norm.

Nick Lamb
Thursday, June 17, 2004

I recently fought this same problem in Windows XP Embedded, further made tricky by the fact that you must  issue an EWF call to commit the memory (since the machine is diskless).  A nice set of features the people behind windows did provide us are:

HKCU\Software\Microsoft\Windows\CurrentVersion\RunOnce

and

HKCU\Software\Microsoft\Windows\CurrentVersion\Run

Their function is prettry clear. 

I do updates from within my app with these.  After my app downloads its files (using a temp name for the main exe) I delete the Run reg key, then I write to the RunOnce (to a launcher exe which simply renames the file and sets the reg keys back).  With the commit issue I actually gain the bonus of a full rollback if install fails along the way.  You could also get this by waiting to flush your reg keys until after the update went well. 

Another gem I found is AdjustTokenPrivileges which allows me to grant my app the privileges it needs to perform a restart (another oddity of XPe being that it seems I need a clean reboot after commit for it to REALLY commit). 

D Nova
Thursday, June 17, 2004

*  Recent Topics

*  Fog Creek Home