Reading registry in windows service - c#

I have made a windows service using VS2017 template and it have created two classes: Program.cs and Service1.cs:
Program.cs Main() function code is separated as below:
#if DEBUG
Service1 service = new Service1();
service.OnDebug();
System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
#else
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new Service1()
};
ServiceBase.Run(ServicesToRun);
#endif
It helps me while I debug my service before release.
In Service1.cs class I have OnDebug() method:
public void OnDebug()
{
OnStart(null);
}
and OnStartMethod() looks like this:
protected override void OnStart(string[] args)
{
const string keyPath = "HKEY_CURRENT_USER\\Software\\MyKey";
string companyCardNumber = null;
while (companyCardNumber == null || companyCardNumber.Equals(""))
{
companyCardNumber = (string)Registry.GetValue(keyPath, "CompanyCardNumber", null);
if (companyCardNumber != null && !companyCardNumber.Equals(""))
{
break;
}
Debug.WriteLine("company card number in registry is empty or key doesn't exist");
System.Threading.Thread.Sleep(5000);
}
//more code...
}
Now the problem is that when i use DEBUG mode in VS it goes to //more code and program correctly read value from the registy. But when I switch to RELEASE mode and deploy service and then install, it loops in this while and after
companyCardNumber = (string)Registry.GetValue(keyPath, "CompanyCardNumber", null);
companyCardNumer doesn't have any value.
What causes this problem? Do I need any administrative privileges to read values from the registry? It would be weird, because as user I can modify registy. Another thing I noticed is state of service, because most services are launched, but mine is launching (if i can say that). But it's still working but companyCardNumber is empty.

Related

Launching Click Once Application - File Not Found

I have a basic service that will be used to run a ClickOnce application every x minutes, however when i run Process.Start() i am receiving an exception that the file cannot be found.
Code
private void OnElapsedTime(object source, ElapsedEventArgs e)
{
WriteToFile("Timer ticked");
CheckProcess(GetProcessName());
}
public void CheckProcess(string ProcessName)
{
WriteToFile(ProcessName);
try
{
Process.Start(ProcessName);
WriteToFile("It ran");
}
catch (Exception ex)
{
WriteToFile(ex.ToString());
}
}
public string GetProcessName()
{
string ProcessName = string.Concat("%AppData%\\Microsoft\\Windows\\Start Menu\\Programs\\", PublisherName, "\\", ProductName, ".appref-ms");
return ProcessName;
}
The error i receive is:
%AppData%\Microsoft\Windows\Start Menu\Programs\PubName\ProdName.appref-ms
System.ComponentModel.Win32Exception (0x80004005): The system cannot find the file specified
at System.Diagnostics.Process.StartWithShellExecuteEx(ProcessStartInfo startInfo)
at System.Diagnostics.Process.Start()
at System.Diagnostics.Process.Start(ProcessStartInfo startInfo)
at System.Diagnostics.Process.Start(String fileName)
If i run the ProcessName retrieved in explorer then the application launches successfully. Value of ProcessName is :
C:\Users\xxx\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\PubName\ProdName.appref-ms
Is there something i am missing in order to start the file?
Windows Services are the programs which will runs even before a user logged into it's Account. This is Windows Service purpose, and by this definition you haven't access to specific User Environment Variables (Like %AppData%) because you aren't in the User Session so your address will be translated to something Odd if you write it into a .txt you will see the result.
Windows Services (By your definitions) will run by LocalSystem, LocalService or NetworkService. Go to TaskManager->Services->Open Services and watch Log On As Column.
So you must use a general path which be access-able through your service.
Most terrifying solution is to force your Service to wait for a user login and impersonate his token.
I will Prefer to choose a better place.
There is a way to debug and see your Service bugs (In UserSession) in VisualStudio.
Change your Program.cs to something like:
static void Main()
{
#if DEBUG
var MainService = new MainService();
MainService.OnDebug();
#else
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new MainService()
};
ServiceBase.Run(ServicesToRun);
#endif
}
and Add OnDebug function to your Service:
public void OnDebug()
{
OnStart(null);
}
if you debug your project in this way you will see that your service is working As Expected !!!

Windows service (c#) not starting

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()
{
...
}
...
...
...
}
}
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

Windows service - only one instance to allow at a time

