added new inno setup config

This commit is contained in:
Shreyas Zare
2021-03-13 13:31:33 +05:30
parent c346e553e8
commit 09ebfa260f
8 changed files with 656 additions and 0 deletions

View File

@@ -0,0 +1,113 @@
; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#define MyAppName "Technitium DNS Server"
#define MyAppVersion "6.0"
#define MyAppPublisher "Technitium"
#define MyAppURL "https://technitium.com/dns/"
#define MyAppExeName "DnsServerSystemTrayApp.exe"
[Setup]
; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{1052DB5E-35BD-4F67-89CD-1F45A1688E77}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
VersionInfoVersion=2.0.0.0
VersionInfoCopyright="Copyright (C) 2021 Technitium"
DefaultDirName={commonpf32}\Technitium\DNS Server
DefaultGroupName={#MyAppName}
DisableProgramGroupPage=yes
PrivilegesRequired=admin
OutputDir=.\Release
OutputBaseFilename=DnsServerSetup
SetupIconFile=.\logo.ico
WizardSmallImageFile=.\logo.bmp
Compression=lzma
SolidCompression=yes
WizardStyle=modern
UninstallDisplayIcon={app}\{#MyAppExeName}
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}";
[Files]
Source: ".\publish\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
Source: ".\publish\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
[Icons]
Name: "{group}\DNS Server App"; Filename: "{app}\{#MyAppExeName}"
Name: "{group}\Dashboard"; Filename: "http://localhost:5380/"
Name: "{group}\{cm:ProgramOnTheWeb,{#MyAppName}}"; Filename: "{#MyAppURL}"
Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"
Name: "{autodesktop}\DNS Server App"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
[Run]
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange("DNS Server App", '&', '&&')}}"; Flags: nowait postinstall skipifsilent
#include "helper.iss"
#include "legacy.iss"
#include "dotnet.iss"
#include "appinstall.iss"
[Code]
{
Skips the tasks page if it is an upgrade install
}
function ShouldSkipPage(PageID: Integer): Boolean;
begin
Result := ((PageID = wpSelectTasks) or (PageID = wpSelectDir)) and (IsLegacyInstallerInstalled or IsUpgrade);
end;
function InitializeSetup: Boolean;
begin
CheckDotnetDependency;
Result := true;
end;
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssInstall then begin //Step happens just before installing files
WizardForm.StatusLabel.Caption := 'Stopping Tray App...';
KillTrayApp(); //Stop the tray app if running
if IsLegacyInstallerInstalled then
begin
WizardForm.StatusLabel.Caption := 'Stopping Service...';
DoStopService(); //Stop the service if running
WizardForm.StatusLabel.Caption := 'Removing Legacy Installer...';
UninstallLegacyInstaller(); //Uninstall Legacy Installer if Installed already
end else
begin
WizardForm.StatusLabel.Caption := 'Uninstalling Service...';
DoRemoveService(); //Stop and remove the service if installed
end;
end;
if CurStep = ssPostInstall then begin //Step happens just after installing files
WizardForm.StatusLabel.Caption := 'Installing Service...';
DoInstallService(); //Install service after all files installed, if not a portable install
end;
end;
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
if CurUninstallStep = usUninstall then //Step happens before processing uninstall log
begin
UninstallProgressForm.StatusLabel.Caption := 'Stopping Tray App...';
KillTrayApp(); //Stop the tray app if running
UninstallProgressForm.StatusLabel.Caption := 'Uninstalling Service...';
DoRemoveService(); //Stop and remove the service
end;
end;

View File

