Blog posts tagged: winapi

News and other things I find interesting


RSS Feed


Feb
22
2011

Five Windows 7 taskbar features available to developers

Last modified: Thursday, September 08, 2011

Believe it or not the Windows 1.0 taskbar looked very similar to the Windows 7 taskbar. But it obviously didn't have anywhere near same functionality.

Windows 1.0:

Windows 7:

The Windows 7 taskbar is pretty awesome. And it has some great functionality available to developers who wish to take advantage of it.


The 5 features...

1) Application progress in the taskbar: Progress for anything with visual displays of errors and warnings.

2) Overlay icons: Small icons within your icon for any type of user notification (below shows the online status as an overlay)

3) Custom thumbnail preview groupings: Thumbnail previews across processes or within a single process with tabs

4) Taskbar action buttons (Thumbnail toolbars): Buttons inside the taskbar icon's thumbnail preview

5) Jump lists: Easily create shortcuts to different startup types and other custom actions.


Before you start...

Before jumping into the interesting stuff, you need to get notified that the taskbar button was created.

There is a new message sent to your application called TaskbarButtonCreated, it is sent when Windows creates a taskbar button for your application on your application's behalf.

And once this message is sent to you, you can interact with your taskbar button (Not before!). To get the identifier of the message you need to call RegisterWindowMessage .

The important elements here in a typical MFC application would look like so:

//Get the message identifier
const int TaskBarButtonCreated = RegisterWindowMessage(L"TaskbarButtonCreated");

//Put this in your message map to register a callback
ON_REGISTERED_MESSAGE( TaskBarButtonCreated, CTaskBarTestAppDlg::OnTarbarButtonCreated )

//The actual callback
LRESULT CTaskBarTestAppDlg::OnTarbarButtonCreated(WPARAM wParam, LPARAM lParam)
{
  //Custom code here once the taskbar is created
}

1) Application progress in the taskbar

To show progress in your application icon you need to use 2 simple API calls: ITaskbarList3::SetProgressState and ITaskbarList3::SetProgressValue.

Your taskbar icon can have one of the following states:

  • No progress (default)
  • Intermediate (green and cycles repeatedly along the length of the taskbar button)
  • Paused (yellow progress bar)
  • error (red progress bar)
  • normal (green progress bar)

You can see this in action yourself when Windows explorer is copying a set of files and it encounters a locked file, the windows explorer icon will change to the error progress status which is red.

When you use SHFileOperation or the IFileOperation interface your taskbar icon will automatically update as well with progress.

To get your application icon to show progress for an indeterminate amount of time:

m_pTaskBarlist->SetProgressState(GetSafeHwnd(), TBPF_INDETERMINATE);

To set determinate progress you use one of TBPF_NORMAL, TBPF_ERROR, or TBPF_PAUSED. For example:

m_pTaskBarlist->SetProgressState(GetSafeHwnd(), TBPF_NORMAL);
m_pTaskBarlist->SetProgressValue(GetSafeHwnd(), 10, 100);
//...
m_pTaskBarlist->SetProgressValue(GetSafeHwnd(), 20, 100);
//...
m_pTaskBarlist->SetProgressValue(GetSafeHwnd(), 100, 100);
//...
m_pTaskBarlist->SetProgressState(GetSafeHwnd(), TBPF_NOPROGRESS);

The last parameter of SetProgressValue is the number of steps in your operation total, the second last parameter is the current number of steps already completed.


2) Overlay icons

Icon overlays on the actual taskbar icon can be accomplished by calling TaskbarList3::SetOverlayIcon.

The overlay icon should be a small icon, measuring 16x16 pixels at 96 dpi. In my experience though you can use any icon and Windows will scale it for you. Every time this method is called, the previous icons get removed.

m_pTaskBarlist->SetOverlayIcon(GetSafeHwnd(), hMyIcon, L"Descriptive string for accessibility");

3) Custom thumbnail preview groupings:

A single application which has a single process with tabs (Or an MDI application) can have multiple previews available to it.

