# Windows Stations and Desktops in General

## Recommended Posts

Well hello again guys, my second thread here. I recently decided that I would like to create my own virtual desktop program (like Cube DeskTop or something). I've done quite a lot of research and found that there are three desktops that the computer starts of with; Winlogon, Default and Screensaver. I started off knowing nothing, but now I know a few things and am doing some tests, such as how to enumerate through all the desktops. But I've already run into a little snag... for some reason my program only tells me that there is the Default desktop and says nothing about the Winlogon or screensaver desktops, why is that?
#include <windows.h>

#define TEST MessageBox(MainWindow, "Success.", "Report", MB_OK);
#define DesktopsList 1001
#define DesktopSearch 1002

HINSTANCE hInstance = NULL;

HDESK TempDesk = NULL;

HWND MainWindow     = NULL;
HWND DesktopsListLB = NULL;
HWND DesktopSearchB = NULL;

BOOL CALLBACK DesktopSearchProc(LPTSTR DesktopName, LPARAM lParam);
LRESULT CALLBACK MainWNDProc(HWND MainWindow, UINT Msg, WPARAM wParam, LPARAM lParam);

INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nShowCmd)
{

WNDCLASSEX WNDClass;
MSG Msg;

ZeroMemory(&WNDClass, sizeof(WNDClass));

WNDClass.cbSize = sizeof(WNDClass);
WNDClass.style = CS_HREDRAW | CS_VREDRAW;
WNDClass.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
WNDClass.hInstance = hInstance;
WNDClass.lpfnWndProc = MainWNDProc;
WNDClass.lpszClassName = "MainWNDClass";

RegisterClassEx(&WNDClass);

MainWindow = CreateWindowEx(NULL, WNDClass.lpszClassName, "Welcome", WS_VISIBLE | WS_OVERLAPPED | WS_MINIMIZEBOX | WS_SYSMENU | WS_CAPTION, CW_USEDEFAULT, CW_USEDEFAULT, 233, 480, NULL, NULL, hInstance, NULL);

ShowWindow(MainWindow, nShowCmd);
UpdateWindow(MainWindow);

while(GetMessage(&Msg, NULL, NULL, NULL) > 0)
{

TranslateMessage(&Msg);
DispatchMessage(&Msg);

}

return Msg.wParam;

}

BOOL CALLBACK DesktopSearchProc(LPTSTR DesktopName, LPARAM lParam)
{

return TRUE;

}

LRESULT CALLBACK MainWNDProc(HWND MainWindow, UINT Msg, WPARAM wParam, LPARAM lParam)
{

switch(Msg)
{

case WM_CREATE:

DesktopsListLB = CreateWindowEx(NULL, "LISTBOX", "DesktopsListLB", WS_CHILD | WS_VISIBLE | LBS_STANDARD, 15, 12, 200, 100, MainWindow, (HMENU)DesktopsList, hInstance, NULL);
DesktopSearchB = CreateWindowEx(NULL, "BUTTON", "Search for Desktops", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 15, 118, 200, 20, MainWindow, (HMENU)DesktopSearch, hInstance, NULL);

//TempDesk = CreateDesktop("TempDesk", NULL, NULL, NULL, DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW | DESKTOP_ENUMERATE | DESKTOP_HOOKCONTROL | DESKTOP_JOURNALPLAYBACK | DESKTOP_JOURNALRECORD | DESKTOP_READOBJECTS | DESKTOP_SWITCHDESKTOP | DESKTOP_WRITEOBJECTS, NULL);

//SwitchDesktop(TempDesk);

break;

case WM_COMMAND:

switch(LOWORD(wParam))
{

case DesktopSearch:

while(SendMessage(DesktopsListLB, LB_GETCOUNT, NULL, NULL) != 0) SendMessage(DesktopsListLB, LB_DELETESTRING, NULL, NULL);

EnumDesktops(GetProcessWindowStation(), DesktopSearchProc, NULL);

break;

}

break;

case WM_CLOSE:

DestroyWindow(MainWindow);

break;

case WM_DESTROY:

PostQuitMessage(WM_QUIT);

break;

default: return DefWindowProc(MainWindow, Msg, wParam, lParam);

}

return 0;

}


