我有一个问题,我有一个正在启动和停止应用程序的 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++;
}
}
如果有办法完成这件事,我将永远欠你的情,我觉得我已经尝试了一切。
要解决 Windows 服务启动在后台运行的应用程序的问题,您需要了解现代 Windows 操作系统所施加的限制和安全约束。服务通常在与登录用户不同的会话中运行,并且无法直接访问用户的桌面。这就是为什么您从服务启动的应用程序不会出现在前台。
解决方案概述
1 - 使用辅助应用程序:
创建一个在用户会话中运行的单独应用程序。该应用程序可以在前台处理启动进程。
使用进程间通信 (IPC) 方法(例如命名管道、WCF 或其他 IPC 机制)在 Windows 服务和帮助程序应用程序之间进行通信。
2- 使用任务计划程序:
3-利用CreateProcessAsUser:
详细实施
第 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 步: 确保助手应用程序在用户登录时运行
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);
}
}
}
}
#CSharp #WindowsService #ProcessManagement #IPC #DotNet #ProgrammingTips #WindowsAPI #SoftwareDevelopment #UserSession #TaskScheduler