<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://msmvps.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Joacim's view on stuff : windows service</title><link>http://msmvps.com/blogs/joacim/archive/tags/windows+service/default.aspx</link><description>Tags: windows service</description><dc:language>en</dc:language><generator>CommunityServer 2008.5 SP2 (Build: 40407.4157)</generator><item><title>Debugging a Windows Service</title><link>http://msmvps.com/blogs/joacim/archive/2009/09/13/debugging-a-windows-service.aspx</link><pubDate>Sun, 13 Sep 2009 19:17:31 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1723066</guid><dc:creator>Joacim Andersson</dc:creator><slash:comments>9</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/joacim/rsscomments.aspx?PostID=1723066</wfw:commentRss><comments>http://msmvps.com/blogs/joacim/archive/2009/09/13/debugging-a-windows-service.aspx#comments</comments><description>&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;In my &lt;a href="http://msmvps.com/blogs/joacim/archive/2009/09/13/creating-a-windows-service-using-vb-net.aspx"&gt;last article&lt;/a&gt; I showed a simple example of how to create a Windows Service using VB. This time we’re going to have a look at how to debug the service from Visual Studio.&lt;/p&gt;  &lt;p&gt;Since a service must run from the context of the &lt;em&gt;Service Control Manager&lt;/em&gt; you can’t normally debug it in the same manner as you would any other project type. Normally you would need to build the project, install it using the &lt;em&gt;InstallUtil.exe&lt;/em&gt; command line tool, and attach a debugger to the process while it’s running. Another approach is to create a separate project (console application) and call your main code from there.&lt;/p&gt;  &lt;p&gt;Neither of these are an ideal way of doing the debugging so I’m going to show an alternative method, which you also can use to run your service from the command line, just like any other application.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Converting the service into a command line tool&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;When you create a Windows Service project in Visual Studio 2008, you get a &lt;em&gt;ServiceBase&lt;/em&gt; designer to which you add controls and your code to. Normally you would, at the very least, override the &lt;em&gt;OnLoad()&lt;/em&gt; and the &lt;em&gt;OnStop() &lt;/em&gt;methods. But the designer also creates a shared (static) &lt;em&gt;Main()&lt;/em&gt; method for you, which is the real starting point of the service. To be able to see that you need to open the designer generated code file. In VB this file is normally hidden, so you need to press the &lt;em&gt;Show all files &lt;/em&gt;button in the Solution Explorer.&lt;/p&gt;  &lt;p&gt;&lt;img style="border-right-width:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" title="image" border="0" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/joacim.metablogapi/4812.image_5F00_0E6D228A.png" width="339" height="313" /&gt; &lt;/p&gt;  &lt;p&gt;The &lt;em&gt;Main()&lt;/em&gt; method looks like this (with some comments removed).&lt;/p&gt;  &lt;pre class="code"&gt;&amp;lt;MTAThread()&amp;gt; _
&amp;lt;System.Diagnostics.DebuggerNonUserCode()&amp;gt; _
&lt;span style="color:blue;"&gt;Public Shared Sub &lt;/span&gt;Main()
&lt;span style="color:blue;"&gt;  Dim &lt;/span&gt;ServicesToRun() &lt;span style="color:blue;"&gt;As &lt;/span&gt;System.ServiceProcess.ServiceBase
  ServicesToRun = _&lt;br /&gt;      &lt;span style="color:blue;"&gt;New &lt;/span&gt;System.ServiceProcess.ServiceBase() {&lt;span style="color:blue;"&gt;New &lt;/span&gt;FileWatcherService}
  System.ServiceProcess.ServiceBase.Run(ServicesToRun)
&lt;span style="color:blue;"&gt;End Sub&lt;/span&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;A &lt;em&gt;Main()&lt;/em&gt; method can receive arguments from the command line, you just have to add a string array as a parameter of the method. The whole idea is that if a specific command line switch is passed to the executable it should not act as a Windows Service but instead run as any other EXE file. So I rewrote the above method to this:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:green;"&gt;&amp;#39; The main entry point for the process
&lt;/span&gt;&amp;lt;MTAThread()&amp;gt; _
&amp;lt;System.Diagnostics.DebuggerNonUserCode()&amp;gt; _
&lt;span style="color:blue;"&gt;Public Shared Sub &lt;/span&gt;Main(&lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;args() &lt;span style="color:blue;"&gt;As String&lt;/span&gt;)
  &lt;span style="color:blue;"&gt;Dim &lt;/span&gt;runAsService &lt;span style="color:blue;"&gt;As Boolean &lt;/span&gt;= &lt;span style="color:blue;"&gt;True
  For Each &lt;/span&gt;arg &lt;span style="color:blue;"&gt;As String In &lt;/span&gt;args
    &lt;span style="color:blue;"&gt;Select Case &lt;/span&gt;arg.ToLower
      &lt;span style="color:blue;"&gt;Case &lt;/span&gt;&lt;span style="color:#a31515;"&gt;&amp;quot;/c&amp;quot;&lt;/span&gt;, &lt;span style="color:#a31515;"&gt;&amp;quot;-c&amp;quot;
        &lt;/span&gt;runAsService = &lt;span style="color:blue;"&gt;False
    End Select
  Next
  If &lt;/span&gt;runAsService &lt;span style="color:blue;"&gt;Then
    Dim &lt;/span&gt;ServicesToRun() &lt;span style="color:blue;"&gt;As &lt;/span&gt;System.ServiceProcess.ServiceBase
