C# 从服务(和在 Vista 中)运行 Windows 窗体应用程序
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/418119/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C# Run Windows Form Application from Service (and in Vista)
提问by Andrew Ensley
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.
我正在用 C# 编写一个应用程序,它需要作为服务运行,但也需要用户交互。我知道服务没有 UI 等,所以我把我的程序分成了一个 windows 窗体应用程序和一个可以相互通信的服务。
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:
我遇到的问题是我需要该服务来确保 windows 窗体应用程序始终运行,如果不是,则重新启动它。我能够检测它是否正在运行,并在 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.
但在 Vista 上,它将新进程作为用户不可见的本地/系统进程运行。有人解决这个问题吗?有没有办法检测当前登录的用户并以该用户身份运行新进程?此时我不需要考虑快速用户切换。东西 - 任何东西 - 基本就足够了。
I would be grateful for any help or tips you have on the subject.
对于您在该主题上的任何帮助或提示,我将不胜感激。
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.
我需要澄清的是,我在安装服务时设置了“允许服务与桌面交互”选项。这就是它可以在 2000/XP 上运行的原因。但是,Vista 仍然存在上述问题。
采纳答案by Bob
The general idea for this sort of thing is, if the user needs to interact with a service, they should launch a separate application. If you want to help them out, you can configure that separate 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.
这种事情的一般想法是,如果用户需要与服务交互,他们应该启动一个单独的应用程序。如果您想帮助他们,您可以通过在启动菜单中放置快捷方式来配置该单独的应用程序以从 Windows 启动。您还可以将崩溃恢复构建到您的应用程序中,以便它可以自动重新启动。
You shouldn't really rely on monitoring the forms application, what if no one is logged in? What if multiple people are logged 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.
让服务只是坐在那里并向听众广播是要走的路。当表单应用程序启动时,它可以通知服务它想要监听事件。
回答by casperOne
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.
您可能需要重新考虑这种方法。
回答by Rich
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.
在 Windows 2000 和 XP 中,服务属性窗口的登录选项卡上有一个选项(复选框)允许服务与桌面交互。我相信这就是你正在寻找的。我刚刚在 VB.NET 中编写了一个带有 Process.Start("calc.exe") 的快速服务,并且 Windows Calculator 打开得很好。
I'm not 100% sure this works the same way in Vista though.
不过,我不是 100% 确定这在 Vista 中的工作方式相同。
回答by Rowland Shaw
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.
听起来您可能不需要其中的一半作为服务运行(除非需要更高的权限),因为当没有交互式用户登录时,您的服务也需要处理。
回答by Sailing Judo
Its a tough situation. As mentioned in a couple places, if you musthave 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.
这是一个艰难的局面。正如在几个地方提到的,如果你必须有一个 UI,那么从技术上讲你不应该使用服务。毕竟,服务在没有用户登录的情况下运行。如果没有人登录,您将无法拥有 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.
在你的情况下,我会使用队列。当用户登录时,您可以为他们自动启动监控队列的应用程序。如果应用程序正在运行,当收到消息时,他们也会以这种方式收到警报。但是,如果用户关闭应用程序,则会发生同样的事情……他们不会知道。
回答by Daniel
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.
像其他人一样,我怀疑有更好的方法来解决这个问题,并且以下任一方法都是正确的: - 服务内部的代码可以包含在 winforms 应用程序中(可能在后台线程中运行),并添加到 Windows 启动中。两者都将运行 - winforms 应用程序可以在服务开启时监听服务,不需要从服务启动。或者类似地,该应用程序可以添加到启动中。
回答by Roger Lipscombe
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#.
请参阅问题:Windows 服务如何执行 GUI 应用程序?. 它解决了来自 C/C++ 的相同问题(简短答案:CreateProcessAsUser),但答案对于 C# 仍然有效(带有一些 P/Invoke)。
回答by Tyson Zwicker
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)
- path = 可执行文件的完整路径(包括文件名)。
- arguments = 参数字符串(使用空字符串是无)
- 用户名 = 您的服务器/计算机上的用户帐户的名称
- domain = 您的网络域(如果您使用网络帐户 - 如果没有则为空)
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";