Start an application or batch file using Windows Service - c#

I made a C# application that backups some files and sends it to FTP or Dropbox. This application works in servers. But sometimes my application crashes or closes somehow. It must stay open all the time. I thought I can make a Windows Service to check my app status. If my app shuts down opens it again. I created the service. I used the Process.Start() method to open my app again. But it didn't work. I changed the code to open an a batch file that opens my app. It didn't work too. Then I searched this situation. I learned Windows services can't open an app from desktop. I didn't find a solution for this.
Is there any solutions for this or is there any different method from Windows service that I can use for open my app again?
Sorry for my bad English. Thanks.

A quick solution will be is to create one exe(Monitor.exe) just to monitor if your app process is running. If not launch your application.
The single responsibility of Monitor.exe is to ensure your main app is up and running

There is absolutely no reason your application should crash. For this add handling for unlhandled exception on start
// For service
AppDomain.CurrentDomain.UnhandledException += ...
// For windows forms
Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
Then your logic should be- you start your execution thread and if that thread dies it should be handled here
static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
// Log the exception, display it, etc
// Restart your processor on new thread
// count number of breakages. If it exceeds certain criteria, like total number,
// or number per minute, stop service ans send yourself email -
// hey your service encounters too many exceptions
}
As far as component part of your question - write your logic in DLL and then you can re-use it in the service or application, or elsewhere
But with all that said, your code should handle all the exception and prevent unhandled ones. And also it could be a little different based on framework version. See HandleProcessCorruptedStateExceptionsAttribute

I learned Windows services can't open an app from desktop.
This is wrong, services can start an app as the desktop user on windows. But you need to do some workarounds to make it work.
The problem is that the windows services are running in a different session than your windows desktop user. And their interactions are not directly allowed. This is called: Session 0 Isolation
What you need to do is, start your desktop application "as the desktop user" from the windows service.
Windows has CreateProcessAsUserA function to help with that.
OK so Where is my code?
Here it is
I really like this example class. "Impersonation.cs"
Because, it makes it very easy for you to use the CreateProcessAsUser function. You can call the function like:
Impersonation.ExecuteAppAsLoggedOnUser("applicationName", null);
Also make sure you give Replace a Process Level Token privilege to the user:
https://defaultreasoning.com/2017/01/16/migration-assistant-error-replace-process-level-token/

Related

What is the best way to keep a C# Console app running [duplicate]

This question already has answers here:
How to keep a .NET console app running?
(9 answers)
Closed 6 years ago.
I have developed a console app which must run in the background. The app must constantly check a database for new records. If new records are returned they are processed. My app as it currently stands uses while(true) to keep the application running. Is using a while loop the best solution.
A snippet of my code:
static void Main(string[] args)
{
while(true)
{
// Query db for new records
if(record_count > 0)
{
// Process the records
}
Thread.Sleep(500);
}
}
Create as Windows Service Application
What a Windows Service is ?
Enables you to create long-running executable applications that run in their own windows session.
Can be automatically started when the computer boots, can be paused and restarted without any user interaction.
Easily installable by running the command line utility InstallUtil.exe and passing the path to the service's executable file.
Why a Windows Service?
One of the most common requirements of some businesses is long-running scheduled jobs based on some time interval. For example: sending a newsletter everyday afternoon or send an email alert to the customer for every one hour.
So building a Windows Service could be one of the reliable solutions to do the goal that can do the required job in the behind the scenes without interfering others users on the same computer.
Please refer the link for step by step implementation -
http://www.c-sharpcorner.com/UploadFile/naresh.avari/develop-and-install-a-windows-service-in-C-Sharp/
Your approach to keep your console application continuously running is absolutely fine. Only thing is that you want to keep it running in background silently without user to know anything. Since a console app has a windowed UI (a command console) the user will keep seeing it. Here is what you can do to get rid of command console. Since you already have your console application with you, here is what you need to do :
Go to project properties -> Go to application Tab -> Change the Output type to Windows Application
Phew! Now your same console application will run without a command console and your code will keep running.
Creating a windows service will be too much of a kill for such a simple logic. Also installing a windows service is an extra overhead, though I am not aware of the deployment you are looking forward to for your application in production.
Better option would be to use Windows service that run in background.
Creating a Windows Service Application
Develop and Install a Windows Service in C#
Just google and you can find lots of article and tutorial on Windows Service.
There is no need to make your program running as a services. Services aren't for these small tasks. You should simply create a Windows (GUI, WinForms) application with a hidden window. Or, just don't create a window and just keep the Main running. Main would launch a thread and would itself wait for that thread.
A service has to be installed as a service and not all users would have permission to do that. It is complex task to have service, manage it, have security attributes settled et. al.
The hidden application can simply run in current user account (the service would be running in high-privilege SYSTEM or NETWORK account). Your application won't demand any privilege from current user - it just need SQL database/table read access.
Create a windows service which will check if your console app is running. If console app is down, then windows service will execute it again.
Don't write your console app's code into windows service. Because if it will start automatically at windows start up, then it may not work correctly as your console app.