&lt;span style="color:green;"&gt;    &lt;/span&gt;ServicesToRun = _&lt;br /&gt;        &lt;span style="color:blue;"&gt;New &lt;/span&gt;System.ServiceProcess.ServiceBase() {&lt;span style="color:blue;"&gt;New &lt;/span&gt;FileWatcherService}
    System.ServiceProcess.ServiceBase.Run(ServicesToRun)
  &lt;span style="color:blue;"&gt;Else
    Dim &lt;/span&gt;service &lt;span style="color:blue;"&gt;As New &lt;/span&gt;FileWatcherService
    service.CommandLineExecution = &lt;span style="color:blue;"&gt;True
    &lt;/span&gt;service.OnStart(&lt;span style="color:blue;"&gt;New String&lt;/span&gt;() {&lt;span style="color:#a31515;"&gt;&amp;quot;&amp;quot;&lt;/span&gt;})
  &lt;span style="color:blue;"&gt;End If
End Sub&lt;/span&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;If the /c or –c switch is found among the command line parameters then it will start as a regular program. As you can see, if the switch is found, instead of creating an instance of the &lt;em&gt;ServiceBase&lt;/em&gt; class I create an instance of my service class directly and call its &lt;em&gt;OnStart()&lt;/em&gt; method. I also added a &lt;em&gt;CommandLineExecution&lt;/em&gt; property to the class so I can keep track of how it is supposed to be executed. If you need to set a breakpoint or step through the &lt;em&gt;Main()&lt;/em&gt; method you need to remove the &lt;em&gt;DebuggerNonUserCode&lt;/em&gt; attribute, otherwise Visual Studio will just run through this method without stopping (this is what you normally would want to do with designer created code).&lt;/p&gt;

&lt;p&gt;Now I also needed to make some changes to the &lt;em&gt;OnStart()&lt;/em&gt; method.&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;Protected Overrides Sub &lt;/span&gt;OnStart(&lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;args() &lt;span style="color:blue;"&gt;As String&lt;/span&gt;)
  &lt;span style="color:blue;"&gt;Dim &lt;/span&gt;handle &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr = &lt;span style="color:blue;"&gt;Me&lt;/span&gt;.ServiceHandle
  &lt;span style="color:blue;"&gt;If Not Me&lt;/span&gt;.CommandLineExecution &lt;span style="color:blue;"&gt;Then
    &lt;/span&gt;_serviceStatus.currentState = Fix(State.SERVICE_START_PENDING)
    SetServiceStatus(handle, _serviceStatus)
  &lt;span style="color:blue;"&gt;End If
  Dim &lt;/span&gt;logMessage &lt;span style="color:blue;"&gt;As String &lt;/span&gt;= &lt;span style="color:blue;"&gt;String&lt;/span&gt;.Empty
  &lt;span style="color:blue;"&gt;If Not &lt;/span&gt;ReadSettings(logMessage) &lt;span style="color:blue;"&gt;Then
    &lt;/span&gt;WriteLogMessage(logMessage, EventLogEntryType.Error)
    _serviceStatus.currentState = Fix(State.SERVICE_STOPPED)
    &lt;span style="color:blue;"&gt;If Not Me&lt;/span&gt;.CommandLineExecution &lt;span style="color:blue;"&gt;Then
      &lt;/span&gt;SetServiceStatus(handle, _serviceStatus)
    &lt;span style="color:blue;"&gt;End If
  Else
    If Not String&lt;/span&gt;.IsNullOrEmpty(logMessage) &lt;span style="color:blue;"&gt;Then
      &lt;/span&gt;WriteLogMessage(logMessage, EventLogEntryType.Information)
    &lt;span style="color:blue;"&gt;End If
    &lt;/span&gt;&lt;span style="color:green;"&gt;&amp;#39;Start the file watching...
    &lt;/span&gt;&lt;span style="color:blue;"&gt;With &lt;/span&gt;FileSystemWatcher1
      .BeginInit()
      .Filter = _fileMask
      .IncludeSubdirectories = _includeSubFolders
      .Path = _folderName
      .EnableRaisingEvents = &lt;span style="color:blue;"&gt;True
      &lt;/span&gt;.EndInit()
      &lt;span style="color:blue;"&gt;If Not Me&lt;/span&gt;.CommandLineExecution &lt;span style="color:blue;"&gt;Then
        &lt;/span&gt;_serviceStatus.currentState = Fix(State.SERVICE_RUNNING)
        SetServiceStatus(handle, _serviceStatus)
      &lt;span style="color:blue;"&gt;Else
        &lt;/span&gt;Threading.Thread.Sleep(Threading.Timeout.Infinite)
      &lt;span style="color:blue;"&gt;End If
    End With
  End If