Thank you very much. EDIT - If possible, please recommend me any book that has information on this subject, I've tries so hard but failed to find any book that matched the following criteria: C++, Win32, Windows Stations and Desktops. Of course MSDN does have information regarding this but it doesn't have all my answers which is why I'm somewhat desperate for a book.

##### Share on other sites
Colin Jeanne    1114
It sounds like your application does not have the rights to enumerate those desktops. Having said that, if you want a virtual desktop manager using actual Windows desktops is going to be a bad move. Switching between desktop objects is very expensive: for example, you know that long wait when UAC is activated on Vista? That wait is mainly from the switch to the secure desktop.

Instead you probably just want to make clever use of ShowWindow() with SW_HIDE. If you remember XP's virtual desktop manager powertoy, this is what it used.

##### Share on other sites
Hmm, so am I right in assuming that the "Default" desktop does not have the DESKTOP_ENUMERATE right? or something (sorry for the un-professional term but I don't completely understand what I'm dealing with :D). Well I don't plan to switch between the default 3 Windows desktops, I'll create my own and use them instead.

Thank you for telling me where the delay came from, I was curious :). If I have anoy more questions later I will post.

EDIT - I just remembered that I created another desktop just for testing purposes, then while in the new desktop I pressed CTRL+ALT+DELETE and got the task manager, I could see the programs running from the other "Default" desktop but not on the active desktop (the one I created), why is this? is it to do with the Windows Station or something?

Thanks again.

##### Share on other sites
Oh yeahh another thing. In my program I create a new desktop that's called "TempDesktop" but don't switch to it. I then click the button that enumerates through the desktops and surely enough it finds "Default" and "TempDesktop" but when I close the program and open it again and then click Search... I still get "Default" and "TempDesktop"... shouldn't I get "Default" and 2 desktops called "TempDesktop"? I also tried changing the name to "TempDesktop2" and still when I re-start the program only those two desktops are detected. Are desktops created by a program automatically destroyed upon the program exiting?

##### Share on other sites
Quote:
 I close the program and open it again and then click Search... I still get "Default" and "TempDesktop"... shouldn't I get "Default" and 2 desktops called "TempDesktop"?

No, it re-opens the one created when you first ran the program. Desktops are destroyed when the associated Windowstation is, until then, it just hangs around. The second time you run your program, Windows goes "Something with this name already exists so you must want that one." and gives you it.

Quote:
 I also tried changing the name to "TempDesktop2" and still when I re-start the program only those two desktops are detected.

The first step to answering this is the same as every other "Why isn't <windows function> working?", check GetLastError when the function fails and see what it tells you. Probably out-of-memory, but who knows.

##### Share on other sites
Thanks for the answer my friend :).

Hmm I see, so if a desktop named "TempDesktop" already exists and I try to create another desktop with the same name I get the handle to a already existing desktop? OK that makes sense, but wouldn't that give the same as result OpenDesktop()?

I'm pretty sure it wasn't to do with memory... as I have 4 Gigabytes of it :D. The desktop was in deed created and I know this because the procedure that searches for desktops reports that it exists. What I was trying to say was, when I compile the code with the name of the new desktop being "TempDesktop" and then close the program to change the name of the desktop to "TempDesktop2" and then recompile, why is it that my program only shows "TempDesktop2" and not "TempDesktop2" and "TempDesktop"? I am asking this because you said that the handles still exist after my program has been closed yet my program doesn't pick up the first desktop I created, and it should regardless of whether or not I have the handle because it searches for them.

Thanks again :).

##### Share on other sites
Colin Jeanne    1114
Quote:
 Original post by VirtualProgrammerHmm, so am I right in assuming that the "Default" desktop does not have the DESKTOP_ENUMERATE right?