Chrome 10 Beta does not take advantage of tab/thumbnail yet; however, IE9 does (as seen in my screenshot above in section #3).

Every time a tab is created you would call both RegisterTab and SetTabOrder like so:

HRESULT hr0 = m_pTaskBarlist->RegisterTab(hTab1, GetSafeHwnd());
m_pTaskBarlist->SetTabOrder(hTab1, NULL);

SetTabOrder can be used to specify the order of previews, passing in NULL appends the tab to the end of the list of previews.

You can remove a tab preview from your taskbar icon by calling UnregisterTab:

m_pTaskBarlist->UnregisterTab(hTab1);

But sometimes applications today span multiple processes. Both IE 9 and Chrome use one process per tab, and I believe that Firefox will eventually go this way too (They already do this for mobile phones).
The Windows 7 taskbar has this architecture covered (People bust Microsoft's ass a lot but in many cases they really deliver).

In this previous blog post, I talked about Sessions, Windows Stations, and Desktops. Well as of Windows 7 there is also something called Application IDs. Application IDs allows Windows to know what you view as an individual application. With multi process applications on the rise this becomes important. Application IDs can be associated with individual Windows. An application ID is a string of up to 128 characters.

The default application ID for a window is the same as the application ID for the process to which the Window belongs. Applications with the same application ID are grouped to the same taskbar icon.

You can set the application ID of a process using the Win32 API SetCurrentProcessExplicitAppUserModelID You can set the application ID of a window using the Win32 API SHGetPropertyStoreForWindow and then calling functions on the return result which is of type IPropertyStore.

Application IDs are assigned dynamically so they can be changed at any time which means you could do some pretty interesting things.


4) Taskbar action buttons (Thumbnail toolbars):

Thumbnail toolbars allow you to add functionality and buttons available to the user without switching their current application. For example Windows Media Player adds previous, pause, and next button support. To do this you create an array of THUMBBUTTON structures.

When a thumbnail button is clicked you receive a WM_COMMAND message with the high word of the wParam set to THBN_CLICKED and the low word set the button ID.

Each button can have either an individual icon being used or a bitmap from the taskbar's image list which was set through ITaskbarList3::ThumbBarSetImageList.

THUMBBUTTON thbButtons[2];

//Initialize the first button
thbButtons[0].dwMask = THB_BITMAP | THB_TOOLTIP | THB_FLAGS;
thbButtons[0].iId = 0;
thbButtons[0].iBitmap = 0;
wcscpy(thbButtons[0].szTip, L"Button 1");
thbButtons[0].dwFlags = THBF_DISMISSONCLICK;

//Initialize the second button
dwMask = THB_BITMAP | THB_TOOLTIP;
thbButtons[1].dwMask = THB_BITMAP | THB_TOOLTIP;
thbButtons[1].iId = 1;
thbButtons[1].iBitmap = 1;
wcscpy(thbButtons[1].szTip, L"Button 2");

//Add the buttons to the thumbnail window
m_pTaskBarlist->ThumbBarAddButtons(hTab1, _countof(thbButtons), thbButtons);

Each tab thumbnail preview can have its own set of thumbnail buttons.

You may notice that the first button above has the THBF_DISMISSONCLICK flag but the second does not. The difference is that when the first button is clicked the thumbnail preview will be closed, whereas if the second button is clicked, the thumbnail preview remains open. Other important flags are THBF_HIDDEN, THBF_ENABLED, and THBF_DISABLED.

After the buttons are created, they can be updated by using ITaskbarList3::ThumbBarUpdateButtons. You would want to update an existing button to for example disable it.

Each time a button is clicked the OnCommand virtual function of your dialog is specified:

virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam);

So you simply need to override this function for the window that is associated with the thumbnail preview:

BOOL CTaskBarTestAppDlg::OnCommand(WPARAM wParam, LPARAM lParam)
{
    UINT cmdID = LOWORD(wParam);
    switch(cmdID)
    {
    case ID_BUTTON1:
        MessageBox(_T("Button 1 was clicked"));
        break;
    case ID_BUTTON2:
        MessageBox(_T("Button 2 was clicked"));
        break;
    default:
        return CDialogEx::OnCommand(wParam, lParam);
    }
}

5) Jump lists:

There is a great article here on Jump lists, but I will give a quick overview.

Each application is associated with a Jump List.

You can customize the tasks area which is a set of actions. You can also customize the destination area which is a list of Recent items or Frequent items.

The recent items is calculated for you automatically as long as your application is the default handler for the associated document type. If you want to add somethign to the list you can use the Win32 API SHAddToRecentDocs.

You can customize custom areas of the jump list, for example Chrome includes a "Most visited section" and a "Recently closed" section.

Custom destinations are controlled by: ICustomDestinationList.


