C# 从Windows服务启动GUI应用程序-未显示窗口

C# 从Windows服务启动GUI应用程序-未显示窗口,c#,windows,windows-services,C#,Windows,Windows Services,我已经编写了一个简单的windows服务,它将启动 onstart()服务的方法。启动服务后,exe仅启动它 在内存中显示,但在资源管理器中不显示 我正试图从我的代码中启动一个calc.exe。它在内存中显示exe,但是 不进入我的视野(即在浏览器中) 下面是我在onStart()方法中启动exe的代码 根据定义,服务不是交互式的,所以当您从服务启动应用程序时,不应该期望显示任何用户界面元素 这是出于设计…服务在不同的帐户权限下运行(LocalService/NetworkService等),因

我已经编写了一个简单的windows服务,它将启动
onstart()
服务的方法。启动服务后,exe仅启动它 在内存中显示,但在资源管理器中不显示

我正试图从我的代码中启动一个
calc.exe
。它在内存中显示exe,但是 不进入我的视野(即在浏览器中)

下面是我在onStart()方法中启动exe的代码


根据定义,服务不是交互式的,所以当您从服务启动应用程序时,不应该期望显示任何用户界面元素


这是出于设计…

服务在不同的帐户权限下运行(LocalService/NetworkService等),因此它们无法访问您的桌面(在您的登录帐户的控制下)


服务意味着默默地完成他们的工作,这是他们应该做的。(除了在windows事件日志中记录一些重要内容之外)

服务在Vista或更高版本的其他会话中运行,默认情况下,直接从服务启动的应用程序在同一会话中启动。可以在其他会话中启动应用程序-您必须找到用户会话的id并使用CreateProcessAsUser

如果有多个用户登录,并且需要为所有用户启动程序,则必须找到所有会话的ID

以下是示例代码:

int session = Win32.WTSGetActiveConsoleSessionId();
if (session == 0xFFFFFFFF)
{
    return false;
}

IntPtr userToken;
bool res = Win32.WTSQueryUserToken(session, out userToken);
if (!res)
{
    this.log.WriteEntry("Error WTSQueryUserToken");
    return false;
}

string path = GetPath();
string dir = Path.GetDirectoryName(path);
Win32.STARTUPINFO si = new Win32.STARTUPINFO();
si.lpDesktop = "winsta0\\default";
si.cb = Marshal.SizeOf(si);

Win32.PROCESS_INFORMATION pi = new Win32.PROCESS_INFORMATION();
Win32.SECURITY_ATTRIBUTES sa = new Win32.SECURITY_ATTRIBUTES();
sa.bInheritHandle = 0;
sa.nLength = Marshal.SizeOf(sa);
sa.lpSecurityDescriptor = IntPtr.Zero;

if (!Win32.CreateProcessAsUser(userToken,       // user token
                                path,           // exexutable path
                                string.Empty,   // arguments
                                ref sa,         // process security attributes ( none )
                                ref sa,         // thread  security attributes ( none )
                                false,          // inherit handles?
                                0,              // creation flags
                                IntPtr.Zero,    // environment variables
                                dir,            // current directory of the new process
                                ref si,         // startup info
                                out pi))        // receive process information in pi
{
    int error = Marshal.GetLastWin32Error();
    this.log.WriteEntry("Error CreateProcessAsUser:" + error);
    return false;
}

正如前面提到的,windows服务“通常”在单独的帐户(“LocalSystem”或“NetworkService”)下运行。这就是为什么您可能看不到由您的服务启动的程序的UI的原因。此外,服务并不打算有UI,它们充当后台服务

但也要注意,通过服务启动应用程序可能会有很高的安全风险,因为应用程序使用与服务相同的权限运行。通常这将是本地系统帐户


我不知道你想用你的服务来实现什么,但是考虑使用Windows的自动启动功能而不是服务来运行你的应用程序。

< P>如果你打开你的服务的属性窗口,转到登录标签,然后检查“允许服务与桌面交互”复选框,你将得到你想要的行为。此外,根据您要运行的应用程序,您可能需要更改登录帐户。

您希望看到什么?请尝试运行批处理文件。您尝试启动哪种类型的exe?请将您的问题重新表述为更有意义的问题。当浏览一系列问题时,它不会告诉你很多……而且,默认情况下,任务管理器只显示在您的登录帐户下运行的进程。
int session = Win32.WTSGetActiveConsoleSessionId();
if (session == 0xFFFFFFFF)
{
    return false;
}

IntPtr userToken;
bool res = Win32.WTSQueryUserToken(session, out userToken);
if (!res)
{
    this.log.WriteEntry("Error WTSQueryUserToken");
    return false;
}

string path = GetPath();
string dir = Path.GetDirectoryName(path);
Win32.STARTUPINFO si = new Win32.STARTUPINFO();
si.lpDesktop = "winsta0\\default";
si.cb = Marshal.SizeOf(si);

Win32.PROCESS_INFORMATION pi = new Win32.PROCESS_INFORMATION();
Win32.SECURITY_ATTRIBUTES sa = new Win32.SECURITY_ATTRIBUTES();
sa.bInheritHandle = 0;
sa.nLength = Marshal.SizeOf(sa);
sa.lpSecurityDescriptor = IntPtr.Zero;

if (!Win32.CreateProcessAsUser(userToken,       // user token
                                path,           // exexutable path
                                string.Empty,   // arguments
                                ref sa,         // process security attributes ( none )
                                ref sa,         // thread  security attributes ( none )
                                false,          // inherit handles?
                                0,              // creation flags
                                IntPtr.Zero,    // environment variables
                                dir,            // current directory of the new process
                                ref si,         // startup info
                                out pi))        // receive process information in pi
{
    int error = Marshal.GetLastWin32Error();
    this.log.WriteEntry("Error CreateProcessAsUser:" + error);
    return false;
}