From 1e7a0873558140b506c01af5c50c73cfe940466e Mon Sep 17 00:00:00 2001 From: Mark van Renswoude Date: Thu, 6 Jul 2017 17:05:07 +0200 Subject: [PATCH] Support for Delphi 10.2 Tokyo Added packages Changed hardcoded IFDEF to CompilerVersion comparison --- .gitignore | 6 +- Packages/D10/X2Utils.dpk | 70 ++++ Packages/D10/X2Utils.dproj | 241 +++++++++++ Packages/D10/X2Utils.res | Bin 0 -> 27432 bytes Packages/D10/X2Utils.stat | 10 + Packages/D10/X2Utils_Icon.ico | Bin 0 -> 26694 bytes X2UtElevation.pas | 4 +- X2UtService.GUIContext.Form.dfm | 264 ++++++------ X2UtService.GUIContext.Form.pas | 684 ++++++++++++++++---------------- X2UtService.GUIContext.pas | 140 +++---- X2UtService.Intf.pas | 204 +++++----- X2UtService.ServiceContext.pas | 292 +++++++------- X2UtService.pas | 124 +++--- 13 files changed, 1180 insertions(+), 859 deletions(-) create mode 100644 Packages/D10/X2Utils.dpk create mode 100644 Packages/D10/X2Utils.dproj create mode 100644 Packages/D10/X2Utils.res create mode 100644 Packages/D10/X2Utils.stat create mode 100644 Packages/D10/X2Utils_Icon.ico diff --git a/.gitignore b/.gitignore index bc36587..5127620 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ -__history/ -*.local -*.identcache +__history/ +*.local +*.identcache diff --git a/Packages/D10/X2Utils.dpk b/Packages/D10/X2Utils.dpk new file mode 100644 index 0000000..d669045 --- /dev/null +++ b/Packages/D10/X2Utils.dpk @@ -0,0 +1,70 @@ +package X2Utils; + +{$R *.res} +{$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} +{$ALIGN 8} +{$ASSERTIONS ON} +{$BOOLEVAL OFF} +{$DEBUGINFO OFF} +{$EXTENDEDSYNTAX ON} +{$IMPORTEDDATA ON} +{$IOCHECKS ON} +{$LOCALSYMBOLS ON} +{$LONGSTRINGS ON} +{$OPENSTRINGS ON} +{$OPTIMIZATION ON} +{$OVERFLOWCHECKS OFF} +{$RANGECHECKS OFF} +{$REFERENCEINFO ON} +{$SAFEDIVIDE OFF} +{$STACKFRAMES ON} +{$TYPEDADDRESS OFF} +{$VARSTRINGCHECKS ON} +{$WRITEABLECONST ON} +{$MINENUMSIZE 1} +{$IMAGEBASE $400000} +{$ENDIF IMPLICITBUILDING} +{$DESCRIPTION 'X2Utils'} +{$LIBSUFFIX 'D10'} +{$RUNONLY} +{$IMPLICITBUILD ON} + +requires + rtl, + vcl, + xmlrtl; + +contains + X2UtApp in '..\..\X2UtApp.pas', + X2UtBits in '..\..\X2UtBits.pas', + X2UtGraphics in '..\..\X2UtGraphics.pas', + X2UtHandCursor in '..\..\X2UtHandCursor.pas', + X2UtHashes in '..\..\X2UtHashes.pas', + X2UtHashesVariants in '..\..\X2UtHashesVariants.pas', + X2UtMisc in '..\..\X2UtMisc.pas', + X2UtOS in '..\..\X2UtOS.pas', + X2UtStrings in '..\..\X2UtStrings.pas', + X2UtImageInfo in '..\..\X2UtImageInfo.pas', + X2UtTempFile in '..\..\X2UtTempFile.pas', + X2UtIniParser in '..\..\X2UtIniParser.pas', + X2UtProcess in '..\..\X2UtProcess.pas', + X2UtSingleInstance in '..\..\X2UtSingleInstance.pas', + X2UtStreams in '..\..\X2UtStreams.pas', + X2UtNamedFormat in '..\..\X2UtNamedFormat.pas', + X2UtPersist in '..\..\X2UtPersist.pas', + X2UtPersistForm in '..\..\X2UtPersistForm.pas', + X2UtPersistIntf in '..\..\X2UtPersistIntf.pas', + X2UtPersistRegistry in '..\..\X2UtPersistRegistry.pas', + X2UtElevation in '..\..\X2UtElevation.pas', + X2UtPersistXML in '..\..\X2UtPersistXML.pas', + X2UtPersistXMLBinding in '..\..\X2UtPersistXMLBinding.pas', + XMLDataBindingUtils in '..\..\XMLDataBindingUtils.pas', + X2UtDelphiCompatibility in '..\..\X2UtDelphiCompatibility.pas', + X2UtCursors in '..\..\X2UtCursors.pas', + X2UtService.GUIContext.Form in '..\..\X2UtService.GUIContext.Form.pas' {X2ServiceContextGUIForm}, + X2UtService.GUIContext in '..\..\X2UtService.GUIContext.pas', + X2UtService.Intf in '..\..\X2UtService.Intf.pas', + X2UtService in '..\..\X2UtService.pas', + X2UtService.ServiceContext in '..\..\X2UtService.ServiceContext.pas'; + +end. diff --git a/Packages/D10/X2Utils.dproj b/Packages/D10/X2Utils.dproj new file mode 100644 index 0000000..9483666 --- /dev/null +++ b/Packages/D10/X2Utils.dproj @@ -0,0 +1,241 @@ + + + {3cd28184-f9a5-4320-9ad8-80ef25ba762e} + X2Utils.dpk + Debug + DCC32 + P:\algemeen\bin\D2007\X2Utils2007.bpl + VCL + 18.2 + True + Debug + Win32 + 3 + Package + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + true + Cfg_2 + true + true + + + true + Cfg_2 + true + true + + + true + true + 00400000 + true + X2Utils + Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;Winapi;System.Win;$(DCC_Namespace) + true + 1043 + true + CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + D10 + true + X2Utils + + + package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey= + Debug + false + android-support-v4.dex.jar;cloud-messaging.dex.jar;fmx.dex.jar;google-analytics-v2.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar;google-play-services.dex.jar + + + $(DELPHIBIN) + $(DELPHILIB) + $(DELPHIBIN) + X2Utils_Icon.ico + Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + 1033 + + + Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) + $(DELPHIBIN64) + 1033 + $(DELPHIBIN64) + $(DELPHILIB64) + X2Utils_Icon.ico + + + 7.0 + 0 + True + False + True + 0 + RELEASE;$(DCC_Define) + + + 1033 + + + 1033 + + + 7.0 + True + True + $(DELPHILIB) + $(DELPHILIB) + + + 1033 + + + 1033 + + + Delphi.Personality.12 + Package + + + + False + True + False + + + True + False + 1 + 0 + 0 + 0 + False + False + False + False + False + 1043 + 1252 + + + + + 1.0.0.0 + + + + + + 1.0.0.0 + + + + X2Utils.dpk + + + Microsoft Office 2000 Sample Automation Server Wrapper Components + Microsoft Office XP Sample Automation Server Wrapper Components + + + + False + True + True + + + 12 + + + + + MainSource + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
X2ServiceContextGUIForm
+
+ + + + + + Cfg_2 + Base + + + Base + + + Cfg_1 + Base + +
+ + +
diff --git a/Packages/D10/X2Utils.res b/Packages/D10/X2Utils.res new file mode 100644 index 0000000000000000000000000000000000000000..df7d05824cab9f268c78f0458188fc0a779e7b37 GIT binary patch literal 27432 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 literal 0 HcmV?d00001 diff --git a/Packages/D10/X2Utils.stat b/Packages/D10/X2Utils.stat new file mode 100644 index 0000000..822d5bf --- /dev/null +++ b/Packages/D10/X2Utils.stat @@ -0,0 +1,10 @@ +[Stats] +EditorSecs=43 +DesignerSecs=1 +InspectorSecs=1 +CompileSecs=1667 +OtherSecs=12 +StartTime=6-7-2017 15:40:36 +RealKeys=0 +EffectiveKeys=0 +DebugSecs=1 diff --git a/Packages/D10/X2Utils_Icon.ico b/Packages/D10/X2Utils_Icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..7ade9bfeb8b05b0ea62fea5df422623ce7fc8311 GIT binary patch literal 26694 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 a#sOVYz&US-*N!}_#yl;*8c!pxT%T& literal 0 HcmV?d00001 diff --git a/X2UtElevation.pas b/X2UtElevation.pas index d749888..bc53f72 100644 --- a/X2UtElevation.pas +++ b/X2UtElevation.pas @@ -336,11 +336,11 @@ begin end; except on E: Exception do - {$IFDEF VER230} + {$IF CompilerVersion >= 23} raise EOleRegistrationError.Create(E.Message, 0, 0); {$ELSE} raise EOleRegistrationError.Create(E.Message); - {$ENDIF} + {$IFEND} end; end; diff --git a/X2UtService.GUIContext.Form.dfm b/X2UtService.GUIContext.Form.dfm index b0cf4a8..5bcdc8d 100644 --- a/X2UtService.GUIContext.Form.dfm +++ b/X2UtService.GUIContext.Form.dfm @@ -1,132 +1,132 @@ -object X2ServiceContextGUIForm: TX2ServiceContextGUIForm - Left = 0 - Top = 0 - BorderIcons = [biSystemMenu, biMinimize] - BorderStyle = bsSingle - Caption = 'X2ServiceContextGUIForm' - ClientHeight = 204 - ClientWidth = 439 - Color = clBtnFace - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'Tahoma' - Font.Style = [] - OldCreateOrder = False - Position = poScreenCenter - OnCloseQuery = FormCloseQuery - OnCreate = FormCreate - DesignSize = ( - 439 - 204) - PixelsPerInch = 96 - TextHeight = 13 - object btnClose: TButton - Left = 8 - Top = 171 - Width = 75 - Height = 25 - Anchors = [akLeft, akBottom] - Caption = '&Close' - TabOrder = 0 - OnClick = btnCloseClick - end - object gbStatus: TGroupBox - AlignWithMargins = True - Left = 8 - Top = 8 - Width = 423 - Height = 57 - Margins.Left = 8 - Margins.Top = 8 - Margins.Right = 8 - Margins.Bottom = 0 - Align = alTop - Caption = ' Status ' - TabOrder = 1 - ExplicitWidth = 358 - object lblStatus: TLabel - Left = 34 - Top = 26 - Width = 50 - Height = 13 - Caption = 'Starting...' - end - object shpStatus: TShape - Left = 12 - Top = 24 - Width = 16 - Height = 16 - Brush.Color = 33023 - Shape = stCircle - end - end - object gbCustomControl: TGroupBox - AlignWithMargins = True - Left = 8 - Top = 73 - Width = 423 - Height = 88 - Margins.Left = 8 - Margins.Top = 8 - Margins.Right = 8 - Margins.Bottom = 0 - Align = alTop - Caption = ' Custom control ' - TabOrder = 2 - ExplicitWidth = 358 - DesignSize = ( - 423 - 88) - object lblControlCode: TLabel - Left = 12 - Top = 27 - Width = 25 - Height = 13 - Caption = 'Code' - end - object edtControlCode: TEdit - Left = 72 - Top = 24 - Width = 256 - Height = 21 - Anchors = [akLeft, akTop, akRight] - TabOrder = 0 - Text = '128' - OnChange = edtControlCodeChange - ExplicitWidth = 191 - end - object btnSend: TButton - Left = 334 - Top = 24 - Width = 75 - Height = 21 - Anchors = [akTop, akRight] - Caption = '&Send' - TabOrder = 1 - OnClick = btnSendClick - ExplicitLeft = 269 - end - object cmbControlCodePredefined: TComboBox - Left = 72 - Top = 51 - Width = 256 - Height = 21 - Style = csDropDownList - Anchors = [akLeft, akTop, akRight] - TabOrder = 2 - ExplicitWidth = 220 - end - object btnSendPredefined: TButton - Left = 334 - Top = 51 - Width = 75 - Height = 21 - Anchors = [akTop, akRight] - Caption = '&Send' - TabOrder = 3 - OnClick = btnSendPredefinedClick - ExplicitLeft = 269 - end - end -end +object X2ServiceContextGUIForm: TX2ServiceContextGUIForm + Left = 0 + Top = 0 + BorderIcons = [biSystemMenu, biMinimize] + BorderStyle = bsSingle + Caption = 'X2ServiceContextGUIForm' + ClientHeight = 204 + ClientWidth = 439 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + OldCreateOrder = False + Position = poScreenCenter + OnCloseQuery = FormCloseQuery + OnCreate = FormCreate + DesignSize = ( + 439 + 204) + PixelsPerInch = 96 + TextHeight = 13 + object btnClose: TButton + Left = 8 + Top = 171 + Width = 75 + Height = 25 + Anchors = [akLeft, akBottom] + Caption = '&Close' + TabOrder = 0 + OnClick = btnCloseClick + end + object gbStatus: TGroupBox + AlignWithMargins = True + Left = 8 + Top = 8 + Width = 423 + Height = 57 + Margins.Left = 8 + Margins.Top = 8 + Margins.Right = 8 + Margins.Bottom = 0 + Align = alTop + Caption = ' Status ' + TabOrder = 1 + ExplicitWidth = 358 + object lblStatus: TLabel + Left = 34 + Top = 26 + Width = 50 + Height = 13 + Caption = 'Starting...' + end + object shpStatus: TShape + Left = 12 + Top = 24 + Width = 16 + Height = 16 + Brush.Color = 33023 + Shape = stCircle + end + end + object gbCustomControl: TGroupBox + AlignWithMargins = True + Left = 8 + Top = 73 + Width = 423 + Height = 88 + Margins.Left = 8 + Margins.Top = 8 + Margins.Right = 8 + Margins.Bottom = 0 + Align = alTop + Caption = ' Custom control ' + TabOrder = 2 + ExplicitWidth = 358 + DesignSize = ( + 423 + 88) + object lblControlCode: TLabel + Left = 12 + Top = 27 + Width = 25 + Height = 13 + Caption = 'Code' + end + object edtControlCode: TEdit + Left = 72 + Top = 24 + Width = 256 + Height = 21 + Anchors = [akLeft, akTop, akRight] + TabOrder = 0 + Text = '128' + OnChange = edtControlCodeChange + ExplicitWidth = 191 + end + object btnSend: TButton + Left = 334 + Top = 24 + Width = 75 + Height = 21 + Anchors = [akTop, akRight] + Caption = '&Send' + TabOrder = 1 + OnClick = btnSendClick + ExplicitLeft = 269 + end + object cmbControlCodePredefined: TComboBox + Left = 72 + Top = 51 + Width = 256 + Height = 21 + Style = csDropDownList + Anchors = [akLeft, akTop, akRight] + TabOrder = 2 + ExplicitWidth = 220 + end + object btnSendPredefined: TButton + Left = 334 + Top = 51 + Width = 75 + Height = 21 + Anchors = [akTop, akRight] + Caption = '&Send' + TabOrder = 3 + OnClick = btnSendPredefinedClick + ExplicitLeft = 269 + end + end +end diff --git a/X2UtService.GUIContext.Form.pas b/X2UtService.GUIContext.Form.pas index 8821114..00a23a2 100644 --- a/X2UtService.GUIContext.Form.pas +++ b/X2UtService.GUIContext.Form.pas @@ -1,342 +1,342 @@ -unit X2UtService.GUIContext.Form; - -interface -uses - System.Classes, - Vcl.Controls, - Vcl.ExtCtrls, - Vcl.Forms, - Vcl.Graphics, - Vcl.StdCtrls, - Winapi.Messages, - - X2UtService.Intf; - - -type - TX2ServiceContextGUIForm = class(TForm) - btnClose: TButton; - gbStatus: TGroupBox; - lblStatus: TLabel; - shpStatus: TShape; - gbCustomControl: TGroupBox; - lblControlCode: TLabel; - edtControlCode: TEdit; - btnSend: TButton; - cmbControlCodePredefined: TComboBox; - btnSendPredefined: TButton; - - procedure FormCreate(Sender: TObject); - procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); - procedure edtControlCodeChange(Sender: TObject); - procedure btnSendClick(Sender: TObject); - procedure btnSendPredefinedClick(Sender: TObject); - procedure btnCloseClick(Sender: TObject); - private - FContext: IX2ServiceContext; - FService: IX2Service; - FServiceThread: TThread; - FAllowClose: Boolean; - protected - procedure DoShow; override; - - procedure UpdatePredefinedControlCodes; virtual; - - function GetControlCode: Byte; - procedure SetStatus(const AMessage: string; AColor: TColor); - - property ServiceThread: TThread read FServiceThread; - public - property Context: IX2ServiceContext read FContext write FContext; - property Service: IX2Service read FService write FService; - end; - - -implementation -uses - System.Generics.Collections, - System.Math, - System.SyncObjs, - System.SysUtils, - Winapi.Windows; - - -{$R *.dfm} - - -const - StatusColorStarting = $00B0FFB0; - StatusColorStarted = clGreen; - StatusColorStopping = $008080FF; - StatusColorStopped = clRed; - - -type - TX2ServiceThread = class(TThread) - private - FContext: IX2ServiceContext; - FService: IX2Service; - FWakeEvent: TEvent; - FSendCodeList: TList; - - 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 } -procedure TX2ServiceContextGUIForm.FormCreate(Sender: TObject); -begin - btnClose.Left := (ClientWidth - btnClose.Width) div 2; -end; - - -procedure TX2ServiceContextGUIForm.DoShow; -var - serviceThread: TX2ServiceThread; -begin - inherited DoShow; - - if not Assigned(FServiceThread) then - begin - UpdatePredefinedControlCodes; - - SetStatus('Starting...', StatusColorStarting); - serviceThread := TX2ServiceThread.Create(Context, Service); - serviceThread.OnStarted := - procedure - begin - 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; - - - -procedure TX2ServiceContextGUIForm.edtControlCodeChange(Sender: TObject); -begin - edtControlCode.Text := IntToStr(GetControlCode); -end; - - -procedure TX2ServiceContextGUIForm.btnSendClick(Sender: TObject); -begin - (ServiceThread as TX2ServiceThread).SendControlCode(GetControlCode); -end; - - -procedure TX2ServiceContextGUIForm.btnSendPredefinedClick(Sender: TObject); -var - code: Byte; - -begin - if cmbControlCodePredefined.ItemIndex > -1 then - begin - code := Byte(cmbControlCodePredefined.Items.Objects[cmbControlCodePredefined.ItemIndex]); - (ServiceThread as TX2ServiceThread).SendControlCode(code); - end; -end; - - -procedure TX2ServiceContextGUIForm.btnCloseClick(Sender: TObject); -begin - Close; -end; - - -procedure TX2ServiceContextGUIForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean); -begin - if not FAllowClose then - begin - SetStatus('Stopping...', StatusColorStopping); - CanClose := False; - - ServiceThread.Terminate; - end; -end; - - -procedure TX2ServiceContextGUIForm.UpdatePredefinedControlCodes; -var - serviceCustomControl: IX2ServiceCustomControl; - -begin - cmbControlCodePredefined.Items.Clear; - - if Supports(Service, IX2ServiceCustomControl, serviceCustomControl) then - begin - serviceCustomControl.EnumCustomControlCodes( - procedure(ACode: Byte; const ADescription: string) - begin - cmbControlCodePredefined.Items.AddObject(Format('%s (%d)', [ADescription, ACode]), TObject(ACode)); - end); - - cmbControlCodePredefined.Enabled := True; - cmbControlCodePredefined.ItemIndex := 0; - btnSendPredefined.Enabled := cmbControlCodePredefined.Items.Count > 0; - end else - begin - cmbControlCodePredefined.Enabled := False; - btnSendPredefined.Enabled := False; - end; -end; - - -function TX2ServiceContextGUIForm.GetControlCode: Byte; -begin - Result := Byte(Min(Max(StrToIntDef(edtControlCode.Text, 0), 128), 255)); -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.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. +unit X2UtService.GUIContext.Form; + +interface +uses + System.Classes, + Vcl.Controls, + Vcl.ExtCtrls, + Vcl.Forms, + Vcl.Graphics, + Vcl.StdCtrls, + Winapi.Messages, + + X2UtService.Intf; + + +type + TX2ServiceContextGUIForm = class(TForm) + btnClose: TButton; + gbStatus: TGroupBox; + lblStatus: TLabel; + shpStatus: TShape; + gbCustomControl: TGroupBox; + lblControlCode: TLabel; + edtControlCode: TEdit; + btnSend: TButton; + cmbControlCodePredefined: TComboBox; + btnSendPredefined: TButton; + + procedure FormCreate(Sender: TObject); + procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); + procedure edtControlCodeChange(Sender: TObject); + procedure btnSendClick(Sender: TObject); + procedure btnSendPredefinedClick(Sender: TObject); + procedure btnCloseClick(Sender: TObject); + private + FContext: IX2ServiceContext; + FService: IX2Service; + FServiceThread: TThread; + FAllowClose: Boolean; + protected + procedure DoShow; override; + + procedure UpdatePredefinedControlCodes; virtual; + + function GetControlCode: Byte; + procedure SetStatus(const AMessage: string; AColor: TColor); + + property ServiceThread: TThread read FServiceThread; + public + property Context: IX2ServiceContext read FContext write FContext; + property Service: IX2Service read FService write FService; + end; + + +implementation +uses + System.Generics.Collections, + System.Math, + System.SyncObjs, + System.SysUtils, + Winapi.Windows; + + +{$R *.dfm} + + +const + StatusColorStarting = $00B0FFB0; + StatusColorStarted = clGreen; + StatusColorStopping = $008080FF; + StatusColorStopped = clRed; + + +type + TX2ServiceThread = class(TThread) + private + FContext: IX2ServiceContext; + FService: IX2Service; + FWakeEvent: TEvent; + FSendCodeList: TList; + + 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 } +procedure TX2ServiceContextGUIForm.FormCreate(Sender: TObject); +begin + btnClose.Left := (ClientWidth - btnClose.Width) div 2; +end; + + +procedure TX2ServiceContextGUIForm.DoShow; +var + serviceThread: TX2ServiceThread; +begin + inherited DoShow; + + if not Assigned(FServiceThread) then + begin + UpdatePredefinedControlCodes; + + SetStatus('Starting...', StatusColorStarting); + serviceThread := TX2ServiceThread.Create(Context, Service); + serviceThread.OnStarted := + procedure + begin + 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; + + + +procedure TX2ServiceContextGUIForm.edtControlCodeChange(Sender: TObject); +begin + edtControlCode.Text := IntToStr(GetControlCode); +end; + + +procedure TX2ServiceContextGUIForm.btnSendClick(Sender: TObject); +begin + (ServiceThread as TX2ServiceThread).SendControlCode(GetControlCode); +end; + + +procedure TX2ServiceContextGUIForm.btnSendPredefinedClick(Sender: TObject); +var + code: Byte; + +begin + if cmbControlCodePredefined.ItemIndex > -1 then + begin + code := Byte(cmbControlCodePredefined.Items.Objects[cmbControlCodePredefined.ItemIndex]); + (ServiceThread as TX2ServiceThread).SendControlCode(code); + end; +end; + + +procedure TX2ServiceContextGUIForm.btnCloseClick(Sender: TObject); +begin + Close; +end; + + +procedure TX2ServiceContextGUIForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean); +begin + if not FAllowClose then + begin + SetStatus('Stopping...', StatusColorStopping); + CanClose := False; + + ServiceThread.Terminate; + end; +end; + + +procedure TX2ServiceContextGUIForm.UpdatePredefinedControlCodes; +var + serviceCustomControl: IX2ServiceCustomControl; + +begin + cmbControlCodePredefined.Items.Clear; + + if Supports(Service, IX2ServiceCustomControl, serviceCustomControl) then + begin + serviceCustomControl.EnumCustomControlCodes( + procedure(ACode: Byte; const ADescription: string) + begin + cmbControlCodePredefined.Items.AddObject(Format('%s (%d)', [ADescription, ACode]), TObject(ACode)); + end); + + cmbControlCodePredefined.Enabled := True; + cmbControlCodePredefined.ItemIndex := 0; + btnSendPredefined.Enabled := cmbControlCodePredefined.Items.Count > 0; + end else + begin + cmbControlCodePredefined.Enabled := False; + btnSendPredefined.Enabled := False; + end; +end; + + +function TX2ServiceContextGUIForm.GetControlCode: Byte; +begin + Result := Byte(Min(Max(StrToIntDef(edtControlCode.Text, 0), 128), 255)); +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.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. diff --git a/X2UtService.GUIContext.pas b/X2UtService.GUIContext.pas index 06b22f0..2ed5cd2 100644 --- a/X2UtService.GUIContext.pas +++ b/X2UtService.GUIContext.pas @@ -1,70 +1,70 @@ -unit X2UtService.GUIContext; - -interface -uses - System.Classes, - - X2UtService.Intf; - - -type - TX2ServiceContextGUI = class(TInterfacedObject, IX2ServiceContext, IX2InteractiveServiceContext) - protected - procedure StartService(AService: IX2Service); virtual; - public - constructor Create(AService: IX2Service); - - { IX2ServiceContext } - function GetMode: TX2ServiceMode; - - - { IX2InteractiveServiceContext } - procedure RunInteractive(AProc: TThreadProcedure); - end; - - -implementation -uses - Vcl.Forms, - - X2UtService.GUIContext.Form; - - -{ TX2ServiceContextGUI } -constructor TX2ServiceContextGUI.Create(AService: IX2Service); -begin - inherited Create; - - StartService(AService); -end; - - -function TX2ServiceContextGUI.GetMode: TX2ServiceMode; -begin - Result := smInteractive; -end; - - -procedure TX2ServiceContextGUI.StartService(AService: IX2Service); -var - serviceForm: TX2ServiceContextGUIForm; - -begin - Application.Initialize; - Application.MainFormOnTaskBar := True; - - Application.CreateForm(TX2ServiceContextGUIForm, serviceForm); - serviceForm.Caption := AService.DisplayName; - serviceForm.Context := Self; - serviceForm.Service := AService; - - Application.Run; -end; - - -procedure TX2ServiceContextGUI.RunInteractive(AProc: TThreadProcedure); -begin - TThread.Queue(nil, AProc); -end; - -end. +unit X2UtService.GUIContext; + +interface +uses + System.Classes, + + X2UtService.Intf; + + +type + TX2ServiceContextGUI = class(TInterfacedObject, IX2ServiceContext, IX2InteractiveServiceContext) + protected + procedure StartService(AService: IX2Service); virtual; + public + constructor Create(AService: IX2Service); + + { IX2ServiceContext } + function GetMode: TX2ServiceMode; + + + { IX2InteractiveServiceContext } + procedure RunInteractive(AProc: TThreadProcedure); + end; + + +implementation +uses + Vcl.Forms, + + X2UtService.GUIContext.Form; + + +{ TX2ServiceContextGUI } +constructor TX2ServiceContextGUI.Create(AService: IX2Service); +begin + inherited Create; + + StartService(AService); +end; + + +function TX2ServiceContextGUI.GetMode: TX2ServiceMode; +begin + Result := smInteractive; +end; + + +procedure TX2ServiceContextGUI.StartService(AService: IX2Service); +var + serviceForm: TX2ServiceContextGUIForm; + +begin + Application.Initialize; + Application.MainFormOnTaskBar := True; + + Application.CreateForm(TX2ServiceContextGUIForm, serviceForm); + serviceForm.Caption := AService.DisplayName; + serviceForm.Context := Self; + serviceForm.Service := AService; + + Application.Run; +end; + + +procedure TX2ServiceContextGUI.RunInteractive(AProc: TThreadProcedure); +begin + TThread.Queue(nil, AProc); +end; + +end. diff --git a/X2UtService.Intf.pas b/X2UtService.Intf.pas index a3781e4..5446dc8 100644 --- a/X2UtService.Intf.pas +++ b/X2UtService.Intf.pas @@ -1,102 +1,102 @@ -unit X2UtService.Intf; - -interface -uses - System.Classes, - System.SysUtils; - - -type - TX2ServiceMode = (smService, smInteractive); - - - IX2ServiceContext = interface - ['{0AC283A7-B46C-4E4E-8F36-F8AA1272E04B}'] - function GetMode: TX2ServiceMode; - - property Mode: TX2ServiceMode read GetMode; - end; - - - IX2InteractiveServiceContext = interface(IX2ServiceContext) - ['{82E69997-013D-4349-8060-B9F31B72CDF4}'] - procedure RunInteractive(AProc: TThreadProcedure); - 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; - - - - TX2ServiceCustomControlProc = reference to procedure(ACode: Byte; const ADescription: string); - - { Implement this to enable discovery of supported custom control codes - for use in interactive contexts. } - IX2ServiceCustomControl = interface - ['{D6363AC5-3DD5-4897-90A7-6F63D82B6A74}'] - procedure EnumCustomControlCodes(Yield: TX2ServiceCustomControlProc); - 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; - Result := True; -end; - - -function TX2CustomService.Stop: Boolean; -begin - FContext := nil; - Result := True; -end; - - -function TX2CustomService.DoCustomControl(ACode: Byte): Boolean; -begin - Result := True; -end; - -end. +unit X2UtService.Intf; + +interface +uses + System.Classes, + System.SysUtils; + + +type + TX2ServiceMode = (smService, smInteractive); + + + IX2ServiceContext = interface + ['{0AC283A7-B46C-4E4E-8F36-F8AA1272E04B}'] + function GetMode: TX2ServiceMode; + + property Mode: TX2ServiceMode read GetMode; + end; + + + IX2InteractiveServiceContext = interface(IX2ServiceContext) + ['{82E69997-013D-4349-8060-B9F31B72CDF4}'] + procedure RunInteractive(AProc: TThreadProcedure); + 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; + + + + TX2ServiceCustomControlProc = reference to procedure(ACode: Byte; const ADescription: string); + + { Implement this to enable discovery of supported custom control codes + for use in interactive contexts. } + IX2ServiceCustomControl = interface + ['{D6363AC5-3DD5-4897-90A7-6F63D82B6A74}'] + procedure EnumCustomControlCodes(Yield: TX2ServiceCustomControlProc); + 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; + Result := True; +end; + + +function TX2CustomService.Stop: Boolean; +begin + FContext := nil; + Result := True; +end; + + +function TX2CustomService.DoCustomControl(ACode: Byte): Boolean; +begin + Result := True; +end; + +end. diff --git a/X2UtService.ServiceContext.pas b/X2UtService.ServiceContext.pas index a1a8ce9..a11ce5d 100644 --- a/X2UtService.ServiceContext.pas +++ b/X2UtService.ServiceContext.pas @@ -1,146 +1,146 @@ -unit X2UtService.ServiceContext; - -interface -uses - X2UtService.Intf; - - -type - TX2ServiceContextService = class(TInterfacedObject, IX2ServiceContext) - protected - procedure StartService(AService: IX2Service); virtual; - public - class function IsInstallUninstall: Boolean; - - constructor Create(AService: IX2Service); - - { IX2ServiceContext } - function GetMode: TX2ServiceMode; - end; - - -implementation -uses - System.Classes, - System.SysUtils, - Vcl.SvcMgr, - - X2UtElevation; - - -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 } -class function TX2ServiceContextService.IsInstallUninstall: Boolean; -begin - Result := FindCmdLineSwitch('install', ['-', '/'], True) or - FindCmdLineSwitch('uninstall', ['-', '/'], True); -end; - - -constructor TX2ServiceContextService.Create(AService: IX2Service); -begin - inherited Create; - - if IsInstallUninstall and (not IsElevated) then - raise Exception.Create('Elevation is required for install or uninstall'); - - StartService(AService); -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 := AService.DisplayName; - ServiceModuleInstance.Name := AService.ServiceName; - - Application.Run; - finally - ServiceModuleInstance := nil; - end; -end; - - -{ TX2ServiceModule } -constructor TX2ServiceModule.Create(AOwner: TComponent; AContext: IX2ServiceContext; AService: IX2Service); -begin - // Skip default constructor to prevent DFM streaming - CreateNew(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. +unit X2UtService.ServiceContext; + +interface +uses + X2UtService.Intf; + + +type + TX2ServiceContextService = class(TInterfacedObject, IX2ServiceContext) + protected + procedure StartService(AService: IX2Service); virtual; + public + class function IsInstallUninstall: Boolean; + + constructor Create(AService: IX2Service); + + { IX2ServiceContext } + function GetMode: TX2ServiceMode; + end; + + +implementation +uses + System.Classes, + System.SysUtils, + Vcl.SvcMgr, + + X2UtElevation; + + +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 } +class function TX2ServiceContextService.IsInstallUninstall: Boolean; +begin + Result := FindCmdLineSwitch('install', ['-', '/'], True) or + FindCmdLineSwitch('uninstall', ['-', '/'], True); +end; + + +constructor TX2ServiceContextService.Create(AService: IX2Service); +begin + inherited Create; + + if IsInstallUninstall and (not IsElevated) then + raise Exception.Create('Elevation is required for install or uninstall'); + + StartService(AService); +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 := AService.DisplayName; + ServiceModuleInstance.Name := AService.ServiceName; + + Application.Run; + finally + ServiceModuleInstance := nil; + end; +end; + + +{ TX2ServiceModule } +constructor TX2ServiceModule.Create(AOwner: TComponent; AContext: IX2ServiceContext; AService: IX2Service); +begin + // Skip default constructor to prevent DFM streaming + CreateNew(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. diff --git a/X2UtService.pas b/X2UtService.pas index 4942ed2..6c46535 100644 --- a/X2UtService.pas +++ b/X2UtService.pas @@ -1,62 +1,62 @@ -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 TX2ServiceContextService.IsInstallUninstall or (not IsUserInteractive) then - Result := TX2ServiceContextService.Create(AService) - else - Result := TX2ServiceContextGUI.Create(AService); -end; - -end. +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 TX2ServiceContextService.IsInstallUninstall or (not IsUserInteractive) then + Result := TX2ServiceContextService.Create(AService) + else + Result := TX2ServiceContextGUI.Create(AService); +end; + +end.