A couple other things you can do:

You can customize your taskbar thumbnails by specifying a clipped rectangle of your window:

RECT r = {0,0,100,100};
m_pTaskBarlist->SetThumbnailClip(GetSafeHwnd(), &r);

You can set a tooltip for your thumbnail previews as follows:

m_pTaskBarlist->SetThumbnailTooltip(GetSafeHwnd(), L"Test1");

Or if you have multiple tab thumbnail previews:

m_pTaskBarlist->SetThumbnailTooltip(hTab1, L"Test1");
m_pTaskBarlist->SetThumbnailTooltip(hTab2, L"Test1");

What about managed code?

There are a couple of good resources for tying into the taskbar API from managed languages:


Other reading:

Tags:

Add a new comment





Oct
19
2010

Understanding Windows at a deeper level - Sessions, Window Stations, and Desktops

Last modified: Monday, December 10, 2012

This post will answer some very simple questions about how Windows works. This post is meant to be read by people with a technical background, and at parts it will help if you have a little knowledge about programming in Windows.

If you don't fully know the answer to any of the questions below, then you should read this post:

  • Ever wonder what happens when you lock your computer? What happens to all of the open programs? How about your task bar?
  • What is so special about UAC anyway? How do they lock and dim the whole screen? Does it really protect me?
  • Why don't software key loggers work anymore to capture a locked computer's password?
  • What's so special about screen savers? How do they work?
  • How can there be more than one user at a time logged onto the same computer at the same time?
  • How does Terminal Services or Remote Desktop work?
  • Why does your remote computer control software probably suck?
  • What does the "Allow services to interact with desktop" checkbox do on the NT services property page?
  • Why was Vista perceived to be so bad and Windows 7 so good?

To understand how all of the above works, you need to understand the concept of something called Sessions, Window Stations, and Desktops.

Some of the below may be a little heavy, but it's worth learning it to see how Windows really works.

A gentle introduction to Sessions:

Each program you have on your computer, when run is considered a process. A process is a program which is being executed. Each process is the program code, a collection of threads, and other resources relating to the program.

Each process in Windows belongs to a single user who started that process, and each process also belongs to something called a Session. Each Session in Windows hosts a collection of processes, windows, Window Stations, Desktops, and several other resources. Window Stations and Desktops will be covered later in this post.

You can see a list of all of the processes on your computer by going into Task Manager (taskmgr.exe) and clicking on the "Processes" tab. In this list you can see the Username of the user who started the process and also the Session that the process belongs to. By default Windows will not show you the Session each process belongs to but you can easily see it by clicking on the View menu item and then "Select Columns..." Turn on the option "Session ID".

Each process belongs to exactly 1 Session and each Session has a Session ID which identifies it. You cannot change a process' Session after the process is started. In Task Manager you will see at least 1 Session if you are using an operating system below Windows Vista and you will see at least 2 Sessions if you are using an operating system of Vista or above.

In Windows you are not limited to that initial number of Sessions though. There can be many different Sessions, there is a limit that can be reached but we'll say for the sake of conversation that you can potentially have infinite Sessions.

If you're using Vista or above, the first Session, Session 0 is where all of the NT services are started. The second Session above 0 is where the first logged on user's programs will be started.

More Sessions than what I mentioned will occur anytime you have multiple users logged into the same machine. You can have multiple users logged into the same machine via Terminal Services, Remote Desktop, or multi user logins onto the same machine via switch-user. For each additional login operation that you make, a new Session is made.

You can use CreateProcessAsUser to create a process in another Session. To do this you must use a user token which will contain the associated Session. To set the Session on the user token you can use the Win32 API SetUserToken with a token information class of TokenSessionId.

So to recap, so far we understand that inside your Windows operating system (OS) you have the following:

  • Session 0
    • Process 0.1
    • Process 0.2
    • Process 0.3
    • ...
    • Process 0.N
  • Session 1
    • Process 1.1
    • Process 1.2
    • Process 1.3
    • ...
    • Process 1.N
  • ...
  • Session M
    • Process M.1
    • Process M.2
    • Process M.3
    • ...
    • Process M.N

How Vista changes how Sessions work:

Before Windows Vista, the first logged in user and the NT services shared the first Session which was Session 0. This Session was also allowed to be interactive.

Windows Vista and above started to put user Sessions separate from NT service Sessions. It also made sure that Session 0 was not interactive.

