C#从服务运行Windows窗体应用程序(在Vista中)

时间:2021-01-23 15:54:49

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仍然存在上述问题。

8 个解决方案

#1


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.

让服务只是坐在那里并向听众广播是要走的路。当表单应用程序启动时,它可以通知它想要监听事件的服务。

#2


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)。

#3


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.

您可能想重新考虑这种方法。

#4


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.

这是一个艰难的局面。正如在几个地方所提到的,如果您必须拥有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.

在你的情况下,我会使用一个队列。当用户登录时,您可以为监视队列的用户自动启动应用程序。如果应用程序正在运行,则在收到消息时,它们也会以此方式收到警报。但是,如果用户关闭应用程序,那么同样的事情发生......他们不会知道。

#5


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应用程序只能在服务启动时收听服务,而无需从服务启动。或者类似地,应用程序可以添加到启动。

#6


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.
  • path =可执行文件的完整路径(包括文件名)。

  • arguments = string of arguments (use an empty string is none)
  • arguments =参数字符串(使用空字符串为none)

  • username = The name of an user account on your server/computer
  • username =服务器/计算机上用户帐户的名称

  • domain = your network domain (if your using a network account- blank if none)
  • 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";

#7


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计算器打开就好了。

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

我不是100%确定它在Vista中的工作原理相同。

#8


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.

听起来你可能不需要将其中的一半作为服务运行(除非需要更高的权限),因为当没有交互式用户登录时,你的服务需要应对。

#1


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.

让服务只是坐在那里并向听众广播是要走的路。当表单应用程序启动时,它可以通知它想要监听事件的服务。

#2


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)。

#3


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.

您可能想重新考虑这种方法。

#4


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.

这是一个艰难的局面。正如在几个地方所提到的,如果您必须拥有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.

在你的情况下,我会使用一个队列。当用户登录时,您可以为监视队列的用户自动启动应用程序。如果应用程序正在运行,则在收到消息时,它们也会以此方式收到警报。但是,如果用户关闭应用程序,那么同样的事情发生......他们不会知道。

#5


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应用程序只能在服务启动时收听服务,而无需从服务启动。或者类似地,应用程序可以添加到启动。

#6


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.
  • path =可执行文件的完整路径(包括文件名)。

  • arguments = string of arguments (use an empty string is none)
  • arguments =参数字符串(使用空字符串为none)

  • username = The name of an user account on your server/computer
  • username =服务器/计算机上用户帐户的名称

  • domain = your network domain (if your using a network account- blank if none)
  • 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";

#7


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计算器打开就好了。

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

我不是100%确定它在Vista中的工作原理相同。

#8


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.

听起来你可能不需要将其中的一半作为服务运行(除非需要更高的权限),因为当没有交互式用户登录时,你的服务需要应对。