2

Apologies for my English, I'm not a native speaker.

I'm trying to make a Windows service. If I try to build, install and run a VS template I don't get any errors.

I have ported my winform application to a service, made an installer, added some data sources, added a reference for the webservice, added some classes, but DIDN'T add any code to OnStart() and OnStop(). My code builds correctly and I can start and stop the service from the service manager.

However, if I add some code to the service class (which I don't call anywhere) and if I don't add code to OnStart() and to OnStop() then I can't start the service and the error is something like "The service doesn't respond the control functions". In the event log I can see the exception:

  System.ArgumentOutOfRangeException
Stack:
 in System.String.InternalSubStringWithChecks(Int32, Int32, Boolean)
 in System.String.Substring(Int32, Int32)
 in UpdaterFIAS.FIASMainClass.getNameFile(System.String, System.String, System.String)
 in UpdaterFIAS.FIASMainClass..ctor()
 in UpdaterFIAS.Updater..ctor()
 in UpdaterFIAS.Program.Main()

And I can see here my function getNameFile() is throwing an Exception. However, this isn't called in my code because I have empty OnStart(). So, how can I find what went wrong if the event log doesn't write anything ( if it is in the OnStart() ) ? And I can't attach a debugger to it because it throws this exception.

edit: Forgot to say, my code works correctly when I use windows forms but here I don't call anything in OnStart, the project builds without errors but I have an exception when starting the service.

EDIT 2: Program.cs code:

namespace UpdaterFIAS
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        static void Main()
        {
            ServiceBase[] ServicesToRun;
            ServicesToRun = new ServiceBase[] 
            { 
                new Updater() 
            };
            ServiceBase.Run(ServicesToRun);
        }
    }
}

Updater.cs code:

namespace UpdaterFIAS
{
    public partial class Updater : ServiceBase
    {
        public Updater()
        {
            InitializeComponent();
            if (!System.Diagnostics.EventLog.SourceExists("MySource"))
            {
                System.Diagnostics.EventLog.CreateEventSource("MySource", "MyNewLog");
            }
            eventLog1.Source = "MySource";
            eventLog1.Log = "MyNewLog";
        }

        FIASMainClass mainFIAS = new FIASMainClass();

        protected override void OnStart(string[] args)
        {
            //timer1 = new System.Timers.Timer(5000);
            //timer1.Elapsed += timer1_Elapsed;
            //timer1.AutoReset = false;
            //timer1.Enabled = true;

            //ServiceStarterThread = new Thread(ServiceStarter);
            //ServiceStarterThread.Start();

            eventLog1.WriteEntry("In OnStart");
            //mainFIAS.Start();
        }

        protected override void OnStop()
        {
            //if (updater != null && (updater.ThreadState != System.Threading.ThreadState.Aborted && updater.ThreadState != System.Threading.ThreadState.Stopped)) updater.Abort();
            //if (log != null && (log.ThreadState != System.Threading.ThreadState.Aborted && log.ThreadState != System.Threading.ThreadState.Stopped)) log.Abort();

            //log.Abort();
            //timer1.Enabled = false;
            //timer1.Dispose();

            eventLog1.WriteEntry("In OnStop");
            //mainFIAS.Stop();
        }
    }
}