End Sub&lt;/span&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;If the &lt;em&gt;CommandLineExecution &lt;/em&gt;property is set to True I skip all the calls to the &lt;em&gt;SetServiceStatus() &lt;/em&gt;Win32 API function. I also end the method by letting the current thread sleep for infinity, if I didn’t do that the program would just exit when it reached the end of the method.&lt;/p&gt;

&lt;p&gt;I also made a slight change to the &lt;em&gt;WriteLogMessage()&lt;/em&gt; method, if the application isn’t running as a service there is no reason to do the logging to the Event Viewer. Instead it simply shows a message box.&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;Private Sub &lt;/span&gt;WriteLogMessage(&lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;message &lt;span style="color:blue;"&gt;As String&lt;/span&gt;, _&lt;br /&gt;                            &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;type &lt;span style="color:blue;"&gt;As &lt;/span&gt;EventLogEntryType)
  &lt;span style="color:blue;"&gt;If Not Me&lt;/span&gt;.CommandLineExecution &lt;span style="color:blue;"&gt;Then
    If Not &lt;/span&gt;EventLog.SourceExists(&lt;span style="color:#a31515;"&gt;&amp;quot;File Observer&amp;quot;&lt;/span&gt;) &lt;span style="color:blue;"&gt;Then
      &lt;/span&gt;EventLog.CreateEventSource(&lt;span style="color:#a31515;"&gt;&amp;quot;File Observer&amp;quot;&lt;/span&gt;, &lt;span style="color:#a31515;"&gt;&amp;quot;File Observer Log&amp;quot;&lt;/span&gt;)
    &lt;span style="color:blue;"&gt;End If
    Dim &lt;/span&gt;log &lt;span style="color:blue;"&gt;As New &lt;/span&gt;EventLog()
    log.Source = &lt;span style="color:#a31515;"&gt;&amp;quot;File Observer&amp;quot;
    &lt;/span&gt;log.WriteEntry(message, type)
  &lt;span style="color:blue;"&gt;Else
    &lt;/span&gt;MsgBox(&lt;span style="color:blue;"&gt;String&lt;/span&gt;.Format(&lt;span style="color:#a31515;"&gt;&amp;quot;{0}: {1}&amp;quot;&lt;/span&gt;, type.ToString, message))
  &lt;span style="color:blue;"&gt;End If
End Sub&lt;/span&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;&lt;strong&gt;Debug the service&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To be able to run this service as a regular application from Visual Studio you must pass the command line switch /c. You can specify command line arguments on the Debug tab of the project properties dialog.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/joacim.metablogapi/5008.image_5F00_4C1A0A46.png"&gt;&lt;img style="border-right-width:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" title="image" border="0" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/joacim.metablogapi/6253.image_5F00_thumb_5F00_0A3324F8.png" width="599" height="280" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In this post I showed you how to turn a Windows Service into a regular executable using a command line switch to allow you to debug it from Visual Studio. Of course, instead of a command line switch you could instead just check if the application is in debug or release mode. But I wanted to be able to run the service as a regular application even after it was compiled and deployed in release mode.&lt;/p&gt;

