views:

16964

answers:

9

I am writing an application in C# that needs to run as a service but also have user interaction. I understand that services have no UI, etc, so I've divided up my program into a windows form application and a service that can communicate with each other.

The problem I'm having is that I need the service to make sure the windows form application is always running and restart it if it is not. I'm able to detect if it is running, and restart it with the following code on Windows 2000/XP:

System.Diagnostics.Process.Start("ExePath");

but on Vista, it runs the new process as a Local/System process which is invisible to the user. Does someone way around this? Is there some way to detect which user is currently logged on and run the new process as that user? I don't need to account for fast-user switching at this point. Something - anything - basic would suffice.

I would be grateful for any help or tips you have on the subject.

EDIT: I need to clarify that I am setting the "Allow service to interact with desktop" option when the service is installed. This is what allows it to work on 2000/XP. However, Vista still has the aforementioned problem.

+2  A: 

In this case, you will have to have a third monitor process which detects if the program fails and restart it in that case.

However, you end up with an unsolvable problem here, as the monitor process will have to be watched to make sure it doesn't get shut down, and so on, and so on, and so on.

You might want to reconsider this approach.

casperOne
+9  A: 

The general idea for this sort of thing is if the user needs to interact with a service, they should launch a seperate applcation. If you want to help them out, you can configure your that seperate application to start with windows by placing a shortcut in the start up menu. You can also build crash recovery into your application so it can automatically restart.

You shouldn't really rely on monitoring the forms application, what if no one is loged in? What if multiple people are loged in? It just gets messy doing things this way.

Having the service just sit there and broadcast to listeners is the way to go. When the forms application starts it can notify the service it wants to listen to events.

Bob
As I mentioned in my comments above, I need the service to be able to notify the user of certain events directly. I'll be happy one of two ways: if there's a way to resolve the problem I described, or if there's a better way to accomplish this goal.
Andrew
You should have your forms application start up automatically. Then it will notify the service it is listening for updates.
Bob
I guess I'll have to accept that. I was really hoping there was a way to relaunch it from the service.
Andrew
This is considered the "proper" way to do things. If you wanted to be sneaky you could have an application running in the background. Use tactics to hide that and its only job would be to keep the form app alive.
Bob
I despise apps that always run and hide themselves in the background. I'm looking at you adobe, google updater, quicktime, and java. Bastards, the lot of you.
Will
In all other cases I would agree with you Will, but the nature of my program means that users will try to hack it or stop it. That's why I wanted to be able to relaunch the process. The important work is done in the service, and it's secured in other ways, but I want that form running too! Oh well
Andrew
Have two apps in user space: the forms app and a hidden app. The forms app makes sure the hidden app is running and the hidden app makes sure the forms app is running.
Jeff Cuscutis
@Jeff, thanks that is what I was trying to convey
Bob
To your credit, Bob. I understood exactly that from you. I will probably have to do this eventually. Thank you for your help.
Andrew
A: 

In Windows 2000 and XP, there is an option (checkbox) on the Logon tab of the service properties window to allow the service to interact with the desktop. I believe this is what you are looking for. I just wrote a quick service in VB.NET with a Process.Start("calc.exe") and Windows Calculator opened just fine.

I'm not 100% sure this works the same way in Vista though.

Rich
I should have been clearer in my question. I have done this. This is what allows it to launch the forms application on 2000/xp. However, Vista opens the program as a local system process and it is invisible to the user.
Andrew
A: 

Sounds like you might not need half of it running as a service (unless there's a requirement of higher privileges), as your service would need to cope with when there is no interactive user logged on as well.

Rowland Shaw
Thanks, but I do need it to be a service for privileges. I am accounting for situations when the forms app is not running or there's no user logged on (which are logically the same for right now).
Andrew
+1  A: 

Its a tough situation. As mentioned in a couple places, if you must have a UI then technically you shouldn't be using a service. Afterall, services run without a user even logged on. If nobody is logged in, you cannot have a UI.

Normally, when I need a service needs to communicate with the outside world, there are two things I opt for. I can either place an entry in the event log, or I can drop a message in a queue.

In your case I'd use a queue. When a user logs in, you can auto start an app for them that monitors the queue. If the app is running, when the message is received, they are alerted that way as well. However, if the user closes the app then the same thing occurs... they won't know.

Sailing Judo
That is my problem :-p
Andrew
+1  A: 

First, a quick answer: Does the 'Allow service to interact with desktop' option (service -> Properties -> LogOn) or specifying an account allow what you're wanting? If so, both of these can be configured on your service installer class.

Like the others, I suspect there is a better approach to this and either one of the following is true: -The code inside the service could be included in the winforms app (perhaps running in a background thread), and added to windows startup. Both will be running -The winforms app can just listen to the service when it's on, and doesn't need to be started from the service. Or similarly, the app could be added to startup.

Daniel
I've edited my original question. I have been setting that option when the service is installed. Thanks for the suggestion. I will probably explore both options. I just wish it was possible to do what I'm asking. It would make my life so much easier.
Andrew
+1  A: 

See the question: How can a Windows Service execute a GUI application?. It addresses the same question from C/C++ (short answer: CreateProcessAsUser), but the answer's still valid (with some P/Invoke) for C#.

Roger Lipscombe
Thanks. After looking at that answer, I think I'll go with the hidden background process approach mentioned by many helpful answers/comments.
Andrew
A: 

To have your service run the application as a user (which seems to be what you are trying to do) you need to do the following:

System.Security.SecureString ss = new System.Security.SecureString();

foreach (char c in password) ss.AppendChar(c);

System.Diagnostics.Process proc = Process.Start(path, arguments, username, ss, domain);

Where:

path = full path (including filename) of the executable.

arguments = string of arguments (use an empty string is none)

username = The name of an user account on your server/computer

domain = your network domain (if your using a network account- blank if none)

Also, In order for your service to have permission to launch an application, it must be running as a service also. To do this, you need to add these lines to your service installer class:

serviceProcessInstaller.Account = ServiceAccount.User;

serviceProcessInstaller.Username = "yourdomain\yourAccountName"; \Or just "AccountName" for local accounts..

serviceProcessInstaller.Password = "yourPassword";

Tyson Zwicker
A: 

I think you are better off with an application that launches seprate workerthreads to do the service alike tasks.

Willem Luijk