Process.Start() working under Win7 and Win8 but not Windows 2012 R2

My program, run via a Windows Service was able to successfully run the following code under Win7 and Win8.
Log("About to run the file...");
try
{
Process.Start(filePath, args);
Log("File Triggered!");
}
catch (Exception ex)
{
Log("Error.");
}
Although the UI of the program located at filePath was never shown, but the program did its job completely in the background.
When I try the exact same program on a Windows 2012 R2 environment, I notice that after receiving the first log message above in my log file ("About to run the file...") nothing else is logged and Process.Start() does not work either. This is confusing because the exact same program worked in other operating systems.
So if Process.Start() is not called successfully, who do I not receive the "Error" message in my log and if Process.Start() is run, why do I not get the "File Triggered!" message?
Update:
Following the comments, I ran Process Monitor and this is the log generated for the target .exe file at the exact minute that it was supposed to run. Please take a look and see you find anything suspicious:
Link to log spreadsheet on Google Docs
I think this is because Windows Server 2012 does not by default allow processes to run interactively.
See here for details.
You can override this behaviour by setting a registry key:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Windows
NoInteractiveServices
Set the value to "0".
What's in process viewer -- do you see your process to start?
What's in Windows Event Log?
Win2012 is probably more strict regarding security and your application (executed from service, thus quite specific user). You can try using FileMon/ProcessMonitor from SysInternals to check which call it is failing at or stuck at.
And a generic advice: starting UI from service in Windows is not the best practice. Services are created to do some background work and not to have user interaction. If you need UI for your service, better create UI that user start himself, of create a small app that will sit in tray and wait for an event from service and then start UI in user so called "window station".
Windows Server 2012 blocks all the files copied from other places. So I unblocked all the program files. Thanks for your help.

Arguments in a Microsoft Service

I'm trying to make a tool that will launch an application on another PC through a combination of batch files and a custom service.
At the moment, my program only runs one specific program on the hit of a button. When I hit the button (held in a winform) it begins a batch files that runs my exe found on my target PC. Like so:
// when the service starts open paint
protected override void OnStart(string[] args)
{
// name of the application to launch
String applicationName = "C:\\TargetFolder\\Target.exe";
// launch the application
ApplicationLoader.PROCESS_INFORMATION procInfo;
ApplicationLoader.StartProcessAndBypassUAC(applicationName, out procInfo);
}
Then when I hit the close button, this happens
// when the service is stopped close the client
protected override void OnStop()
{
// name of the application to launch
String batchFile = "C:\\BatchFiles\\KillClient.bat";
// launch the application
ApplicationLoader.PROCESS_INFORMATION procInfo;
ApplicationLoader.StartProcessAndBypassUAC(batchFile, out procInfo);
}
My winform runs this batch file:
#echo off
net start "MyNewService"
Now though, I am trying to make my original tool open up specific exes depending on the button, without the need to make X amount more services. Who's sole job would be to run this single exe.
For example, if I want one button to up paint, another to close it down, another to open up word and a final one to close that. How would I do so in a service?
You don't use a service for a program that has a UI and requires user interaction.
A service is meant for a program that runs quietly in the background without any human intervention (other than starting and stopping it perhaps).
If you want human interaction a regular Windows Application (WinForms, WPF,...) is what you need to write.
You need to carefully consider the answer given by Chris above because there has been a lot of effort in recent years to tighten security in Windows Operating Systems. One change which came in with Vista (I call that recent :)) was that services now run as 'User0', not 'User1' as previously. User0 does not have access to the screen.
What you are trying to do is bypass the security. I said above - consider what would happen when no user is logged onto the target machine, but you also might consider what you want to happen if MANY users have active sessions. It seems to me you need to backtrack a little and formulate the requirement more closely.
That having been said, your question title asks how to pass parameters to a Windows Service. 2 answers spring to mind -
you could perhaps implement the service as a WCF service.(Not a Windows Service) This would allow you to define a method that receives the arguments you want to pass. WCF also has the flexibility of being hostable in a number of different ways. Consequently this might resolve some of the issues Chris and I have raised; a console host that runs when a particular user logs in might make more sense for your particular problem. You could also host your WCF service in a Windows service - I mention this with all the reservations expressed above.
You could implement a Windows(NT) service that opens a listening socket. Your launcher app connects and passes parameters through a socket conversation.
Doubtless there are other ways.

