I am trying to set a service's failure actions using Inno Setup's Pascal scripting language. I receive the classic "access violation at address..." error. Seems that it is impossible because the language don't have any support to pointers. Any ideas? Here is the code snippet:
type
TScAction = record
aType1 : Longword;
Delay1 : Longword;
aType2 : Longword;
Delay2 : Longword;
aType3 : Longword;
Delay3 : Longword;
end;
type
TServiceFailureActionsA = record
dwResetPeriod : DWORD;
pRebootMsg : String;
pCommand : String;
cActions : DWORD;
saActions : TScAction;
end;
function ChangeServiceConfig2(hService: Longword; dwInfoLevel: Longword; lpInfo: TServiceFailureActionsA): BOOL;
external 'ChangeServiceConfig2A@advapi32.dll stdcall';
procedure SimpleChangeServiceConfig(AService: string);
var
SCMHandle: Longword;
ServiceHandle: Longword;
sfActions: TServiceFailureActionsA;
sActions: TScAction;
begin
try
SCMHandle := OpenSCManager('', '', SC_MANAGER_ALL_ACCESS);
if SCMHandle = 0 then
RaiseException('SimpleChangeServiceConfig@OpenSCManager: ' + AService + ' ' +
SysErrorMessage(DLLGetLastError));
try
ServiceHandle := OpenService(SCMHandle, AService, SERVICE_ALL_ACCESS);
if ServiceHandle = 0 then
RaiseException('SimpleChangeServiceConfig@OpenService: ' + AService + ' ' +
SysErrorMessage(DLLGetLastError));
try
sActions.aType1 := SC_ACTION_RESTART;
sActions.Delay1 := 60000; // First.nDelay: in milliseconds, MMC displayed in minutes
sActions.aType2 := SC_ACTION_RESTART;
sActions.Delay2 := 60000;
sActions.aType3 := SC_ACTION_RESTART;
sActions.Delay3 := 60000;
sfActions.dwResetPeriod := 1; // in seconds, MMC displayes in days
//sfActions.pRebootMsg := null; // reboot message unchanged
//sfActions.pCommand := null; // command line unchanged
sfActions.cActions := 3; // first, second and subsequent failures
sfActions.saActions := sActions;
if not ChangeServiceConfig2(
ServiceHandle, // handle to service
SERVICE_CONFIG_FAILURE_ACTIONS, // change: description
sfActions) // new description
then
RaiseException('SimpleChangeServiceConfig@ChangeServiceConfig2: ' + AService + ' ' +
SysErrorMessage(DLLGetLastError));
finally
if ServiceHandle <> 0 then
CloseServiceHandle(ServiceHandle);
end;
finally
if SCMHandle <> 0 then
CloseServiceHandle(SCMHandle);
end;
except
ShowExceptionMessage;
end;
end;
You have two problems in your script. Like Deanna suggested you have to use the var
keyword in the declaration of the lpInfo
parameter.
Also you need to change the TScAction
type to an array with two elements.
Here is my script that you can include in your Inno Setup script.
const
SERVICE_CONFIG_DELAYED_AUTO_START_INFO = 3; //The lpInfo parameter is a pointer to a SERVICE_DELAYED_AUTO_START_INFO structure.
//Windows Server 2003 and Windows XP: This value is not supported.
SERVICE_CONFIG_DESCRIPTION = 1; //The lpInfo parameter is a pointer to a SERVICE_DESCRIPTION structure.
SERVICE_CONFIG_FAILURE_ACTIONS = 2; //The lpInfo parameter is a pointer to a SERVICE_FAILURE_ACTIONS structure.
//If the service controller handles the SC_ACTION_REBOOT action, the caller must have
// the SE_SHUTDOWN_NAME privilege. For more information, see Running with Special Privileges.
SERVICE_CONFIG_FAILURE_ACTIONS_FLAG = 4; //The lpInfo parameter is a pointer to a SERVICE_FAILURE_ACTIONS_FLAG structure.
//Windows Server 2003 and Windows XP: This value is not supported.
SERVICE_CONFIG_PREFERRED_NODE = 9; //The lpInfo parameter is a pointer to a SERVICE_PREFERRED_NODE_INFO structure.
//Windows Server 2008, Windows Vista, Windows Server 2003, and Windows XP: This value is not supported.
SERVICE_CONFIG_PRESHUTDOWN_INFO = 7; //The lpInfo parameter is a pointer to a SERVICE_PRESHUTDOWN_INFO structure.
//Windows Server 2003 and Windows XP: This value is not supported.
SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO = 6; //The lpInfo parameter is a pointer to a SERVICE_REQUIRED_PRIVILEGES_INFO structure.
//Windows Server 2003 and Windows XP: This value is not supported.
SERVICE_CONFIG_SERVICE_SID_INFO = 5; //The lpInfo parameter is a pointer to a SERVICE_SID_INFO structure.
SERVICE_CONFIG_TRIGGER_INFO = 8; //The lpInfo parameter is a pointer to a SERVICE_TRIGGER_INFO structure.
//This value is not supported by the ANSI version of ChangeServiceConfig2.
//Windows Server 2008, Windows Vista, Windows Server 2003, and Windows XP: This value is not supported until Windows Server 2008 R2.
SC_ACTION_NONE = 0; // No action.
SC_ACTION_REBOOT = 2; // Reboot the computer.
SC_ACTION_RESTART = 1; // Restart the service.
SC_ACTION_RUN_COMMAND = 3; // Run a command.
type
TScAction = record
aType1 : Longword;
Delay1 : Longword;
end;
type
TServiceFailureActionsA = record
dwResetPeriod : DWORD;
pRebootMsg : String;
pCommand : String;
cActions : DWORD;
saActions : array of TScAction;
end;
function ChangeServiceConfig2(
hService: Longword;
dwInfoLevel: Longword;
var lpInfo: TServiceFailureActionsA): BOOL;
external 'ChangeServiceConfig2A@advapi32.dll stdcall';
procedure SimpleChangeServiceConfig(AService: string);
var
SCMHandle: Longword;
ServiceHandle: Longword;
sfActions: TServiceFailureActionsA;
sActions: array of TScAction;
begin
SetArrayLength(sActions ,3);
try
SCMHandle := OpenSCManager('', '', SC_MANAGER_ALL_ACCESS);
if SCMHandle = 0 then
RaiseException('SimpleChangeServiceConfig@OpenSCManager: ' + AService + ' ' +
SysErrorMessage(DLLGetLastError));
try
ServiceHandle := OpenService(SCMHandle, AService, SERVICE_ALL_ACCESS);
if ServiceHandle = 0 then
RaiseException('SimpleChangeServiceConfig@OpenService: ' + AService + ' ' +
SysErrorMessage(DLLGetLastError));
try
sActions[0].aType1 := SC_ACTION_RESTART;
sActions[0].Delay1 := 60000; // First.nDelay: in milliseconds, MMC displayed in minutes
sActions[1].aType1 := SC_ACTION_RESTART;
sActions[1].Delay1 := 60000;
sActions[2].aType1 := SC_ACTION_NONE;
sActions[2].Delay1 := 60000;
sfActions.dwResetPeriod := 1; // in seconds, MMC displayes in days
//sfActions.pRebootMsg := null; // reboot message unchanged
//sfActions.pCommand := null; // command line unchanged
sfActions.cActions := 3; // first, second and subsequent failures
sfActions.saActions := sActions;
if not ChangeServiceConfig2(
ServiceHandle, // handle to service
SERVICE_CONFIG_FAILURE_ACTIONS, // change: description
sfActions) // new description
then
RaiseException('SimpleChangeServiceConfig@ChangeServiceConfig2: ' + AService + ' ' +
SysErrorMessage(DLLGetLastError));
finally
if ServiceHandle <> 0 then
CloseServiceHandle(ServiceHandle);
end;
finally
if SCMHandle <> 0 then
CloseServiceHandle(SCMHandle);
end;
except
ShowExceptionMessage;
end;
end;
Try using the var keyword in the declaration for the lpInfo parameter to specify that it's to pass a pointer to the structure to the function.