为何调用WTSRegisterSessionNotification会出现拒绝访问(错误码5)?
WTSRegisterSessionNotification返回错误码5(拒绝访问)的成因与复现方法
问题背景
用户反馈在部分Windows 10和8.1设备上调用WTSRegisterSessionNotification时返回错误码5(拒绝访问),但在自身测试的Windows 10、8、7系统的管理员/普通用户账号中始终无法复现该Bug。相关Delphi代码如下:
type TForm1 = class(TForm) private { Private declarations } FWTSNotification: Boolean; protected procedure WndProc(var Msg: TMessage); override; procedure CreateWnd; override; procedure DestroyWindowHandle; override; public { Public declarations } end; ... procedure TForm1.CreateWnd; begin inherited; FWTSNotification:= WTSRegisterSessionNotification(Handle, NOTIFY_FOR_THIS_SESSION); if not FWTSNotification then begin var FLastError:= GetLastError; Raise Exception.Create(Format('WTSRegisterSessionNotification failed: [ErrorCode: #%d] - %s', [FLastError, SysErrorMessage(FLastError)])); end; end; ... procedure TForm1.WndProc(var Msg: TMessage); begin case Msg.Msg of WM_WTSSESSION_CHANGE: begin case Msg.wParam of WTS_SESSION_LOCK: ... WTS_SESSION_UNLOCK: ... WTS_CONSOLE_CONNECT: ... WTS_CONSOLE_DISCONNECT: ... end; end; else inherited; end; end; ... procedure TForm1.DestroyWindowHandle; begin if FWTSNotification then WTSUnRegisterSessionNotification(Handle); inherited; end;
错误成因分析
错误码5代表拒绝访问,结合WTSRegisterSessionNotification的系统特性,可能的触发原因包括:
- UAC权限与进程完整性级别限制:Windows 8.1及后续版本中,若程序以低完整性级别运行(比如从
Program Files这类受保护文件夹启动但未请求管理员权限,或被UAC虚拟化机制限制),调用该API会被系统拒绝。即使用户是管理员账号,程序未以管理员身份启动时也可能处于较低完整性级别。 - 多会话环境权限隔离:当设备处于多会话场景(如开启远程桌面、存在快速用户切换的其他登录会话),当前进程所在的会话可能没有足够权限注册全局或本地会话通知。例如在远程会话中运行程序,尝试注册本地控制台的会话通知时容易触发权限问题。
- 系统安全策略/组策略限制:部分设备通过组策略或本地安全策略,限制了普通用户注册会话通知的权限,比如在用户权限分配中移除了相关操作的权限。
- 窗口初始化时机问题:在
CreateWnd中调用API时,窗口句柄可能尚未完成系统层面的初始化,导致系统拒绝该注册请求(此场景相对少见,但特定系统环境下可能出现)。
复现方法
要复现该错误,可以尝试以下几种场景:
- 低完整性级别运行程序:
将程序放入C:\Program Files目录,以普通用户身份直接双击启动(不选择“以管理员身份运行”)。Windows会对该目录下的程序启用UAC虚拟化,降低进程完整性级别,此时调用WTSRegisterSessionNotification大概率返回错误码5。 - 远程桌面会话测试:
在Windows 10/8.1设备上开启远程桌面功能,从另一台设备登录到该设备的普通用户账号,然后运行目标程序,触发API调用。 - 快速用户切换场景:
在设备上先登录管理员账号,再切换到普通用户账号,在普通用户的会话中运行程序并调用WTSRegisterSessionNotification。 - 修改组策略限制:
打开本地组策略编辑器(运行gpedit.msc),导航至计算机配置>Windows设置>安全设置>本地策略>用户权限分配,调整相关权限(比如移除普通用户的“允许本地登录”权限),重启设备后用普通用户账号运行程序。
补充验证建议
- 调用API前,可通过
GetTokenInformation获取当前进程的完整性级别,确认是否处于低完整性状态。 - 尝试将
WTSRegisterSessionNotification的调用移至FormShow事件中并延迟执行,避免窗口句柄未完全初始化的问题。
内容的提问来源于stack exchange,提问作者Tigero
相关产品推荐
相关产品推荐

