Added thread for running the service in GUIContext
Added Elevation check for install / uninstall
This commit is contained in:
parent
b2e6510d19
commit
360f06ae74
@ -6,15 +6,13 @@ uses
|
|||||||
Vcl.Controls,
|
Vcl.Controls,
|
||||||
Vcl.ExtCtrls,
|
Vcl.ExtCtrls,
|
||||||
Vcl.Forms,
|
Vcl.Forms,
|
||||||
|
Vcl.Graphics,
|
||||||
Vcl.StdCtrls,
|
Vcl.StdCtrls,
|
||||||
Winapi.Messages,
|
Winapi.Messages,
|
||||||
|
|
||||||
X2UtService.Intf;
|
X2UtService.Intf;
|
||||||
|
|
||||||
|
|
||||||
const
|
|
||||||
CM_AFTERSHOW = WM_USER + 1;
|
|
||||||
|
|
||||||
type
|
type
|
||||||
TX2ServiceContextGUIForm = class(TForm)
|
TX2ServiceContextGUIForm = class(TForm)
|
||||||
btnClose: TButton;
|
btnClose: TButton;
|
||||||
@ -33,12 +31,15 @@ type
|
|||||||
private
|
private
|
||||||
FContext: IX2ServiceContext;
|
FContext: IX2ServiceContext;
|
||||||
FService: IX2Service;
|
FService: IX2Service;
|
||||||
|
FServiceThread: TThread;
|
||||||
|
FAllowClose: Boolean;
|
||||||
protected
|
protected
|
||||||
procedure DoShow; override;
|
procedure DoShow; override;
|
||||||
|
|
||||||
procedure CMAfterShow(var Msg: TMessage); message CM_AFTERSHOW;
|
|
||||||
|
|
||||||
function GetControlCode: Byte;
|
function GetControlCode: Byte;
|
||||||
|
procedure SetStatus(const AMessage: string; AColor: TColor);
|
||||||
|
|
||||||
|
property ServiceThread: TThread read FServiceThread;
|
||||||
public
|
public
|
||||||
property Context: IX2ServiceContext read FContext write FContext;
|
property Context: IX2ServiceContext read FContext write FContext;
|
||||||
property Service: IX2Service read FService write FService;
|
property Service: IX2Service read FService write FService;
|
||||||
@ -47,9 +48,10 @@ type
|
|||||||
|
|
||||||
implementation
|
implementation
|
||||||
uses
|
uses
|
||||||
|
System.Generics.Collections,
|
||||||
System.Math,
|
System.Math,
|
||||||
|
System.SyncObjs,
|
||||||
System.SysUtils,
|
System.SysUtils,
|
||||||
Vcl.Graphics,
|
|
||||||
Winapi.Windows;
|
Winapi.Windows;
|
||||||
|
|
||||||
|
|
||||||
@ -63,36 +65,87 @@ const
|
|||||||
StatusColorStopped = clRed;
|
StatusColorStopped = clRed;
|
||||||
|
|
||||||
|
|
||||||
// #ToDo1 -oMvR: 21-10-2016: separate service handling out to thread to prevent blocking of the UI
|
type
|
||||||
|
TX2ServiceThread = class(TThread)
|
||||||
|
private
|
||||||
|
FContext: IX2ServiceContext;
|
||||||
|
FService: IX2Service;
|
||||||
|
FWakeEvent: TEvent;
|
||||||
|
FSendCodeList: TList<Integer>;
|
||||||
|
|
||||||
|
FOnStarted: TThreadProcedure;
|
||||||
|
FOnStartFailed: TThreadProcedure;
|
||||||
|
FOnStopped: TThreadProcedure;
|
||||||
|
FOnStopFailed: TThreadProcedure;
|
||||||
|
protected
|
||||||
|
procedure Execute; override;
|
||||||
|
procedure TerminatedSet; override;
|
||||||
|
|
||||||
|
procedure FlushSendCodeList;
|
||||||
|
|
||||||
|
property Context: IX2ServiceContext read FContext;
|
||||||
|
property Service: IX2Service read FService;
|
||||||
|
property WakeEvent: TEvent read FWakeEvent;
|
||||||
|
public
|
||||||
|
constructor Create(AContext: IX2ServiceContext; AService: IX2Service);
|
||||||
|
destructor Destroy; override;
|
||||||
|
|
||||||
|
procedure SendControlCode(ACode: Byte);
|
||||||
|
|
||||||
|
property OnStarted: TThreadProcedure read FOnStarted write FOnStarted;
|
||||||
|
property OnStartFailed: TThreadProcedure read FOnStartFailed write FOnStartFailed;
|
||||||
|
property OnStopped: TThreadProcedure read FOnStopped write FOnStopped;
|
||||||
|
property OnStopFailed: TThreadProcedure read FOnStopFailed write FOnStopFailed;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{ TX2ServiceContextGUIForm }
|
{ TX2ServiceContextGUIForm }
|
||||||
procedure TX2ServiceContextGUIForm.DoShow;
|
procedure TX2ServiceContextGUIForm.DoShow;
|
||||||
|
var
|
||||||
|
serviceThread: TX2ServiceThread;
|
||||||
begin
|
begin
|
||||||
inherited DoShow;
|
inherited DoShow;
|
||||||
|
|
||||||
PostMessage(Self.Handle, CM_AFTERSHOW, 0, 0);
|
if not Assigned(FServiceThread) then
|
||||||
end;
|
|
||||||
|
|
||||||
|
|
||||||
procedure TX2ServiceContextGUIForm.CMAfterShow(var Msg: TMessage);
|
|
||||||
begin
|
|
||||||
shpStatus.Brush.Color := StatusColorStarting;
|
|
||||||
lblStatus.Caption := 'Starting...';
|
|
||||||
Application.ProcessMessages;
|
|
||||||
|
|
||||||
if Service.Start(Context) then
|
|
||||||
begin
|
begin
|
||||||
shpStatus.Brush.Color := StatusColorStarted;
|
SetStatus('Starting...', StatusColorStarting);
|
||||||
lblStatus.Caption := 'Started';
|
serviceThread := TX2ServiceThread.Create(Context, Service);
|
||||||
end else
|
serviceThread.OnStarted :=
|
||||||
begin
|
procedure
|
||||||
shpStatus.Brush.Color := StatusColorStopped;
|
begin
|
||||||
lblStatus.Caption := 'Failed to start';
|
SetStatus('Started', StatusColorStarted);
|
||||||
|
end;
|
||||||
|
|
||||||
|
serviceThread.OnStartFailed :=
|
||||||
|
procedure
|
||||||
|
begin
|
||||||
|
SetStatus('Start failed', StatusColorStopped);
|
||||||
|
FServiceThread := nil;
|
||||||
|
end;
|
||||||
|
|
||||||
|
serviceThread.OnStopped :=
|
||||||
|
procedure
|
||||||
|
begin
|
||||||
|
SetStatus('Stopped', StatusColorStopped);
|
||||||
|
|
||||||
|
FAllowClose := True;
|
||||||
|
Close;
|
||||||
|
end;
|
||||||
|
|
||||||
|
serviceThread.OnStopFailed :=
|
||||||
|
procedure
|
||||||
|
begin
|
||||||
|
SetStatus('Stop failed', StatusColorStarted);
|
||||||
|
end;
|
||||||
|
|
||||||
|
FServiceThread := serviceThread;
|
||||||
|
FServiceThread.Start;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
procedure TX2ServiceContextGUIForm.edtControlCodeChange(Sender: TObject);
|
procedure TX2ServiceContextGUIForm.edtControlCodeChange(Sender: TObject);
|
||||||
begin
|
begin
|
||||||
edtControlCode.Text := IntToStr(GetControlCode);
|
edtControlCode.Text := IntToStr(GetControlCode);
|
||||||
@ -101,7 +154,7 @@ end;
|
|||||||
|
|
||||||
procedure TX2ServiceContextGUIForm.btnSendClick(Sender: TObject);
|
procedure TX2ServiceContextGUIForm.btnSendClick(Sender: TObject);
|
||||||
begin
|
begin
|
||||||
Service.DoCustomControl(GetControlCode);
|
(ServiceThread as TX2ServiceThread).SendControlCode(GetControlCode);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -113,14 +166,13 @@ end;
|
|||||||
|
|
||||||
procedure TX2ServiceContextGUIForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
|
procedure TX2ServiceContextGUIForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
|
||||||
begin
|
begin
|
||||||
shpStatus.Brush.Color := StatusColorStopping;
|
if not FAllowClose then
|
||||||
lblStatus.Caption := 'Stopping...';
|
begin
|
||||||
Application.ProcessMessages;
|
SetStatus('Stopping...', StatusColorStopping);
|
||||||
|
CanClose := False;
|
||||||
|
|
||||||
CanClose := Service.Stop;
|
ServiceThread.Terminate;
|
||||||
|
end;
|
||||||
if not CanClose then
|
|
||||||
lblStatus.Caption := 'Failed to stop';
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -129,4 +181,109 @@ begin
|
|||||||
Result := Byte(Min(Max(StrToIntDef(edtControlCode.Text, 0), 128), 255));
|
Result := Byte(Min(Max(StrToIntDef(edtControlCode.Text, 0), 128), 255));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TX2ServiceContextGUIForm.SetStatus(const AMessage: string; AColor: TColor);
|
||||||
|
begin
|
||||||
|
shpStatus.Brush.Color := AColor;
|
||||||
|
lblStatus.Caption := AMessage;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{ TX2ServiceThread }
|
||||||
|
constructor TX2ServiceThread.Create(AContext: IX2ServiceContext; AService: IX2Service);
|
||||||
|
begin
|
||||||
|
inherited Create(True);
|
||||||
|
|
||||||
|
FContext := AContext;
|
||||||
|
FService := AService;
|
||||||
|
|
||||||
|
FWakeEvent := TEvent.Create(nil, False, False, '');
|
||||||
|
FSendCodeList := TList<Integer>.Create;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
destructor TX2ServiceThread.Destroy;
|
||||||
|
begin
|
||||||
|
FreeAndNil(FWakeEvent);
|
||||||
|
FreeAndNil(FSendCodeList);
|
||||||
|
|
||||||
|
inherited Destroy;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TX2ServiceThread.Execute;
|
||||||
|
begin
|
||||||
|
try
|
||||||
|
Service.Start(Context);
|
||||||
|
except
|
||||||
|
if Assigned(FOnStartFailed) then
|
||||||
|
Synchronize(FOnStartFailed);
|
||||||
|
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if Assigned(FOnStarted) then
|
||||||
|
Synchronize(FOnStarted);
|
||||||
|
|
||||||
|
while True do
|
||||||
|
begin
|
||||||
|
try
|
||||||
|
WakeEvent.WaitFor(INFINITE);
|
||||||
|
|
||||||
|
if Terminated then
|
||||||
|
begin
|
||||||
|
Service.Stop;
|
||||||
|
|
||||||
|
if Assigned(FOnStopped) then
|
||||||
|
Synchronize(FOnStopped);
|
||||||
|
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
|
||||||
|
FlushSendCodeList;
|
||||||
|
except
|
||||||
|
if Assigned(FOnStopFailed) then
|
||||||
|
Synchronize(FOnStopFailed);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TX2ServiceThread.FlushSendCodeList;
|
||||||
|
var
|
||||||
|
code: Byte;
|
||||||
|
|
||||||
|
begin
|
||||||
|
System.TMonitor.Enter(FSendCodeList);
|
||||||
|
try
|
||||||
|
for code in FSendCodeList do
|
||||||
|
Service.DoCustomControl(code);
|
||||||
|
|
||||||
|
FSendCodeList.Clear;
|
||||||
|
finally
|
||||||
|
System.TMonitor.Exit(FSendCodeList);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TX2ServiceThread.TerminatedSet;
|
||||||
|
begin
|
||||||
|
inherited TerminatedSet;
|
||||||
|
|
||||||
|
WakeEvent.SetEvent;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TX2ServiceThread.SendControlCode(ACode: Byte);
|
||||||
|
begin
|
||||||
|
System.TMonitor.Enter(FSendCodeList);
|
||||||
|
try
|
||||||
|
FSendCodeList.Add(ACode);
|
||||||
|
finally
|
||||||
|
System.TMonitor.Exit(FSendCodeList);
|
||||||
|
end;
|
||||||
|
|
||||||
|
WakeEvent.SetEvent;
|
||||||
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
@ -19,6 +19,8 @@ type
|
|||||||
|
|
||||||
implementation
|
implementation
|
||||||
uses
|
uses
|
||||||
|
Vcl.Forms,
|
||||||
|
|
||||||
X2UtService.GUIContext.Form;
|
X2UtService.GUIContext.Form;
|
||||||
|
|
||||||
|
|
||||||
@ -38,16 +40,18 @@ end;
|
|||||||
|
|
||||||
|
|
||||||
procedure TX2ServiceContextGUI.StartService(AService: IX2Service);
|
procedure TX2ServiceContextGUI.StartService(AService: IX2Service);
|
||||||
begin
|
var
|
||||||
with TX2ServiceContextGUIForm.Create(nil) do
|
serviceForm: TX2ServiceContextGUIForm;
|
||||||
try
|
|
||||||
Caption := AService.DisplayName;
|
|
||||||
Service := AService;
|
|
||||||
|
|
||||||
ShowModal;
|
begin
|
||||||
finally
|
Application.Initialize;
|
||||||
Free;
|
Application.MainFormOnTaskBar := True;
|
||||||
end;
|
|
||||||
|
Application.CreateForm(TX2ServiceContextGUIForm, serviceForm);
|
||||||
|
serviceForm.Caption := AService.DisplayName;
|
||||||
|
serviceForm.Service := AService;
|
||||||
|
|
||||||
|
Application.Run;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
@ -10,6 +10,8 @@ type
|
|||||||
protected
|
protected
|
||||||
procedure StartService(AService: IX2Service); virtual;
|
procedure StartService(AService: IX2Service); virtual;
|
||||||
public
|
public
|
||||||
|
class function IsInstallUninstall: Boolean;
|
||||||
|
|
||||||
constructor Create(AService: IX2Service);
|
constructor Create(AService: IX2Service);
|
||||||
|
|
||||||
{ IX2ServiceContext }
|
{ IX2ServiceContext }
|
||||||
@ -20,7 +22,10 @@ type
|
|||||||
implementation
|
implementation
|
||||||
uses
|
uses
|
||||||
System.Classes,
|
System.Classes,
|
||||||
Vcl.SvcMgr;
|
System.SysUtils,
|
||||||
|
Vcl.SvcMgr,
|
||||||
|
|
||||||
|
X2UtElevation;
|
||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
@ -56,9 +61,21 @@ end;
|
|||||||
|
|
||||||
|
|
||||||
{ TX2ServiceContextService }
|
{ TX2ServiceContextService }
|
||||||
|
class function TX2ServiceContextService.IsInstallUninstall: Boolean;
|
||||||
|
begin
|
||||||
|
Result := FindCmdLineSwitch('install', ['-', '/'], True) or
|
||||||
|
FindCmdLineSwitch('uninstall', ['-', '/'], True);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
constructor TX2ServiceContextService.Create(AService: IX2Service);
|
constructor TX2ServiceContextService.Create(AService: IX2Service);
|
||||||
begin
|
begin
|
||||||
inherited Create;
|
inherited Create;
|
||||||
|
|
||||||
|
if IsInstallUninstall and (not IsElevated) then
|
||||||
|
raise Exception.Create('Elevation is required for install or uninstall');
|
||||||
|
|
||||||
|
StartService(AService);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -76,8 +93,8 @@ begin
|
|||||||
Application.Initialize;
|
Application.Initialize;
|
||||||
ServiceModuleInstance := TX2ServiceModule.Create(Application, Self, AService);
|
ServiceModuleInstance := TX2ServiceModule.Create(Application, Self, AService);
|
||||||
try
|
try
|
||||||
ServiceModuleInstance.DisplayName := '';//
|
ServiceModuleInstance.DisplayName := AService.DisplayName;
|
||||||
ServiceModuleInstance.ServiceStartName := '';//
|
ServiceModuleInstance.Name := AService.ServiceName;
|
||||||
|
|
||||||
Application.Run;
|
Application.Run;
|
||||||
finally
|
finally
|
||||||
@ -89,7 +106,8 @@ end;
|
|||||||
{ TX2ServiceModule }
|
{ TX2ServiceModule }
|
||||||
constructor TX2ServiceModule.Create(AOwner: TComponent; AContext: IX2ServiceContext; AService: IX2Service);
|
constructor TX2ServiceModule.Create(AOwner: TComponent; AContext: IX2ServiceContext; AService: IX2Service);
|
||||||
begin
|
begin
|
||||||
inherited Create(AOwner);
|
// Skip default constructor to prevent DFM streaming
|
||||||
|
CreateNew(AOwner);
|
||||||
|
|
||||||
FContext := AContext;
|
FContext := AContext;
|
||||||
FService := AService;
|
FService := AService;
|
||||||
|
@ -53,12 +53,9 @@ end;
|
|||||||
{ TX2Service }
|
{ TX2Service }
|
||||||
class function TX2Service.Run(AService: IX2Service): IX2ServiceContext;
|
class function TX2Service.Run(AService: IX2Service): IX2ServiceContext;
|
||||||
begin
|
begin
|
||||||
if FindCmdLineSwitch('install', ['-', '/'], True) or
|
if TX2ServiceContextService.IsInstallUninstall or (not IsUserInteractive) then
|
||||||
FindCmdLineSwitch('uninstall', ['-', '/'], True) or
|
Result := TX2ServiceContextService.Create(AService)
|
||||||
(not IsUserInteractive) then
|
else
|
||||||
begin
|
|
||||||
Result := TX2ServiceContextService.Create(AService);
|
|
||||||
end else
|
|
||||||
Result := TX2ServiceContextGUI.Create(AService);
|
Result := TX2ServiceContextGUI.Create(AService);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user