Inno Setup - properly stop service before file copy

11,102

There is currently no direct way to exclude a file from checking if it's in use. You can disable this control globally (by setting CloseApplications directive value to no), which I wouldn't recommend. Or you can set a filter for files, which will be checked (in the CloseApplicationsFilter directive), which for you might require e.g. to list all the files except your service executable, which is hard to maintain.

You may also list all the files to be checked by specifying a filter which won't match any of your files and adding them from the RegisterExtraCloseApplicationsResources event method is the same as doing this from the mentioned directive.

What I would suggest is to stop your service from the PrepareToInstall event method. Its reference explicitly suggests this (emphasized by me):

You can use this event function to detect and install missing prerequisites and/or to shutdown any application which is about to be updated.

This event method is executed before all the file in use checks are performed and allows you to say that you need a system restart for cases when stopping of your service fails for some reason. If you wouldn't require restart, you may just return a string with some sensible message what happened to the user.

For your script it would just mean to move the code from your BeforeServiceInstall procedure to the PrepareToInstall event method and remove the BeforeInstall parameter from the entry.

Share:
11,102

Related videos on Youtube

Jerry Dodge
Author by

Jerry Dodge

I'm a Delphi developer. I work for a software company which does solutions for retail management, including inventory, POS, reporting, BI, Tags, and more. It's been in Delphi since Delphi's been around. I am actively in Stack Overflow monitoring the Delphi tag, and looking for those questions I can answer and also contributing my time to keep Stack Overflow in order. I'm not an expert in anything, a jack of all trades rather. But I love to help people when I'm able to. I've known Delphi since about 2007 now, and before that, I had learned VB6. I havn't gone back to VB since I learned Delphi. I also taught myself QBasic and HTML as a kid. It hasn't been until the past 5 years that I've been diving into programming. Since then I've also become vaguely familiar with ASP.NET with C#, as well as some C# windows apps. But I'm not too fond of the whole .NET idea. .NET is good for web platforms and such, but not for win apps. My latest work has been with Delphi 10 Seattle mobile development. I'm still very raw on the subject, but see a huge potential behind it. My strengths: Understanding the bigger picture of projects Writing Custom Classes, Components, and Controls Code organization (within unit or namespace) Writing purely independent classes (as opposed to cross-referencing units or namespaces) User Friendly UI's Developer Friendly Classes Encapsulating layers of business logic My weaknesses: Lower-level coding (such as Assembly) Platform-specific design (using Firemonkey) Web Design It's always nice to know you're able to do something, even if you never use it.

Updated on October 20, 2022

Comments

  • Jerry Dodge
    Jerry Dodge over 1 year

    Our installation process includes a Windows Service which is installed if our software is configured to be installed as a server (vs. a client installation). I added a service library to be able to manage the services, then in the files, I added handlers for BeforeInstall and AfterInstall events...

    [Files]
    Source: "MyService.exe"; DestDir: "{app}"; Check: IsServer; BeforeInstall: BeforeServiceInstall('MyServiceName', 'MyService.exe'); AfterInstall: AfterServiceInstall('MyServiceName', 'MyService.exe')
    
    procedure BeforeServiceInstall(SvcName, FileName: String);
    var
      S: Longword;
    begin
      //If service is installed, it needs to be stopped
      if ServiceExists(SvcName) then begin
        S:= SimpleQueryService(SvcName);
        if S <> SERVICE_STOPPED then begin
          SimpleStopService(SvcName, True, True);
        end;
      end;
    end;
    
    procedure AfterServiceInstall(SvcName, FileName: String);
    begin
      //If service is not installed, it needs to be installed now
      if not ServiceExists(SvcName) then begin
        if SimpleCreateService(SvcName, 'My Service Name', ExpandConstant('{app}')+'\' + FileName, SERVICE_AUTO_START, '', '', False, True) then begin
          //Service successfully installed
          SimpleStartService(SvcName, True, True);
        end else begin
          //Service failed to install
    
        end;
      end;
    end;
    

    When installing the service for the first time (doesn't already exist and isn't currently running), the installation/starting of this service works just fine. However, when running this installer on an existing installation (upgrade), the installer stops when it recognizes that this service is running, and prompts to terminate the process (before it calls the BeforeServiceInstall() handler)...

    Prompt message

    How do I prevent this prompt from appearing for services? I'm avoiding having to require a restart and would still like this prompt to appear for all other files.

    • Jerry Dodge
      Jerry Dodge over 10 years
    • TLama
      TLama over 10 years
      OT: Luigi (the author of that library) obviously likes Longword data type. Unfortunately, it's far away from correctness. I've been in the middle of translating Windows Service API prototypes, but it remained pending on my to-do list.
  • roalz
    roalz about 6 years
    I had a problem similar to the original question here, so I followed your suggestion and used PrepareToInstall, but I still get the "file in use" error, even if the service is correctly stopped. Any idea how I can fix it?
  • John Grabanski
    John Grabanski over 5 years
    @roalz It's possible that the service successfully stopped, but the process is still running. Which has happened to me a few times. Look in the Task Manager to double check if the process is still running, and if it is then update the service, or reach out to the vendor/developer for commercial services.
  • roalz
    roalz over 5 years
    @John Indeed that's the problem, the service was incorrectly doing some stuff AFTER the StopService function returned, thus the service was reported as stopped, but the process was still running. Thanks for confirming the behaviour