TCynthesisAppUpdate


 The TCynthesisAppUpdate component provides an application with the capability of automatically checking the web for updates to your application, and automatically downloading and installing the update if one is found. This page provides more detail on the component.

Download TCynthesisAppUpdate Now! (430K ZIP File)

Download ZipMaster Now! (500K ZIP File; used by the TCynthesisAppUpdate component)
Note: I have made some small changes to the ZipMstr.pas file - you should use the one that comes with the AppUpdate component, or make the equivalent changes in the ZipMstr.pas source in the ZIP file above.

 


Date: 12/1/1999
Version: 2.1.0.0
Author: James Waletzky
E-Mail:

cynthesis@home.com


Contents


Requirements

History

Coming real soon: Delphi 5 support!

Version: Notes:

2.1.0.0

  • Added: Resource DLLs for German and Italian support (in addition to currently supported English).
  • Added: the component is now responsible for unzipping the UPDATE.EXE file from the downloaded update before running the UPDATE.EXE helper. This allows the update of the helper application (and language resource DLLs) in the same update operation.
  • Added: properties to select a resource DLL that contains foreign language translations of all the strings used by the component and the update helper application. Note that the Language property from version 2.0.0.0 is now deprecated.
  • Added: FTP mode now accepts FTP URLs pointing to the update to be downloaded in the update information file.
  • Added: ASSERTs to code to ensure that Initialize is called before any of the other public methods.
  • Changed: Using the update mode umAutoNoUI will result in the update helper application (UPDATE.EXE) being run invisibly. The updated application will launch automatically as if the user had clicked the 'Run' button.
  • Fixed: periodic freeze when the URL to the update information file or update file is redirected due to a 404 error.
  • Fixed: problem download update in FTP mode if update in different directory than update information file.
  • Fixed: temporary files being left in the user's TEMP directory after multiple "check for update" operations.
  • Fixed: UnzDLL.DLL no longer needs to be in the Windows system directory to work. Simply install it into the same directory as your application's main executable.

2.0.0.0

  • Added: FTP, LANWAN, and hard disk retrieval of updates
  • Added: auto-update mode with UI
  • Added: auto-update mode without UI
  • Added: support for proxy servers
  • Added: support for user name and password
  • Added: version number need not be set (retrieved from EXE of application to be updated)
  • Added: smart (can use wildcards) and case-sensitive version compare
  • Added: improved code for localization
  • Added: use ZipMaster 1.52 for international support
  • Fixed: update helper application preserves command-line arguments from original program when launching after update
  • Fixed: including update information files with spaces in pathnames causing problems
  • Fixed: other misc. bug fixes

1.0.0.0

  • First public release

0.99.0.0

  • First BETA release

Known Problems (as of Version 2.1.0.0)

File Contents

What is the TCynthesisAppUpdate Component?

The TCynthesisAppUpdate component provides the functionality to an application of automatically checking for new versions when on-line (via a HTTP web connection, FTP connection, or network connection), and downloading and installing application updates. The component can handle the entire update process using its own user interface, or you can capture a few simple events and handle the update process manually. Dropping the component on your application's main form, setting some properties, creating a simple INI file, and placing both the INI file and the zipped update on a web server, FTP server, or network drive are all that's required for your application to update itself!

Other features include:

Limitations of Use

The TCynthesisAppUpdate component (and its various pieces) is free for non-commercial use . All I ask is that you send me an e-mail telling me that you are using the component. For use in a commercial application , please contact me (James Waletzky) via e-mail at cynthesis@home.com for licensing details. Cynthesis software has the right to charge a fee for use of this component in a commercial application. Please contact me for commercial licensing and I will forward the license agreement to you via e-mail.

The source code for this component is available from Cynthesis Software for a suggested cost of $10 (US Funds). Higher denominations are encouraged, however, to fund future development. The source code may be modified for your use but may not be redistributed. You may include the source code in any non-commercial applications that you develop without royalty. To purchase the source code please remit a cheque or money order payable to Cynthesis Software Inc. to the following address:

Cynthesis Software Inc.
408 - 260 Newport Drive
Port Moody, BC
Canada
V3H 5C6

If you decide to make use of this component, I would like to hear from you as to your comments about the component, or suggestions for improvement.

