C++ Windows 服务如何执行 GUI 应用程序?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/267838/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can a Windows service execute a GUI application?
提问by sep
I have written a Windows service that allows me to remotely run and stop applications. These applications are run using CreateProcess, and this works for me because most of them only perform backend processing. Recently, I need to run applications that present GUI to the current log in user. How do I code in C++ to allow my service to locate the currently active desktop and run the GUI on it?
我编写了一个 Windows 服务,允许我远程运行和停止应用程序。这些应用程序使用 CreateProcess 运行,这对我有用,因为它们中的大多数只执行后端处理。最近,我需要运行向当前登录用户显示 GUI 的应用程序。如何在 C++ 中编码以允许我的服务定位当前活动的桌面并在其上运行 GUI?
回答by mdb
Roger Lipscombe's answer, to use WTSEnumerateSessionsto find the right desktop, then CreateProcessAsUserto start the application on that desktop (you pass it the handle of the desktop as part of the STARTUPINFOstructure) is correct.
Roger Lipscombe 的答案是使用WTSEnumerateSessions找到正确的桌面,然后使用CreateProcessAsUser在该桌面上启动应用程序(您将桌面句柄作为STARTUPINFO结构的一部分传递给它)是正确的。
However, I would stronglyrecommend against doing this. In some environments, such as Terminal Server hosts with many active users, determining which desktop is the 'active' one isn't easy, and may not even be possible.
但是,我强烈建议不要这样做。在某些环境中,例如具有许多活动用户的终端服务器主机,确定哪个桌面是“活动”桌面并不容易,甚至可能是不可能的。
But most importantly, if an application will suddenly appear on a user's desktop, this may very well occur at a bad time (either because the user simply isn't expecting it, or because you're trying to launch the app when the session isn't quite initialized yet, in the process of shutting down, or whatever).
但最重要的是,如果应用程序突然出现在用户的桌面上,这很可能发生在不合适的时间(因为用户根本没有预料到它,或者因为您试图在会话未启动时启动应用程序) '还没有完全初始化,在关闭的过程中,或者其他什么)。
A more conventional approach would be to put a shortcut to a small client app for your service in the global startup group. This app will then launch along with every user session, and can be used start other apps (if so desired) without any juggling of user credentials, sessions and/or desktops.
一种更传统的方法是在全局启动组中为您的服务添加一个小型客户端应用程序的快捷方式。然后,此应用程序将与每个用户会话一起启动,并且可以用于启动其他应用程序(如果需要),而无需处理用户凭据、会话和/或桌面。
Also, this shortcut can be moved/disabled by administrators as desired, which will make deployment of your application much easier, since it doesn't deviate from the standards used by other Windows apps...
此外,管理员可以根据需要移动/禁用此快捷方式,这将使您的应用程序的部署更加容易,因为它不会偏离其他 Windows 应用程序使用的标准......
回答by mlarsen
The short answer is "You don't", as opening a GUI program running under another user context is a security vulnerability commonly known as a Shatter Attack.
简短的回答是“你不知道”,因为打开在另一个用户上下文下运行的 GUI 程序是一个安全漏洞,通常称为Shatter Attack。
Take a look at this MSDN article: Interactive Services. It gives some options for a service to interact with a user.
看看这篇 MSDN 文章:交互式服务。它为服务与用户交互提供了一些选项。
In short you have these options:
简而言之,您有以下选择:
Display a dialog box in the user's session using the WTSSendMessage function.
Create a separate hidden GUI application and use the CreateProcessAsUser function to run the application within the context of the interactive user. Design the GUI application to communicate with the service through some method of interprocess communication (IPC), for example, named pipes. The service communicates with the GUI application to tell it when to display the GUI. The application communicates the results of the user interaction back to the service so that the service can take the appropriate action. Note that IPC can expose your service interfaces over the network unless you use an appropriate access control list (ACL).
If this service runs on a multiuser system, add the application to the following key so that it is run in each session: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run. If the application uses named pipes for IPC, the server can distinguish between multiple user processes by giving each pipe a unique name based on the session ID.
使用 WTSSendMessage 函数在用户会话中显示一个对话框。
创建一个单独的隐藏 GUI 应用程序并使用 CreateProcessAsUser 函数在交互式用户的上下文中运行该应用程序。设计 GUI 应用程序以通过某种进程间通信 (IPC) 方法(例如,命名管道)与服务进行通信。该服务与 GUI 应用程序通信以告诉它何时显示 GUI。应用程序将用户交互的结果传达回服务,以便服务可以采取适当的行动。请注意,除非您使用适当的访问控制列表 (ACL),否则 IPC 可以通过网络公开您的服务接口。
如果此服务在多用户系统上运行,请将应用程序添加到以下项,以便它在每个会话中运行:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run。如果应用程序为 IPC 使用命名管道,则服务器可以通过基于会话 ID 为每个管道指定唯一名称来区分多个用户进程。
回答by Roger Lipscombe
WTSEnumerateSessions and CreateProcessAsUser.
WTSEnumerateSessions 和 CreateProcessAsUser。
回答by Windows programmer
Several people suggested WTSEnumerateSessions and CreateProcessAsUser. I wonder why no one suggested WTSGetActiveConsoleSessionId, since you said you only want to target one logged in user.
有几个人建议使用 WTSEnumerateSessions 和 CreateProcessAsUser。我想知道为什么没有人建议 WTSGetActiveConsoleSessionId,因为你说你只想定位一个登录用户。
Several people sure are right to suggest CreateProcessAsUser though. If you call plain old CreateProcess the way you said, then the application's GUI will run with your service's privileges instead of the user's privileges.
不过,有几个人确实建议 CreateProcessAsUser 是正确的。如果您按照您所说的方式调用普通的旧 CreateProcess,那么应用程序的 GUI 将使用您的服务的权限而不是用户的权限运行。
回答by mtaskopru
That problems Session 0 , Interactive Services , Windows Service Allow Service To Interact With Desktop on Windows 7 or Windows Vista
Session 0、Interactive Services、Windows Service 允许服务与 Windows 7 或 Windows Vista 上的桌面交互的问题
You can read this article http://www.codeproject.com/KB/vista-security/SubvertingVistaUAC.aspx
你可以阅读这篇文章 http://www.codeproject.com/KB/vista-security/SubvertingVistaUAC.aspx
I try explained here it's working on Windows 7
我尝试在这里解释它在 Windows 7 上工作
回答by Franci Penov
On Win2K, XP and Win2K3 the console user is logged on in Session 0, the same session the services live in. If a service is configured as interactive, it'll be able to show the UI on the user's desktop.
在 Win2K、XP 和 Win2K3 上,控制台用户登录到会话 0,即服务所在的会话。如果服务配置为交互式,它将能够在用户桌面上显示 UI。
However, on Vista, no user can be logged on in Session 0. Showing UI from a service there is a bit trickier. You need to enumerate the active sessions using WTSEnumerateSessionsAPI, find the console session and create the process as that user. Of course, you need also a token or user credentials to be able to do that. You can read more details about this process here.
但是,在 Vista 上,没有用户可以在会话 0 中登录。显示来自服务的 UI 有点棘手。您需要使用WTSEnumerateSessionsAPI枚举活动会话,找到控制台会话并以该用户身份创建进程。当然,您还需要令牌或用户凭据才能执行此操作。您可以在此处阅读有关此过程的更多详细信息。
回答by Franci Penov
Important Services cannot directly interact with a user as of Windows Vista. Therefore, the techniques mentioned in the section titled Using an Interactive Service should not be used in new code.
重要服务不能直接与 Windows Vista 的用户交互。因此,不应在新代码中使用标题为使用交互式服务的部分中提到的技术。
This is taken from : http://msdn.microsoft.com/en-us/library/ms683502(VS.85).aspx
这取自:http: //msdn.microsoft.com/en-us/library/ms683502(VS.85).aspx
回答by Treb
I think as long as you have only one user logged in, it will automatically display on that user's desktop.
我认为只要您只有一个用户登录,它就会自动显示在该用户的桌面上。
Anyway, be very careful when having a service start an exe.
无论如何,在让服务启动 exe 时要非常小心。
If the write access to the folder with the exe is not restricted, any user can replace that exe with any other program, which will then be run with sytem rights. Take for example cmd.exe (available on all windows sytems). The next time the service tries to start your exe, you get a command shell with system rights...
如果对带有 exe 的文件夹的写访问权限不受限制,则任何用户都可以用任何其他程序替换该 exe,然后该程序将使用系统权限运行。以 cmd.exe 为例(适用于所有 Windows 系统)。下次该服务尝试启动您的 exe 时,您将获得一个具有系统权限的命令外壳...
回答by mkoeller
If you launch a GUI from your service it will show up on the currently active desktop.
如果您从您的服务启动 GUI,它将显示在当前活动的桌面上。
But only if you adjusted the service permissions: You need to allow it to interact with the desktop.
但前提是你调整了服务权限:你需要允许它与桌面交互。