I'm no expert at desktops so I dont know. It might also be that perhaps those desktops do not allow themselves to be enumerated.

Quote:
 Original post by VirtualProgrammerEDIT - I just remembered that I created another desktop just for testing purposes, then while in the new desktop I pressed CTRL+ALT+DELETE and got the task manager, I could see the programs running from the other "Default" desktop but not on the active desktop (the one I created), why is this? is it to do with the Windows Station or something?

If I understand what you did and if I understand what the task manager reports, I do not believe the task manager reports any application besides those running on the current desktop.

Quote:
 Original post by VirtualProgrammerHmm I see, so if a desktop named "TempDesktop" already exists and I try to create another desktop with the same name I get the handle to a already existing desktop? OK that makes sense, but wouldn't that give the same as result OpenDesktop()?

Most Open*() functions in the Win32 API only differ from the Create*() functions in that the Open*() functions fail if the object does not already exist.

##### Share on other sites

Quote:
 I'm no expert at desktops so I dont know. It might also be that perhaps those desktops do not allow themselves to be enumerated.

Does this mean that it is impossible for any program to detect a desktop if the desktop does not have the DESKTOP_ENUMERATE style? Hmm, when you set the types of access allowed to a soon to be created desktop (in CreateDesktop(), for example DESKTOP_ENUMERATE or DESKTOP_SWITCH) what do those access types apply to? Is it my program or every other program or both? I'm sorry if I don't make sense here, I can't seem to say it in a better way right now :(.

Quote:
 If I understand what you did and if I understand what the task manager reports, I do not believe the task manager reports any application besides those running on the current desktop.

In the new desktop that I created and switched to ("TempDesktop") I did definatly see the programs running in the other desktop, but when I clicked "Switch To" or "End Task" or when I right-clicked a program and clicked on "Go to process" nothing happened, but if I went to the processes tab and chose to terminate a process by force it worked.

Quote:
 Most Open*() functions in the Win32 API only differ from the Create*() functions in that the Open*() functions fail if the object does not already exist.

Well alright then this made complete sense :).

##### Share on other sites
Quote:
 Original post by VirtualProgrammerDoes this mean that it is impossible for any program to detect a desktop if the desktop does not have the DESKTOP_ENUMERATE style? Hmm, when you set the types of access allowed to a soon to be created desktop (in CreateDesktop(), for example DESKTOP_ENUMERATE or DESKTOP_SWITCH) what do those access types apply to? Is it my program or every other program or both?

Every object in Windows has an associated list of accounts and permissions. If that list has an entry for your account and it includes DESKTOP_ENUMERATE, then you can enumerate it, otherwise you can't. Those flags you pass in to CreateDesktop (and every other Create* function) determine the operations you can perform on that instance. If you include DESKTOP_SWITCH for instance you'll be able to switch to it, else you won't, even if you have permission to. The last argument lets you assign a custom list of accounts and permissions to the object if you so desire, otherwise you get a default one.

Quote:
 In the new desktop that I created and switched to ("TempDesktop") I did definatly see the programs running in the other desktop, but when I clicked "Switch To" or "End Task" or when I right-clicked a program and clicked on "Go to process" nothing happened, but if I went to the processes tab and chose to terminate a process by force it worked.

Seems like Task Manager can't (or won't) switch desktops. And since windows are bound to a single desktop it can't move that, so it does nothing. You can terminate the process since it's just a process like any other, desktops don't come into it.

##### Share on other sites
Quote:
 Every object in Windows has an associated list of accounts and permissions. If that list has an entry for your account and it includes DESKTOP_ENUMERATE, then you can enumerate it, otherwise you can't. Those flags you pass in to CreateDesktop (and every other Create* function) determine the operations you can perform on that instance. If you include DESKTOP_SWITCH for instance you'll be able to switch to it, else you won't, even if you have permission to. The last argument lets you assign a custom list of accounts and permissions to the object if you so desire, otherwise you get a default one.

