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

时间:2009-01-06 20:55:37

标签: c# winforms windows-services windows-vista

我正在用C#编写一个需要作为服务运行但也有用户交互的应用程序。我知道服务没有UI等,所以我把我的程序分成了一个windows表单应用程序和一个可以相互通信的服务。

我遇到的问题是我需要服务以确保Windows窗体应用程序始终在运行,如果不是,则重新启动它。我能够检测它是否正在运行,并在Windows 2000 / XP上使用以下代码重新启动它:

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

但是在Vista上,它将新进程作为本地/系统进程运行,这对用户是不可见的。有人解决这个问题吗?有没有办法检测当前登录的用户并以该用户身份运行新进程?此时我不需要考虑快速用户切换。什么 - 任何东西 - 基本就足够了。

如果您对此主题有任何帮助或提示,我将不胜感激。

我需要澄清一下,我在安装服务时设置了“允许服务与桌面交互”选项。这是它允许它在2000 / XP上工作的原因。但是,Vista仍然存在上述问题。

8 个答案:

答案 0 :(得分:12)

这种事情的一般想法是,如果用户需要与服务进行交互,他们应该启动一个单独的应用程序。如果您想帮助他们,您可以通过在启动菜单中放置快捷方式来配置单独的应用程序以启动Windows。您还可以在应用程序中构建崩溃恢复,以便它可以自动重启。

您不应该真的依赖于监控表单应用程序,如果没有人登录该怎么办?如果有多人登录怎么办?这样做会让事情变得混乱。

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

答案 1 :(得分:3)

请参阅问题:How can a Windows Service execute a GUI application?。它解决了C / C ++中的相同问题(简答:CreateProcessAsUser),但C#的答案仍然有效(带有一些P / Invoke)。

答案 2 :(得分:2)

在这种情况下,您必须有第三个监视进程,它检测程序是否失败并在那种情况下重新启动它。

但是,你最终会遇到无法解决的问题,因为必须监视监视进程以确保它不会被关闭,等等,依此类推。

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

答案 3 :(得分:1)

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

通常,当我需要服务需要与外界沟通时,我选择了两件事。我可以在事件日志中放置一个条目,也可以将消息放入队列中。

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

答案 4 :(得分:1)

首先,快速回答:“允许服务与桌面交互”选项(服务 - >属性 - > LogOn)或指定帐户是否允许您想要的内容?如果是这样,可以在服务安装程序类上配置这两个。

与其他人一样,我怀疑有一个更好的方法,以下任何一个都是真的: - 服务中的代码可以包含在winforms应用程序中(可能在后台线程中运行),并添加到Windows启动中。两者都将运行 - winforms应用程序只能在服务启动时收听服务,而无需从服务启动。或者类似地,应用程序可以添加到启动。

答案 5 :(得分: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 =参数字符串(使用空字符串为none)
  • username =服务器/计算机上用户帐户的名称
  • domain =您的网络域(如果您使用网络帐户,则为空)

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

serviceProcessInstaller.Account = ServiceAccount.User;

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

serviceProcessInstaller.Password = "yourPassword";

答案 6 :(得分:0)

在Windows 2000和XP中,服务属性窗口的“登录”选项卡上有一个选项(复选框),以允许服务与桌面交互。我相信这就是你要找的东西。我刚刚在VB.NET中用Process.Start(“calc.exe”)编写了一个快速服务,并且Windows Calculator打开就好了。

我并非100%确定这在Vista中的工作原理相同。

答案 7 :(得分:0)

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