Link to home
Start Free TrialLog in
Avatar of madlan
madlan

asked on

Stop + Uninstall a service with Custom Action

I have an application that installs and starts a service during its usage.
I need to stop and uninstall this service as part of the uninstallation process (before actually uninstalling the file(s) in the MyApp folder as they will be in use by the running service)

I can stop and remove the service with the attached code.
How would I go about doing this?

With a custom action as part of my Setup project in Visual Studio can I trigger this pre uninstall?

Coding in VB.NET VS2008
Dim sc As New ServiceController()
        sc.ServiceName = "svrctrl"
        sc.Stop()
        Dim svrctrl As New ProcessStartInfo
        nssm.FileName = "C:\Program Files\MyApp\svrctrl.exe"
        nssm.Arguments = "remove ServiceName"
        nssm.CreateNoWindow = False
        nssm.WindowStyle = ProcessWindowStyle.Hidden
        nssm.WorkingDirectory = "C:\Program Files\MyApp\"
        Process.Start(svrctrl)

Open in new window

Avatar of Meir Rivkin
Meir Rivkin
Flag of Israel image

yes, in your custom action code simply override the following:

Protected Overloads Overrides Sub OnBeforeUninstall(ByVal savedState As IDictionary)
''put your code here
    MyBase.OnBeforeUninstall(savedState)
End Sub
check this following class i wrote for start/stop services.
u can explicitly call Start/Stop/Restart with the service name
for example:
Services.ServiceRestarter.Restart("mysql")

or using "using" keyword, for example:
 Using (New Services.ServiceRestarter("MySql"))
            ''do some stuff while service is down
        End Using

in the ctor the service is stopped and upon OnDispose() the service is back on again.
it's perfect when u wish to perform procedures which requires stop then start the service.
Imports System
Imports System.Diagnostics

Namespace Services
    Public Class ServiceRestarter
        Implements IDisposable
#Region "Internal"
        Private _service As String = String.Empty
#End Region

#Region "Ctor"
        ''' <summary>
        ''' Initializes a new instance of the <see cref="ServiceRestarter"/> class.
        ''' </summary>
        ''' <param name="service">The service.</param>
        Public Sub New(ByVal service As String)
            _service = service
            ServiceRestarter.[Stop](_service)
        End Sub

#End Region

#Region "Methods"

#Region "Static"
        ''' <summary>
        ''' Restarts the specified service.
        ''' </summary>
        ''' <param name="service">The service.</param>
        Public Shared Sub Restart(ByVal service As String)
            ServiceRestarter.[Stop](service)
            ServiceRestarter.Start(service)
        End Sub

        ''' <summary>
        ''' Starts the specified service.
        ''' </summary>
        ''' <param name="service">The service.</param>
        Public Shared Sub Start(ByVal service As String)
            Console.WriteLine("Start Service {0}", service)
            Dim proc As Process = Process.Start("net", String.Format("start {0}", service))
            proc.WaitForExit()
            Select Case proc.ExitCode
                Case 2
                    Console.WriteLine("service {0} is already running.", service)
                    Exit Select
                Case 0
                    Console.WriteLine("service {0} was started.", service)
                    Exit Select
                Case Else
                    Throw New ApplicationException(String.Format("start service {0} return with exitCode: {1}", service, proc.ExitCode))
            End Select
        End Sub

        ''' <summary>
        ''' Stops the specified service.
        ''' </summary>
        ''' <param name="service">The service.</param>
        Public Shared Sub [Stop](ByVal service As String)
            Dim proc As Process = Process.Start("net", String.Format("stop {0}", service))
            proc.WaitForExit()
            Select Case proc.ExitCode
                Case 2
                    Console.WriteLine("service {0} is already stopped.", service)
                    Exit Select
                Case 0
                    Console.WriteLine("service {0} was stopped.", service)
                    Exit Select
                Case Else
                    Throw New ApplicationException(String.Format("stop service {0} return with exitCode: {1}", service, proc.ExitCode))
            End Select
        End Sub

#End Region

#End Region

#Region "IDisposable Members"

        ''' <summary>
        ''' Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        ''' </summary>
        Public Sub Dispose() Implements IDisposable.Dispose
            ServiceRestarter.Start(_service)
        End Sub

#End Region
    End Class
End Namespace

Open in new window

Avatar of madlan
madlan

ASKER

I've added a VB Class library to the project (add / new project) with the attached code.
How do I get OnBeforeUninstall to reference the innstall project rather than the class it's in?

(sub 'OnBeforeUninstall' cannot be declared 'Overrides' because it does not override a sub in a base class.)

I've referenced the output of the uninstall class to the uninstall custom action.

My Solution is structured:

Solution
------ Actual program (Forms application)
------ Uninstall (VB Class)
------ Installer (Install wizard project)
Public Class Uninstall
    Protected Overloads Overrides Sub OnBeforeUninstall(ByVal savedState As IDictionary)
        ''put your code here
        MyBase.OnBeforeUninstall(savedState)
    End Sub
End Class

Open in new window

why would u separate the uninstall code from your custom action code?
override OnBeforeUninstall should be placed in your custom action code as well.
ASKER CERTIFIED SOLUTION
Avatar of Meir Rivkin
Meir Rivkin
Flag of Israel image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
sorry man, i understand how u got mixed up cause i pasted the function signature all wrong in my first post.

Avatar of madlan

ASKER

Ahh I see - thanks sedgwick.
One question, having the resulting .dll in the installation folder is a bit messy, can this code not be embeded in the MSI?
why is it messy?
having this code not embedded in the msi means that it could be in a different exe (or dll) which the msi invokes, is that what u mean?
Avatar of madlan

ASKER

My application has very few files in its program folder, less the better.
I thought the code had to be in it's own dll\exe? for custom actions?
the custom action is coded in a dll which being referenced from the setup deployment project.