【问题标题】:Windows Service can not open Windows FormWindows 服务无法打开 Windows 窗体
【发布时间】:2019-06-12 07:27:51
【问题描述】:

我正在尝试使用TopShelf 创建一个Windows Service,并且在此服务中我想启动一个Windows Form。在我创建服务并调试它调用ShowDialog 后,表单不显示:

服务

 class SimpleServ {
    private Task task;
    private const string PATH = @"D:/out.txt";
    private Logger logger;
    private CancellationTokenSource src = new CancellationTokenSource();
    public SimpleServ() {
        logger = new Logger();

    }
    public void Start() {

        logger.Log("Started");
        this.task = Task.Run(async () => {

            var fm = new Fm(logger);
            while (true) {
                fm.ShowDialog();
                logger.Log("Just closed the dialog");
                await Task.Delay(3000);
            }
        });
    }
    public void Stop() {
        logger.Log("Stopped service");
    }
}

表格

public partial class Fm : Form {
    private Logger log;
    public Fm(Logger log) {
        this.log = log;
        this.log.Log("From Form constructor");
        InitializeComponent();

    }

    private void button1_Click(object sender, EventArgs e) {
        this.log.Log("Button clicked");
        this.Close();
    }
}

主要

class Program {
        static void Main(string[] args) {
            var exitCode = HostFactory.Run(x => {
                x.Service<SimpleServ>(s => {
                    s.ConstructUsing(h => new SimpleServ());
                    s.WhenStarted(h => h.Start());
                    s.WhenStopped(h => h.Stop());
                });
                x.RunAsLocalSystem();
                x.SetServiceName("SimpleService");
                x.SetDisplayName("Simple Service");
                x.SetDescription("Simple serv description");

            });
            int exitCodeValue = (int)Convert.ChangeType(exitCode, exitCode.GetTypeCode());
            Environment.ExitCode = exitCodeValue;
        }
    }

我已将自己附加到该服务,在它到达ShowDialog 行后,没有任何反应。

更新
我还添加了一个Logger 来记录所有重要事件,到目前为止,表单似乎打开了,但我看不到它:

记录器

public class Logger {
        private string path;
        public Logger(string logPath=Constants.PATH) {
            this.path = logPath;
        }
        private object @lock = new object();
        public void Log(string message) {
            string formattedMessage = "Date:" + DateTime.Now.ToString() + "\tMessage:" + message;
            File.AppendAllLines(this.path, new string[] { formattedMessage });
        }
    }

文件的输出是:

Date:6/12/2019 11:19:13 AM  Message:Started
Date:6/12/2019 11:19:13 AM  Message:From Form constructor

【问题讨论】:

  • 由于Session 0 isolation,您的表单不会显示在桌面上。它可能在 Session 0 上可见。您使用的是哪个版本的 Windows?有些允许您切换到会话 0。
  • 我正在使用Windows 10,你是对的,该服务必须独立于User 运行。它在每台机器上运行一个实例。

标签: winforms windows-services topshelf


【解决方案1】:

在会话 0 隔离(防止Shatter attacks 的重要安全措施)已成为法律的世界中,您应该非常仔细地考虑任何依赖服务交互的设计。

最佳做法是重新构建您的解决方案,以便:

  1. 在后台运行的服务,独立于 用户
  2. 与服务交互的传统 GUI 应用程序和 任何用户都可以运行

【讨论】:

  • 所以我不可能有一个原子进程来运行一个长时间运行的线程和一个GUI?在当前场景中,比安全更重要的是GUI 和另一个Thread 之间的距离。到目前为止,它们是同一进程中的两个tasks
  • 当然,您可以创建一个在启动时启动并启动 GUI 的原子进程。 Windows 对此没有任何限制。服务都是关于“长期运行”的,它们可以愉快地创建窗口和其他 GUI 元素。
  • 但是,当您希望某人从长时间运行的进程中与 GUI 交互时,就会出现问题。
  • 谁应该看到 GUI?有登录的人吗?只有第一个登录的人?假设第一次登录是通过 RDP,他们还能看到 GUI 吗?如果第一个人注销而第二个人登录会发生什么?第二个人能看到 GUI 吗?如您所见,事情变得非常复杂!
  • 此外,单进程方法被一个基本事实所削弱:每个进程必须驻留在单个会话中。在会话 0(启动时唯一可用的会话)中启动的进程无法在会话 1(第一个用户登录时创建的)中显示 GUI。此限制限制了服务与用户交互的方式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-05-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-22
  • 2017-03-14
相关资源
最近更新 更多