I would like to be able to have a Windows service start, launch another executable, and then exit, leaving the launched executable to run in place of itself as the service.
The processes will be able to communicate with each other, so any information needed in either process from the other process is available.
Is this possible to do in .NET?
EDIT: To clarify, here's what the workflow would look like:
Service starts, launching a.exe. Note: a.exe does not call ServiceBase.Run()
a.exe launches b.exe using Process.Start()
a.exe and b.exe accomplish any communication required to exchange information, such as process or service handles (Note: this functionality already exists)
a.exe assigns service control to b.exe
a.exe exits, leaving b.exe running and bound to the service control
No you can't change the the process that is bound to the service control manager. To see why this is impossible you need to see how the unmanaged Windows service API works. (which .NET is wrapping).
You connect to the service control manager by calling StartServiceCtrlDispatcher (which can only be called once). In the lpServiceTable parameter you pass a pointer to a ServiceMain function, which obviously is only valid for the current process and all of the service control notifications are sent to this function.
The call to StartServiceCtrlDispatcher also does not return until all the services have stopped. So the service control managed is also tied to a thread in process that started the service, so that can't exit without the link to the service manager being severed.
So in your example, step 4 cannot occur, and process a.exe needs to stay alive for the duration.
See Process.Start(), this tutorial (old, but should still work), or this one.
If you're trying to start a service that's already registered, this may help.
Once the new process is running, communication with it has the same requirements as any other interprocess communications secnario.
You could use WCF, open a socket, use a database, etc. Without more details about what sort of communication you need, it's difficult to recommend a particular approach.
Related
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.
I'm designing a Windows Service that maintains a list of processes. It can run tasks on them. For example - stop a specific process (within its list), restart a specific process, run a new process and add it to the list, etc.
This Windows Service is controlled by a web app, through a WCF service - the Windows Service runs a WCF service, and the web app connects to that WCF service. The WCF service exports methods such as Restart(int id) and Stop(int id).
I have several questions:
When a process unexpectedly closes (for example, because of an internal error), the service should update a value in some database. Right now, to do this, I'm just having a thread that every 30 seconds it checks if the process is running or not.
Is this the right to do this? Should I use the Exit event?
When the service closes, for any reason, all of the processes that it maintains shall close too. What is the right way to do this?
I was thinking about just loop through the list and kill all processes when the service's OnClose() is called. The problem with this is that the OnClose() event is not always being called. For example, what if the service unexpectedly closes? It won't call OnClose().
How should I represent each task (for example - restart a process or stop a process)?
Right now I'm using System.Threading.Tasks. Is it the right way?
This service should be highly scalable, with minimum mistakes.
Thanks.
For closing the processes when the service closes, i think following steps can do the job for you.
Write a small program which can close the processes you want to close.
Go to Service Control Manager and right click on your service.
Go to Recovery tab and specify your program for execution under First Failure, Second Failure and Subsequest Failure listboxs.
Hope this would help.
I want to debug a Windows managed (C++/CLI) process, which's being invoked by a WCF consumed service. It calls process.start on that process, but I am unable to pause that process becuase when its main method gets executed, MessageBox which's placed inside is not executed and prompted, so that after I can attach that process to VS Debugger. If I launch the process manually which's placed on the disk, it gives the message box, or if somehow I start the process with a test stub application which uses Process.Start, message Box appears.
I need to debug the C++/CLI managed process in the context of WCF consumer service written in C#, which actually dispatches the data as remoting objects after starting that process. Is there any way around this?
Regards,
Usman
Maybe messagebox doesn't appear because of WCF service launch it with a different user.
But if you can test your component, why "re-test" it under WCF?
Once you are sure there are not logical errors, all remaining bugs can be solved by properly trace execution ad data in your component and, if necessary, reproduce these errors in your test application.
i don't know c++ but if you have access to the .Net Framework you could just call Debugger.Launch
I was also facing the same issue. It got resolved after checking "Allow Service to interact with desktop" on LogOn property page of the Windows Service
I need to start an executable from a WCF service which should run under the same service account that the WCF service uses. The WCF service is hosted in IIS and configured to run under a specific service account.
I also need to get a handle to that process and save it somewhere (in database for example) so that I can kill later if it runs for a long time unexpectedly.
I should be able to start multiple instances of that process in parallel with different arguments.
Is this possible OR do I need to create a windows service (assuming it does the same thing what executable does) and configure it with an account and start it from WCF service? Please let me know what is the right solution for this. thanks.
You should just be able to kick off a new process using System.Diagnostics.Process and use the Start method. It will run under the context it was started under.
If you want to get the handle for the process later, save its PID into your DB or file. Afterwards use Process.GetProcessById to get that handle.
I currently have a WCF Service Library which will be started through a Console Application acting as ServiceHost. The ServiceHost starts the service and then waits with Console.ReadLine() for the "quit" command. If i do "Console.WriteLine();" in the service this will be printed to the ServiceHosts Console of course. The Service prints some information when the clients connect for example.
Is it possible to have the ServiceHost converted to a real Windows Service (to start up when the machine boots without console window) and attach or detach a command prompt (cmd.exe) or another Console Application to it when needed? For example if I want so see which clients connect from now on?
Thanks in advance!
EDIT: I really woudln't like to write and read a LogFile.
Only if you run on an old operating system, XP is the last one that allows a service to interact with the desktop. You'll need to write a separate app that can run on the user's desktop. Talk to the service through, well, WCF. Or a named pipe or socket.
You would be far better off exposing the properties and methods you wish to access on the WCF Service and then creating a console or desktop application that allowed you to access the properties via the WCF service. As you are not limited to a single End Point or interface you could easily implement some form of authentication and use netTcp binding between applications.