Added X2UtService wrapper
This commit is contained in:
parent
d4cee0403c
commit
4a287a0715
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
__history/
|
105
X2UtService.GUIContext.Form.dfm
Normal file
105
X2UtService.GUIContext.Form.dfm
Normal file
@ -0,0 +1,105 @@
|
||||
object X2ServiceContextGUIForm: TX2ServiceContextGUIForm
|
||||
Left = 0
|
||||
Top = 0
|
||||
BorderIcons = [biSystemMenu, biMinimize]
|
||||
BorderStyle = bsSingle
|
||||
Caption = 'X2ServiceContextGUIForm'
|
||||
ClientHeight = 177
|
||||
ClientWidth = 285
|
||||
Color = clBtnFace
|
||||
Font.Charset = DEFAULT_CHARSET
|
||||
Font.Color = clWindowText
|
||||
Font.Height = -11
|
||||
Font.Name = 'Tahoma'
|
||||
Font.Style = []
|
||||
OldCreateOrder = False
|
||||
OnCloseQuery = FormCloseQuery
|
||||
DesignSize = (
|
||||
285
|
||||
177)
|
||||
PixelsPerInch = 96
|
||||
TextHeight = 13
|
||||
object btnClose: TButton
|
||||
Left = 107
|
||||
Top = 144
|
||||
Width = 75
|
||||
Height = 25
|
||||
Anchors = [akLeft, akBottom]
|
||||
Caption = '&Close'
|
||||
TabOrder = 0
|
||||
ExplicitTop = 180
|
||||
end
|
||||
object gbStatus: TGroupBox
|
||||
AlignWithMargins = True
|
||||
Left = 8
|
||||
Top = 8
|
||||
Width = 269
|
||||
Height = 57
|
||||
Margins.Left = 8
|
||||
Margins.Top = 8
|
||||
Margins.Right = 8
|
||||
Margins.Bottom = 0
|
||||
Align = alTop
|
||||
Caption = ' Status '
|
||||
TabOrder = 1
|
||||
ExplicitWidth = 261
|
||||
object lblStatus: TLabel
|
||||
Left = 34
|
||||
Top = 26
|
||||
Width = 50
|
||||
Height = 13
|
||||
Caption = 'Starting...'
|
||||
end
|
||||
object Shape1: TShape
|
||||
Left = 12
|
||||
Top = 24
|
||||
Width = 16
|
||||
Height = 16
|
||||
end
|
||||
end
|
||||
object gbCustomControl: TGroupBox
|
||||
AlignWithMargins = True
|
||||
Left = 8
|
||||
Top = 73
|
||||
Width = 269
|
||||
Height = 60
|
||||
Margins.Left = 8
|
||||
Margins.Top = 8
|
||||
Margins.Right = 8
|
||||
Margins.Bottom = 0
|
||||
Align = alTop
|
||||
Caption = ' Custom control '
|
||||
TabOrder = 2
|
||||
DesignSize = (
|
||||
269
|
||||
60)
|
||||
object lblControlCode: TLabel
|
||||
Left = 12
|
||||
Top = 27
|
||||
Width = 25
|
||||
Height = 13
|
||||
Caption = 'Code'
|
||||
end
|
||||
object edtControlCode: TEdit
|
||||
Left = 72
|
||||
Top = 24
|
||||
Width = 102
|
||||
Height = 21
|
||||
Anchors = [akLeft, akTop, akRight]
|
||||
TabOrder = 0
|
||||
Text = '128'
|
||||
OnChange = edtControlCodeChange
|
||||
ExplicitWidth = 173
|
||||
end
|
||||
object btnSend: TButton
|
||||
Left = 180
|
||||
Top = 24
|
||||
Width = 75
|
||||
Height = 21
|
||||
Anchors = [akTop, akRight]
|
||||
Caption = '&Send'
|
||||
TabOrder = 1
|
||||
ExplicitLeft = 251
|
||||
end
|
||||
end
|
||||
end
|
95
X2UtService.GUIContext.Form.pas
Normal file
95
X2UtService.GUIContext.Form.pas
Normal file
@ -0,0 +1,95 @@
|
||||
unit X2UtService.GUIContext.Form;
|
||||
|
||||
interface
|
||||
uses
|
||||
System.Classes,
|
||||
Vcl.Controls,
|
||||
Vcl.ExtCtrls,
|
||||
Vcl.Forms,
|
||||
Vcl.StdCtrls,
|
||||
Winapi.Messages,
|
||||
|
||||
X2UtService.Intf;
|
||||
|
||||
|
||||
const
|
||||
CM_AFTERSHOW = WM_USER + 1;
|
||||
|
||||
type
|
||||
TX2ServiceContextGUIForm = class(TForm)
|
||||
btnClose: TButton;
|
||||
gbStatus: TGroupBox;
|
||||
lblStatus: TLabel;
|
||||
Shape1: TShape;
|
||||
gbCustomControl: TGroupBox;
|
||||
lblControlCode: TLabel;
|
||||
edtControlCode: TEdit;
|
||||
btnSend: TButton;
|
||||
|
||||
procedure edtControlCodeChange(Sender: TObject);
|
||||
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
|
||||
private
|
||||
FContext: IX2ServiceContext;
|
||||
FService: IX2Service;
|
||||
protected
|
||||
procedure DoShow; override;
|
||||
|
||||
procedure CMAfterShow(var Msg: TMessage); message CM_AFTERSHOW;
|
||||
public
|
||||
property Context: IX2ServiceContext read FContext write FContext;
|
||||
property Service: IX2Service read FService write FService;
|
||||
end;
|
||||
|
||||
|
||||
implementation
|
||||
uses
|
||||
System.Math,
|
||||
System.SysUtils,
|
||||
Winapi.Windows;
|
||||
|
||||
|
||||
{$R *.dfm}
|
||||
|
||||
|
||||
// #ToDo1 -oMvR: 21-10-2016: separate service handling out to thread to prevent blocking of the UI
|
||||
|
||||
|
||||
{ TX2ServiceContextGUIForm }
|
||||
procedure TX2ServiceContextGUIForm.DoShow;
|
||||
begin
|
||||
inherited DoShow;
|
||||
|
||||
PostMessage(Self.Handle, CM_AFTERSHOW, 0, 0);
|
||||
end;
|
||||
|
||||
|
||||
procedure TX2ServiceContextGUIForm.CMAfterShow(var Msg: TMessage);
|
||||
begin
|
||||
lblStatus.Caption := 'Starting...';
|
||||
lblStatus.Update;
|
||||
|
||||
if Service.Start(Context) then
|
||||
lblStatus.Caption := 'Started'
|
||||
else
|
||||
lblStatus.Caption := 'Failed to start';
|
||||
end;
|
||||
|
||||
|
||||
procedure TX2ServiceContextGUIForm.edtControlCodeChange(Sender: TObject);
|
||||
begin
|
||||
edtControlCode.Text := IntToStr(Min(Max(StrToIntDef(edtControlCode.Text, 0), 128), 255));
|
||||
end;
|
||||
|
||||
|
||||
procedure TX2ServiceContextGUIForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
|
||||
begin
|
||||
lblStatus.Caption := 'Stopping...';
|
||||
lblStatus.Update;
|
||||
|
||||
CanClose := Service.Stop;
|
||||
|
||||
if not CanClose then
|
||||
lblStatus.Caption := 'Failed to stop';
|
||||
end;
|
||||
|
||||
end.
|
51
X2UtService.GUIContext.pas
Normal file
51
X2UtService.GUIContext.pas
Normal file
@ -0,0 +1,51 @@
|
||||
unit X2UtService.GUIContext;
|
||||
|
||||
interface
|
||||
uses
|
||||
X2UtService.Intf;
|
||||
|
||||
|
||||
type
|
||||
TX2ServiceContextGUI = class(TInterfacedObject, IX2ServiceContext)
|
||||
protected
|
||||
procedure StartService(AService: IX2Service); virtual;
|
||||
public
|
||||
constructor Create(AService: IX2Service);
|
||||
|
||||
{ IX2ServiceContext }
|
||||
function GetMode: TX2ServiceMode;
|
||||
end;
|
||||
|
||||
|
||||
implementation
|
||||
uses
|
||||
X2UtService.GUIContext.Form;
|
||||
|
||||
|
||||
{ TX2ServiceContextGUI }
|
||||
constructor TX2ServiceContextGUI.Create(AService: IX2Service);
|
||||
begin
|
||||
inherited Create;
|
||||
end;
|
||||
|
||||
|
||||
function TX2ServiceContextGUI.GetMode: TX2ServiceMode;
|
||||
begin
|
||||
Result := smInteractive;
|
||||
end;
|
||||
|
||||
|
||||
procedure TX2ServiceContextGUI.StartService(AService: IX2Service);
|
||||
begin
|
||||
with TX2ServiceContextGUIForm.Create(nil) do
|
||||
try
|
||||
Caption := AService.DisplayName;
|
||||
Service := AService;
|
||||
|
||||
ShowModal;
|
||||
finally
|
||||
Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
end.
|
82
X2UtService.Intf.pas
Normal file
82
X2UtService.Intf.pas
Normal file
@ -0,0 +1,82 @@
|
||||
unit X2UtService.Intf;
|
||||
|
||||
interface
|
||||
uses
|
||||
Classes;
|
||||
|
||||
|
||||
type
|
||||
TX2ServiceMode = (smService, smInteractive);
|
||||
|
||||
|
||||
IX2ServiceContext = interface
|
||||
['{0AC283A7-B46C-4E4E-8F36-F8AA1272E04B}']
|
||||
function GetMode: TX2ServiceMode;
|
||||
|
||||
property Mode: TX2ServiceMode read GetMode;
|
||||
end;
|
||||
|
||||
|
||||
IX2Service = interface
|
||||
['{C8597906-87B8-444E-847B-37A034F72FFC}']
|
||||
function GetServiceName: string;
|
||||
function GetDisplayName: string;
|
||||
|
||||
|
||||
{ Called when the service starts. Return True if succesful.
|
||||
Storing a reference to AContext is allowed, but must be released when Stop is called. }
|
||||
function Start(AContext: IX2ServiceContext): Boolean;
|
||||
|
||||
{ Called when the service is about to stop.
|
||||
Return True if succesful. }
|
||||
function Stop: Boolean;
|
||||
|
||||
{ Called for control codes in the user-defined range of 128 to 255. }
|
||||
function DoCustomControl(ACode: Byte): Boolean;
|
||||
|
||||
|
||||
property ServiceName: string read GetServiceName;
|
||||
property DisplayName: string read GetDisplayName;
|
||||
end;
|
||||
|
||||
|
||||
TX2CustomService = class(TInterfacedObject, IX2Service)
|
||||
private
|
||||
FContext: IX2ServiceContext;
|
||||
protected
|
||||
property Context: IX2ServiceContext read FContext;
|
||||
public
|
||||
{ IX2Service }
|
||||
function GetServiceName: string; virtual; abstract;
|
||||
function GetDisplayName: string; virtual; abstract;
|
||||
|
||||
function Start(AContext: IX2ServiceContext): Boolean; virtual;
|
||||
function Stop: Boolean; virtual;
|
||||
|
||||
function DoCustomControl(ACode: Byte): Boolean; virtual;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
|
||||
{ TX2CustomService }
|
||||
function TX2CustomService.Start(AContext: IX2ServiceContext): Boolean;
|
||||
begin
|
||||
FContext := AContext;
|
||||
end;
|
||||
|
||||
|
||||
function TX2CustomService.Stop: Boolean;
|
||||
begin
|
||||
FContext := nil;
|
||||
end;
|
||||
|
||||
|
||||
function TX2CustomService.DoCustomControl(ACode: Byte): Boolean;
|
||||
begin
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
end.
|
128
X2UtService.ServiceContext.pas
Normal file
128
X2UtService.ServiceContext.pas
Normal file
@ -0,0 +1,128 @@
|
||||
unit X2UtService.ServiceContext;
|
||||
|
||||
interface
|
||||
uses
|
||||
X2UtService.Intf;
|
||||
|
||||
|
||||
type
|
||||
TX2ServiceContextService = class(TInterfacedObject, IX2ServiceContext)
|
||||
protected
|
||||
procedure StartService(AService: IX2Service); virtual;
|
||||
public
|
||||
constructor Create(AService: IX2Service);
|
||||
|
||||
{ IX2ServiceContext }
|
||||
function GetMode: TX2ServiceMode;
|
||||
end;
|
||||
|
||||
|
||||
implementation
|
||||
uses
|
||||
System.Classes,
|
||||
Vcl.SvcMgr;
|
||||
|
||||
|
||||
type
|
||||
TX2ServiceModule = class(TService)
|
||||
private
|
||||
FContext: IX2ServiceContext;
|
||||
FService: IX2Service;
|
||||
protected
|
||||
function GetServiceController: TServiceController; override;
|
||||
|
||||
procedure HandleStart(Sender: TService; var Started: Boolean); virtual;
|
||||
procedure HandleStop(Sender: TService; var Stopped: Boolean); virtual;
|
||||
|
||||
function DoCustomControl(CtrlCode: Cardinal): Boolean; override;
|
||||
|
||||
property Context: IX2ServiceContext read FContext;
|
||||
property Service: IX2Service read FService;
|
||||
public
|
||||
constructor Create(AOwner: TComponent; AContext: IX2ServiceContext; AService: IX2Service); reintroduce;
|
||||
end;
|
||||
|
||||
|
||||
var
|
||||
ServiceModuleInstance: TX2ServiceModule;
|
||||
|
||||
|
||||
procedure ServiceController(CtrlCode: Cardinal); stdcall;
|
||||
begin
|
||||
if Assigned(ServiceModuleInstance) then
|
||||
ServiceModuleInstance.Controller(CtrlCode);
|
||||
end;
|
||||
|
||||
|
||||
|
||||
{ TX2ServiceContextService }
|
||||
constructor TX2ServiceContextService.Create(AService: IX2Service);
|
||||
begin
|
||||
inherited Create;
|
||||
end;
|
||||
|
||||
|
||||
function TX2ServiceContextService.GetMode: TX2ServiceMode;
|
||||
begin
|
||||
Result := smService;
|
||||
end;
|
||||
|
||||
|
||||
procedure TX2ServiceContextService.StartService(AService: IX2Service);
|
||||
begin
|
||||
if Assigned(ServiceModuleInstance) then
|
||||
raise EInvalidOperation.Create('An instance of TX2ServiceContextService is already running');
|
||||
|
||||
Application.Initialize;
|
||||
ServiceModuleInstance := TX2ServiceModule.Create(Application, Self, AService);
|
||||
try
|
||||
ServiceModuleInstance.DisplayName := '';//
|
||||
ServiceModuleInstance.ServiceStartName := '';//
|
||||
|
||||
Application.Run;
|
||||
finally
|
||||
ServiceModuleInstance := nil;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
{ TX2ServiceModule }
|
||||
constructor TX2ServiceModule.Create(AOwner: TComponent; AContext: IX2ServiceContext; AService: IX2Service);
|
||||
begin
|
||||
inherited Create(AOwner);
|
||||
|
||||
FContext := AContext;
|
||||
FService := AService;
|
||||
|
||||
OnStart := HandleStart;
|
||||
OnStop := HandleStop;
|
||||
end;
|
||||
|
||||
|
||||
function TX2ServiceModule.GetServiceController: TServiceController;
|
||||
begin
|
||||
Result := ServiceController;
|
||||
end;
|
||||
|
||||
|
||||
function TX2ServiceModule.DoCustomControl(CtrlCode: Cardinal): Boolean;
|
||||
begin
|
||||
Result := True;
|
||||
|
||||
if (CtrlCode >= 128) and (CtrlCode <= 255) then
|
||||
Result := Service.DoCustomControl(Byte(CtrlCode));
|
||||
end;
|
||||
|
||||
|
||||
procedure TX2ServiceModule.HandleStart(Sender: TService; var Started: Boolean);
|
||||
begin
|
||||
Started := Service.Start(Context);
|
||||
end;
|
||||
|
||||
|
||||
procedure TX2ServiceModule.HandleStop(Sender: TService; var Stopped: Boolean);
|
||||
begin
|
||||
Stopped := Service.Stop;
|
||||
end;
|
||||
|
||||
end.
|
65
X2UtService.pas
Normal file
65
X2UtService.pas
Normal file
@ -0,0 +1,65 @@
|
||||
unit X2UtService;
|
||||
|
||||
interface
|
||||
uses
|
||||
X2UtService.Intf;
|
||||
|
||||
|
||||
type
|
||||
TX2Service = class(TObject)
|
||||
public
|
||||
class function Run(AService: IX2Service): IX2ServiceContext;
|
||||
end;
|
||||
|
||||
|
||||
function IsUserInteractive: Boolean;
|
||||
|
||||
|
||||
implementation
|
||||
uses
|
||||
System.SysUtils,
|
||||
Winapi.Windows,
|
||||
|
||||
X2UtService.GUIContext,
|
||||
X2UtService.ServiceContext;
|
||||
|
||||
|
||||
|
||||
function IsUserInteractive: Boolean;
|
||||
var
|
||||
windowStation: HWINSTA;
|
||||
userObject: TUserObjectFlags;
|
||||
lengthNeeded: Cardinal;
|
||||
|
||||
begin
|
||||
Result := True;
|
||||
|
||||
windowStation := GetProcessWindowStation;
|
||||
if windowStation <> 0 then
|
||||
begin
|
||||
lengthNeeded := 0;
|
||||
FillChar(userObject, SizeOf(userObject), 0);
|
||||
|
||||
if GetUserObjectInformation(windowStation, UOI_FLAGS, @userObject, SizeOf(userObject), lengthNeeded) and
|
||||
((userObject.dwFlags and WSF_VISIBLE) = 0) then
|
||||
begin
|
||||
Result := False;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
{ TX2Service }
|
||||
class function TX2Service.Run(AService: IX2Service): IX2ServiceContext;
|
||||
begin
|
||||
if FindCmdLineSwitch('install', ['-', '/'], True) or
|
||||
FindCmdLineSwitch('uninstall', ['-', '/'], True) or
|
||||
(not IsUserInteractive) then
|
||||
begin
|
||||
Result := TX2ServiceContextService.Create(AService);
|
||||
end else
|
||||
Result := TX2ServiceContextGUI.Create(AService);
|
||||
end;
|
||||
|
||||
end.
|
Loading…
Reference in New Issue
Block a user