These changes with Vista were made for security reasons. The security reason the change was made, was to ensure that services would be safe from application code. Why do services need to be protected? Because services run at an elevated privilege when run as the System account and hence have access to do things a user program shouldn't be able to control. More on this later in the section: "How to circumvent all security in Windows".

How Sessions worked Pre-Vista with 3 logged on users:

Pre-Vista how Sessions work

How Sessions worked Post-Vista with 3 logged on users:

Pre-Vista how Sessions work

The difference of the 2 diagrams being that the first logged on user has his own Session in the Post-Vista diagram.

Window Stations:

Each Session contains a collection of Window Stations, a clipboard, and more. Each Window station has a name unique to the Session it belongs to. Meaning within a Session each Window Station is unique. But across Sessions two Window Stations can share a name but they are completely distinct.
You can think of a Window Station as a security boundary. Once a Window Station is created, you cannot change the Session that it belongs to.

Each process belongs to a single Window Station but unlike Sessions vs. Processes, a single process can change its Window Station after startup time.

The following Win32 API can be used to deal with Window Stations: GetProcessWindowStation, SetProcessWindowStation, CreateWindowStation, and OpenWindowStation.

There is one special Window Station called Winsta0 for every session. WinSta0 is the only Window Station that can display a user interface and receive user input, it uses the keyboard, mouse and display. Other Window stations cannot display graphical user interfaces nor receive user input.

A process can set a Window Station, to associate itself with, by calling the Win32 API SetProcessWindowStation.
Once a process sets its Window Station it can then access things inside that Window Station such as Desktops, and the clipboard. Desktops will be discussed later.

Each process actually has a parent process. When your process gets started, if you aren't dealing with Window Station code directly it will put you in the same Window Station as your parent process. A process can create new Window stations with the Win32 API CreateWindowStation

So to recap , so far we understand that inside your Windows OS you have the following:

  • Session 0
    • Winsta0
      • Some Processes
    • Winsta1
      • Some Processes
    • ...
    • WinstaN
      • Some Processes
  • Session 1
    • Winsta0
      • Some Processes
    • Winsta1
      • Some Processes
    • ...
    • WinstaN
    • Some Processes
  • ...
  • Session M
    • Winsta0
      • Some Processes
    • Winsta1
      • Some Processes
    • ...
    • WinstaN
      • Some Processes

Windows Desktops

Each Window Station contains a collection of Desktops. A Desktop is loaded into kernel memory space and is a logical display surface. Any GUI object is allocated here.

Each Windows Desktop belongs to a single Session and also a single Window Station.

Only one Desktop at a time can be active (displayed) per Session. And by definition it must belong to WinSta0. The active Desktop is called the input Desktop. One can always get a handle to the active Desktop within ones own Session by calling OpenInputDesktop

WinSta0 has 3 Desktops loaded:

  1. Winlogon (the logon screen)
  2. Default (the user Desktop)
  3. ScreenSaver

There is a 4th Desktop on Vista and higher called the "Secure Desktop" which is used by default in UAC prompts.

When you lock your workstation you perform a Desktop swtich from the Default Desktop to the WinLogon Desktop.

As far as NT services go, each NT service that has credentials specified will create its own Window Station and Desktop.

The following Win32 API can be used to deal with Desktops:

  • To set a Desktop for a thread you can call SetThreadDesktop
  • A process can create a new Desktop by calling CreateDesktopEx, when a new Desktop is created it will be assigned into the Window Station associated with the calling process.

When starting a process you can specify which Window Station and Desktop to start it in. You can do this with the STARTUP info structure and the lpDesktop member. Typically this is called from a function like CreateProcessAsUser or CreateProcess.

So to recap , so far we understand that inside your Windows OS you have the following:

  • Session 0
    • Station Winsta0
      • Desktop Winlogon
        • Some processes
      • Desktop Default
        • Some processes
      • Desktop Screensaver
        • Some processes
      • Desktop UAC
        • Some processes
      • Some other Desktops
        • Some processes
    • Station Winsta1
      • Some other Desktops
        • Some processes
    • ...
    • Station WinstaN
      • Some other Desktops
        • Some processes
  • Session 1
    • Station Winsta0
      • Desktop Winlogon
        • Some processes
      • Desktop Default
        • Some processes
      • Desktop Screensaver
        • Some processes
      • Desktop UAC
        • Some processes
      • Some other Desktops
        • Some processes
    • Station Winsta1
      • Some other Desktops
        • Some processes
    • ...
    • Station WinstaN
      • Some other Desktops
        • Some processes
  • ...
  • Session M
    • Station Winsta0
      • Desktop Winlogon
        • Some processes
      • Desktop Default
        • Some processes
      • Desktop Screensaver
        • Some processes
      • Desktop UAC
        • Some processes
      • Some other Desktops
        • Some processes
    • Station Winsta1
      • Some other Desktops
        • Some processes
    • ...
    • Station WinstaN
      • Some other Desktops
        • Some processes

