Tuesday, July 26, 2011

Create, install, and uninstall Windows Service with VB.NET.

One powerful feature of Visual Basic .NET is the capability to create a Windows Service. Before we start creating our own window service lets have a glance at the definition of window service.

Window Service : The core function of a windows service is to run an application in the background. There are few things that make them different from a Windows application. A Windows service starts much before any user logs in to the system (if it has been setup to start at boot up process). A Windows service can also be setup in such a way that it requires a user to start it manually – the ultimate customization!

Windows services have their own processes, and hence run very efficiently. Normally a Windows service will not have a user interface for the simple reason that it can be run even if no one is logged into the system, but this is not a rule -- you can still have a Windows service with a user interface.
you can view a list of services currently running on your computer by opening Control Panel -> Administrative Tools -> Services, as shown below:



Developing Windows Services changes completely in .NET. VB.NET is as good a choice as any other .NET language for developing a Windows Service. As with many areas of advanced functionality, the reason you can use VB.NET for this purpose is because base classes in the .NET Framework take care of the system-level interfacing. You need two base classes to create a Windows Service in VB.NET: System.ServiceProcess.ServiceBase and System.Configuration.Install.Installer.

System.ServiceProcess.ServiceBase provides the base class for the service itself. The class that inherits from this class contains the logic that runs in the service. System.Configuration.Install.Installer provides the interface necessary to get the service installed under Windows 2000 and NT. It isn't typically necessary to put any logic in your installer class.

Create the Beep Service example

Create a new project in Visual Studio with the type Windows Service. Name the project BeepService, then go to the design surface for the Service1 component. Open the Toolbox and click on the Components tab. Drag a Timer control from the Toolbox onto the Service1 component. It appears on the design surface with the name Timer1.

In the Properties window for Timer1, change the Interval property to a value of 3000. (i.e; 3,000 milliseconds, which causes the timer to fire every three seconds.) Then go back to the code for Service1.vb. Enter this code in the OnStart event:

Timer1.Enabled = True

Enter this code in the OnStop event for the class:
Timer1.Enabled = False


To create an Elapsed event for the timer, highlight Timer1 in the left-hand dropdown box at the top of the code editor window, then select the Elapsed event in the right-hand dropdown. Place this line of code in the Elapsed event:

Beep()

Now add an installer to the project. Go back to the design surface for Service1 and right-click on it. Select Add Installer, which creates a new component called ProjectInstaller and adds it to the project.

Highlight the ServiceProcessInstaller1 control on the ProjectInstaller design surface. Change the Account property in its Properties window to LocalSystem. Then highlight the ServiceInstaller1 control. In its Properties window, change the ServiceName property to BeepService. Now build the project. This creates an EXE for the service.
Now you're ready to install the service.

Install the Beep Service
You must start the .net utility InstallUtil.exe  from a command line to install the window service. InstallUtil.exe is located in "c:\windows\Microsoft.NET\Framework\v2.0.50727". Start up a DOS-style command window or Visual Studio.NET command Window and change the current directory to
 c:\windows\Microsoft.NET\Framework\v2.0.50727.





After getting one of the two command windows, enter a command such as this:

InstallUtil.exe {path for BeepService.exe}

The path for the Windows Service executable varies depending on where you put your BeepService project. Remember that .NET places executable modules in a \bin subdirectory under the project directory. If the executable's path is complex, you might want to copy the executable to a simpler path such as C:\MyServices. In this case, the command to install the service would look like this:

InstallUtil.exe

   C:\MyServices\BeepService.exe

You should look at the messages generated by InstallUtil.exe to ensure the service installed successfully.

Start BeepService
Now goto Control Panel -> Administrative Tools -> Services as shown above, Note the presence of the BeepService program you installed earlier; if BeepService doesn't appear, the installation wasn't successful.





Start BeepService by right-clicking on it and selecting Start. Your computer begins to beep every three seconds. You can stop the service by right-clicking on BeepService and selecting Stop.
Uninstalling the service

Uninstalling the service is similar to installing it. You do this in a command window; use the same command used as the one for installation, except include the option "/u" just before the path for the service. Assuming you placed BeepService.exe in the C:\MyServices directory, the command to uninstall BeepService would look like this:

InstallUtil.exe /u

   C:\MyServices\BeepService.exe

Once you uninstall BeepService, it no longer shows up in the list of available services to start and stop.
You must uninstall and reinstall a Windows Service every time you make changes to it.


Important: You should close the Services screen every time you uninstall a service. If the Services screen remains open, reinstalling your service might be difficult. After reinstalling the service, you can reopen the Services program from Administrative Tools.

Hope this article be usefull...

