6

I have a program that switches desktop and start a new process on it. When the process exits, the parent process restores the original desktop.

For testing purposes, I put a button in a plain win32 app that triggers the switch. It works, and closing the launched process (notepad), I go back to the original desktop.

In that same program, I have called WTSRegisterSessionNotification to receive a notification when a session is unlocked (WTS_SESSION_UNLOCK). I receive it.

But when I try to switch desktops in WTS_SESSION_UNLOCK message handler, SwitchDesktop fails and GetLastError is 0. The documentation says that last error is usually not set by SwitchDesktop.

Funny enough, if I put my call to switch desktop in a for loop, it works on the 5th iteration.

In short, this does not work :

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

But this ugly hack works :

    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;

Setting a timer (to exit the message loop) also works, but it is just a more convoluted form of loop with regards to this problem. SwitchDesktop will work on after a handfull of WM_TIMER messages. It looks like constant time, although I did not measure it.

MSDN documentation for SwitchDesktop mentions that this will fail with a custom Userinit process, which I use. But getting the name of the current desktop just before the switch :

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

Gives me default all the time. And since GetLastError is 0, not 5 (access denied) I am pretty sure the secure desktop is gone before I receive the WTS_SESSION_UNLOCK notification.

I known I can't switch desktop while the screen is locked, but is there a "grace period" after the desktop is unlocked in which I can't call SwitchDesktop ?

ixe013
  • 9,559
  • 3
  • 46
  • 77

3 Answers3

3

When the desktop gets locked, it switches to another desktop which is reserved for this purpose. It is quite possible that when you receive the message, that desktop is still in control and you're not allowed to switch because you're not running in the current desktop.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • Possible, indeed. I used OutputDebugString timestamp to check for that, but I will add code that specifically checks for that. Stay tuned ! – ixe013 Feb 03 '12 at 15:53
  • @ixe013: Have you able to run that test? I have to award this bounty and want to know which answer was most helpful to you. – Ben Voigt Feb 05 '12 at 19:50
  • @BenVoigt I would say Yahia deserves the bounty. Thank you, I will paty it forward ! – ixe013 Feb 06 '12 at 02:13
  • @MarkRansom : It looks like when the WTS_SESSION_UNLOCK notification is sent, Windows already switched desktop. I always get `default` when I retreive the name of the desktop (before trying to change it again myself). – ixe013 Feb 06 '12 at 02:15
  • 1
    @BenVoigt, I don't mind missing out on the bounty. I just wish that a better answer had been forthcoming. – Mark Ransom Feb 06 '12 at 03:07
  • @ixe013: Ok, bounty awarded. I don't know what you meant by "paty it forward", but the bounty comes out of my rep and I have plenty to spare, you don't need to do anything. You just had a really good question. – Ben Voigt Feb 06 '12 at 04:39
2

I can't test it right now but I would put the call to SwitchDesktop not on WTS_SESSION_UNLOCK but on WTS_CONSOLE_CONNECT. From what I gather WTS_SESSION_UNLOCK occurs first and then your get WTS_CONSOLE_CONNECT which would correspond to what you see with the "constand time"...

Yahia
  • 69,653
  • 9
  • 115
  • 144
  • +1 for the good idea, but not quite the answer... Calling SwitchDesktop on WTS_CONSOLE_CONNECT does work the first time, every time. But WTS_CONSOLE_CONNECT is not called when the user locks and unlocks his session. To trigger a WTS_CONSOLE_CONNECT, I must select "Switch user" in the CTRL-ALT-DEL menu. I get back to the secure desktop with all the user's tiles. I can log back in with the same user and I will get WTS_CONSOLE_CONNECT. – ixe013 Feb 01 '12 at 04:25
  • @ixe013 Just wondering, did you ever find a solution to this? I somehow came across the same issue – CC Inc Jun 14 '13 at 23:39
  • I did something that worked on all the computers I was tested on, but it qualifies as a hack, not a solution. I basically did two things. 1. I added `WTS_CONSOLE_CONNECT` in the `switch` statement of my question, guided by Yahia. 2. After switching (no matter what is the result), I launch a process in the *new* desktop. That new process also tries to switch the desktop. In other words, the first process tries to "push" the user to a new desktop, while the second tries to "pull" him over. Switching is always in retry a loop. +The question is still unanswered, @CCInc ! – ixe013 Jun 15 '13 at 01:05
0

SwitchDesktop fails (with error 0) because (accordingly to MSDN) it belongs to a window station not (yet) visible. There is no user notification I know of that says "the HWINSTA become visible".

Cristian Amarie
  • 160
  • 1
  • 8