14

I've got a windows service, built using C#, that is installed via a VS2008 setup project, and am having a couple of problems occurring with the uninstall process:

Service is not stopped prior to uninstalling

When the uninstall routine runs, it throws up an error about files being in use. Clicking continue completes the installer correctly, but the service still shows up in the list, so it's not being uninstalled properly.

(At present, I have to resort to deleting it manually using sc delete servicename).

I'm trying to stop the service before uninstalling using the following code, but it doesn't seem to be taking effect:

protected override void OnBeforeUninstall(IDictionary savedState)
{
   base.OnBeforeUninstall(savedState);
   ServiceController serviceController = new ServiceController(MyInstaller.ServiceName);
   serviceController.Stop();
}

When is this code called, and how can I stop the service prior to uninstalling?

Installation folder not deleted after uninstalling

The application also creates some files within it's installation folder when executed. After uninstalling, the installation folder (C:\Program Files\MyApp) is not deleted, and contains the files created by the application, though all other files that were actually installed by the installer have been deleted successfully.

Is it possible for the uninstall process to delete the installation folder, including all generated files within that folder, and if so, how?

Thanks.

Mun
  • 14,098
  • 11
  • 59
  • 83

3 Answers3

7

For the benefit of anyone looking for an answer to these problems:

Service is not stopped prior to uninstalling

Haven't yet found a solution to this.

Installation folder not deleted after uninstalling

The OnAfterUninstall method in the project installer needs to be overridden, and any created files must be deleted. The application installer folder is automatically deleted if it doesn't contain any files after this step.

protected override void OnAfterUninstall(IDictionary savedState)
{
    base.OnAfterUninstall(savedState);

    string targetDir = Context.Parameters["TargetDir"]; // Must be passed in as a parameter

    if (targetDir.EndsWith("|"))
        targetDir = targetDir.Substring(0, targetDir.Length-1);

    if (!targetDir.EndsWith("\\"))
        targetDir += "\\";

    if (!Directory.Exists(targetDir))
    {
        Debug.WriteLine("Target dir does not exist: " + targetDir);
        return;
    }

    string[] files = new[] { "File1.txt", "File2.tmp", "File3.doc" };
    string[] dirs  = new[] { "Logs", "Temp" };

    foreach (string f in files)
    {
        string path = Path.Combine(targetDir, f);

        if (File.Exists(path))
            File.Delete(path);
    }

    foreach (string d in dirs)
    {
        string path = Path.Combine(targetDir, d);

        if (Directory.Exists(d))
            Directory.Delete(d, true);
    }

    // At this point, all generated files and directories must be deleted.
    // The installation folder will be removed automatically.
}

Remember, the installation folder must be passed in as a parameter:

  • Right click on your setup project, then choose View -> Custom Actions
  • The custom actions will open in your main window. Right click on "Primary output from XXX" under the Uninstall node and select "Properties Window"
  • In the properties window, under CustomActionData, enter the following: /TargetDir="[TARGETDIR]|" (note the pipe at the end, do not remove this).

This will pass the installation folder as a parameter to your uninstall routine so that you know where the application was installed and can delete your generated files and folders.

Mun
  • 14,098
  • 11
  • 59
  • 83
  • 1
    I'd like an answer to your first issue myself. Please post it if you ever figure it out. – PaulH Oct 27 '11 at 21:36
  • @Mun I added [this code](http://www.primordialcode.com/blog/post/msi-simple-delete-files-custom-action) to `OnAfterUninstall` method, but it says the File is being used by another process or access denied – Yogesh lele Aug 20 '14 at 08:43
1

Most likely the service is just taking a little time to shut down, and you're continuing on before the service has fully stopped. Try calling the WaitForStatus(ServiceControllerStatus) method.

This will cause your code to wait until the service processes the "stop" message, and shuts down. Once the service is actually shut down, it will no longer be holding on to any file handles.

Nader Shirazie
  • 10,736
  • 2
  • 37
  • 43
  • 1
    I've tried this, without any luck. Some further debugging reveals that none of the uninstall (OnBeforeUninstall, OnAfterUninstall, Uninstall) methods are actually being called before Windows pops up the "Files in use" warning, which would be why the service is not being stopped. – Mun Aug 08 '10 at 05:51
  • Ah, ok. A different question, when you say "files created by the application", you mean files not present when the installer completes the installation, rather created as the application runs? Those files may need to be cleaned up manually (onafterinstall?)... many installers will be very careful about what they "automatically" delete. – Nader Shirazie Aug 08 '10 at 06:26
  • 1
    Yep, I managed to resolve that problem by passing in the installation directory as a custom parameter, and overriding the OnAfterUninstall method to delete the files created by the application. If the folder is empty after that, the installer automatically removes it. – Mun Aug 10 '10 at 14:13
0

Just follow Mun's answer, by adding the following code in the "OnAfterUninstall" function, the Windows service will be deleted.

        var process = new System.Diagnostics.Process();
        process.StartInfo.FileName = "sc.exe";
        process.StartInfo.Arguments = "delete \"" + serviceName + "\"";
        process.StartInfo.CreateNoWindow = true;
        process.Start();
qiuyl
  • 21
  • 6
  • I would advise against this approach. The `sc.exe` utility is part of some resource kit which would not usually be installed on client machines, so this code won't do anything. The service should also be deleted anyway as part of the uninstall process, and should not need to be deleted in this way. – Mun Mar 19 '18 at 14:16