8 comments:

  1. I followed your example EXACTLY as you laid it out, but when I went to you installutil.exe, I keep getting this message:

    Exception occurred while initializing the installation: System.BadImageFormatException: Could not load file or assembly 'file:///c:\_hdlocal\beep\BeepService.exe' or one of its dependencies. The module was expected to contain an assembly manifest...

    How do I fix this?

    ReplyDelete
  2. Thanks for your comment.
    It seems the .exe file(BeepService.exe) path issues. Please specify the exe file locally instead of network.

    E.g;

    InstallUtil.exe c:\beep\BeepService.exe

    ReplyDelete
  3. Thing is, I'm actually typing it in that way. Typed it in that way from the beginning. It's adding the "file:///" all on it's own, and I can't seem to make it not do that. Ideas?

    ReplyDelete
  4. Okay, so here's the deal. I got it installed. I realized when I build the project, by default it was creating it in 4.0 framework, so I changed the path of installutil.exe to the 4.0 framework instead of the 2.0 framework. That DID install the service. I viewed my services, right-clicked and started it, but it's not beeping. Beep Service is running in Processes.

    Why isn't it actually beeping? I understand the code, and the timer events are programmed correctly, so why won't it do it?

    ReplyDelete
  5. Hi Gravity!
    Thanks for your comment.

    Please be sure you have placed the beep() function in timers Elapsed event. if you are not getting the elapsed event. Please follow these code. It will help you.

    1. go to your Projects Solution explorer. Click on show all files.
    Open your service Designer code e.g; (Service1.Designer.vb for vb.net).

    2. Go to InitializeComponent() function, Comment old code and change the timers type from Windows.forms.Timer to System.Timers.Timer
    as below code

    Private Sub InitializeComponent()
    '''Commented Code

    'Me.components = New System.ComponentModel.Container
    'Me.Timer1 = New System.Windows.Forms.Timer(Me.components)
    ''
    ''Timer1
    ''
    'Me.Timer1.Interval = 3000
    ''
    ''Service1
    ''
    'Me.ServiceName = "Service1"


    ''''''New Code

    Me.tmrService = New System.Timers.Timer()
    DirectCast(Me.tmrService, System.ComponentModel.ISupportInitialize).BeginInit()
    '
    ' tmrService
    '
    Me.tmrService.Enabled = True

    '
    ' Service1
    '
    Me.ServiceName = "Service1"
    DirectCast(Me.tmrService, System.ComponentModel.ISupportInitialize).EndInit()
    End Sub

    Friend WithEvents tmrService As System.Timers.Timer



    3. Now its done! Just Select Timer Elapsed event and place the beep() function inside this block.


    Hope this will help you.

    ReplyDelete
  6. Man, I'm trying. I guess I'm just stupid or something. Here's all my code for VB 2012 RC. Definitely using the correct .NET framework.

    '===============================
    Service1.vb
    '===============================
    Public Class BeepService3

    Protected Overrides Sub OnStart(ByVal args() As String)
    ' Add code here to start your service. This method should set things
    ' in motion so your service can do its work.
    Timer1.Enabled = True
    Timer1.Start()
    End Sub

    Protected Overrides Sub OnStop()
    ' Add code here to perform any tear-down necessary to stop your service.
    Timer1.Enabled = False
    End Sub

    Private Sub Timer1_Elapsed(sender As Object, e As Timers.ElapsedEventArgs) Handles Timer1.Elapsed
    Beep()
    End Sub


    End Class

    '===============================
    Service1.Designer.vb
    '===============================
    Imports System.ServiceProcess

    _
    Partial Class BeepService3
    Inherits System.ServiceProcess.ServiceBase

    'UserService overrides dispose to clean up the component list.
    _
    Protected Overrides Sub Dispose(ByVal disposing As Boolean)
    Try
    If disposing AndAlso components IsNot Nothing Then
    components.Dispose()
    End If
    Finally
    MyBase.Dispose(disposing)
    End Try
    End Sub

    ' The main entry point for the process
    _
    _
    Shared Sub Main()
    Dim ServicesToRun() As System.ServiceProcess.ServiceBase

    ' More than one NT Service may run within the same process. To add
    ' another service to this process, change the following line to
    ' create a second service object. For example,
    '
    ' ServicesToRun = New System.ServiceProcess.ServiceBase () {New Service1, New MySecondUserService}
    '
    ServicesToRun = New System.ServiceProcess.ServiceBase() {New BeepService3}

    System.ServiceProcess.ServiceBase.Run(ServicesToRun)
    End Sub

    'Required by the Component Designer
    Private components As System.ComponentModel.IContainer

    ' NOTE: The following procedure is required by the Component Designer
    ' It can be modified using the Component Designer.
    ' Do not modify it using the code editor.
    _
    Private Sub InitializeComponent()
    Me.Timer1 = New System.Timers.Timer()
    DirectCast(Me.Timer1, System.ComponentModel.ISupportInitialize).BeginInit()
    CType(Me.Timer1, System.ComponentModel.ISupportInitialize).BeginInit()
    '
    'Timer1
    '
    Me.Timer1.Enabled = True
    Me.Timer1.Interval = 3000.0R
    '
    'BeepService3
    '
    Me.ServiceName = "BeepService3"
    DirectCast(Me.Timer1, System.ComponentModel.ISupportInitialize).EndInit()
    CType(Me.Timer1, System.ComponentModel.ISupportInitialize).EndInit()

    End Sub
    Friend WithEvents Timer1 As System.Timers.Timer

    End Class

    ' ****************

    That stuff in InitializeComponent() where it says "CType(me.timer1", that was in the code already. I've tried it with and without that line, since your sample code did not have it.

    Timer1, as a System Timer DOES exist on Service1.vb as a control (Component).

    I've been trying and trying and TRYING to get this to work for DAYS now. Not just your code, but I've read so much documentation on services it's unbelievable. I think I'm so close.

    ReplyDelete
  7. It also also noteworthy that I was able to add the Timer to the service WITH the Elapsed event, and not just Tick, because I chose the appropriate one from adding components. But whether I use Tick OR Elapsed, still nothing. It never, ever beeps, and the service is definitely running.

    ReplyDelete
  8. Hi!

    I verified my sample code.
    There is no issue with code. Kindly verify whether the sound device is working with your system.

    One more alternative You can try instead of beep() call Microsoft.VisualBasic.Beep()

    ReplyDelete