Updatecheck: Find a batchfile-solution to replace the running exe with a downloaded build.

TODO: find some sleep command for the batch file, as we sometimes get "access denied" while trying to overwrite the just terminated exe. Seems like taskkill doesn't close all handles itself.
This commit is contained in:
Ansgar Becker
2008-02-23 00:54:02 +00:00
parent 700ac08264
commit 9f23a9b313
7 changed files with 204 additions and 17 deletions

View File

@ -35,7 +35,8 @@ uses
data_sorting in '..\..\source\data_sorting.pas' {DataSortingForm},
runsqlfile in '..\..\source\runsqlfile.pas' {RunSQLFileForm},
createdatabase in '..\..\source\createdatabase.pas' {CreateDatabaseForm},
updatecheck in '..\..\source\updatecheck.pas' {frmUpdateCheck};
updatecheck in '..\..\source\updatecheck.pas' {frmUpdateCheck},
updatedownload in '..\..\source\updatedownload.pas' {frmUpdateDownload};
{$R *.RES}

View File

@ -35,7 +35,8 @@ uses
data_sorting in '..\..\source\data_sorting.pas' {DataSortingForm},
runsqlfile in '..\..\source\runsqlfile.pas' {RunSQLFileForm},
createdatabase in '..\..\source\createdatabase.pas' {CreateDatabaseForm},
updatecheck in '..\..\source\updatecheck.pas' {frmUpdateCheck};
updatecheck in '..\..\source\updatecheck.pas' {frmUpdateCheck},
updatedownload in '..\..\source\updatedownload.pas' {frmUpdateDownload};
{$R *.RES}

View File

@ -1,4 +1,4 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{53d02113-9bb2-4326-83eb-53734f07dae7}</ProjectGuid>
<MainSource>heidisql.dpr</MainSource>
@ -137,6 +137,9 @@
<DCCReference Include="..\..\source\updatecheck.pas">
<Form>frmUpdateCheck</Form>
</DCCReference>
<DCCReference Include="..\..\source\updatedownload.pas">
<Form>frmUpdateDownload</Form>
</DCCReference>
<DCCReference Include="..\..\source\usermanager.pas">
<Form>UserManagerForm</Form>
</DCCReference>

View File

@ -85,6 +85,7 @@ type
function TColorToHex( Color : TColor ): string;
function GetVTCaptions( VT: TVirtualStringTree; OnlySelected: Boolean = False; Column: Integer = 0 ): TStringList;
function Pos2(const Needle, HayStack: string; const StartPos: Integer) : Integer;
function GetTempDir: String;
procedure ExtractUpdater;
procedure UpdateItWith(const _file: String);
@ -2138,6 +2139,15 @@ begin
end;
function GetTempDir: String;
var
TempPath: array[0..MAX_PATH] of Char;
begin
GetTempPath(MAX_PATH, @TempPath);
Result := StrPas(TempPath);
end;
{**
Extract the updater from resource.

View File

@ -34,7 +34,7 @@ type
implementation
uses helpers, main;
uses helpers, main, UpdateDownload;
{$R *.dfm}
@ -65,7 +65,6 @@ end;
}
procedure TfrmUpdateCheck.FormShow(Sender: TObject);
var
TempPath: array[0..MAX_PATH] of Char;
reg : TRegistry;
begin
Status('Initiating ... ');
@ -78,13 +77,10 @@ begin
memoRelease.Clear;
memoBuild.Clear;
// Detect temp directory
GetTempPath(MAX_PATH, @TempPath);
// Prepare download
CheckfileDownload := TDownLoadURL.Create(Self);
CheckfileDownload.URL := APPDOMAIN + 'updatecheck.php';
CheckfileDownload.Filename := StrPas(TempPath) + APPNAME + '_updatecheck.ini';
CheckfileDownload.Filename := GetTempDir + APPNAME + '_updatecheck.ini';
// Download the check file
Screen.Cursor := crHourglass;
@ -172,7 +168,7 @@ begin
Note := Ini.ReadString(INISECT_BUILD, 'Note', '');
if Note <> '' then
memoBuild.Lines.Add( 'Note: ' + Note );
btnBuild.Caption := 'Download build ' + IntToStr(BuildRevision);
btnBuild.Caption := 'Download and install build ' + IntToStr(BuildRevision);
// A new release should have priority over a new nightly build.
// So the user should not be able to download a newer build here
// before having installed the new release.
@ -197,16 +193,11 @@ end;
{**
Download latest build via web browser
TODO: internally replace heidisql.exe:
1. create a batch file which replaces heidisql.exe
2. quit Heidi
3. start the batch
4. start Heidi
Download latest build and replace running exe
}
procedure TfrmUpdateCheck.btnBuildClick(Sender: TObject);
begin
ShellExec(BuildURL);
DoUpdateDownload(Self, BuildURL, Application.ExeName);
end;
end.

51
source/updatedownload.dfm Normal file
View File