&lt;p&gt;Have fun!&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1723066" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/joacim/archive/tags/vb/default.aspx">vb</category><category domain="http://msmvps.com/blogs/joacim/archive/tags/visual+basic/default.aspx">visual basic</category><category domain="http://msmvps.com/blogs/joacim/archive/tags/windows+service/default.aspx">windows service</category><category domain="http://msmvps.com/blogs/joacim/archive/tags/debugging/default.aspx">debugging</category></item><item><title>Creating a Windows Service using VB.Net</title><link>http://msmvps.com/blogs/joacim/archive/2009/09/13/creating-a-windows-service-using-vb-net.aspx</link><pubDate>Sun, 13 Sep 2009 10:23:02 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1722980</guid><dc:creator>Joacim Andersson</dc:creator><slash:comments>14</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/joacim/rsscomments.aspx?PostID=1722980</wfw:commentRss><comments>http://msmvps.com/blogs/joacim/archive/2009/09/13/creating-a-windows-service-using-vb-net.aspx#comments</comments><description>&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Yesterday I got a call from my brother, or actually he sent me a message over MSN. He wanted to know if I could help him create a program with a very specific requirement. Where he works they have a system that creates a lock file when you enter a new journal into the system. However because of a bug (?) in that system, this file is not always deleted after the journal have been entered. If this file is not removed, no more journals can be entered and the system runs amok.&lt;/p&gt;  &lt;p&gt;So my brother wanted a program that could monitor a folder for this file, if it’s not removed within a specified time, say 1 minute, an e-mail notification is supposed to be sent. Since this program was supposed to run on the server, it needed to be a Windows Service.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Creating a Windows Service&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Creating a Windows Service might not be something you do on a daily bases, during my career I’ve only made 3 or 4 of them, and this one was the very first I’ve created using .Net. Developing a Windows Service used to be pretty darn difficult, but not any more. As it turned out it’s fairly easy these days.&lt;/p&gt;  &lt;p&gt;You start by selecting the &lt;em&gt;Windows Service &lt;/em&gt;project type in the &lt;em&gt;New Project&lt;/em&gt; dialog box in Visual Studio.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/joacim.metablogapi/8625.image_5F00_5F8853B2.png"&gt;&lt;img style="border-right-width:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" title="image" border="0" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/joacim.metablogapi/8228.image_5F00_thumb_5F00_703FD893.png" width="603" height="369" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Doing that will give you a &lt;em&gt;ServiceBase&lt;/em&gt; designer on which you can drop your controls, but since a Service normally don’t interact with the desktop, since it’s supposed to be running even if nobody is logged in, you shouldn’t use input controls such as text boxes or buttons. Using a Timer is a normal way of handling the work the service should do, but in my case I only needed a &lt;em&gt;FileSystemWatcher, s&lt;/em&gt;o I just dropped that on to the designer surface. The designer also have a handful of properties, many of which are named &lt;em&gt;Can…&lt;/em&gt; such as &lt;em&gt;CanPauseAndContinue&lt;/em&gt; and &lt;em&gt;CanStop&lt;/em&gt;. If you set the &lt;em&gt;CanPauseAndContinue&lt;/em&gt; property to True you can override the &lt;em&gt;OnPaus&lt;/em&gt; and &lt;em&gt;OnContinue&lt;/em&gt; methods. In my case I wasn’t interested in that but I did want an administrator to be able to stop the service so I left the &lt;em&gt;CanStop&lt;/em&gt; property as True. If you, like me, leave the properties with their default settings you will have to override the &lt;em&gt;OnStart &lt;/em&gt;and &lt;em&gt;OnStop&lt;/em&gt; methods and I will cover that shortly.&lt;/p&gt;  &lt;p&gt;I needed a way to store settings for this service, such as the time it would wait before sending an e-mail, the folder and file it was going to watch, and various SMTP and mail settings, such as the subject and the body text. To keep it as simple as possible I decided to add an &lt;em&gt;App.Config&lt;/em&gt; file. To do that just right click on the project in the solution explorer and select &lt;em&gt;Add &amp;gt; New Item&lt;/em&gt;, in the context menu. Find the &lt;em&gt;Application Configuration &lt;/em&gt;template and click the Add button. Note, leave the name as &lt;em&gt;app.config&lt;/em&gt; Visual Studio will automatically rename this file and copy it to the Bin folder when you build the project. To be able to read the config file you need to add a reference to &lt;em&gt;System.Configuration.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;I will not go into the details of using an app.config file but in short you need to add an &amp;lt;&lt;em&gt;appSettings&amp;gt;&lt;/em&gt; section under the &amp;lt;&lt;em&gt;configuration&lt;/em&gt;&amp;gt; node under which you add your own settings.&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a31515;"&gt;xml &lt;/span&gt;&lt;span style="color:red;"&gt;version&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color:blue;"&gt;1.0&lt;/span&gt;&amp;quot; &lt;span style="color:red;"&gt;encoding&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color:blue;"&gt;utf-8&lt;/span&gt;&amp;quot; &lt;span style="color:blue;"&gt;?&amp;gt;
&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;configuration&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;
  &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;appSettings&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;