EDIT 3: FIASMainClass.cs code:

        namespace UpdaterFIAS
        {
            class FIASMainClass
            {
                public FIASMainClass()
                { }

                public void Start()
                {
                    ServiceStarterThread = new Thread(ServiceStarter);
                    ServiceStarterThread.Start();
                }

                public void Stop()
                {
                    if (updater != null && (updater.ThreadState != System.Threading.ThreadState.Aborted && updater.ThreadState != System.Threading.ThreadState.Stopped)) updater.Abort();
                    if (log != null && (log.ThreadState != System.Threading.ThreadState.Aborted && log.ThreadState != System.Threading.ThreadState.Stopped)) log.Abort();
                }

                private void ServiceStarter()
                {
                ...
                }
    ...
    ...
    ...
    }
}
HackSaw
  • 201
  • 1
  • 3
  • 12
  • Is that all of the code for `FIASMainClass`? Are there no data members? – Philip Pittle Jul 14 '14 at 13:01
  • There are lots of data members, but I'm restricted to publish all code. The code is correct (everything works in the winform app) and I've looked for all occurances of getNameFile, it isn't called in any initialization or directly. So I can't understand why the stack trace shows this to me. I rebuild, clean, uninstall the service, install again (not in this order) - always the same exception. – HackSaw Jul 14 '14 at 13:08
  • Ok, then another avenue of investigation. Where is getNameFiles() called from? – Philip Pittle Jul 16 '14 at 08:10
  • I solved my problem. It really was connected with getNameFiles(). When I was examining my code for getNameFiles calls, I found the place in the big list of variables and structures defenition where one of the variable is initialized with constructor which gets getNameFiles as parameter. It was very strange and I don't know how it appeared there :) Anyway, thaks for your answers. – HackSaw Jul 16 '14 at 15:39
  • Glad you found out. The stack trace is usually pretty good about telling you where the problem is, although it can be a huge pain in the ass to find out where the transitions occur. Although, I just thought of this now. If you compile in 'debug' mode, the stack trace should include line numbers, which will make it far easier to find the offending line. – Philip Pittle Jul 16 '14 at 16:15

1 Answers1

0

From you Stack Trace, the entry point is Program.Main. From there a new Updater is created and the getNameFiles is called. That would be the place to start.

As far as Debugging a windows service. You are right, this is indeed hard. There are two tricks I know. The first one is in the Main (or OnStart) to set a Thread.Sleep before you do anything. This way you have time to attach your debugger.

The other trick, is if your Visual Studio is on the same machine as your service, in the Main (or OnStart) add this line: Debugger.Launch(). This will tell the service to seek out Visual Studio for a debugging session. See here for more: Debugger.Launch() on windows service in Windows 8

Community
  • 1
  • 1
Philip Pittle
  • 11,821
  • 8
  • 59
  • 123
  • Thank you for your answer. The information about attach is very helpful and I'll try to do this. But I have to say that getNameFiles isn't called from Program.Main. It wasn't modified an only initializes the Updater class: static void Main() { ServiceBase[] ServicesToRun; ServicesToRun = new ServiceBase[] { new Updater() }; ServiceBase.Run(ServicesToRun); } And the constructor of this class is empty. This function isn't called anywhere. – HackSaw Jul 14 '14 at 12:35
  • Please add the code from `UpdateFIAS.Program.Main`. According to the Stack Trace, somewhere in `Main` you are calling `new Updater()`. The `Updater` constructor calls `getNameFiles` – Philip Pittle Jul 14 '14 at 12:35
  • Just have done this in the previous comment, but I have problems with code highlighting, sorry for this, I'll try to edit it later. The constructor is Empty and every initialization is made in the other thread which starts when I uncomment code from OnStart(), but now I don't have any initialization. – HackSaw Jul 14 '14 at 12:45
  • Code highlighting doesn't work in the comments section. Can you add it to the main body of the question. Also, your problem is here: `ServicesToRun = new ServiceBase[] { new Updater() }; ` – Philip Pittle Jul 14 '14 at 12:48
  • Done. I can't paste here code of FIASMainClass, but I have to say that the constructor is empty. If I don't use separate class and copy-paste all code to the Updater - it also doesn't start and stop. – HackSaw Jul 14 '14 at 12:53
  • And as you can see, I don't use FIASMainClass in my code, except initializing it. – HackSaw Jul 14 '14 at 12:55
  • `Updater` has a data member: `FIASMainClass mainFIAS = new FIASMainClass();` this will be called when `new Updater()` is called. According to the stack trace, `new FIASMainClass()` calls `getNameFile()` which calls `string.substring()` which is where the error occurs. – Philip Pittle Jul 14 '14 at 12:55