@ -0,0 +1,51 @@
object frmUpdateDownload: TfrmUpdateDownload
Left = 0
Top = 0
BorderStyle = bsDialog
Caption = 'Downloading update file ...'
ClientHeight = 95
ClientWidth = 286
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
Position = poOwnerFormCenter
DesignSize = (
286
95)
PixelsPerInch = 96
TextHeight = 13
object lblStatus: TLabel
Left = 8
Top = 31
Width = 270
Height = 28
Anchors = [akLeft, akTop, akRight]
AutoSize = False
Caption = 'lblStatus'
WordWrap = True
end
object progressDownload: TProgressBar
Left = 8
Top = 8
Width = 270
Height = 17
Anchors = [akLeft, akTop, akRight]
TabOrder = 0
end
object btnCancel: TButton
Left = 104
Top = 62
Width = 68
Height = 25
Anchors = [akLeft, akTop, akRight]
Cancel = True
Caption = 'Cancel'
ModalResult = 2
TabOrder = 1
OnClick = btnCancelClick
end
end

130
source/updatedownload.pas Normal file
View File

@ -0,0 +1,130 @@
unit updatedownload;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls, ExtActns, Helpers;
type
TfrmUpdateDownload = class(TForm)
progressDownload: TProgressBar;
lblStatus: TLabel;
btnCancel: TButton;
procedure btnCancelClick(Sender: TObject);
private
{ Private declarations }
Download: TDownLoadURL;
DoCancel: Boolean;
FilePath: String;
procedure DoDownload;
procedure URLOnDownloadProgress(Sender: TDownLoadURL; Progress, ProgressMax: Cardinal;
StatusCode: TURLDownloadStatus; StatusText: String; var Cancel: Boolean);
public
{ Public declarations }
end;
function DoUpdateDownload(AOwner: TComponent; URL, FilePath: String): Boolean;
implementation
{$R *.dfm}
{**
Initiate the download + update process
}
function DoUpdateDownload(AOwner: TComponent; URL, FilePath: String): Boolean;
var
frm: TfrmUpdateDownload;
begin
Result := False;
frm := TfrmUpdateDownload.Create(AOwner);
frm.Download := TDownLoadURL.Create(frm);
frm.Download.URL := URL;
frm.FilePath := FilePath;
frm.DoDownload;
end;
{**
Cancel clicked
}
procedure TfrmUpdateDownload.btnCancelClick(Sender: TObject);
begin
DoCancel := True;
end;
{**
Start the download + update process
}
procedure TfrmUpdateDownload.DoDownload;
var
BatchFile: Textfile;
BatchFilename, ExeName: String;
begin
Show;
// Save the file in a temp directory
Download.Filename := GetTempDir + ExtractFileName(Filepath);
Download.OnDownloadProgress := URLOnDownloadProgress;
// Delete probably previously downloaded file
if FileExists(Download.Filename) then
DeleteFile(Download.Filename);
// Do the download
Download.ExecuteTarget(nil);
// Check if downloaded file exists
if not FileExists(Download.Filename) then begin
Raise Exception.Create('Downloaded file not found: '+Download.Filename);
end;
if FilePath = Application.ExeName then begin
ExeName := ExtractFilename(FilePath);
BatchFilename := ExtractFilepath(Application.ExeName) + 'Update_' + ExeName + '.cmd';
AssignFile(BatchFile, BatchFilename);
Rewrite(BatchFile);
WriteLn(BatchFile, 'rem Killing task '+ExeName);
WriteLn(BatchFile, 'taskkill /im "'+ExeName+'" /f');
// TODO: find some sleep command, as we sometimes get "access denied"
// while trying to overwrite the just terminated exe. Seems like taskkill
// doesn't close all handles itself
WriteLn(BatchFile, 'rem Moving downloaded file to '+ExtractFilepath(FilePath));
WriteLn(BatchFile, 'move /Y "'+Download.Filename+'" "'+FilePath+'"');
WriteLn(BatchFile, 'rem Restarting '+APPNAME);
WriteLn(BatchFile, 'start /D"'+ExtractFilepath(FilePath)+'" '+ExeName);
WriteLn(Batchfile);
CloseFile(BatchFile);
// Calling the batchfile will now terminate the running exe...
WinExec(PAnsiChar(BatchFilename), 1);
end else begin
// We're not replacing the running exe, so just move file to destination
MoveFile(PChar(Download.Filename), PChar(FilePath));
end;
// Close form
ModalResult := mrOK;
end;
{**
Download progress event
}
procedure TfrmUpdateDownload.URLOnDownloadProgress(Sender: TDownLoadURL; Progress, ProgressMax: Cardinal;
StatusCode: TURLDownloadStatus; StatusText: String; var Cancel: Boolean);
begin
progressDownload.Max := ProgressMax;
progressDownload.Position := Progress;
lblStatus.Caption := StatusText;
// Notification if cancel button was pressed
Cancel := DoCancel;
Application.ProcessMessages;
end;
end.