&lt;/span&gt;&lt;span style="color:blue;"&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;add &lt;/span&gt;&lt;span style="color:red;"&gt;key&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color:blue;"&gt;emailSubject&lt;/span&gt;&amp;quot; &lt;span style="color:red;"&gt;value&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color:blue;"&gt;Can somebody remove this file please?&lt;/span&gt;&amp;quot; &lt;span style="color:blue;"&gt;/&amp;gt;
    &amp;lt;!-- 
      &lt;/span&gt;&lt;span style="color:green;"&gt;more settings go here…
    &lt;/span&gt;&lt;span style="color:blue;"&gt;--&amp;gt; &lt;/span&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;You can then read these values using the &lt;em&gt;ConfigurationManager.AppSettings() &lt;/em&gt;method (this requires that you have imported the &lt;em&gt;System.Configuration &lt;/em&gt;namespace which we set a reference to earlier).&lt;/p&gt;

&lt;p&gt;In my service I added a private method which I simply called &lt;em&gt;ReadSettings.&lt;/em&gt; I will not show you all of that code since it’s mainly boiler plate, but a part of it looks like this:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;Private Function &lt;/span&gt;ReadSettings(&lt;span style="color:blue;"&gt;ByRef &lt;/span&gt;logMessage &lt;span style="color:blue;"&gt;As String&lt;/span&gt;) &lt;span style="color:blue;"&gt;As Boolean
  Dim &lt;/span&gt;emailRecipients &lt;span style="color:blue;"&gt;As String&lt;/span&gt;()
  _eMailTo = &lt;span style="color:blue;"&gt;New &lt;/span&gt;List(&lt;span style="color:blue;"&gt;Of String&lt;/span&gt;)
  &lt;span style="color:blue;"&gt;Try
    &lt;/span&gt;emailRecipients = ConfigurationManager.AppSettings(&lt;span style="color:#a31515;"&gt;&amp;quot;emailTo&amp;quot;&lt;/span&gt;).Split(&lt;span style="color:#a31515;"&gt;&amp;quot;;&amp;quot;c&lt;/span&gt;)
  &lt;span style="color:blue;"&gt;Catch &lt;/span&gt;ex &lt;span style="color:blue;"&gt;As &lt;/span&gt;Exception
    logMessage = _&lt;br /&gt;      &lt;span style="color:#a31515;"&gt;&amp;quot;No e-mail recipients with valid e-mails found, &lt;span style="color:#a31515;"&gt;&amp;quot; &amp;amp; _&lt;br /&gt;       &lt;span style="color:#a31515;"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;edit &amp;quot;&amp;quot;emailTo&amp;quot;&amp;quot; in the config file.&amp;quot;
    &lt;/span&gt;&lt;span style="color:blue;"&gt;Return False
  End Try
  For Each &lt;/span&gt;email &lt;span style="color:blue;"&gt;In &lt;/span&gt;emailRecipients
    email = email.Trim
    &lt;span style="color:blue;"&gt;If Not String&lt;/span&gt;.IsNullOrEmpty(email) &lt;span style="color:blue;"&gt;AndAlso &lt;/span&gt;IsValidEmail(email) &lt;span style="color:blue;"&gt;Then
      &lt;/span&gt;_eMailTo.Add(email)
    &lt;span style="color:blue;"&gt;End If
  Next
  If &lt;/span&gt;_eMailTo.Count = 0 &lt;span style="color:blue;"&gt;Then
    &lt;/span&gt;logMessage = &lt;span style="color:#a31515;"&gt;&amp;quot;No e-mail recipients with valid e-mails found.&amp;quot;
    &lt;/span&gt;&lt;span style="color:blue;"&gt;Return False
  End If
  Try
    &lt;/span&gt;_subject = ConfigurationManager.AppSettings(&lt;span style="color:#a31515;"&gt;&amp;quot;emailSubject&amp;quot;&lt;/span&gt;)
  &lt;span style="color:blue;"&gt;Catch &lt;/span&gt;ex &lt;span style="color:blue;"&gt;As &lt;/span&gt;Exception
    logMessage = &lt;span style="color:#a31515;"&gt;&amp;quot;No e-mail subject found&amp;quot;
    &lt;/span&gt;_subject = &lt;span style="color:blue;"&gt;String&lt;/span&gt;.Empty
  &lt;span style="color:blue;"&gt;End Try
&lt;/span&gt;&lt;span style="color:blue;"&gt;  &lt;/span&gt;&lt;span style="color:green;"&gt;&amp;#39;read the rest of the settings
  &lt;/span&gt;&lt;span style="color:blue;"&gt;Return True