@@ -0,0 +1,133 @@
#include "service.iss"
#define SERVICE_NAME "DnsService"
#define SERVICE_FILE "DnsService.exe"
#define SERVICE_DISPLAY_NAME "Technitium DNS Server"
#define SERVICE_DESCRIPTION "Technitium DNS Server"
#define TRAYAPP_FILENAME "DnsServerSystemTrayApp.exe"
[Code]
{
Kills the tray app
}
procedure KillTrayApp;
begin
TaskKill('{#TRAYAPP_FILENAME}');
end;
{
Stops the service
}
procedure DoStopService();
var
stopCounter: Integer;
begin
stopCounter := 0;
if IsServiceInstalled('{#SERVICE_NAME}') then begin
Log('Service: Already installed');
if IsServiceRunning('{#SERVICE_NAME}') then begin
Log('Service: Already running, stopping service...');
StopService('{#SERVICE_NAME}');
while IsServiceRunning('{#SERVICE_NAME}') do
begin
if stopCounter > 2 then begin
Log('Service: Waited too long to stop, killing task...');
TaskKill('{#SERVICE_FILE}');
Log('Service: Task killed');
break;
end else begin
Log('Service: Waiting for stop');
Sleep(2000);
stopCounter := stopCounter + 1
end;
end;
if stopCounter < 3 then Log('Service: Stopped');
end;
end;
end;
{
Removes the service from the computer
}
procedure DoRemoveService();
var
stopCounter: Integer;
begin
stopCounter := 0;
if IsServiceInstalled('{#SERVICE_NAME}') then begin
Log('Service: Already installed, begin remove...');
if IsServiceRunning('{#SERVICE_NAME}') then begin
Log('Service: Already running, stopping...');
StopService('{#SERVICE_NAME}');
while IsServiceRunning('{#SERVICE_NAME}') do
begin
if stopCounter > 2 then begin
Log('Service: Waited too long to stop, killing task...');
TaskKill('{#SERVICE_FILE}');
Log('Service: Task killed');
break;
end else begin
Log('Service: Waiting for stop');
Sleep(5000);
stopCounter := stopCounter + 1
end;
end;
end;
stopCounter := 0;
Log('Service: Removing...');
RemoveService('{#SERVICE_NAME}');
while IsServiceInstalled('{#SERVICE_NAME}') do
begin
if stopCounter > 2 then begin
Log('Service: Waited too long to remove, continuing');
break;
end else begin
Log('Service: Waiting for removal');
Sleep(5000);
stopCounter := stopCounter + 1
end;
end;
if stopCounter < 3 then Log('Service: Removed');
end;
end;
{
Installs the service onto the computer
}
procedure DoInstallService();
var
InstallSuccess: Boolean;
stopCounter: Integer;
begin
stopCounter := 0;
if IsServiceInstalled('{#SERVICE_NAME}') then begin
Log('Service: Already installed, skip install service');
end else begin
Log('Service: Begin Install');
InstallSuccess := InstallService(ExpandConstant('{app}\DnsService.exe'), '{#SERVICE_NAME}', '{#SERVICE_DISPLAY_NAME}', '{#SERVICE_DESCRIPTION}', SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START);
if not InstallSuccess then
begin
Log('Service: Install Fail ' + ServiceErrorToMessage(GetLastError()));
SuppressibleMsgBox(ExpandConstant('{cm:ServiceInstallFailure,' + ServiceErrorToMessage(GetLastError()) + '}'), mbCriticalError, MB_OK, IDOK);
end else begin
Log('Service: Install Success, Starting...');
StartService('{#SERVICE_NAME}');
while IsServiceRunning('{#SERVICE_NAME}') <> true do
begin
if stopCounter > 3 then begin
Log('Service: Waited too long to start, continue');
break;
end else begin
Log('Service: still starting')
Sleep(5000);
stopCounter := stopCounter + 1
end;
end;
if stopCounter < 4 then Log('Service: Started');
end;
end;
end;

View File

