Inno Setup Windows DLL извикване на функция с указател към структура

Опитвам се да настроя действия при повреда на услуга, като използвам скриптовия език Pascal на Inno Setup. Получавам класическата грешка "нарушение на достъпа на адрес...". Изглежда, че е невъзможно, защото езикът няма никаква поддръжка за указатели. Някакви идеи? Ето кодовия фрагмент:

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 '[email protected] 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;

person Charlie Brown    schedule 01.07.2011    source източник


Отговори (2)


Имате два проблема във вашия скрипт. Както 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 '[email protected] 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;     
person stapel    schedule 26.09.2012

Опитайте да използвате ключовата дума var в декларацията за параметъра lpInfo, за да посочите, че той трябва да предаде указател към структурата към функцията.

person Deanna    schedule 01.07.2011