Usage

  1. Install the ZipMaster component by adding the ZipMstr.pas file to a package of your choice.
  2. Install the TCynthesisAppUpdate into a package of your choice such that it is available on the component palette. If you have trouble, try this: open or create a new package in the IDE. Right-click on the Contains folder in the package tree view and select "Add...". Add the DCU file to the package. Compile the package. Right-click the Contains folder once again and click Install.
  3. Drop the component on your application's main form.
  4. Decide what online mode (HTTP, FTP or LANWAN) you want the component to use.
  5. Determine whether you want the component to handle the entire update or you want to do it manually via events (set the UpdateMode property).
  6. Fill in the current version of the product, or ensure that the version information in the project settings is up-to-date.
  7. Fill in the URL (for HTTP), FTP host name, or network location that will point to the update information INI file, and any other properties you desire..
  8. [Optional] Fill in the ResourceDLL property to point to the DLL that contains your string resources (path information not required if the resource DLL is in the same directory as your application executable). If you are distributing your application and want to use English messages, this field may be left blank.
  9. Distribute your application (don't forget to include UPDATE.EXE in your distribution package in the -same directory- as your application executable). You should also install UnzDLL.DLL in the Windows directory.
  10. When it comes time for an update to your application, create an INI file as described below.
  11. Prepare the update information INI file.
  12. Upload the INI file and the update file to a web server as indiciated by the UpdateInfoURL property.

About the Sample Application

The sample application illustrates how to use the TCynthesisAppUpdate component in a couple of different ways. It consists of two tabs - one that allows you to update the sample application itself using one of the specified protocols, and another tab to update this component package. The first tab takes a modal dialog approach and informs the user when the update is available, asks to download, etc. via dialog boxes. The second tab updates the component package via a changing button state (run it to see what I mean). When an update is available you will be presented with an edit box where you fill in the path where your component files reside. The update will unzip the new version over top. For full details on how this works, check out the source. I have tried to comment it fairly thoroughly.

Note: The sample application has not been translated to languages other than English. Therefore, if you set the ResourceDLL property on any of the AppUpdate components on the sample form, some messages will remain in English.

Update Info INI File Format

The Update Info INI File describes the most recent application update that is sitting on the web server. The TCynthesisAppUpdate component first downloads this INI file to determine whether an update is necessary before downloading the update itself. You will need to create an INI file and upload it to the location specified in the UpdateInfoURL property of the component every time an update is available.

The format of the INI file is as follows (anything that appears in angle brackets <> should be replaced):

[UpdateInfo]

Name Value

Name

[string] any string that describes the application (usually just the name of the application).

Version

[string] version number of the update; usually in the following format: w.x.y.z

InstallAction

[enumeration] see the InstallAction property on the component for details.

UpdateURL

[string] Location of the zip or executable file that represents the update.

  • When the OnlineMode property of the component is set to olHTTP, this must be a URL (example: http://www.npsnet.com/waletzky/samples/sampleappupdate.zip) URL to the zip or executable file that represents the update.
  • When OnlineMode is olFTP the UpdateURL must be in a special format of host/path/filename or be a complete FTP URL. (example: ftp.npsnet.com/waletzky/samples/appupdate.zip or ftp://ftp.npsnet.com/waletzky/samples/appupdate.zip )
  • When OnlineMode is olLANWAN this must be in one of two formats: standard Windows path format: d:\path\filename OR \\machine\sharename\path\filename (UNC Format) (examples: c:\waletzky\samples\appupdate.zip or \\waletzky\sharedir\samples\appupdate.zip ) 

Note: all lowercase is recommended for this value as well as the actual name of the file and directories on the server when OnlineMode is olFTP to avoid case sensitivity issues.

Details

[string] any text used to describe the update; could be an abbreviated list of changes. This is not used by the component other than to be made available to your event handlers via the property INIDetails.

SmartCompare

[boolean]Indicates the type of comparison that is performed when comparing version information.

  • When SmartCompare is False (default), the version strings are compared alphanumerically.
  • With SmartCompare True then at each segment of the version number (dot-delimited segments), comparison is done numerically if and only if that segment of both version numbers is comprised entirely of numeric digits. Also when SmartCompare is True you can use '*' as a segment wildcard in the INI variable CompatibleVersions (see below). Wildcards are NOT allowed in the INI variable "Version" or in the component property "CurrentVersion". (Any asterisk present in those two values is treated as a literal character.)

SmartCompare is especially useful when the component's CurrentVersion property is left blank to cause CurrentVersion to be extracted from the exe's embedded version number.

Examples: With SmartCompare True:

  • '2.22.4c' is newer than '2.5.4c' (because numerically, 22 > 5)
  • '2.2a.4c' is older than '2.20.4c (because alphanumerically, '22.2a' > '22.20')
  • '2.22.*' is SAME as '2.22.4c.3' (only when 2.22.* is from the compatibilty list)
  • '2.22.4*' is older than '2.22.4c' (because '4*' < '4c', '4*' is never a wildcard!)

With SmartCompare False:

  • '2.22.4c' is older than '2.5.4c' (because alphanumerically, '2.22' < '2.5')
  • '2.22.*' is older than '2.22.4c.3' (because '*' is less than '4')
  • '2.22.4*.#' is older than '2.22.4.#' (because '*' is less than '.')

Regardless of SmartCompare setting:

  • '2.2a.4c' is older than '2.5.4c'. (because '2a' < '5')
  • '2.22.blah' is newer than '2.22'

CaseSensitiveCompare

[boolean] The default value is False, no case sensitivity in version comparison. Applies to comparison of CompatibleVersions and Version INI variables with component property CurrentVersion.
CompatibleVersions

[string; comma-delimited] A list of versions (in the same format as the version field) that this update can be applied over top of. If the user has, say, version 1.0.0.0 of your application installed, the patch may not apply. You may only want to patch 2.0.0.0 clients. Any person with a 1.0.0.0 client will have to upgrade to 2.0.0.0 before applying the update.

If the SmartCompare INI variable is True, then you can use "wildcards" here. For example, CompatibleVersions=1.9.*,2.* would update all versions begining with '1.9.' or '2.'. Note that the '*' must be the only character of the segment in order to be considered a wildcard, and if it's not the last segment, then and trailing segments will be ignored. There is no wild card in '2.2*.3' or '2.*2.3'. Also, '2.*' is the same as '2.*.1'.

This INI variable is optional. If missing, it is assumed that any version is compatible with the update, if its version compares older than the update.  


Creating the Update ZIP File

When using the install action iaUseUpdate, you need to create a ZIP file containing the update and place that file on a web server for retrieval. This file should take on the same directory structure as your application. For example, if your directory structure looks like this:

MyApp (where your main executable is stored)
+ Samples
+ Help
+ Doc

then your update ZIP file should have the same structure so that you can place updated files directly over top of the currently installed versions. You may want to place a CHANGES.TXT file inside your update so that the user can view the release notes for the update some time after the update has been applied.

Localizing Message Strings

The AppUpdate component is easily localized to different languages. By default, the component has English messages linked into the component. If a different language is desired, the following actions must be performed:

  1. Create a new DLL that basically contains nothing but a resource file containing a string table.
    Open the AppUpdateDE.DLL in a resource editor (like the Visual C++ IDE) and check out the string table that resides within that DLL for reference. If you would like the source to the AppUpdateDE.DLL file, e-mail me .
  2. Open the AppUpdateMessages.RES file in a resource editor (to be used for comparison).
  3. In the new string table, perform a one-to-one translation of all of the strings listed in the string table in AppUpdateMessages.RES. Each translated string should have the same resource ID as in the AppUpdateMessages.RES file.
    For example, translate the string "Update progress", which has a string ID of 100, to the equivalent foreign-language string, and give it the same string ID of 100.
  4. Also copy the strings in the appropriate ZipMsgXX file into the new string table.
    For example, the german resource DLL AppUpdateDE.DLL contains within it the contents of the ZipMsgDE.RES file. You can get resource files for many different languages in the full version of the ZipMaster component, which you can download here.
  5. Build the DLL and include it with your application distribution. Name the file "AppUpdateXX.DLL", where "XX" is the two character country code.
    For example, AppUpdateDE.DLL is for German translations.
  6. Set the "ResourceDLL" property on the AppUpdate component that is contained within your form to the name of the DLL you just built.
  7. Build your application and you're done!

Shortcut: A shortcut to the above procedure would be to copy one of the sample resource DLLs included with the AppUpdate component (e.g. AppUpdateDE.DLL) to a new file. Open the DLL in a resource editor and replace the resources in the DLL with your own translations.

Note: This technique of localization even allows you to change languages dynamically at run-time simply by shipping the appropriate resource DLLs with your application and setting the ResourceFilename property on the component.

Note: Unfortunately, the strings that are defined within the HTTP component and FTP component that are used by the AppUpdate component are not localized. Therefore, some rarely seen error messages may in fact appear in English even though you have localized the component for a different language. I will do my best to find a better, cross-language, HTTP and FTP helper component in the near future.

Component Properties

PUBLISHED (Design-time/Run-time):
Property Type Description

CurrentVersion

string

The version of your application that is currently running. If this property is left blank, the component will attempt to extract the version number from the current running EXE file (which you supply in the Project/Options/Version Info tab, or is maintained by your version control system). An error is raised if version information cannot be found.

This version number is compared to the one listed in the update info INI file. If this version is older, (and if it is in the CompatibleVersions list, when this list is supplied) then the update process continues.

ResourceDLL

string

By default, the english-language strings associated with the component are linked into your application. If strings have been translated to another language and are present within some external DLL, this property should contain the filename (no path information) of the DLL that contains the string resources. The resource DLL file should be distributed in the same directory as your application executable.

See Localizing Message Strings for details.

OnlineMode

TCynthesisAppUpdate-OnlineModes

  • olHTTP - uses HTTP mode for file transfer from a URL
  • olFTP - uses FTP file transfer from an FTP host + path + filename 
  • olLANWAN - File transfer from d:\path\filename or \\machine\sharename\path\filename 

The value of this property affects the formatting requirements of the UpdateInfoURL property and of the INI file variable UpdateURL.

UpdateInfoURL

string

The URL that points to the update info INI file that you will create when an update is available e.g. http://www.npsnet.com/waletzky/samples/SampleAppUpdate.ini

ProxyServer

string

Name or IP address of the proxy server if the running application needs to access the target URL or FTP server via a proxy server. Note that if the user's ISP requires a proxy server specification and OnlineMode is olHTTP, there could be a problem with the running exe not "seeing" the most current INI file because of the proxy server only updating its contents occasionally (cache is out of sync). This could create the situation where you program an "instant fix", you put up a new version, call the user and say "it's there, download it", but the user's CheckForUpdate routine downloads the previous INI file from the proxy server, since the proxy server has not updated itself yet. If instant updates are a reality for you, FTP is recommended.

This property is ignored when OnlineMode is olLANWAN.

ProxyPort

integer

Number of the proxy port on the proxy server. This MUST be > 0 if the proxy server string is non-blank.

This property is ignored when OnlineMode is olLANWAN

UserName

string

Must be non-blank when OnlineMode olFTP and will be used by the FTP hosts specified both in the UpdateInfoURL property and in the UpdateURL INI variable. Logging into a public directory of a public FTP server usually requires the User ID "anonymous", whereas logging into a private directory of any FTP server will require a directory-specific User ID. Normally FTP user names are case sensitive.

UserName will also be used when non-blank and OnlineMode is olLANWAN and a UNC specification is given in the UpdateInfoURL property or in the UpdateURL INI variable, when making the connection to the //machine/sharename specified. In this case, UserPassword (see below) may or may not also be required.

UserPassword

string

Must be non-blank when OnlineMode olFTP and is used by the FTP hosts specified both in the UpdateInfoURL property and in the UpdateURL INI variable. In case of a public FTP server where "anonymous" is used for the UserName, the usual practice is to supply the user's email address for the password. An option that usually works with "anonymous" in the case where you need to hardcode a password is to use "guest@unknown" or "-". Normally FTP passwords are case sensitive.

UserPassword will also be used when non-blank and OnlineMode is olLANWAN and a UNC specification is given in the UpdateInfoURL property or in the UpdateURL INI variable, when making the connection to the //machine/sharename specified. In this case, UserName (see above) may or may not also be required.

UpdateMode

TCynthesisAppUpdate-Modes

  • If set to umAutoWithUI, the TCynthesisAppUpdate component will handle the entire update process using its own UI and dialog boxes. This includes checking for the update, prompting the user to install it, and installing it - all without intervention from your application. In this mode, if no OnDownloadProgress event handler is suppied, a default handler provides a progress bar during both downloads. In this mode, if no OnError event handler is supplied, any appropriate error messages are presented via a MessageDlg. In this mode if no OnNoUpdateAvailable event handler is supplied, a deafult one is supplied presenting a 'No Update Available' messagebox.
  • If set to umAutoNoUI, the same events will occur except no UI will appear. The update will occur without user intervention. As of version 2.1.0.0, the update helper application will run invisibly as well.
  • If set to mManual, you have to display the update UI by handling the various events that are thrown from the component.  
PUBLIC (Run-time):
Property Usage Type Description

DestDirectory

Run-time only (read/write)

string

Optionally set to indicate where the files in the update ZIP file should be unzipped to. If this property is left blank, the destination directory is the same directory in which your application executable resides.

UpdateFilename

Run-time only (read)

string

The name of the update ZIP file that was downloaded from the web server.

InstallAction

Run-time only (read/write)

TCynthesisAppUpdate-InstallActions

The various values are as follows:

  • iaNone: Don't do anything when told to install the application
  • iaUseUpdate: Use the update helper application when told to install the application. This implies that the update file on the web server is a ZIP file and the helper application will unzip it to the same destination directory as your application resides in keeping subdirectories intact.
  • iaRunExecutable: The update to be downloaded is an executable file. Instead of using the helper application to install the update, simply run the downloaded executable.

FileSize

Run-time only (read)

LongInt

The size of the file being downloaded during CheckForUpdate or DownloadUpdate. If value is zero, the filesize has not been calculated yet. (Could be used to abort if deemed by event handler to be too big for downloading, etc.)  

Component Methods

Method Signature Description
Initialize; Make sure that this method is called before using the component within an application. If you want to override any design-time values you assigned to the component properties, assign the override values prior to calling this method. For example, your application may prompt the user for UserName, UserPassword, ProxyServer, and ProxyPort.
CheckForUpdate: TCynthesisAppUpdateError;

Call this method to check the web, FTP, or LAN/WAN server for an update. Note that for mode umAutoWithUI and umAutoNoUI, you call only Initialize and then this method. A good place to call this method is when your application is initializing. Another possible spot is when the user chooses a menu item in your application like "Check For Updates".

Note that if you call CheckForUpdate and you are not on-line, the standard Windows dial-up networking dialog box will appear asking you to dial in to your Internet service provider. You may want to have your application check the on-line status and only call CheckForUpdate if you are on-line. If there is demand for this feature, I may add the check to the component itself.

DownloadUpdate: TCynthesisAppUpdateError;

Call this method once it has been determined that an update is available and the user has decided to apply it. This method should be called from the OnUpdateAvailable event handler in the case of a manual update. 

Note that the "auto" UpdateModes will call this method for you.

InstallUpdate: TCynthesisAppUpdateError;

Call this method once the update file has been successfully downloaded and the user wishes to apply the update. This method should be called from the OnDownloadComplete event handler in the case of a manual update. 

Calling InstallUpdate will trigger the update of the UPDATE.EXE helper application and resource DLL (if one is being used). The update of these files are necessary at this point as updating the helper application while it is running is not possible due to the files being loaded in memory.

Note that the "auto" UpdateModes will call this method for you.

CancelUpdate: TCynthesisAppUpdateError; Call this if for some reason you want to abort the update process once it has been started.

* For a definition of the TCynthesisAppUpdateError structure, see the file CynthesisAppUpdateTypes.pas

Component Events

Event Signature Description
OnUpdateAvailable(
Sender: TObject;
Version: String)

This event is fired by the update component when an update has been found. The Version string indicates the version of the update that was found on the web server. This event allows the application to prompt the user to download the update, or dismiss the update until some later time. You should call DownloadUpdate once it is determined that the update should be downloaded.

If you are using umAutoWithUI mode and you do not furnish this event handler, the component will automatically prompt to download the update or cancel. 

OnNoUpdateAvailable(
Sender: TObject)

This event is fired when it is determined that no update exists on the web server. This may be because either an update info file does not exist, or because the version on the web server is the same or earlier than the one currently installed. This type of event is required since the whole update checking sequence is asynchronous. If it was synchronous, you could simply wait for a result code from the CheckForUpdate method.

If you are using umAutoWithUI mode and have not supplied this event handler and no update is available, a messagebox 'No Update Available' will be presented to the user. 

OnDownloadProgress(
Sender: TObject;
Progress: Integer;
Msg: String)

This event is fired by the update component periodically to indicate the current progress and status of the update file download. The Progress parameter indicates a percentage complete, and the message is a status string that you may want to display in a status bar. This is a good place to update a progress bar based on the value, and display the message on a status bar.

If you are using umAutoWithUI mode and have not supplied this event, the component will present a progress window with progress text and a progress bar for both downloads (info file and update).

OnDownloadComplete(
Sender: TObject)
Called when the download of the update is complete. This is a good spot to warn the user that the application will now be closed and that the update will now be applied. You should call InstallUpdate once it is determined that the update is to be applied.
OnUpdateAborted(Sender: TObject; eReason: TUpdateAbortReasons)

This event is called when an error occurs when attempting to download the update or the update file. The error message will indicate the problem so you should display it to the user..

If you are using umAutoWithUI mode and have not suppied this event handler, the component will suppy its own and present appropriate error messages.

OnError(
Sender: TObject;
ErrorInfo: TCynthesisAppUpdateError)

This event is called when an error occurs when attempting to download the update or the update file. The error message will indicate the problem so you should display it to the user. - See AppUpdateTypes.pas for details on the TCynthesisAppUpdateError s structure

Tips and Tricks

Here are some tips and tricks to help you out when using the component:

Testimonials

Acknowledgements


 James Waletzky,
cynthesis@home.com