Inno Setup Windows DLL函数调用指针结构

时间:2011-07-01 08:50:07

标签: pointers inno-setup

我正在尝试使用Inno Setup的Pascal脚本语言设置服务的失败操作。我收到了经典“地址访问冲突...”错误。似乎这是不可能的,因为语言对指针没有任何支持。有任何想法吗?以下是代码段:

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;

2 个答案:

答案 0 :(得分:6)

您的脚本中有两个问题。与Deanna建议您必须在var参数的声明中使用lpInfo关键字。

此外,您需要将TScAction类型更改为包含两个元素的数组。

这是我的脚本,您可以将其包含在Inno安装脚本中。

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;     

答案 1 :(得分:0)

尝试在lpInfo参数的声明中使用var关键字来指定它将指向结构的指针传递给函数。