有没有办法从Windows服务在前台打开程序

问题描述 投票:0回答:1

我有一个问题,我有一个正在启动和停止应用程序的 Windows 服务。 应用程序的会话正在启动,但它们在后台运行。 对于我需要做的事情,我需要将它们带到前台,以便用户能够监控它们是否正确运行。 我们的想法是制作一个控制台应用程序,但这项服务的重点是让用户从另一台 PC 控制会话。 请记住,已经有一个为此服务启动并运行的 API 可以控制程序的启动和停止。 到目前为止我发现的所有内容都是让我寻找主窗口句柄,但由于这些程序在后台打开,主窗口句柄为 0,这可能会返回正常,因为我无法访问它。任何提示或技巧都会非常有帮助

这就是我为启动产品会话所做的操作,但它们使用 0 CPU 在后台运行。

public static void StartProcess(int Year, int sessionCount, string filepath, string newProcess)
        {
            int i = 1;
            while (i <= sessionCount)
            {
                try
                {
                    System.Diagnostics.Process cmdProcess = new System.Diagnostics.Process();
            System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
                if (newProcess.Contains("Program1"))
                {
                    //Needs to be set this way so the widow is visible.
                    startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Maximized;
                        startInfo.UseShellExecute = true;
                        startInfo.CreateNoWindow = false;
                        ProcessStartInfo psi = new ProcessStartInfo(newProcess);
                    Process.Start(psi);
                }
                else if (newProcess.Contains("Program2"))
                {
                    startInfo.WindowStyle = ProcessWindowStyle.Normal;
                    startInfo.Arguments = "\"" + filepath + "\""; ;
                    startInfo.FileName = newProcess;
                        cmdProcess.StartInfo = startInfo;
                        cmdProcess.Start();
                                  }
                }
                catch (Exception ex)
                {
                    AppLogger appLogger = new AppLogger();
                    if (newProcess == "")
                    {
                        appLogger.LogError("The process could not be found. Please verify the product and year");
                    }
                    else
                    {
                        appLogger.LogError(ex.Message);
                    }
                }

                i++;
            }
        }

如果有办法完成这件事,我将永远欠你的情,我觉得我已经尝试了一切。

c# service process
1个回答
0
投票

要解决 Windows 服务启动在后台运行的应用程序的问题,您需要了解现代 Windows 操作系统所施加的限制和安全约束。服务通常在与登录用户不同的会话中运行,并且无法直接访问用户的桌面。这就是为什么您从服务启动的应用程序不会出现在前台。

解决方案概述

1 - 使用辅助应用程序:

  • 创建一个在用户会话中运行的单独应用程序。该应用程序可以在前台处理启动进程。

  • 使用进程间通信 (IPC) 方法(例如命名管道、WCF 或其他 IPC 机制)在 Windows 服务和帮助程序应用程序之间进行通信。

2- 使用任务计划程序:

  • 安排任务在登录用户的上下文中运行。这可确保应用程序在用户会话中启动并出现在前台。

3-利用CreateProcessAsUser:

  • 模拟用户并使用 CreateProcessAsUser API 在用户会话中启动进程。这需要适当的权限和安全令牌的处理。

详细实施

  1. 创建助手应用程序

第 1 步: 开发助手应用程序

  • 此应用程序在用户会话中运行并侦听来自服务的命令。

  • 它可以是保持隐藏或最小化的简单 Windows 窗体或 WPF 应用程序。

第2步:实现IPC通信

  • 使用命名管道、WCF 或其他 IPC 方法来允许服务向帮助器应用程序发送命令。

  • 例如,使用命名管道:

// In the Helper Application
using System;
using System.Diagnostics;
using System.IO.Pipes;
using System.Threading.Tasks;

public class Program
{
    public static void Main()
    {
        Task.Run(() => ListenForCommands());
        // Keep the application running
        System.Windows.Forms.Application.Run();
    }

    private static void ListenForCommands()
    {
        using (var pipeServer = new NamedPipeServerStream("ProcessControlPipe"))
        {
            pipeServer.WaitForConnection();
            using (var reader = new StreamReader(pipeServer))
            {
                string command;
                while ((command = reader.ReadLine()) != null)
                {
                    // Parse command and start process
                    Process.Start(command);
                }
            }
        }
    }
}

