At Loss for Words

…of Programming, Love and Metaphors

Desktops on Windows ultimately broken by every other application using IsWorkstationLocked

,

How could a short snippet of a bad Delphi code have affected whole Windows ecosystem resulting in completely and ultimately unusable desktops. I could guess. It has something to do with the nature of coding monkeys to copy and paste seemingly working code first and leave wondering about consequences until something breaks.

There is a nice few particularly EPIC FAILures in Windows API applications ecosystem that make use of a certain features a pain in the arse, but this one just completely disables the feature of multiple desktops for each and every session.

Symptoms

You have decided to use some software that uses separated desktop. Attempt to switch to desktop other than "default" (the one with TaskBar) succeeds. But only for a fraction of second, or just a few seconds. Then the default desktop restores for no apparent reason... Unfortunately this problem affects not only my recently released Supervisor application, but also tools like Desktops from Mark Russinovich himself.

Two years ago I traced this issue to Miranda IM. A simple patch which I contributed was almost immediately accepted, and for a while it was all good. Few days ago I found out that on my new Windows 7 computer, with many applications installed, I am yet again unable to use desktops. First step was to shutdown Miranda, then other program, and another, but the problem remains. Today, I still don't know, what program causes the problem. I'll let you know when I find out, but I bet you are curious about something else.

Cause

The original WRONG code appeared at some point in 2001 and might be even older. From that point almost every programmer, who wanted to determine whether the workstation is locked, copied, pasted and used the following code:

function IsWorkstationLocked: Boolean;
var
  hDesktop: HDESK;
begin
  Result := False;
  hDesktop := OpenDesktop('defualt', 0, False, DESKTOP_SWITCHDESKTOP);
  if hDesktop <> 0 then
  begin
    Result := not SwitchDesktop(hDesktop);
    CloseDesktop(hDesktop);
  end;
end;
This code is WRONG. Do not use it! See better solution below!

Please, take a few seconds and look at the code. Do you see what exactly is wrong? You probably do because of the context of this article. The original author probably thought to himself: Workstation locks down to Logon desktop. And SwitchDesktop fails when on Logon desktop. Thus when SwitchDesktop fails, the workstation must be locked. This reasoning is flawed. It misses the important fact, which you now definitely see, that the workstation could be switched to different desktop than "default". Although it still returns the correct value, as a side effect, it switches back to default desktop.

Intermezzo: I was going to list here a lot of links where someone advises to use that wrong code, but if you are interested, just google for "IsWorkstationLocked", almost ALL have it wrong. You will find it even on the stackoverflow.com. Who knows how many applications use this code.

Fix

The CORRECT code is similar in nature to the first one. But instead of opening "default" desktop and trying to switch to it, we just try to open current desktop. And since the Logon desktop is secured, the system won't let us open it. The corrected version of IsWorkstationLocked has thus one less function call and is even simpler.

bool IsWorkstationLocked () {
    if (HDESK hDesk = OpenInputDesktop (0, FALSE, DESKTOP_SWITCHDESKTOP)) {
        CloseDesktop (hDesk);
        return false;
    } else
        return true;
}
This is the CORRECT code. Fix your application if you have been using the previous one!

Solution

But. Presenting correct code and sending patches to open-source applications may help improve future development, it won't fix the current state. And the current state is that tools that create/use other desktops are unusable if you are not lucky enough.

I really don't see how could be this mess fixed without intervention from Microsoft. There are few options I can think of, each and every having its pros and cons.

  1. Add a AllowSwitchToDefaultDesktop API function, which would have an application have to call, before it would be able to switch to default desktop. The con is obviously the backward compatibility. But the cost is not that great since there is only a few applications that use SwitchDesktop for its intended purpose.
  2. Add a compatibility shim that would cause SwitchDesktop not to switch yet still return the expected value. But this way, the compatibility team would have to examine all the applications that use SwitchDesktop whether they do it right or wrong.
  3. Do nothing. Which will most likely be done.

Conclusion

...is that I don't really have one. If you really need the IsWorkstationLocked function or know someone who does, make sure that you/they use the correct version. Otherwise you might be later unable to use some cool application.

Update 27.3.2010

As I finally found out, the problem was caused by DisplayFusion (3.1.8 version only) ...great program by the way, with great support. The second day after I reported this bug, Jon Tackabury posted a fixed beta version. As if it were just for me :)

Blízké setkání s VW Passat R36Naming key HTML page elements