├── Logo.png ├── Binaries ├── Updater.exe ├── libeay32.dll ├── ssleay32.dll ├── Documentation.pdf ├── UpdaterWizard.exe ├── Snapshots │ ├── Alpha │ │ ├── AuthoringTool.exe │ │ └── Alpha.json │ ├── Beta │ │ ├── AuthoringTool.exe │ │ └── Beta.json │ ├── Nightly │ │ ├── AuthoringTool.exe │ │ └── Nightly.json │ ├── Stable │ │ ├── AuthoringTool.exe │ │ └── Stable.json │ └── Channels.json ├── Preferences.json ├── WebUpdate.wup ├── WebUpdate │ ├── Beta.json │ ├── Alpha.json │ ├── Stable.json │ ├── Nightly.json │ └── Channels.json └── AuthoringTool.json ├── Glyphs ├── WebUpdate.ico └── WebUpdate.png ├── Packages ├── WebUpdateD.dcr ├── RX │ ├── WebUpdateD.dpk │ ├── WebUpdateR.dpk │ └── Packages.groupproj ├── RX1 │ ├── WebUpdateD.dpk │ ├── WebUpdateR.dpk │ └── Packages.groupproj ├── RX2 │ ├── WebUpdateD.dpk │ ├── WebUpdateR.dpk │ ├── Packages.groupproj │ ├── WebUpdateD.dproj │ └── WebUpdateR.dproj ├── XE2 │ ├── WebUpdateD.dpk │ ├── WebUpdateR.dpk │ └── Packages.groupproj ├── XE3 │ ├── WebUpdateD.dpk │ └── WebUpdateR.dpk ├── XE4 │ ├── WebUpdateD.dpk │ └── WebUpdateR.dpk ├── XE5 │ ├── WebUpdateD.dpk │ └── WebUpdateR.dpk ├── XE6 │ ├── WebUpdateD.dpk │ └── WebUpdateR.dpk ├── XE7 │ ├── WebUpdateD.dpk │ ├── WebUpdateR.dpk │ └── Packages.groupproj └── XE8 │ ├── WebUpdateD.dpk │ ├── WebUpdateR.dpk │ └── Packages.groupproj ├── Delphinus.Info.json ├── Source ├── Common │ ├── README.md │ ├── WebUpdate.Tools.pas │ ├── WebUpdate.JSON.Channels.pas │ ├── WebUpdate.JSON.Serializer.pas │ ├── WebUpdate.JSON.Channel.pas │ ├── WebUpdate.Classes.WebUpdate.pas │ ├── WebUpdate.JSON.Project.pas │ └── WebUpdate.Classes.Updater.pas ├── Authoring Tool │ ├── README.md │ ├── WebUpdate.GUI.CommandLine.pas │ ├── AuthoringTool.dpr │ ├── WebUpdate.GUI.CommandLine.dfm │ ├── WebUpdate.GUI.About.pas │ ├── WebUpdate.JSON.Preferences.pas │ ├── WebUpdate.GUI.Options.pas │ └── WebUpdate.GUI.Options.dfm ├── Package │ ├── WebUpdate.Package.Reg.pas │ └── WebUpdate.Package.Component.pas ├── Update Helper Wizard │ ├── README.md │ ├── UpdaterWizard.dpr │ └── WebUpdate.GUI.Updater.pas ├── Example Application │ ├── ExampleApp.dpr │ ├── MainUnit.dfm │ └── MainUnit.pas ├── Web Update Tools.groupproj ├── Update Helper (Command-line) │ ├── Updater.dpr │ └── Updater.dproj └── Snapshot Tool (Command Line) │ └── SnapshotTool.dpr ├── Delphinus.Install.json └── README.md /Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CWBudde/WebUpdate/HEAD/Logo.png -------------------------------------------------------------------------------- /Binaries/Updater.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CWBudde/WebUpdate/HEAD/Binaries/Updater.exe -------------------------------------------------------------------------------- /Glyphs/WebUpdate.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CWBudde/WebUpdate/HEAD/Glyphs/WebUpdate.ico -------------------------------------------------------------------------------- /Glyphs/WebUpdate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CWBudde/WebUpdate/HEAD/Glyphs/WebUpdate.png -------------------------------------------------------------------------------- /Binaries/libeay32.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CWBudde/WebUpdate/HEAD/Binaries/libeay32.dll -------------------------------------------------------------------------------- /Binaries/ssleay32.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CWBudde/WebUpdate/HEAD/Binaries/ssleay32.dll -------------------------------------------------------------------------------- /Packages/WebUpdateD.dcr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CWBudde/WebUpdate/HEAD/Packages/WebUpdateD.dcr -------------------------------------------------------------------------------- /Binaries/Documentation.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CWBudde/WebUpdate/HEAD/Binaries/Documentation.pdf -------------------------------------------------------------------------------- /Binaries/UpdaterWizard.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CWBudde/WebUpdate/HEAD/Binaries/UpdaterWizard.exe -------------------------------------------------------------------------------- /Delphinus.Info.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "{E132F855-C717-46E1-98F0-AFBB8EE573A6}", 3 | "picture": "Logo.png" 4 | } -------------------------------------------------------------------------------- /Binaries/Snapshots/Alpha/AuthoringTool.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CWBudde/WebUpdate/HEAD/Binaries/Snapshots/Alpha/AuthoringTool.exe -------------------------------------------------------------------------------- /Binaries/Snapshots/Beta/AuthoringTool.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CWBudde/WebUpdate/HEAD/Binaries/Snapshots/Beta/AuthoringTool.exe -------------------------------------------------------------------------------- /Binaries/Snapshots/Nightly/AuthoringTool.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CWBudde/WebUpdate/HEAD/Binaries/Snapshots/Nightly/AuthoringTool.exe -------------------------------------------------------------------------------- /Binaries/Snapshots/Stable/AuthoringTool.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CWBudde/WebUpdate/HEAD/Binaries/Snapshots/Stable/AuthoringTool.exe -------------------------------------------------------------------------------- /Source/Common/README.md: -------------------------------------------------------------------------------- 1 | Common 2 | ====== 3 | 4 | This directory contains commonly used units containing procedures, functions and classes used across the different projects. -------------------------------------------------------------------------------- /Binaries/Preferences.json: -------------------------------------------------------------------------------- 1 | { 2 | "ID" : "Preferences", 3 | "Left" : 1389, 4 | "Top" : 758, 5 | "ViewFiles" : true, 6 | "RecentProject" : "C:\\Users\\Public\\Code\\WebUpdate\\Binaries\\WebUpdate.wup" 7 | } -------------------------------------------------------------------------------- /Binaries/WebUpdate.wup: -------------------------------------------------------------------------------- 1 | { 2 | "ID" : "Project", 3 | "ChannelFilename" : "WebUpdate\\Channels.json", 4 | "CurrentChannel" : "Nightly", 5 | "Copy" : { 6 | "Path" : ".\\Snapshots", 7 | "Enabled" : true 8 | } 9 | } -------------------------------------------------------------------------------- /Source/Authoring Tool/README.md: -------------------------------------------------------------------------------- 1 | Authoring Tool 2 | ============== 3 | 4 | The authoring tool is used to create and manage channels and to take snapshots. The snapshots can be copied to a certain path or uploaded to an FTP client directly. -------------------------------------------------------------------------------- /Binaries/WebUpdate/Beta.json: -------------------------------------------------------------------------------- 1 | { 2 | "ID" : "Channel", 3 | "Modified" : "2014-11-20T14:48:01.000", 4 | "Name" : "Beta", 5 | "Files" : [ 6 | { 7 | "FileName" : "AuthoringTool.exe", 8 | "Size" : 1068032, 9 | "Modified" : "2014-11-20T14:48:01.000" 10 | } 11 | ], 12 | "AppName" : "AuthoringTool.exe" 13 | } -------------------------------------------------------------------------------- /Binaries/AuthoringTool.json: -------------------------------------------------------------------------------- 1 | { 2 | "ID" : "Channel", 3 | "Modified" : "2014-11-20T12:51:42.000", 4 | "Name" : "Stable", 5 | "Files" : [ 6 | { 7 | "FileName" : "AuthoringTool.exe", 8 | "Size" : 1068032, 9 | "Modified" : "2014-11-20T12:51:42.000" 10 | } 11 | ], 12 | "AppName" : "AuthoringTool.exe" 13 | } -------------------------------------------------------------------------------- /Binaries/Snapshots/Beta/Beta.json: -------------------------------------------------------------------------------- 1 | { 2 | "ID" : "Channel", 3 | "Modified" : "2014-11-20T14:48:01.000", 4 | "Name" : "Beta", 5 | "Files" : [ 6 | { 7 | "FileName" : "AuthoringTool.exe", 8 | "Size" : 1068032, 9 | "Modified" : "2014-11-20T14:48:01.000" 10 | } 11 | ], 12 | "AppName" : "AuthoringTool.exe" 13 | } -------------------------------------------------------------------------------- /Binaries/WebUpdate/Alpha.json: -------------------------------------------------------------------------------- 1 | { 2 | "ID" : "Channel", 3 | "Modified" : "2014-11-20T14:48:01.000", 4 | "Name" : "Alpha", 5 | "Files" : [ 6 | { 7 | "FileName" : "AuthoringTool.exe", 8 | "Size" : 1068032, 9 | "Modified" : "2014-11-20T14:48:01.000" 10 | } 11 | ], 12 | "AppName" : "AuthoringTool.exe" 13 | } -------------------------------------------------------------------------------- /Binaries/WebUpdate/Stable.json: -------------------------------------------------------------------------------- 1 | { 2 | "ID" : "Channel", 3 | "Modified" : "2014-11-20T14:48:01.000", 4 | "Name" : "Stable", 5 | "Files" : [ 6 | { 7 | "FileName" : "AuthoringTool.exe", 8 | "Size" : 1068032, 9 | "Modified" : "2014-11-20T14:48:01.000" 10 | } 11 | ], 12 | "AppName" : "AuthoringTool.exe" 13 | } -------------------------------------------------------------------------------- /Binaries/Snapshots/Alpha/Alpha.json: -------------------------------------------------------------------------------- 1 | { 2 | "ID" : "Channel", 3 | "Modified" : "2014-11-20T14:48:01.000", 4 | "Name" : "Alpha", 5 | "Files" : [ 6 | { 7 | "FileName" : "AuthoringTool.exe", 8 | "Size" : 1068032, 9 | "Modified" : "2014-11-20T14:48:01.000" 10 | } 11 | ], 12 | "AppName" : "AuthoringTool.exe" 13 | } -------------------------------------------------------------------------------- /Binaries/WebUpdate/Nightly.json: -------------------------------------------------------------------------------- 1 | { 2 | "ID" : "Channel", 3 | "Modified" : "2014-11-20T14:48:01.000", 4 | "Name" : "Nightly", 5 | "Files" : [ 6 | { 7 | "FileName" : "AuthoringTool.exe", 8 | "Size" : 1068032, 9 | "Modified" : "2014-11-20T14:48:01.000" 10 | } 11 | ], 12 | "AppName" : "AuthoringTool.exe" 13 | } -------------------------------------------------------------------------------- /Binaries/Snapshots/Nightly/Nightly.json: -------------------------------------------------------------------------------- 1 | { 2 | "ID" : "Channel", 3 | "Modified" : "2014-11-20T14:48:01.000", 4 | "Name" : "Nightly", 5 | "Files" : [ 6 | { 7 | "FileName" : "AuthoringTool.exe", 8 | "Size" : 1068032, 9 | "Modified" : "2014-11-20T14:48:01.000" 10 | } 11 | ], 12 | "AppName" : "AuthoringTool.exe" 13 | } -------------------------------------------------------------------------------- /Binaries/Snapshots/Stable/Stable.json: -------------------------------------------------------------------------------- 1 | { 2 | "ID" : "Channel", 3 | "Modified" : "2014-11-20T14:48:01.000", 4 | "Name" : "Stable", 5 | "Files" : [ 6 | { 7 | "FileName" : "AuthoringTool.exe", 8 | "Size" : 1068032, 9 | "Modified" : "2014-11-20T14:48:01.000" 10 | } 11 | ], 12 | "AppName" : "AuthoringTool.exe" 13 | } -------------------------------------------------------------------------------- /Source/Package/WebUpdate.Package.Reg.pas: -------------------------------------------------------------------------------- 1 | unit WebUpdate.Package.Reg; 2 | 3 | interface 4 | 5 | uses 6 | System.Classes, WebUpdate.Package.Component; 7 | 8 | procedure Register; 9 | 10 | implementation 11 | 12 | procedure Register; 13 | begin 14 | RegisterComponents('WebUpdate', [TWebUpdateComponent]); 15 | end; 16 | 17 | end. 18 | -------------------------------------------------------------------------------- /Binaries/Snapshots/Channels.json: -------------------------------------------------------------------------------- 1 | { 2 | "ID" : "Channels", 3 | "Modified" : "2014-11-20T14:49:37.121", 4 | "Channels" : [ 5 | { 6 | "Name" : "Stable", 7 | "Modified" : "2014-11-20T14:48:01.000" 8 | }, 9 | { 10 | "Name" : "Beta", 11 | "Modified" : "2014-11-20T14:48:01.000" 12 | }, 13 | { 14 | "Name" : "Alpha", 15 | "Modified" : "2014-11-20T14:48:01.000" 16 | }, 17 | { 18 | "Name" : "Nightly", 19 | "Modified" : "2014-11-20T14:48:01.000" 20 | } 21 | ] 22 | } -------------------------------------------------------------------------------- /Binaries/WebUpdate/Channels.json: -------------------------------------------------------------------------------- 1 | { 2 | "ID" : "Channels", 3 | "Modified" : "2014-11-20T14:49:37.121", 4 | "Channels" : [ 5 | { 6 | "Name" : "Stable", 7 | "Modified" : "2014-11-20T14:48:01.000" 8 | }, 9 | { 10 | "Name" : "Beta", 11 | "Modified" : "2014-11-20T14:48:01.000" 12 | }, 13 | { 14 | "Name" : "Alpha", 15 | "Modified" : "2014-11-20T14:48:01.000" 16 | }, 17 | { 18 | "Name" : "Nightly", 19 | "Modified" : "2014-11-20T14:48:01.000" 20 | } 21 | ] 22 | } -------------------------------------------------------------------------------- /Source/Update Helper Wizard/README.md: -------------------------------------------------------------------------------- 1 | Update Helper Wizard 2 | ==================== 3 | 4 | In order to perform a web update from a running application, the application must be closed first while a helper tool is started to perform the download and replacement of files. 5 | Since this helper tool must exists along with the main executable file, it can also serve as a stand-alone wizard to update the application while not running. 6 | 7 | The source code, which can be found in this directory is meant to produce both: An update helper and a stand-alone update wizard. -------------------------------------------------------------------------------- /Source/Example Application/ExampleApp.dpr: -------------------------------------------------------------------------------- 1 | program ExampleApp; 2 | 3 | uses 4 | Vcl.Forms, 5 | WebUpdate.JSON.Channel in '..\Common\WebUpdate.JSON.Channel.pas', 6 | WebUpdate.JSON.Channels in '..\Common\WebUpdate.JSON.Channels.pas', 7 | WebUpdate.JSON.Serializer in '..\Common\WebUpdate.JSON.Serializer.pas', 8 | WebUpdate.Classes.WebUpdate in '..\Common\WebUpdate.Classes.WebUpdate.pas', 9 | MainUnit in 'MainUnit.pas' {FormExample}; 10 | 11 | {$R *.res} 12 | 13 | begin 14 | Application.Initialize; 15 | Application.MainFormOnTaskbar := True; 16 | Application.CreateForm(TFormExample, FormExample); 17 | Application.Run; 18 | end. 19 | 20 | -------------------------------------------------------------------------------- /Source/Update Helper Wizard/UpdaterWizard.dpr: -------------------------------------------------------------------------------- 1 | program UpdaterWizard; 2 | 3 | uses 4 | Vcl.Forms, 5 | WebUpdate.Classes.Updater in '..\Common\WebUpdate.Classes.Updater.pas', 6 | WebUpdate.JSON.Serializer in '..\Common\WebUpdate.JSON.Serializer.pas', 7 | WebUpdate.JSON.Channel in '..\Common\WebUpdate.JSON.Channel.pas', 8 | WebUpdate.JSON.Channels in '..\Common\WebUpdate.JSON.Channels.pas', 9 | WebUpdate.GUI.Updater in 'WebUpdate.GUI.Updater.pas' {FormWebUpdate}, 10 | WebUpdate.Tools in '..\Common\WebUpdate.Tools.pas'; 11 | 12 | {$R *.res} 13 | 14 | begin 15 | Application.Initialize; 16 | Application.MainFormOnTaskbar := True; 17 | Application.CreateForm(TFormWebUpdate, FormWebUpdate); 18 | Application.Run; 19 | end. 20 | 21 | -------------------------------------------------------------------------------- /Source/Authoring Tool/WebUpdate.GUI.CommandLine.pas: -------------------------------------------------------------------------------- 1 | unit WebUpdate.GUI.CommandLine; 2 | 3 | interface 4 | 5 | uses 6 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, 7 | Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls; 8 | 9 | type 10 | TFormCommandLine = class(TForm) 11 | MemoCommandLine: TMemo; 12 | procedure FormCreate(Sender: TObject); 13 | end; 14 | 15 | implementation 16 | 17 | uses 18 | System.Types; 19 | 20 | {$R *.dfm} 21 | 22 | procedure TFormCommandLine.FormCreate(Sender: TObject); 23 | begin 24 | MemoCommandLine.Lines[3] := Format(MemoCommandLine.Lines[3], 25 | [ExtractFileName(ParamStr(0))]); 26 | MemoCommandLine.Lines[26] := Format(MemoCommandLine.Lines[26], 27 | [ExtractFileName(ParamStr(0))]); 28 | MemoCommandLine.CaretPos := Point(0, MemoCommandLine.Lines.Count); 29 | end; 30 | 31 | end. 32 | 33 | -------------------------------------------------------------------------------- /Packages/RX/WebUpdateD.dpk: -------------------------------------------------------------------------------- 1 | package WebUpdateD; 2 | 3 | {$R *.res} 4 | {$R '..\WebUpdateD.dcr'} 5 | {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} 6 | {$ALIGN 8} 7 | {$ASSERTIONS ON} 8 | {$BOOLEVAL OFF} 9 | {$DEBUGINFO OFF} 10 | {$EXTENDEDSYNTAX ON} 11 | {$IMPORTEDDATA ON} 12 | {$IOCHECKS ON} 13 | {$LOCALSYMBOLS ON} 14 | {$LONGSTRINGS ON} 15 | {$OPENSTRINGS ON} 16 | {$OPTIMIZATION OFF} 17 | {$OVERFLOWCHECKS OFF} 18 | {$RANGECHECKS OFF} 19 | {$REFERENCEINFO ON} 20 | {$SAFEDIVIDE OFF} 21 | {$STACKFRAMES ON} 22 | {$TYPEDADDRESS OFF} 23 | {$VARSTRINGCHECKS ON} 24 | {$WRITEABLECONST OFF} 25 | {$MINENUMSIZE 1} 26 | {$IMAGEBASE $400000} 27 | {$DEFINE DEBUG} 28 | {$ENDIF IMPLICITBUILDING} 29 | {$DESCRIPTION 'WebUpdate Non-Visual'} 30 | {$LIBSUFFIX '230'} 31 | {$DESIGNONLY} 32 | {$IMPLICITBUILD OFF} 33 | 34 | requires 35 | DesignIDE, 36 | WebUpdateR; 37 | 38 | contains 39 | WebUpdate.Package.Reg in '..\..\Source\Package\WebUpdate.Package.Reg.pas'; 40 | 41 | end. 42 | 43 | -------------------------------------------------------------------------------- /Packages/RX1/WebUpdateD.dpk: -------------------------------------------------------------------------------- 1 | package WebUpdateD; 2 | 3 | {$R *.res} 4 | {$R '..\WebUpdateD.dcr'} 5 | {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} 6 | {$ALIGN 8} 7 | {$ASSERTIONS ON} 8 | {$BOOLEVAL OFF} 9 | {$DEBUGINFO OFF} 10 | {$EXTENDEDSYNTAX ON} 11 | {$IMPORTEDDATA ON} 12 | {$IOCHECKS ON} 13 | {$LOCALSYMBOLS ON} 14 | {$LONGSTRINGS ON} 15 | {$OPENSTRINGS ON} 16 | {$OPTIMIZATION OFF} 17 | {$OVERFLOWCHECKS OFF} 18 | {$RANGECHECKS OFF} 19 | {$REFERENCEINFO ON} 20 | {$SAFEDIVIDE OFF} 21 | {$STACKFRAMES ON} 22 | {$TYPEDADDRESS OFF} 23 | {$VARSTRINGCHECKS ON} 24 | {$WRITEABLECONST OFF} 25 | {$MINENUMSIZE 1} 26 | {$IMAGEBASE $400000} 27 | {$DEFINE DEBUG} 28 | {$ENDIF IMPLICITBUILDING} 29 | {$DESCRIPTION 'WebUpdate Non-Visual'} 30 | {$LIBSUFFIX '240'} 31 | {$DESIGNONLY} 32 | {$IMPLICITBUILD OFF} 33 | 34 | requires 35 | DesignIDE, 36 | WebUpdateR; 37 | 38 | contains 39 | WebUpdate.Package.Reg in '..\..\Source\Package\WebUpdate.Package.Reg.pas'; 40 | 41 | end. 42 | 43 | -------------------------------------------------------------------------------- /Packages/RX2/WebUpdateD.dpk: -------------------------------------------------------------------------------- 1 | package WebUpdateD; 2 | 3 | {$R *.res} 4 | {$R '..\WebUpdateD.dcr'} 5 | {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} 6 | {$ALIGN 8} 7 | {$ASSERTIONS ON} 8 | {$BOOLEVAL OFF} 9 | {$DEBUGINFO OFF} 10 | {$EXTENDEDSYNTAX ON} 11 | {$IMPORTEDDATA ON} 12 | {$IOCHECKS ON} 13 | {$LOCALSYMBOLS ON} 14 | {$LONGSTRINGS ON} 15 | {$OPENSTRINGS ON} 16 | {$OPTIMIZATION OFF} 17 | {$OVERFLOWCHECKS OFF} 18 | {$RANGECHECKS OFF} 19 | {$REFERENCEINFO ON} 20 | {$SAFEDIVIDE OFF} 21 | {$STACKFRAMES ON} 22 | {$TYPEDADDRESS OFF} 23 | {$VARSTRINGCHECKS ON} 24 | {$WRITEABLECONST OFF} 25 | {$MINENUMSIZE 1} 26 | {$IMAGEBASE $400000} 27 | {$DEFINE DEBUG} 28 | {$ENDIF IMPLICITBUILDING} 29 | {$DESCRIPTION 'WebUpdate Non-Visual'} 30 | {$LIBSUFFIX '250'} 31 | {$DESIGNONLY} 32 | {$IMPLICITBUILD OFF} 33 | 34 | requires 35 | DesignIDE, 36 | WebUpdateR; 37 | 38 | contains 39 | WebUpdate.Package.Reg in '..\..\Source\Package\WebUpdate.Package.Reg.pas'; 40 | 41 | end. 42 | 43 | -------------------------------------------------------------------------------- /Packages/XE2/WebUpdateD.dpk: -------------------------------------------------------------------------------- 1 | package WebUpdateD; 2 | 3 | {$R *.res} 4 | {$R '..\WebUpdateD.dcr'} 5 | {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} 6 | {$ALIGN 8} 7 | {$ASSERTIONS ON} 8 | {$BOOLEVAL OFF} 9 | {$DEBUGINFO ON} 10 | {$EXTENDEDSYNTAX ON} 11 | {$IMPORTEDDATA ON} 12 | {$IOCHECKS ON} 13 | {$LOCALSYMBOLS ON} 14 | {$LONGSTRINGS ON} 15 | {$OPENSTRINGS ON} 16 | {$OPTIMIZATION OFF} 17 | {$OVERFLOWCHECKS OFF} 18 | {$RANGECHECKS OFF} 19 | {$REFERENCEINFO ON} 20 | {$SAFEDIVIDE OFF} 21 | {$STACKFRAMES ON} 22 | {$TYPEDADDRESS OFF} 23 | {$VARSTRINGCHECKS ON} 24 | {$WRITEABLECONST OFF} 25 | {$MINENUMSIZE 1} 26 | {$IMAGEBASE $400000} 27 | {$DEFINE DEBUG} 28 | {$ENDIF IMPLICITBUILDING} 29 | {$DESCRIPTION 'WebUpdate Non-Visual'} 30 | {$LIBSUFFIX '160'} 31 | {$DESIGNONLY} 32 | {$IMPLICITBUILD OFF} 33 | 34 | requires 35 | DesignIDE, 36 | WebUpdateR; 37 | 38 | contains 39 | WebUpdate.Package.Reg in '..\..\Source\Package\WebUpdate.Package.Reg.pas'; 40 | 41 | end. 42 | 43 | -------------------------------------------------------------------------------- /Packages/XE3/WebUpdateD.dpk: -------------------------------------------------------------------------------- 1 | package WebUpdateD; 2 | 3 | {$R *.res} 4 | {$R '..\WebUpdateD.dcr'} 5 | {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} 6 | {$ALIGN 8} 7 | {$ASSERTIONS ON} 8 | {$BOOLEVAL OFF} 9 | {$DEBUGINFO ON} 10 | {$EXTENDEDSYNTAX ON} 11 | {$IMPORTEDDATA ON} 12 | {$IOCHECKS ON} 13 | {$LOCALSYMBOLS ON} 14 | {$LONGSTRINGS ON} 15 | {$OPENSTRINGS ON} 16 | {$OPTIMIZATION OFF} 17 | {$OVERFLOWCHECKS OFF} 18 | {$RANGECHECKS OFF} 19 | {$REFERENCEINFO ON} 20 | {$SAFEDIVIDE OFF} 21 | {$STACKFRAMES ON} 22 | {$TYPEDADDRESS OFF} 23 | {$VARSTRINGCHECKS ON} 24 | {$WRITEABLECONST OFF} 25 | {$MINENUMSIZE 1} 26 | {$IMAGEBASE $400000} 27 | {$DEFINE DEBUG} 28 | {$ENDIF IMPLICITBUILDING} 29 | {$DESCRIPTION 'WebUpdate Non-Visual'} 30 | {$LIBSUFFIX '170'} 31 | {$DESIGNONLY} 32 | {$IMPLICITBUILD OFF} 33 | 34 | requires 35 | DesignIDE, 36 | WebUpdateR; 37 | 38 | contains 39 | WebUpdate.Package.Reg in '..\..\Source\Package\WebUpdate.Package.Reg.pas'; 40 | 41 | end. 42 | 43 | -------------------------------------------------------------------------------- /Packages/XE4/WebUpdateD.dpk: -------------------------------------------------------------------------------- 1 | package WebUpdateD; 2 | 3 | {$R *.res} 4 | {$R '..\WebUpdateD.dcr'} 5 | {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} 6 | {$ALIGN 8} 7 | {$ASSERTIONS ON} 8 | {$BOOLEVAL OFF} 9 | {$DEBUGINFO ON} 10 | {$EXTENDEDSYNTAX ON} 11 | {$IMPORTEDDATA ON} 12 | {$IOCHECKS ON} 13 | {$LOCALSYMBOLS ON} 14 | {$LONGSTRINGS ON} 15 | {$OPENSTRINGS ON} 16 | {$OPTIMIZATION OFF} 17 | {$OVERFLOWCHECKS OFF} 18 | {$RANGECHECKS OFF} 19 | {$REFERENCEINFO ON} 20 | {$SAFEDIVIDE OFF} 21 | {$STACKFRAMES ON} 22 | {$TYPEDADDRESS OFF} 23 | {$VARSTRINGCHECKS ON} 24 | {$WRITEABLECONST OFF} 25 | {$MINENUMSIZE 1} 26 | {$IMAGEBASE $400000} 27 | {$DEFINE DEBUG} 28 | {$ENDIF IMPLICITBUILDING} 29 | {$DESCRIPTION 'WebUpdate Non-Visual'} 30 | {$LIBSUFFIX '180'} 31 | {$DESIGNONLY} 32 | {$IMPLICITBUILD OFF} 33 | 34 | requires 35 | DesignIDE, 36 | WebUpdateR; 37 | 38 | contains 39 | WebUpdate.Package.Reg in '..\..\Source\Package\WebUpdate.Package.Reg.pas'; 40 | 41 | end. 42 | 43 | -------------------------------------------------------------------------------- /Packages/XE5/WebUpdateD.dpk: -------------------------------------------------------------------------------- 1 | package WebUpdateD; 2 | 3 | {$R *.res} 4 | {$R '..\WebUpdateD.dcr'} 5 | {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} 6 | {$ALIGN 8} 7 | {$ASSERTIONS ON} 8 | {$BOOLEVAL OFF} 9 | {$DEBUGINFO ON} 10 | {$EXTENDEDSYNTAX ON} 11 | {$IMPORTEDDATA ON} 12 | {$IOCHECKS ON} 13 | {$LOCALSYMBOLS ON} 14 | {$LONGSTRINGS ON} 15 | {$OPENSTRINGS ON} 16 | {$OPTIMIZATION OFF} 17 | {$OVERFLOWCHECKS OFF} 18 | {$RANGECHECKS OFF} 19 | {$REFERENCEINFO ON} 20 | {$SAFEDIVIDE OFF} 21 | {$STACKFRAMES ON} 22 | {$TYPEDADDRESS OFF} 23 | {$VARSTRINGCHECKS ON} 24 | {$WRITEABLECONST OFF} 25 | {$MINENUMSIZE 1} 26 | {$IMAGEBASE $400000} 27 | {$DEFINE DEBUG} 28 | {$ENDIF IMPLICITBUILDING} 29 | {$DESCRIPTION 'WebUpdate Non-Visual'} 30 | {$LIBSUFFIX '190'} 31 | {$DESIGNONLY} 32 | {$IMPLICITBUILD OFF} 33 | 34 | requires 35 | DesignIDE, 36 | WebUpdateR; 37 | 38 | contains 39 | WebUpdate.Package.Reg in '..\..\Source\Package\WebUpdate.Package.Reg.pas'; 40 | 41 | end. 42 | 43 | -------------------------------------------------------------------------------- /Packages/XE6/WebUpdateD.dpk: -------------------------------------------------------------------------------- 1 | package WebUpdateD; 2 | 3 | {$R *.res} 4 | {$R '..\WebUpdateD.dcr'} 5 | {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} 6 | {$ALIGN 8} 7 | {$ASSERTIONS ON} 8 | {$BOOLEVAL OFF} 9 | {$DEBUGINFO ON} 10 | {$EXTENDEDSYNTAX ON} 11 | {$IMPORTEDDATA ON} 12 | {$IOCHECKS ON} 13 | {$LOCALSYMBOLS ON} 14 | {$LONGSTRINGS ON} 15 | {$OPENSTRINGS ON} 16 | {$OPTIMIZATION OFF} 17 | {$OVERFLOWCHECKS OFF} 18 | {$RANGECHECKS OFF} 19 | {$REFERENCEINFO ON} 20 | {$SAFEDIVIDE OFF} 21 | {$STACKFRAMES ON} 22 | {$TYPEDADDRESS OFF} 23 | {$VARSTRINGCHECKS ON} 24 | {$WRITEABLECONST OFF} 25 | {$MINENUMSIZE 1} 26 | {$IMAGEBASE $400000} 27 | {$DEFINE DEBUG} 28 | {$ENDIF IMPLICITBUILDING} 29 | {$DESCRIPTION 'WebUpdate Non-Visual'} 30 | {$LIBSUFFIX '200'} 31 | {$DESIGNONLY} 32 | {$IMPLICITBUILD OFF} 33 | 34 | requires 35 | DesignIDE, 36 | WebUpdateR; 37 | 38 | contains 39 | WebUpdate.Package.Reg in '..\..\Source\Package\WebUpdate.Package.Reg.pas'; 40 | 41 | end. 42 | 43 | -------------------------------------------------------------------------------- /Packages/XE7/WebUpdateD.dpk: -------------------------------------------------------------------------------- 1 | package WebUpdateD; 2 | 3 | {$R *.res} 4 | {$R '..\WebUpdateD.dcr'} 5 | {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} 6 | {$ALIGN 8} 7 | {$ASSERTIONS ON} 8 | {$BOOLEVAL OFF} 9 | {$DEBUGINFO OFF} 10 | {$EXTENDEDSYNTAX ON} 11 | {$IMPORTEDDATA ON} 12 | {$IOCHECKS ON} 13 | {$LOCALSYMBOLS ON} 14 | {$LONGSTRINGS ON} 15 | {$OPENSTRINGS ON} 16 | {$OPTIMIZATION OFF} 17 | {$OVERFLOWCHECKS OFF} 18 | {$RANGECHECKS OFF} 19 | {$REFERENCEINFO ON} 20 | {$SAFEDIVIDE OFF} 21 | {$STACKFRAMES ON} 22 | {$TYPEDADDRESS OFF} 23 | {$VARSTRINGCHECKS ON} 24 | {$WRITEABLECONST OFF} 25 | {$MINENUMSIZE 1} 26 | {$IMAGEBASE $400000} 27 | {$DEFINE DEBUG} 28 | {$ENDIF IMPLICITBUILDING} 29 | {$DESCRIPTION 'WebUpdate Non-Visual'} 30 | {$LIBSUFFIX '210'} 31 | {$DESIGNONLY} 32 | {$IMPLICITBUILD OFF} 33 | 34 | requires 35 | DesignIDE, 36 | WebUpdateR; 37 | 38 | contains 39 | WebUpdate.Package.Reg in '..\..\Source\Package\WebUpdate.Package.Reg.pas'; 40 | 41 | end. 42 | 43 | -------------------------------------------------------------------------------- /Packages/XE8/WebUpdateD.dpk: -------------------------------------------------------------------------------- 1 | package WebUpdateD; 2 | 3 | {$R *.res} 4 | {$R '..\WebUpdateD.dcr'} 5 | {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} 6 | {$ALIGN 8} 7 | {$ASSERTIONS ON} 8 | {$BOOLEVAL OFF} 9 | {$DEBUGINFO OFF} 10 | {$EXTENDEDSYNTAX ON} 11 | {$IMPORTEDDATA ON} 12 | {$IOCHECKS ON} 13 | {$LOCALSYMBOLS ON} 14 | {$LONGSTRINGS ON} 15 | {$OPENSTRINGS ON} 16 | {$OPTIMIZATION OFF} 17 | {$OVERFLOWCHECKS OFF} 18 | {$RANGECHECKS OFF} 19 | {$REFERENCEINFO ON} 20 | {$SAFEDIVIDE OFF} 21 | {$STACKFRAMES ON} 22 | {$TYPEDADDRESS OFF} 23 | {$VARSTRINGCHECKS ON} 24 | {$WRITEABLECONST OFF} 25 | {$MINENUMSIZE 1} 26 | {$IMAGEBASE $400000} 27 | {$DEFINE DEBUG} 28 | {$ENDIF IMPLICITBUILDING} 29 | {$DESCRIPTION 'WebUpdate Non-Visual'} 30 | {$LIBSUFFIX '220'} 31 | {$DESIGNONLY} 32 | {$IMPLICITBUILD OFF} 33 | 34 | requires 35 | DesignIDE, 36 | WebUpdateR; 37 | 38 | contains 39 | WebUpdate.Package.Reg in '..\..\Source\Package\WebUpdate.Package.Reg.pas'; 40 | 41 | end. 42 | 43 | -------------------------------------------------------------------------------- /Source/Authoring Tool/AuthoringTool.dpr: -------------------------------------------------------------------------------- 1 | program AuthoringTool; 2 | 3 | uses 4 | Vcl.Forms, 5 | WebUpdate.Classes.WebUpdate in '..\Common\WebUpdate.Classes.WebUpdate.pas', 6 | WebUpdate.GUI.About in 'WebUpdate.GUI.About.pas' {FormAbout}, 7 | WebUpdate.GUI.AuthorTool in 'WebUpdate.GUI.AuthorTool.pas' {FormWebUpdateTool}, 8 | WebUpdate.GUI.Options in 'WebUpdate.GUI.Options.pas' {FormOptions}, 9 | WebUpdate.GUI.CommandLine in 'WebUpdate.GUI.CommandLine.pas' {FormCommandLine}, 10 | WebUpdate.JSON.Channel in '..\Common\WebUpdate.JSON.Channel.pas', 11 | WebUpdate.JSON.Channels in '..\Common\WebUpdate.JSON.Channels.pas', 12 | WebUpdate.JSON.Preferences in 'WebUpdate.JSON.Preferences.pas', 13 | WebUpdate.JSON.Project in '..\Common\WebUpdate.JSON.Project.pas', 14 | WebUpdate.JSON.Serializer in '..\Common\WebUpdate.JSON.Serializer.pas', 15 | WebUpdate.Tools in '..\Common\WebUpdate.Tools.pas'; 16 | 17 | {$R *.res} 18 | 19 | begin 20 | Application.Initialize; 21 | Application.MainFormOnTaskbar := True; 22 | Application.CreateForm(TFormWebUpdateTool, FormWebUpdateTool); 23 | Application.Run; 24 | end. 25 | 26 | -------------------------------------------------------------------------------- /Packages/RX/WebUpdateR.dpk: -------------------------------------------------------------------------------- 1 | package WebUpdateR; 2 | 3 | {$R *.res} 4 | {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} 5 | {$ALIGN 8} 6 | {$ASSERTIONS ON} 7 | {$BOOLEVAL OFF} 8 | {$DEBUGINFO OFF} 9 | {$EXTENDEDSYNTAX ON} 10 | {$IMPORTEDDATA ON} 11 | {$IOCHECKS ON} 12 | {$LOCALSYMBOLS ON} 13 | {$LONGSTRINGS ON} 14 | {$OPENSTRINGS ON} 15 | {$OPTIMIZATION OFF} 16 | {$OVERFLOWCHECKS OFF} 17 | {$RANGECHECKS OFF} 18 | {$REFERENCEINFO ON} 19 | {$SAFEDIVIDE OFF} 20 | {$STACKFRAMES ON} 21 | {$TYPEDADDRESS OFF} 22 | {$VARSTRINGCHECKS ON} 23 | {$WRITEABLECONST OFF} 24 | {$MINENUMSIZE 1} 25 | {$IMAGEBASE $400000} 26 | {$DEFINE DEBUG} 27 | {$ENDIF IMPLICITBUILDING} 28 | {$LIBSUFFIX '230'} 29 | {$RUNONLY} 30 | {$IMPLICITBUILD OFF} 31 | 32 | requires 33 | vcl, 34 | IndyCore, 35 | IndySystem, 36 | IndyProtocols, 37 | dwsLibRuntime; 38 | 39 | contains 40 | WebUpdate.Tools in '..\..\Source\Common\WebUpdate.Tools.pas', 41 | WebUpdate.Classes.Updater in '..\..\Source\Common\WebUpdate.Classes.Updater.pas', 42 | WebUpdate.Classes.WebUpdate in '..\..\Source\Common\WebUpdate.Classes.WebUpdate.pas', 43 | WebUpdate.JSON.Channels in '..\..\Source\Common\WebUpdate.JSON.Channels.pas', 44 | WebUpdate.JSON.Channel in '..\..\Source\Common\WebUpdate.JSON.Channel.pas', 45 | WebUpdate.JSON.Serializer in '..\..\Source\Common\WebUpdate.JSON.Serializer.pas', 46 | WebUpdate.Package.Component in '..\..\Source\Package\WebUpdate.Package.Component.pas'; 47 | 48 | end. 49 | 50 | -------------------------------------------------------------------------------- /Packages/XE3/WebUpdateR.dpk: -------------------------------------------------------------------------------- 1 | package WebUpdateR; 2 | 3 | {$R *.res} 4 | {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} 5 | {$ALIGN 8} 6 | {$ASSERTIONS ON} 7 | {$BOOLEVAL OFF} 8 | {$DEBUGINFO ON} 9 | {$EXTENDEDSYNTAX ON} 10 | {$IMPORTEDDATA ON} 11 | {$IOCHECKS ON} 12 | {$LOCALSYMBOLS ON} 13 | {$LONGSTRINGS ON} 14 | {$OPENSTRINGS ON} 15 | {$OPTIMIZATION OFF} 16 | {$OVERFLOWCHECKS OFF} 17 | {$RANGECHECKS OFF} 18 | {$REFERENCEINFO ON} 19 | {$SAFEDIVIDE OFF} 20 | {$STACKFRAMES ON} 21 | {$TYPEDADDRESS OFF} 22 | {$VARSTRINGCHECKS ON} 23 | {$WRITEABLECONST OFF} 24 | {$MINENUMSIZE 1} 25 | {$IMAGEBASE $400000} 26 | {$DEFINE DEBUG} 27 | {$ENDIF IMPLICITBUILDING} 28 | {$LIBSUFFIX '170'} 29 | {$RUNONLY} 30 | {$IMPLICITBUILD OFF} 31 | 32 | requires 33 | vcl, 34 | IndyCore, 35 | IndySystem, 36 | IndyProtocols, 37 | dwsLibRuntime; 38 | 39 | contains 40 | WebUpdate.Tools in '..\..\Source\Common\WebUpdate.Tools.pas', 41 | WebUpdate.Classes.Updater in '..\..\Source\Common\WebUpdate.Classes.Updater.pas', 42 | WebUpdate.Classes.WebUpdate in '..\..\Source\Common\WebUpdate.Classes.WebUpdate.pas', 43 | WebUpdate.JSON.Channels in '..\..\Source\Common\WebUpdate.JSON.Channels.pas', 44 | WebUpdate.JSON.Channel in '..\..\Source\Common\WebUpdate.JSON.Channel.pas', 45 | WebUpdate.JSON.Serializer in '..\..\Source\Common\WebUpdate.JSON.Serializer.pas', 46 | WebUpdate.Package.Component in '..\..\Source\Package\WebUpdate.Package.Component.pas'; 47 | 48 | end. 49 | 50 | -------------------------------------------------------------------------------- /Packages/XE4/WebUpdateR.dpk: -------------------------------------------------------------------------------- 1 | package WebUpdateR; 2 | 3 | {$R *.res} 4 | {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} 5 | {$ALIGN 8} 6 | {$ASSERTIONS ON} 7 | {$BOOLEVAL OFF} 8 | {$DEBUGINFO ON} 9 | {$EXTENDEDSYNTAX ON} 10 | {$IMPORTEDDATA ON} 11 | {$IOCHECKS ON} 12 | {$LOCALSYMBOLS ON} 13 | {$LONGSTRINGS ON} 14 | {$OPENSTRINGS ON} 15 | {$OPTIMIZATION OFF} 16 | {$OVERFLOWCHECKS OFF} 17 | {$RANGECHECKS OFF} 18 | {$REFERENCEINFO ON} 19 | {$SAFEDIVIDE OFF} 20 | {$STACKFRAMES ON} 21 | {$TYPEDADDRESS OFF} 22 | {$VARSTRINGCHECKS ON} 23 | {$WRITEABLECONST OFF} 24 | {$MINENUMSIZE 1} 25 | {$IMAGEBASE $400000} 26 | {$DEFINE DEBUG} 27 | {$ENDIF IMPLICITBUILDING} 28 | {$LIBSUFFIX '180'} 29 | {$RUNONLY} 30 | {$IMPLICITBUILD OFF} 31 | 32 | requires 33 | vcl, 34 | IndyCore, 35 | IndySystem, 36 | IndyProtocols, 37 | dwsLibRuntime; 38 | 39 | contains 40 | WebUpdate.Tools in '..\..\Source\Common\WebUpdate.Tools.pas', 41 | WebUpdate.Classes.Updater in '..\..\Source\Common\WebUpdate.Classes.Updater.pas', 42 | WebUpdate.Classes.WebUpdate in '..\..\Source\Common\WebUpdate.Classes.WebUpdate.pas', 43 | WebUpdate.JSON.Channels in '..\..\Source\Common\WebUpdate.JSON.Channels.pas', 44 | WebUpdate.JSON.Channel in '..\..\Source\Common\WebUpdate.JSON.Channel.pas', 45 | WebUpdate.JSON.Serializer in '..\..\Source\Common\WebUpdate.JSON.Serializer.pas', 46 | WebUpdate.Package.Component in '..\..\Source\Package\WebUpdate.Package.Component.pas'; 47 | 48 | end. 49 | 50 | -------------------------------------------------------------------------------- /Packages/XE5/WebUpdateR.dpk: -------------------------------------------------------------------------------- 1 | package WebUpdateR; 2 | 3 | {$R *.res} 4 | {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} 5 | {$ALIGN 8} 6 | {$ASSERTIONS ON} 7 | {$BOOLEVAL OFF} 8 | {$DEBUGINFO ON} 9 | {$EXTENDEDSYNTAX ON} 10 | {$IMPORTEDDATA ON} 11 | {$IOCHECKS ON} 12 | {$LOCALSYMBOLS ON} 13 | {$LONGSTRINGS ON} 14 | {$OPENSTRINGS ON} 15 | {$OPTIMIZATION OFF} 16 | {$OVERFLOWCHECKS OFF} 17 | {$RANGECHECKS OFF} 18 | {$REFERENCEINFO ON} 19 | {$SAFEDIVIDE OFF} 20 | {$STACKFRAMES ON} 21 | {$TYPEDADDRESS OFF} 22 | {$VARSTRINGCHECKS ON} 23 | {$WRITEABLECONST OFF} 24 | {$MINENUMSIZE 1} 25 | {$IMAGEBASE $400000} 26 | {$DEFINE DEBUG} 27 | {$ENDIF IMPLICITBUILDING} 28 | {$LIBSUFFIX '190'} 29 | {$RUNONLY} 30 | {$IMPLICITBUILD OFF} 31 | 32 | requires 33 | vcl, 34 | IndyCore, 35 | IndySystem, 36 | IndyProtocols, 37 | dwsLibRuntime; 38 | 39 | contains 40 | WebUpdate.Tools in '..\..\Source\Common\WebUpdate.Tools.pas', 41 | WebUpdate.Classes.Updater in '..\..\Source\Common\WebUpdate.Classes.Updater.pas', 42 | WebUpdate.Classes.WebUpdate in '..\..\Source\Common\WebUpdate.Classes.WebUpdate.pas', 43 | WebUpdate.JSON.Channels in '..\..\Source\Common\WebUpdate.JSON.Channels.pas', 44 | WebUpdate.JSON.Channel in '..\..\Source\Common\WebUpdate.JSON.Channel.pas', 45 | WebUpdate.JSON.Serializer in '..\..\Source\Common\WebUpdate.JSON.Serializer.pas', 46 | WebUpdate.Package.Component in '..\..\Source\Package\WebUpdate.Package.Component.pas'; 47 | 48 | end. 49 | 50 | -------------------------------------------------------------------------------- /Packages/XE6/WebUpdateR.dpk: -------------------------------------------------------------------------------- 1 | package WebUpdateR; 2 | 3 | {$R *.res} 4 | {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} 5 | {$ALIGN 8} 6 | {$ASSERTIONS ON} 7 | {$BOOLEVAL OFF} 8 | {$DEBUGINFO ON} 9 | {$EXTENDEDSYNTAX ON} 10 | {$IMPORTEDDATA ON} 11 | {$IOCHECKS ON} 12 | {$LOCALSYMBOLS ON} 13 | {$LONGSTRINGS ON} 14 | {$OPENSTRINGS ON} 15 | {$OPTIMIZATION OFF} 16 | {$OVERFLOWCHECKS OFF} 17 | {$RANGECHECKS OFF} 18 | {$REFERENCEINFO ON} 19 | {$SAFEDIVIDE OFF} 20 | {$STACKFRAMES ON} 21 | {$TYPEDADDRESS OFF} 22 | {$VARSTRINGCHECKS ON} 23 | {$WRITEABLECONST OFF} 24 | {$MINENUMSIZE 1} 25 | {$IMAGEBASE $400000} 26 | {$DEFINE DEBUG} 27 | {$ENDIF IMPLICITBUILDING} 28 | {$LIBSUFFIX '200'} 29 | {$RUNONLY} 30 | {$IMPLICITBUILD OFF} 31 | 32 | requires 33 | vcl, 34 | IndyCore, 35 | IndySystem, 36 | IndyProtocols, 37 | dwsLibRuntime; 38 | 39 | contains 40 | WebUpdate.Tools in '..\..\Source\Common\WebUpdate.Tools.pas', 41 | WebUpdate.Classes.Updater in '..\..\Source\Common\WebUpdate.Classes.Updater.pas', 42 | WebUpdate.Classes.WebUpdate in '..\..\Source\Common\WebUpdate.Classes.WebUpdate.pas', 43 | WebUpdate.JSON.Channels in '..\..\Source\Common\WebUpdate.JSON.Channels.pas', 44 | WebUpdate.JSON.Channel in '..\..\Source\Common\WebUpdate.JSON.Channel.pas', 45 | WebUpdate.JSON.Serializer in '..\..\Source\Common\WebUpdate.JSON.Serializer.pas', 46 | WebUpdate.Package.Component in '..\..\Source\Package\WebUpdate.Package.Component.pas'; 47 | 48 | end. 49 | 50 | -------------------------------------------------------------------------------- /Packages/RX1/WebUpdateR.dpk: -------------------------------------------------------------------------------- 1 | package WebUpdateR; 2 | 3 | {$R *.res} 4 | {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} 5 | {$ALIGN 8} 6 | {$ASSERTIONS ON} 7 | {$BOOLEVAL OFF} 8 | {$DEBUGINFO OFF} 9 | {$EXTENDEDSYNTAX ON} 10 | {$IMPORTEDDATA ON} 11 | {$IOCHECKS ON} 12 | {$LOCALSYMBOLS ON} 13 | {$LONGSTRINGS ON} 14 | {$OPENSTRINGS ON} 15 | {$OPTIMIZATION OFF} 16 | {$OVERFLOWCHECKS OFF} 17 | {$RANGECHECKS OFF} 18 | {$REFERENCEINFO ON} 19 | {$SAFEDIVIDE OFF} 20 | {$STACKFRAMES ON} 21 | {$TYPEDADDRESS OFF} 22 | {$VARSTRINGCHECKS ON} 23 | {$WRITEABLECONST OFF} 24 | {$MINENUMSIZE 1} 25 | {$IMAGEBASE $400000} 26 | {$DEFINE DEBUG} 27 | {$ENDIF IMPLICITBUILDING} 28 | {$LIBSUFFIX '240'} 29 | {$RUNONLY} 30 | {$IMPLICITBUILD OFF} 31 | 32 | requires 33 | vcl, 34 | IndyCore, 35 | IndySystem, 36 | IndyProtocols, 37 | dwsLibRuntime; 38 | 39 | contains 40 | WebUpdate.Tools in '..\..\Source\Common\WebUpdate.Tools.pas', 41 | WebUpdate.Classes.Updater in '..\..\Source\Common\WebUpdate.Classes.Updater.pas', 42 | WebUpdate.Classes.WebUpdate in '..\..\Source\Common\WebUpdate.Classes.WebUpdate.pas', 43 | WebUpdate.JSON.Channels in '..\..\Source\Common\WebUpdate.JSON.Channels.pas', 44 | WebUpdate.JSON.Channel in '..\..\Source\Common\WebUpdate.JSON.Channel.pas', 45 | WebUpdate.JSON.Serializer in '..\..\Source\Common\WebUpdate.JSON.Serializer.pas', 46 | WebUpdate.Package.Component in '..\..\Source\Package\WebUpdate.Package.Component.pas'; 47 | 48 | end. 49 | 50 | -------------------------------------------------------------------------------- /Packages/RX2/WebUpdateR.dpk: -------------------------------------------------------------------------------- 1 | package WebUpdateR; 2 | 3 | {$R *.res} 4 | {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} 5 | {$ALIGN 8} 6 | {$ASSERTIONS ON} 7 | {$BOOLEVAL OFF} 8 | {$DEBUGINFO OFF} 9 | {$EXTENDEDSYNTAX ON} 10 | {$IMPORTEDDATA ON} 11 | {$IOCHECKS ON} 12 | {$LOCALSYMBOLS ON} 13 | {$LONGSTRINGS ON} 14 | {$OPENSTRINGS ON} 15 | {$OPTIMIZATION OFF} 16 | {$OVERFLOWCHECKS OFF} 17 | {$RANGECHECKS OFF} 18 | {$REFERENCEINFO ON} 19 | {$SAFEDIVIDE OFF} 20 | {$STACKFRAMES ON} 21 | {$TYPEDADDRESS OFF} 22 | {$VARSTRINGCHECKS ON} 23 | {$WRITEABLECONST OFF} 24 | {$MINENUMSIZE 1} 25 | {$IMAGEBASE $400000} 26 | {$DEFINE DEBUG} 27 | {$ENDIF IMPLICITBUILDING} 28 | {$LIBSUFFIX '250'} 29 | {$RUNONLY} 30 | {$IMPLICITBUILD OFF} 31 | 32 | requires 33 | vcl, 34 | IndyCore, 35 | IndySystem, 36 | IndyProtocols, 37 | dwsLibRuntime; 38 | 39 | contains 40 | WebUpdate.Tools in '..\..\Source\Common\WebUpdate.Tools.pas', 41 | WebUpdate.Classes.Updater in '..\..\Source\Common\WebUpdate.Classes.Updater.pas', 42 | WebUpdate.Classes.WebUpdate in '..\..\Source\Common\WebUpdate.Classes.WebUpdate.pas', 43 | WebUpdate.JSON.Channels in '..\..\Source\Common\WebUpdate.JSON.Channels.pas', 44 | WebUpdate.JSON.Channel in '..\..\Source\Common\WebUpdate.JSON.Channel.pas', 45 | WebUpdate.JSON.Serializer in '..\..\Source\Common\WebUpdate.JSON.Serializer.pas', 46 | WebUpdate.Package.Component in '..\..\Source\Package\WebUpdate.Package.Component.pas'; 47 | 48 | end. 49 | 50 | -------------------------------------------------------------------------------- /Packages/XE7/WebUpdateR.dpk: -------------------------------------------------------------------------------- 1 | package WebUpdateR; 2 | 3 | {$R *.res} 4 | {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} 5 | {$ALIGN 8} 6 | {$ASSERTIONS ON} 7 | {$BOOLEVAL OFF} 8 | {$DEBUGINFO OFF} 9 | {$EXTENDEDSYNTAX ON} 10 | {$IMPORTEDDATA ON} 11 | {$IOCHECKS ON} 12 | {$LOCALSYMBOLS ON} 13 | {$LONGSTRINGS ON} 14 | {$OPENSTRINGS ON} 15 | {$OPTIMIZATION OFF} 16 | {$OVERFLOWCHECKS OFF} 17 | {$RANGECHECKS OFF} 18 | {$REFERENCEINFO ON} 19 | {$SAFEDIVIDE OFF} 20 | {$STACKFRAMES ON} 21 | {$TYPEDADDRESS OFF} 22 | {$VARSTRINGCHECKS ON} 23 | {$WRITEABLECONST OFF} 24 | {$MINENUMSIZE 1} 25 | {$IMAGEBASE $400000} 26 | {$DEFINE DEBUG} 27 | {$ENDIF IMPLICITBUILDING} 28 | {$LIBSUFFIX '210'} 29 | {$RUNONLY} 30 | {$IMPLICITBUILD OFF} 31 | 32 | requires 33 | vcl, 34 | IndyCore, 35 | IndySystem, 36 | IndyProtocols, 37 | dwsLibRuntime; 38 | 39 | contains 40 | WebUpdate.Tools in '..\..\Source\Common\WebUpdate.Tools.pas', 41 | WebUpdate.Classes.Updater in '..\..\Source\Common\WebUpdate.Classes.Updater.pas', 42 | WebUpdate.Classes.WebUpdate in '..\..\Source\Common\WebUpdate.Classes.WebUpdate.pas', 43 | WebUpdate.JSON.Channels in '..\..\Source\Common\WebUpdate.JSON.Channels.pas', 44 | WebUpdate.JSON.Channel in '..\..\Source\Common\WebUpdate.JSON.Channel.pas', 45 | WebUpdate.JSON.Serializer in '..\..\Source\Common\WebUpdate.JSON.Serializer.pas', 46 | WebUpdate.Package.Component in '..\..\Source\Package\WebUpdate.Package.Component.pas'; 47 | 48 | end. 49 | 50 | -------------------------------------------------------------------------------- /Packages/XE8/WebUpdateR.dpk: -------------------------------------------------------------------------------- 1 | package WebUpdateR; 2 | 3 | {$R *.res} 4 | {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} 5 | {$ALIGN 8} 6 | {$ASSERTIONS ON} 7 | {$BOOLEVAL OFF} 8 | {$DEBUGINFO OFF} 9 | {$EXTENDEDSYNTAX ON} 10 | {$IMPORTEDDATA ON} 11 | {$IOCHECKS ON} 12 | {$LOCALSYMBOLS ON} 13 | {$LONGSTRINGS ON} 14 | {$OPENSTRINGS ON} 15 | {$OPTIMIZATION OFF} 16 | {$OVERFLOWCHECKS OFF} 17 | {$RANGECHECKS OFF} 18 | {$REFERENCEINFO ON} 19 | {$SAFEDIVIDE OFF} 20 | {$STACKFRAMES ON} 21 | {$TYPEDADDRESS OFF} 22 | {$VARSTRINGCHECKS ON} 23 | {$WRITEABLECONST OFF} 24 | {$MINENUMSIZE 1} 25 | {$IMAGEBASE $400000} 26 | {$DEFINE DEBUG} 27 | {$ENDIF IMPLICITBUILDING} 28 | {$LIBSUFFIX '220'} 29 | {$RUNONLY} 30 | {$IMPLICITBUILD OFF} 31 | 32 | requires 33 | vcl, 34 | IndyCore, 35 | IndySystem, 36 | IndyProtocols, 37 | dwsLibRuntime; 38 | 39 | contains 40 | WebUpdate.Tools in '..\..\Source\Common\WebUpdate.Tools.pas', 41 | WebUpdate.Classes.Updater in '..\..\Source\Common\WebUpdate.Classes.Updater.pas', 42 | WebUpdate.Classes.WebUpdate in '..\..\Source\Common\WebUpdate.Classes.WebUpdate.pas', 43 | WebUpdate.JSON.Channels in '..\..\Source\Common\WebUpdate.JSON.Channels.pas', 44 | WebUpdate.JSON.Channel in '..\..\Source\Common\WebUpdate.JSON.Channel.pas', 45 | WebUpdate.JSON.Serializer in '..\..\Source\Common\WebUpdate.JSON.Serializer.pas', 46 | WebUpdate.Package.Component in '..\..\Source\Package\WebUpdate.Package.Component.pas'; 47 | 48 | end. 49 | 50 | -------------------------------------------------------------------------------- /Packages/XE2/WebUpdateR.dpk: -------------------------------------------------------------------------------- 1 | package WebUpdateR; 2 | 3 | {$R *.res} 4 | {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} 5 | {$ALIGN 8} 6 | {$ASSERTIONS ON} 7 | {$BOOLEVAL OFF} 8 | {$DEBUGINFO ON} 9 | {$EXTENDEDSYNTAX ON} 10 | {$IMPORTEDDATA ON} 11 | {$IOCHECKS ON} 12 | {$LOCALSYMBOLS ON} 13 | {$LONGSTRINGS ON} 14 | {$OPENSTRINGS ON} 15 | {$OPTIMIZATION OFF} 16 | {$OVERFLOWCHECKS OFF} 17 | {$RANGECHECKS OFF} 18 | {$REFERENCEINFO ON} 19 | {$SAFEDIVIDE OFF} 20 | {$STACKFRAMES ON} 21 | {$TYPEDADDRESS OFF} 22 | {$VARSTRINGCHECKS ON} 23 | {$WRITEABLECONST OFF} 24 | {$MINENUMSIZE 1} 25 | {$IMAGEBASE $400000} 26 | {$DEFINE DEBUG} 27 | {$ENDIF IMPLICITBUILDING} 28 | {$DESCRIPTION 'WebUpdate Non-Visual runtime'} 29 | {$LIBSUFFIX '160'} 30 | {$RUNONLY} 31 | {$IMPLICITBUILD OFF} 32 | 33 | requires 34 | vcl, 35 | IndyCore, 36 | IndySystem, 37 | IndyProtocols, 38 | dwsLibRuntime; 39 | 40 | contains 41 | WebUpdate.Tools in '..\..\Source\Common\WebUpdate.Tools.pas', 42 | WebUpdate.Classes.Updater in '..\..\Source\Common\WebUpdate.Classes.Updater.pas', 43 | WebUpdate.Classes.WebUpdate in '..\..\Source\Common\WebUpdate.Classes.WebUpdate.pas', 44 | WebUpdate.JSON.Channels in '..\..\Source\Common\WebUpdate.JSON.Channels.pas', 45 | WebUpdate.JSON.Channel in '..\..\Source\Common\WebUpdate.JSON.Channel.pas', 46 | WebUpdate.JSON.Serializer in '..\..\Source\Common\WebUpdate.JSON.Serializer.pas', 47 | WebUpdate.Package.Component in '..\..\Source\Package\WebUpdate.Package.Component.pas'; 48 | 49 | end. 50 | 51 | -------------------------------------------------------------------------------- /Source/Example Application/MainUnit.dfm: -------------------------------------------------------------------------------- 1 | object FormExample: TFormExample 2 | Left = 0 3 | Top = 0 4 | Caption = 'Example Application' 5 | ClientHeight = 128 6 | ClientWidth = 201 7 | Color = clBtnFace 8 | Font.Charset = DEFAULT_CHARSET 9 | Font.Color = clWindowText 10 | Font.Height = -11 11 | Font.Name = 'Tahoma' 12 | Font.Style = [] 13 | OldCreateOrder = False 14 | OnCreate = FormCreate 15 | OnDestroy = FormDestroy 16 | OnShow = FormShow 17 | PixelsPerInch = 96 18 | TextHeight = 13 19 | object LabelChannel: TLabel 20 | Left = 8 21 | Top = 11 22 | Width = 43 23 | Height = 13 24 | Caption = 'Channel:' 25 | end 26 | object ButtonCheckUpdates: TButton 27 | Left = 8 28 | Top = 35 29 | Width = 185 30 | Height = 25 31 | Caption = '&Check for Updates' 32 | Default = True 33 | TabOrder = 0 34 | OnClick = ButtonCheckUpdatesClick 35 | end 36 | object ButtonExit: TButton 37 | Left = 8 38 | Top = 97 39 | Width = 185 40 | Height = 25 41 | Caption = 'E&xit' 42 | TabOrder = 1 43 | OnClick = ButtonExitClick 44 | end 45 | object ButtonPerformUpdate: TButton 46 | Left = 8 47 | Top = 66 48 | Width = 185 49 | Height = 25 50 | Caption = 'Perform &Update' 51 | TabOrder = 2 52 | OnClick = ButtonPerformUpdateClick 53 | end 54 | object ComboBoxChannels: TComboBox 55 | Left = 57 56 | Top = 8 57 | Width = 136 58 | Height = 21 59 | Style = csDropDownList 60 | TabOrder = 3 61 | OnChange = ComboBoxChannelsChange 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /Packages/XE2/Packages.groupproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | {B0BE1F5A-716F-458F-A2E9-1E695A5535D7} 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Default.Personality.12 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Delphinus.Install.json: -------------------------------------------------------------------------------- 1 | { 2 | "search_pathes": 3 | [ 4 | { 5 | "pathes": "Common;Package", 6 | "platforms": "Win32;Win64;OSX32" 7 | } 8 | ], 9 | "browsing_pathes": 10 | [ 11 | { 12 | "pathes": "Common;Package", 13 | "platforms": "Win32;Win64;OSX32" 14 | } 15 | ], 16 | 17 | "source_folders": 18 | [ 19 | { 20 | "folder": "Source", 21 | "base": "Source", 22 | "recursive": true, 23 | "filter": "*;*.*" 24 | } 25 | ], 26 | 27 | "projects": 28 | [ 29 | { 30 | "project": "Packages\\XE2\\Packages.groupproj", 31 | "compiler_min": 23, 32 | "compiler_max": 23 33 | }, 34 | { 35 | "project": "Packages\\XE3\\Packages.groupproj", 36 | "compiler_min": 24, 37 | "compiler_max": 24 38 | }, 39 | { 40 | "project": "Packages\\XE4\\Packages.groupproj", 41 | "compiler_min": 25, 42 | "compiler_max": 25 43 | }, 44 | { 45 | "project": "Packages\\XE5\\Packages.groupproj", 46 | "compiler_min": 26, 47 | "compiler_max": 26 48 | }, 49 | { 50 | "project": "Packages\\XE6\\Packages.groupproj", 51 | "compiler_min": 27, 52 | "compiler_max": 27 53 | }, 54 | { 55 | "project": "Packages\\XE7\\Packages.groupproj", 56 | "compiler_min": 28, 57 | "compiler_max": 28 58 | }, 59 | { 60 | "project": "Packages\\XE8\\Packages.groupproj", 61 | "compiler_min": 29, 62 | "compiler_max": 29 63 | }, 64 | { 65 | "project": "Packages\\RX\\Packages.groupproj", 66 | "compiler_min": 30, 67 | "compiler_max": 30 68 | }, 69 | { 70 | "project": "Packages\\RX1\\Packages.groupproj", 71 | "compiler_min": 31, 72 | "compiler_max": 31 73 | } 74 | ] 75 | } -------------------------------------------------------------------------------- /Packages/RX/Packages.groupproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | {B0BE1F5A-716F-458F-A2E9-1E695A5535D7} 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Default.Personality.12 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Packages/RX1/Packages.groupproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | {B0BE1F5A-716F-458F-A2E9-1E695A5535D7} 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Default.Personality.12 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Packages/RX2/Packages.groupproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | {F6F4CE59-8301-44FE-9E78-A17DA3D8B97D} 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Default.Personality.12 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Packages/XE7/Packages.groupproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | {B0BE1F5A-716F-458F-A2E9-1E695A5535D7} 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Default.Personality.12 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Packages/XE8/Packages.groupproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | {B0BE1F5A-716F-458F-A2E9-1E695A5535D7} 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Default.Personality.12 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Source/Authoring Tool/WebUpdate.GUI.CommandLine.dfm: -------------------------------------------------------------------------------- 1 | object FormCommandLine: TFormCommandLine 2 | Left = 0 3 | Top = 0 4 | BorderStyle = bsDialog 5 | Caption = 'Command-line switches' 6 | ClientHeight = 353 7 | ClientWidth = 624 8 | Color = clBtnFace 9 | Font.Charset = DEFAULT_CHARSET 10 | Font.Color = clWindowText 11 | Font.Height = -11 12 | Font.Name = 'Tahoma' 13 | Font.Style = [] 14 | OldCreateOrder = False 15 | Position = poMainFormCenter 16 | OnCreate = FormCreate 17 | PixelsPerInch = 96 18 | TextHeight = 13 19 | object MemoCommandLine: TMemo 20 | Left = 0 21 | Top = 0 22 | Width = 624 23 | Height = 353 24 | Align = alClient 25 | Color = clBlack 26 | Font.Charset = DEFAULT_CHARSET 27 | Font.Color = clSilver 28 | Font.Height = -16 29 | Font.Name = 'Terminal_Hex' 30 | Font.Style = [] 31 | Lines.Strings = ( 32 | 'Command-line switches' 33 | '---------------------' 34 | '' 35 | 'Syntax: %s project.wup command [more commands] [-options]' 36 | '' 37 | ' project.wup must be replaced by your project name' 38 | '' 39 | 'Commands:' 40 | '---------' 41 | '' 42 | ' s or S or Snapshot (take snapshot)' 43 | ' c or C or Copy (copy to path)' 44 | ' u or U or Upload (upload to server)' 45 | '' 46 | 'Options:' 47 | '---------' 48 | '' 49 | 50 | ' -Channel="channel name" (with/without quotes, default: "N' + 51 | 'ightly")' 52 | 53 | ' -FtpHost=host (FTP host name, overrides project' + 54 | #39's default)' 55 | 56 | ' -FtpUser=username (FTP user name, overrides project' + 57 | #39's default)' 58 | 59 | ' -FtpPassword=password (FTP password, overrides project'#39 + 60 | 's default)' 61 | ' -CopyPath=path (Path of snapshot copies)' 62 | '' 63 | 'Example:' 64 | '--------' 65 | '' 66 | ' %s project.wup scu -Channel=Beta') 67 | ParentFont = False 68 | ReadOnly = True 69 | TabOrder = 0 70 | end 71 | end 72 | -------------------------------------------------------------------------------- /Source/Authoring Tool/WebUpdate.GUI.About.pas: -------------------------------------------------------------------------------- 1 | unit WebUpdate.GUI.About; 2 | 3 | interface 4 | 5 | uses 6 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, 7 | Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, 8 | Vcl.ExtCtrls; 9 | 10 | type 11 | TFormAbout = class(TForm) 12 | ImageHeader: TImage; 13 | LabelAnd: TLabel; 14 | LabelComma1: TLabel; 15 | LabelComma2: TLabel; 16 | LabelCopyright: TLabel; 17 | LabelDualLicenses: TLabel; 18 | LabelDWS: TLabel; 19 | LabelIndy: TLabel; 20 | LabelJEDI: TLabel; 21 | LabelSubTitle: TLabel; 22 | LabelTitle: TLabel; 23 | LabelVirtualTreeview: TLabel; 24 | MemoLGPL: TMemo; 25 | MemoMIT: TMemo; 26 | PanelHeader: TPanel; 27 | RadioButtonLicenseLGPL: TRadioButton; 28 | RadioButtonLicenseMIT: TRadioButton; 29 | procedure LabelDWSClick(Sender: TObject); 30 | procedure LabelIndyClick(Sender: TObject); 31 | procedure LabelJEDIClick(Sender: TObject); 32 | procedure LabelVirtualTreeviewClick(Sender: TObject); 33 | procedure RadioButtonLicenseLGPLClick(Sender: TObject); 34 | procedure RadioButtonLicenseMITClick(Sender: TObject); 35 | end; 36 | 37 | implementation 38 | 39 | {$R *.dfm} 40 | 41 | uses 42 | WinApi.ShellApi; 43 | 44 | procedure OpenLink(const URL: string); 45 | begin 46 | ShellExecute(0, 'open', PChar(URL), nil, nil, SW_SHOWDEFAULT) 47 | end; 48 | 49 | procedure TFormAbout.LabelDWSClick(Sender: TObject); 50 | begin 51 | OpenLink('http://www.delphitools.info/dwscript/'); 52 | end; 53 | 54 | procedure TFormAbout.LabelIndyClick(Sender: TObject); 55 | begin 56 | OpenLink('http://www.indyproject.org/'); 57 | end; 58 | 59 | procedure TFormAbout.LabelJEDIClick(Sender: TObject); 60 | begin 61 | OpenLink('http://www.delphi-jedi.org/'); 62 | end; 63 | 64 | procedure TFormAbout.LabelVirtualTreeviewClick(Sender: TObject); 65 | begin 66 | OpenLink('http://www.jam-software.com/virtual-treeview/'); 67 | end; 68 | 69 | procedure TFormAbout.RadioButtonLicenseLGPLClick(Sender: TObject); 70 | begin 71 | MemoLGPL.BringToFront; 72 | end; 73 | 74 | procedure TFormAbout.RadioButtonLicenseMITClick(Sender: TObject); 75 | begin 76 | MemoMIT.BringToFront; 77 | end; 78 | 79 | end. 80 | -------------------------------------------------------------------------------- /Source/Common/WebUpdate.Tools.pas: -------------------------------------------------------------------------------- 1 | unit WebUpdate.Tools; 2 | 3 | interface 4 | 5 | uses 6 | {$IFDEF MSWINDOWS} Winapi.Windows, {$ENDIF} 7 | System.Classes, System.SysUtils, IdHashMessageDigest, IdGlobal; 8 | 9 | {$IFDEF MSWINDOWS} 10 | function FileTimeToDateTime(Time: TFileTime): TDateTime; 11 | {$ENDIF} 12 | function MD5(const FileName: string): string; overload; 13 | function MD5(Stream: TStream): string; overload; 14 | 15 | function WebToLocalFileName(const WebFileName: string): string; 16 | function LocalToWebFileName(const LocalFileName: string): string; 17 | 18 | implementation 19 | 20 | {$IFDEF MSWINDOWS} 21 | function FileTimeToDateTime(Time: TFileTime): TDateTime; 22 | 23 | function InternalEncodeDateTime(const AYear, AMonth, ADay, AHour, AMinute, ASecond, 24 | AMilliSecond: Word): TDateTime; 25 | var 26 | LTime: TDateTime; 27 | Success: Boolean; 28 | begin 29 | Result := 0; 30 | Success := TryEncodeDate(AYear, AMonth, ADay, Result); 31 | if Success then 32 | begin 33 | Success := TryEncodeTime(AHour, AMinute, ASecond, AMilliSecond, LTime); 34 | if Success then 35 | if Result >= 0 then 36 | Result := Result + LTime 37 | else 38 | Result := Result - LTime 39 | end; 40 | end; 41 | 42 | var 43 | LFileTime: TFileTime; 44 | SysTime: TSystemTime; 45 | begin 46 | Result := 0; 47 | FileTimeToLocalFileTime(Time, LFileTime); 48 | 49 | if FileTimeToSystemTime(LFileTime, SysTime) then 50 | with SysTime do 51 | begin 52 | Result := InternalEncodeDateTime(wYear, wMonth, wDay, wHour, wMinute, 53 | wSecond, wMilliseconds); 54 | end; 55 | end; 56 | {$ENDIF} 57 | 58 | function MD5(Stream: TStream): string; 59 | var 60 | IdMD5: TIdHashMessageDigest5; 61 | begin 62 | IdMD5 := TIdHashMessageDigest5.Create; 63 | try 64 | Result := IdMD5.HashStreamAsHex(Stream); 65 | finally 66 | IdMD5.Free; 67 | end; 68 | end; 69 | 70 | function MD5(const FileName: string): string; 71 | var 72 | FS: TFileStream; 73 | begin 74 | FS := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); 75 | try 76 | Result := MD5(FS); 77 | finally 78 | FS.Free; 79 | end; 80 | end; 81 | 82 | function WebToLocalFileName(const WebFileName: string): string; 83 | begin 84 | Result := StringReplace(WebFileName, '/', '\', [rfReplaceAll]); 85 | end; 86 | 87 | function LocalToWebFileName(const LocalFileName: string): string; 88 | begin 89 | Result := StringReplace(LocalFileName, '\', '/', [rfReplaceAll]); 90 | end; 91 | 92 | end. 93 | -------------------------------------------------------------------------------- /Source/Example Application/MainUnit.pas: -------------------------------------------------------------------------------- 1 | unit MainUnit; 2 | 3 | interface 4 | 5 | uses 6 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, 7 | Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, 8 | WebUpdate.Classes.WebUpdate; 9 | 10 | type 11 | TFormExample = class(TForm) 12 | ButtonCheckUpdates: TButton; 13 | ButtonExit: TButton; 14 | ButtonPerformUpdate: TButton; 15 | LabelChannel: TLabel; 16 | ComboBoxChannels: TComboBox; 17 | procedure FormCreate(Sender: TObject); 18 | procedure ButtonCheckUpdatesClick(Sender: TObject); 19 | procedure ButtonExitClick(Sender: TObject); 20 | procedure FormDestroy(Sender: TObject); 21 | procedure FormShow(Sender: TObject); 22 | procedure ButtonPerformUpdateClick(Sender: TObject); 23 | procedure ComboBoxChannelsChange(Sender: TObject); 24 | private 25 | FWebUpdate: TWebUpdate; 26 | end; 27 | 28 | var 29 | FormExample: TFormExample; 30 | 31 | implementation 32 | 33 | {$R *.dfm} 34 | 35 | { TFormExample } 36 | 37 | procedure TFormExample.FormCreate(Sender: TObject); 38 | begin 39 | FWebUpdate := TWebUpdate.Create; 40 | FWebUpdate.BaseURL := 'http://www.savioursofsoul.de/Christian/WebUpdate/'; 41 | FWebUpdate.ChannelName := 'Stable'; 42 | end; 43 | 44 | procedure TFormExample.FormDestroy(Sender: TObject); 45 | begin 46 | FWebUpdate.Free; 47 | end; 48 | 49 | procedure TFormExample.FormShow(Sender: TObject); 50 | var 51 | Index: Integer; 52 | begin 53 | FWebUpdate.GetChannels(ComboBoxChannels.Items); 54 | FWebUpdate.GetLocalChannelInformation; 55 | Index := ComboBoxChannels.Items.IndexOf(FWebUpdate.ChannelName); 56 | if Index >= 0 then 57 | ComboBoxChannels.ItemIndex := Index 58 | else 59 | ComboBoxChannels.ItemIndex := 0; 60 | end; 61 | 62 | procedure TFormExample.ButtonCheckUpdatesClick(Sender: TObject); 63 | begin 64 | if FWebUpdate.CheckForUpdate then 65 | begin 66 | ButtonPerformUpdate.Default := True; 67 | ButtonPerformUpdate.SetFocus; 68 | if MessageDlg('A new update is available!'#13#10#13#10'Update now?', 69 | mtConfirmation, [mbYes, mbNo], 0) = mrYes then 70 | ButtonPerformUpdateClick(Self); 71 | end 72 | else 73 | MessageDlg('No update is available!', mtInformation, [mbOK], 0); 74 | end; 75 | 76 | procedure TFormExample.ButtonPerformUpdateClick(Sender: TObject); 77 | begin 78 | FWebUpdate.PerformUpdate; 79 | end; 80 | 81 | procedure TFormExample.ComboBoxChannelsChange(Sender: TObject); 82 | begin 83 | FWebUpdate.ChannelName := ComboBoxChannels.Text; 84 | end; 85 | 86 | procedure TFormExample.ButtonExitClick(Sender: TObject); 87 | begin 88 | Close; 89 | end; 90 | 91 | end. 92 | -------------------------------------------------------------------------------- /Source/Authoring Tool/WebUpdate.JSON.Preferences.pas: -------------------------------------------------------------------------------- 1 | unit WebUpdate.JSON.Preferences; 2 | 3 | interface 4 | 5 | uses 6 | System.SysUtils, dwsJSON, WebUpdate.JSON.Serializer; 7 | 8 | type 9 | TWebUpdatePreferences = class(TJsonSerializer) 10 | private 11 | FFileName: TFileName; 12 | FRecentProject: TFileName; 13 | FTop: Integer; 14 | FLeft: Integer; 15 | FViewFiles: Boolean; 16 | procedure Load; 17 | procedure Save; 18 | protected 19 | procedure Read(Root: TdwsJSONObject); override; 20 | procedure Write(Root: TdwsJSONObject); override; 21 | public 22 | constructor Create(FileName: TFileName); 23 | destructor Destroy; override; 24 | 25 | class function GetID: string; override; 26 | 27 | property Left: Integer read FLeft write FLeft; 28 | property Top: Integer read FTop write FTop; 29 | property RecentProject: TFileName read FRecentProject write FRecentProject; 30 | property ViewFiles: Boolean read FViewFiles write FViewFiles; 31 | end; 32 | 33 | implementation 34 | 35 | uses 36 | dwsXPlatform; 37 | 38 | { TWebUpdatePreferences } 39 | 40 | constructor TWebUpdatePreferences.Create(FileName: TFileName); 41 | begin 42 | FLeft := 16; 43 | FTop := 16; 44 | FFileName := FileName; 45 | if FileExists(FFileName) then 46 | Load; 47 | end; 48 | 49 | destructor TWebUpdatePreferences.Destroy; 50 | begin 51 | Save; 52 | inherited; 53 | end; 54 | 55 | class function TWebUpdatePreferences.GetID: string; 56 | begin 57 | Result := 'Preferences'; 58 | end; 59 | 60 | procedure TWebUpdatePreferences.Load; 61 | begin 62 | LoadFromFile(FFileName); 63 | end; 64 | 65 | procedure TWebUpdatePreferences.Save; 66 | begin 67 | SaveToFile(FFileName); 68 | end; 69 | 70 | procedure TWebUpdatePreferences.Read(Root: TdwsJSONObject); 71 | var 72 | Value: TdwsJSONValue; 73 | begin 74 | inherited; 75 | 76 | // read window position 77 | Value := Root.Items['Left']; 78 | if Assigned(Value) then 79 | FLeft := Value.AsInteger; 80 | Value := Root.Items['Top']; 81 | if Assigned(Value) then 82 | FTop := Value.AsInteger; 83 | 84 | // read view files 85 | Value := Root.Items['ViewFiles']; 86 | if Assigned(Value) then 87 | FViewFiles := Value.AsBoolean; 88 | 89 | // read recent project 90 | Value := Root.Items['RecentProject']; 91 | if Assigned(Value) then 92 | FRecentProject := Value.AsString; 93 | end; 94 | 95 | procedure TWebUpdatePreferences.Write(Root: TdwsJSONObject); 96 | begin 97 | inherited; 98 | 99 | // write window position 100 | Root.AddValue('Left').AsInteger := FLeft; 101 | Root.AddValue('Top').AsInteger := FTop; 102 | 103 | // write view files 104 | Root.AddValue('ViewFiles').AsBoolean := FViewFiles; 105 | 106 | // write recent project 107 | if FRecentProject <> '' then 108 | Root.AddValue('RecentProject').AsString := FRecentProject; 109 | end; 110 | 111 | end. 112 | -------------------------------------------------------------------------------- /Source/Package/WebUpdate.Package.Component.pas: -------------------------------------------------------------------------------- 1 | unit WebUpdate.Package.Component; 2 | 3 | interface 4 | 5 | uses 6 | System.Classes, System.SysUtils, WebUpdate.Classes.Updater, 7 | WebUpdate.Classes.WebUpdate; 8 | 9 | type 10 | TWebUpdateComponent = class(TComponent) 11 | private 12 | FWebUpdate: TWebUpdate; 13 | function GetBaseURL: string; 14 | function GetChannelName: string; 15 | function GetDownloadUpdater: Boolean; 16 | procedure SetBaseURL(const Value: string); 17 | procedure SetChannelName(const Value: string); 18 | procedure SetDownloadUpdater(const Value: Boolean); 19 | public 20 | constructor Create(AOwner: TComponent); override; 21 | destructor Destroy; override; 22 | 23 | function CheckForUpdate: Boolean; 24 | procedure GetLocalChannelInformation; 25 | procedure GetChannelsInformationFromServer; 26 | procedure PerformUpdate; 27 | procedure PerformDownloadUpdater; 28 | 29 | property WebUpdate: TWebUpdate read FWebUpdate; 30 | published 31 | property BaseURL: string read GetBaseURL write SetBaseURL; 32 | property ChannelName: string read GetChannelName write SetChannelName; 33 | property DownloadUpdater: Boolean read GetDownloadUpdater write SetDownloadUpdater default False; 34 | end; 35 | 36 | implementation 37 | 38 | resourcestring 39 | RStrURLNotSpecified = 'URL not specified!'; 40 | 41 | { TWebUpdateComponent } 42 | 43 | constructor TWebUpdateComponent.Create(AOwner: TComponent); 44 | begin 45 | inherited; 46 | FWebUpdate := TWebUpdate.Create; 47 | FWebUpdate.BaseURL := ''; 48 | end; 49 | 50 | destructor TWebUpdateComponent.Destroy; 51 | begin 52 | FWebUpdate.Free; 53 | inherited; 54 | end; 55 | 56 | function TWebUpdateComponent.CheckForUpdate: Boolean; 57 | begin 58 | Result := FWebUpdate.CheckForUpdate; 59 | end; 60 | 61 | function TWebUpdateComponent.GetBaseURL: string; 62 | begin 63 | Result := FWebUpdate.BaseURL; 64 | end; 65 | 66 | function TWebUpdateComponent.GetChannelName: string; 67 | begin 68 | Result := FWebUpdate.ChannelName; 69 | end; 70 | 71 | procedure TWebUpdateComponent.GetChannelsInformationFromServer; 72 | begin 73 | FWebUpdate.GetChannelsInformationFromServer; 74 | end; 75 | 76 | procedure TWebUpdateComponent.GetLocalChannelInformation; 77 | begin 78 | FWebUpdate.GetLocalChannelInformation 79 | end; 80 | 81 | function TWebUpdateComponent.GetDownloadUpdater: Boolean; 82 | begin 83 | Result := FWebUpdate.DownloadUpdater; 84 | end; 85 | 86 | procedure TWebUpdateComponent.PerformDownloadUpdater; 87 | begin 88 | if FWebUpdate.BaseURL = '' then 89 | raise Exception.Create(RStrURLNotSpecified); 90 | 91 | FWebUpdate.PerformDownloadUpdater; 92 | end; 93 | 94 | procedure TWebUpdateComponent.PerformUpdate; 95 | begin 96 | if FWebUpdate.BaseURL = '' then 97 | raise Exception.Create(RStrURLNotSpecified); 98 | 99 | FWebUpdate.PerformUpdate; 100 | end; 101 | 102 | procedure TWebUpdateComponent.SetBaseURL(const Value: string); 103 | begin 104 | FWebUpdate.BaseURL := Value; 105 | end; 106 | 107 | procedure TWebUpdateComponent.SetChannelName(const Value: string); 108 | begin 109 | FWebUpdate.ChannelName := Value; 110 | end; 111 | 112 | procedure TWebUpdateComponent.SetDownloadUpdater(const Value: Boolean); 113 | begin 114 | FWebUpdate.DownloadUpdater := Value; 115 | end; 116 | 117 | end. 118 | -------------------------------------------------------------------------------- /Source/Authoring Tool/WebUpdate.GUI.Options.pas: -------------------------------------------------------------------------------- 1 | unit WebUpdate.GUI.Options; 2 | 3 | interface 4 | 5 | uses 6 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, 7 | Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, 8 | Vcl.ExtCtrls, Vcl.ComCtrls, Vcl.Mask, 9 | VirtualTrees, JvExMask, JvToolEdit; 10 | 11 | type 12 | TOptionsItem = record 13 | TabSheet: TTabSheet; 14 | end; 15 | POptionsItem = ^TOptionsItem; 16 | 17 | TFormOptions = class(TForm) 18 | ButtonCancel: TButton; 19 | ButtonOK: TButton; 20 | CheckBoxAutoCopyUpload: TCheckBox; 21 | CheckBoxCopyTo: TCheckBox; 22 | EditBaseDirectory: TJvDirectoryEdit; 23 | EditChannelFileName: TJvFilenameEdit; 24 | EditCopyPath: TEdit; 25 | EditFtpPassword: TEdit; 26 | EditFtpServer: TEdit; 27 | EditFtpUsername: TEdit; 28 | GroupBoxCopy: TGroupBox; 29 | GroupBoxFTP: TGroupBox; 30 | LabelChannelFileName: TLabel; 31 | LabelFileName: TLabel; 32 | LabelPassword: TLabel; 33 | LabelServer: TLabel; 34 | LabelUsername: TLabel; 35 | PageControl: TPageControl; 36 | Panel: TPanel; 37 | TabSheetFTP: TTabSheet; 38 | TabSheetMain: TTabSheet; 39 | TreeOptions: TVirtualStringTree; 40 | CheckBoxMD5: TCheckBox; 41 | procedure FormCreate(Sender: TObject); 42 | procedure EditChannelFileNameAfterDialog(Sender: TObject; var AName: string; 43 | var AAction: Boolean); 44 | procedure TreeOptionsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; 45 | Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); 46 | procedure TreeOptionsChange(Sender: TBaseVirtualTree; Node: PVirtualNode); 47 | private 48 | procedure SetupTree; 49 | end; 50 | 51 | implementation 52 | 53 | {$R *.dfm} 54 | 55 | { TFormOptions } 56 | 57 | procedure TFormOptions.EditChannelFileNameAfterDialog(Sender: TObject; 58 | var AName: string; var AAction: Boolean); 59 | begin 60 | // try to make the path relative 61 | AName := ExtractRelativePath(IncludeTrailingPathDelimiter( 62 | EditBaseDirectory.Directory), AName); 63 | end; 64 | 65 | procedure TFormOptions.FormCreate(Sender: TObject); 66 | begin 67 | TreeOptions.NodeDataSize := SizeOf(TOptionsItem); 68 | SetupTree; 69 | PageControl.ActivePageIndex := 0; 70 | end; 71 | 72 | procedure TFormOptions.TreeOptionsChange(Sender: TBaseVirtualTree; 73 | Node: PVirtualNode); 74 | var 75 | NodeData: POptionsItem; 76 | begin 77 | if Assigned(Node) then 78 | begin 79 | NodeData := TreeOptions.GetNodeData(Node); 80 | PageControl.ActivePage := NodeData^.TabSheet; 81 | end; 82 | end; 83 | 84 | procedure TFormOptions.TreeOptionsGetText(Sender: TBaseVirtualTree; 85 | Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; 86 | var CellText: string); 87 | var 88 | NodeData: POptionsItem; 89 | begin 90 | NodeData := TreeOptions.GetNodeData(Node); 91 | CellText := NodeData^.TabSheet.Caption; 92 | end; 93 | 94 | procedure TFormOptions.SetupTree; 95 | var 96 | Node: PVirtualNode; 97 | NodeData: POptionsItem; 98 | Index: Integer; 99 | begin 100 | // build tree 101 | for Index := 0 to PageControl.PageCount - 1 do 102 | begin 103 | Node := TreeOptions.AddChild(TreeOptions.RootNode); 104 | NodeData := TreeOptions.GetNodeData(Node); 105 | NodeData^.TabSheet := PageControl.Pages[Index]; 106 | end; 107 | end; 108 | 109 | end. 110 | -------------------------------------------------------------------------------- /Source/Web Update Tools.groupproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | {0F76F6EF-5669-4EF1-AB45-2FC4E56B085A} 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | Default.Personality.12 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | WebUpdate 2 | ========= 3 | 4 | WebUpdate is a bunch of code that can be included into any application to add some simple JSON based WebUpdate. The contained authoring tool allows to create snapshots with a single click. These snapshots can be copied to a dedicated location or uploaded to an FTP server. This can also be done automatically when taking a snapshot. Once uploaded the WebUpdate only needs a simple HTTP connection in order to perform a web update. 5 | 6 | The tool was created after thinking about how a modern, lightweight web update tool could work without the need of an extra server (only file serving is required). It is not yet used and thus mostly untested beyond the used in the tool itself. 7 | 8 | In order to use this tool in your project there are a few prerequisites. First the source code is licensed under a dual license of MPL or LGPL, which means you can use this either under the conditions of MPL or under the conditions of LGPL. Both have advantages and disadvantages, however the essence of these libraries is that you mention the use of this library and to allow integration of changes to the original project. If you need to license this under a different license, feel free to contact me. 9 | 10 | Beyond the license, there are at least 4 dependencies to other libraries namely: 11 | * [DWS](http://www.delphitools.info/dwscript/) 12 | * [Virtual Treeview](http://www.jam-software.com/virtual-treeview/) 13 | * [JEDI](http://www.delphi-jedi.org/) 14 | * [Indy](http://www.indyproject.org/) 15 | 16 | Please make sure you have these libraries accessible from your Delphi environment. So far all modern Delphi XE versions are supported. Older versions might work as well, but probably need some refactoring in order to run out of the box. 17 | 18 | Beyond this a basic Delphinus-Support has been added, which should make installation easier in the future. 19 | 20 | Command-line switches (Authoring tool) 21 | -------------------------------------- 22 | 23 | In case you want to automate the authoring tool, you can use the following command-line switches. In fact the tool will still be a GUI-tool, but with a hidden user interface, so don't expect any output of the tool. Following, all commands and options are listed: 24 | 25 | Syntax: AuthoringTool.exe project.wup command [more commands] [-options] 26 | 27 | project.wup must be replaced by your project name 28 | 29 | Commands: 30 | --------- 31 | 32 | s or S or Snapshot (take snapshot) 33 | c or C or Copy (copy to path) 34 | u or U or Upload (upload to server) 35 | 36 | Options: 37 | --------- 38 | 39 | -Channel="channel name" (with/without quotes, default: "Nightly") 40 | -FtpHost=host (FTP host name, overrides project's default) 41 | -FtpUser=username (FTP user name, overrides project's default) 42 | -FtpPassword=password (FTP password, overrides project's default) 43 | -CopyPath=path (Path of snapshot copies) 44 | 45 | Example: 46 | -------- 47 | 48 | AuthoringTool.exe project.wup scu -Channel=Beta 49 | 50 | 51 | Command-line switches (Updater) 52 | ------------------------------- 53 | 54 | While the 'Updater' tool can be started as stand-alone tool, it is supposed to work as a helper for a main application. It is required because a running application can't replace itself. 55 | 56 | Syntax: Updater.exe [-options] 57 | 58 | Options: 59 | -------- 60 | 61 | -u=URL (Base URL for JSON files) 62 | -c=Channel (Update Channel, default is 'Stable') 63 | -f=FileName (Channels) (Filename of channels definition file) 64 | -d=Delay (Integer) (Time in milliseconds before updating starts) 65 | -l=FileName (Local filename of current setup) 66 | -e=ExeFileName (Name of main application executable) 67 | -w=WindowCaption (Caption of main application window) 68 | -v (Verbose) 69 | 70 | Example: 71 | -------- 72 | 73 | Updater.exe -c=Nightly 74 | 75 | 76 | -------------------------------------------------------------------------------- /Source/Common/WebUpdate.JSON.Channels.pas: -------------------------------------------------------------------------------- 1 | unit WebUpdate.JSON.Channels; 2 | 3 | interface 4 | 5 | uses 6 | System.SysUtils, System.Generics.Collections, dwsJSON, 7 | WebUpdate.JSON.Serializer; 8 | 9 | type 10 | TWebUpdateChannelItem = class 11 | Name: string; 12 | FileName: TFileName; 13 | Modified: TDateTime; 14 | MD5: string; 15 | end; 16 | TWebUpdateChannelItems = TObjectList; 17 | 18 | TWebUpdateChannels = class(TJsonSerializer) 19 | private 20 | FItems: TWebUpdateChannelItems; 21 | protected 22 | procedure Read(Root: TdwsJSONObject); override; 23 | procedure Write(Root: TdwsJSONObject); override; 24 | public 25 | constructor Create; 26 | destructor Destroy; override; 27 | class function GetID: string; override; 28 | 29 | function GetItemForChannel(ChannelName: string): TWebUpdateChannelItem; 30 | 31 | property Items: TWebUpdateChannelItems read FItems; 32 | end; 33 | 34 | implementation 35 | 36 | { TWebUpdateChannels } 37 | 38 | constructor TWebUpdateChannels.Create; 39 | begin 40 | inherited; 41 | FItems := TWebUpdateChannelItems.Create; 42 | end; 43 | 44 | destructor TWebUpdateChannels.Destroy; 45 | begin 46 | FItems.Free; 47 | inherited; 48 | end; 49 | 50 | class function TWebUpdateChannels.GetID: string; 51 | begin 52 | Result := 'Channels'; 53 | end; 54 | 55 | function TWebUpdateChannels.GetItemForChannel( 56 | ChannelName: string): TWebUpdateChannelItem; 57 | var 58 | Index: Integer; 59 | begin 60 | Result := nil; 61 | for Index := 0 to FItems.Count - 1 do 62 | if SameText(FItems[Index].Name, ChannelName) then 63 | Exit(FItems[Index]); 64 | end; 65 | 66 | procedure TWebUpdateChannels.Read(Root: TdwsJSONObject); 67 | var 68 | Value: TdwsJSONValue; 69 | Channels: TdwsJSONArray; 70 | Index: Integer; 71 | Item: TWebUpdateChannelItem; 72 | begin 73 | inherited; 74 | 75 | Value := Root.Items['Channels']; 76 | 77 | // try the older 'Files' [deprecated!] 78 | if not (Value is TdwsJSONArray) then 79 | Value := Root.Items['Files']; 80 | 81 | if not (Value is TdwsJSONArray) then 82 | raise Exception.Create('Array expected!'); 83 | 84 | // clear existing items 85 | FItems.Clear; 86 | 87 | Channels := TdwsJSONArray(Value); 88 | for Index := 0 to Channels.ElementCount - 1 do 89 | begin 90 | Item := TWebUpdateChannelItem.Create; 91 | 92 | // get name 93 | Value := Channels.Elements[Index].Items['Name']; 94 | Item.Name := Value.AsString; 95 | 96 | // get filename 97 | Value := Channels.Elements[Index].Items['FileName']; 98 | if Assigned(Value) then 99 | Item.FileName := Value.AsString 100 | else 101 | Item.FileName := Item.Name + '/' + Item.Name + '.json'; 102 | 103 | // get file modified 104 | Value := Channels.Elements[Index].Items['Modified']; 105 | if Assigned(Value) then 106 | Item.Modified := ISO8601ToDateTime(Value.AsString) 107 | else 108 | Item.Modified := 0; 109 | 110 | // get MD5 hash 111 | Value := Channels.Elements[Index].Items['MD5']; 112 | if Assigned(Value) then 113 | Item.MD5 := Value.AsString; 114 | 115 | FItems.Add(Item); 116 | end; 117 | end; 118 | 119 | procedure TWebUpdateChannels.Write(Root: TdwsJSONObject); 120 | var 121 | Value: TdwsJSONObject; 122 | Channels: TdwsJSONArray; 123 | Item: TWebUpdateChannelItem; 124 | begin 125 | inherited; 126 | 127 | Root.AddValue('Modified').AsString := DateTimeToISO8601(Now); 128 | Channels := Root.AddArray('Channels'); 129 | for Item in FItems do 130 | begin 131 | Value := TdwsJSONObject(Channels.AddObject); 132 | Value.AddValue('Name').AsString := Item.Name; 133 | 134 | // eventually store file name (if not identical to Name + '.json') 135 | if not (Item.FileName = Item.Name + '/' + Item.Name + '.json') then 136 | if not (Item.FileName = '') then 137 | Value.AddValue('FileName').AsString := Item.FileName; 138 | 139 | // eventually store file modification date 140 | if Item.Modified > 0 then 141 | Value.AddValue('Modified').AsString := DateTimeToISO8601(Item.Modified); 142 | 143 | // eventually store MD5 hash 144 | if Item.MD5 <> '' then 145 | Value.AddValue('MD5').AsString := Item.MD5; 146 | end; 147 | end; 148 | 149 | end. 150 | -------------------------------------------------------------------------------- /Source/Common/WebUpdate.JSON.Serializer.pas: -------------------------------------------------------------------------------- 1 | unit WebUpdate.JSON.Serializer; 2 | 3 | interface 4 | 5 | uses 6 | System.SysUtils, dwsJSON; 7 | 8 | type 9 | EJsonSerializer = class(Exception); 10 | 11 | TJsonSerializer = class 12 | protected 13 | procedure Read(Root: TdwsJSONObject); virtual; 14 | procedure Write(Root: TdwsJSONObject); virtual; 15 | public 16 | class function GetID: string; virtual; 17 | 18 | procedure LoadFromFile(const FileName: TFileName); 19 | procedure SaveToFile(const FileName: TFileName); 20 | 21 | procedure LoadFromString(const Text: string); 22 | function SaveToString: string; 23 | end; 24 | 25 | function DateTimeToISO8601(DateTime: TDateTime): string; 26 | function ISO8601ToDateTime(const Value: string): TDateTime; 27 | 28 | implementation 29 | 30 | uses 31 | dwsXPlatform; 32 | 33 | function DateTimeToISO8601(DateTime: TDateTime): string; 34 | begin 35 | Result := FormatDateTime('yyyy-mm-dd"' + 'T' + '"hh":"mm":"ss.zzz', DateTime); 36 | end; 37 | 38 | function ISO8601ToDateTime(const Value: string): TDateTime; 39 | 40 | function Str2Time(s: string): TDateTime; 41 | var 42 | Hour, Minute, MSec, Second: Word; 43 | Temp: Integer; 44 | begin 45 | s := Trim(s); 46 | if s = '' then 47 | Result := 0 48 | else 49 | begin 50 | Temp := Pos(':', s); 51 | Hour := StrToInt(Copy(s, 1, Temp - 1)); 52 | Delete(s, 1, Temp); 53 | Temp := Pos(':', s); 54 | Minute := StrToInt(Copy(s, 1, Temp - 1)); 55 | Delete(s, 1, Temp); 56 | Temp := Pos('.', s); 57 | if Temp > 0 then 58 | begin 59 | MSec := StrToInt(Copy(s, Temp + 1, Length(s) - Temp)); 60 | Delete(s, Temp, Length(s) - Temp + 1); 61 | end 62 | else 63 | MSec := 0; 64 | Second := StrToInt(s); 65 | Result := EncodeTime(Hour, Minute, Second, MSec); 66 | end; 67 | end; 68 | 69 | var 70 | Day, Month, Year: Word; 71 | Temp: Integer; 72 | DateStr, TimeStr: string; 73 | begin 74 | // check for a value (At all) 75 | if Value = '' then 76 | Exit(0); 77 | 78 | Temp := Pos ('T', Value); 79 | // detect all known date/time formats 80 | if (Temp = 0) and (Pos('-', Value) > 0) then 81 | Temp := Length(Value) + 1; 82 | DateStr := Trim(Copy(Value, 1, Temp - 1)); 83 | TimeStr := Trim(Copy(Value, Temp + 1, Length(Value) - Temp)); 84 | Result := 0; 85 | if DateStr <> '' then 86 | begin 87 | Temp := Pos ('-', DateStr); 88 | Year := StrToInt(Copy(DateStr, 1, Temp - 1)); 89 | Delete(DateStr, 1, Temp); 90 | Temp := Pos ('-', DateStr); 91 | Month := StrToInt(Copy(DateStr, 1, Temp - 1)); 92 | Day := StrToInt(Copy(DateStr, Temp + 1, Length(DateStr) - Temp)); 93 | Result := EncodeDate(Year, Month, Day); 94 | end; 95 | Result := Result + Frac(Str2Time(TimeStr)); 96 | end; 97 | 98 | 99 | { TJsonSerializer } 100 | 101 | class function TJsonSerializer.GetID: string; 102 | begin 103 | Result := ''; 104 | end; 105 | 106 | procedure TJsonSerializer.LoadFromFile(const FileName: TFileName); 107 | var 108 | Root: TdwsJSONValue; 109 | begin 110 | // check if file exists 111 | if not FileExists(FileName) then 112 | raise Exception.CreateFmt('File %s does not exist!', [FileName]); 113 | 114 | // parse JSON file 115 | Root := TdwsJSONValue.ParseFile(FileName); 116 | 117 | // ensure the JSON file is an object 118 | if not (Root is TdwsJSONObject) then 119 | raise EJsonSerializer.Create('Object expected'); 120 | 121 | try 122 | Read(TdwsJSONObject(Root)); 123 | finally 124 | Root.Free; 125 | end; 126 | end; 127 | 128 | procedure TJsonSerializer.SaveToFile(const FileName: TFileName); 129 | var 130 | Root: TdwsJSONObject; 131 | begin 132 | Root := TdwsJSONObject.Create; 133 | Write(Root); 134 | 135 | SaveTextToUTF8File(FileName, Root.ToBeautifiedString); 136 | end; 137 | 138 | procedure TJsonSerializer.LoadFromString(const Text: string); 139 | var 140 | Root: TdwsJSONValue; 141 | begin 142 | Root := TdwsJSONValue.ParseString(Text); 143 | 144 | if not (Root is TdwsJSONObject) then 145 | raise EJsonSerializer.Create('Object expected'); 146 | 147 | try 148 | Read(TdwsJSONObject(Root)); 149 | finally 150 | Root.Free; 151 | end; 152 | end; 153 | 154 | function TJsonSerializer.SaveToString: string; 155 | var 156 | Root: TdwsJSONObject; 157 | begin 158 | Root := TdwsJSONObject.Create; 159 | Write(Root); 160 | 161 | Result := Root.ToBeautifiedString; 162 | end; 163 | 164 | procedure TJsonSerializer.Read(Root: TdwsJSONObject); 165 | begin 166 | // eventually check ID 167 | if GetID <> '' then 168 | if not (Root.Items['ID'].AsString = GetID) then 169 | raise EJsonSerializer.Create('ID mismatch'); 170 | end; 171 | 172 | procedure TJsonSerializer.Write(Root: TdwsJSONObject); 173 | begin 174 | // eventually set ID 175 | if GetID <> '' then 176 | Root.AddValue('ID').AsString := GetID; 177 | end; 178 | 179 | end. 180 | -------------------------------------------------------------------------------- /Packages/RX2/WebUpdateD.dproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | {B84A8AED-6387-4DEF-9F94-0D9A5040ACB7} 4 | WebUpdateD.dpk 5 | True 6 | Debug 7 | 1 8 | Package 9 | None 10 | 18.2 11 | Win32 12 | 13 | 14 | true 15 | 16 | 17 | true 18 | Base 19 | true 20 | 21 | 22 | true 23 | Base 24 | true 25 | 26 | 27 | true 28 | Base 29 | true 30 | 31 | 32 | false 33 | false 34 | false 35 | false 36 | false 37 | 00400000 38 | true 39 | true 40 | WebUpdateD 41 | WebUpdate Non-Visual 42 | 250 43 | true 44 | true 45 | 1031 46 | CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=;CFBundleName= 47 | System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace) 48 | 49 | 50 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) 51 | true 52 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName) 53 | 1033 54 | WebUpdateR;$(DCC_UsePackage) 55 | 56 | 57 | RELEASE;$(DCC_Define) 58 | 0 59 | false 60 | 0 61 | 62 | 63 | DEBUG;$(DCC_Define) 64 | false 65 | true 66 | 67 | 68 | 69 | MainSource 70 | 71 | 72 | 73 | 74 | 75 | 76 | Cfg_2 77 | Base 78 | 79 | 80 | Base 81 | 82 | 83 | Cfg_1 84 | Base 85 | 86 | 87 | 88 | Delphi.Personality.12 89 | Package 90 | 91 | 92 | 93 | WebUpdateD.dpk 94 | 95 | 96 | 97 | False 98 | False 99 | False 100 | False 101 | False 102 | True 103 | 104 | 105 | 12 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /Packages/RX2/WebUpdateR.dproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | {AF3F4B4E-F9D1-4108-987F-28BCAEB0F0C6} 4 | WebUpdateR.dpk 5 | True 6 | Debug 7 | 1 8 | Package 9 | VCL 10 | 18.2 11 | Win32 12 | 13 | 14 | true 15 | 16 | 17 | true 18 | Base 19 | true 20 | 21 | 22 | true 23 | Base 24 | true 25 | 26 | 27 | true 28 | Base 29 | true 30 | 31 | 32 | false 33 | false 34 | false 35 | false 36 | false 37 | 00400000 38 | true 39 | true 40 | WebUpdateR 41 | 250 42 | true 43 | true 44 | Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace) 45 | 1031 46 | CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=;CFBundleName= 47 | 48 | 49 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) 50 | true 51 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName) 52 | 1033 53 | 54 | 55 | RELEASE;$(DCC_Define) 56 | 0 57 | false 58 | 0 59 | 60 | 61 | DEBUG;$(DCC_Define) 62 | false 63 | true 64 | 65 | 66 | 67 | MainSource 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | Cfg_2 83 | Base 84 | 85 | 86 | Base 87 | 88 | 89 | Cfg_1 90 | Base 91 | 92 | 93 | 94 | Delphi.Personality.12 95 | Package 96 | 97 | 98 | 99 | WebUpdateR.dpk 100 | 101 | 102 | 103 | False 104 | False 105 | False 106 | True 107 | 108 | 109 | 12 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /Source/Authoring Tool/WebUpdate.GUI.Options.dfm: -------------------------------------------------------------------------------- 1 | object FormOptions: TFormOptions 2 | Left = 0 3 | Top = 0 4 | BorderStyle = bsDialog 5 | Caption = 'Options' 6 | ClientHeight = 305 7 | ClientWidth = 525 8 | Color = clBtnFace 9 | Font.Charset = DEFAULT_CHARSET 10 | Font.Color = clWindowText 11 | Font.Height = -11 12 | Font.Name = 'Tahoma' 13 | Font.Style = [] 14 | OldCreateOrder = False 15 | Position = poMainFormCenter 16 | OnCreate = FormCreate 17 | PixelsPerInch = 96 18 | TextHeight = 13 19 | object PageControl: TPageControl 20 | Left = 208 21 | Top = 0 22 | Width = 317 23 | Height = 272 24 | ActivePage = TabSheetMain 25 | Align = alClient 26 | Style = tsButtons 27 | TabOrder = 0 28 | object TabSheetMain: TTabSheet 29 | Caption = 'Main' 30 | TabVisible = False 31 | DesignSize = ( 32 | 309 33 | 262) 34 | object LabelFileName: TLabel 35 | Left = 3 36 | Top = 11 37 | Width = 74 38 | Height = 13 39 | Caption = 'Base Directory:' 40 | end 41 | object LabelChannelFileName: TLabel 42 | Left = 3 43 | Top = 59 44 | Width = 88 45 | Height = 13 46 | Caption = 'Channel Filename:' 47 | end 48 | object EditChannelFileName: TJvFilenameEdit 49 | Left = 3 50 | Top = 75 51 | Width = 303 52 | Height = 21 53 | OnAfterDialog = EditChannelFileNameAfterDialog 54 | Filter = 'JSON files (*.json)|*.json' 55 | Anchors = [akLeft, akTop, akRight] 56 | TabOrder = 0 57 | end 58 | object EditBaseDirectory: TJvDirectoryEdit 59 | Left = 3 60 | Top = 27 61 | Width = 303 62 | Height = 21 63 | DialogKind = dkWin32 64 | Anchors = [akLeft, akTop, akRight] 65 | TabOrder = 1 66 | end 67 | object CheckBoxMD5: TCheckBox 68 | Left = 3 69 | Top = 112 70 | Width = 118 71 | Height = 17 72 | Caption = 'Use MD5 Checksums' 73 | TabOrder = 2 74 | end 75 | end 76 | object TabSheetFTP: TTabSheet 77 | Caption = 'Copy / Upload' 78 | ImageIndex = 1 79 | TabVisible = False 80 | object CheckBoxAutoCopyUpload: TCheckBox 81 | Left = 0 82 | Top = 0 83 | Width = 309 84 | Height = 22 85 | Align = alTop 86 | Caption = 'Automatically Copy/Upload on Snapshot' 87 | TabOrder = 0 88 | end 89 | object GroupBoxFTP: TGroupBox 90 | AlignWithMargins = True 91 | Left = 3 92 | Top = 82 93 | Width = 303 94 | Height = 169 95 | Align = alTop 96 | Caption = 'FTP' 97 | TabOrder = 1 98 | DesignSize = ( 99 | 303 100 | 169) 101 | object LabelPassword: TLabel 102 | Left = 11 103 | Top = 115 104 | Width = 50 105 | Height = 13 106 | Caption = 'Password:' 107 | end 108 | object LabelUsername: TLabel 109 | Left = 11 110 | Top = 67 111 | Width = 52 112 | Height = 13 113 | Caption = 'Username:' 114 | end 115 | object LabelServer: TLabel 116 | Left = 11 117 | Top = 19 118 | Width = 36 119 | Height = 13 120 | Caption = 'Server:' 121 | end 122 | object EditFtpPassword: TEdit 123 | Left = 11 124 | Top = 131 125 | Width = 282 126 | Height = 21 127 | Anchors = [akLeft, akTop, akRight] 128 | TabOrder = 0 129 | end 130 | object EditFtpUsername: TEdit 131 | Left = 11 132 | Top = 83 133 | Width = 282 134 | Height = 21 135 | Anchors = [akLeft, akTop, akRight] 136 | TabOrder = 1 137 | end 138 | object EditFtpServer: TEdit 139 | Left = 11 140 | Top = 35 141 | Width = 282 142 | Height = 21 143 | Anchors = [akLeft, akTop, akRight] 144 | TabOrder = 2 145 | end 146 | end 147 | object GroupBoxCopy: TGroupBox 148 | AlignWithMargins = True 149 | Left = 3 150 | Top = 25 151 | Width = 303 152 | Height = 51 153 | Align = alTop 154 | Caption = 'Copy' 155 | TabOrder = 2 156 | DesignSize = ( 157 | 303 158 | 51) 159 | object CheckBoxCopyTo: TCheckBox 160 | Left = 11 161 | Top = 18 162 | Width = 63 163 | Height = 23 164 | Caption = 'Copy to:' 165 | TabOrder = 0 166 | end 167 | object EditCopyPath: TEdit 168 | Left = 80 169 | Top = 19 170 | Width = 213 171 | Height = 21 172 | Anchors = [akLeft, akTop, akRight] 173 | TabOrder = 1 174 | end 175 | end 176 | end 177 | end 178 | object TreeOptions: TVirtualStringTree 179 | AlignWithMargins = True 180 | Left = 4 181 | Top = 4 182 | Width = 200 183 | Height = 264 184 | Margins.Left = 4 185 | Margins.Top = 4 186 | Margins.Right = 4 187 | Margins.Bottom = 4 188 | Align = alLeft 189 | Header.AutoSizeIndex = 0 190 | Header.Font.Charset = DEFAULT_CHARSET 191 | Header.Font.Color = clWindowText 192 | Header.Font.Height = -11 193 | Header.Font.Name = 'Tahoma' 194 | Header.Font.Style = [] 195 | Header.MainColumn = -1 196 | TabOrder = 1 197 | OnChange = TreeOptionsChange 198 | OnGetText = TreeOptionsGetText 199 | Columns = <> 200 | end 201 | object Panel: TPanel 202 | Left = 0 203 | Top = 272 204 | Width = 525 205 | Height = 33 206 | Align = alBottom 207 | BevelOuter = bvNone 208 | TabOrder = 2 209 | object ButtonOK: TButton 210 | AlignWithMargins = True 211 | Left = 363 212 | Top = 4 213 | Width = 75 214 | Height = 25 215 | Margins.Left = 4 216 | Margins.Top = 4 217 | Margins.Right = 4 218 | Margins.Bottom = 4 219 | Align = alRight 220 | Caption = '&OK' 221 | Default = True 222 | ModalResult = 1 223 | TabOrder = 0 224 | end 225 | object ButtonCancel: TButton 226 | AlignWithMargins = True 227 | Left = 446 228 | Top = 4 229 | Width = 75 230 | Height = 25 231 | Margins.Left = 4 232 | Margins.Top = 4 233 | Margins.Right = 4 234 | Margins.Bottom = 4 235 | Align = alRight 236 | Caption = '&Cancel' 237 | ModalResult = 2 238 | TabOrder = 1 239 | end 240 | end 241 | end 242 | -------------------------------------------------------------------------------- /Source/Common/WebUpdate.JSON.Channel.pas: -------------------------------------------------------------------------------- 1 | unit WebUpdate.JSON.Channel; 2 | 3 | interface 4 | 5 | uses 6 | System.SysUtils, System.Types, System.Generics.Collections, dwsJSON, 7 | WebUpdate.JSON.Serializer; 8 | 9 | type 10 | TWebUpdateFileAction = (iaAdd, iaDelete); 11 | 12 | TWebUpdateFileItem = class 13 | private 14 | FFileName: TFileName; 15 | FFileSize: Integer; 16 | FModified: TDateTime; 17 | FMD5Hash: string; 18 | FAction: TWebUpdateFileAction; 19 | public 20 | constructor Create; 21 | 22 | property Action: TWebUpdateFileAction read FAction write FAction; 23 | property FileName: TFileName read FFileName write FFileName; 24 | property FileSize: Integer read FFileSize write FFileSize; 25 | property Modified: TDateTime read FModified write FModified; 26 | property MD5Hash: string read FMD5Hash write FMD5Hash; 27 | end; 28 | TWebUpdateFileItems = TObjectList; 29 | 30 | TWebUpdateChannelSetup = class(TJsonSerializer) 31 | private 32 | FItems: TWebUpdateFileItems; 33 | FModified: TDateTime; 34 | FChannelName: string; 35 | FAppName: TFileName; 36 | FPreUpdateScript: string; 37 | FPostUpdateScript: string; 38 | protected 39 | procedure Read(Root: TdwsJSONObject); override; 40 | procedure Write(Root: TdwsJSONObject); override; 41 | public 42 | constructor Create; 43 | destructor Destroy; override; 44 | class function GetID: string; override; 45 | 46 | property Modified: TDateTime read FModified write FModified; 47 | property Items: TWebUpdateFileItems read FItems; 48 | property AppName: TFileName read FAppName write FAppName; 49 | property PreUpdateScript: string read FPreUpdateScript write FPreUpdateScript; 50 | property PostUpdateScript: string read FPostUpdateScript write FPostUpdateScript; 51 | property ChannelName: string read FChannelName write FChannelName; 52 | end; 53 | 54 | implementation 55 | 56 | uses 57 | System.StrUtils; 58 | 59 | { TWebUpdateFileItem } 60 | 61 | constructor TWebUpdateFileItem.Create; 62 | begin 63 | FFileName := ''; 64 | FFileSize := 0; 65 | FModified := 0; 66 | FMD5Hash := ''; 67 | FAction := iaAdd; 68 | end; 69 | 70 | 71 | { TWebUpdateChannelSetup } 72 | 73 | constructor TWebUpdateChannelSetup.Create; 74 | begin 75 | inherited; 76 | FItems := TWebUpdateFileItems.Create; 77 | FAppName := ''; 78 | FModified := 0; 79 | end; 80 | 81 | destructor TWebUpdateChannelSetup.Destroy; 82 | begin 83 | FItems.Free; 84 | inherited; 85 | end; 86 | 87 | class function TWebUpdateChannelSetup.GetID: string; 88 | begin 89 | Result := 'Channel'; 90 | end; 91 | 92 | procedure TWebUpdateChannelSetup.Read(Root: TdwsJSONObject); 93 | var 94 | Value: TdwsJSONValue; 95 | FileValue: TdwsJSONObject; 96 | Files: TdwsJSONArray; 97 | Index: Integer; 98 | Item: TWebUpdateFileItem; 99 | begin 100 | inherited; 101 | 102 | // get channel name 103 | Value := Root.Items['Name']; 104 | if Assigned(Value) then 105 | FChannelName := Value.AsString; 106 | 107 | // get modification date 108 | Value := Root.Items['Modified']; 109 | if Assigned(Value) then 110 | FModified := ISO8601ToDateTime(Value.AsString); 111 | 112 | // get pre-build script 113 | Value := Root.Items['PreUpdateScript']; 114 | if Assigned(Value) then 115 | FPreUpdateScript := Value.AsString; 116 | 117 | // get files 118 | Value := Root.Items['Files']; 119 | if not (Value is TdwsJSONArray) then 120 | raise Exception.Create('Array expected!'); 121 | 122 | // clear existing items 123 | FItems.Clear; 124 | 125 | Files := TdwsJSONArray(Value); 126 | for Index := 0 to Files.ElementCount - 1 do 127 | begin 128 | Value := Files.Elements[Index]; 129 | if not (Value is TdwsJSONObject) then 130 | raise Exception.Create('Object expected!'); 131 | 132 | // get file item 133 | FileValue := TdwsJSONObject(Value); 134 | Item := TWebUpdateFileItem.Create; 135 | 136 | // get file name 137 | Value := FileValue.Items['FileName']; 138 | if not Assigned(Value) then 139 | raise Exception.Create('FileName not specified!'); 140 | Item.FileName := Value.AsString; 141 | 142 | // get file size 143 | Value := FileValue.Items['Size']; 144 | if Assigned(Value) then 145 | Item.FileSize := Value.AsInteger; 146 | 147 | // get modification date/time 148 | Value := FileValue.Items['Modified']; 149 | if Assigned(Value) then 150 | Item.Modified := ISO8601ToDateTime(Value.AsString); 151 | 152 | // get MD5 hash 153 | Value := FileValue.Items['MD5']; 154 | if Assigned(Value) then 155 | Item.MD5Hash := Value.AsString; 156 | 157 | // get action 158 | Value := FileValue.Items['Action']; 159 | if Assigned(Value) then 160 | if SameText(Value.AsString, 'delete') then 161 | Item.Action := iaDelete 162 | else if SameText(Value.AsString, 'add') then 163 | Item.Action := iaAdd 164 | else 165 | raise Exception.Create('Unknown action'); 166 | 167 | // add item to file items 168 | FItems.Add(Item); 169 | end; 170 | 171 | // get post-build script 172 | Value := Root.Items['PostUpdateScript']; 173 | if Assigned(Value) then 174 | FPostUpdateScript := Value.AsString; 175 | 176 | // get application name 177 | Value := Root.Items['AppName']; 178 | if Assigned(Value) then 179 | FAppName := Value.AsString; 180 | end; 181 | 182 | procedure TWebUpdateChannelSetup.Write(Root: TdwsJSONObject); 183 | var 184 | Files: TdwsJSONArray; 185 | FileValue: TdwsJSONObject; 186 | Item: TWebUpdateFileItem; 187 | begin 188 | inherited; 189 | 190 | // write modification data 191 | Root.AddValue('Modified').AsString := DateTimeToISO8601(FModified); 192 | 193 | // eventually write channel name (if present) 194 | if FChannelName <> '' then 195 | Root.AddValue('Name').AsString := FChannelName; 196 | 197 | // get pre-build script 198 | if FPreUpdateScript <> '' then 199 | Root.AddValue('PreUpdateScript').AsString := FPreUpdateScript; 200 | 201 | // create files array 202 | Files := Root.AddArray('Files'); 203 | 204 | for Item in FItems do 205 | begin 206 | FileValue := Files.AddObject; 207 | FileValue.AddValue('FileName').AsString := Item.FileName; 208 | 209 | // eventually store file size 210 | if Item.FileSize <> 0 then 211 | FileValue.AddValue('Size').AsInteger := Item.FileSize; 212 | 213 | // eventually store file modification time stamp 214 | if Item.Modified <> 0 then 215 | FileValue.AddValue('Modified').AsString := DateTimeToISO8601(Item.Modified); 216 | 217 | // eventually store MD5 hash 218 | if Item.MD5Hash <> '' then 219 | FileValue.AddValue('MD5').AsString := Item.MD5Hash; 220 | 221 | // eventually store action (default is 'add') 222 | case Item.Action of 223 | iaDelete: 224 | FileValue.AddValue('Action').AsString := 'Delete'; 225 | end; 226 | end; 227 | 228 | // get post-build script 229 | if FPostUpdateScript <> '' then 230 | Root.AddValue('PostUpdateScript').AsString := FPostUpdateScript; 231 | 232 | // write app name 233 | if FAppName <> '' then 234 | Root.AddValue('AppName').AsString := FAppName; 235 | end; 236 | 237 | end. 238 | -------------------------------------------------------------------------------- /Source/Common/WebUpdate.Classes.WebUpdate.pas: -------------------------------------------------------------------------------- 1 | unit WebUpdate.Classes.WebUpdate; 2 | 3 | interface 4 | 5 | uses 6 | System.SysUtils, System.Classes, WebUpdate.JSON.Channels, 7 | WebUpdate.JSON.Channel; 8 | 9 | type 10 | TWebUpdate = class 11 | private 12 | FAutoGet: Boolean; 13 | FBaseURL: string; 14 | FChannelName: string; 15 | FChannels: TWebUpdateChannels; 16 | FChannelsFile: TFileName; 17 | FDownloadUpdater: Boolean; 18 | FLastModified: TDateTime; 19 | FLocalFileName: TFileName; 20 | FUpdaterFileName: TFileName; 21 | procedure SetChannelName(const Value: string); 22 | public 23 | constructor Create; overload; 24 | constructor Create(BaseURL: string; ChannelsFileName: TFileName = ''); overload; 25 | destructor Destroy; override; 26 | 27 | function CheckForUpdate: Boolean; 28 | procedure GetLocalChannelInformation; 29 | procedure GetChannelsInformationFromServer; 30 | procedure GetChannels(Channels: TStrings); 31 | procedure PerformUpdate; 32 | procedure PerformDownloadUpdater; 33 | 34 | property AutoGetLocalChannelInformation: Boolean read FAutoGet write FAutoGet; 35 | property BaseURL: string read FBaseURL write FBaseURL; 36 | property ChannelName: string read FChannelName write SetChannelName; 37 | property ChannelsFileName: TFileName read FChannelsFile write FChannelsFile; 38 | property LocalChannelFileName: TFileName read FLocalFileName write FLocalFileName; 39 | property LastModified: TDateTime read FLastModified; 40 | property DownloadUpdater: Boolean read FDownloadUpdater write FDownloadUpdater; 41 | property UpdaterFileName: TFileName read FUpdaterFileName write FUpdaterFileName; 42 | end; 43 | 44 | implementation 45 | 46 | uses 47 | System.StrUtils, WinApi.ShellApi, WinApi.Windows, Vcl.Forms, 48 | IdSSLOpenSSL, IdHTTP; 49 | 50 | { TWebUpdate } 51 | 52 | constructor TWebUpdate.Create; 53 | begin 54 | FAutoGet := False; 55 | FBaseURL := ''; 56 | FChannelsFile := 'Channels.json'; 57 | FChannelName := 'Stable'; 58 | FChannels := TWebUpdateChannels.Create; 59 | FLocalFileName := 'WebUpdate.json'; 60 | FUpdaterFileName := 'UpdaterWizard.exe'; 61 | end; 62 | 63 | constructor TWebUpdate.Create(BaseURL: string; ChannelsFileName: TFileName = ''); 64 | begin 65 | Create; 66 | FBaseURL := BaseURL; 67 | if ChannelsFileName <> '' then 68 | FChannelsFile := ChannelsFileName; 69 | end; 70 | 71 | destructor TWebUpdate.Destroy; 72 | begin 73 | FChannels.Free; 74 | inherited; 75 | end; 76 | 77 | procedure TWebUpdate.PerformDownloadUpdater; 78 | var 79 | Http: TIdHTTP; 80 | Text: string; 81 | Success: Boolean; 82 | begin 83 | // get channels file (JSON) text 84 | if StartsText('http://', FBaseURL) or StartsText('https://', FBaseURL) then 85 | begin 86 | Http := TIdHTTP.Create(nil); 87 | try 88 | // eventually create SSL IO handler 89 | if FileExists(ExtractFilePath(ParamStr(0)) + 'ssleay32.dll') and 90 | FileExists(ExtractFilePath(ParamStr(0)) + 'libeay32.dll') then 91 | Http.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil); 92 | 93 | try 94 | // get text from URI 95 | Text := Http.Get(FBaseURL + FUpdaterFileName); 96 | 97 | // check if text is available (might need check for JSON format) 98 | Success := Text <> ''; 99 | except 100 | Success := False; 101 | end; 102 | 103 | // ignore errors here! 104 | if not Success then 105 | Exit; 106 | finally 107 | Http.IOHandler.Free; 108 | Http.Free; 109 | end; 110 | end 111 | else 112 | raise Exception.Create('Protocol not supported'); 113 | end; 114 | 115 | procedure TWebUpdate.GetChannelsInformationFromServer; 116 | var 117 | Http: TIdHTTP; 118 | Text: string; 119 | Success: Boolean; 120 | begin 121 | // get channels file (JSON) text 122 | if StartsText('http://', FBaseURL) or StartsText('https://', FBaseURL) then 123 | begin 124 | Http := TIdHTTP.Create(nil); 125 | try 126 | // eventually create SSL IO handler 127 | if FileExists(ExtractFilePath(ParamStr(0)) + 'ssleay32.dll') and 128 | FileExists(ExtractFilePath(ParamStr(0)) + 'libeay32.dll') then 129 | Http.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil); 130 | 131 | try 132 | // get text from URI 133 | Text := Http.Get(FBaseURL + FChannelsFile); 134 | 135 | // check if text is available (might need check for JSON format) 136 | Success := Text <> ''; 137 | except 138 | Success := False; 139 | end; 140 | 141 | // ignore errors here! 142 | if not Success then 143 | Exit; 144 | finally 145 | Http.IOHandler.Free; 146 | Http.Free; 147 | end; 148 | end 149 | else 150 | raise Exception.Create('Protocol not supported'); 151 | 152 | FChannels.LoadFromString(Text); 153 | end; 154 | 155 | procedure TWebUpdate.GetChannels(Channels: TStrings); 156 | var 157 | Item: TWebUpdateChannelItem; 158 | begin 159 | // first get channels information from server 160 | GetChannelsInformationFromServer; 161 | 162 | Channels.Clear; 163 | for Item in FChannels.Items do 164 | Channels.Add(Item.Name) 165 | end; 166 | 167 | procedure TWebUpdate.GetLocalChannelInformation; 168 | var 169 | FullLocalFileName: TFileName; 170 | LocalSetup: TWebUpdateChannelSetup; 171 | begin 172 | FullLocalFileName := FLocalFileName; 173 | if IsRelativePath(FullLocalFileName) then 174 | FullLocalFileName := ExtractFilePath(ParamStr(0)) + FullLocalFileName; 175 | 176 | LocalSetup := TWebUpdateChannelSetup.Create; 177 | try 178 | LocalSetup.LoadFromFile(FullLocalFileName); 179 | 180 | FChannelName := LocalSetup.ChannelName; 181 | FLastModified := LocalSetup.Modified; 182 | finally 183 | LocalSetup.Free; 184 | end; 185 | end; 186 | 187 | function TWebUpdate.CheckForUpdate: Boolean; 188 | var 189 | ChannelItem: TWebUpdateChannelItem; 190 | begin 191 | Result := False; 192 | 193 | // eventually get information about local channel 194 | if FAutoGet then 195 | GetLocalChannelInformation; 196 | 197 | // locate local channel 198 | for ChannelItem in FChannels.Items do 199 | if ChannelItem.Name = FChannelName then 200 | if ChannelItem.Modified > FLastModified then 201 | Exit(True); 202 | end; 203 | 204 | procedure TWebUpdate.PerformUpdate; 205 | var 206 | LocalPath: string; 207 | Parameters: string; 208 | begin 209 | // eventually download updater 210 | if FDownloadUpdater then 211 | PerformDownloadUpdater; 212 | 213 | LocalPath := ExtractFilePath(ParamStr(0)); 214 | if FileExists(LocalPath + FUpdaterFileName) then 215 | begin 216 | Parameters := Format('-u="%s" -d=%d -c="%s" -l="%s"', [BaseURL, 1000, 217 | ChannelName, ExtractRelativePath(LocalPath, FLocalFileName)]); 218 | ShellExecute(Application.Handle, 'open', PChar(LocalPath + FUpdaterFileName), 219 | PChar(Parameters), PChar(LocalPath), SW_SHOW); 220 | Application.Terminate; 221 | end; 222 | end; 223 | 224 | procedure TWebUpdate.SetChannelName(const Value: string); 225 | begin 226 | if FChannelName <> Value then 227 | begin 228 | FChannelName := Value; 229 | FLastModified := 0; 230 | end; 231 | end; 232 | 233 | end. 234 | -------------------------------------------------------------------------------- /Source/Update Helper (Command-line)/Updater.dpr: -------------------------------------------------------------------------------- 1 | program Updater; 2 | 3 | {$APPTYPE CONSOLE} 4 | 5 | {$R *.res} 6 | 7 | uses 8 | System.SysUtils, 9 | System.Classes, 10 | System.StrUtils, 11 | {$IFDEF MSWINDOWS} 12 | WinApi.Windows, 13 | WinApi.TlHelp32, 14 | {$ENDIF} 15 | WebUpdate.Classes.Updater in '..\Common\WebUpdate.Classes.Updater.pas', 16 | WebUpdate.JSON.Serializer in '..\Common\WebUpdate.JSON.Serializer.pas', 17 | WebUpdate.JSON.Channel in '..\Common\WebUpdate.JSON.Channel.pas', 18 | WebUpdate.JSON.Channels in '..\Common\WebUpdate.JSON.Channels.pas', 19 | WebUpdate.Tools in '..\Common\WebUpdate.Tools.pas'; 20 | 21 | resourcestring 22 | RStrMD5MismatchUpdate = 'Error: MD5 mismatch, update might be corrupt!'; 23 | RStrUnknownOption = 'Error: Unknown option: %s!'; 24 | RStrUnknownCommand = 'Error: Unknown command: %s'; 25 | RStrChannelDefinitionError = 'Error: Could not load channel definition!'; 26 | RStrSetupLoadError = 'Error: Could not load setup!'; 27 | RStrNoURLSpecified = 'Error: No URL specified!'; 28 | 29 | var 30 | Delay: Integer; 31 | WebUpdater: TWebUpdater; 32 | MainAppExecutable: string; 33 | MainAppWindowCaption: string; 34 | 35 | {$IFDEF MSWINDOWS} 36 | procedure KillProcess(ProcessID: Integer); 37 | var 38 | ProcessHandle: THandle; 39 | ExitCode: Integer; 40 | begin 41 | // get process handle 42 | ProcessHandle := OpenProcess(PROCESS_CREATE_THREAD or PROCESS_VM_OPERATION 43 | or PROCESS_VM_WRITE or PROCESS_VM_READ or PROCESS_TERMINATE, False, 44 | ProcessID); 45 | 46 | // eventually close process 47 | if (ProcessHandle > 0) then 48 | try 49 | ExitCode := 0; 50 | GetExitCodeProcess(ProcessHandle, DWORD(ExitCode)); 51 | TerminateProcess(ProcessHandle, ExitCode); 52 | finally 53 | CloseHandle(ProcessHandle); 54 | end; 55 | end; 56 | 57 | function GetProcessIDForExecutable(ExecutableFileName: string): Cardinal; 58 | var 59 | ContinueLoop: Boolean; 60 | SnapshotHandle: THandle; 61 | ProcessEntry32: TProcessEntry32; 62 | Found: Boolean; 63 | begin 64 | // initialization 65 | ProcessEntry32.dwSize := SizeOf(TProcessEntry32); 66 | Found := False; 67 | 68 | // get snapshot 69 | SnapshotHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 70 | if SnapshotHandle > 0 then 71 | try 72 | ContinueLoop := Process32First(SnapshotHandle, ProcessEntry32); 73 | while Integer(ContinueLoop) <> 0 do 74 | begin 75 | if SameText(ExtractFileName(ProcessEntry32.szExeFile), ExecutableFileName) then 76 | begin 77 | Found := True; 78 | Break; 79 | end; 80 | ContinueLoop := Process32Next(SnapshotHandle, ProcessEntry32); 81 | end; 82 | if not Found then 83 | Exit(0); 84 | finally 85 | CloseHandle(SnapshotHandle); 86 | end; 87 | 88 | Result := ProcessEntry32.th32ProcessID; 89 | end; 90 | 91 | function GetProcessIDForWindow(Caption: string): Cardinal; 92 | var 93 | WinHwnd: HWND; 94 | begin 95 | Result := 0; 96 | 97 | // check for opened main application 98 | WinHwnd := FindWindow(nil, PWideChar(Caption)); 99 | if not (IsWindow(WinHwnd)) then 100 | Exit; 101 | 102 | // get process ID 103 | GetWindowThreadProcessID(WinHwnd, @Result); 104 | end; 105 | 106 | procedure CloseMainApplication; 107 | var 108 | ProcessID: Integer; 109 | Counter: Integer; 110 | begin 111 | Counter := 0; 112 | repeat 113 | ProcessID := 0; 114 | if MainAppExecutable <> '' then 115 | ProcessID := GetProcessIDForExecutable(MainAppExecutable) 116 | else if MainAppWindowCaption <> '' then 117 | ProcessID := GetProcessIDForWindow(MainAppWindowCaption); 118 | 119 | // check if process has been found 120 | if ProcessID = 0 then 121 | Exit; 122 | 123 | Sleep(1 + Delay); 124 | Inc(Counter); 125 | until Counter >= 10; 126 | 127 | KillProcess(ProcessID); 128 | end; 129 | {$ENDIF} 130 | 131 | procedure WriteUsage; 132 | begin 133 | WriteLn('Syntax: Updater.exe [-options]'); 134 | WriteLn(''); 135 | WriteLn('Options:'); 136 | WriteLn('--------'); 137 | WriteLn(''); 138 | WriteLn(' -u=URL (Base URL for JSON files)'); 139 | WriteLn(' -c=Channel (Update Channel, default is ''Stable'')'); 140 | WriteLn(' -f=FileName (Channels) (Filename of channels definition file)'); 141 | WriteLn(' -d=Delay (Integer) (Time in milliseconds before updating starts)'); 142 | WriteLn(' -l=FileName (Local filename of current setup)'); 143 | WriteLn(' -e=ExeFileName (Name of main application executable)'); 144 | WriteLn(' -w=WindowCaption (Caption of main application window)'); 145 | WriteLn(''); 146 | WriteLn('Example:'); 147 | WriteLn('--------'); 148 | WriteLn(''); 149 | WriteLn(' Updater.exe -c=Nightly'); 150 | WriteLn(''); 151 | end; 152 | 153 | procedure ScanParameters; 154 | var 155 | Index: Integer; 156 | Text: string; 157 | EqPos: Integer; 158 | begin 159 | Delay := 99; 160 | for Index := 1 to ParamCount do 161 | begin 162 | Text := ParamStr(Index); 163 | if Text[1] = '-' then 164 | begin 165 | // remove options identifier and get colon pos 166 | Delete(Text, 1, 1); 167 | EqPos := Pos('=', Text); 168 | 169 | if StartsText('u=', Text) then 170 | WebUpdater.BaseURL := Copy(Text, EqPos, Length(Text) - EqPos) 171 | else if StartsText('f=', Text) then 172 | WebUpdater.ChannelsFileName := Copy(Text, EqPos, Length(Text) - EqPos) 173 | else if StartsText('c=', Text) then 174 | WebUpdater.ChannelName := Copy(Text, EqPos, Length(Text) - EqPos) 175 | else if StartsText('d=', Text) then 176 | Delay := StrToInt(Copy(Text, EqPos, Length(Text) - EqPos)) 177 | else if StartsText('l=', Text) then 178 | WebUpdater.LocalChannelFileName := Copy(Text, EqPos, Length(Text) - EqPos) 179 | {$IFDEF MSWINDOWS} 180 | else if StartsText('e=', Text) then 181 | MainAppExecutable := Copy(Text, EqPos, Length(Text) - EqPos) 182 | else if StartsText('w=', Text) then 183 | MainAppWindowCaption := Copy(Text, EqPos, Length(Text) - EqPos) 184 | {$ENDIF} 185 | else 186 | begin 187 | WriteLn(Format(RStrUnknownOption, [Text])); 188 | WriteLn(''); 189 | WriteUsage; 190 | Halt(100); 191 | end; 192 | end 193 | else 194 | WriteLn(Format(RStrUnknownCommand, [Text])); 195 | WriteLn(''); 196 | WriteUsage; 197 | Halt(101); 198 | end; 199 | 200 | if WebUpdater.BaseURL = '' then 201 | begin 202 | WriteLn(RStrNoURLSpecified); 203 | WriteLn(''); 204 | WriteUsage; 205 | Halt(102); 206 | end; 207 | 208 | if WebUpdater.ChannelsFileName = '' then 209 | begin 210 | WriteLn('Error: No file name for channels definition specified!'); 211 | WriteLn(''); 212 | WriteUsage; 213 | Halt(103); 214 | end; 215 | end; 216 | 217 | begin 218 | try 219 | WebUpdater := TWebUpdater.Create; 220 | try 221 | ScanParameters; 222 | 223 | // give main application some time to close 224 | Sleep(1 + Delay); 225 | 226 | {$IFDEF MSWINDOWS} 227 | // close main application 228 | CloseMainApplication; 229 | {$ENDIF} 230 | 231 | // perform web update 232 | WebUpdater.PerformWebUpdate; 233 | finally 234 | WebUpdater.Free; 235 | end; 236 | except 237 | on E: Exception do 238 | Writeln(E.ClassName, ': ', E.Message); 239 | end; 240 | end. 241 | -------------------------------------------------------------------------------- /Source/Common/WebUpdate.JSON.Project.pas: -------------------------------------------------------------------------------- 1 | unit WebUpdate.JSON.Project; 2 | 3 | interface 4 | 5 | uses 6 | System.SysUtils, dwsJSON, WebUpdate.JSON.Serializer; 7 | 8 | type 9 | TWebUpdateProject = class(TJsonSerializer) 10 | type 11 | TFTPOptions = class(TJsonSerializer) 12 | private 13 | FPassword: string; 14 | FUsername: string; 15 | FServer: string; 16 | protected 17 | procedure Read(Root: TdwsJSONObject); override; 18 | procedure Write(Root: TdwsJSONObject); override; 19 | public 20 | constructor Create; 21 | 22 | property Server: string read FServer write FServer; 23 | property Username: string read FUsername write FUsername; 24 | property Password: string read FPassword write FPassword; 25 | end; 26 | 27 | TCopyOptions = class(TJsonSerializer) 28 | private 29 | FPath: string; 30 | FEnabled: Boolean; 31 | protected 32 | procedure Read(Root: TdwsJSONObject); override; 33 | procedure Write(Root: TdwsJSONObject); override; 34 | public 35 | constructor Create; 36 | 37 | property Path: string read FPath write FPath; 38 | property Enabled: Boolean read FEnabled write FEnabled; 39 | end; 40 | 41 | private 42 | FApplicationName: string; 43 | FAutoCopyUpload: Boolean; 44 | FBaseDirectory: string; 45 | FChannelsFilename: TFileName; 46 | FCopyOptions: TCopyOptions; 47 | FCurrentChannel: string; 48 | FFtpOptions: TFTPOptions; 49 | FUseMD5: Boolean; 50 | function GetFullChannelsFilename: TFileName; 51 | function GetBasePath: string; 52 | function GetChannelsPath: string; 53 | protected 54 | procedure Read(Root: TdwsJSONObject); override; 55 | procedure Write(Root: TdwsJSONObject); override; 56 | public 57 | constructor Create; 58 | destructor Destroy; override; 59 | 60 | class function GetID: string; override; 61 | 62 | property AutoCopyUpload: Boolean read FAutoCopyUpload write FAutoCopyUpload; 63 | property ApplicationName: string read FApplicationName write FApplicationName; 64 | property BaseDirectory: string read FBaseDirectory write FBaseDirectory; 65 | property BasePath: string read GetBasePath; 66 | property ChannelsFilename: TFileName read FChannelsFilename write FChannelsFilename; 67 | property ChannelsPath: string read GetChannelsPath; 68 | property Copy: TCopyOptions read FCopyOptions; 69 | property ChannelName: string read FCurrentChannel write FCurrentChannel; 70 | property FullChannelsFilename: TFileName read GetFullChannelsFilename; 71 | property FTP: TFTPOptions read FFtpOptions; 72 | property UseMD5: Boolean read FUseMD5 write FUseMD5; 73 | end; 74 | 75 | implementation 76 | 77 | { TWebUpdateProject.TFTPOptions } 78 | 79 | constructor TWebUpdateProject.TFTPOptions.Create; 80 | begin 81 | FServer := ''; 82 | FUsername := ''; 83 | FPassword := ''; 84 | end; 85 | 86 | procedure TWebUpdateProject.TFTPOptions.Read(Root: TdwsJSONObject); 87 | var 88 | Value: TdwsJSONValue; 89 | begin 90 | inherited; 91 | 92 | Value := Root.Items['Server']; 93 | if Assigned(Value) then 94 | FServer := Value.AsString; 95 | 96 | Value := Root.Items['Username']; 97 | if Assigned(Value) then 98 | FUsername := Value.AsString; 99 | 100 | Value := Root.Items['Password']; 101 | if Assigned(Value) then 102 | FPassword := Value.AsString; 103 | end; 104 | 105 | procedure TWebUpdateProject.TFTPOptions.Write(Root: TdwsJSONObject); 106 | begin 107 | inherited; 108 | 109 | if FServer <> '' then 110 | Root.AddValue('Server').AsString := FServer; 111 | 112 | if FUsername <> '' then 113 | Root.AddValue('Username').AsString := FUsername; 114 | 115 | if FPassword <> '' then 116 | Root.AddValue('Password').AsString := FPassword; 117 | end; 118 | 119 | 120 | { TWebUpdateProject.TCopyOptions } 121 | 122 | constructor TWebUpdateProject.TCopyOptions.Create; 123 | begin 124 | FPath := ''; 125 | FEnabled := False; 126 | end; 127 | 128 | procedure TWebUpdateProject.TCopyOptions.Read(Root: TdwsJSONObject); 129 | var 130 | Value: TdwsJSONValue; 131 | begin 132 | inherited; 133 | 134 | Value := Root.Items['Path']; 135 | if Assigned(Value) then 136 | FPath := Value.AsString; 137 | 138 | Value := Root.Items['Enabled']; 139 | if Assigned(Value) then 140 | FEnabled := Value.AsBoolean; 141 | end; 142 | 143 | procedure TWebUpdateProject.TCopyOptions.Write(Root: TdwsJSONObject); 144 | begin 145 | inherited; 146 | 147 | if FPath <> '' then 148 | Root.AddValue('Path').AsString := FPath; 149 | 150 | if FEnabled then 151 | Root.AddValue('Enabled').AsBoolean := FEnabled; 152 | end; 153 | 154 | 155 | { TWebUpdateProject } 156 | 157 | constructor TWebUpdateProject.Create; 158 | begin 159 | FFtpOptions := TFTPOptions.Create; 160 | FCopyOptions := TCopyOptions.Create; 161 | FCurrentChannel := 'Nightly'; 162 | end; 163 | 164 | destructor TWebUpdateProject.Destroy; 165 | begin 166 | FCopyOptions.Free; 167 | FFtpOptions.Free; 168 | inherited; 169 | end; 170 | 171 | function TWebUpdateProject.GetBasePath: string; 172 | begin 173 | if FBaseDirectory = '' then 174 | Exit(''); 175 | 176 | Result := IncludeTrailingPathDelimiter(FBaseDirectory) 177 | end; 178 | 179 | function TWebUpdateProject.GetChannelsPath: string; 180 | begin 181 | Result := ExtractFilePath(FChannelsFilename); 182 | end; 183 | 184 | function TWebUpdateProject.GetFullChannelsFilename: TFileName; 185 | begin 186 | if FChannelsFilename <> '' then 187 | if FBaseDirectory <> '' then 188 | Result := IncludeTrailingPathDelimiter(FBaseDirectory) + FChannelsFilename 189 | else 190 | Result := FChannelsFilename 191 | else 192 | Result := ''; 193 | end; 194 | 195 | class function TWebUpdateProject.GetID: string; 196 | begin 197 | Result := 'Project'; 198 | end; 199 | 200 | procedure TWebUpdateProject.Read(Root: TdwsJSONObject); 201 | var 202 | Value: TdwsJSONValue; 203 | begin 204 | inherited; 205 | 206 | Value := Root.Items['BaseDirectory']; 207 | if Assigned(Value) then 208 | FBaseDirectory := Value.AsString; 209 | 210 | Value := Root.Items['ChannelFilename']; 211 | if Assigned(Value) then 212 | FChannelsFilename := Value.AsString; 213 | 214 | Value := Root.Items['CurrentChannel']; 215 | if Assigned(Value) then 216 | FCurrentChannel := Value.AsString; 217 | 218 | Value := Root.Items['AutoCopyUpload']; 219 | if Assigned(Value) then 220 | FAutoCopyUpload := Value.AsBoolean; 221 | 222 | Value := Root.Items['ApplicationName']; 223 | if Assigned(Value) then 224 | FApplicationName := Value.AsString; 225 | 226 | Value := Root.Items['UseMD5']; 227 | if Assigned(Value) then 228 | FUseMD5 := Value.AsBoolean; 229 | 230 | Value := Root.Items['FTP']; 231 | if Value is TdwsJSONObject then 232 | FFtpOptions.Read(TdwsJSONObject(Value)); 233 | 234 | Value := Root.Items['Copy']; 235 | if Value is TdwsJSONObject then 236 | FCopyOptions.Read(TdwsJSONObject(Value)); 237 | end; 238 | 239 | procedure TWebUpdateProject.Write(Root: TdwsJSONObject); 240 | var 241 | ObjVal: TdwsJSONObject; 242 | begin 243 | inherited; 244 | 245 | if FBaseDirectory <> '' then 246 | Root.AddValue('BaseDirectory').AsString := FBaseDirectory; 247 | 248 | if FChannelsFilename <> '' then 249 | Root.AddValue('ChannelFilename').AsString := FChannelsFilename; 250 | 251 | if FCurrentChannel <> '' then 252 | Root.AddValue('CurrentChannel').AsString := FCurrentChannel; 253 | 254 | if FAutoCopyUpload = True then 255 | Root.AddValue('AutoCopyUpload').AsBoolean := FAutoCopyUpload; 256 | 257 | if FApplicationName <> '' then 258 | Root.AddValue('ApplicationName').AsString := FApplicationName; 259 | 260 | if FUseMD5 = True then 261 | Root.AddValue('UseMD5').AsBoolean := FUseMD5; 262 | 263 | // write FTP options (and add if it contains any data) 264 | ObjVal := TdwsJSONObject.Create; 265 | try 266 | FFtpOptions.Write(ObjVal); 267 | if ObjVal.ElementCount > 0 then 268 | Root.Add('FTP', ObjVal.Clone); 269 | finally 270 | ObjVal.Free; 271 | end; 272 | 273 | // write copy options (and add if it contains any data) 274 | ObjVal := TdwsJSONObject.Create; 275 | try 276 | FCopyOptions.Write(ObjVal); 277 | if ObjVal.ElementCount > 0 then 278 | Root.Add('Copy', ObjVal.Clone); 279 | finally 280 | ObjVal.Free; 281 | end; 282 | end; 283 | 284 | end. 285 | -------------------------------------------------------------------------------- /Source/Snapshot Tool (Command Line)/SnapshotTool.dpr: -------------------------------------------------------------------------------- 1 | program SnapshotTool; 2 | 3 | {$APPTYPE CONSOLE} 4 | 5 | {$R *.res} 6 | 7 | uses 8 | System.IOUtils, 9 | System.SysUtils, 10 | System.StrUtils, 11 | WinApi.Windows, 12 | WebUpdate.Classes.WebUpdate in '..\Common\WebUpdate.Classes.WebUpdate.pas', 13 | WebUpdate.JSON.Channel in '..\Common\WebUpdate.JSON.Channel.pas', 14 | WebUpdate.JSON.Channels in '..\Common\WebUpdate.JSON.Channels.pas', 15 | WebUpdate.JSON.Project in '..\Common\WebUpdate.JSON.Project.pas', 16 | WebUpdate.JSON.Serializer in '..\Common\WebUpdate.JSON.Serializer.pas', 17 | WebUpdate.Tools in '..\Common\WebUpdate.Tools.pas'; 18 | 19 | procedure WriteUsage; 20 | begin 21 | WriteLn(Format('Syntax: %s project.wup command [more commands] [-options]', 22 | [ExtractFileName(ParamStr(0))])); 23 | WriteLn(''); 24 | WriteLn(' project.wup must be replaced by your project name'); 25 | WriteLn(''); 26 | WriteLn('Commands:'); 27 | WriteLn('---------'); 28 | WriteLn(''); 29 | WriteLn(' s or S or Snapshot (take snapshot)'); 30 | WriteLn(' c or C or Copy (copy to path)'); 31 | WriteLn(' u or U or Upload (upload to server)'); 32 | WriteLn(''); 33 | WriteLn('Options:'); 34 | WriteLn('---------'); 35 | WriteLn(''); 36 | WriteLn(' -Channel="channel name" (with/without quotes, default: "Nightly")'); 37 | WriteLn(' -FtpHost=host (FTP host name, overrides project''s default)'); 38 | WriteLn(' -FtpUser=username (FTP user name, overrides project''s default)'); 39 | WriteLn(' -FtpPassword=password (FTP password, overrides project''s default)'); 40 | WriteLn(' -CopyPath=path (Path of snapshot copies)'); 41 | WriteLn(''); 42 | WriteLn('Example:'); 43 | WriteLn('--------'); 44 | WriteLn(''); 45 | WriteLn(Format(' %s project.wup scu -Channel=Beta', 46 | [ExtractFileName(ParamStr(0))])); 47 | WriteLn(''); 48 | end; 49 | 50 | procedure UploadSnapshot(Project: TWebUpdateProject); 51 | begin 52 | 53 | end; 54 | 55 | procedure CopySnapshot(Project: TWebUpdateProject); 56 | var 57 | Path: string; 58 | ChannelSetup: TWebUpdateChannelSetup; 59 | FileItem: TWebUpdateFileItem; 60 | RealFileName, ChannelFileName, DestFileName: TFileName; 61 | begin 62 | Path := IncludeTrailingPathDelimiter(Project.Copy.Path); 63 | if IsRelativePath(Path) then 64 | Path := Project.BasePath + Path; 65 | 66 | ChannelFileName := Project.ChannelsPath + Project.ChannelName + '.json'; 67 | 68 | // upload files 69 | ChannelSetup := TWebUpdateChannelSetup.Create; 70 | try 71 | // load channel setup 72 | ChannelSetup.LoadFromFile(ChannelFileName); 73 | 74 | for FileItem in ChannelSetup.Items do 75 | begin 76 | WriteLn('Copying file ', FileItem.FileName, '...'); 77 | 78 | RealFileName := Project.BasePath + WebToLocalFileName(FileItem.FileName); 79 | 80 | // copy file 81 | DestFileName := ExpandFileName(Path + Project.ChannelName + '\' + FileItem.FileName); 82 | ForceDirectories(ExtractFileDir(DestFileName)); 83 | TFile.Copy(RealFileName, DestFileName, True); 84 | 85 | // set file date/time according to the JSON file 86 | FileSetDate(DestFileName, DateTimeToFileDate(FileItem.Modified)); 87 | end; 88 | 89 | // copy channel setup 90 | WriteLn('Copying channel setup...'); 91 | DestFileName := ExpandFileName(Path + Project.ChannelName + '\' + 92 | Project.ChannelName + '.json'); 93 | ForceDirectories(ExtractFileDir(DestFileName)); 94 | TFile.Copy(ChannelFileName, DestFileName, True); 95 | 96 | // set file date/time according to the JSON file 97 | FileSetDate(DestFileName, DateTimeToFileDate(ChannelSetup.Modified)); 98 | finally 99 | ChannelSetup.Free; 100 | end; 101 | 102 | // copy channel file 103 | WriteLn('Copying channels list...'); 104 | DestFileName := ExpandFileName(Path + ExtractFileName(Project.ChannelsFilename)); 105 | TFile.Copy(Project.FullChannelsFilename, DestFileName, True); 106 | end; 107 | 108 | procedure TakeSnapshot(Project: TWebUpdateProject); 109 | var 110 | Item: TWebUpdateFileItem; 111 | ChannelItem: TWebUpdateChannelItem; 112 | Fad: TWin32FileAttributeData; 113 | LastModified: TDateTime; 114 | FileName: TFileName; 115 | Channels: TWebUpdateChannels; 116 | ChannelSetup: TWebUpdateChannelSetup; 117 | begin 118 | // update status 119 | WriteLn('Taking snapshot...'); 120 | 121 | Channels := TWebUpdateChannels.Create; 122 | try 123 | // load 124 | Channels.LoadFromFile(Project.ChannelsPath + Project.ChannelsFilename); 125 | ChannelItem := Channels.GetItemForChannel(Project.ChannelName); 126 | 127 | // create selected channels 128 | ChannelSetup := TWebUpdateChannelSetup.Create; 129 | try 130 | // get filename for currently selected channel 131 | FileName := Project.ChannelsPath + Project.ChannelName + '\' + 132 | Project.ChannelName + '.json'; 133 | 134 | ChannelSetup.LoadFromFile(FileName); 135 | 136 | // store current channel name 137 | ChannelSetup.AppName := Project.ApplicationName; 138 | ChannelSetup.ChannelName := Project.ChannelName; 139 | LastModified := 0; 140 | for Item in ChannelSetup.Items do 141 | begin 142 | // get file attribute 143 | if not GetFileAttributesEx(PChar(Item.FileName), GetFileExInfoStandard, @Fad) then 144 | RaiseLastOSError; 145 | 146 | // create (& update) file item 147 | Item.Modified := FileTimeToDateTime(Fad.ftLastWriteTime); 148 | Item.FileSize := Fad.nFileSizeLow; 149 | if Project.UseMD5 then 150 | Item.MD5Hash := MD5(Item.FileName) 151 | else 152 | Item.MD5Hash := ''; 153 | 154 | if Item.Modified > LastModified then 155 | LastModified := Item.Modified; 156 | 157 | // add item to file items list 158 | ChannelSetup.Items.Add(Item); 159 | end; 160 | 161 | ChannelSetup.Modified := LastModified; 162 | ChannelItem.Modified := LastModified; 163 | 164 | // save channel setup 165 | ChannelSetup.SaveToFile(FileName); 166 | finally 167 | ChannelSetup.Free; 168 | end; 169 | 170 | // save channels to file 171 | Channels.SaveToFile(Project.ChannelsPath + Project.ChannelsFilename); 172 | finally 173 | Channels.Free; 174 | end; 175 | end; 176 | 177 | type 178 | TWebUpdateCommand = (wuSnapshot, wuUpload, wuCopy); 179 | TWebUpdateCommands = set of TWebUpdateCommand; 180 | var 181 | Project: TWebUpdateProject; 182 | ParamIndex, CharIndex: Integer; 183 | Commands: TWebUpdateCommands; 184 | Text: string; 185 | EqPos: Integer; 186 | begin 187 | try 188 | // check for parameters 189 | if ParamCount = 0 then 190 | begin 191 | WriteUsage; 192 | Halt(100); 193 | end; 194 | 195 | // check if project file exists 196 | if not FileExists(ParamStr(1)) then 197 | begin 198 | WriteLn('File %s does not exist!', ParamStr(1)); 199 | Halt(101); 200 | end; 201 | 202 | Project := TWebUpdateProject.Create; 203 | try 204 | // now load project 205 | Project.LoadFromFile(ParamStr(1)); 206 | 207 | Commands := []; 208 | for ParamIndex := 2 to ParamCount do 209 | begin 210 | Text := ParamStr(ParamIndex); 211 | if Text[1] = '-' then 212 | begin 213 | // remove options identifier and get colon pos 214 | Delete(Text, 1, 1); 215 | EqPos := Pos('=', Text); 216 | 217 | if StartsText('Channel:', Text) then 218 | Project.ChannelName := Copy(Text, EqPos, Length(Text) - EqPos) 219 | else if StartsText('FtpHost:', Text) then 220 | Project.FTP.Server := Copy(Text, EqPos, Length(Text) - EqPos) 221 | else if StartsText('FtpUser:', Text) then 222 | Project.FTP.Username := Copy(Text, EqPos, Length(Text) - EqPos) 223 | else if StartsText('FtpPassword:', Text) then 224 | Project.FTP.Password := Copy(Text, EqPos, Length(Text) - EqPos) 225 | else if StartsText('CopyPath:', Text) then 226 | Project.Copy.Path := Copy(Text, EqPos, Length(Text) - EqPos) 227 | else 228 | begin 229 | WriteLn('Unknown option: %s!', Text); 230 | Halt(102); 231 | end; 232 | end 233 | else 234 | begin 235 | if SameText(Text, 'Snapshot') then 236 | Commands := Commands + [wuSnapshot] 237 | else if SameText(Text, 'Copy') then 238 | Commands := Commands + [wuCopy] 239 | else if SameText(Text, 'Upload') then 240 | Commands := Commands + [wuUpload] 241 | else 242 | for CharIndex := 1 to Length(Text) do 243 | case Text[CharIndex] of 244 | 's', 'S': 245 | Commands := Commands + [wuSnapshot]; 246 | 'c', 'C': 247 | Commands := Commands + [wuCopy]; 248 | 'u', 'U': 249 | Commands := Commands + [wuUpload]; 250 | else 251 | begin 252 | WriteLn('Unknown command %s', Text[CharIndex]); 253 | Halt(103); 254 | end; 255 | end; 256 | end; 257 | end; 258 | 259 | if Project.AutoCopyUpload then 260 | begin 261 | if Project.Copy.Enabled then 262 | Commands := Commands + [wuCopy]; 263 | 264 | if Project.FTP.Server <> '' then 265 | Commands := Commands + [wuUpload]; 266 | end; 267 | 268 | if wuSnapshot in Commands then 269 | TakeSnapshot(Project); 270 | 271 | // eventually copy to path 272 | if wuCopy in Commands then 273 | CopySnapshot(Project); 274 | 275 | // eventually upload to a server 276 | if wuUpload in Commands then 277 | UploadSnapshot(Project); 278 | finally 279 | Project.Free; 280 | end; 281 | except 282 | on E: Exception do 283 | Writeln(E.ClassName, ': ', E.Message); 284 | end; 285 | end. 286 | -------------------------------------------------------------------------------- /Source/Update Helper Wizard/WebUpdate.GUI.Updater.pas: -------------------------------------------------------------------------------- 1 | unit WebUpdate.GUI.Updater; 2 | 3 | interface 4 | 5 | uses 6 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, 7 | Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, 8 | Vcl.ComCtrls, Vcl.ExtCtrls, Vcl.ImgList, VirtualTrees, 9 | WebUpdate.Classes.Updater; 10 | 11 | type 12 | TNodeFileItem = record 13 | FileItem: TFileItem; 14 | end; 15 | PNodeFileItem = ^TNodeFileItem; 16 | 17 | TFormWebUpdate = class(TForm) 18 | ButtonClose: TButton; 19 | ButtonNext: TButton; 20 | CheckBoxStartApplication: TCheckBox; 21 | ComboBoxChannels: TComboBox; 22 | ImageHeader: TImage; 23 | ImageList: TImageList; 24 | LabelCurrentFile: TLabel; 25 | LabelFileList: TLabel; 26 | LabelHeader: TLabel; 27 | LabelRemainingTime: TLabel; 28 | LabelSelectChannel: TLabel; 29 | LabelSpeed: TLabel; 30 | LabelSummary: TLabel; 31 | LabelTotalStatus: TLabel; 32 | PageControl: TPageControl; 33 | PanelControl: TPanel; 34 | PanelHeader: TPanel; 35 | ProgressBarCurrent: TProgressBar; 36 | ProgressBarTotal: TProgressBar; 37 | RadioButtonAlternative: TRadioButton; 38 | RadioButtonStable: TRadioButton; 39 | TabFileList: TTabSheet; 40 | TabProgress: TTabSheet; 41 | TabSelectChannel: TTabSheet; 42 | TabSummary: TTabSheet; 43 | TreeFiles: TVirtualStringTree; 44 | procedure FormCreate(Sender: TObject); 45 | procedure FormDestroy(Sender: TObject); 46 | procedure ButtonAbortClick(Sender: TObject); 47 | procedure ButtonFinishClick(Sender: TObject); 48 | procedure ButtonNextClick(Sender: TObject); 49 | procedure ButtonStartClick(Sender: TObject); 50 | procedure RadioButtonChannelClick(Sender: TObject); 51 | procedure TabProgressShow(Sender: TObject); 52 | procedure TabSelectChannelShow(Sender: TObject); 53 | procedure TabFileListShow(Sender: TObject); 54 | procedure TabSummaryShow(Sender: TObject); 55 | procedure TreeFilesGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; 56 | Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); 57 | procedure TreeFilesGetImageIndex(Sender: TBaseVirtualTree; 58 | Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; 59 | var Ghosted: Boolean; var ImageIndex: Integer); 60 | private 61 | FWebUpdater: TWebUpdater; 62 | FCommandLine: Boolean; 63 | FMainAppWindowCaption: string; 64 | FMainAppExecutable: string; 65 | FDelay: Integer; 66 | FVerbose: Boolean; 67 | 68 | procedure ProgressEventHandler(Sender: TObject; Progress: Integer; 69 | ByteCount: Integer; KBPS: Single; RemainingTime: TDateTime); 70 | procedure FileNameProgressEventHandler(Sender: TObject; const FileName: TFileName); 71 | procedure WebUpdateCompleteEventHandler(Sender: TObject); 72 | procedure ErrorHandler(Sender: TObject; ErrorType: TWebUpdateErrorType; 73 | const FileName: TFileName; var Ignore: Boolean); 74 | public 75 | procedure ScanCommandLineParameters; 76 | procedure PerformWebUpdate; 77 | function CloseMainApplication: Boolean; 78 | end; 79 | 80 | var 81 | FormWebUpdate: TFormWebUpdate; 82 | 83 | implementation 84 | 85 | {$R *.dfm} 86 | 87 | uses 88 | System.StrUtils, WinAPI.ShellAPI, WinAPI.TlHelp32, dwsUtils; 89 | 90 | resourcestring 91 | RStrBaseURL = 'https://raw.githubusercontent.com/CWBudde/WebUpdate/master/Binaries/Snapshots/'; 92 | 93 | resourcestring 94 | RStrMD5MismatchUpdate = 'MD5 mismatch, update might be corrupt!'; 95 | RStrUnknownOption = 'Unknown option: %s!'; 96 | RStrUnknownCommand = 'Unknown command: %s'; 97 | RStrChannelDefinitionError = 'Could not load channel definition!'; 98 | RStrSetupLoadError = 'Could not load setup!'; 99 | 100 | procedure KillProcess(ProcessID: Integer); 101 | var 102 | ProcessHandle: THandle; 103 | ExitCode: Integer; 104 | begin 105 | // get process handle 106 | ProcessHandle := OpenProcess(PROCESS_CREATE_THREAD or PROCESS_VM_OPERATION 107 | or PROCESS_VM_WRITE or PROCESS_VM_READ or PROCESS_TERMINATE, False, 108 | ProcessID); 109 | 110 | // eventually close process 111 | if (ProcessHandle > 0) then 112 | try 113 | ExitCode := 0; 114 | GetExitCodeProcess(ProcessHandle, DWORD(ExitCode)); 115 | TerminateProcess(ProcessHandle, ExitCode); 116 | finally 117 | CloseHandle(ProcessHandle); 118 | end; 119 | end; 120 | 121 | function GetProcessIDForExecutable(ExecutableFileName: string): Cardinal; 122 | var 123 | ContinueLoop: Boolean; 124 | SnapshotHandle: THandle; 125 | ProcessEntry32: TProcessEntry32; 126 | Found: Boolean; 127 | begin 128 | // initialization 129 | ProcessEntry32.dwSize := SizeOf(TProcessEntry32); 130 | Found := False; 131 | 132 | // get snapshot 133 | SnapshotHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 134 | if SnapshotHandle > 0 then 135 | try 136 | ContinueLoop := Process32First(SnapshotHandle, ProcessEntry32); 137 | while Integer(ContinueLoop) <> 0 do 138 | begin 139 | if UnicodeSameText(ExtractFileName(ProcessEntry32.szExeFile), ExecutableFileName) then 140 | begin 141 | Found := True; 142 | Break; 143 | end; 144 | ContinueLoop := Process32Next(SnapshotHandle, ProcessEntry32); 145 | end; 146 | if not Found then 147 | Exit(0); 148 | finally 149 | CloseHandle(SnapshotHandle); 150 | end; 151 | 152 | Result := ProcessEntry32.th32ProcessID; 153 | end; 154 | 155 | function GetProcessIDForWindow(Caption: string): Cardinal; 156 | var 157 | WinHwnd: HWND; 158 | begin 159 | Result := 0; 160 | 161 | // check for opened main application 162 | WinHwnd := FindWindow(nil, PWideChar(Caption)); 163 | if not (IsWindow(WinHwnd)) then 164 | Exit; 165 | 166 | // get process ID 167 | GetWindowThreadProcessID(WinHwnd, @Result); 168 | end; 169 | 170 | 171 | { TFormWebUpdate } 172 | 173 | procedure TFormWebUpdate.FormCreate(Sender: TObject); 174 | begin 175 | PageControl.ActivePage := TabSelectChannel; 176 | TreeFiles.NodeDataSize := SizeOf(TNodeFileItem); 177 | 178 | FMainAppWindowCaption := ''; 179 | FMainAppExecutable := ''; 180 | 181 | // create WebUpdater 182 | FWebUpdater := TWebUpdater.Create; 183 | FWebUpdater.BaseURL := RStrBaseURL; 184 | FWebUpdater.OnProgress := ProgressEventHandler; 185 | FWebUpdater.OnFileNameProgress := FileNameProgressEventHandler; 186 | FWebUpdater.OnDone := WebUpdateCompleteEventHandler; 187 | FWebUpdater.OnError := ErrorHandler; 188 | 189 | ScanCommandLineParameters; 190 | end; 191 | 192 | procedure TFormWebUpdate.FormDestroy(Sender: TObject); 193 | begin 194 | FWebUpdater.Free; 195 | end; 196 | 197 | procedure TFormWebUpdate.ButtonAbortClick(Sender: TObject); 198 | begin 199 | if Assigned(FWebUpdater) then 200 | FWebUpdater.Abort; 201 | Close; 202 | end; 203 | 204 | procedure TFormWebUpdate.ButtonFinishClick(Sender: TObject); 205 | var 206 | AppName: TFileName; 207 | begin 208 | // now eventually execute specified application 209 | if CheckBoxStartApplication.Visible and CheckBoxStartApplication.Checked then 210 | begin 211 | AppName := FWebUpdater.MainAppFileName; 212 | if AppName <> '' then 213 | ShellExecute(Application.Handle, 'open', PChar(AppName), nil, 214 | PChar(ExtractFileDir(AppName)), SW_SHOW); 215 | end; 216 | 217 | Close; 218 | end; 219 | 220 | procedure TFormWebUpdate.ButtonNextClick(Sender: TObject); 221 | begin 222 | if RadioButtonStable.Checked then 223 | FWebUpdater.ChannelName := 'Stable' 224 | else 225 | FWebUpdater.ChannelName := ComboBoxChannels.Text; 226 | 227 | // switch pages to file list / progress tab 228 | if FVerbose then 229 | PageControl.ActivePage := TabFileList 230 | else 231 | begin 232 | PerformWebUpdate; 233 | 234 | PageControl.ActivePage := TabProgress; 235 | Update; 236 | end; 237 | end; 238 | 239 | procedure TFormWebUpdate.ButtonStartClick(Sender: TObject); 240 | begin 241 | PerformWebUpdate; 242 | 243 | // switch pages to progress tab 244 | PageControl.ActivePage := TabProgress; 245 | Update; 246 | end; 247 | 248 | procedure TFormWebUpdate.FileNameProgressEventHandler(Sender: TObject; 249 | const FileName: TFileName); 250 | begin 251 | LabelCurrentFile.Caption := 'Current File: ' + FileName; 252 | end; 253 | 254 | procedure TFormWebUpdate.ProgressEventHandler(Sender: TObject; 255 | Progress: Integer; ByteCount: Integer; KBPS: Single; RemainingTime: TDateTime); 256 | begin 257 | ProgressBarCurrent.Position := Progress; 258 | ProgressBarTotal.Position := ProgressBarTotal.Position + ByteCount; 259 | 260 | LabelRemainingTime.Caption := 'Time remaining: ' + TimeToStr(RemainingTime); 261 | LabelRemainingTime.Visible := True; 262 | LabelSpeed.Caption := 'Speed: ' + IntToStr(Round(KBPS)) + ' kb/s'; 263 | LabelSpeed.Visible := True; 264 | end; 265 | 266 | procedure TFormWebUpdate.WebUpdateCompleteEventHandler(Sender: TObject); 267 | begin 268 | // allow starting the application, if an (existing!) app is specified 269 | CheckBoxStartApplication.Visible := FileExists(FWebUpdater.MainAppFileName); 270 | CheckBoxStartApplication.Checked := CheckBoxStartApplication.Visible; 271 | 272 | // switch pages to summary tab 273 | PageControl.ActivePage := TabSummary; 274 | end; 275 | 276 | procedure TFormWebUpdate.ErrorHandler(Sender: TObject; 277 | ErrorType: TWebUpdateErrorType; const FileName: TFileName; var Ignore: Boolean); 278 | begin 279 | if ErrorType = etChecksum then 280 | case MessageDlg(RStrMD5MismatchUpdate, 281 | mtWarning, [mbAbort, mbIgnore], 0) of 282 | mrAbort: 283 | Ignore := False; 284 | mrIgnore: 285 | Ignore := True; 286 | end 287 | else 288 | Ignore := False; 289 | end; 290 | 291 | procedure TFormWebUpdate.RadioButtonChannelClick(Sender: TObject); 292 | begin 293 | ComboBoxChannels.Visible := RadioButtonAlternative.Checked; 294 | end; 295 | 296 | procedure TFormWebUpdate.ScanCommandLineParameters; 297 | var 298 | Index: Integer; 299 | Text: string; 300 | EqPos: Integer; 301 | ChannelNames: TStringList; 302 | begin 303 | FVerbose := False; 304 | FCommandLine := ParamCount >= 1; 305 | 306 | for Index := 1 to ParamCount do 307 | begin 308 | Text := ParamStr(Index); 309 | if Text[1] = '-' then 310 | begin 311 | // remove options identifier and get colon pos 312 | Delete(Text, 1, 1); 313 | EqPos := Pos('=', Text); 314 | 315 | if StartsText('u=', Text) then 316 | FWebUpdater.BaseURL := Copy(Text, EqPos + 1, Length(Text) - EqPos) 317 | else if StartsText('f=', Text) then 318 | FWebUpdater.ChannelsFileName := Copy(Text, EqPos + 1, Length(Text) - EqPos) 319 | else if StartsText('c=', Text) then 320 | FWebUpdater.ChannelName := Copy(Text, EqPos + 1, Length(Text) - EqPos) 321 | else if StartsText('d=', Text) then 322 | FDelay := StrToInt(Copy(Text, EqPos + 1, Length(Text) - EqPos)) 323 | else if StartsText('l=', Text) then 324 | FWebUpdater.LocalChannelFileName := Copy(Text, EqPos + 1, Length(Text) - EqPos) 325 | else if StartsText('e=', Text) then 326 | FMainAppExecutable := Copy(Text, EqPos + 1, Length(Text) - EqPos) 327 | else if StartsText('w=', Text) then 328 | FMainAppWindowCaption := Copy(Text, EqPos + 1, Length(Text) - EqPos) 329 | else if StartsText('verbose', Text) then 330 | FVerbose := True 331 | else 332 | begin 333 | MessageDlg(Format(RStrUnknownOption, [Text]), mtError, [mbOK], 0); 334 | Exit; 335 | end; 336 | end 337 | else 338 | MessageDlg(Format(RStrUnknownCommand, [Text]), mtError, [mbOK], 0); 339 | end; 340 | 341 | // check for command-line calling 342 | if FCommandLine then 343 | begin 344 | PerformWebUpdate; 345 | 346 | // switch pages to progress tab 347 | PageControl.ActivePage := TabProgress; 348 | Update; 349 | end 350 | else 351 | begin 352 | FVerbose := True; 353 | ChannelNames := TStringList.Create; 354 | try 355 | ComboBoxChannels.Clear; 356 | FWebUpdater.GetChannelNames(ChannelNames); 357 | for Index := 0 to ChannelNames.Count - 1 do 358 | if not SameText(ChannelNames[Index], 'Stable') then 359 | ComboBoxChannels.Items.Add(ChannelNames[Index]); 360 | ComboBoxChannels.ItemIndex := 0; 361 | finally 362 | ChannelNames.Free; 363 | end; 364 | end; 365 | end; 366 | 367 | procedure TFormWebUpdate.TabProgressShow(Sender: TObject); 368 | begin 369 | ProgressBarTotal.Max := FWebUpdater.TotalBytes; 370 | ProgressBarTotal.Position := 0; 371 | 372 | ButtonNext.Visible := False; 373 | ButtonClose.Caption := '&Abort'; 374 | ButtonClose.OnClick := ButtonAbortClick; 375 | end; 376 | 377 | procedure TFormWebUpdate.TabSelectChannelShow(Sender: TObject); 378 | begin 379 | ButtonNext.Visible := True; 380 | if FVerbose then 381 | ButtonNext.Caption := '&Next >' 382 | else 383 | ButtonNext.Caption := '&Start >'; 384 | ButtonNext.OnClick := ButtonNextClick; 385 | ButtonClose.Caption := '&Abort'; 386 | ButtonClose.OnClick := ButtonAbortClick; 387 | end; 388 | 389 | procedure TFormWebUpdate.TabFileListShow(Sender: TObject); 390 | var 391 | FileList: TFileItemList; 392 | FileItem: TFileItem; 393 | Node: PVirtualNode; 394 | NodeData: PNodeFileItem; 395 | begin 396 | ButtonNext.Visible := True; 397 | ButtonNext.Caption := '&Start >'; 398 | ButtonNext.OnClick := ButtonStartClick; 399 | ButtonClose.Caption := '&Abort'; 400 | ButtonClose.OnClick := ButtonAbortClick; 401 | 402 | TreeFiles.BeginUpdate; 403 | TreeFiles.Clear; 404 | try 405 | FileList := FWebUpdater.FileItemList; 406 | for FileItem in FileList do 407 | begin 408 | Node := TreeFiles.AddChild(TreeFiles.RootNode); 409 | NodeData := TreeFiles.GetNodeData(Node); 410 | NodeData^.FileItem := FileItem; 411 | end; 412 | finally 413 | TreeFiles.EndUpdate 414 | end; 415 | end; 416 | 417 | procedure TFormWebUpdate.TabSummaryShow(Sender: TObject); 418 | begin 419 | ButtonNext.Visible := False; 420 | ButtonClose.Caption := '&Finish'; 421 | ButtonClose.OnClick := ButtonFinishClick; 422 | end; 423 | 424 | procedure TFormWebUpdate.TreeFilesGetImageIndex(Sender: TBaseVirtualTree; 425 | Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; 426 | var Ghosted: Boolean; var ImageIndex: Integer); 427 | var 428 | NodeData: PNodeFileItem; 429 | begin 430 | // Ignore overlay and other columns 431 | if (Kind = ikOverlay) or (Column <> 0) then 432 | Exit; 433 | 434 | NodeData := TreeFiles.GetNodeData(Node); 435 | 436 | case NodeData.FileItem.Action of 437 | faAdd: 438 | ImageIndex := 0; 439 | faChange: 440 | ImageIndex := 1; 441 | faDelete: 442 | ImageIndex := 2; 443 | faVerify: 444 | ImageIndex := 3; 445 | end; 446 | end; 447 | 448 | procedure TFormWebUpdate.TreeFilesGetText(Sender: TBaseVirtualTree; 449 | Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; 450 | var CellText: string); 451 | var 452 | NodeData: PNodeFileItem; 453 | begin 454 | CellText := ''; 455 | NodeData := TreeFiles.GetNodeData(Node); 456 | case Column of 457 | 0: 458 | CellText := NodeData^.FileItem.FileName; 459 | 1: 460 | if NodeData^.FileItem.Modified > 0 then 461 | CellText := DateTimeToStr(NodeData^.FileItem.Modified); 462 | 2: 463 | if NodeData^.FileItem.FileSize > 0 then 464 | CellText := IntToStr(NodeData^.FileItem.FileSize); 465 | end; 466 | end; 467 | 468 | function TFormWebUpdate.CloseMainApplication: Boolean; 469 | var 470 | ProcessID: Integer; 471 | Counter: Integer; 472 | begin 473 | Result := False; 474 | Counter := 0; 475 | repeat 476 | ProcessID := 0; 477 | if FMainAppExecutable <> '' then 478 | ProcessID := GetProcessIDForExecutable(FMainAppExecutable) 479 | else if FMainAppWindowCaption <> '' then 480 | ProcessID := GetProcessIDForWindow(FMainAppWindowCaption); 481 | 482 | // check if process has been found 483 | if ProcessID = 0 then 484 | Exit(True); 485 | 486 | // show dialog 487 | case MessageDlg('Main application is already running!' + #13#10#13#10 + 488 | 'Force closing the main application?', mtWarning, [mbYes, mbAbort, 489 | mbRetry, mbIgnore], 0) of 490 | mrRetry: 491 | Sleep(1 + FDelay); 492 | mrYes: 493 | KillProcess(ProcessID); 494 | mrAbort: 495 | Exit(False); 496 | mrIgnore: 497 | Exit(True); 498 | end; 499 | Inc(Counter); 500 | until Counter >= 10; 501 | end; 502 | 503 | procedure TFormWebUpdate.PerformWebUpdate; 504 | begin 505 | // give other applications time to close 506 | Sleep(1 + FDelay); 507 | 508 | // first check if main application is still running 509 | if CloseMainApplication then 510 | FWebUpdater.PerformWebUpdate; 511 | end; 512 | 513 | end. 514 | -------------------------------------------------------------------------------- /Source/Common/WebUpdate.Classes.Updater.pas: -------------------------------------------------------------------------------- 1 | unit WebUpdate.Classes.Updater; 2 | 3 | interface 4 | 5 | uses 6 | System.SysUtils, System.Classes, System.Generics.Collections, 7 | IdHTTP, IdComponent, dwsComp, dwsExprs, dwsErrors, dwsClassesLibModule, 8 | WebUpdate.JSON.Channels, WebUpdate.JSON.Channel; 9 | 10 | type 11 | EHttpDownload = class(Exception); 12 | 13 | TFileItem = class 14 | type 15 | TFileAction = (faAdd, faChange, faDelete, faVerify); 16 | private 17 | FFileName: TFileName; 18 | FLocalFileName: TFileName; 19 | FMD5Hash: string; 20 | FAction: TFileAction; 21 | FModified: TDateTime; 22 | FFileSize: Integer; 23 | procedure SetFileName(const Value: TFileName); 24 | protected 25 | procedure UpdateLocalFileName; 26 | public 27 | constructor Create(const FileName: TFileName; MD5Hash: string = ''; 28 | FileSize: Integer = 0; Modified: TDateTime = 0); 29 | 30 | property FileName: TFileName read FFileName write SetFileName; 31 | property LocalFileName: TFileName read FLocalFileName; 32 | property MD5Hash: string read FMD5Hash write FMD5Hash; 33 | property Action: TFileAction read FAction write FAction; 34 | property Modified: TDateTime read FModified write FModified; 35 | property FileSize: Integer read FFileSize write FFileSize; 36 | end; 37 | 38 | TFileItemList = class(TList) 39 | public 40 | function LocateItemByFileName(const FileName: TFileName): TFileItem; 41 | end; 42 | 43 | TWebUpdateErrorType = (etDownload, etChecksum); 44 | 45 | TUpdaterThread = class(TThread) 46 | type 47 | TProgressEvent = procedure (Sender: TObject; Progress: Integer; 48 | ByteCount: Integer; KBPS: Single; ProgressTime: TDateTime) of object; 49 | TFileNameProgressEvent = procedure (Sender: TObject; const FileName: TFileName) of object; 50 | TErrorEvent = procedure (Sender: TObject; ErrorType: TWebUpdateErrorType; 51 | const FileName: TFileName; var Ignore: Boolean) of object; 52 | TScriptErrorsEvent = procedure (Sender: TObject; const MessageList: TdwsMessageList) of object; 53 | private 54 | FFiles: TFileItemList; 55 | FHttp: TIdHttp; 56 | FLocalPath: string; 57 | FBasePath: string; 58 | FStartTimeStamp: TDateTime; 59 | FLastTimeStamp: TDateTime; 60 | FLastWorkCount: Integer; 61 | 62 | FOnFileNameProgress: TFileNameProgressEvent; 63 | FOnProgress: TProgressEvent; 64 | FOnDone: TNotifyEvent; 65 | FOnScriptErrors: TScriptErrorsEvent; 66 | FOnError: TErrorEvent; 67 | procedure HttpWork(ASender: TObject; AWorkMode: TWorkMode; AWorkCount: Int64); 68 | protected 69 | procedure Execute; override; 70 | public 71 | constructor Create(const Files: TFileItemList); reintroduce; 72 | 73 | property Files: TFileItemList read FFiles; 74 | property BasePath: string read FBasePath write FBasePath; 75 | property LocalPath: string read FLocalPath write FLocalPath; 76 | 77 | property OnProgress: TProgressEvent read FOnProgress write FOnProgress; 78 | property OnFileNameProgress: TFileNameProgressEvent read FOnFileNameProgress write FOnFileNameProgress; 79 | property OnDone: TNotifyEvent read FOnDone write FOnDone; 80 | property OnError: TErrorEvent read FOnError write FOnError; 81 | property OnScriptErrors: TScriptErrorsEvent read FOnScriptErrors write FOnScriptErrors; 82 | end; 83 | 84 | TWebUpdater = class 85 | private 86 | FBaseURL: string; 87 | FChannelName: string; 88 | FChannels: TWebUpdateChannels; 89 | FChannelPath: string; 90 | FChannelsFileName: TFileName; 91 | FLocalChannelFileName: TFileName; 92 | FNewSetup: TWebUpdateChannelSetup; 93 | FThread: TUpdaterThread; 94 | FFileItemListCache: TFileItemList; 95 | FTotalSize: Int64; 96 | FCurrentSize: Int64; 97 | FDownloadSpeedAverage: Single; 98 | FScriptCompiler: TDelphiWebScript; 99 | FClassesLib: TdwsClassesLib; 100 | 101 | FOnFileNameProgress: TUpdaterThread.TFileNameProgressEvent; 102 | FOnScriptErrors: TUpdaterThread.TScriptErrorsEvent; 103 | FOnDone: TNotifyEvent; 104 | FOnError: TUpdaterThread.TErrorEvent; 105 | FOnProgress: TUpdaterThread.TProgressEvent; 106 | 107 | function GetFileItemList: TFileItemList; 108 | function GetLocalChannelFileName: TFileName; 109 | function GetMainAppFileName: TFileName; 110 | function GetTotalSize: Int64; 111 | procedure SetBaseURL(Value: string); 112 | procedure SetChannelName(const Value: string); 113 | procedure SetChannelsFileName(const Value: TFileName); 114 | procedure SetLocalChannelFileName(const Value: TFileName); 115 | protected 116 | procedure ErrorHandler(Sender: TObject; ErrorType: TWebUpdateErrorType; 117 | const FileName: TFileName; var Ignore: Boolean); 118 | procedure ProgressEventHandler(Sender: TObject; Progress: Integer; 119 | ByteCount: Integer; KBPS: Single; PassedTime: TDateTime); 120 | procedure FileChangedEventHandler(Sender: TObject; const FileName: TFileName); 121 | procedure ScriptErrorsEventHandler(Sender: TObject; const MessageList: TdwsMessageList); 122 | procedure DoneEventHandler(Sender: TObject); 123 | 124 | procedure RunScript(SourceCode: string); 125 | 126 | procedure BuildFileListCache; 127 | procedure ResetFileListCache; 128 | procedure LoadSetupFromFile(const FileName: TFileName); 129 | procedure LoadChannels; 130 | public 131 | constructor Create; 132 | destructor Destroy; override; 133 | 134 | procedure Abort; 135 | procedure PerformWebUpdate; 136 | procedure GetChannelNames(const ChannelNames: TStringList); 137 | 138 | property BaseURL: string read FBaseURL write SetBaseURL; 139 | property ChannelName: string read FChannelName write SetChannelName; 140 | property Channels: TWebUpdateChannels read FChannels; 141 | property ChannelsFileName: TFileName read FChannelsFileName write SetChannelsFileName; 142 | property LocalChannelFileName: TFileName read GetLocalChannelFileName write SetLocalChannelFileName; 143 | property MainAppFileName: TFileName read GetMainAppFileName; 144 | property FileItemList: TFileItemList read GetFileItemList; 145 | property TotalBytes: Int64 read GetTotalSize; 146 | 147 | property OnProgress: TUpdaterThread.TProgressEvent read FOnProgress write FOnProgress; 148 | property OnFileNameProgress: TUpdaterThread.TFileNameProgressEvent read FOnFileNameProgress write FOnFileNameProgress; 149 | property OnDone: TNotifyEvent read FOnDone write FOnDone; 150 | property OnScriptErrors: TUpdaterThread.TScriptErrorsEvent read FOnScriptErrors write FOnScriptErrors; 151 | property OnError: TUpdaterThread.TErrorEvent read FOnError write FOnError; 152 | end; 153 | 154 | implementation 155 | 156 | uses 157 | dwsUtils, IdSSLOpenSSL, WebUpdate.Tools; 158 | 159 | { TFileItem } 160 | 161 | constructor TFileItem.Create(const FileName: TFileName; MD5Hash: string = ''; 162 | FileSize: Integer = 0; Modified: TDateTime = 0); 163 | begin 164 | FFileName := FileName; 165 | FMD5Hash := MD5Hash; 166 | FFileSize := FileSize; 167 | FModified := Modified; 168 | FAction := faAdd; 169 | UpdateLocalFileName; 170 | end; 171 | 172 | procedure TFileItem.SetFileName(const Value: TFileName); 173 | begin 174 | if FFileName <> Value then 175 | begin 176 | FFileName := Value; 177 | UpdateLocalFileName; 178 | end; 179 | end; 180 | 181 | procedure TFileItem.UpdateLocalFileName; 182 | begin 183 | FLocalFileName := WebToLocalFileName(FFileName); 184 | end; 185 | 186 | 187 | { TFileItemList } 188 | 189 | function TFileItemList.LocateItemByFileName( 190 | const FileName: TFileName): TFileItem; 191 | var 192 | Index: Integer; 193 | begin 194 | Result := nil; 195 | for Index := 0 to Count - 1 do 196 | if UnicodeSameText(Items[Index].FileName, FileName) then 197 | Exit(Items[Index]); 198 | end; 199 | 200 | 201 | { TUpdaterThread } 202 | 203 | constructor TUpdaterThread.Create(const Files: TFileItemList); 204 | begin 205 | FFiles := Files; 206 | 207 | FLastWorkCount := 0; 208 | 209 | inherited Create(False); 210 | end; 211 | 212 | procedure TUpdaterThread.HttpWork(ASender: TObject; AWorkMode: TWorkMode; 213 | AWorkCount: Int64); 214 | var 215 | ContentLength: Int64; 216 | Encoding: string; 217 | begin 218 | // check whether a HTTP client is assigned 219 | if not Assigned(FHttp) then 220 | Exit; 221 | 222 | // check whether a progress event is assigned 223 | if not Assigned(FOnProgress) then 224 | Exit; 225 | 226 | Encoding := FHttp.Response.TransferEncoding; 227 | ContentLength := FHttp.Response.ContentLength; 228 | 229 | if (Pos('chunked', LowerCase(Encoding)) = 0) and (ContentLength > 0) then 230 | begin 231 | Synchronize(procedure 232 | var 233 | KBPS: Single; 234 | begin 235 | KBPS := 0.001 * (AWorkCount - FLastWorkCount) / (86400 * (Now - FLastTimeStamp)); 236 | FLastTimeStamp := Now; 237 | FOnProgress(Self, 100 * AWorkCount div ContentLength, 238 | AWorkCount - FLastWorkCount, KBPS, Now - FStartTimeStamp); 239 | end); 240 | FLastWorkCount := AWorkCount; 241 | end; 242 | end; 243 | 244 | procedure TUpdaterThread.Execute; 245 | var 246 | MS: TMemoryStream; 247 | Item: TFileItem; 248 | Hash: string; 249 | IgnoreError: Boolean; 250 | begin 251 | FStartTimeStamp := Now; 252 | FHttp := TIdHTTP.Create(nil); 253 | try 254 | // eventually create SSL IO handler 255 | if FileExists(ExtractFilePath(ParamStr(0)) + 'ssleay32.dll') and 256 | FileExists(ExtractFilePath(ParamStr(0)) + 'libeay32.dll') then 257 | FHttp.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil); 258 | 259 | FHttp.OnWork := HttpWork; 260 | MS := TMemoryStream.Create; 261 | try 262 | for Item in FFiles do 263 | begin 264 | // eventually call 'file changed' event 265 | if Assigned(FOnFileNameProgress) then 266 | Synchronize(procedure 267 | begin 268 | FOnFileNameProgress(Self, Item.FileName); 269 | end); 270 | 271 | // eventually delete file and continue with next file 272 | if Item.Action = faDelete then 273 | begin 274 | DeleteFile(FLocalPath + Item.LocalFileName); 275 | Continue; 276 | end; 277 | 278 | // clear buffer / reset last work count 279 | MS.Clear; 280 | FLastWorkCount := 0; 281 | FLastTimeStamp := Now; 282 | 283 | // check if terminated 284 | if Terminated then 285 | Exit; 286 | 287 | try 288 | // download file 289 | FHttp.Get(FBasePath + Item.FileName, MS); 290 | except 291 | IgnoreError := False; 292 | if Assigned(FOnError) then 293 | FOnError(Self, etDownload, FBasePath + Item.FileName, IgnoreError); 294 | if not IgnoreError then 295 | Exit; 296 | end; 297 | 298 | // check if terminated 299 | if Terminated then 300 | Exit; 301 | 302 | // eventually check MD5 hash 303 | if Item.MD5Hash <> '' then 304 | begin 305 | Hash := MD5(MS); 306 | if Hash <> Item.MD5Hash then 307 | begin 308 | IgnoreError := False; 309 | if Assigned(FOnError) then 310 | FOnError(Self, etChecksum, Item.FileName, IgnoreError); 311 | if not IgnoreError then 312 | Exit; 313 | end; 314 | end; 315 | 316 | // save downloaded file 317 | MS.SaveToFile(FLocalPath + Item.LocalFileName); 318 | 319 | // eventually update modification date/time 320 | if Item.Modified > 0 then 321 | FileSetDate(FLocalPath + Item.LocalFileName, DateTimeToFileDate(Item.Modified)); 322 | 323 | // check if terminated 324 | if Terminated then 325 | Exit; 326 | end; 327 | finally 328 | MS.Free; 329 | end; 330 | finally 331 | FHttp.IOHandler.Free; 332 | FreeAndNil(FHttp); 333 | end; 334 | 335 | // check if terminated 336 | if Terminated then 337 | Exit; 338 | 339 | // check if terminated 340 | if Terminated then 341 | Exit; 342 | 343 | // check if terminated 344 | if Terminated then 345 | Exit; 346 | 347 | // eventually call 'done' event 348 | if Assigned(FOnDone) then 349 | Synchronize(procedure 350 | begin 351 | FOnDone(Self); 352 | end); 353 | end; 354 | 355 | 356 | { TWebUpdater } 357 | 358 | constructor TWebUpdater.Create; 359 | begin 360 | FChannels := TWebUpdateChannels.Create; 361 | FNewSetup := TWebUpdateChannelSetup.Create; 362 | 363 | FScriptCompiler := TDelphiWebScript.Create(nil); 364 | FClassesLib := TdwsClassesLib.Create(nil); 365 | FClassesLib.Script := FScriptCompiler; 366 | 367 | // specify default values 368 | FBaseURL := ''; 369 | FCurrentSize := 0; 370 | FChannelPath := ''; 371 | FDownloadSpeedAverage := 0; 372 | 373 | FChannelsFileName := 'Channels.json'; 374 | FLocalChannelFileName := 'WebUpdate.json'; 375 | end; 376 | 377 | destructor TWebUpdater.Destroy; 378 | begin 379 | // eventually terminate file download thread 380 | if Assigned(FThread) then 381 | FThread.Terminate; 382 | 383 | // free objects 384 | FFileItemListCache.Free; 385 | FClassesLib.Free; 386 | FScriptCompiler.Free; 387 | FChannels.Free; 388 | FNewSetup.Free; 389 | if Assigned(FThread) then 390 | FThread.WaitFor; 391 | FThread.Free; 392 | 393 | inherited; 394 | end; 395 | 396 | procedure TWebUpdater.Abort; 397 | begin 398 | if Assigned(FThread) then 399 | FThread.Terminate; 400 | ResetFileListCache; 401 | end; 402 | 403 | procedure TWebUpdater.BuildFileListCache; 404 | var 405 | ChannelItem: TWebUpdateChannelItem; 406 | Item: TWebUpdateFileItem; 407 | FileItem: TFileItem; 408 | PathDelimPos: Integer; 409 | LocalSetup: TWebUpdateChannelSetup; 410 | begin 411 | LoadChannels; 412 | 413 | for ChannelItem in FChannels.Items do 414 | if UnicodeSameText(ChannelItem.Name, ChannelName) then 415 | begin 416 | PathDelimPos := LastDelimiter('/', ChannelItem.FileName); 417 | FChannelPath := Copy(ChannelItem.FileName, 1, PathDelimPos); 418 | LoadSetupFromFile(ChannelItem.FileName); 419 | Break; 420 | end; 421 | 422 | FTotalSize := 0; 423 | 424 | // eventually load existing setup 425 | if FileExists(FLocalChannelFileName) then 426 | begin 427 | LocalSetup := TWebUpdateChannelSetup.Create; 428 | try 429 | LocalSetup.LoadFromFile(FLocalChannelFileName); 430 | 431 | // assume deletion of all files currently present 432 | for Item in LocalSetup.Items do 433 | begin 434 | FileItem := TFileItem.Create(Item.FileName, Item.MD5Hash, Item.FileSize, 435 | Item.Modified); 436 | FileItem.Action := faDelete; 437 | FFileItemListCache.Add(FileItem); 438 | end; 439 | finally 440 | LocalSetup.Free; 441 | end; 442 | end; 443 | 444 | // add all files (and eventually mark as 445 | for Item in FNewSetup.Items do 446 | begin 447 | // now check if file is already present (from local setup) 448 | FileItem := FFileItemListCache.LocateItemByFileName(Item.FileName); 449 | 450 | if Assigned(FileItem) then 451 | begin 452 | // check if file is marked for explicit deletion 453 | if Item.Action = iaDelete then 454 | begin 455 | FileItem.Action := faDelete; 456 | 457 | // set MD5 hash, size and modification date to 0 => always delete! 458 | FileItem.MD5Hash := ''; 459 | FileItem.Modified := 0; 460 | FileItem.FileSize := 0; 461 | 462 | Continue; 463 | end; 464 | 465 | // check if file is (supposed to be) identical to previous version 466 | if (FileItem.Modified = Item.Modified) and 467 | (FileItem.FileSize = Item.FileSize) and 468 | (FileItem.MD5Hash = Item.MD5Hash) then 469 | FileItem.Action := faVerify 470 | else 471 | begin 472 | // set action to 'change' and update properties 473 | FileItem.Action := faChange; 474 | FileItem.MD5Hash := Item.MD5Hash; 475 | FileItem.Modified := Item.Modified; 476 | FileItem.FileSize := Item.FileSize; 477 | end; 478 | end 479 | else 480 | begin 481 | FileItem := TFileItem.Create(Item.FileName, Item.MD5Hash, Item.FileSize, 482 | Item.Modified); 483 | FFileItemListCache.Add(FileItem); 484 | 485 | // check if the item action is to delete the file 486 | if Item.Action = iaDelete then 487 | begin 488 | FileItem.Action := faDelete; 489 | Continue; 490 | end; 491 | end; 492 | 493 | // inc total file size (if item is about to be added 494 | if Item.Action <> iaDelete then 495 | FTotalSize := FTotalSize + Item.FileSize; 496 | end; 497 | 498 | // eventually run pre script 499 | if FNewSetup.PreUpdateScript <> '' then 500 | RunScript(FNewSetup.PreUpdateScript); 501 | end; 502 | 503 | procedure TWebUpdater.DoneEventHandler(Sender: TObject); 504 | begin 505 | // save new setup 506 | FNewSetup.SaveToFile(FLocalChannelFileName); 507 | 508 | // eventually run post script 509 | if FNewSetup.PostUpdateScript <> '' then 510 | RunScript(FNewSetup.PostUpdateScript); 511 | 512 | FThread := nil; 513 | 514 | if Assigned(FOnDone) then 515 | FOnDone(Sender); 516 | end; 517 | 518 | procedure TWebUpdater.FileChangedEventHandler(Sender: TObject; 519 | const FileName: TFileName); 520 | begin 521 | if Assigned(OnFileNameProgress) then 522 | OnFileNameProgress(Sender, FileName); 523 | end; 524 | 525 | procedure TWebUpdater.ScriptErrorsEventHandler(Sender: TObject; 526 | const MessageList: TdwsMessageList); 527 | begin 528 | if Assigned(OnScriptErrors) then 529 | OnScriptErrors(Sender, MessageList); 530 | end; 531 | 532 | procedure TWebUpdater.SetBaseURL(Value: string); 533 | begin 534 | if not StrEndsWith(Value, '/') then 535 | Value := Value + '/'; 536 | 537 | if FBaseURL <> Value then 538 | begin 539 | FBaseURL := Value; 540 | 541 | ResetFileListCache; 542 | end; 543 | end; 544 | 545 | procedure TWebUpdater.SetChannelName(const Value: string); 546 | begin 547 | if FChannelName <> Value then 548 | begin 549 | FChannelName := Value; 550 | ResetFileListCache; 551 | end; 552 | end; 553 | 554 | procedure TWebUpdater.SetChannelsFileName(const Value: TFileName); 555 | begin 556 | if FChannelsFileName <> Value then 557 | begin 558 | FChannelsFileName := Value; 559 | ResetFileListCache; 560 | end; 561 | end; 562 | 563 | procedure TWebUpdater.SetLocalChannelFileName(const Value: TFileName); 564 | begin 565 | if FLocalChannelFileName <> Value then 566 | begin 567 | FLocalChannelFileName := Value; 568 | ResetFileListCache; 569 | end; 570 | end; 571 | 572 | procedure TWebUpdater.GetChannelNames(const ChannelNames: TStringList); 573 | var 574 | Item: TWebUpdateChannelItem; 575 | begin 576 | // load channels setup from URI 577 | LoadChannels; 578 | 579 | // get channel names 580 | ChannelNames.Clear; 581 | for Item in Channels.Items do 582 | ChannelNames.Add(Item.Name); 583 | end; 584 | 585 | function TWebUpdater.GetFileItemList: TFileItemList; 586 | begin 587 | // eventually create file item list (if not already created) 588 | if Assigned(FFileItemListCache) then 589 | Exit(FFileItemListCache); 590 | 591 | FFileItemListCache := TFileItemList.Create; 592 | BuildFileListCache; 593 | Result := FFileItemListCache; 594 | end; 595 | 596 | function TWebUpdater.GetLocalChannelFileName: TFileName; 597 | begin 598 | Result := FLocalChannelFileName; 599 | if IsRelativePath(Result) then 600 | Result := ExtractFilePath(ParamStr(0)) + Result; 601 | end; 602 | 603 | function TWebUpdater.GetMainAppFileName: TFileName; 604 | begin 605 | Result := ''; 606 | if FNewSetup.AppName <> '' then 607 | begin 608 | // get application name 609 | Result := WebToLocalFileName(FNewSetup.AppName); 610 | 611 | // now add local path information 612 | Result := ExtractFilePath(FLocalChannelFileName) + Result; 613 | end; 614 | end; 615 | 616 | function TWebUpdater.GetTotalSize: Int64; 617 | begin 618 | GetFileItemList; 619 | Result := FTotalSize; 620 | end; 621 | 622 | procedure TWebUpdater.PerformWebUpdate; 623 | begin 624 | // eventually kill thread 625 | if Assigned(FThread) then 626 | begin 627 | FThread.Terminate; 628 | FThread.WaitFor; 629 | FThread.Free; 630 | end; 631 | 632 | FThread := TUpdaterThread.Create(FileItemList); 633 | 634 | // specify event handlers 635 | FThread.OnProgress := ProgressEventHandler; 636 | FThread.OnFileNameProgress := FileChangedEventHandler; 637 | FThread.OnDone := DoneEventHandler; 638 | FThread.OnScriptErrors := ScriptErrorsEventHandler; 639 | FThread.OnError := ErrorHandler; 640 | 641 | FThread.BasePath := FBaseURL + FChannelPath; 642 | FThread.LocalPath := ExtractFilePath(FLocalChannelFileName); 643 | 644 | FThread.Suspended := False; 645 | end; 646 | 647 | procedure TWebUpdater.RunScript(SourceCode: string); 648 | var 649 | CompiledProgram: IdwsProgram; 650 | begin 651 | // compile script 652 | CompiledProgram := FScriptCompiler.Compile(SourceCode); 653 | 654 | // check for errors 655 | if CompiledProgram.Msgs.HasErrors then 656 | begin 657 | if Assigned(OnScriptErrors) then 658 | OnScriptErrors(Self, CompiledProgram.Msgs); 659 | 660 | Exit; 661 | end; 662 | 663 | // execute script 664 | CompiledProgram.Execute; 665 | end; 666 | 667 | procedure TWebUpdater.LoadSetupFromFile(const FileName: TFileName); 668 | var 669 | Http: TIdHTTP; 670 | Text: string; 671 | Success: Boolean; 672 | begin 673 | Http := TIdHTTP.Create(nil); 674 | try 675 | try 676 | // eventually create SSL IO handler 677 | if FileExists(ExtractFilePath(ParamStr(0)) + 'ssleay32.dll') and 678 | FileExists(ExtractFilePath(ParamStr(0)) + 'libeay32.dll') then 679 | Http.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil); 680 | 681 | // get text from URI 682 | Text := Http.Get(FBaseURL + FileName); 683 | 684 | // check if text is available (might need check for JSON format) 685 | Success := Text <> ''; 686 | except 687 | Success := False; 688 | end; 689 | 690 | // handle errors 691 | if not Success then 692 | raise EHttpDownload.CreateFmt('Error downloading from URL %s', 693 | [FBaseURL + FileName]); 694 | finally 695 | Http.IOHandler.Free; 696 | Http.Free; 697 | end; 698 | 699 | // now load setup from string 700 | FNewSetup.LoadFromString(Text); 701 | end; 702 | 703 | procedure TWebUpdater.ErrorHandler(Sender: TObject; 704 | ErrorType: TWebUpdateErrorType; const FileName: TFileName; var Ignore: Boolean); 705 | begin 706 | // event redirection 707 | if Assigned(FOnError) then 708 | FOnError(Sender, ErrorType, FileName, Ignore); 709 | end; 710 | 711 | procedure TWebUpdater.ProgressEventHandler(Sender: TObject; Progress, 712 | ByteCount: Integer; KBPS: Single; PassedTime: TDateTime); 713 | var 714 | TotalTime: TDateTime; 715 | begin 716 | FCurrentSize := FCurrentSize + ByteCount; 717 | TotalTime := PassedTime * FTotalSize / FCurrentSize; 718 | 719 | // average download speed 720 | if FDownloadSpeedAverage = 0 then 721 | FDownloadSpeedAverage := KBPS 722 | else 723 | FDownloadSpeedAverage := 0.5 * (FDownloadSpeedAverage + KBPS); 724 | 725 | // event redirection 726 | if Assigned(OnProgress) then 727 | OnProgress(Sender, Progress, ByteCount, FDownloadSpeedAverage, 728 | TotalTime - PassedTime); 729 | end; 730 | 731 | procedure TWebUpdater.ResetFileListCache; 732 | begin 733 | FreeAndNil(FFileItemListCache); 734 | end; 735 | 736 | procedure TWebUpdater.LoadChannels; 737 | var 738 | Http: TIdHTTP; 739 | Text: string; 740 | Success: Boolean; 741 | begin 742 | Http := TIdHTTP.Create(nil); 743 | try 744 | try 745 | // eventually create SSL IO handler 746 | if FileExists(ExtractFilePath(ParamStr(0)) + 'ssleay32.dll') and 747 | FileExists(ExtractFilePath(ParamStr(0)) + 'libeay32.dll') then 748 | Http.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil); 749 | 750 | // get text from URL 751 | Text := Http.Get(BaseURL + ChannelsFileName); 752 | 753 | // check if text is available (might need check for JSON format) 754 | Success := Text <> ''; 755 | except 756 | Success := False; 757 | end; 758 | 759 | // handle errors 760 | if not Success then 761 | raise EHttpDownload.CreateFmt('Error downloading from URL %s', 762 | [BaseURL + ChannelsFileName]); 763 | finally 764 | Http.IOHandler.Free; 765 | Http.Free; 766 | end; 767 | 768 | // load channels from string 769 | FChannels.LoadFromString(Text); 770 | end; 771 | 772 | end. 773 | -------------------------------------------------------------------------------- /Source/Update Helper (Command-line)/Updater.dproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | {14BD67DA-2875-471A-8356-7C0BBF43AFDA} 4 | 13.4 5 | None 6 | Updater.dpr 7 | True 8 | Debug 9 | Win32 10 | 7 11 | Console 12 | 13 | 14 | true 15 | 16 | 17 | true 18 | Base 19 | true 20 | 21 | 22 | true 23 | Base 24 | true 25 | 26 | 27 | true 28 | Base 29 | true 30 | 31 | 32 | true 33 | Base 34 | true 35 | 36 | 37 | true 38 | Cfg_1 39 | true 40 | true 41 | 42 | 43 | true 44 | Base 45 | true 46 | 47 | 48 | System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace) 49 | fmx;IndySystem;CustomIPTransport;dsnap;IndyCore;fmxase;FmxTeeUI;inetdbxpress;bindcompfmx;rtl;dbrtl;bindcomp;inetdb;xmlrtl;IndyProtocols;bindengine;FMXTee;soaprtl;inet;fmxobj;fmxdae;$(DCC_UsePackage) 50 | ..\..\DCU 51 | ..\..\Binaries 52 | 53 | 54 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) 55 | 1033 56 | CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= 57 | AbbreviaVCL;TeeDB;vclimg;vcldb;vcldsnap;vclribbon;EasyListviewD16;vcl;webdsnap;OmniThreadLibraryRuntimeXE2;GR32_RSXE2;Tee;SynEdit_RXE2;O408_r;vclactnband;TeeUI;bindcompvcl;vclie;vcltouch;websnap;VclSmp;dsnapcon;vclx;MPCommonLibD16;VirtualTreesR;O408br;$(DCC_UsePackage) 58 | 59 | 60 | CFBundleName=$(MSBuildProjectName);CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleVersion=1.0.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName) 61 | 62 | 63 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) 64 | 1033 65 | JvBDE;JvGlobus;fsADO16;AggPasRunXE2;JvMM;JvManagedThreads;AbbreviaVCL;USBDeviceTreePkg;JvDlgs;Alcinoe_d2007;TeeDB;JvCrypt;frxTee16;inetdbbde;frxBDE16;ColorPickerButtonD16;GLScene_RunTime;JvNet;JvDotNetCtrls;PrintPreview;ECXMLParserD160;DIHtmlParser_DXE2;vclimg;fmi;JvXPCtrls;GeckoSDK;vcldb;GLS_Computing_RunTime;vcldsnap;mbColorLibD16;DeHL_Package;ChromeTabs_XE2_R;MetaGraphics_D16;GR32_AddOn_RSXE2;DCEF_XE2;dwsLibRuntime;JvCore;frxADO16;vclribbon;frxe16;EasyListviewD16;vcl;ewbrun;fsTee16;GeckoComponents;JvAppFrm;JvDB;hexlicensemgr;DAV_ASIOHost_D16;webdsnap;JvRuntimeDesign;OmniThreadLibraryRuntimeXE2;JclDeveloperTools;GR32_RSXE2;BMSpinEdit;GR32_DSGN_RSXE2;JvDocking;JvWizards;madBasic_;GR32_FreeType_XE2;OpenWirePkgD16;JvHMI;frxDBX16;JvBands;vcldbx;GR32_Controls_D16;frx16;DAV_Common_D16;JvPluginSystem;mrMath;DAV_DSP_D16;MFControls;Tee;JclContainers;dhcomps;JvCmp;madDisAsm_;JvSystem;svnui;JvTimeFramework;SynEdit_RXE2;JvControls;Mitov.Runtime.D16;fsBDE16;frxDB16;DAV_GUI_D16;O408_r;vclactnband;TeeUI;JvJans;bindcompvcl;JvStdCtrls;JvCustom;Jcl;vclie;JvPageComps;JvPrintPreview;fs16;madExcept_;frxcs16;vcltouch;websnap;ExceptionExpert16;CrossFPC_XE2;VclSmp;fsDB16;WebUpdateR;DAV_SEHost_D16;DScintillaRuntime;dsnapcon;FlatControls;JclVcl;JvPascalInterpreter;GR32_Charts_D16;vclx;MPCommonLibD16;SuperTrackbar_D16;svn;OPDE;CPortLibDXE2;bdertl;RemObjects_Synapse_D16;ExpertTools;VirtualTreesR;DAV_VSTHost_D16;O408br;$(DCC_UsePackage) 66 | CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= 67 | 68 | 69 | DEBUG;$(DCC_Define) 70 | false 71 | true 72 | true 73 | true 74 | 75 | 76 | false 77 | 78 | 79 | false 80 | RELEASE;$(DCC_Define) 81 | 0 82 | false 83 | 84 | 85 | 86 | MainSource 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | Cfg_2 95 | Base 96 | 97 | 98 | Base 99 | 100 | 101 | Cfg_1 102 | Base 103 | 104 | 105 | 106 | Delphi.Personality.12 107 | 108 | 109 | 110 | 111 | Updater.dpr 112 | 113 | 114 | False 115 | False 116 | 1 117 | 0 118 | 0 119 | 0 120 | False 121 | False 122 | False 123 | False 124 | False 125 | 1031 126 | 1252 127 | 128 | 129 | 130 | 131 | 1.0.0.0 132 | 133 | 134 | 135 | 136 | 137 | 1.0.0.0 138 | 139 | 140 | 141 | 142 | 143 | True 144 | True 145 | True 146 | 147 | 148 | 12 149 | 150 | 151 | 152 | 153 | 154 | 638 | --------------------------------------------------------------------------------