End Function&lt;/span&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;This method takes a parameter, &lt;em&gt;logMessage&lt;/em&gt;, by reference. In some cases, for example with the e-mail subject, it is allowed to leave that out of the config file and the application will simply send the e-mail without a subject. Other settings, like the address or addresses to send the e-mail to is required. The &lt;em&gt;ReadSettings &lt;/em&gt;method will return False if some required setting was not found, or in the wrong format. The actual writing to the log is done by the &lt;em&gt;OnStart&lt;/em&gt; method, or rather it’s done by another small helper method that is called by the OnStart method.&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;Private Sub &lt;/span&gt;WriteLogMessage(&lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;message &lt;span style="color:blue;"&gt;As String&lt;/span&gt;, _&lt;br /&gt;                            &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;type &lt;span style="color:blue;"&gt;As &lt;/span&gt;EventLogEntryType)
  &lt;span style="color:blue;"&gt;If Not &lt;/span&gt;EventLog.SourceExists(&lt;span style="color:#a31515;"&gt;&amp;quot;File Observer&amp;quot;&lt;/span&gt;) &lt;span style="color:blue;"&gt;Then
    &lt;/span&gt;EventLog.CreateEventSource(&lt;span style="color:#a31515;"&gt;&amp;quot;File Observer&amp;quot;&lt;/span&gt;, &lt;span style="color:#a31515;"&gt;&amp;quot;File Observer Log&amp;quot;&lt;/span&gt;)
  &lt;span style="color:blue;"&gt;End If
  Dim &lt;/span&gt;log &lt;span style="color:blue;"&gt;As New &lt;/span&gt;EventLog()
  log.Source = &lt;span style="color:#a31515;"&gt;&amp;quot;File Observer&amp;quot;
  &lt;/span&gt;log.WriteEntry(message, type)
&lt;span style="color:blue;"&gt;End Sub&lt;/span&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;I put all validation rules in the &lt;em&gt;ReadSettings()&lt;/em&gt; method so that when it’s time to send the e-mail, I know that I have e-mail addresses that are valid (or rather, that they have a valid form, not that I can check if the address itself really exists), and that the SMTP IP port is set to a valid integer and so on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The OnStart() and OnEnd() methods&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Even though you can override the constructor of the &lt;em&gt;ServiceBase&lt;/em&gt; control, you shouldn’t really put initialization code there. This is because if the service is stopped and then restarted the constructor is not called again, but the &lt;em&gt;OnStart()&lt;/em&gt; method is. So initialization should go into that method.&lt;/p&gt;

&lt;p&gt;In my very specific case, I used a &lt;em&gt;FileSystemWatcher&lt;/em&gt; to monitor the specified folder for the creation of the specified file. If the &lt;em&gt;ReadSettings()&lt;/em&gt; method returned True I started monitoring the folder. If not I needed a way to stop the service from starting and write an error message to the event viewer. Unfortunately the &lt;em&gt;OnStart()&lt;/em&gt; method does not have a way of signaling an error, so what you need to do is to call the &lt;em&gt;SetServiceStatus()&lt;/em&gt; function which is a Win32 API function. Import the &lt;em&gt;System.Runtime.InteropServices &lt;/em&gt;namespace and add the following code to your class.&lt;/p&gt;

&lt;pre class="code"&gt;&amp;lt;StructLayout(LayoutKind.Sequential)&amp;gt; _
&lt;span style="color:blue;"&gt;Public Structure &lt;/span&gt;SERVICE_STATUS
  &lt;span style="color:blue;"&gt;Public &lt;/span&gt;serviceType &lt;span style="color:blue;"&gt;As Integer
  Public &lt;/span&gt;currentState &lt;span style="color:blue;"&gt;As Integer
  Public &lt;/span&gt;controlsAccepted &lt;span style="color:blue;"&gt;As Integer
  Public &lt;/span&gt;win32ExitCode &lt;span style="color:blue;"&gt;As Integer
  Public &lt;/span&gt;serviceSpecificExitCode &lt;span style="color:blue;"&gt;As Integer
  Public &lt;/span&gt;checkPoint &lt;span style="color:blue;"&gt;As Integer
  Public &lt;/span&gt;waitHint &lt;span style="color:blue;"&gt;As Integer
End Structure

Public Enum &lt;/span&gt;State
  SERVICE_STOPPED = &amp;amp;H1
  SERVICE_START_PENDING = &amp;amp;H2
  SERVICE_STOP_PENDING = &amp;amp;H3
  SERVICE_RUNNING = &amp;amp;H4
  SERVICE_CONTINUE_PENDING = &amp;amp;H5
  SERVICE_PAUSE_PENDING = &amp;amp;H6
  SERVICE_PAUSED = &amp;amp;H7
&lt;span style="color:blue;"&gt;End Enum &lt;/span&gt;&lt;span style="color:green;"&gt;