show a windows form from a window service

i am creating a window service. my requirement is to display window form from window NT service on particular interval. For testing purpose , i just want to display the form on service start:
protected override void OnStart(string[] args)
{
eventLog1.WriteEntry("In OnStart -before form show");
Messager_Form obj = new Messager_Form();
obj.Show();
// System.Diagnostics.Process.Start("calc.exe");
eventLog1.WriteEntry("In OnStart -after form show");
// timer1.Start();
}
it not working. Neither form is showing nor calc process is running. i have found some links
showing pop up , but most of them suggesting WCF. isn't it possible without wcf. can anybody show me the way to achieve this.
Cant be done*. In later Operating Systems that won't work as Windows Services are disallowed from interacting with the Desktop - instead UI presented by Windows Services is shown in Session 0, a special logon session which is not normally visible to the end user.
What you should instead do is write a separate Windows Forms application which is always running, but not always visible (possibly have that application run at startup and have an icon in the notification area) and communicates with the Windows Service using some form of IPC
When the Windows Service wishes to display some UI to the user it sends a message to the application, which in turns shows the desired UI to the end user.
*or at least it definitely shouldn't be done
I am just referring to the answer given in another link in StackOverflow
How to communicate with a windows service from an application that interacts with the desktop?
Answer is :
Be aware that if you are planning to eventually deploy on Windows Vista or Windows Server 2008, many ways that this can be done today will not work. This is because of the introduction of a new security feature called "Session 0 Isolation".
Most windows services have been moved to run in Session 0 now in order to properly isolate them from the rest of the system. An extension of this is that the first user to login to the system no longer is placed in Session #0, they are placed in Session 1. And hence, the isolation will break code that does certain types of communication between services and desktop applications.
The best way to write code today that will work on Vista and Server 2008 going forward when doing communication between services and applications is to use a proper cross-process API like RPC, Named Pipes, etc. Do not use SendMessage/PostMessage as that will fail under Session 0 Isolation.
http://www.microsoft.com/whdc/system/vista/services.mspx
Now, given your requirements, you are going to be in a bit of a pickle. For the cross-platform concerns, I'm not sure if Remoting would be supported. You may have to drop down and go all the way back to sockets: http://msdn.microsoft.com/en-us/library/system.net.sockets.aspx
Checking the "Interact with desktop" box will work on Windows NT, 2000, XP and 2003 but thanks to Session 0 Isolation that setting no longer works as you may expect in Windows Vista and beyond. You want to think very carefully before developing an interactive service...

Launch program under interactive logon user from .NET WinService

At the moment we have .NET WinService started under LocalService user at windows start. The service launch another WinForms Application using Process.Start().
But there are several problems in this solution:
We don't wait for an interactive user logon and the Application falls because it tries and fails to initialize DirectX device.
Application launched under LocalService perfectly interacts with user desktop in Windows XP. But it doesn't work in Windows 7 because of there are different graphic stations for each user in win7.
Sometimes we need to run application with current interactive logon user rights.
Does anybody know how to wait for user interactive logon in the service and start WinForms Application with these user rights?
I think this helps to solve all problems.
You will need a separate client app. Check out this document, page 6: http://msdn.microsoft.com/en-us/windows/hardware/gg463353.aspx.
For your monitoring/restart scenario look at CreateProcessAsUser as mentioned in the document. You will almost certainly need to have your client app coordinate with the service for this, and it's still pushing a square peg into a round hole.
I would try using a combination of the answers above.
To solve #1
At user logon, launch the Winforms application using autostart in registry or startup folder. Make it notify the service that it was started successfully.
To make sure that the Winform app is started successfully after user log on:
Have your service that checks if application is started running in the background as you have now but don't let it do the initial startup.
Instead just let it register when user logs on, should be possible to do by listening to OnSessionChange.
Set a delay for X number of seconds to allow the login/startup process finish before it starts checking for a running application (ok maybe not the best solution).
If the service discovers that the application is not started or crashes, restart it from the service using the method Mark points out, CreateProcessAsUser.
Is it possible that this just isn't the right approach for what you're trying to do? It seems possible that you'd be better off putting the monitoring logic or whatever has the uptime requirements into the service so that it's "always on" so to speak. Then you would be left with UI logic in the WinForms app, which could be open or closed with no ill effect.

Categories