// In the Windows Service
using System.IO.Pipes;

public static void StartProcess(string processPath)
{
    using (var pipeClient = new NamedPipeClientStream(".", "ProcessControlPipe", PipeDirection.Out))
    {
        pipeClient.Connect();
        using (var writer = new StreamWriter(pipeClient))
        {
            writer.WriteLine(processPath);
        }
    }
}

第 3 步: 确保助手应用程序在用户登录时运行

  • 将帮助程序应用程序添加到用户的启动程序中,或使用 Windows 任务计划程序在用户登录时启动它。

2- 使用任务计划程序

您可以以编程方式创建在用户上下文中运行的计划任务:

using Microsoft.Win32.TaskScheduler;

public void StartProcessInUserSession(string processPath)
{
    using (TaskService ts = new TaskService())
    {
        TaskDefinition td = ts.NewTask();
        td.RegistrationInfo.Description = "Start process in user session";

        td.Triggers.Add(new LogonTrigger());

        td.Actions.Add(new ExecAction(processPath, null, null));

        ts.RootFolder.RegisterTaskDefinition(@"StartUserProcess", td);
    }
}

3-使用CreateProcessAsUser

此方法涉及更复杂的安全令牌处理:

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Principal;

public class ProcessStarter
{
    [DllImport("advapi32.dll", SetLastError=true)]
    public static extern bool CreateProcessAsUser(
        IntPtr hToken,
        string lpApplicationName,
        string lpCommandLine,
        ref SECURITY_ATTRIBUTES lpProcessAttributes,
        ref SECURITY_ATTRIBUTES lpThreadAttributes,
        bool bInheritHandles,
        uint dwCreationFlags,
        IntPtr lpEnvironment,
        string lpCurrentDirectory,
        ref STARTUPINFO lpStartupInfo,
        out PROCESS_INFORMATION lpProcessInformation);

    // Define SECURITY_ATTRIBUTES, STARTUPINFO, PROCESS_INFORMATION structures...

    public static void StartProcess(string processPath)
    {
        // Obtain user token, e.g., from WTSGetActiveConsoleSessionId and WTSQueryUserToken
        // Then call CreateProcessAsUser with the token and desired process path
    }
}

注意:实现CreateProcessAsUser需要仔细处理用户令牌和安全性,建议参考详细的微软文档和示例。

优化现有代码

在解决前台问题的同时,你还可以优化现有的 StartProcess 方法,以获得更好的可读性和可维护性:

public static void StartProcess(int year, int sessionCount, string filepath, string newProcess)
{
    for (int i = 1; i <= sessionCount; i++)
    {
        try
        {
            var startInfo = new ProcessStartInfo
            {
                FileName = newProcess,
                UseShellExecute = true,
                CreateNoWindow = false,
                WindowStyle = newProcess.Contains("Program1") ? ProcessWindowStyle.Maximized : ProcessWindowStyle.Normal,
                Arguments = newProcess.Contains("Program2") ? $"\"{filepath}\"" : null
            };

            Process.Start(startInfo);
        }
        catch (Exception ex)
        {
            var appLogger = new AppLogger();
            if (string.IsNullOrEmpty(newProcess))
            {
                appLogger.LogError("The process could not be found. Please verify the product and year");
            }
            else
            {
                appLogger.LogError(ex.Message);
            }
        }
    }
}

要记住的要点

  • 服务和用户会话:服务在不同的会话中运行,由于安全限制,在现代 Windows 版本中无法直接与用户桌面交互。
  • 帮助应用程序: 用户模式帮助应用程序是与桌面交互并在用户会话中启动进程所必需的。
  • 安全注意事项:确保使用的任何 IPC 机制都是安全的,并且不会使您的系统面临潜在的漏洞。
  • 错误处理:改进错误处理和日志记录,以便在启动流程时更好地诊断问题。

#CSharp #WindowsService #ProcessManagement #IPC #DotNet #ProgrammingTips #WindowsAPI #SoftwareDevelopment #UserSession #TaskScheduler

© www.soinside.com 2019 - 2024. All rights reserved.