Hmm I see... but for what reason wouldn't you want full access to a desktop that you created? Also how do I see the list of accounts and permissions?

Quote:
 Seems like Task Manager can't (or won't) switch desktops. And since windows are bound to a single desktop it can't move that, so it does nothing. You can terminate the process since it's just a process like any other, desktops don't come into it.

How is it that the Task Manager can even see the windows running in the "Default" desktop while I'm in the one I created? I thought desktops were completely secluded from one another. I also read that it is impossible for a program to communicate with a program in another desktop. But say I really need to switch some information with the program, what would be the best way to communicate with my program running in the other desktop? One idea that comes to mind is to not use SendMessage() or any of its sister functions becuase they are useless but rather to use files and the registry (I could update information in the files or registry (depending on what I choose) and then have the other instance of my program periodically search for changes and respond.

Thank you and sorry if I'm overloading you with questions. Its just that I want to get everything down about Window Stations and Desktops because information seems scarce... no EBook seems to even mention anything about creating an managing anything like this. Thanks again!

##### Share on other sites
Colin Jeanne    1114
Task Manager is part of the OS. It can do things that normal programs can not do.

As for communicating between desktops - the key here is to not use real desktops. The key is to simulate that there are different desktops since otherwise you run into all sorts of possibly intractable issues.

##### Share on other sites
Quote:
 Also how do I see the list of accounts and permissions?

As far as I know, there's no builtin UI that displays them. If you just want to see it, you can use my QueryDACL tool (it's the first QueryDACL one, just unzip the download and run "qd.exe user <desktop_name>" from an elevated command prompt). If you want to determine it yourself, you'll need GetUserObjectSecurity along with GetSecurityDescriptorDacl, GetAce, and LookupAccountName. The second QueryDacl one is the source code which you can browse if you want.

Note that desktops, the default one at least, are associated with your logon token rather than your personal account, so if you see something like Logon SID S-1-5-... that's what that is.

Quote:
 Task Manager is part of the OS. It can do things that normal programs can not do.

While it is, can and does, enumeration for the Applications tab isn't one of those things. It's just a loop

EnumWindowStations    EnumDesktops        EnumWindows            List Window if IsWindowVisible() && GetParent(GW_OWNER) == NULL && InternalGetWindowText() != "Program Manager"            Details:                Icon = SendMessage(WM_GETICON)                Status = IsHungAppWindow() ? "Not Responding" : "Running";

So the application tab lists everything opened by the current user session. It's perhaps user unfriendly to list something that can't be accessed, but it's not doing anything you can't do.

I haven't toyed with apps on different desktops so I don't know if SendMessage et al. work or not, but I don't see any reason why other IPC methods like sockets, pipes, or shared memory wouldn't suffice.

##### Share on other sites
Thanks for the posts guys :D. Alright then I think I'll give that tool a try :), but a little later on.

Quote:
 So the application tab lists everything opened by the current user session. It's perhaps user unfriendly to list something that can't be accessed, but it's not doing anything you can't do.

How does the Task Manager enumerate the windows in another desktop? Wouldn't it have to switch first? I'm asking this because EnumWindows() does not have a parameter that allows you to choose which desktop to enumerate so I'm guessing it should only be able to enumerate the one its on. But obviously that's not the case.

Quote:
 I haven't toyed with apps on different desktops so I don't know if SendMessage et al. work or not, but I don't see any reason why other IPC methods like sockets, pipes, or shared memory wouldn't suffice.

Hmm how would it work though? SendMessage() can not go accross to other desktops because the message queue is different there (or something like that). Well I havn't really done any research into IPC yet so I don't know how to do those things you mentioned.

Thanks :D.

##### Share on other sites
Quote:
 How does the Task Manager enumerate the windows in another desktop?

By calling SetThreadDesktop before starting the enumeration.

Quote:
 Hmm how would it work though?

If it does, then it'll work the same way it normally does