&lt;/span&gt;&lt;span style="color:blue;"&gt;Private Declare Auto Function &lt;/span&gt;SetServiceStatus &lt;span style="color:blue;"&gt;Lib &lt;/span&gt;&lt;span style="color:#a31515;"&gt;&amp;quot;ADVAPI32.DLL&amp;quot; &lt;/span&gt;( _
    &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;hServiceStatus &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr, _
    &lt;span style="color:blue;"&gt;ByRef &lt;/span&gt;lpServiceStatus &lt;span style="color:blue;"&gt;As &lt;/span&gt;SERVICE_STATUS _
) &lt;span style="color:blue;"&gt;As Boolean&lt;br /&gt;
Private &lt;/span&gt;_serviceStatus &lt;span style="color:blue;"&gt;As &lt;/span&gt;SERVICE_STATUS&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;So the following is the code I used in the &lt;em&gt;OnStart() &lt;/em&gt;method.&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;Protected Overrides Sub &lt;/span&gt;OnStart(&lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;args() &lt;span style="color:blue;"&gt;As String&lt;/span&gt;)
  &lt;span style="color:blue;"&gt;Dim &lt;/span&gt;handle &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr = &lt;span style="color:blue;"&gt;Me&lt;/span&gt;.ServiceHandle
  _serviceStatus.currentState = Fix(State.SERVICE_START_PENDING)
  SetServiceStatus(handle, _serviceStatus)
  &lt;span style="color:blue;"&gt;Dim &lt;/span&gt;logMessage &lt;span style="color:blue;"&gt;As String &lt;/span&gt;= &lt;span style="color:blue;"&gt;String&lt;/span&gt;.Empty
  &lt;span style="color:blue;"&gt;If Not &lt;/span&gt;ReadSettings(logMessage) &lt;span style="color:blue;"&gt;Then
    &lt;/span&gt;WriteLogMessage(logMessage, EventLogEntryType.Error)
    _serviceStatus.currentState = Fix(State.SERVICE_STOPPED)
    SetServiceStatus(handle, _serviceStatus)
  &lt;span style="color:blue;"&gt;Else
    If Not String&lt;/span&gt;.IsNullOrEmpty(logMessage) &lt;span style="color:blue;"&gt;Then
      &lt;/span&gt;WriteLogMessage(logMessage, EventLogEntryType.Information)
    &lt;span style="color:blue;"&gt;End If
    &lt;/span&gt;&lt;span style="color:green;"&gt;&amp;#39;Start the file watching...
    &lt;/span&gt;&lt;span style="color:blue;"&gt;With &lt;/span&gt;FileSystemWatcher1
      .BeginInit()
      .Filter = _fileMask
      .IncludeSubdirectories = _includeSubFolders
      .Path = _folderName
      .EnableRaisingEvents = &lt;span style="color:blue;"&gt;True
      &lt;/span&gt;.EndInit()
      _serviceStatus.currentState = Fix(State.SERVICE_RUNNING)
      SetServiceStatus(handle, _serviceStatus)
    &lt;span style="color:blue;"&gt;End With
  End If
End Sub&lt;/span&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;So if everything works out the way it should I start the FileSystemWatcher by setting its &lt;em&gt;EnableRaisingEvents &lt;/em&gt;property to True. In the &lt;em&gt;OnStop()&lt;/em&gt; method I simply set this property to False to disable it.&lt;/p&gt;

&lt;p&gt;When the FileSystemWatcher finds that the file that is being watched is created it raises the &lt;em&gt;Created()&lt;/em&gt; event, in which I start a new thread that will simply sleep for the specified number of seconds and then check if the file still exists. If it does it sends the e-mail.&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;Private Sub &lt;/span&gt;FileSystemWatcher1_Created( _
    &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;sender &lt;span style="color:blue;"&gt;As Object&lt;/span&gt;, _
    &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;e &lt;span style="color:blue;"&gt;As &lt;/span&gt;System.IO.FileSystemEventArgs) &lt;span style="color:blue;"&gt;Handles &lt;/span&gt;FileSystemWatcher1.Created
  &lt;span style="color:blue;"&gt;If &lt;/span&gt;e.ChangeType = IO.WatcherChangeTypes.Created &lt;span style="color:blue;"&gt;Then
    Dim &lt;/span&gt;thread &lt;span style="color:blue;"&gt;As New &lt;/span&gt;Threading.Thread(&lt;span style="color:blue;"&gt;AddressOf &lt;/span&gt;WatchFile)
    thread.Start(e.FullPath)
  &lt;span style="color:blue;"&gt;End If
End Sub

Private Sub &lt;/span&gt;WatchFile(&lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;fullPath &lt;span style="color:blue;"&gt;As Object&lt;/span&gt;)
  &lt;span style="color:blue;"&gt;Dim &lt;/span&gt;fileName &lt;span style="color:blue;"&gt;As String &lt;/span&gt;= &lt;span style="color:blue;"&gt;CStr&lt;/span&gt;(fullPath)
  Threading.Thread.Sleep(_delayTime * 1000)
  &lt;span style="color:blue;"&gt;If &lt;/span&gt;IO.File.Exists(fileName) &lt;span style="color:blue;"&gt;Then
    &lt;/span&gt;SendMail()
  &lt;span style="color:blue;"&gt;End If