Mysterious checkbox in the services tab (Optional Read)

There is a little mysterious checkbox that appears in the property page of each of your services called "Allow services to interact with Desktop".

This checkbox decides that your service will run under the Window Station Winsta0 or under a different Window Station that doesn't allow user interaction. This checkbox is not guaranteed to be supported forever, and will probably eventually disapear, but it is supported up to Windows 7 so far.

This checkbox can be turned on for any service via the registry, so this by itself may be a security risk. So I would think the checkbox will probably be removed.

If this checkbox is ON, then a new Session is created and a new Window Station called Winsta0. If the service tries to display a GUI, then active user Sessions in front of a GUI will get a notification that there is a GUI on another Desktop trying to be displayed. You can then click on it to view that GUI. A user can also chose to be reminded again in 5 minutes time about the GUI notification. When you view this new Desktop it will usually look like a blank screen except for the service GUI itself.

If this checkbox is OFF, and the service tries to display a GUI, nothing will happen to any visible Desktop. The service gets started in Session 0. The GUI calls will succeed but no GUI will ever be shown.

Windows Handles

Windows inside the Windows OS are children of Desktop objects.

A Window is any GUI element and is usually identified by a Windows handle (HWND). It is important to understand where Windows Handles fit into the whole picture because then you can understand what you can do across Desktops and what you cannot do across Desktops.

Communication across Sessions

Depending on the type of communication, inter-Session communication is possible.

Things like pipes, global events, and sockets allow you to communicate across Sessions.

Things like Windows Messages, and local events do not allow you to communicate across Sessions.

As I mentioned earlier Windows Vista made a gigantic change to how Windows works by starting all of the services inside Session 0. This meant that a ton of programs which were built as Windows services and used to display a GUI no longer could display that GUI.

The proper way to display a GUI for service code now is to do some kind of inter-Session communication such as a pipe and have the GUI program be a separate program which communicates with your service.

A second way to display a GUI from a service is to simply launch the process within another user's Session inside Winsta0 and the Default Desktop.

Communication across Desktops

Windows messages are not possible across Desktops. Windows messages are only possible within the same Desktop. As confirmed here: Inter-Desktop communication via message passing is not possible.

This means that Windows Hooks which allow you to monitor and get notifications for any message from another process can only be installed at a Desktop Level.

So a key logger for example wouldn't be allowed to have access to what is typed when a computer is locked in a different Desktop.

After enumerating the Desktops you can enumerate the windows inside each Desktop.
You can use the Win323 API EnumDesktopWindows to enumerate these Desktop windows. The purpose of me telling you this is that this function takes in a handle to a Desktop and it returns to you a handle to the Windows inside that Desktop. This reinforces what I've been saying about Windows being children of Desktops.

How to circumvent all security in Windows

It is actually possible to do anything you want in Windows in any Session, Window Station, or Desktop. The solution is to build a service running on your computer running as the Local System Account.

As long as this service is running elevated via a manifest file, it can obtain the token and linked token of any process in any Session, and start a helper program within that same token to do anything it wishes to. This is probably exactly how Windows Task Manager works.

//UAC creates 2 tokens.  The second one is the restricted token and the first one is the one returned by LogonUser
//Vista and above links the elevated token to the Logonuser token though :))))
TOKEN_LINKED_TOKEN tlt;
DWORD len;
if(GetTokenInformation(hToken
    , (TOKEN_INFORMATION_CLASS)TokenLinkedToken
    , &tlt, sizeof(TOKEN_LINKED_TOKEN)
    , &len))
{
    hLinkedToken = tlt.LinkedToken;
    //From here you can start elevated processes
}

Tying it all together

Now is the fun part when we can now answer each of the questions in turn:

Ever wonder what happens when you lock your computer? What happens to all of the open programs? How about your task bar?

