Site Map Contact Us Home
E-mail Newsletter
Subscribe to get informed about
Clever Components news.

Your Name:
Your Email:
 
SUBSCRIBE
 
Previous Newsletters
 




Products Articles Downloads Order Support
Customer Portal      

Updating your application via the Internet

Submitted on November 1, 2004

Currently the newer version of the Clever Internet Suite 6.2 is available. This version includes the Web Update component. Also please check the How to migrate to the Clever Internet Suite Version 5.0 article.

Introduction

In this article we continue discussing the task of receiving updates from the Internet. Starting from the moment when the first part of this article was published (Adding automatic update support to your application, 25 March 2003) we received many comments and requests from our readers about extending the main functionality of the WebUpdate Delphi component. After collecting and analyzing all these feature requests, we have selected the most important of them and decided to publish new WebUpdate component.

The most frequently asked features for the Internet updater tools can be displayed in the following order:

Let us move ahead and discuss all of these features in details.

Receiving updates in a background

This option is necessary when the update files are large and it is important to do not interrupt the main application process while receiving the updates. In order to satisfy this condition we have used the TclDownloader component from the Internet Components - Clever Internet Suite library. Generally speaking it is possible to use any other library you prefer but since the TclDownloader component supports the asynchronous downloading mode out of the box we will use it in our examples extensively. If your library does not support the asynchronous downloading mode, you have to implement a thread inside of which your socket control will perform the downloading process.

When the update retrieving is started, the StartDownloading method is called and returns immediately since the whole downloading process is performed inside of internal TclDownloader's thread.

procedure TclWebUpdate.StartDownloading;
begin
   FDownloader.URL := ActualInfo[FUpdateNo].URL;
   FDownloader.Start();
end;

The ProcessCompleted method is called automatically when the downloader has finished its work.

procedure TclWebUpdate.DoOnProcessCompleted(Sender: TObject);
begin
   if FIsDownloading then
   begin
      Inc(FUpdateNo);
      if (FUpdateNo < ActualInfo.Count) then
      begin
         StartDownloading();
      end else
      begin
         FIsDownloading := False;
         StartUpdating();
      end;
   end else
   begin
      CheckUpdateInfo();
   end;
end;

Receiving of multiple non-cumulative updates

The algorithm of receiving of updates from the Web is described in the Adding automatic update support to your application article in details. The main difference between two these algorithms is that the new algorithm allows you to receive multiple updates at the same session. This is necessary requirement if you run your application periodically and there are more than one Web updates are coming between two sessions of your work. In such case you must keep the information about all previously downloaded updates in order to do not download them again. In the WebUpdate component we have used the XML document object model for storing of such information. The listing below demonstrates the comparing process of the updates available from the Web and ones which were already downloaded during the previous sessions.

procedure TclWebUpdate.CheckUpdateInfo;
var
   i: integer;
begin
   for i := 0 to UpdateInfo.Count - 1 do
   begin
      if HasUpdate(UpdateInfo[i]) then
      begin
         ActualInfo.Add().Assign(UpdateInfo[i]);
      end;
   end;
   if ActualInfo.HasDownloads then
   begin
      StartDownloading();
   end else
   if ActualInfo.HasUpdates then
   begin
      StartUpdating();
   end else
   begin
      DoNoUpdatesFound();
   end;
end;

Updating of the main application executable

After all updates are received, they are executed using the corresponding information from their Command Batch scripts. You can associate the command batch statements (such as copy, unzip, del...) with each update archive separately. When the WebUpdate component processes the downloaded updates, all updates are applied immediately except for ones which contain the main application executable. Such updates have the NeedTerminate flag enabled. In order to update the main application executable and also all locked resources the user must have a chance to terminate the application. If at least one of the update files has the NeedTerminate flag enabled, the OnTerminating event is raised just after the last received update is processed.

It is important to accumulate the updates which require the main application to be closed. The implementation of this algorithm is application-dependant. One of the possible ways is to store the updates command batch scripts into the separated command batch file (starter.cmd, e.g). The last statement of the starter.cmd file should always contain the line which runs the main application executable.

Please Note! You must always run your application using this starter.cmd file and not using the application executable. Next time you run your application, the executable file will be replaced with new one and finally will be started.

Another way you can use the separated application for the WebUpdate component. In this article we do not consider all possible implementations of the updating of locked files. This is a place where you can realize your own best solutions.

procedure TclWebUpdate.StartUpdating;
var
   i: Integer;
