Contents
Preface
The upcoming version of kbmMW, will contain a new unit, kbmMWUpdateClient, which contains two specialized file clients: TkbmMWUpdateClient and TkbmMWPooledUpdateClient.
The update client is a tool making it easy for you to push updates of your Windows (currently) based client applications directly from your application server.
You may already have another system/method running for providing updates of your client applications, and you can continue to use that if that fits your use. However now that feature will come built into kbmMW.
Preparing your application server
You will need a kbmMW based application server which the client connects to. The communication/transport can be async/messaging or traditional synchronous request/response based.
Using the kbmMW service wizard, add a file service, name it KBMMW_UPDATE as that is the default named expected by a client update component. It is, as always, all configurable to something else. But let us just use the standard at this point (no audio).
The wizard automatically added a new TkbmMWFilePool component to the main form. Of security reasons we will now make access to files via that file pool, read only, by writing this code in it’s OnAccessFile event:
procedure TForm1.kbmMWFilePool1AccessFile(FilePool: TkbmMWFilePool; New: Boolean; var FilePath: string; AccessMode: TkbmMWFileAccessMode); begin if AccessMode<>TkbmMWFileAccessMode.mwfamOpenRead then kbmMWRaiseException(KBMMW_ERR_FILEPOOL_ACCESSDENIED,'Access denied'); end;
The wizard also produced a kbmMW file service module. Depending on if you register service modules the “old fashioned way” using the RegisterService method, or the modern way using AutoRegisterServices, you (in the case of AutoRegisterServices) needs to add a service attribute to the generated file, and add kbmMWSmartServiceUtils to the uses clause:
... interface uses ... kbmMWSmartServiceUtils; type [kbmMW_Service('name:KBMMW_UPDATE, flags:[], rootPath:".\\updates", blockSize:1048576')] TFileService1 = class(TkbmMWFileService) private { Private declarations } protected { Protected declarations } public { Public declarations } ... end; implementation ... initialization TkbmMWRTTI.EnableRTTI(TFileService1); end.
Now all the code has been prepared for the application server. We also need to create the update folder structure from which clients fetch their updated applications and files, but I will show that after having shown the changes needed to the client to make it auto updatable.
Preparing your auto updating client
Now we create a simple client which only purpose is to update itself 🙂 Obviously you would want to put some more functionality inside the client, but this demo will focus on the update features.
The video (no audio) show two components placed on a form, a kbmMW client transport and the new kbmMW update client component.
You will already have a client transport in your existing kbmMW based applications, and will not need to add another. However the update client component (TkbmMWUpdateClient or TkbmMWPooledUpdateClient) is needed.
In this sample we use TkbmMWUpdateClient and hook it directly up to the transport.
Then we set it’s Application property to a unique identifier (DEMO) for this application. You can have multiple different applications which all takes advantage of the update feature, but each of them must have a unique identifier.
procedure TForm1.CheckForUpdate; var bUpdate,bUpdateRequired:boolean; begin bUpdate:=kbmMWUpdateClient1.IsUpdatesAvailable(true); if bUpdate then bUpdateRequired:=kbmMWUpdateClient1.IsRequiredUpdatesAvailable(false); if bUpdate then begin if bUpdateRequired then ShowMessage('A required update is available. It will auto update when you close this message.') else if MessageDlg('An optional, but recommended, update is available. Do you want to update?', mtConfirmation,[mbYes, mbNo],0,mbYes)<>mrYes then exit; end; kbmMWUpdateClient1.Update; end;
At application start, we ask the update component if there are any updates available, and if there are, then if the update is required or optional. Depending on the result, a matching dialog is presented.
In case the update is going on, the Update method of the update client component is called, after which whatever magic is needed is happening, resulting in your client application being updated.
The magic
What happens behind the scenes?
The first call to IsUpdatesAvailable has its argument set to true. It instructs the update client to ask the server for new update information. The next call to IsRequiredUpdatesAvailable has its argument set to false, which tells it not to update status from the server, but work on with the status that has already been received previously.
The client figures out if there are updates available by asking for a directory listing from within the applications update folder on the server. Since we have given this client the Application name DEMO, it will look in the DEMO directory on the server.
It will look for directories, which are named release_XXX_XXX_XXX_XXX or release_XXX_XXX_XXX_XXXR. Everything else is ignored. XXX is a 3 digit version number, typically expressed as major, minor, release and build, exactly matching the versioning features in Delphi/C++Builder. All 3 digits must be available, so prefix with 0 as needed. R indicates if the directory contains a required release.
Inside the release…. directory, you can place one or more files that you want sent to the client. It includes executables and data files as you see fit. An additional file must also exist in the directory, the manifest.json file.
The manifest file contains detailed information about what files to provide to the client, and how to update them in addition to a textual description of the update.
It is recommended that updates are absolute, not incremental, so each release directory contains everything needed for that particular version. The following is an example of a manifest file.
{ "description": "Project1 v2.0.0.5", "files": { "src": "release_002_000_000_005\\Project1.exe", "dst": "[!--app--!]\\Project1.exe", "restart": true } }
In description, you can provide whatever textual description you would like to make available for your client users. Use the method VersionDescription of the update client to fetch the description.
files – Required – contains an object or an array of objects, describing the files that constitute the update. Each object must have a src and a dst field.
afterRestart – Optional – can be true, false or missing (default false). If true, the file will only be processed after the client application has been restarted. Default a file and its rules will be processed before a restart.
src – Required – specifies the path to the source file (either absolute or relative from the root of the servers root update directory)
dst – Required – specifies the name under which the field should be known on the client, including a path. A number of macros exists, which makes it easy to place the file in the correct directories on the client. See later for the list of macros.
restart – Optional – can be true, false or missing (default false). It controls if the client application must be restarted after updating. The restart is postponed until all files, that are to be handled before a restart, has been handled.
run– Optional – can be true, false or missing (default false). If true, it will execute the given file on the client with the space separated arguments provided in the optional runArgs.
runArgs – Optional – the space separated arguments provided for the application to be executed in case run is true.
terminate – Optional – can be true, false or missing (default false). If true instructs the client application to terminate after the update. The termination code can be provided via the terminateCode property.
terminateCode – Optional – a 16 bit numeric non signed value (default 0). Used when terminate is true to signal an exit code for the client application.
dst and runArgs supports macro expansion of a number of values (all paths are without the final path separator):
[!–App–!] – The current path of the running client application.
[!–Home–!] – The user’s home path. On Windows typically C:\Users\<username>\AppData\Roaming
[!–Doc–!] – The user’s document path. On Windows typically C:\Users\<username>\Documents
[!–PublicDoc–!] – The shared document path. On Windows typically C:\Users\Public\Documents
[!–Temp–!] – The user’s temporary directory. On Windows typically C:\Users\<User name>\AppData\Local\Temp
[!–Pictures–!] – The user’s image directory. On Windows typically C:\Users\<username>\Pictures
[!–CommonPictures–!] – The shared image directory. On Windows typically C:\Users\Public\Pictures
[!–Lib–!] – The program files application path. On Windows typically C:\Program Files\<application folder>
[!–AppData–!] – The user’s local files (cache/data) path. On Windows typically C:\Users\<username>\AppData\Local
[!–CommonData–!] – The shared local files (cache/data) path. On Windows typically C:\ProgramData
[!–Cam–!] – The user’s camera/picture path. On Windows typically C:\Users\<username>\Pictures
[!–CommonCam–!] – The sared camera/picture path. On Windows typically C:\Users\Public\Pictures
[!–Music–!] – The user’s music path. On Windows typically C:\Users\<username>\Music
[!–CommonMusic–!] – The shared music path. On Windows typically C:\Users\Public\Music
[!–Movies–!] – The user’s video path. On Windows typically C:\Users\<username>\Videos
[!–CommonMovies–!] – The shader video path. On Windows typically C:\Users\Public\Videos
[!–Downloads–!] – The user’s download path. On Windows typically C:\Users\<username>\AppData\Local
[!–CommonDownloads–!] – The shared download path. On Windows typically C:\ProgramData
[!–Win–!] – The system windows path. On Windows typically C:\Windows
[!–Sys–!] – The system32 path. On Windows typically C:\Windows\System32
[!–ProgramFiles–!] – The system’s program files path. On Windows typically C:\Program Files
[!–CommonProgramFiles–!] – The system’s common program files path. On Windows typically C:\ProgramData\Common
Default kbmMW update client will detect the version number of the executable directly, however if you would rather like to pick the current version number of the executable, from an external configuration file, you can set the property CurrentVersionMethod to mwucvmConfiguration instead of the default mwucvmFileVersion. When using mwucvmFileVersion, it is obviously important that your executable is compiled with the correct version number and that it match the version number in the manifest file and in the name of the release_xxxx directory.
In case more updates are available you can ask for a list of them (even older versions making it possible to offer downgrade features), and specify exactly which version you would like to upgrade/downgrade to.
The Update method of TkbmMWUpdateClient supports an optional version argument which indicates which version you want to update/downgrade to. Default, when no argument or an empty argument is provided, the update will be to the newest version.
The identifiers of the versions that can be downloaded from the server, can be fetched via the AvailableVersions method.
kbmMW update will automatically backup all overwritten files if the property Backup is true. The path where the files are backed up can be specified in BackupPath.
If you support android, it will be more perfect!
Updating Android applications outside Google Play is imo not recommended, and in most cases it would require having a rooted device.
Will it be able to also update Windows Services?
Yes indirectly by using an executable.
It is possible to specify in the manifest file that an installer executable should be transferred and then run.
Stopping and installing service stuff, usually require the installer to be running in an elevated state, why the installer most likely will ask if it is ok to run it elevated.
Hi Kim when do you plan to release this new feature?
Expect release today.