Καλώς ορίσατε στο dotNETZone.gr - Σύνδεση | Εγγραφή | Βοήθεια

Creating a simple, reusable Windows Service (template code) - Part II

Part II

In part I, we examined how we can extend the Service Control methods by adding methods for all states of the Windows service in addition to the two methods provided by the designer. As you may remember, each of those methods called our own private Service Control method. Our private Service Control methods are implemented below:

Implementing our own Service Control methods



#Region " Implementation of Service Related Methods "

    '/// <summary>
    '/// Service Start.
    '/// </summary>
    Private Sub ServiceStart()

        'Create event log
        If Me.s_logMain Is Nothing Then
            Me.s_logMain = New EventLog("APPLICATION", ".", Me.m_strServiceName)
        End If

        'If the status is PAUSE
        If Me.s_enumMode = mdlGlobals.ServiceModeEnum.MODE_PAUSE Then

            'Resume main thread
            Me.s_thrdMaster.Resume()

            'Set Status
            Me.s_enumMode = mdlGlobals.ServiceModeEnum.MODE_RUN

        Else

            'Set Status
            Me.s_enumMode = mdlGlobals.ServiceModeEnum.MODE_RUN

            'Start Main Processing Thread
            Me.s_thrdMaster.Start()

        End If

    End Sub

Our ServiceStart() method does exactly what it says: It starts the service. Remember that this method is called by the OnStart() overriden Service method, so it does what it does whenever OnStart() runs. That is, whenever the service is started or resumed from Pause.

