Alright, so I'm creating a windows service that will start and stop my rendering executable based on whether or not a user is logged in. I have already determined that I want to run the exe from a service, and know it will run in a secure desktop with no gui. That is not a problem for me.
What is a problem is that my service, when I tell it to start, instantly starts. I think that means I'm missing some sort of loop or event handler or SOMETHING, but I have no clue what. This is the first service I've tried to program. As there seems to be no way to debug a service effectively, I was hoping to get some input from the brilliant minds here.
Any input would be very much appreciated! Here's the code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Management;
namespace SessionService
{
public partial class renderServ : ServiceBase
{
private readonly ManagementClass _wmiComputerSystem = new ManagementClass("Win32_ComputerSystem");
private Process process;
Boolean isRunning;
public renderServ()
{
InitializeComponent();
process = new Process();
process.StartInfo = new ProcessStartInfo(#"C:\Windows\notepad.exe");
isRunning = false;
}
public void OnUserLogin()
{
/*if (isRunning == true)
{
process.Kill();
process.WaitForExit();
}*/
isRunning = false;
}
public void OnUserLogoff()
{
if (isRunning == false)
{
process.Start();
process.PriorityClass = ProcessPriorityClass.Idle;
}
isRunning = true;
}
protected override void OnSessionChange(SessionChangeDescription changeDescription)
{
base.OnSessionChange(changeDescription);
switch (changeDescription.Reason)
{
case SessionChangeReason.SessionLogon:
{
OnUserLogin();
} break;
case SessionChangeReason.SessionLogoff:
{
OnUserLogoff();
} break;
case SessionChangeReason.SessionLock:
{
OnUserLogoff();
} break;
case SessionChangeReason.SessionUnlock:
{
OnUserLogin();
} break;
}
}
protected override void OnStart(string[] args)
{
CanHandleSessionChangeEvent = true;
System.Windows.Forms.Application.Run();
}
protected override void OnStop()
{
}
}
}
Related
I have made a Windows Service in C# that calls a python script to run. This works without a problem. However, when I go to stop the service, it gives the error "could not be stopped" and I have to manually kill it using the PID in the command line. This hasn't always been like this and I can't seem to find previous versions of my code in VS2017. What part of my code is causing the Windows service to not be able to close?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Timers;
using System.Threading;
using System.Security.Permissions;
namespace WindowsService1
{
public partial class Service1 : ServiceBase
{
public ThreadStart startScript;
public Thread PyScriptThread;
public ServerClass serverObject;
//-------------------------------------------------------------------------
public Service1() { InitializeComponent(); }
//-------------------------------------------------------------------------
protected override void OnStart(string[] args)
{
serverObject = new ServerClass();
PyScriptThread = new Thread(new ThreadStart(serverObject.PyScript));
var t = Task.Run(() => serverObject.PyScriptAsync(PyScriptThread));
}
//-------------------------------------------------------------------------
protected override void OnStop()
{
try
{
StreamWriter sw = new StreamWriter(#"C:\Users\bakere1\A19149\Projects\text_doc.txt", false);
sw.Write("***STOP***");
sw.Close(); //stop the script within the process
if (!serverObject.p.HasExited) //kill the process within the thread
{
serverObject.p.CancelErrorRead();
serverObject.p.CancelOutputRead();
serverObject.p.CloseMainWindow();
serverObject.p.Refresh();
serverObject.p.Close();
serverObject.p.Kill();
serverObject.p.Dispose();
}
serverObject.PyScriptAsync(PyScriptThread).Dispose();
killPyThread(PyScriptThread); //kill the overarching thread
base.OnStop();
}
catch (Exception ex)
{
if (ex is IOException || ex is ThreadInterruptedException || ex is ThreadAbortException || ex is InvalidOperationException)
{
StreamWriter errorSW = new StreamWriter(#"C:\Users\bakere1\A19149\Projects\text_doc.txt", true);
errorSW.Write("Error occurred: Stacktrace/Message/Source", ex.StackTrace, ex.Message, ex.Source);
errorSW.Close();
}
}
}
//-------------------------------------------------------------------------
[SecurityPermissionAttribute(SecurityAction.Demand, ControlThread = true)]
public void killPyThread(Thread thread)
{
thread.Interrupt();
thread.Abort();
}
}
public class ServerClass
{
public event System.EventHandler serviceChanged;
public Process p;
//-------------------------------------------------------------------------
public async Task PyScriptAsync(Thread thread)
{
await Task.Delay(10000).ConfigureAwait(false);
thread.Start();
}
public void PyScript()
{
string fileName = #"C:\Users\bakere1\A19149\Projects\BLE_Advertiser.py";
p = new Process
{
StartInfo = new ProcessStartInfo(#"C:\Python36_64\python.exe", fileName)
{
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = false
}
};
p.Start();
p.WaitForExit();
p.CancelErrorRead();
p.CancelOutputRead();
p.CloseMainWindow();
p.Refresh();
p.Close();
p.Kill();
p.Dispose();
return;
}
//-------------------------------------------------------------------------
protected virtual void onServiceChanged()
{
serviceChanged?.Invoke(this, EventArgs.Empty);
}
}
}
It is my first program for service.
If i run this code as Console, LOOP works, but if I convert it to service, it does the operation initially, but does not LOOP.
Could you help me correct it?
tnx
using System;
using System.Net;
using KICBservice;
using System.Data;
using ConsoleApplication1.Classes;
using System.IO;
using System.ServiceProcess;
using System.Configuration.Install;
using System.ComponentModel;
namespace KICBService
{
[RunInstaller(true)]
public class MyWindowsServiceInstaller : Installer
{
public MyWindowsServiceInstaller()
{
var processInstaller = new ServiceProcessInstaller();
var serviceInstaller = new ServiceInstaller();
//set the privileges
processInstaller.Account = ServiceAccount.LocalSystem;
serviceInstaller.DisplayName = "KICB_Payment";
serviceInstaller.StartType = ServiceStartMode.Manual;
//must be the same as what was set in Program's constructor
serviceInstaller.ServiceName = "KICB_Payment";
this.Installers.Add(processInstaller);
this.Installers.Add(serviceInstaller);
}
}
class Program : ServiceBase
{
static void Main(string[] args)
{
ServiceBase.Run(new Program());
KICBservice.Service1SoapClient kicb = new KICBservice.Service1SoapClient();
kicb.ClientCredentials.Windows.ClientCredential = new NetworkCredential("register", "KICBregistr1");
kicb.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
while (true)
{
try
{
kicb.Open();
StreamWriter tw = File.AppendText("c:\\KICB.log");
NewPayment np = new NewPayment();
np = kicb.GetPayment("register", "KICBregistr1");
// Operation with Database
tw.WriteLine("----------------");
tw.WriteLine(DateTime.Now);
tw.Close();
kicb.Close();
System.Threading.Thread.Sleep(60000);
}
catch (Exception ex)
{
kicb.Abort();
}
}
}
public Program()
{
this.ServiceName = "KICB_Payment";
}
protected override void OnStart(string[] args)
{
base.OnStart(args);
//TODO: place your start code here
}
protected override void OnStop()
{
base.OnStop();
//TODO: clean up any variables and stop any threads
}
}
}
I am pasting full code of my program.
Where is that first code located?
Without that context, my best guess is that your OnStart() method fires, and then the service quits as soon the method ends because there's nothing left to do.
Also, I'm not a fan of the while (true) { Sleep(60000); // do work } pattern for services. Instead, you want to look for a function that actually blocks execution to keep your code going. Examples include TcpListener.AcceptTcpClient() and Thread.Join(). If you can't find something like that for the meat of your service, you may want to do something like set up a scheduled task instead.
You've placed the code outside of a function. What you have shown in the question should not even compile, and it certainly won't loop.
Note the //TODO: comment in the OnStart function definition:
protected override void OnStart(string[] args)
{
base.OnStart(args);
//TODO: place your start code here
}
I am recently writing a wiimote program:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using WiimoteLib;
namespace WiiTester
{
public partial class Form1 : Form
{
Wiimote wm = new Wiimote();
public Form1()
{
InitializeComponent();
wm.WiimoteChanged += wm_WiimoteChanged;
wm.WiimoteExtensionChanged += wm_WiimoteExtensionChanged;
wm.Connect();
wm.SetReportType(InputReport.IRAccel, true);
}
void wm_WiimoteChanged(object sender, WiimoteChangedEventArgs args)
{
WiimoteState ws = args.WiimoteState;
if (ws.ButtonState.A == true)
{
wm.SetRumble(true);
}
else
{
wm.SetRumble(false);
}
}
void wm_WiimoteExtensionChanged(object sender, WiimoteExtensionChangedEventArgs args)
{
if (args.Inserted)
{
wm.SetReportType(InputReport.IRExtensionAccel, true);
}
else
{
wm.SetReportType(InputReport.IRAccel, true);
}
}
}
}
My wiimote keeps getting disconnected and this error keeps running on wm.Connect();
Timed out waiting for status report
Is there a solution?
I have a lot of experience with this library, and your problem is most likely being caused because you are calling SetRumble so often, this code:
void wm_WiimoteChanged(object sender, WiimoteChangedEventArgs args)
{
WiimoteState ws = args.WiimoteState;
if (ws.ButtonState.A == true)
{
wm.SetRumble(true);
}
else
{
wm.SetRumble(false);
}
}
Will call SetRumble constantly whether A is down or not, consider using this code instead:
bool rumbleOn = false;
void wm_WiimoteChanged(object sender, WiimoteChangedEventArgs args)
{
WiimoteState ws = args.WiimoteState;
bool newRumble = (ws.ButtonState.A == true);
if (rumbleOn != newRumble)
{
rumbleOn = newRumble;
wm.SetRumble(rumbleOn);
}
}
This way the set rumble method is only called when required and not constantly sending output reports to the WiiMote which causes the Bluetooth BUS to overload.
I have read this question. I have same issue, but I don't understand the answer from lubos hasko. How exactly can I do it? Can you someone post me full walkthrough?
When I run code below, something is installed, but in list of service, I could not find it.
I have this, but this not work:
using System;
using System.Collections.Generic;
using System.Configuration.Install;
using System.Linq;
using System.Reflection;
using System.ServiceProcess;
using System.Text;
using System.IO;
namespace ConsoleApplication1
{
public class Service1 : ServiceBase
{
public Service1()
{
File.AppendAllText("sss.txt", "ccccc");
}
protected override void OnStart(string[] args)
{
File.AppendAllText("sss.txt", "asdfasdf");
}
protected override void OnStop()
{
File.AppendAllText("sss.txt", "bbbbb");
}
static void Main(string[] args)
{
if (System.Environment.UserInteractive)
{
string parameter = string.Concat(args);
switch (parameter)
{
case "--install":
ManagedInstallerClass.InstallHelper(new string[] { Assembly.GetExecutingAssembly().Location });
break;
case "--uninstall":
ManagedInstallerClass.InstallHelper(new string[] { "/u", Assembly.GetExecutingAssembly().Location });
break;
}
}
else
{
ServiceBase.Run(new Service1());
}
Console.ReadKey();
}
}
}
I dont understad this either:
if (System.Environment.UserInteractive) ...
This is my complete solution, and it works. It is basically the same answer as in this question.
using System;
using System.Configuration.Install;
using System.Reflection;
using System.ServiceProcess;
using System.IO;
namespace ConsoleApplication1
{
class Program : ServiceBase
{
static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += CurrentDomainUnhandledException;
if (System.Environment.UserInteractive)
{
string parameter = string.Concat(args);
switch (parameter)
{
case "--install":
ManagedInstallerClass.InstallHelper(new string[] { Assembly.GetExecutingAssembly().Location });
break;
case "--uninstall":
ManagedInstallerClass.InstallHelper(new string[] { "/u", Assembly.GetExecutingAssembly().Location });
break;
}
}
else
{
ServiceBase.Run(new Program());
}
}
private static void CurrentDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
File.AppendAllText(#"C:\Temp\error.txt", ((Exception)e.ExceptionObject).Message + ((Exception)e.ExceptionObject).InnerException.Message);
}
public Program()
{
this.ServiceName = "My Service";
File.AppendAllText(#"C:\Temp\sss.txt", "aaa");
}
protected override void OnStart(string[] args)
{
base.OnStart(args);
File.AppendAllText(#"C:\Temp\sss.txt", "bbb");
}
protected override void OnStop()
{
base.OnStop();
File.AppendAllText(#"C:\Temp\sss.txt", "ccc");
}
}
}
and in same project create this class:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration.Install;
using System.Linq;
using System.ServiceProcess;
using System.Text;
namespace ConsoleApplication1
{
[RunInstaller(true)]
public class MyWindowsServiceInstaller : Installer
{
public MyWindowsServiceInstaller()
{
var processInstaller = new ServiceProcessInstaller();
var serviceInstaller = new ServiceInstaller();
//set the privileges
processInstaller.Account = ServiceAccount.LocalSystem;
serviceInstaller.DisplayName = "My Service";
serviceInstaller.StartType = ServiceStartMode.Automatic;
//must be the same as what was set in Program's constructor
serviceInstaller.ServiceName = "My Service";
this.Installers.Add(processInstaller);
this.Installers.Add(serviceInstaller);
}
}
}
Run this program with parameters --install/--uninstall as Administrator on Windows 7. Check the error log in temp. Check working log on the same path.
First of all, in your Service1 constructor set ServiceName property.
Excerpt from MSDN:
The minimum you need to implement in the constructor for a class inherited from ServiceBase is to set the ServiceName on your component. No other processing is specifically required in the constructor. You should handle most initialization in OnStart rather than in the constructor.
Second of all you need to pass arguments to your service when running it from command line. --install for install, --uninstall for uninstall - look at your switch statement it's doing it on input arguments.
System.Environment.UserInteractive property tells you that
whether a Windows process or a service like IIS that runs without a user interface.
If this property is false, do not display modal dialogs or message boxes because there is no graphical user interface for the user to interact with.
Source
Check this article as well.
I am trying to create a simple service in C# using VS2008 that creates a text file when the computer goes into sleep mode. My current code throws out the following error:
'SleepNotifierService.WqlEventQuery' does not contain a constructor that takes '1' arguments
Now I looked in the Object browser, and it looks like it does take in one argument. This is what the browser had to say:
public WqlEventQuery(string queryOrEventClassName)
Here is my code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Management;
using System.IO;
namespace SleepNotifierService
{
public class WqlEventQuery : EventQuery { }
public partial class Service1 : ServiceBase
{
ManagementEventWatcher _watcher;
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
WqlEventQuery query = new WqlEventQuery("Win32_PowerManagementEvent");
_watcher = new ManagementEventWatcher(query);
_watcher.EventArrived += new EventArrivedEventHandler(watcher_EventArrived);
_watcher.Start();
}
protected override void OnStop()
{
_watcher.Stop();
}
void watcher_EventArrived(object sender, EventArrivedEventArgs e)
{
try
{
int eventType = Convert.ToInt32(e.NewEvent.Properties["EventType"].Value);
switch (eventType)
{
case 4:
Sleep();
break;
case 7:
Resume();
break;
}
}
catch (Exception ex)
{
//Log(ex.Message);
}
}
public void Sleep()
{
StreamWriter SW;
SW = File.CreateText("c:\\MyTextFile.txt");
SW.WriteLine("Sleep mode initiated");
SW.Close();
}
public void Resume()
{
}
}
}
Am I interpreting that object browser wrong? I'm new to creating services and C#/.NET in general so it might be something trivial.
Appreciate any help,
Tomek
You're using wrong WqlEventQuery. There's one defined in System.Management and it indeed has a one-argument constructor, but there's also your custom WqlEventQuery class.
If you want to use .NET BCL's class, you'll have to fully qualify it:
var query = new System.Management.WqlEventQuery("Win32_PowerManagementEvent");
or even prefix it with global keyword:
var query = new global::System.Management.WqlEventQuery("Win32_PowerManagementEvent");