Arguments in a Microsoft Service - c#

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.

Related

Start an application or batch file using Windows Service

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/

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.

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...

Monitoring a custom windows service

I've built a windows service application using Visual Studio .NET and C#. This service will be deployed on a few hundred machines and I'm looking for a solid way to monitor the application. By monitor, I mean, I just want to check to make sure that it's running, and check the status of a few settings on each client.
Is there a common method of doing this?
The easiest thing to do is have each application "call home". Create a single central application, preferably a web app, and have the remote applications make a small call to the central app on whatever interval you feel is necessary. They can include the extra information you want to monitor.
Keep a list of where the application is deployed and if you don't get a call from any on the list within the expected timeframe, then you know it's offline.
If you can't change the actual application that you're monitoring, then write a small companion application that can run as a scheduled tasks and perform the same local checks and call back to the central application.
We do this with thousands of client machines worldwide and it works well.
You could write a little monitor utility program that checks the service state via the SCM and provides a simple HTTP interface so you can poll the status. This would basically be just a big loop with some reporting if the service state changes.
while (true)
{
string serviceName = "NameOfYourService";
ServiceController Svc = new ServiceController(serviceName);
if (Svc.Status != ServiceControllerStatus.Running)
{
//Do reporting/set status here
}
Thread.Sleep(5000);
}
You could take advantage of a monitoring tool like Zabbix, for example.

How to do things within a windows service?

I have an application, written by me in C#.net 2.0 - when the application is opened, a timer will check every 3 seconds for x. If x happens, it shows a warning in a windows form.
Is there a possibility to install this timer and the windows form call in a windows-service? So that the timer ticks every time a system is up and shows the message then?
No, it is not possible to have a service display a form. This is by design, since a service is supposed to run without a user interface
You can have a regular application that communicates with your service and displays the warning, but I don't know how exactly this is done.
IMO, you don't need a service, just create a regular application without a main form that runs in the background, performs your check, and displays a warning when necessary. You can add that application to the Run section of HKLM or HKCU, so that it is always started when a user logs on to the system.
Windows Forms cannot be displayed from a Windows Service. A Service runs only in the background.
You can have a separate Windows application that communicates with the Windows service and display warnings, information, etc.
To do this, the service runs on the LocalSystem account, and you have to enable the property for the service to interact with the desktop.
Services are forbidden from interacting with the desktop, including displaying windows or forms. In windows 2003 and XP you could work around the issue by marking the service 'interactive' and this would allow the service to display on the user session, but as of Windows 2008 and Vista this is enforced and services can no longer interact in any fashion with the user.
When services need to display anything, the solution is to split the logic into two separate processes, one being the service and one being a normal user process. The user process runs launched by the user, in its session (it can be launched automatically at session start up) and it connects to the service via some IPC channel (shared memory, named pipes, sockets etc). The service can then display anything it wishes to the user by asking the user process half of the application to display what it needs to display.
As others have said, remember that a windows service is supposed to be a background, never-interacting-with-the-user program. Many services run even when the user is not logged on -- how would they go about displaying a form when there's no desktop for them to display it on?
That said, it shounds like you're trying to shoehorn something into a service that shouldn't be a service. If you want something that runs in the background and still interacts with the user, look into making a lightweight system try application. In fact... here's a helpful tutorial:
Lightweight System Tray Application (NotifyIcon Based)

Categories