The first thing this method does is to write something to the Event Log so that we know that the service has started. Then, it checks the status using the s_enumMode variable (mdlGlobals.ServiceModeEnum). Essentially, the variable at this point can have the value MODE_PAUSE or the value MODE_STOP or the value MODE_SHUTDOWN. If the value of the variable is MODE_PAUSE, then we can assume that the service is entering run mode from a pause state (which means that our main thread of execution has been paused, as you'll see below) and so we resume the main thread. In any other case, we can safely assume that our main thread has not been started so we just start it. In both cases, what we must do afterwards is to set the variable to MODE_RUN to indicate that our service is running.

Let's see now how we should implement the ServiceStop() method, called by the OnStop() overriden service method:



    '/// <summary>
    '/// Service Stop.
    '/// </summary>
    Private Sub ServiceStop()

        'Terminate Master thread
        If Me.s_thrdMaster.IsAlive = True Then

            'If the thread is suspended, resume it before aborting
            If Me.s_enumMode = mdlGlobals.ServiceModeEnum.MODE_PAUSE Then
                Try
                    Me.s_thrdMaster.Resume()
                Catch
                End Try
            End If

            'Abort Master thread
            Me.s_thrdMaster.Abort()

            'This is needed in case we have other threads, but no harm done if we leave it
            Me.s_thrdMaster.Join()

        End If

        'Set Status
        Me.s_enumMode = mdlGlobals.ServiceModeEnum.MODE_STOP

    End Sub

Here we check if we have a "live" main thread. If so, we must abort it. Because we don't really know what the thread's status is, we must check whether the thread is paused or active. We can do so by checking the value of the s_enumMode variable. If the value is MODE_PAUSE, then we can safely assume that our thread has been paused (as you'll see below), and what we must do is to resume it and kill it immediately afterwards. (Not a very good way, I'm open to better ones). In all other cases, we don't need to do something else. After this check, we just abort the main thread and (this is optional) wait for any other threads to finish. When it's all done, we set the value of the s_enumMode variable to MODE_STOP so that our methods will know the service's current status.

Let's see the remaining methods now:



    '/// <summary>
    '/// Service Restore
    '/// </summary>
    Private Sub ServiceContinue()

        'Resume Master thread
        If Me.s_thrdMaster.IsAlive = True Then
            Me.s_thrdMaster.Resume()
        End If

        'Set Operational Mode
        Me.s_enumMode = mdlGlobals.ServiceModeEnum.MODE_RUN

    End Sub

    '/// <summary>
    '/// Service Pause
    '/// </summary>
    Private Sub ServicePause()

        Try

            'Pause Master thread
            If Me.s_thrdMaster.IsAlive = True Then
                Me.s_thrdMaster.Suspend()
            End If

            'Set Operational Mode
            Me.s_enumMode = mdlGlobals.ServiceModeEnum.MODE_PAUSE

        Catch ex As Exception

            'TODO: Error handling

        End Try

    End Sub

    '/// <summary>
    '/// Service Shutdown
    '/// </summary>
    Private Sub ServiceShutdown()

        'Set Operational Mode
        Me.s_enumMode = mdlGlobals.ServiceModeEnum.MODE_SHUTDOWN

        'Do some sleep
        Thread.CurrentThread.Sleep(1000)

        'Terminate Master thread (in any case)
        If Me.s_thrdMaster.IsAlive = True Then
            Me.s_thrdMaster.Abort()
            Me.s_thrdMaster.Join()
        End If

    End Sub

#End Region

As you can see, we follow the same idea with the other methods, i.e. handling the main thread and setting the correct value to the control variable. An interesting note is that we pause for a second when we shut down the service to give time to the main thread to finish what it's doing. The period of time we should pause depends on what the main thread is actually doing. Remember, the s_enumMode variable WILL be visible from our main thread, so the thread can possibly check the value of the variable and decide what it should do itself. In this example, the service control methods handle the status of the main thread, but that can be possibly handled by another thread if we extend the code, leaving to the control methods only the responsibility to set the appropriate value to the s_enumMode variable. (Which is more correct, by the way, because in the current implemenation our methods will brutally abort/pause/stop the thread when they need to, something which can prove risky in certain situations).

Conclusion

Having done all of the above, we have created a simple Windows service with a main thread which can be paused and aborted when the service is paused and stopped / shut down. Not much of a safe logic here, but remember that this is only an example. What you can do from now on is to create your own assembly, and hook its entry point to your main thread which will be repeating itself once in a while. (See the code for the main thread and assign your own period of time). Of course you can create a more complex (and safer) logic for controlling the thread and I will be more than happy to see your own examples.

kick it on DotNetKicks.com

 

 

 

Έχουν δημοσιευτεί Δευτέρα, 3 Οκτωβρίου 2005 12:13 μμ από το μέλος cap
Δημοσίευση στην κατηγορία:

Ενημέρωση για Σχόλια

Αν θα θέλατε να λαμβάνετε ένα e-mail όταν γίνονται ανανεώσεις στο περιεχόμενο αυτής της δημοσίευσης, παρακαλούμε γίνετε συνδρομητής εδώ

Παραμείνετε ενήμεροι στα τελευταία σχόλια με την χρήση του αγαπημένου σας RSS Aggregator και συνδρομή στη Τροφοδοσία RSS με σχόλια

Σχόλια:

# Απ: Creating a simple, reusable Windows Service (template code) - Part II

Τετάρτη, 26 Οκτωβρίου 2005 3:19 μμ by axaros
Σωτήρη δεν προσθέτεις και ένα μικρό part 3 που να αναφέρεις τις διαδικασίες setup του service;

Πάνος

# Απ: Creating a simple, reusable Windows Service (template code) - Part II

Δευτέρα, 31 Οκτωβρίου 2005 11:57 πμ by cap
Χμ, Πανο έχεις δίκιο. Βεβαια, οι διαδικασίες setup αυτού ή οποιουδήποτε άλλου service είναι σχετικά σταθερές και δεν αφορούν τη συγκεκριμένη μόνο υλοποίηση. Θα επιχειρήσω κάτι μολις βρω λίγο χρόνο.

# Creating a simple, reusable Windows Service (template code) - Part II

Τρίτη, 2 Ιανουαρίου 2007 6:34 μμ by DotNetKicks.com
You've been kicked (a good thing) - Trackback from DotNetKicks.com

# Creating a simple, reusable Windows Service (template code) - Part I

Παρασκευή, 5 Ιανουαρίου 2007 11:39 πμ by Sotiris Filippidis' Weblog
In this article, we'll see a way to create a simple Windows Service that can be reusable in that it can...

Ποιά είναι η άποψή σας για την παραπάνω δημοσίευση;

(απαιτούμενο) 
απαιτούμενο 
(απαιτούμενο) 
Εισάγετε τον κωδικό:
CAPTCHA Image