mirror of
https://github.com/HeidiSQL/HeidiSQL.git
synced 2026-03-13 09:24:25 +08:00
Refactor build updater once again:
* convert to console application without window, so the user sees all status messages in the order of appearance * include SysUtils unit, which increases file size to ~2MB, but enhances maintainability * restrict compilation and resource inclusion to 64bit mode - the build updater is disabled in 32bit mode anyway
This commit is contained in:
@@ -2,8 +2,10 @@ brcc32 res\version.rc
|
||||
cgrc res\icon.rc
|
||||
brcc32 res\icon-question.rc
|
||||
brcc32 res\manifest.rc
|
||||
brcc32 -fores\updater.res res\updater64.rc
|
||||
brcc32 res\updater.rc
|
||||
cgrc.exe res\styles.rc
|
||||
brcc32.exe source\vcl-styles-utils\AwesomeFont.rc
|
||||
brcc32.exe source\vcl-styles-utils\AwesomeFont_zip.rc
|
||||
brcc32.exe res\updater\manifest.rc
|
||||
|
||||
pause
|
||||
|
||||
2
packages/Delphi11.2/heidisql.dpr
vendored
2
packages/Delphi11.2/heidisql.dpr
vendored
@@ -62,7 +62,7 @@ uses
|
||||
{$R ..\..\res\icon-question.RES}
|
||||
{$R ..\..\res\version.RES}
|
||||
{$R ..\..\res\manifest.RES}
|
||||
{$R ..\..\res\updater.RES}
|
||||
{$IFDEF CPUX64}{$R ..\..\res\updater.RES}{$ENDIF}
|
||||
{$R ..\..\res\styles.RES}
|
||||
|
||||
var
|
||||
|
||||
1
res/updater.rc
Normal file
1
res/updater.rc
Normal file
@@ -0,0 +1 @@
|
||||
updater exe "updater\updater.exe"
|
||||
@@ -6,7 +6,7 @@
|
||||
processorArchitecture="*"
|
||||
name="HeidiSQL"
|
||||
type="win32" />
|
||||
<description>A lightweight, fast and flexible interface to MySQL</description>
|
||||
<description>HeidiSQL build updater</description>
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
|
||||
<security>
|
||||
<requestedPrivileges>
|
||||
|
||||
@@ -1,119 +1,25 @@
|
||||
program updater;
|
||||
|
||||
{ A window which terminates running HeidiSQL instances and moves the downloaded update file to
|
||||
its desired directory. Avoids to use any VCL unit, to keep the executable small. }
|
||||
{ A console window which terminates running HeidiSQL instances and moves the downloaded update file to
|
||||
its desired directory. }
|
||||
|
||||
{$APPTYPE CONSOLE}
|
||||
|
||||
{$R manifest.RES}
|
||||
|
||||
// (un)comment the following resource inclusion to vary the binary size. Update checker trusts the same file size before overwriting the old one.
|
||||
{$R ..\icon.RES}
|
||||
|
||||
uses
|
||||
Windows, Messages, Tlhelp32, psapi, Winapi.ShellAPI;
|
||||
Winapi.Windows, Winapi.Messages, Winapi.TlHelp32, Winapi.PsAPI, Winapi.ShellAPI, System.SysUtils;
|
||||
|
||||
var
|
||||
WClass: TWndClass;
|
||||
BackupPath, AppPath, DownloadPath: String;
|
||||
MainWin, HLabel: HWND;
|
||||
AppMsg: TMsg;
|
||||
FormShowing: Boolean = False;
|
||||
RestartTaskName, RestartCmd, RestartParams: String;
|
||||
|
||||
const
|
||||
AppName = 'HeidiSQL';
|
||||
WindowPadding = 10;
|
||||
WindowWidth = 600;
|
||||
WindowHeight = 80;
|
||||
QuitTimeout = 20000; // We long we're gracefully waiting for a window to be gone, in milliseconds
|
||||
TerminatedCheck = 200; // Interval between checks if host application is gone
|
||||
PathDelim = '\';
|
||||
|
||||
|
||||
|
||||
{ We don't include SysUtils unit, so we need to implement our own versions of some basic functions here }
|
||||
|
||||
function FileExists(Filename: String): Boolean;
|
||||
var
|
||||
Find: THandle;
|
||||
Data: TWin32FindData;
|
||||
begin
|
||||
Find := FindFirstFile(PChar(Filename), Data);
|
||||
Result := Find <> INVALID_HANDLE_VALUE;
|
||||
end;
|
||||
|
||||
function IntToStr(Value: Int64): String;
|
||||
var
|
||||
Minus : Boolean;
|
||||
begin
|
||||
Result := '';
|
||||
if Value = 0 then
|
||||
Result := '0';
|
||||
Minus := Value < 0;
|
||||
if Minus then
|
||||
Value := -Value;
|
||||
while Value > 0 do begin
|
||||
Result := Char((Value mod 10) + Integer('0')) + Result;
|
||||
Value := Value div 10;
|
||||
end;
|
||||
if Minus then
|
||||
Result := '-' + Result;
|
||||
end;
|
||||
|
||||
function ExtractFileName(const FileName: string): string;
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
for i:=Length(Filename) downto 0 do
|
||||
if Filename[i] = PathDelim then
|
||||
break;
|
||||
Result := Copy(FileName, i+1, MaxInt);
|
||||
end;
|
||||
|
||||
function ExtractFilePath(const FileName: string): string;
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
for i:=Length(Filename) downto 0 do
|
||||
if Filename[i] = PathDelim then
|
||||
break;
|
||||
Result := Copy(FileName, 1, i);
|
||||
end;
|
||||
|
||||
|
||||
{ Version of ValidFilename in main project, without usage of large IOutils SysUtils units
|
||||
function ValidFilename(Str: String): String;
|
||||
var
|
||||
InvChar: Char;
|
||||
i: Integer;
|
||||
InvalidFileNameChars: TArray<Char>;
|
||||
begin
|
||||
Result := Str;
|
||||
InvalidFileNameChars := TArray<Char>.Create(
|
||||
#0, #1, #2, #3, #4, #5, #6, #7, #8, #9, #10, #11, #12,
|
||||
#13, #14, #15, #16, #17, #18, #19, #20, #21, #22, #23, #24,
|
||||
#25, #26, #27, #28, #29, #30, #31,
|
||||
'"', '*', '/', ':', '<', '>', '?', '\', '|');
|
||||
for InvChar in InvalidFileNameChars do begin
|
||||
for i := 1 to Length(Str) do begin
|
||||
if Result[i] = InvChar then
|
||||
Result[i] := '_';
|
||||
end;
|
||||
end;
|
||||
end; }
|
||||
|
||||
|
||||
function Trim(const S: string): string;
|
||||
var
|
||||
I, L: Integer;
|
||||
begin
|
||||
L := Length(S);
|
||||
I := 1;
|
||||
if (L > 0) and (S[I] > ' ') and (S[L] > ' ') then Exit(S);
|
||||
while (I <= L) and (S[I] <= ' ') do Inc(I);
|
||||
if I > L then Exit('');
|
||||
while S[L] <= ' ' do Dec(L);
|
||||
Result := Copy(S, I, L - I + 1);
|
||||
end;
|
||||
|
||||
TerminatedCheck = 500; // Interval between checks if host application is gone
|
||||
|
||||
function GetEXEFromHandle(const wnd: HWND) : string;
|
||||
var
|
||||
@@ -169,12 +75,14 @@ end;
|
||||
|
||||
|
||||
procedure Status(Text: String; IsError: Boolean=False);
|
||||
const
|
||||
SleepSecondsOnError: Integer=10;
|
||||
begin
|
||||
// Display status message on label
|
||||
SendMessage(HLabel, WM_SETTEXT, 0, LPARAM(PChar(Text)) );
|
||||
UpdateWindow(hLabel);
|
||||
// Display status message
|
||||
WriteLn(Text);
|
||||
if IsError then begin
|
||||
Sleep(4000);
|
||||
Writeln('Exiting in '+SleepSecondsOnError.ToString+' seconds...');
|
||||
Sleep(SleepSecondsOnError * 1000);
|
||||
Halt(1);
|
||||
end;
|
||||
end;
|
||||
@@ -189,7 +97,7 @@ begin
|
||||
// EnumWindows will stop processing if we return false
|
||||
Result := True;
|
||||
WndPath := GetEXEFromHandle(Wnd);
|
||||
if (WndPath <> AppPath) and (WndPath <> ExtractFilename(AppPath)) then
|
||||
if (LowerCase(WndPath) <> LowerCase(AppPath)) and (LowerCase(WndPath) <> LowerCase(ExtractFilename(AppPath))) then
|
||||
Exit;
|
||||
|
||||
SetLength(WndTitle, 256);
|
||||
@@ -216,146 +124,54 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
// Callback function for Timer
|
||||
procedure FormShow(wnd: HWND; uMsg: UINT; idEvent: UINT; dwTime: DWORD); stdcall;
|
||||
var
|
||||
RestartTaskName, RestartCmd, RestartParams: String;
|
||||
// Main program code
|
||||
begin
|
||||
FormShowing := True;
|
||||
KillTimer(MainWin, 0);
|
||||
AppPath := Paramstr(1);
|
||||
DownloadPath := ParamStr(2);
|
||||
RestartTaskName := ParamStr(3);
|
||||
try
|
||||
AppPath := Paramstr(1);
|
||||
DownloadPath := ParamStr(2);
|
||||
RestartTaskName := ParamStr(3);
|
||||
|
||||
// Paremeter syntax check
|
||||
if (AppPath = '') or (DownloadPath = '') or (RestartTaskName = '') then begin
|
||||
Status('Syntax: '+ExtractFilename(Paramstr(0))+' OldFile.exe NewFile.exe RestartTaskName'+#13#10+
|
||||
'Please don''t execute this file directly.', True);
|
||||
end;
|
||||
if (not FileExists(AppPath)) or (not FileExists(DownloadPath)) then
|
||||
Status('Error: Either target file "'+AppPath+'" or download file "'+DownloadPath+'" does not exist.', True);
|
||||
// Parameter syntax check
|
||||
if (AppPath = '') or (DownloadPath = '') or (RestartTaskName = '') then begin
|
||||
Status('Syntax: '+ExtractFilename(Paramstr(0))+' OldFile.exe NewFile.exe RestartTaskName'+#13#10+
|
||||
'Please don''t execute this file directly.', True);
|
||||
end;
|
||||
if (not FileExists(AppPath)) or (not FileExists(DownloadPath)) then
|
||||
Status('Error: Either target file "'+AppPath+'" or download file "'+DownloadPath+'" does not exist.', True);
|
||||
|
||||
// Terminate running instances
|
||||
Status('Close running '+AppName+' instances ...');
|
||||
EnumWindows(@EnumAllInstances, 0);
|
||||
// Terminate running instances
|
||||
Status('Close running '+AppName+' instances ...');
|
||||
EnumWindows(@EnumAllInstances, 0);
|
||||
|
||||
// Backup old .exe to working directory
|
||||
Status('Creating backup of old file ...');
|
||||
BackupPath := ExtractFilepath(Paramstr(0))+ExtractFilename(AppPath)+'.backup.exe';
|
||||
if FileExists(BackupPath) then
|
||||
DeleteFile(PChar(BackupPath));
|
||||
if not CopyFile(PChar(AppPath), PChar(BackupPath), False) then
|
||||
Status('Failed to create backup file "'+BackupPath+'" from "'+AppPath+'"', True)
|
||||
else begin
|
||||
DeleteFile(PChar(AppPath));
|
||||
Status('Success.');
|
||||
end;
|
||||
|
||||
// Move update file to final path
|
||||
Status('Moving downloaded file to desired directory ...');
|
||||
// Issue #1616: MoveFile() does not work when target directory is a symlink, so we prefer CopyFile + DeleteFile
|
||||
if not CopyFile(PChar(DownloadPath), PChar(AppPath), False) then
|
||||
Status('Failed to copy file "'+DownloadPath+'" to "'+AppPath+'"', True)
|
||||
else begin
|
||||
DeleteFile(PChar(DownloadPath));
|
||||
Status('Success. Restarting '+AppName+' through task "'+RestartTaskName+'" now ...');
|
||||
RestartCmd := 'schtasks';
|
||||
RestartParams := '/Run /TN ' + RestartTaskName;
|
||||
ShellExecute(0, 'open', PChar(RestartCmd), PChar(RestartParams), '', SW_HIDE);
|
||||
end;
|
||||
PostQuitMessage(0);
|
||||
end;
|
||||
|
||||
|
||||
function WindowProc(hWnd: HWND; msg: UINT; wpr: WPARAM; lpr: LPARAM): LRESULT; stdcall;
|
||||
var
|
||||
x, y: integer;
|
||||
Font: HFont;
|
||||
begin
|
||||
// Custom window procedure
|
||||
case msg of
|
||||
// WM_NCCREATE: Non-client part of the window is being created
|
||||
WM_CREATE: begin
|
||||
// Center window
|
||||
x := GetSystemMetrics(SM_CXSCREEN);
|
||||
y := GetSystemMetrics(SM_CYSCREEN);
|
||||
MoveWindow(hWnd,
|
||||
(x div 2) - (WindowWidth div 2),
|
||||
(y div 2) - (WindowHeight div 2),
|
||||
WindowWidth,
|
||||
WindowHeight,
|
||||
true);
|
||||
// Create status label
|
||||
HLabel := CreateWindow(
|
||||
'STATIC', // Class name
|
||||
'Status:', // Label's text
|
||||
WS_VISIBLE or WS_CHILD or SS_LEFT, // Styles
|
||||
WindowPadding, // X pos
|
||||
WindowPadding, // Y pos
|
||||
WindowWidth - 2*WindowPadding, // Width
|
||||
WindowHeight - 2*WindowPadding, // Height
|
||||
hWnd, // Parent hwnd
|
||||
0, // ID
|
||||
MainWin, // HInstance of program
|
||||
nil // Params for main window
|
||||
);
|
||||
// Cosmetics
|
||||
Font := Createfont(-11, 0, 0, 0, 0, 0, 0, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, 'Tahoma');
|
||||
SendMessage(HLabel, WM_SETFONT, Font, 1);
|
||||
SetBkColor(hwnd, COLOR_BTNFACE+1);
|
||||
// Backup old .exe to working directory
|
||||
Status('Creating backup of old file ...');
|
||||
BackupPath := ExtractFilepath(Paramstr(0))+ExtractFilename(AppPath)+'.backup.exe';
|
||||
if FileExists(BackupPath) then
|
||||
DeleteFile(PChar(BackupPath));
|
||||
if not CopyFile(PChar(AppPath), PChar(BackupPath), False) then
|
||||
Status('Failed to create backup file "'+BackupPath+'" from "'+AppPath+'"', True)
|
||||
else begin
|
||||
DeleteFile(PChar(AppPath));
|
||||
Status('Success.');
|
||||
end;
|
||||
|
||||
WM_SHOWWINDOW: begin
|
||||
if not FormShowing then
|
||||
SetTimer(MainWin, 0, 200, @FormShow);
|
||||
end;
|
||||
|
||||
WM_DESTROY: begin
|
||||
PostQuitMessage(0);
|
||||
// Move update file to final path
|
||||
Status('Moving downloaded file to desired directory ...');
|
||||
// Issue #1616: MoveFile() does not work when target directory is a symlink, so we prefer CopyFile + DeleteFile
|
||||
if not CopyFile(PChar(DownloadPath), PChar(AppPath), False) then
|
||||
Status('Failed to copy file "'+DownloadPath+'" to "'+AppPath+'"', True)
|
||||
else begin
|
||||
DeleteFile(PChar(DownloadPath));
|
||||
Status('Success. Restarting '+AppName+' through task "'+RestartTaskName+'" now ...');
|
||||
RestartCmd := 'schtasks';
|
||||
RestartParams := '/Run /TN ' + RestartTaskName;
|
||||
ShellExecute(0, 'open', PChar(RestartCmd), PChar(RestartParams), '', SW_HIDE);
|
||||
end;
|
||||
|
||||
Status('Exiting in 10 seconds...');
|
||||
Sleep(10000);
|
||||
except
|
||||
on E: Exception do
|
||||
Status(E.ClassName + ': ' + E.Message, True);
|
||||
end;
|
||||
|
||||
Result := DefWindowProc(hWnd, msg, wpr, lpr);
|
||||
end;
|
||||
|
||||
|
||||
|
||||
// Main program goes here
|
||||
begin
|
||||
// Define window class
|
||||
WClass.hInstance := hInstance;
|
||||
WClass.lpszClassName := 'WndClass';
|
||||
WClass.style := CS_HREDRAW or CS_VREDRAW;
|
||||
WClass.hIcon := LoadIcon(hInstance, IDI_WINLOGO);
|
||||
WClass.lpfnWndProc := @WindowProc;
|
||||
WClass.hbrBackground := COLOR_BTNFACE+1;
|
||||
WClass.hCursor := LoadCursor(0, IDC_ARROW);
|
||||
WClass.cbClsExtra := 0;
|
||||
WClass.cbWndExtra := 0;
|
||||
WClass.lpszMenuName := '';
|
||||
RegisterClass(WClass);
|
||||
|
||||
// Create form
|
||||
MainWin := CreateWindow(
|
||||
WClass.lpszClassName,
|
||||
AppName+' Updater',
|
||||
WS_POPUPWINDOW or WS_CAPTION or WS_VISIBLE,
|
||||
100, // Default x + y coordinates, will be centered in WM_CREATE
|
||||
100,
|
||||
WindowWidth, // nWidth
|
||||
WindowHeight, // nHeight
|
||||
0, // hWndParent
|
||||
0, // hMenu
|
||||
hInstance, // hInstance
|
||||
nil // lpParam
|
||||
);
|
||||
|
||||
// Message loop
|
||||
while GetMessage(AppMsg, 0, 0, 0) do begin
|
||||
TranslateMessage(AppMsg);
|
||||
DispatchMessage(AppMsg);
|
||||
end;
|
||||
ExitCode := AppMsg.wParam;
|
||||
end.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
BIN
res/updater/updater.exe
Normal file
BIN
res/updater/updater.exe
Normal file
Binary file not shown.
Binary file not shown.
@@ -1 +0,0 @@
|
||||
updater exe "updater32.exe"
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
updater exe "updater64.exe"
|
||||
Reference in New Issue
Block a user