Windows Service install/uninstall (files locked)

128 views
Skip to first unread message

Paw Hauge Byrialsen

unread,
Apr 28, 2022, 6:53:39 PM4/28/22
to innosetup
Hi 

Many years ago I used InnoSetup and I loved it totally but I remembering having some troubles with Windows Services install/uninstall flow. Now I started to use InnoSetup again and I find myself having big problems with Windows Services all over again. Tried to google solutions and expected to find some complete guides of how to do it, but no luck.

My task is very simple.

[Install]
Stop my service if already installed+running
Update all files 

[Uninstall]
Stop my service if already installed+running
Delete the files

I have tried a lot of ways to register/unregister/stop a service (sc.exe, net, srvman), but the main issue seems to be that even though Windows has stopped the service, the files are still locked for some time. I managed to get it working in the install process if I just wait 10 seconds after I stopped the service, but to be honest I hate such solutions. (I stop the service in the event 'PrepareToInstall').

And for the uninstall process I don't have a solution that works. The service isself is stopped and unregistered but all related files is reported "Failed to delete the file; it may be in use (5)".

I really hope someone can tell me how to handle this properly. 
/Paw

Gavin Lambert

unread,
Apr 28, 2022, 10:18:32 PM4/28/22
to inno...@googlegroups.com
On 29/04/2022 10:53, Paw Hauge Byrialsen wrote:
> I have tried a lot of ways to register/unregister/stop a service
> (sc.exe, net, srvman), but the main issue seems to be that even though
> Windows has stopped the service, the files are still locked for some
> time. I managed to get it working in the install process if I just wait
> 10 seconds after I stopped the service, but to be honest I hate such
> solutions. (I stop the service in the event 'PrepareToInstall').
>
> And for the uninstall process I don't have a solution that works. The
> service isself is stopped and unregistered but all related files is
> reported "Failed to delete the file; it may be in use (5)".

The easy way is to use "net start"/"net stop" instead of SC -- SC is
asynchronous so it will request the start/stop but not actually wait for
it, while net will wait for it to complete before returning.

For the actual service registration/deregistration, the way that I
prefer to do that is to run the service exe itself with an /install
/uninstall command line parameter and let it do the heavy lifting. You
could potentially do the same thing if you wanted to have finer control
over the timing of starting/stopping the service than "net" provides.

Sadly the ISXKB Wiki has been lost to time, but it used to have some
example code for using the service control APIs directly from Inno
script, which is another option.

Gavin Lambert

unread,
Apr 28, 2022, 10:48:46 PM4/28/22
to inno...@googlegroups.com
Mere moments ago, quoth I:
> The easy way is to use "net start"/"net stop" instead of SC -- SC is
> asynchronous so it will request the start/stop but not actually wait for
> it, while net will wait for it to complete before returning.

Another thing to watch out for is exactly where in your own code you're
issuing the "service status = stopped" indication.

You want to issue "service status = stopping" almost immediately, and
then clean up absolutely everything you can (including destroying
threads and global objects) and only issue the "stopped" status as the
absolute last thing before your process exits. (Global destructors will
run after this, but you want to ensure that they have already been
cleaned up so there's nothing to do.)

There will be a window of time between "stopped" and when the process
actually exits and releases the file, and you want this time to be as
short as possible. Usually you don't need to make any special effort to
ensure this as long as you've issued it as the last thing with little to
no additional subsequent cleanup -- especially if you're running "net
stop" since the time for *that* process to stop and exit should
hopefully be similar to that of the service process.

If you can't completely eliminate this as a problem, then you may need
to explicitly wait for the service process to terminate as well.
Although note that Inno's own default Restart Manager checks (which run
after PrepareToInstall) will handle some of this as well.

Martijn Laan

unread,
Apr 29, 2022, 3:17:03 AM4/29/22
to inno...@googlegroups.com
If you're updating the service then it should be stopped and restarted automatically by default, thanks to Windows' Restart Manager.

Greetings,
Martijn

Paw Hauge Byrialsen

unread,
Apr 29, 2022, 5:05:31 PM4/29/22
to innosetup
Hi again. I created a complete new setup for testing this problem. It contains a new very simple Windows Service and a new IS script like below:

[Run]
Filename: "{sys}\sc.exe"; Parameters: "create ISWindowsService displayname=""ISWindowsService"" start= auto binPath= ""{app}\InnoSetupWindowsService.exe"""; Flags: runhidden

[UninstallRun]
Filename: "{sys}\sc.exe"; Parameters: "delete ISWindowsService"; Flags: runhidden

[Code]
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
var
  ResultCode: Integer;
begin
  case CurUninstallStep of
    usUninstall:
      begin
        if not Exec(ExpandConstant('{sys}\net.exe'), 'stop ISWindowsService', '', SW_HIDE, ewWaitUntilTerminated, ResultCode) then
        begin
          MsgBox('Failed to stop service!', mbError, MB_OK);
        end
      end;
    end;
end;

This works perfectly. On update the service is stopped, files updated and at the end the service is re-started again.
On Uninstall the service is stopped, and files are uninstalled.

BUT, running this with my original Windows Service on update the installer will give an access denied 5 error a few times until the files are release (eventhough the service is stopped), and on uninstall the final dialog tell that not all files could be removed (because they were locked).

So any clues what to do. Should I investigate my Windows service and find out what locks the files for so loooong, after the service is stopped or can I handle this scenario from innosetup checking process termination or similar?

Paw Hauge Byrialsen

unread,
May 11, 2022, 2:15:39 PM5/11/22
to innosetup
FYI...To be able to handle this problem I created a small command line tool:


The tool can help me stop the service and wait for Windows to release the file(s) before my installer will continue (both install and unistall). Every relevant code/info/.iss script can be found in the above github repo. 

Maybe others than myself can benefit from it. 
And please let me know if the solution could be optimized, or has any flaws.

/Paw

Otomatic

unread,
May 12, 2022, 9:46:20 AM5/12/22
to innosetup
Hi,

I use an iss include services.iss

Define the services to stop
#define APACHESERVICE 'wampapache64'
#define MYSQLSERVICE 'wampmysqld64'
#define MARIASERVICE 'wampmariadb64'

 in PrepareToInstall function

    //--- Stopping running services (Eventually)
  ServiceToStop[0] := '{#APACHESERVICE}';
  ServiceToStop[1] := '{#MYSQLSERVICE}';
  ServiceToStop[2] := '{#MARIASERVICE}';

  ServicesFound := GetArrayLength(ServiceToStop);
  for Index := 0 to ServicesFound - 1 do
  begin
    if ServiceExists(ServiceToStop[Index]) then begin
      if SimpleQueryService(ServiceToStop[Index], True) = SERVICE_RUNNING then begin
        SimpleStopService(ServiceToStop[Index], True, False);
      end;
    end;
  end;

Paw Hauge Byrialsen

unread,
May 12, 2022, 2:10:35 PM5/12/22
to innosetup
But if I read the .iss file correctly this one only stops the service and continues after Service state is changed to STOPPED. It doesn't wait for Windows to actually release the .exe file. ? And that is where my original problem was. My command line tool waits for the windows service executeable to Exit also

Maybe I miss something in the. iss :-)

/Paw

Reply all
Reply to author
Forward
0 new messages