C# 2005 Windows Service says is starting, but EventLog.WriteEntry() doesn't show

I have written Windows Services before, both in 2005 and in 2003, but I can't see what I'm missing.

I have a thin Windows Service that does little more than load an XML file for config options and then an external assembly which I've independantly tested.

After creating the new project with a Windows Service, and adding a timer and and installer, I have had so much difficulty figuring out what is not working that I have commented out everything but the OnStart and OnStop commands to EventLog.WriteEntry a message, essentially saying "I'm here".  But every time I reinstall my Service and start it up in the Services app, it immediately stops, and I do not get my custom EventLog entries.  I just get the default "The MultiFTP service was successfully sent a start control." messages.

Where do I need to go from here?

UPDATE:

As usual, I finally managed to get the basics to work.  Somehow though I added both the serviceInstaller and the serviceProcessIntaller, only one was shown as being added to the Installers.AddRange() method.  I do not know if this fixed my problem, because it didn't work at first, but when I cleared my events in the events viewer, suddenly it started to work for me.

I don't know why.

But now I have a different problem.  I am using a System.Windows.Forms.Timer control which supposedly fires off an event to an event handler.  But though I have a delegate method assigned to that event handler, when I attach to the process and put a breakpoint on that method, it never fires.  

I need help....

Here's the code.

using System;

namespace ServiceMultiFTP
{
    partial class ServiceMultiFTP
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        private void LoadConfig()
        {
            try
            {
                //Config.xml contains various configration options for the service.
                System.Xml.XmlDocument config = new System.Xml.XmlDocument();

                //Config.xml must be set as "Copy to output directory" in properties.
                config.Load(AppDomain.CurrentDomain.BaseDirectory + "Config.xml");

                this.timerMultiFTP.Interval = Convert.ToInt32(config.SelectSingleNode("//Config/Timer/IntervalInMinutes").InnerText) * 1000 * 60;

                this.EventLog.WriteEntry("Loaded Config.xml.  Interval set to " + this.timerMultiFTP.Interval.ToString() + " milliseconds.");
            }
            catch (Exception FileMissing)
            {
                this.timerMultiFTP.Interval = 1000;//600000;
                this.EventLog.WriteEntry("Missing config file Config.xml.  Interval set to " + this.timerMultiFTP.Interval.ToString() + " milliseconds.");
            }
        }

        #region Component Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.timerMultiFTP = new System.Windows.Forms.Timer(this.components);
            //
            // timerMultiFTP
            //
            this.timerMultiFTP.Interval = 1000;
            this.timerMultiFTP.Tick += new System.EventHandler(this.timerMultiFTP_Tick);
            this.timerMultiFTP.Disposed += new System.EventHandler(this.timerMultiFTP_Disposed);
            //
            // ServiceMultiFTP
            //
            this.AutoLog = false;
            this.CanPauseAndContinue = true;
            this.ServiceName = "ServiceMultiFTP";

        }

        #endregion

        private System.Windows.Forms.Timer timerMultiFTP;
    }
}


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using System.Text;

namespace ServiceMultiFTP
{
    public partial class ServiceMultiFTP : ServiceBase
    {
        public ServiceMultiFTP()
        {
            InitializeComponent();
        }

        /// <summary>
        /// This will attempt to find a config file called Config.xml, but
        /// failing that it will simply use default values.
        /// </summary>
        /// <param name="args"></param>
        protected override void OnStart(string[] args)
        {
            this.EventLog.WriteEntry("MultiFTP has started, dude!");
            LoadConfig();
            this.timerMultiFTP.Enabled = true;
        }

        protected override void OnStop()
        {
            this.EventLog.WriteEntry("MultiFTP has stopped, dude.");

            this.timerMultiFTP.Enabled = false;
        }

        private void timerMultiFTP_Tick(object sender, EventArgs e)
        {
            timerMultiFTP.Stop();

            this.EventLog.WriteEntry("MultiFTP cycle begun, checking for reports");

            MultiFTP.AutomatedProcessMain TheAutomatedApp = new MultiFTP.AutomatedProcessMain();

            TheAutomatedApp.RunMain();

            timerMultiFTP.Start();
        }

        private void timerMultiFTP_Disposed(object sender, EventArgs e)
        {
            this.EventLog.WriteEntry("timerMultiFTP disposed.");
        }
    }
}


Now that the installers are correctly starting and stopping the service, I'll assume that the installer code is not necessary.

V
VSmirkAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

cookreCommented:
Debug mode breakpoints in a service?

Services run in a very different environment from regular windowed executables.  Unless the service is typed  win32 own, interactive, and run under the system local security context, there will be no interaction with any window and no message pump to receive windows messages.  Even then, not all windows messages are received by the pump, and no shell messages are.

That may also be why the timer doesn't seem to work.  I'd guess the Winforms timer uses the underlying, old way of using the message queue to pass timer events (which won't work if the service isn't interactive, even them, I'm not sure they'd work).  Use System.Timers instead.

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
VSmirkAuthor Commented:
Absolutely debug mode breakpoints in a service!

One of the best features of .Net 2005 (though I don't know for a fact that you couldn't do it earlier).  When your service is installed and running, you can go back to your IDE and "attach to a process" and find your running service there.  As far as I know, you can't do it quickly enough to get to a breakpoint in the OnStart, unless you put a delay in that block, but in other Windows Services, I have been able to put breakpoints on all of the other methods, like FileSystemWatcher event handlers, OnStop() and many others.  This is the first time using the timer control, though.

To that end, the reason I am using the timer I am is because that's the one that is provided by default in the Toolbox.  

Does the System.Timers control have the same interface?
VSmirkAuthor Commented:
Regardless, though, it looks like your suggestion to change the timer control did the trick.  I had to re-do some of the delegation, but it appears to work like a charm.  When I attach to the process in debug mode and put a breakpoint on the timer event handler, I came back around the time I hoped to see the event fired, and lo' there was the bright yellow break point line on my windows service!

Thanks for the help!

V
cookreCommented:
Dunno, I don't use the winforms one.  Here's a sample:

System.Timers.Timer  STimer;

...

STimer=new System.Timers.Timer();
STimer.Elapsed+=new ElapsedEventHandler(STimerTriggered);
STimer.Interval=500;
STimer.Enabled=true;



void STimerTriggered(object source,ElapsedEventArgs evt)
{
STimer.Enabled=false; // Leave us not interrupt ourselves
...
STimer.Enabled=true; // Leave us not interrupt ourselves
}



I've never had any problems in either a normal service or an interactive one.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C#

From novice to tech pro — start learning today.