C#如何从服务中运行Windows表单应用程序(包括在Vista系统中)

7
我正在使用C#编写一个应用程序,需要以服务的方式运行,同时还需要用户交互。我知道服务没有UI界面等等,因此我将程序分成了一个Windows窗体应用程序和一个可以相互通信的服务。
我遇到的问题是,我需要确保服务始终运行并在不运行时重新启动Windows窗体应用程序。我能够检测它是否正在运行,并使用以下代码在Windows 2000/XP上重新启动:
System.Diagnostics.Process.Start("ExePath");

但在Vista上,它会将新进程作为本地/系统进程运行,对用户不可见。是否有什么方法可以解决这个问题?有没有办法检测当前登录的用户并将新进程作为该用户运行?目前我不需要考虑快速用户切换。任何基本的东西都可以。
如果您对此有任何帮助或提示,我将不胜感激。
我需要澄清的是,在安装服务时,我设置了“允许服务与桌面交互”选项。这就是它能够在2000 / XP上工作的原因。然而,在Vista上仍存在上述问题。

我有什么遗漏吗?如果您有一个始终运行的服务...那么您的Windows窗体应用程序是否正在运行就无关紧要了吗? - bobwienholt
因为我需要一种服务与用户直接通信的方式。这有很多原因,但最基本的例子是升级通知。 - Andrew Ensley
1
我和其他人一样认为... 我怀疑您正在采取错误的方法来解决任何问题。如果您必须拥有用户界面,那么您可能不应该使用服务模型。也许可以使用系统托盘中的某些东西...? - Sailing Judo
我的表单应用实际上是驻留在系统托盘中的。如果我采取的方法不正确,我很乐意接受建议。到目前为止,我还没有被说服过。我需要该服务能够在某些事件发生时直接与用户进行通信。有更好的方式吗? - Andrew Ensley
8个回答

12
这种事情的一般想法是,如果用户需要与服务互动,则应启动单独的应用程序。如果您想帮助他们,可以配置该独立应用程序以在Windows启动时启动,方法是将快捷方式放在启动菜单中。您还可以将故障恢复构建到应用程序中,以便它可以自动重新启动。
您不应该真的依赖于监视表单应用程序,如果没有人登录怎么办?如果有多个人登录怎么办?这样做会变得混乱。
让服务坐在那里向侦听器广播是正确的方法。当表单应用程序启动时,它可以通知服务它想要监听事件。

正如我在上面的评论中提到的,我需要该服务能够直接通知用户某些事件。有两种方式可以让我满意:如果有解决我描述问题的方法,或者有更好的实现此目标的方法。 - Andrew Ensley
1
你应该让你的表单应用程序自动启动。然后它会通知服务它正在监听更新。 - Bob
我想我必须接受这个事实。我真的希望有一种方法可以从服务中重新启动它。 - Andrew Ensley
10
我讨厌那些总是在后台运行并隐藏自己的应用程序。我的意思是adobe、谷歌更新程序、QuickTime和Java等等。你们全都是混蛋。 - user1228
在其他情况下,我会同意你的看法,威尔,但我的程序的性质意味着用户会尝试黑客攻击或停止它。这就是为什么我想要能够重新启动该进程。重要的工作是在服务中完成的,并且以其他方式进行了保护,但我也希望那个表单能够运行!哦,好吧。 - Andrew Ensley
显示剩余3条评论

3

谢谢。看了那个答案后,我想我会采用许多有帮助的回答/评论提到的隐藏后台进程方法。 - Andrew Ensley

2
在这种情况下,您需要有一个第三个监视进程来检测程序是否失败,并在这种情况下重新启动它。
然而,您会遇到一个无法解决的问题,因为监视进程必须被监视以确保它不会被关闭,等等,等等。
您可能需要重新考虑这种方法。

1
要让您的服务作为用户运行应用程序(这似乎是您想做的),您需要执行以下操作:
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);

其中:

  • path = 可执行文件的完整路径(包括文件名)。
  • arguments = 参数字符串(如果没有则使用空字符串)
  • username = 服务器/计算机上用户帐户的名称
  • domain = 您的网络域(如果使用网络帐户,则为空白)

此外,为了使您的服务有权限启动应用程序,它必须也作为服务运行。要做到这一点,您需要将以下行添加到您的服务安装程序类中:

serviceProcessInstaller.Account = ServiceAccount.User;

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

serviceProcessInstaller.Password = "yourPassword";

你能从Active Directory对象中匹配用户名和密码吗? - SoftwareSavant

1

这是一个棘手的情况。如几个地方所提到的,如果您必须有一个用户界面,则从技术上讲,您不应该使用服务。毕竟,服务在没有用户登录的情况下运行。如果没有人登录,您就无法拥有用户界面。

通常,当我需要服务与外部世界通信时,我会选择两件事情。我可以在事件日志中放置一个条目,或者我可以将消息放入队列中。

在您的情况下,我会使用队列。当用户登录时,您可以自动为他们启动一个监视队列的应用程序。如果应用程序正在运行,当接收到消息时,他们也会通过这种方式得到通知。但是,如果用户关闭了应用程序,则会发生相同的事情...他们将不知道。


1
首先,一个快速的答案:'允许服务与桌面交互'选项(服务-> 属性-> 登录)或指定帐户是否可以允许您想要的内容? 如果是这样,这两个选项都可以在您的服务安装程序类中配置。
像其他人一样,我怀疑有更好的方法来解决这个问题,以下其中一个是正确的: - 服务内部的代码可以包含在winforms应用程序中(可能在后台线程中运行),并添加到Windows启动项。 两者都将运行 - 当服务启动时,winforms应用程序可以只监听服务,并且不需要从服务启动。 或类似地,该应用程序可以添加到启动项。

我已编辑了我的原始问题。我一直在安装服务时设置该选项。感谢您的建议。我可能会探索两种选择。我只希望能够做到我所问的那样。这将使我的生活变得轻松得多。 - Andrew Ensley

0
在Windows 2000和XP中,服务属性窗口的登录选项卡上有一个选项(复选框),允许服务与桌面交互。我相信这就是您要找的。我刚用VB.NET编写了一个快速服务,其中包含Process.Start("calc.exe"),Windows计算器正常打开。

但我不确定Vista是否以同样的方式工作。


我在问题表述上应该更清晰明了。我已经完成了这个步骤。这就是允许它在2000/xp上启动表单应用程序的原因。然而,在Vista中,该程序作为本地系统进程打开,对用户来说是不可见的。 - Andrew Ensley

0

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


谢谢,但我确实需要它成为特权服务。我正在考虑当表单应用程序未运行或没有用户登录时的情况(从逻辑上讲,现在它们是相同的)。 - Andrew Ensley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接