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 ?
9 个解决方案
#1
50
Roger Lipscombe's answer, to use WTSEnumerateSessions to find the right desktop, then CreateProcessAsUser to start the application on that desktop (you pass it the handle of the desktop as part of the STARTUPINFO structure) is correct.
Roger Lipscombe的回答是,使用wtsenumeratesession寻找正确的桌面,然后CreateProcessAsUser在那个桌面上启动应用程序(你把桌面的句柄作为STARTUPINFO结构的一部分传递给它)是正确的。
However, I would strongly recommend 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.
一种更传统的方法是在global startup group中为您的服务设置一个小客户端应用程序的快捷方式。该应用程序将随每个用户会话一起启动,并且可以使用start其他应用程序(如果需要的话),而不需要处理用户凭证、会话和/或桌面。
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应用程序使用的标准……
#2
16
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程序是一个安全漏洞,通常称为“破坏攻击”。
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.
使用WTSSendMessage函数在用户会话中显示一个对话框。
-
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).
创建一个单独的隐藏GUI应用程序,并使用CreateProcessAsUser函数在交互用户的上下文中运行应用程序。通过一些进程间通信(IPC)的方法设计GUI应用程序以与服务通信,例如,命名管道。服务与GUI应用程序通信,告诉它何时显示GUI。应用程序将用户交互的结果传递回服务,以便服务能够采取适当的操作。注意,IPC可以通过网络公开您的服务接口,除非您使用适当的访问控制列表(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.
如果该服务在多用户系统上运行,请将应用程序添加到以下键,以便在每个会话中运行:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\ run。如果应用程序为IPC使用命名管道,服务器可以根据会话ID为每个管道指定唯一名称,从而区分多个用户进程。
#3
6
WTSEnumerateSessions and CreateProcessAsUser.
WTSEnumerateSessions CreateProcessAsUser。
#4
5
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.
一些人建议使用wtsenumeratesession和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将使用您的服务的特权而不是用户的特权运行。
#5
2
That problems Session 0 , Interactive Services , Windows Service Allow Service To Interact With Desktop on Windows 7 or Windows Vista
问题在于会话0,交互服务,Windows服务允许服务与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上工作
#6
1
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 WTSEnumerateSessions API, 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有点麻烦。您需要使用wtsenumeratesqueues API枚举活动会话,找到控制台会话并作为该用户创建流程。当然,还需要一个令牌或用户凭据才能做到这一点。您可以在这里阅读有关此过程的更多细节。
#7
0
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,然后使用sytem权限运行该程序。例如cmd。exe(可在所有windows系统上使用)。下次当服务试图启动exe时,您将获得具有系统权限的命令shell……
#8
0
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.
但是,只有当您调整了服务权限:您需要允许它与桌面交互。
#9
0
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
#1
50
Roger Lipscombe's answer, to use WTSEnumerateSessions to find the right desktop, then CreateProcessAsUser to start the application on that desktop (you pass it the handle of the desktop as part of the STARTUPINFO structure) is correct.
Roger Lipscombe的回答是,使用wtsenumeratesession寻找正确的桌面,然后CreateProcessAsUser在那个桌面上启动应用程序(你把桌面的句柄作为STARTUPINFO结构的一部分传递给它)是正确的。
However, I would strongly recommend 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.
一种更传统的方法是在global startup group中为您的服务设置一个小客户端应用程序的快捷方式。该应用程序将随每个用户会话一起启动,并且可以使用start其他应用程序(如果需要的话),而不需要处理用户凭证、会话和/或桌面。
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应用程序使用的标准……
#2
16
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程序是一个安全漏洞,通常称为“破坏攻击”。
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.
使用WTSSendMessage函数在用户会话中显示一个对话框。
-
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).
创建一个单独的隐藏GUI应用程序,并使用CreateProcessAsUser函数在交互用户的上下文中运行应用程序。通过一些进程间通信(IPC)的方法设计GUI应用程序以与服务通信,例如,命名管道。服务与GUI应用程序通信,告诉它何时显示GUI。应用程序将用户交互的结果传递回服务,以便服务能够采取适当的操作。注意,IPC可以通过网络公开您的服务接口,除非您使用适当的访问控制列表(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.
如果该服务在多用户系统上运行,请将应用程序添加到以下键,以便在每个会话中运行:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\ run。如果应用程序为IPC使用命名管道,服务器可以根据会话ID为每个管道指定唯一名称,从而区分多个用户进程。
#3
6
WTSEnumerateSessions and CreateProcessAsUser.
WTSEnumerateSessions CreateProcessAsUser。
#4
5
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.
一些人建议使用wtsenumeratesession和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将使用您的服务的特权而不是用户的特权运行。
#5
2
That problems Session 0 , Interactive Services , Windows Service Allow Service To Interact With Desktop on Windows 7 or Windows Vista
问题在于会话0,交互服务,Windows服务允许服务与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上工作
#6
1
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 WTSEnumerateSessions API, 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有点麻烦。您需要使用wtsenumeratesqueues API枚举活动会话,找到控制台会话并作为该用户创建流程。当然,还需要一个令牌或用户凭据才能做到这一点。您可以在这里阅读有关此过程的更多细节。
#7
0
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,然后使用sytem权限运行该程序。例如cmd。exe(可在所有windows系统上使用)。下次当服务试图启动exe时,您将获得具有系统权限的命令shell……
#8
0
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.
但是,只有当您调整了服务权限:您需要允许它与桌面交互。
#9
0
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