@@ -0,0 +1,332 @@
[Setup]
MinVersion=6.2
// remove next line if you only deploy 32-bit binaries and dependencies
ArchitecturesInstallIn64BitMode=x64
// dependency installation requires ready page and ready memo to be enabled (default behaviour)
DisableReadyPage=no
DisableReadyMemo=no
// shared code for installing the dependencies
[Code]
// types and variables
type
TDependency = record
Filename: String;
Parameters: String;
Title: String;
URL: String;
Checksum: String;
ForceSuccess: Boolean;
InstallClean: Boolean;
RebootAfter: Boolean;
end;
InstallResult = (InstallSuccessful, InstallRebootRequired, InstallError);
var
MemoInstallInfo: String;
Dependencies: array of TDependency;
DelayedReboot, ForceX86: Boolean;
DownloadPage: TDownloadWizardPage;
procedure AddDependency(const Filename, Parameters, Title, URL, Checksum: String; const ForceSuccess, InstallClean, RebootAfter: Boolean);
var
Dependency: TDependency;
I: Integer;
begin
MemoInstallInfo := MemoInstallInfo + #13#10 + '%1' + Title;
Dependency.Filename := Filename;
Dependency.Parameters := Parameters;
Dependency.Title := Title;
if FileExists(ExpandConstant('{tmp}{\}') + Filename) then begin
Dependency.URL := '';
end else begin
Dependency.URL := URL;
end;
Dependency.Checksum := Checksum;
Dependency.ForceSuccess := ForceSuccess;
Dependency.InstallClean := InstallClean;
Dependency.RebootAfter := RebootAfter;
I := GetArrayLength(Dependencies);
SetArrayLength(Dependencies, I + 1);
Dependencies[I] := Dependency;
end;
function IsPendingReboot: Boolean;
var
Value: String;
begin
Result := RegQueryMultiStringValue(HKEY_LOCAL_MACHINE, 'SYSTEM\CurrentControlSet\Control\Session Manager', 'PendingFileRenameOperations', Value) or
(RegQueryMultiStringValue(HKEY_LOCAL_MACHINE, 'SYSTEM\CurrentControlSet\Control\Session Manager', 'SetupExecute', Value) and (Value <> ''));
end;
function InstallProducts: InstallResult;
var
ResultCode, I, ProductCount: Integer;
begin
Result := InstallSuccessful;
ProductCount := GetArrayLength(Dependencies);
MemoInstallInfo := SetupMessage(msgReadyMemoTasks);
if ProductCount > 0 then begin
DownloadPage.Show;
for I := 0 to ProductCount - 1 do begin
if Dependencies[I].InstallClean and (DelayedReboot or IsPendingReboot) then begin
Result := InstallRebootRequired;
break;
end;
DownloadPage.SetText(Dependencies[I].Title, '');
DownloadPage.SetProgress(I + 1, ProductCount);
while True do begin
ResultCode := 0;
if ShellExec('', ExpandConstant('{tmp}{\}') + Dependencies[I].Filename, Dependencies[I].Parameters, '', SW_SHOWNORMAL, ewWaitUntilTerminated, ResultCode) then begin
if Dependencies[I].RebootAfter then begin
// delay reboot after install if we installed the last dependency anyways
if I = ProductCount - 1 then begin
DelayedReboot := True;
end else begin
Result := InstallRebootRequired;
MemoInstallInfo := Dependencies[I].Title;
end;
break;
end else if (ResultCode = 0) or Dependencies[I].ForceSuccess then begin
break;
end else if ResultCode = 3010 then begin
// Windows Installer ResultCode 3010: ERROR_SUCCESS_REBOOT_REQUIRED
DelayedReboot := True;
break;
end;
end;
case SuppressibleMsgBox(FmtMessage(SetupMessage(msgErrorFunctionFailed), [Dependencies[I].Title, IntToStr(ResultCode)]), mbError, MB_ABORTRETRYIGNORE, IDIGNORE) of
IDABORT: begin
Result := InstallError;
MemoInstallInfo := MemoInstallInfo + #13#10 + ' ' + Dependencies[I].Title;
break;
end;
IDIGNORE: begin
MemoInstallInfo := MemoInstallInfo + #13#10 + ' ' + Dependencies[I].Title;
break;
end;
end;
end;
if Result <> InstallSuccessful then begin
break;
end;
end;
DownloadPage.Hide;
end;
end;
// Inno Setup event functions
procedure InitializeWizard;
begin
DownloadPage := CreateDownloadPage(SetupMessage(msgWizardPreparing), SetupMessage(msgPreparingDesc), nil);
end;
function PrepareToInstall(var NeedsRestart: Boolean): String;
begin
DelayedReboot := False;
case InstallProducts of
InstallError: begin
Result := MemoInstallInfo;
end;
InstallRebootRequired: begin
Result := MemoInstallInfo;
NeedsRestart := True;
// write into the registry that the installer needs to be executed again after restart
RegWriteStringValue(HKEY_CURRENT_USER, 'SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce', 'InstallBootstrap', ExpandConstant('{srcexe}'));
end;
end;
end;
function NeedRestart: Boolean;
begin
Result := DelayedReboot;
end;
function UpdateReadyMemo(const Space, NewLine, MemoUserInfoInfo, MemoDirInfo, MemoTypeInfo, MemoComponentsInfo, MemoGroupInfo, MemoTasksInfo: String): String;
begin
Result := '';
if MemoUserInfoInfo <> '' then begin
Result := Result + MemoUserInfoInfo + Newline + NewLine;
end;
if MemoDirInfo <> '' then begin
Result := Result + MemoDirInfo + Newline + NewLine;
end;
if MemoTypeInfo <> '' then begin
Result := Result + MemoTypeInfo + Newline + NewLine;
end;
if MemoComponentsInfo <> '' then begin
Result := Result + MemoComponentsInfo + Newline + NewLine;
end;
if MemoGroupInfo <> '' then begin
Result := Result + MemoGroupInfo + Newline + NewLine;
end;
if MemoTasksInfo <> '' then begin
Result := Result + MemoTasksInfo;
end;
if MemoInstallInfo <> '' then begin
if MemoTasksInfo = '' then begin
Result := Result + SetupMessage(msgReadyMemoTasks);
end;
Result := Result + FmtMessage(MemoInstallInfo, [Space]);
end;
end;
function NextButtonClick(const CurPageID: Integer): Boolean;
var
I, ProductCount: Integer;
Retry: Boolean;
begin
Result := True;
if (CurPageID = wpReady) and (MemoInstallInfo <> '') then begin
DownloadPage.Show;
ProductCount := GetArrayLength(Dependencies);
for I := 0 to ProductCount - 1 do begin
if Dependencies[I].URL <> '' then begin
DownloadPage.Clear;
DownloadPage.Add(Dependencies[I].URL, Dependencies[I].Filename, Dependencies[I].Checksum);
Retry := True;
while Retry do begin
Retry := False;
try
DownloadPage.Download;
except
if GetExceptionMessage = SetupMessage(msgErrorDownloadAborted) then begin
Result := False;
I := ProductCount;
end else begin
case SuppressibleMsgBox(AddPeriod(GetExceptionMessage), mbError, MB_ABORTRETRYIGNORE, IDIGNORE) of
IDABORT: begin
Result := False;
I := ProductCount;
end;
IDRETRY: begin
Retry := True;
end;
end;
end;
end;
end;
end;
end;
DownloadPage.Hide;
end;
end;
// architecture helper functions
function IsX64: Boolean;
begin
Result := not ForceX86 and Is64BitInstallMode;
end;
function GetString(const x86, x64: String): String;
begin
if IsX64 then begin
Result := x64;
end else begin
Result := x86;
end;
end;
function GetArchitectureSuffix: String;
begin
Result := GetString('', '_x64');
end;
function GetArchitectureTitle: String;
begin
Result := GetString(' (x86)', ' (x64)');
end;
function CompareVersion(const Version1, Version2: String): Integer;
var
Position, Number1, Number2: Integer;
begin
Result := 0;
while (Version1 <> '') or (Version2 <> '') do begin
Position := Pos('.', Version1);
if Position > 0 then begin
Number1 := StrToIntDef(Copy(Version1, 1, Position - 1), 0);
Delete(Version1, 1, Position);
end else if Version1 <> '' then begin
Number1 := StrToIntDef(Version1, 0);
Version1 := '';
end else begin
Number1 := 0;
end;
Position := Pos('.', Version2);
if Position > 0 then begin
Number2 := StrToIntDef(Copy(Version2, 1, Position - 1), 0);
Delete(Version2, 1, Position);
end else if Version2 <> '' then begin
Number2 := StrToIntDef(Version2, 0);
Version2 := '';
end else begin
Number2 := 0;
end;
if Number1 < Number2 then begin
Result := -1;
break;
end else if Number1 > Number2 then begin
Result := 1;
break;
end;
end;
end;
{ Check if dotnet5 is installed }
function IsDotNet5DesktopInstalled: Boolean;
var
ResultCode: Integer;
begin
Result := false;
Exec('cmd.exe', '/c dotnet --list-runtimes | find /n "Microsoft.WindowsDesktop.App 5."', '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
if ResultCode = 0 then
begin
Result := true;
end;
end;
{ if dotnet5 is not installed then add it for download }
procedure CheckDotnetDependency;
begin
if not IsDotNet5DesktopInstalled then
begin
AddDependency('dotnet50desktop' + GetArchitectureSuffix + '.exe',
'/lcid ' + IntToStr(GetUILanguage) + ' /passive /norestart',
'.NET Desktop Runtime 5.0.3' + GetArchitectureTitle,
GetString('https://go.microsoft.com/fwlink/?linkid=2155347', 'https://go.microsoft.com/fwlink/?linkid=2155258'),
'', False, False, False);
end;
end;

View File

@@ -0,0 +1,40 @@
[Code]
{
Helper functions
}
{
Checks to see if the installer is an 'upgrade'
}
function IsUpgrade: Boolean;
var
Value: string;
UninstallKey: string;
begin
UninstallKey := 'Software\Microsoft\Windows\CurrentVersion\Uninstall\' +
ExpandConstant('{#SetupSetting("AppId")}') + '_is1';
Result := (RegQueryStringValue(HKLM, UninstallKey, 'UninstallString', Value) or
RegQueryStringValue(HKCU, UninstallKey, 'UninstallString', Value)) and (Value <> '');
end;
{
Kills a running program by its filename
}
procedure TaskKill(fileName: String);
var
ResultCode: Integer;
begin
Exec(ExpandConstant('taskkill.exe'), '/f /im ' + '"' + fileName + '"', '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
end;
{
Executes the MSI Uninstall by GUID functionality
}
function MsiExecUnins(appId: String): Integer;
var
ResultCode: Integer;
begin
ShellExec('', 'msiexec.exe', '/x ' + appId + ' /norestart /qb', '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
Result := ResultCode;
end;

View File

@@ -0,0 +1,36 @@
#define LEGACY_INSTALLER_APPID "{9B86AC7F-53B3-4E31-B245-D4602D16F5C8}"
[Code]
{
Legacy Installer Functionality
}
{
Checks if the MSI Installer is installed
}
function IsLegacyInstallerInstalled: Boolean;
var
Value: string;
UninstallKey1, UninstallKey2: string;
begin
UninstallKey1 := 'Software\Microsoft\Windows\CurrentVersion\Uninstall\{#LEGACY_INSTALLER_APPID}';
UninstallKey2 := 'SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{#LEGACY_INSTALLER_APPID}';
Result := (
RegQueryStringValue(HKLM, UninstallKey1, 'UninstallString', Value) or
RegQueryStringValue(HKCU, UninstallKey1, 'UninstallString', Value) or
RegQueryStringValue(HKLM, UninstallKey2, 'UninstallString', Value)
) and (Value <> '');
end;
{
Uninstalls Legacy Installer
}
procedure UninstallLegacyInstaller;
var
ResultCode: Integer;
begin
Log('Uninstall MSI installer item');
ResultCode := MsiExecUnins('{#LEGACY_INSTALLER_APPID}');
Log('Result code ' + IntToStr(ResultCode));
end;

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

View File

@@ -0,0 +1,226 @@
[Code]
type
SERVICE_STATUS = record
dwServiceType : cardinal;
dwCurrentState : cardinal;
dwControlsAccepted : cardinal;
dwWin32ExitCode : cardinal;
dwServiceSpecificExitCode : cardinal;
dwCheckPoint : cardinal;
dwWaitHint : cardinal;
end;
HANDLE = cardinal;
const
SERVICE_QUERY_CONFIG = $1;
SERVICE_CHANGE_CONFIG = $2;
SERVICE_QUERY_STATUS = $4;
SERVICE_START = $10;
SERVICE_STOP = $20;
SERVICE_ALL_ACCESS = $f01ff;
SC_MANAGER_ALL_ACCESS = $f003f;
SERVICE_WIN32_OWN_PROCESS = $10;
SERVICE_WIN32_SHARE_PROCESS = $20;
SERVICE_WIN32 = $30;
SERVICE_INTERACTIVE_PROCESS = $100;
SERVICE_BOOT_START = $0;
SERVICE_SYSTEM_START = $1;
SERVICE_AUTO_START = $2;
SERVICE_DEMAND_START = $3;
SERVICE_DISABLED = $4;
SERVICE_DELETE = $10000;
SERVICE_CONTROL_STOP = $1;
SERVICE_CONTROL_PAUSE = $2;
SERVICE_CONTROL_CONTINUE = $3;
SERVICE_CONTROL_INTERROGATE = $4;
SERVICE_STOPPED = $1;
SERVICE_START_PENDING = $2;
SERVICE_STOP_PENDING = $3;
SERVICE_RUNNING = $4;
SERVICE_CONTINUE_PENDING = $5;
SERVICE_PAUSE_PENDING = $6;
SERVICE_PAUSED = $7;
ERROR_ACCESS_DENIED = 5;
ERROR_CIRCULAR_DEPENDENCY = 1059;
ERROR_DUPLICATE_SERVICE_NAME = 1078;
ERROR_INVALID_HANDLE = 6;
ERROR_INVALID_NAME = 123;
ERROR_INVALID_PARAMETER = 87;
ERROR_INVALID_SERVICE_ACCOUNT = 1057;
ERROR_SERVICE_EXISTS = 1073;
ERROR_SERVICE_MARKED_FOR_DELETE = 1072;
// #######################################################################################
// nt based service utilities
// #######################################################################################
function OpenSCManager(lpMachineName, lpDatabaseName: string; dwDesiredAccess :cardinal): HANDLE;
external 'OpenSCManagerW@advapi32.dll stdcall';
function OpenService(hSCManager :HANDLE;lpServiceName: string; dwDesiredAccess :cardinal): HANDLE;
external 'OpenServiceW@advapi32.dll stdcall';
function CloseServiceHandle(hSCObject :HANDLE): boolean;
external 'CloseServiceHandle@advapi32.dll stdcall';
function CreateService(hSCManager :HANDLE;lpServiceName, lpDisplayName: string;dwDesiredAccess,dwServiceType,dwStartType,dwErrorControl: cardinal;lpBinaryPathName,lpLoadOrderGroup: String; lpdwTagId : cardinal;lpDependencies,lpServiceStartName,lpPassword :string): cardinal;
external 'CreateServiceW@advapi32.dll stdcall';
function DeleteService(hService :HANDLE): boolean;
external 'DeleteService@advapi32.dll stdcall';
function StartNTService(hService :HANDLE;dwNumServiceArgs : cardinal;lpServiceArgVectors : cardinal) : boolean;
external 'StartServiceW@advapi32.dll stdcall';
function ControlService(hService :HANDLE; dwControl :cardinal;var ServiceStatus :SERVICE_STATUS) : boolean;
external 'ControlService@advapi32.dll stdcall';
function QueryServiceStatus(hService :HANDLE;var ServiceStatus :SERVICE_STATUS) : boolean;
external 'QueryServiceStatus@advapi32.dll stdcall';
function QueryServiceStatusEx(hService :HANDLE;ServiceStatus :SERVICE_STATUS) : boolean;
external 'QueryServiceStatus@advapi32.dll stdcall';
function GetLastError(): dword;
external 'GetLastError@kernel32.dll stdcall';
function OpenServiceManager(): HANDLE;
begin
if UsingWinNT() = true then begin
Result := OpenSCManager('', 'ServicesActive', SC_MANAGER_ALL_ACCESS);
if Result = 0 then
MsgBox(ExpandConstant('{cm:ServiceManagerUnavailable}'), mbError, MB_OK);
end
else begin
MsgBox('only nt based systems support services', mbError, MB_OK);
Result := 0;
end
end;
function IsServiceInstalled(ServiceName: string): boolean;
var
hSCM : HANDLE;
hService: HANDLE;
begin
hSCM := OpenServiceManager();
Result := false;
if hSCM <> 0 then begin
hService := OpenService(hSCM, ServiceName, SERVICE_QUERY_CONFIG);
if hService <> 0 then begin
Result := true;
CloseServiceHandle(hService);
end;
CloseServiceHandle(hSCM);
end
end;
function InstallService(FileName, ServiceName, DisplayName, Description: string; ServiceType, StartType: cardinal): boolean;
var
hSCM : HANDLE;
hService: HANDLE;
begin
hSCM := OpenServiceManager();
Result := false;
if hSCM <> 0 then begin
hService := CreateService(hSCM, ServiceName, DisplayName, SERVICE_ALL_ACCESS, ServiceType, StartType, 0, FileName,'', 0, '', '', '');
if hService <> 0 then begin
Result := true;
// Win2K & WinXP supports aditional description text for services
if Description <> '' then
RegWriteStringValue(HKLM,'System\CurrentControlSet\Services\' + ServiceName, 'Description', Description);
CloseServiceHandle(hService);
end;
CloseServiceHandle(hSCM);
end;
end;
function RemoveService(ServiceName: string): boolean;
var
hSCM : HANDLE;
hService: HANDLE;
begin
hSCM := OpenServiceManager();
Result := false;
if hSCM <> 0 then begin
hService := OpenService(hSCM, ServiceName, SERVICE_DELETE);
if hService <> 0 then begin
Result := DeleteService(hService);
CloseServiceHandle(hService);
end;
CloseServiceHandle(hSCM);
end;
end;
function StartService(ServiceName: string): boolean;
var
hSCM : HANDLE;
hService: HANDLE;
begin
hSCM := OpenServiceManager();
Result := false;
if hSCM <> 0 then begin
hService := OpenService(hSCM, ServiceName, SERVICE_START);
if hService <> 0 then begin
Result := StartNTService(hService, 0, 0);
CloseServiceHandle(hService);
end;
CloseServiceHandle(hSCM);
end;
end;
function StopService(ServiceName: string): boolean;
var
hSCM : HANDLE;
hService: HANDLE;
Status : SERVICE_STATUS;
begin
hSCM := OpenServiceManager();
Result := false;
if hSCM <> 0 then begin
hService := OpenService(hSCM, ServiceName, SERVICE_STOP);
if hService <> 0 then begin
Result := ControlService(hService, SERVICE_CONTROL_STOP, Status);
CloseServiceHandle(hService);
end;
CloseServiceHandle(hSCM);
end;
end;
function IsServiceRunning(ServiceName: string): boolean;
var
hSCM : HANDLE;
hService: HANDLE;
Status : SERVICE_STATUS;
begin
hSCM := OpenServiceManager();
Result := false;
if hSCM <> 0 then begin
hService := OpenService(hSCM, ServiceName, SERVICE_QUERY_STATUS);
if hService <> 0 then begin
if QueryServiceStatus(hService, Status) then begin
Result :=(Status.dwCurrentState = SERVICE_RUNNING);
end;
CloseServiceHandle(hService);
end;
CloseServiceHandle(hSCM);
end
end;
function ServiceErrorToMessage(Error: word): string;
begin
case Error of
ERROR_ACCESS_DENIED: Result := 'Access Denied';
ERROR_CIRCULAR_DEPENDENCY: Result := 'Circular Dependency';
ERROR_DUPLICATE_SERVICE_NAME: Result := 'Duplicate Service Name';
ERROR_INVALID_HANDLE: Result := 'Invalid Handle';
ERROR_INVALID_NAME: Result := 'Invalid Name';
ERROR_INVALID_PARAMETER: Result := 'Invalid Parameter';
ERROR_INVALID_SERVICE_ACCOUNT: Result := 'Invalid Service Account';
ERROR_SERVICE_EXISTS: Result := 'Service Exists';
ERROR_SERVICE_MARKED_FOR_DELETE: Result := 'Service Marked For Deletion';
else
Result := 'Unknown error: ' + IntToStr(Error);
end;
end;