TCynthesisAppUpdate
===================

Date:
Version:  1.0.0.0
Author:   James Waletzky
E-Mail:   ([email protected])
Company:  Cynthesis Software Inc.
Web Site: http://www.npsnet.com/waletzky/


Requirements
------------

 - Delphi 4.x (apply Update Pack #2 or later)
 - The TNMHTTP component (provided with Delphi 4.x) must be installed.


History
-------

Version: 1.0.0.0
 - Fix: The AppUpdate component would fail to launch UPDATE.EXE if
   the path to the executable contained spaces.
 - Change: Minor code enhancements

Version: 0.99.0.0
 - First BETA release.


Known Problems (as of Version 1.0.0.0)
--------------

- SAMPLE APPLICATION: The browse button in the sample application is not
 working as expected. I have yet to look into this. Again, if you have
 any ideas, please e-mail me. For now, just type in the path to the DCU file.

- SAMPLE APPLICATION: If you get a message that there is a new component
 update available, you cannot change tabs in the test application until
 you've downloaded the updated. If you don't want the update, simply quit
 the test app and reload to once again experiement with the sample.

- GENERAL: You may need to copy UnzDLL.DLL to the Windows system directory
 to get things to work properly.


Contents
--------

- Readme.txt: this file
- AppUpdateTest.dpr: sample application project file.
- AppUpdateTest.res: resource file for sample application.
- AppUpdateTst.dfm: main form file for the test application.
- AppUpdateTst.pas: source code for the main form file.
- CynthesisAppUpdate.dcu: compiled TCynthesisAppUpdate component.
- CynthesisAppUpdate.dcr: component resource file.
- CynthesisAppUpdate.int: Interface section for the CynthesisAppUpdate file.
- Update.exe: companion helper application that takes care of installing
 the update.
- UnzDLL.dll: helper DLL that handles unzip operations from the update
 helper application.
- AppUpdateTest.ico - icon file for the test application.


What is the TCynthesisAppUpdate Component?
------------------------------------------

The TCynthesisAppUpdate component provides the functionality to an application
of automatically checking for new versions when on-line, 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 are all
that's required for your application to update itself!

Other features include:
       - distribute your binary files in a ZIP file and have the component
         handle the update; or
       - distribute your update as an executable (EXE) that is run once the
         download process has completed.
       - specify which versions of your application that the udpate is
         compatible with (you may not want to install a v5.01 update over
         a v1.0 binary).
       - the Update helper application will list the files that have been
         updated (when distributing your update using the ZIP method).
       - events are fired to your application for all important actions.


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 [email protected] for permission. Cynthesis
software has the right to charge a nominal fee for use of this component in a
commercial application.

The source code for this component is available from Cynthesis Software
for a cost of $10 (US Funds). 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 TCynthesisAppUpdate into a package of your choice such that it
    is available on the component palette.
(2)  Drop the component on your application's main form.
(3)  Determine whether you want the component to handle the entire update or
    you want to do it manually via events (set the UpdateMode property).
(4)  Fill in the current version of the product.
(5)  Fill in the URL that will point to the update information INI file.
(6)  Distribute your application (don't forget to include UPDATE.EXE in your
    distribution package in the -same directory- as your application
    executable).
(7)  When it comes time for an update to your application, create an INI file
    as described below.
(8)  Prepare the update information INI file.
(9)  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, 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.


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=<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=<None|UseUpdate|RunExecutable>
 - see the InstallAction property on the component for details.

UpdateURL=<string>
 - URL to the zip or executable file that represents the update.

Details=<string>
 - any text used to describe the update; could be an abbreviated list of
   changes.

CompatibleVersions=<string>,<string>,...
 - 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.


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.


Component Properties
--------------------

PUBLISHED (Design-time/Run-time):

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/AppUpdate.ini

UpdateMode
 - TCynthesisAppUpdateModes
 - If set to mAutoWithUI, 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. If set to mAutoNoUI,
   the same events will occur except no UI will appear. The update will occur
   without user intervention. If set to mManual, you have to display the
   update UI by handling the various events that are thrown from the
   component.

CurrentVersion
 - string
 - The version of your application that you are currently releasing. This
   version is checked against the one listed in the update info INI file
   to determine if an update is required.

PUBLIC (Run-time):

DestDirectory
 - Run-time only (read/write)
 - string
 - Optional parameter 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
 - TCynthesisAppUpdateInstallActions
 - run-time only (read/write)
 - 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.


Component Methods
-----------------

Initialize;
 - Make sure that this method is called before using the component within an
   application.

CheckForUpdate: TCynthesisAppUpdateError;
 - Call this method to check the web server for an update. 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 in the future if there is a demand.

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.
 - 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
 AppUpdateTypes.pas


Component Events
----------------

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.

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.

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.

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.

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

OnUpdateAborted(Sender: TObject; eReason: TUpdateAbortReasons)
 - This event is fired when the update process has been aborted for some
   reason. Updates can be aborted because of an error in download, or perhaps
   because the user cancelled the update. This event handler presents a good
   way to restore the initial state of your application before the update
   process was started. Note that when a fatal error occurs in the update
   process, the AppUpdate component will fire the error event, as well as this
   event.
 - See AppUpdateTypes.pas for details on the TUpdateAbortReasons type.


Tips and Tricks
---------------

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

 - Check out the sample application called AppUpdateTest - it will give you
   a good idea as to how the component works and what to do in the case of
   a manual update.

 - The TCynthesisAppUpdate component will close your application automatically
   once the InstallUpdate method is invoked. This is to ensure that none of
   the application files are in use when the update is applied. Your
   application should be coded to expect this situation.

 - Use the iaUseUpdate install action when you simply want to update certain
   files that have been installed to some file hierarchy in or under where
   your application's executable file is located. If you need to apply new
   registry settings, or install files to a different directory (e.g. under
   the Windows system directory), it is recommended that you write a small
   install program (e.g. using InstallShield) that does not permit any
   user interaction, but simply installs the files to the appropriate
   locations and adjusts the registry, etc. as required.

 - It is recommended that every time you distribute an update for your
   application you update the main executable whether it needs it or not.
   This has the effect of updating the version number used by the update
   component to determine if an update on the web is newer than the one
   currently installed.


Testimonials
------------

"The CynthesisAppUpdate component has saved me hours of work and gives my
applications that professional look. I'll be using it on all my Delphi
projects from now on."
       --Michael Holligan


Acknowledgements
----------------

Special thanks to Eric W. Engler for creating the Delphi Zip/Unzip
component that this component leverages.