【问题标题】:What makes SwitchDesktop not work right after a user unlocks it session?是什么让 SwitchDesktop 在用户解锁会话后无法正常工作?
【发布时间】:2018-02-16 01:05:31
【问题描述】:

我有一个程序可以切换桌面并在其上启动一个新进程。当进程退出时,父进程恢复原来的桌面。

出于测试目的,我在一个普通的 win32 应用程序中放置了一个按钮来触发开关。它工作,并关闭启动的进程(记事本),我回到原来的桌面。

在同一个程序中,我调用了 WTSRegisterSessionNotification 以在会话解锁 (WTS_SESSION_UNLOCK) 时接收通知。我收到了。

但是当我尝试在 WTS_SESSION_UNLOCK 消息处理程序中切换桌面时,SwitchDesktop 失败并且 GetLastError 为 0。文档说最后一个错误通常不是由 SwitchDesktop 设置的。

很有趣,如果我将切换桌面的调用放在 for 循环中,它会在第 5 次迭代中运行。

简而言之,这是行不通的:

    case WM_WTSSESSION_CHANGE:
      if(wParam == WTS_SESSION_UNLOCK)          
      {
          SwitchDesktop(a_valid_desktop_handle);
      }
    break;

但是这个丑陋的黑客是有效的:

    case WM_WTSSESSION_CHANGE:
      if(wParam == WTS_SESSION_UNLOCK)          
      {
         for(int i=0; i<10; ++i)
         {
            if(SwitchDesktop(a_valid_desktop_handle))
            {
                //This will work when i == 5, maybe 6.
                break;
            }
         }
      }
    break;

设置一个计时器(退出消息循环)也可以,但就这个问题而言,它只是一种更复杂的循环形式。 SwitchDesktop 将在少量 WM_TIMER 消息后运行。它看起来像常数时间,虽然我没有测量它。

MSDN documentation for SwitchDesktop 提到这将因我使用的自定义 Userinit 进程而失败。但是在切换之前获取当前桌面的名称:

wchar_t name[512];
GetUserObjectInformation(GetThreadDesktop(GetCurrentThreadId()), UOI_NAME, name, sizeof(name)/sizeof(*name), 0);
OutputDebugString(name);

一直给我default。由于GetLastError 是 0,而不是 5(拒绝访问),我很确定安全桌面已经消失我收到 WTS_SESSION_UNLOCK 通知之前。

我知道在屏幕锁定时我无法切换桌面,但在桌面解锁后是否有一个“宽限期”我无法调用 SwitchDesktop?

【问题讨论】:

    标签: windows winapi wtsapi32


    【解决方案1】:

    当桌面被锁定时,它会切换到另一个为此目的而保留的桌面。很有可能当您收到消息时,该桌面仍处于控制状态,并且您无法切换,因为您没有在当前桌面中运行。

    【讨论】:

    • 确实有可能。我使用了 OutputDebugString 时间戳来检查它,但我将添加专门检查它的代码。敬请期待!
    • @ixe013:你能运行那个测试吗?我必须奖励这个赏金,并想知道哪个答案对你最有帮助。
    • @BenVoigt 我会说 Yahia 应该得到赏金。谢谢,我会转发的!
    • @MarkRansom :看起来当 WTS_SESSION_UNLOCK 通知发送时,Windows 已经切换了桌面。当我检索桌面名称时(在尝试自己再次更改之前),我总是得到default
    • @BenVoigt,我不介意错过赏金。我只是希望能有更好的答案。
    【解决方案2】:

    我现在无法对其进行测试,但我会拨打SwitchDesktop 的电话,而不是WTS_SESSION_UNLOCK,而是WTS_CONSOLE_CONNECT。从我收集到的WTS_SESSION_UNLOCK 首先出现然后你得到WTS_CONSOLE_CONNECT 这将对应于你在“恒定时间”中看到的......

    【讨论】:

    • +1 是个好主意,但不是完全正确的答案...在 WTS_CONSOLE_CONNECT 上调用 SwitchDesktop 确实是第一次,每次都有效。但是当用户锁定和解锁他的会话时,不会调用 WTS_CONSOLE_CONNECT。要触发 WTS_CONSOLE_CONNECT,我必须在 CTRL-ALT-DEL 菜单中选择“切换用户”。我回到带有所有用户磁贴的安全桌面。我可以用同一个用户重新登录,我会得到 WTS_CONSOLE_CONNECT。
    • @ixe013 只是想知道,你有没有找到解决方案?我不知何故遇到了同样的问题
    • 我做了一些在我测试过的所有计算机上都可以工作的东西,但它被认为是一种 hack,而不是解决方案。我基本上做了两件事。 1. 在 Yahia 的指导下,我在问题的 switch 声明中添加了 WTS_CONSOLE_CONNECT。 2.切换后(不管结果如何),我在new桌面启动了一个进程。该新进程还尝试切换桌面。换句话说,第一个进程试图将用户“推”到一个新桌面,而第二个进程试图“拉”他过来。切换总是在重试一个循环。 +这个问题仍然没有答案,@CCInc!
    【解决方案3】:

    SwitchDesktop 失败(错误 0),因为(根据 MSDN)它属于一个(还)不可见的窗口站。我所知道的没有用户通知说“HWINSTA 变为可见”。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-05-25
      • 1970-01-01
      • 1970-01-01
      • 2015-05-10
      • 2018-11-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多