End Sub&lt;/span&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;Private Sub &lt;/span&gt;SendMail()
  &lt;span style="color:blue;"&gt;Dim &lt;/span&gt;mail &lt;span style="color:blue;"&gt;As New &lt;/span&gt;System.Net.Mail.MailMessage
  &lt;span style="color:blue;"&gt;For Each &lt;/span&gt;email &lt;span style="color:blue;"&gt;In &lt;/span&gt;_eMailTo
    mail.To.Add(&lt;span style="color:blue;"&gt;New &lt;/span&gt;Net.Mail.MailAddress(email))
  &lt;span style="color:blue;"&gt;Next
  &lt;/span&gt;mail.From = &lt;span style="color:blue;"&gt;New &lt;/span&gt;Net.Mail.MailAddress(_emailFrom)
  mail.Subject = _subject
  mail.Body = _body
  &lt;span style="color:blue;"&gt;Dim &lt;/span&gt;smtpClient &lt;span style="color:blue;"&gt;As New &lt;/span&gt;Net.Mail.SmtpClient(_smtpHost)
  &lt;span style="color:blue;"&gt;With &lt;/span&gt;smtpClient
    .Port = _smtpPort
    &lt;span style="color:blue;"&gt;If &lt;/span&gt;_requireAuthentication &lt;span style="color:blue;"&gt;Then
      &lt;/span&gt;.Credentials = &lt;span style="color:blue;"&gt;New &lt;/span&gt;Net.NetworkCredential(_authenticateName, _&lt;br /&gt;                                               _authenticatePassword)
    &lt;span style="color:blue;"&gt;End If
    Try
      &lt;/span&gt;.Send(mail)
    &lt;span style="color:blue;"&gt;Catch &lt;/span&gt;ex &lt;span style="color:blue;"&gt;As &lt;/span&gt;Exception
      WriteLogMessage(&lt;span style="color:#a31515;"&gt;&amp;quot;Unable to send mail: &amp;quot; &lt;/span&gt;&amp;amp; ex.Message, _&lt;br /&gt;                      EventLogEntryType.Error)
    &lt;span style="color:blue;"&gt;End Try
  End With
End Sub&lt;/span&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;&lt;strong&gt;Adding an installer to the project&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Since this is a Windows Service it has to be installed as such so that it’s listed in the Service control panel applet. So you need to add an installer to the project. Note that this installer is not the same thing as a setup program, it will just add the necessary code that allows this application to be installed as a service using the &lt;em&gt;InstallUtil.exe&lt;/em&gt; command line tool that comes with the .Net framework. More about that tool in a second.&lt;/p&gt;

&lt;p&gt;To add an installer select your &lt;em&gt;ServiceBase&lt;/em&gt; designer and right click on its surface and select &lt;em&gt;Add Installer&lt;/em&gt; in the context menu. This will add a new &lt;em&gt;Installer&lt;/em&gt; designer to your project that contains two component, a &lt;em&gt;ServiceInstaller&lt;/em&gt; and a &lt;em&gt;ServiceProcessInstaller.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Select the &lt;em&gt;ServiceInstaller&lt;/em&gt; and change its &lt;em&gt;DisplayName&lt;/em&gt; property. This will be the name that is listed in the control panel applet. You can also change the &lt;em&gt;StartType&lt;/em&gt; property to &lt;em&gt;Automatic&lt;/em&gt; if you want your service to start directly after it has been installed. In my case I left that property as &lt;em&gt;Manual.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now select the &lt;em&gt;ServiceProcessInstaller&lt;/em&gt; and set the &lt;em&gt;Account&lt;/em&gt; property to &lt;em&gt;LocalSystem&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;That’s it. You can now build the project. To do the installation open up a Visual Studio Command Prompt and type:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;InstallUtil c:\thePath\theNameOfYourAssembly.exe&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And presto! Your service should now be listed among the others in the Services control panel applet. Try to start and stop it from there. If you want to uninstall the service, which you must do if you need to make some changes to the source code, then type the following at the command prompt.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;InstallUtil /u c:\thePath\theNameOfYourAssembly.exe&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Even though this was a Windows Service with some very specific requirements I hope that this article have answered some questions on how you can create your own services.&lt;/p&gt;

&lt;p&gt;Have fun!&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1722980" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/joacim/archive/tags/vb/default.aspx">vb</category><category domain="http://msmvps.com/blogs/joacim/archive/tags/visual+basic/default.aspx">visual basic</category><category domain="http://msmvps.com/blogs/joacim/archive/tags/windows+service/default.aspx">windows service</category></item></channel></rss>