窗口站(window station):
包含剪贴板(clipboard),一个原子表,一个或多个桌面(desktop)对象.窗口站是一个保护对象,当一个窗口站被创建,它被分配到当前进程和当前会话(session).
交互式窗口站Winsta0是唯一的可以显示用户接口和接受用户输入的窗口站,它被分配到当前用户的登录会话,并且包含键盘,鼠标和显示器,其他窗口站都不能显示用户接口和接受用户输入.
当一个用户登录到一个终端服务(Terminal Service)计算机,一个会话被启动,每个会话被分配到自己的交互式窗口站.
桌面对象(desktop):
桌面对象有一个逻辑界面并包含用户接口对象(例如:窗口,菜单,钩子),它可以被用来创建和管理窗口,每个桌面对象是保护对象,当桌面对象被创建,它被分配给当前的线程所在的窗口站.
消息只能在同一个桌面上的进程间发送,所以钩子过程也只能在一个指定的桌面上接受消息.
每个被分配到Winsta0窗口站的桌面对象可以显示用户接口和接受用户输入,但是同一时间只有一个桌面对象是活动的,可以使用OpenInputDesktop和SwitchDesktop去取得和切换不同的桌面.
在默认情况下,有3个桌面对象在Winsta0窗口站:默认桌面(default),屏幕保护和登录窗口(Winlogon),屏幕保护和登录窗口是保护桌面.非保护的屏幕保护运行在Winsta0/default.
登录窗口(Winlogon)在用户登录的过程被激活,当外壳(shell)指示它将已经可以显示什么的时候,系统切换到默认桌面.在用户会话过程中当用户按下CTRL+ALT+DEL或在UAC对话框被打开的情况下将切换到登录桌面.
应用程序不能访问登录桌面,同时应用程序也不能在登录桌面被激活的情况下切换桌面.
系统自动创建交互式窗口站,当一个用户登录时可以系统将交互式窗口站绑定到一个会话上.同时建立一个默认桌面,可以用CreateWindowStation函数去创建一个新的窗口站,CreateDesktop和CreateDesktopEx建立桌面.
当一个非界面进程(例如服务进程)试图连接到一个窗口站,若没有窗口站存在在该进程所在的会话上,那么系统将在该会话上创建一个窗口站和桌面,新创建的窗口站名字是基于登录会话标识符,桌面对象名称描述如下:
如果一个服务运行在LocalSystem并且没有包含SERVICE_INTERACTIVE_PROCESS属性,那么它使用下面的窗口站和桌 面:Service-0x0-3e7$/default.这个窗口站是非交互的,所以这个服务不能显示用户接口,它创建的进程也不能显示用户界面.
如果服务运行在用户安全上下文,则窗口站的命名是在基于用户SID,0xZ1-Z2$,其中Z1是登录SID的高地址部分,Z2是登录SID低地址部分,两个服务运行在同一个安全上下文中.
一个进程在它第一次调用USER32或GDI32函数的时候会自动的连接到窗口站和桌面,系统使用以下规律来决定一个进程究竟连接到什么窗口站或桌面:
1.如果进程调用SetProcessWindowStation函数,该进程将连接到指定的窗口站上.
2.如果进程没有调用SetProcessWindowStation,它将连接到父进程的窗口站上.
3.如果进程没有调用SetProcessWindowStation,也没有继承父进程的窗口站,则系统打开MAXIMUM_ALLOWED访问标识符并使用下列规则连接到窗口站:
如果窗口站名称在创建进程的时候被写到STARTUPINFO.lpDesktop,则进程被连接到指定的窗口站.
否则,如果进程运行在交互用户的登录会话,进程将连接到激活的窗口站中.
如果进程运行在非交互的登录会话中,窗口站名称是基于登录会话标识符的,并尝试连接到该窗口站和桌面.若不存在,则建立窗口站和默认的桌面.
将进程连接到一个窗口站:
分配给某个进程的窗口站不能通过CloseWindowStation被关闭.
当进程连接到一个窗口站,系统在进程的句柄表查找进程继承的句柄,系统使用第一个找到的窗口站句柄.如果希望一个子进程连接到继承的窗口站上,你必须保证只有希望的句柄被标识上.如果有多个继承的窗口站句柄,则最后连接上的窗口站是不确定的.
系统已经在窗口站中打开的句柄在连接一个进程到一个窗口站中的时候是不能被继承的.
将线程连接到一个桌面:
在一个进程连接到一个窗口站后,系统分配一个桌面给线程,系统根据以下规则决定该桌面被分配哪个线程:
1.如果线程调用SetThreadDesktop,该线程被连接到指定的桌面上.
2.如果线程没有调用SetThreadDesktop,它连接到通过父进程继承的桌面上.
3.如果线程没有调用SetThreadDesktop,也没有继承桌面,则系统尝试使用MAXIMUM_ALLOWED权限,并根据以下规则打开桌面:
如果桌面的名称被指定在STARTUPINFO.lpDesktop,则线程连接到指定的桌面上.
否则线程连接到所在进程连接的窗口站中的默认桌面上.
被分配的桌面在连接期间不能通过CloseDesktop关闭.
当进程连接一个桌面的时候,系统在进程的句柄表中查询继承的句柄.系统使用第一个查到的桌面句柄,如果你希望子进连接到一个指定的桌面上,你必须确定只有希望的句柄被标识为可继承的,如果一个子进程继承了多个桌面句柄,则最终连接到的左面是不确定的.
系统打开的桌面句柄在进程连接到桌面是不可继承的.