默认情况下,当用户没有在 Windows 上执行任何输入(没有鼠标键盘等的输入)并保持一定时间后,Windows 会自动切换到锁屏模式(或屏保模式),甚至待机。
一般情况下,这样不会有任何问题,而且也是推荐的设置(出于安全和节能的角度)。但是,如果这台电脑被用于进行一些自动化的测试,尤其是涉及到 UI 的交互操作时(比如,测试过程中用脚本操控鼠标来模拟点击一个按钮),这将会是个很大的问题:鼠标键盘失效了!UI 自动化做不下去了!
解决这个办法的方案很简单:设置 Windows 的电源模式,让 Windows 不要自动锁屏和待机,同时去掉屏保。
脚本自动化测试期间,执行测试的电脑几乎不能继续被他人使用(因为鼠标、键盘等输入设备此时需要响应自动化测试脚本)。为了不影响电脑使用,一般会搭一个虚拟机,然后远程连接到虚拟机里,在虚拟机里执行 脚本自动化测试。
但是,万一你不小心把某个远程桌面“最小化”了...GAME OVER,你的自动化测试就挂了。既然连最小化都会失败,相信你已经猜到直接关闭远程桌面的后果了。
为什么最小化或关闭远程连接的桌面会导致自动化测试失败呢?
要解释清楚这个原因,首先必须要了解3个在Windows 操作系统中的经常用到,却很陌生的对象:Session、Windows Station 和 Desktop。
用户会话,每个登录操作系统的用户都会分配一个唯一的登录会话,用于标识该用户。操作系统(2008 及以上)保留0号会话给一些系统服务及用户态的驱动使用,第1个登录系统的用户使用的 Session ID 为1,该用户执行的所有应用程序都在 Session 1 下执行。
我们可以打开任务管理器,切换到进程列表,然后在菜单->视图->选择列中,勾选 Session ID 列。
如果有其它的用户登录到系统,就会看到 Session ID 大于1的情况,比如远程桌面。
Station 可以理解为工作站,它被认为是桌面和进程的安全边界。因此,每一个 session 都会包含多个 station,而每一个 Station 又包含1个或多个 Desktop。
但是,多个 Station 中,只有名字叫 Winsta0 的 Station 才是交互式的 station,也就是说只有它才能有 UI 并接受用户输入。所以每个 Session 都有一个叫 Winsta0 的用户进行交互。
这里的 Desktop 并不是我们进入系统后所看到的那个蓝底的桌面(,我们看到的这个桌面,实际上只是一个窗口)。而是逻辑上的一个显示对象,它包含可显示的 GUI 对象(比如窗口、菜单、钩子等)。一般情况下,WinSta0 包含至少三个Desktop:登录(WinLogon)、屏保(ScreenSaver)和默认(Default,能看到所有应用程序的地方)。
同一时刻只能有一个Desktop处于激活状态(而能激活的 Desktop 只能属于 Winsta0)。用户还没登录的时候,登录桌面处于激活状态。登录之后,默认的Desktop处于激活状态。当达到系统电源设置的某个点的时候,系统切换到屏保,此时屏保Desktop处于激活状态。当用户按下 Ctrl + Alt + Delete 时,切换到登录Desktop,此时登录Desktop处于激活状态。
激活状态的Desktop才能接收用户输入,钩子才能获取其中的某个窗口消息。
如果你已经体验过 Win10,那应该就会知道 Win10 提供了很方便的创建多个Desktop的方式。
了解了上述三个对象后,就可以比较容易的解释出现问题的原因了。
最小化
最小化会让远程桌面的会话切换到无图形界面的模式,这自然就无法继续接收鼠标、键盘的指令了。
关闭远程桌面
关闭远程桌面会让系统切换到登录Desktop的界面,而在该Desktop上并没有我们打开的其它窗口,因此会导致 UI 自动化测试失败。
通过设置注册表的值可以阻止切换到无图形界面。
32位系统
找到 HKEY_LOCAL_MACHINE\Software\Microsoft\Terminal Server Client,创建一个 DWORD 类型的值,名字叫做 RemoteDesktop_SuppressWhenMinimized,然后设置值为 2。
64位系统
找到 HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Terminal Server Client,然后和 32 位一样创建一个DWORD 类型的值,名字叫做 RemoteDesktop_SuppressWhenMinimized,并设置值为 2。
上面的改动会应用于整个机器,如果只想应用于当前的用户,把 LOCAL 替换成 USER。
方案一:
在远程桌面(被连接到的电脑)中先执行 query session 来查看当前登录到的 session,(远程桌面的 sessionName 都以 rdp-tcp 开头)。
然后用管理员用户打开命令行工具,并执行 "tscon rdp-tcp#0 /dest:console",其中 rdp-tcp#0 为该该命令会关闭远程桌面的连接,然后把连接返回给远程的那台电脑(绕开登录过程)。这里的 console 只是一个 session 的名字,而这个名字的意思并非是 “控制台” 的意思,而是指带有输入输出设备的机器,一般直接登录电脑的会话就是 console。
假设电脑A执行 mstsc 连接到电脑B(连接成功后,电脑B黑屏),此时在电脑B上执行上述命令后(替换对应的session名字),电脑A中的远程连接窗口会被关闭,并提示远程连接会话已经终止。电脑B(假设运行在另一台物理机上)会恢复到已经登录的状态,如果需要重新让电脑B恢复锁屏状态,可以在电脑B上执行如下命令:
rundll32.exe user32.dll,LockWorkStation
方案二:
假设用于跑自动化的机器是虚拟机B,现在再使用另一台虚拟机A作为中转。本机先连接到虚拟机A,然后再从虚拟机A连接到虚拟机C,最后断开虚拟机A。
方案三:
先通过方案一查询console是哪个会话ID,上图所示为3
远程桌面mstsc远程登录虚拟机时,在虚拟机中新建文本文档,写入内容
@%windir%\System32\tscon.exe 0 /dest:console
@%windir%\System32\tscon.exe 1 /dest:console
@%windir%\System32\tscon.exe 2 /dest:console
@%windir%\System32\tscon.exe 3 /dest:console
将文本文档重新命名为‘Close_RDP’,并将后缀名改为‘.bat’,双击文件‘Close_RDP.bat’关闭远程链接。不过此方法存在不太稳定的情况,不推荐使用。经测试主要问题是出现在tscon.exe有的系统可以成功运行,有的会运行失败。得多找几个不同系统的tscon.exe测试保证成功。
方案四:经研究这个方法最可靠(后期代码实现在上传)
使用C#开源远程桌面连接软件Multi RDP Client .NET,当远程连接上后,最小化的情况下,鼠标键盘模拟仍然是生效的。另外由于是开源软件,所以我们可以在源码基础上,扩展自己的功能,比如说在自动化测试过程中,接收请求,自动远程连接相应机器,来满足自动化测试的需求。另外,使用第三方远程连接软件,我们可以将软件的数据保存到远程的数据库中,这样,我们只需要有软件,不需要知道机器密码就可以使用执行机器了。
以上几种解决远程桌面问题的方法,在工作中都有可能用到,比如说在脚本初期,我们使用到的机器不是太多的情况下,脚本的运行需要手工进行,这时,我们可以采用注册表法,这样就可以将远程桌面的窗口最小化到任务栏了;而当我们机器不断增多时,比如说自动化执行的机器超过了10个甚至更多,这时我们最好借助开源远程连接软件了。对于大规模的虚机管理,推荐使用开源远程连接软件来进行管理。
参考:https://www.cnblogs.com/bangejingting/p/6846480.html