I tried with below code to restrict the second instance of the windows service, but below code is not working for me, can anyone help me out.
I have put time interval to run service, that is 5 mints, if first instance is started and running, after 5 mints second instance is starts even though first instance is not completed.
static class Program
{
[STAThread]
static void Main()
{
bool ok;
System.Threading.Mutex m = new System.Threading.Mutex(true, "ImageImportService", out ok);
if (!ok)
{
return;
}
GC.KeepAlive(m);
if (PriorProcess() != null)
{
return;
}
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new ImageImportService()
};
ServiceBase.Run(ServicesToRun);
}
public static Process PriorProcess()
{
Process curr = Process.GetCurrentProcess();
Process[] procs = Process.GetProcessesByName(curr.ProcessName);
foreach (Process p in procs)
{
if ((p.Id != curr.Id) && (p.MainModule.FileName == curr.MainModule.FileName))
return p;
}
return null;
}
}
Service Control Manager, a component of Windows, does not allow starting a Windows service if it is already running. Just rely on it.
The main thing you need to do is to never launch your executable directly. Instead, use the ServiceController class, when starting the service from code, and Control Panel (services.msc) when starting/stopping it manually.
In some cases, you may need to take extra steps to make sure that the service does not keep any resources behind after it has been stopped, preventing its own subsequent startup until some lower level timeout. But nothing in your question indicates that you already ran into such issues (e.g., rebinding a TCP port).

Cannot evaluate expression because a native frame is on top of the call stack

I'm creating a simple window service and when I go to debug I get the error, "Cannot evaluate expression because a native frame is on top of the call stack.". Also, when I build the service in Release and run it just hangs.
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[] { new MyService1() };
ServiceBase.Run(ServicesToRun);
}
Thats all that is in the Program.cs file, where it normally gets hung on the ServiceBase.Run(ServicesToRun) line.
Everything I've been able to find only relates to the expression not being evaluated because the code is optimized or having to deal with asp.net and response.redirect.
Code for the Service.
public TruckRateClearService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
tmrProcess.Enabled = true;
}
protected override void OnCustomCommand(int command)
{
base.OnCustomCommand(command);
if (command == 129)
{
OnStart(null);
}
}
protected override void OnStop()
{
tmrProcess.Enabled = false;
}
private void tmrProcess_Tick(object sender, EventArgs e)
{
tmrProcess.Enabled = false;
try
{
eventLog.WriteEntry("Clearing Truck Rates Start" + DateTime.Now.ToString());
TruckRateClearingAgent.Process();
eventLog.WriteEntry("Clearing Truck Rates Finished" + DateTime.Now.ToString());
}
catch (Exception ex)
{
eventLog.WriteEntry(ex.ToString(), EventLogEntryType.Error);
}
tmrProcess.Enabled = true;
}
internal void Run()
{
tmrProcess_Tick(tmrProcess, null);
}
The Internal Void Run() was added just recent on the suggestion in the comments by Eren Ersönmez. His idea has been very helpful for helping debug my logic until I can figure the rest out.
I was able to get the into the Native call stack and it sits on one location, 76F17094 ret. Now I have no idea what this is but maybe someone else will.
Also, when I start the service and look into attaching it to VS I'm noticing two instances of it. One is the normal .exe and another is a .vshost.exe. When I start other services I only see the .exe file in the Attach to process part of the debugger. Could this be because one is on the v4 Framework ( .vshost .exe service ) and another on the v2 ( single .exe service ) Framework?
I believe I got it working. It seems that the problem lied with the timer I was using. The original timer I was using was a System.Windows.Forms timer. I switched it to System.Timers.Timers and everything started working again. Still cant attach VS to it but I can debug it still by using the Internal Run() method. Thanks for all the help n.n
Your main problem is that you're trying to directly run a windows service exe. Windows services can only be started via Service Control Manager (SCM). In order to be able to debug in VS, I'd recommend something like this:
static void Main()
{
if (Environment.UserInteractive)
{
new MyService1().Run();
Thread.Sleep(Timeout.Infinite);
}
else
{
ServiceBase.Run(new ServiceBase[] { new MyService1() });
}
}
You'd create a MyService1.Run method which spawns a new thread that runs the service loop. Also, you'd call the same Run method from within the MyService1.Onstart.
This scheme runs it as a service when being started by SCM, but treats it like a normal exe when being debugged in VS (or being run directly as an exe outside VS).
The problem
This notification means that the thread is currently executing unmanaged code, and therefore cannot be used to evaluate the expression.
In some situations, you could wait for the call to return to managed code before evaluating the expression. Unfortunately, in this situation, that won't happen until you shut down the service.
An Alternative
You might consider overriding the ServiceBase.OnCustomCommand method and putting a breakpoint there so you can evaluate your expression.
protected override void OnCustomCommand(int command)
{
//Debugger.Break() <- or just put a breakpoint in here.
}
You can invoke the custom command as follows:
c:\>sc control YourServiceName 129
The exception you're seeing means that unmanaged code is throwing an exception, so the .NET debugger can't show you the usual useful details.
What are you doing in MyService1() ? Can you post the code inside it?
Also are you trying to debug the service by just starting it from the environment. That might not work.
I usually write something like this:
static void Main(params string[] args)
{
if (args.Length > 0 && args[0] == "/console")
{
// Run whatever your service calls here
}
else
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[] { new MyService1() };
ServiceBase.Run(ServicesToRun);
}
}
Then in the project properties under the Debug tab enter /console as the command line arguments. You should be able to step into the application and debug it. You can only debug a service by installing it first: http://msdn.microsoft.com/en-us/library/7a50syb3(v=vs.80).aspx