begin
   for i := 0 to ActualInfo.Count - 1 do
   begin
      if (ActualInfo[i].Status = usReady) then
      begin
         RunUpdate(ActualInfo[i]);
      end;
   end;
   if NeedTerminate then
   begin
      Terminating();
   end;
end;

The event handler for the OnRunUpdate component event looks like the following:

procedure TMainForm.clWebUpdateRunUpdate(Sender: TObject;
   AUpdateScript: TStrings; ANeedTerminate: Boolean; var CanRun: Boolean;
   var AErrors: String);
begin
   if ANeedTerminate then
   begin
      AddUpdateScript(AUpdateScript.Text);
      CanRun := False;
   end;
end;

Downloading large-size updates with the resuming of the broken / interrupted downloads

The Microsoft Windows Updater works in a background and continues the downloading process through sessions of working or from time to time the PC is connected to the Internet. In order to continue the downloading process from the point where it is stopped you have to store the current position within the file being downloaded and start the downloading process at this point next time you continue working with your application. Since TclDownloader gets the web resources in the Multiple Threads simultaneously, you must store the current positions for each of these threads. You can learn more about this mode at Multipart Multithreaded Downloading page. The listing below demonstrates how to store and load the multipart downloading state into XML:

procedure TclUpdateInfo.SaveResourceState(ANode: IXMLDomNode;
   AResourceState: TclResourceState);
var
   i: Integer;
   node: IXMLDomNode;
begin
   (ANode as IXMLDOMElement).setAttribute('resourcesize', AResourceState.ResourceSize);
   for i := 0 to AResourceState.Count - 1 do
   begin
      node := ANode.ownerDocument.createElement('item');
      ANode.appendChild(node);

      (node as IXMLDOMElement).setAttribute('resourcepos', AResourceState[i].ResourcePos);
      (node as IXMLDOMElement).setAttribute('bytestoproceed', AResourceState[i].BytesToProceed);
      (node as IXMLDOMElement).setAttribute('bytesproceed', AResourceState[i].BytesProceed);
   end;
end;

procedure TclUpdateInfo.LoadResourceState(ANode: IXMLDomNode;
   AResourceState: TclResourceState);
var
   i: Integer;
   NodeList: IXMLDOMNodeList;
   Item: TclResourceStateItem;
begin
   AResourceState.ResourceSize := StrToIntDef(GetAttributeValue(ANode, 'resourcesize'), 0);
   NodeList := ANode.selectNodes('item');
   for i := 0 to NodeList.length - 1 do
   begin
      Item := AResourceState.Add();
      Item.ResourcePos := StrToIntDef(GetAttributeValue(NodeList.item[i], 'resourcepos'), 0);
      Item.BytesToProceed := StrToIntDef(GetAttributeValue(NodeList.item[i], 'bytestoproceed'), 0);
      Item.BytesProceed := StrToIntDef(GetAttributeValue(NodeList.item[i], 'bytesproceed'), 0);
   end;
end;

Managing of the updates available on the server

As it is described in Adding automatic update support to your application, all updates available on the server are managed by the XML document which is also available on the server. In order to simplify the organizing of such XML document and keeping it up-to-date, we have developed simple program. This program allows you add the information about new updates and also modify existing ones with the user-friendly interface and do not bother about the xml document structure.

All sources of the Delphi project for this application together with compiled executable can be downloaded at WebUpdateSrc.zip

Source Code and working sample

A full source code of all classes, UpdateManager program and also the test application described in this article can be downloaded at WebUpdateSrc.zip

What the test application does:

  • This test application connects to our sample updates page at webupdate.xml
  • Downloads the following three update archives: webupdate1.zipwebupdate2.zip and webupdate3.zip
  • Copies the webupdate1.zip archive as is into the test application folder;
  • Extracts and copies the data.xml file from the webupdate2.zip archive;
  • Extracts the TestApplication.exe main executable file from the webupdate3.zip archive, adds the copy statement of this file into the starter.cmd file and asks the user for closing the test application;
  • Next time you run the test application (for sure using the starter.cmd file), the TestApplication.exe file will be replaced with new one and finally will be started.

The updated version of the TestApplication.exe file will contain the ' - Updated' phrase within the application window caption.

This code is constantly being refined and improved and your comments and suggestions are always welcome.

With best regards,
Sergey Shirokov 
Clever Components team
Please feel free to Contact Us

    Copyright © 2000-2024