When you lock your computer you are doing a Desktop switch from the Default Desktop to the Winlogon Desktop which are both within the same Window Station WinSta0. Both Desktops are also within the same Session of course.

This also means that there are many such login screens across Sessions and many different users logged in could each be at their own version of this screen at the same time on the same computer.

What is so special about UAC anyway? How do they lock and dim the whole screen? Does it really protect me?

When you get a UAC prompt, by default what happens is you switch from the Default Desktop to the Secure Desktop. UAC takes a screenshot of your Default Desktop, applies a dim to that image and then displays it behind the UAC window. The UAC window is part of the Secure Desktop The user can actually set if UAC prompts should run under the current Desktop (less secure) or the Secure Desktop.

Why don't software key loggers work anymore to capture a locked computer's password?

I remember as a kid writing a key logger and using it at school. I was able to see everyone's login password, then later I could login as them and see all of their files. Since then multi Session operating systems have been introduced though.

Because Software Keyloggers are based off of Windows Hooks which work with Windows messages. They get notified for every keystroke that occurs because each keystroke has its own set of Windows Messages (key down, key up, key pressed). Since the key logger is started on a different Desktop it cannot log a password.

I think it would be possible to build such a KeyLogger which would work across Sessions but I'm not aware of any that exist. To learn how see the section: "How to circumvent all security in Windows"

What's so special about screen savers? How do they work?

There's nothing special about a screensaver. It doesn't hide any of your GUI elements nor draw on top of them. It simply does a Desktop switch to the Screensaver Desktop. Remember, a Desktop is a logical graphical device.

How can there be more than one user at a time logged onto the same computer at the same time?

Easy, each user has its own Session, and each Session contains everything else. Each person using a Session sees their own Desktop which is part of that Session's WinSta0 Window Station.

How does Terminal Services or Remote Desktop work?

Terminal Services and Remote Desktop work by either giving you access to an already open Session, or creation a new Session. Each Session can be in a connected or disconnected state.

Why does your remote computer control software probably suck?

Some remote computer control software (not Terminal Services / Remote Desktop) are not Session aware and they only work with the first Session. This includes most VNC servers including FogCreek Copilot.

If you have a multi-Session computer you can't control each Session.

Can a process communicate across different Sessions?

Yes but you need to use the correct communication means.

Can a process communicate across Desktops with Windows messages?

No.

Why was Vista perceived to be so bad and Windows 7 so good?

Because Windows Vista was the first to implement these changes. Windows Vista therefore was the Operating System to break all of the existing changes. Many software development companies and their products took a lot of time to implement the changes needed to support Session 0 isolation. Most probably still don't fully understand it.

Since some of the changes weren't made in time, Windows Vista took the hit for looking bad. But of course it was Vista's fault in the first place for breaking compatibility.

I'm not claiming Vista was perfect, it was far from it; however, Vista took more of a hit than it deserved.

Further reading

Tags:

Add a new comment | 5 comment(s)

Gravatar image asf on Sunday, October 24, 2010 (11:10:05) says:

There are actually two things called a session, a terminal services session and the type of session you didn't talk about; [win]logon session. Processes from different logon sessions can run on the same desktop (RunAs etc)

Gravatar image Benjamin on Sunday, November 07, 2010 (01:11:07) says:

Great post. Thank you. I have some questions.
1. What if a process change its Window Station? If the process is a gui app, the application can't display gui anymore?
2. If so, when should we change Windows Station? I haven't ever used the Apis. What processes are in Windows Station1~N?
3. What happen when we do logoff an acount. Will the Session and Window Station, Desktop, Process be destroyed?
What if we log on again as same account?

Gravatar image He Zhiqiang on Thursday, December 09, 2010 (08:12:26) says:

This post helps me a lot. Thank you!

In the 4th paragraph of the Windows Stations section, the first sentence "There is one special Window Station called Winsta0 for every station", I think it should be "There is one special Window Station called Winsta0 for every session".

A question: Since only the WinStat0 can display UI to the user, why should the other stations have Desktop inside? As you have described, this stations has no chance to display UI anyway.

Gravatar image Brian R. Bondy on Sunday, February 06, 2011 (07:02:11) says:

Sorry guys I do not have all answers here, but I suggest to make an app that can answer it for you.

Gravatar image Kris on Friday, February 17, 2012 (09:02:13) says:

Good article. Is there any easier way to query desktop windows for all sessions or single session?