Debugging a Windows Service

I am making a Windows Service and I want to debug it.
This is the error I get when I try to debug it:
Cannot start service from the command line or a debugger. A Windows service must be first installed and then started with the Server Explorer, Windows Services Administrative TOll or the NET start command.
I have already installed my service using InstallUtil, but I am still facing problems.
Also, when I try to attach a process, my service goes into the running mode, it never starts debugging.
EDIT: DO we have to reinstall the Windows Service everytime we make a change or just building it would suffice?
In your OnStart use something like this:
#if DEBUG
if(!System.Diagnostics.Debugger.IsAttached)
System.Diagnostics.Debugger.Launch();
#endif
For the most use cases it's good enough to run the service as console application. To do this, I usually have the following startup code:
private static void Main(string[] args) {
if (Environment.UserInteractive) {
Console.WriteLine("My Service");
Console.WriteLine();
switch (args.FirstOrDefault()) {
case "/install":
ManagedInstallerClass.InstallHelper(new[] {Assembly.GetExecutingAssembly().Location});
break;
case "/uninstall":
ManagedInstallerClass.InstallHelper(new[] {"/u", Assembly.GetExecutingAssembly().Location});
break;
case "/interactive":
using (MyService service = new MyService(new ConsoleLogger())) {
service.Start(args.Skip(1));
Console.ReadLine();
service.Stop();
}
break;
default:
Console.WriteLine("Supported arguments:");
Console.WriteLine(" /install Install the service");
Console.WriteLine(" /uninstall Uninstall the service");
Console.WriteLine(" /interactive Run the service interactively (on the console)");
break;
}
} else {
ServiceBase.Run(new MyService());
}
}
This makes it easy not only to run and debug the service, but it can then also install and uninstall without needing the InstallUtil program.
This question has an excellent answer in making the service a console/service hybrid. See the answer from user marc_s. I don't want to duplicate the answer here.
I, personally for me, found the easiest solution is not change the code, by adding more mess and #if #else directives, but simply:
Compile your service binaries in DEBUG mode
Point installed service to DEBUG binaries
Run service
Use connect to process dialog of VS to connect to your running process
Enjoy.
The good thing on this that you don't change the code so it's exactly the same as your production binaries, which, I think, is kind of important.
Good luck.
One way that I've done it before was to insert a Debugger.Break() in the service on start method. Compile and install the service. When it starts it break and open the debug with dialog, from there you should be able to attach and debug.
The Debugger.Launch method is a good way but I prefer to create a class that does the processing and call it from the service, This can then also be called from a win forms app.
eg:
class ProcessingManager
{
public void Start()
{
//do processing
}
public void Stop()
{
//stop
}
}
then in your service / win forms app just create an instance of the processing class as a member variable and call the method on start and stop. It can be used in the service, or a win forms app with a start and stop button, which I find a lot quicker than attaching the debugger each time because you can set the windows application to start as default and add any breakpoints into the processing manager.
extract from service code:
namespace Service
{
public partial class Service : ServiceBase
{
#region Members
private ProcessingManager m_ProcessingManager = null;
#endregion Members
#region Constructor
/// <summary>
/// Constructor
/// </summary>
public Service()
{
InitializeComponent();
try
{
//Instantiate the processing manager
m_ProcessingManager = new ProcessingManager();
}
catch (Exception ex)
{
ErrorHandler.LogError(ex);
}
}
#endregion Constructor
#region Events
/// <summary>
/// Starts the processing
/// </summary>
/// <param name="args">Parameters</param>
protected override void OnStart(string[] args)
{
try
{
//Start the Processing
m_ProcessingManager.Start();
}
catch (Exception ex)
{
ErrorHandler.LogError(ex);
}
}
/// <summary>
/// Service Stopped
/// </summary>
protected override void OnStop()
{
try
{
//Stop Processing
m_ProcessingManager.Stop();
}
catch (Exception ex)
{
ErrorHandler.LogError(ex);
}
}
#endregion Events
}
}
Try following this guide
EDIT: Personally, I have a console application in the same project that does all the work. I then just have the service run the Main of the console application. It makes debugging easy especially when just developing.
For debugging or testing your service without installing it, make changes in Program.cs like this.
static class Program
{
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new MyService()
};
ServiceBase.Run(ServicesToRun);
}
}
Change it to:
static class Program
{
static void Main()
{
#if(!DEBUG)
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new MyService()
};
ServiceBase.Run(ServicesToRun);
#else
MyService myServ = new MyService();
myServ.Process();
// here Process is my Service function
// that will run when my service onstart is call
// you need to call your own method or function name here instead of Process();
#endif
}
}
What i always do is put a:
#if DEBUG
Thread.Sleep(20000)
#endif
in the OnStart. That gives me 20s to attach.
Quick and easy, just remember to wrap it in an #if DEBUG #endif :)

Categories

Resources